kate Library API Documentation

katecmds.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2003 Anders Lund <anders@alweb.dk> 00003 Copyright (C) 2001, 2003 Christoph Cullmann <cullmann@kde.org> 00004 Copyright (C) 2001 Charles Samuels <charles@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00018 Boston, MA 02111-1307, USA. 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 // syncs a config flag in the document with a boolean value 00034 static void setDocFlag( KateDocumentConfig::ConfigFlags flag, bool enable, 00035 KateDocument *doc ) 00036 { 00037 doc->config()->setConfigFlags( flag, enable ); 00038 } 00039 00040 // this returns wheather the string s could be converted to 00041 // a bool value, one of on|off|1|0|true|false. the argument val is 00042 // set to the extracted value in case of success 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 // cast it hardcore, we know that it is really a kateview :) 00080 KateView *v = (KateView*) view; 00081 00082 if ( ! v ) 00083 KCC_ERR( i18n("Could not access view") ); 00084 00085 //create a list of args 00086 QStringList args( QStringList::split( QRegExp("\\s+"), _cmd ) ); 00087 QString cmd ( args.first() ); 00088 args.remove( args.first() ); 00089 00090 // ALL commands that takes no arguments. 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 // ALL commands that takes exactly one integer argument. 00132 else if ( cmd == "set-tab-width" || 00133 cmd == "set-indent-width" || 00134 cmd == "set-word-wrap-column" ) 00135 { 00136 // find a integer value > 0 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 // ALL commands that takes 1 boolean argument. 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 // unlikely.. 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 { // isn't a slash 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 // exchange "\t" for the actual tab character, for example 00250 static void exchangeAbbrevs(QString &str) 00251 { 00252 // the format is (findreplace)*[nullzero] 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 // now set the backreferences in the replacement 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 // I need to match "\\" or "", but not "\" 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 // Not implemented 00367 } 00368 else 00369 { // just this line 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 // hex, octal, base 9+1 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 // identify the base 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 { // do the unicode thing 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 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:56:46 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003