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