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