00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "katecmds.h"
00022
00023 #include "katedocument.h"
00024 #include "kateview.h"
00025 #include "kateconfig.h"
00026 #include "kateautoindent.h"
00027
00028 #include <kdebug.h>
00029 #include <klocale.h>
00030
00031 #include <qregexp.h>
00032
00033
00034 static void setDocFlag( KateDocumentConfig::ConfigFlags flag, bool enable,
00035 KateDocument *doc )
00036 {
00037 doc->config()->setConfigFlags( flag, enable );
00038 }
00039
00040
00041
00042
00043 static bool getBoolArg( QString s, bool *val )
00044 {
00045 bool res( false );
00046 s = s.lower();
00047 res = (s == "on" || s == "1" || s == "true");
00048 if ( res )
00049 {
00050 *val = true;
00051 return true;
00052 }
00053 res = (s == "off" || s == "0" || s == "false");
00054 if ( res )
00055 {
00056 *val = false;
00057 return true;
00058 }
00059 return false;
00060 }
00061
00062 QStringList KateCommands::CoreCommands::cmds()
00063 {
00064 QStringList l;
00065 l << "indent" << "unindent" << "cleanindent"
00066 << "comment" << "uncomment"
00067 << "set-tab-width" << "set-replace-tabs" << "set-show-tabs"
00068 << "set-indent-spaces" << "set-indent-width" << "set-indent-mode" << "set-auto-indent"
00069 << "set-line-numbers" << "set-folding-markers" << "set-icon-border"
00070 << "set-word-wrap" << "set-word-wrap-column";
00071 return l;
00072 }
00073
00074 bool KateCommands::CoreCommands::exec(Kate::View *view,
00075 const QString &_cmd,
00076 QString &errorMsg)
00077 {
00078 #define KCC_ERR(s) { errorMsg=s; return false; }
00079
00080 KateView *v = (KateView*) view;
00081
00082 if ( ! v )
00083 KCC_ERR( i18n("Could not access view") );
00084
00085
00086 QStringList args( QStringList::split( QRegExp("\\s+"), _cmd ) );
00087 QString cmd ( args.first() );
00088 args.remove( args.first() );
00089
00090
00091 if ( cmd == "indent" )
00092 {
00093 v->indent();
00094 return true;
00095 }
00096 else if ( cmd == "unindent" )
00097 {
00098 v->unIndent();
00099 return true;
00100 }
00101 else if ( cmd == "cleanindent" )
00102 {
00103 v->cleanIndent();
00104 return true;
00105 }
00106 else if ( cmd == "comment" )
00107 {
00108 v->comment();
00109 return true;
00110 }
00111 else if ( cmd == "uncomment" )
00112 {
00113 v->uncomment();
00114 return true;
00115 }
00116 else if ( cmd == "set-indent-mode" )
00117 {
00118 bool ok(false);
00119 int val ( args.first().toInt( &ok ) );
00120 if ( ok )
00121 {
00122 if ( val < 0 )
00123 KCC_ERR( i18n("Mode must be at least 0.") );
00124 v->doc()->config()->setIndentationMode( val );
00125 }
00126 else
00127 v->doc()->config()->setIndentationMode( KateAutoIndent::modeNumber( args.first() ) );
00128 return true;
00129 }
00130
00131
00132 else if ( cmd == "set-tab-width" ||
00133 cmd == "set-indent-width" ||
00134 cmd == "set-word-wrap-column" )
00135 {
00136
00137 if ( ! args.count() )
00138 KCC_ERR( i18n("Missing argument. Usage: %1 <value>").arg( cmd ) );
00139 bool ok;
00140 int val ( args.first().toInt( &ok ) );
00141 if ( !ok )
00142 KCC_ERR( i18n("Failed to convert argument '%1' to integer.")
00143 .arg( args.first() ) );
00144
00145 if ( cmd == "set-tab-width" )
00146 {
00147 if ( val < 1 )
00148 KCC_ERR( i18n("Width must be at least 1.") );
00149 v->setTabWidth( val );
00150 }
00151 else if ( cmd == "set-indent-width" )
00152 {
00153 if ( val < 1 )
00154 KCC_ERR( i18n("Width must be at least 1.") );
00155 v->doc()->config()->setIndentationWidth( val );
00156 }
00157 else if ( cmd == "set-word-wrap-column" )
00158 {
00159 if ( val < 2 )
00160 KCC_ERR( i18n("Column must be at least 1.") );
00161 v->doc()->setWordWrapAt( val );
00162 }
00163 return true;
00164 }
00165
00166
00167 else if ( cmd == "set-icon-border" ||
00168 cmd == "set-folding-markers" ||
00169 cmd == "set-line-numbers" ||
00170 cmd == "set-replace-tabs" ||
00171 cmd == "set-show-tabs" ||
00172 cmd == "set-indent-spaces" ||
00173 cmd == "set-auto-indent" ||
00174 cmd == "set-word-wrap" )
00175 {
00176 if ( ! args.count() )
00177 KCC_ERR( i18n("Usage: %1 on|off|1|0|true|false").arg( cmd ) );
00178 bool enable;
00179 if ( getBoolArg( args.first(), &enable ) )
00180 {
00181 if ( cmd == "set-icon-border" )
00182 v->setIconBorder( enable );
00183 else if (cmd == "set-folding-markers")
00184 v->setFoldingMarkersOn( enable );
00185 else if ( cmd == "set-line-numbers" )
00186 v->setLineNumbersOn( enable );
00187 else if ( cmd == "set-replace-tabs" )
00188 setDocFlag( KateDocumentConfig::cfReplaceTabs, enable, v->doc() );
00189 else if ( cmd == "set-show-tabs" )
00190 setDocFlag( KateDocumentConfig::cfShowTabs, enable, v->doc() );
00191 else if ( cmd == "set-indent-spaces" )
00192 setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() );
00193 else if ( cmd == "set-auto-indent" )
00194 setDocFlag( KateDocumentConfig::cfAutoIndent, enable, v->doc() );
00195 else if ( cmd == "set-word-wrap" )
00196 v->doc()->setWordWrap( enable );
00197
00198 return true;
00199 }
00200 else
00201 KCC_ERR( i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false")
00202 .arg( args.first() ).arg( cmd ) );
00203 }
00204
00205
00206 KCC_ERR( i18n("Unknown command '%1'").arg(cmd) );
00207 }
00208
00209 static void replace(QString &s, const QString &needle, const QString &with)
00210 {
00211 int pos=0;
00212 while (1)
00213 {
00214 pos=s.find(needle, pos);
00215 if (pos==-1) break;
00216 s.replace(pos, needle.length(), with);
00217 pos+=with.length();
00218 }
00219
00220 }
00221
00222 static int backslashString(const QString &haystack, const QString &needle, int index)
00223 {
00224 int len=haystack.length();
00225 int searchlen=needle.length();
00226 bool evenCount=true;
00227 while (index<len)
00228 {
00229 if (haystack[index]=='\\')
00230 {
00231 evenCount=!evenCount;
00232 }
00233 else
00234 {
00235 if (!evenCount)
00236 {
00237 if (haystack.mid(index, searchlen)==needle)
00238 return index-1;
00239 }
00240 evenCount=true;
00241 }
00242 index++;
00243
00244 }
00245
00246 return -1;
00247 }
00248
00249
00250 static void exchangeAbbrevs(QString &str)
00251 {
00252
00253 const char *magic="a\x07t\t";
00254
00255 while (*magic)
00256 {
00257 int index=0;
00258 char replace=magic[1];
00259 while ((index=backslashString(str, QChar(*magic), index))!=-1)
00260 {
00261 str.replace(index, 2, QChar(replace));
00262 index++;
00263 }
00264 magic++;
00265 magic++;
00266 }
00267 }
00268
00269 QString KateCommands::SedReplace::sedMagic(QString textLine, const QString &find, const QString &repOld, bool noCase, bool repeat)
00270 {
00271
00272 QRegExp matcher(find, noCase);
00273
00274 int start=0;
00275 while (start!=-1)
00276 {
00277 start=matcher.search(textLine, start);
00278
00279 if (start==-1) break;
00280
00281 int length=matcher.matchedLength();
00282
00283
00284 QString rep=repOld;
00285
00286
00287 QStringList backrefs=matcher.capturedTexts();
00288 int refnum=1;
00289
00290 QStringList::Iterator i = backrefs.begin();
00291 ++i;
00292
00293 for (; i!=backrefs.end(); ++i)
00294 {
00295
00296 QString number=QString::number(refnum);
00297
00298 int index=0;
00299 while (index!=-1)
00300 {
00301 index=backslashString(rep, number, index);
00302 if (index>=0)
00303 {
00304 rep.replace(index, 2, *i);
00305 index+=(*i).length();
00306 }
00307 }
00308
00309 refnum++;
00310 }
00311
00312 replace(rep, "\\\\", "\\");
00313 replace(rep, "\\/", "/");
00314
00315 textLine.replace(start, length, rep);
00316 if (!repeat) break;
00317 start+=rep.length();
00318 }
00319
00320
00321 return textLine;
00322 }
00323
00324 static void setLineText(Kate::View *view, int line, const QString &text)
00325 {
00326 if (view->getDoc()->insertLine(line, text))
00327 view->getDoc()->removeLine(line+1);
00328 }
00329
00330 bool KateCommands::SedReplace::exec (Kate::View *view, const QString &cmd, QString &)
00331 {
00332 kdDebug(13010)<<"SedReplace::execCmd()"<<endl;
00333
00334 if (QRegExp("[$%]?s /.+/.*/[ig]*").search(cmd, 0)==-1)
00335 return false;
00336
00337 bool fullFile=cmd[0]=='%';
00338 bool noCase=cmd[cmd.length()-1]=='i' || cmd[cmd.length()-2]=='i';
00339 bool repeat=cmd[cmd.length()-1]=='g' || cmd[cmd.length()-2]=='g';
00340 bool onlySelect=cmd[0]=='$';
00341
00342
00343 QRegExp splitter("^[$%]?s /((?:[^\\\\/]|\\\\.)*)/((?:[^\\\\/]|\\\\.)*)/[ig]*$");
00344 if (splitter.search(cmd)<0) return false;
00345
00346 QString find=splitter.cap(1);
00347 kdDebug(13010)<< "SedReplace: find=" << find.latin1() <<endl;
00348
00349 QString replace=splitter.cap(2);
00350 exchangeAbbrevs(replace);
00351 kdDebug(13010)<< "SedReplace: replace=" << replace.latin1() <<endl;
00352
00353
00354 if (fullFile)
00355 {
00356 int numLines=view->getDoc()->numLines();
00357 for (int line=0; line < numLines; line++)
00358 {
00359 QString text=view->getDoc()->textLine(line);
00360 text=sedMagic(text, find, replace, noCase, repeat);
00361 setLineText(view, line, text);
00362 }
00363 }
00364 else if (onlySelect)
00365 {
00366
00367 }
00368 else
00369 {
00370 QString textLine=view->currentTextLine();
00371 int line=view->cursorLine();
00372 textLine=sedMagic(textLine, find, replace, noCase, repeat);
00373 setLineText(view, line, textLine);
00374 }
00375 return true;
00376 }
00377
00378 bool KateCommands::Character::exec (Kate::View *view, const QString &_cmd, QString &)
00379 {
00380 QString cmd = _cmd;
00381
00382
00383 QRegExp num("^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,3})$");
00384 if (num.search(cmd)==-1) return false;
00385
00386 cmd=num.cap(1);
00387
00388
00389
00390 unsigned short int number=0;
00391 int base=10;
00392 if (cmd[0]=='x' || cmd.left(2)=="0x")
00393 {
00394 cmd.replace(QRegExp("^0?x"), "");
00395 base=16;
00396 }
00397 else if (cmd[0]=='0')
00398 base=8;
00399 bool ok;
00400 number=cmd.toUShort(&ok, base);
00401 if (!ok || number==0) return false;
00402 if (number<=255)
00403 {
00404 char buf[2];
00405 buf[0]=(char)number;
00406 buf[1]=0;
00407 view->insertText(QString(buf));
00408 }
00409 else
00410 {
00411 QChar c(number);
00412 view->insertText(QString(&c, 1));
00413 }
00414
00415 return true;
00416 }
00417
00418 bool KateCommands::Goto::exec (Kate::View *view, const QString &cmd, QString &)
00419 {
00420 if (cmd.left(4) != "goto")
00421 return false;
00422
00423 QStringList args( QStringList::split( QRegExp("\\s+"), cmd ) );
00424 args.remove( args.first() );
00425
00426 view->gotoLineNumber (args[0].toInt());
00427
00428 return true;
00429 }
00430
00431 bool KateCommands::Date::exec (Kate::View *view, const QString &cmd, QString &)
00432 {
00433 if (cmd.left(4) != "date")
00434 return false;
00435
00436 if (QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)).length() > 0)
00437 view->insertText(QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)));
00438 else
00439 view->insertText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
00440
00441 return true;
00442 }
00443
00444