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
#include "katetextline.h"
00028
#include "../interfaces/katecmd.h"
00029
00030
#include <kdebug.h>
00031
#include <klocale.h>
00032
#include <kurl.h>
00033
#include <kshellcompletion.h>
00034
00035
#include <qregexp.h>
00036
00037
00038
00039
00040
static void setDocFlag( KateDocumentConfig::ConfigFlags flag,
bool enable,
00041 KateDocument *doc )
00042 {
00043 doc->config()->setConfigFlags( flag, enable );
00044 }
00045
00046
00047
00048
00049
static bool getBoolArg(
QString s,
bool *val )
00050 {
00051
bool res(
false );
00052 s = s.lower();
00053 res = (s ==
"on" || s ==
"1" || s ==
"true");
00054
if ( res )
00055 {
00056 *val =
true;
00057
return true;
00058 }
00059 res = (s ==
"off" || s ==
"0" || s ==
"false");
00060
if ( res )
00061 {
00062 *val =
false;
00063
return true;
00064 }
00065
return false;
00066 }
00067
00068 QStringList KateCommands::CoreCommands::cmds()
00069 {
00070
QStringList l;
00071 l <<
"indent" <<
"unindent" <<
"cleanindent"
00072 <<
"comment" <<
"uncomment" <<
"goto" <<
"kill-line"
00073 <<
"set-tab-width" <<
"set-replace-tabs" <<
"set-show-tabs"
00074 <<
"set-remove-trailing-space"
00075 <<
"set-indent-spaces" <<
"set-indent-width" <<
"set-mixed-indent"
00076 <<
"set-indent-mode" <<
"set-auto-indent"
00077 <<
"set-line-numbers" <<
"set-folding-markers" <<
"set-icon-border"
00078 <<
"set-word-wrap" <<
"set-word-wrap-column"
00079 <<
"set-replace-tabs-save" <<
"set-remove-trailing-space-save"
00080 <<
"set-highlight";
00081
return l;
00082 }
00083
00084 bool KateCommands::CoreCommands::exec(
Kate::View *view,
00085
const QString &_cmd,
00086
QString &errorMsg)
00087 {
00088
#define KCC_ERR(s) { errorMsg=s; return false; }
00089
00090 KateView *v = (KateView*) view;
00091
00092
if ( ! v )
00093 KCC_ERR( i18n(
"Could not access view") );
00094
00095
00096
QStringList args( QStringList::split(
QRegExp(
"\\s+"), _cmd ) );
00097
QString cmd ( args.first() );
00098 args.remove( args.first() );
00099
00100
00101
if ( cmd ==
"indent" )
00102 {
00103 v->indent();
00104
return true;
00105 }
00106
else if ( cmd ==
"unindent" )
00107 {
00108 v->unIndent();
00109
return true;
00110 }
00111
else if ( cmd ==
"cleanindent" )
00112 {
00113 v->cleanIndent();
00114
return true;
00115 }
00116
else if ( cmd ==
"comment" )
00117 {
00118 v->comment();
00119
return true;
00120 }
00121
else if ( cmd ==
"uncomment" )
00122 {
00123 v->uncomment();
00124
return true;
00125 }
00126
else if ( cmd ==
"kill-line" )
00127 {
00128 v->killLine();
00129
return true;
00130 }
00131
else if ( cmd ==
"set-indent-mode" )
00132 {
00133
bool ok(
false);
00134
int val ( args.first().toInt( &ok ) );
00135
if ( ok )
00136 {
00137
if ( val < 0 )
00138 KCC_ERR( i18n(
"Mode must be at least 0.") );
00139 v->doc()->config()->setIndentationMode( val );
00140 }
00141
else
00142 v->doc()->config()->setIndentationMode( KateAutoIndent::modeNumber( args.first() ) );
00143
return true;
00144 }
00145
else if ( cmd ==
"set-highlight" )
00146 {
00147
QString val = _cmd.section(
' ', 1 ).lower();
00148
for ( uint i=0; i < v->doc()->hlModeCount(); i++ )
00149 {
00150
if ( v->doc()->hlModeName( i ).lower() == val )
00151 {
00152 v->doc()->setHlMode( i );
00153
return true;
00154 }
00155 }
00156 KCC_ERR( i18n(
"No such highlight '%1'").arg( args.first() ) );
00157 }
00158
00159
00160
else if ( cmd ==
"set-tab-width" ||
00161 cmd ==
"set-indent-width" ||
00162 cmd ==
"set-word-wrap-column" ||
00163 cmd ==
"goto" )
00164 {
00165
00166
if ( ! args.count() )
00167 KCC_ERR( i18n(
"Missing argument. Usage: %1 <value>").arg( cmd ) );
00168
bool ok;
00169
int val ( args.first().toInt( &ok ) );
00170
if ( !ok )
00171 KCC_ERR( i18n(
"Failed to convert argument '%1' to integer.")
00172 .arg( args.first() ) );
00173
00174
if ( cmd ==
"set-tab-width" )
00175 {
00176
if ( val < 1 )
00177 KCC_ERR( i18n(
"Width must be at least 1.") );
00178 v->setTabWidth( val );
00179 }
00180
else if ( cmd ==
"set-indent-width" )
00181 {
00182
if ( val < 1 )
00183 KCC_ERR( i18n(
"Width must be at least 1.") );
00184 v->doc()->config()->setIndentationWidth( val );
00185 }
00186
else if ( cmd ==
"set-word-wrap-column" )
00187 {
00188
if ( val < 2 )
00189 KCC_ERR( i18n(
"Column must be at least 1.") );
00190 v->doc()->setWordWrapAt( val );
00191 }
00192
else if ( cmd ==
"goto" )
00193 {
00194
if ( val < 1 )
00195 KCC_ERR( i18n(
"Line must be at least 1") );
00196
if ( (uint)val > v->doc()->numLines() )
00197 KCC_ERR( i18n(
"There is not that many lines in this document") );
00198 v->gotoLineNumber( val - 1 );
00199 }
00200
return true;
00201 }
00202
00203
00204
else if ( cmd ==
"set-icon-border" ||
00205 cmd ==
"set-folding-markers" ||
00206 cmd ==
"set-line-numbers" ||
00207 cmd ==
"set-replace-tabs" ||
00208 cmd ==
"set-remove-trailing-space" ||
00209 cmd ==
"set-show-tabs" ||
00210 cmd ==
"set-indent-spaces" ||
00211 cmd ==
"set-mixed-indent" ||
00212 cmd ==
"set-word-wrap" ||
00213 cmd ==
"set-replace-tabs-save" ||
00214 cmd ==
"set-remove-trailing-space-save" )
00215 {
00216
if ( ! args.count() )
00217 KCC_ERR( i18n(
"Usage: %1 on|off|1|0|true|false").arg( cmd ) );
00218
bool enable;
00219
if ( getBoolArg( args.first(), &enable ) )
00220 {
00221
if ( cmd ==
"set-icon-border" )
00222 v->setIconBorder( enable );
00223
else if (cmd ==
"set-folding-markers")
00224 v->setFoldingMarkersOn( enable );
00225
else if ( cmd ==
"set-line-numbers" )
00226 v->setLineNumbersOn( enable );
00227
else if ( cmd ==
"set-replace-tabs" )
00228 setDocFlag( KateDocumentConfig::cfReplaceTabsDyn, enable, v->doc() );
00229
else if ( cmd ==
"set-remove-trailing-space" )
00230 setDocFlag( KateDocumentConfig::cfRemoveTrailingDyn, enable, v->doc() );
00231
else if ( cmd ==
"set-show-tabs" )
00232 setDocFlag( KateDocumentConfig::cfShowTabs, enable, v->doc() );
00233
else if ( cmd ==
"set-indent-spaces" )
00234 setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() );
00235
else if ( cmd ==
"set-mixed-indent" )
00236 {
00237
00238
00239 setDocFlag( KateDocumentConfig::cfMixedIndent, enable, v->doc() );
00240
if ( enable )
00241 {
00242 setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() );
00243
if ( ! v->doc()->config()->indentationWidth() )
00244 v->doc()->config()->setIndentationWidth( v->tabWidth()/2 );
00245 }
00246 }
00247
else if ( cmd ==
"set-word-wrap" )
00248 v->doc()->setWordWrap( enable );
00249
else if ( cmd ==
"set-replace-tabs-save" )
00250 setDocFlag( KateDocumentConfig::cfReplaceTabs, enable, v->doc() );
00251
else if ( cmd ==
"set-remove-trailing-space-save" )
00252 setDocFlag( KateDocumentConfig::cfRemoveSpaces, enable, v->doc() );
00253
00254
return true;
00255 }
00256
else
00257 KCC_ERR( i18n(
"Bad argument '%1'. Usage: %2 on|off|1|0|true|false")
00258 .arg( args.first() ).arg( cmd ) );
00259 }
00260
00261
00262 KCC_ERR( i18n(
"Unknown command '%1'").arg(cmd) );
00263 }
00264
00265 KCompletion *
KateCommands::CoreCommands::completionObject(
const QString &cmd,
Kate::View *view )
00266 {
00267
if ( cmd ==
"set-highlight" )
00268 {
00269 KateView *v = (KateView*)view;
00270
QStringList l;
00271
for ( uint i = 0; i < v->doc()->hlModeCount(); i++ )
00272 l << v->doc()->hlModeName( i );
00273
00274
KateCmdShellCompletion *co =
new KateCmdShellCompletion();
00275 co->
setItems( l );
00276 co->
setIgnoreCase(
true );
00277
return co;
00278 }
00279
return 0L;
00280 }
00281
00282
00283
00284
static void replace(
QString &s,
const QString &needle,
const QString &with)
00285 {
00286
int pos=0;
00287
while (1)
00288 {
00289 pos=s.find(needle, pos);
00290
if (pos==-1)
break;
00291 s.replace(pos, needle.length(), with);
00292 pos+=with.length();
00293 }
00294
00295 }
00296
00297
static int backslashString(
const QString &haystack,
const QString &needle,
int index)
00298 {
00299
int len=haystack.length();
00300
int searchlen=needle.length();
00301
bool evenCount=
true;
00302
while (index<len)
00303 {
00304
if (haystack[index]==
'\\')
00305 {
00306 evenCount=!evenCount;
00307 }
00308
else
00309 {
00310
if (!evenCount)
00311 {
00312
if (haystack.mid(index, searchlen)==needle)
00313
return index-1;
00314 }
00315 evenCount=
true;
00316 }
00317 index++;
00318
00319 }
00320
00321
return -1;
00322 }
00323
00324
00325
static void exchangeAbbrevs(
QString &str)
00326 {
00327
00328
const char *magic=
"a\x07t\tn\n";
00329
00330
while (*magic)
00331 {
00332
int index=0;
00333
char replace=magic[1];
00334
while ((index=backslashString(str,
QChar(*magic), index))!=-1)
00335 {
00336 str.replace(index, 2,
QChar(replace));
00337 index++;
00338 }
00339 magic++;
00340 magic++;
00341 }
00342 }
00343
00344
int KateCommands::SedReplace::sedMagic( KateDocument *doc,
int &line,
00345
const QString &find,
const QString &repOld,
const QString &delim,
00346
bool noCase,
bool repeat,
00347 uint startcol,
int endcol )
00348 {
00349
KateTextLine *ln = doc->kateTextLine( line );
00350
if ( ! ln || ! ln->
length() )
return 0;
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
QStringList patterns = QStringList::split(
QRegExp(
"(^\\\\n|(?![^\\\\])\\\\n)"), find,
true );
00363
if ( patterns.count() > 1 )
00364 {
00365
for ( uint i = 0; i < patterns.count(); i++ )
00366 {
00367
if ( i < patterns.count() - 1 )
00368 patterns[i].append(
"$");
00369
if ( i )
00370 patterns[i].prepend(
"^");
00371
00372
kdDebug(13025)<<
"patterns["<<i<<
"] ="<<patterns[i]<<
endl;
00373 }
00374 }
00375
00376
QRegExp matcher(patterns[0], noCase);
00377
00378 uint len;
00379
int matches = 0;
00380
00381
while ( ln->
searchText( startcol, matcher, &startcol, &len ) )
00382 {
00383
00384
if ( endcol >= 0 && startcol + len > (uint)endcol )
00385
break;
00386
00387 matches++;
00388
00389
00390
QString rep=repOld;
00391
00392
00393
QStringList backrefs=matcher.capturedTexts();
00394
int refnum=1;
00395
00396 QStringList::Iterator i = backrefs.begin();
00397 ++i;
00398
00399
for (; i!=backrefs.end(); ++i)
00400 {
00401
00402
QString number=QString::number(refnum);
00403
00404
int index=0;
00405
while (index!=-1)
00406 {
00407 index=backslashString(rep, number, index);
00408
if (index>=0)
00409 {
00410 rep.replace(index, 2, *i);
00411 index+=(*i).length();
00412 }
00413 }
00414
00415 refnum++;
00416 }
00417
00418
replace(rep,
"\\\\",
"\\");
00419
replace(rep,
"\\" + delim, delim);
00420
00421 doc->removeText( line, startcol, line, startcol + len );
00422 doc->insertText( line, startcol, rep );
00423
00424
00425
00426
00427
int lns = rep.contains(
'\n');
00428
if ( lns )
00429 {
00430 line += lns;
00431
00432
if ( doc->lineLength( line ) > 0 && ( endcol < 0 || (uint)endcol >= startcol + len ) )
00433 {
00434
00435 endcol -= (startcol + len);
00436 uint sc = rep.length() - rep.findRev(
'\n') - 1;
00437 matches += sedMagic( doc, line, find, repOld, delim, noCase, repeat, sc, endcol );
00438 }
00439 }
00440
00441
if (!repeat)
break;
00442 startcol+=rep.length();
00443
00444
00445 uint ll = ln->
length();
00446
if ( ! ll || startcol > ll )
00447
break;
00448 }
00449
00450
return matches;
00451 }
00452
00453 bool KateCommands::SedReplace::exec (
Kate::View *view,
const QString &cmd,
QString &msg)
00454 {
00455
kdDebug(13025)<<
"SedReplace::execCmd( "<<cmd<<
" )"<<
endl;
00456
00457
QRegExp delim(
"^[$%]?s\\s*([^\\w\\s])");
00458
if ( delim.search( cmd ) < 0 )
return false;
00459
00460
bool fullFile=cmd[0]==
'%';
00461
bool noCase=cmd[cmd.length()-1]==
'i' || cmd[cmd.length()-2]==
'i';
00462
bool repeat=cmd[cmd.length()-1]==
'g' || cmd[cmd.length()-2]==
'g';
00463
bool onlySelect=cmd[0]==
'$';
00464
00465
QString d = delim.cap(1);
00466
kdDebug(13025)<<
"SedReplace: delimiter is '"<<d<<
"'"<<
endl;
00467
00468
QRegExp splitter(
QString(
"^[$%]?s\\s*") + d +
"((?:[^\\\\\\" + d +
"]|\\\\.)*)\\" + d +
"((?:[^\\\\\\" + d +
"]|\\\\.)*)\\" + d +
"[ig]{0,2}$" );
00469
if (splitter.search(cmd)<0)
return false;
00470
00471
QString find=splitter.cap(1);
00472
kdDebug(13025)<<
"SedReplace: find=" << find.latin1() <<
endl;
00473
00474
QString replace=splitter.cap(2);
00475 exchangeAbbrevs(replace);
00476
kdDebug(13025)<<
"SedReplace: replace=" << replace.latin1() <<
endl;
00477
00478 KateDocument *doc = ((KateView*)view)->doc();
00479
if ( ! doc )
return false;
00480
00481 doc->editStart();
00482
00483
int res = 0;
00484
00485
if (fullFile)
00486 {
00487 uint numLines=doc->numLines();
00488
for (
int line=0; (uint)line < numLines; line++)
00489 {
00490 res += sedMagic( doc, line, find, replace, d, !noCase, repeat );
00491
if ( ! repeat && res )
break;
00492 }
00493 }
00494
else if (onlySelect)
00495 {
00496
int startline = doc->selStartLine();
00497 uint startcol = doc->selStartCol();
00498
int endcol = -1;
00499
do {
00500
if ( startline == doc->selEndLine() )
00501 endcol = doc->selEndCol();
00502
00503 res += sedMagic( doc, startline, find, replace, d, !noCase, repeat, startcol, endcol );
00504
00505 startcol = 0;
00506
00507 startline++;
00508 }
while ( (
int)startline <= doc->selEndLine() );
00509 }
00510
else
00511 {
00512
int line=view->cursorLine();
00513 res += sedMagic(doc, line, find, replace, d, !noCase, repeat);
00514 }
00515
00516 msg = i18n(
"1 replacement done",
"%n replacements done",res );
00517
00518 doc->editEnd();
00519
00520
return true;
00521 }
00522
00523
00524
00525 bool KateCommands::Character::exec (
Kate::View *view,
const QString &_cmd,
QString &)
00526 {
00527
QString cmd = _cmd;
00528
00529
00530
QRegExp num(
"^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,3})$");
00531
if (num.search(cmd)==-1)
return false;
00532
00533 cmd=num.cap(1);
00534
00535
00536
00537
unsigned short int number=0;
00538
int base=10;
00539
if (cmd[0]==
'x' || cmd.left(2)==
"0x")
00540 {
00541 cmd.replace(
QRegExp(
"^0?x"),
"");
00542 base=16;
00543 }
00544
else if (cmd[0]==
'0')
00545 base=8;
00546
bool ok;
00547 number=cmd.toUShort(&ok, base);
00548
if (!ok || number==0)
return false;
00549
if (number<=255)
00550 {
00551
char buf[2];
00552 buf[0]=(
char)number;
00553 buf[1]=0;
00554 view->insertText(
QString(buf));
00555 }
00556
else
00557 {
00558
QChar c(number);
00559 view->insertText(
QString(&c, 1));
00560 }
00561
00562
return true;
00563 }
00564
00565
00566
00567 bool KateCommands::Date::exec (
Kate::View *view,
const QString &cmd,
QString &)
00568 {
00569
if (cmd.left(4) !=
"date")
00570
return false;
00571
00572
if (QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)).length() > 0)
00573 view->insertText(QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)));
00574
else
00575 view->insertText(QDateTime::currentDateTime().toString(
"yyyy-MM-dd hh:mm:ss"));
00576
00577
return true;
00578 }
00579
00580
00581