• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
katecmds.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2003 - 2005 Anders Lund <anders@alweb.dk>
3  Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
4  Copyright (C) 2001 Charles Samuels <charles@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "katecmds.h"
22 
23 #include "katedocument.h"
24 #include "kateview.h"
25 #include "kateconfig.h"
26 #include "kateautoindent.h"
27 #include "katetextline.h"
28 #include "katefactory.h"
29 #include "katejscript.h"
30 #include "katerenderer.h"
31 
32 #include "../interfaces/katecmd.h"
33 
34 #include <kdebug.h>
35 #include <tdelocale.h>
36 #include <kurl.h>
37 #include <kshellcompletion.h>
38 
39 #include <tqregexp.h>
40 
41 
42 //BEGIN CoreCommands
43 // syncs a config flag in the document with a boolean value
44 static void setDocFlag( KateDocumentConfig::ConfigFlags flag, bool enable,
45  KateDocument *doc )
46 {
47  doc->config()->setConfigFlags( flag, enable );
48 }
49 
50 // this returns wheather the string s could be converted to
51 // a bool value, one of on|off|1|0|true|false. the argument val is
52 // set to the extracted value in case of success
53 static bool getBoolArg( TQString s, bool *val )
54 {
55  bool res( false );
56  s = s.lower();
57  res = (s == "on" || s == "1" || s == "true");
58  if ( res )
59  {
60  *val = true;
61  return true;
62  }
63  res = (s == "off" || s == "0" || s == "false");
64  if ( res )
65  {
66  *val = false;
67  return true;
68  }
69  return false;
70 }
71 
72 TQStringList KateCommands::CoreCommands::cmds()
73 {
74  TQStringList l;
75  l << "indent" << "unindent" << "cleanindent"
76  << "comment" << "uncomment" << "goto" << "kill-line"
77  << "set-tab-width" << "set-replace-tabs" << "set-show-tabs"
78  << "set-remove-trailing-space"
79  << "set-indent-spaces" << "set-indent-width" << "set-mixed-indent"
80  << "set-indent-mode" << "set-auto-indent"
81  << "set-line-numbers" << "set-folding-markers" << "set-icon-border"
82  << "set-wrap-cursor"
83  << "set-word-wrap" << "set-word-wrap-column"
84  << "set-replace-tabs-save" << "set-remove-trailing-space-save"
85  << "set-highlight" << "run-myself" << "set-show-indent";
86  return l;
87 }
88 
89 bool KateCommands::CoreCommands::exec(Kate::View *view,
90  const TQString &_cmd,
91  TQString &errorMsg)
92 {
93 #define KCC_ERR(s) { errorMsg=s; return false; }
94  // cast it hardcore, we know that it is really a kateview :)
95  KateView *v = (KateView*) view;
96 
97  if ( ! v )
98  KCC_ERR( i18n("Could not access view") );
99 
100  //create a list of args
101  TQStringList args( TQStringList::split( TQRegExp("\\s+"), _cmd ) );
102  TQString cmd ( args.first() );
103  args.remove( args.first() );
104 
105  // ALL commands that takes no arguments.
106  if ( cmd == "indent" )
107  {
108  v->indent();
109  return true;
110  }
111  else if ( cmd == "run-myself" )
112  {
113 #ifndef TQ_WS_WIN //todo
114  return KateFactory::self()->jscript()->execute(v, v->doc()->text(), errorMsg);
115 #else
116  return 0;
117 #endif
118  }
119  else if ( cmd == "unindent" )
120  {
121  v->unIndent();
122  return true;
123  }
124  else if ( cmd == "cleanindent" )
125  {
126  v->cleanIndent();
127  return true;
128  }
129  else if ( cmd == "comment" )
130  {
131  v->comment();
132  return true;
133  }
134  else if ( cmd == "uncomment" )
135  {
136  v->uncomment();
137  return true;
138  }
139  else if ( cmd == "kill-line" )
140  {
141  v->killLine();
142  return true;
143  }
144  else if ( cmd == "set-indent-mode" )
145  {
146  bool ok(false);
147  int val ( args.first().toInt( &ok ) );
148  if ( ok )
149  {
150  if ( val < 0 )
151  KCC_ERR( i18n("Mode must be at least 0.") );
152  v->doc()->config()->setIndentationMode( val );
153  }
154  else
155  v->doc()->config()->setIndentationMode( KateAutoIndent::modeNumber( args.first() ) );
156  return true;
157  }
158  else if ( cmd == "set-highlight" )
159  {
160  TQString val = TQString(_cmd.section( ' ', 1 )).lower();
161  for ( uint i=0; i < v->doc()->hlModeCount(); i++ )
162  {
163  if ( v->doc()->hlModeName( i ).lower() == val )
164  {
165  v->doc()->setHlMode( i );
166  return true;
167  }
168  }
169  KCC_ERR( i18n("No such highlight '%1'").arg( args.first() ) );
170  }
171 
172  // ALL commands that takes exactly one integer argument.
173  else if ( cmd == "set-tab-width" ||
174  cmd == "set-indent-width" ||
175  cmd == "set-word-wrap-column" ||
176  cmd == "goto" )
177  {
178  // find a integer value > 0
179  if ( ! args.count() )
180  KCC_ERR( i18n("Missing argument. Usage: %1 <value>").arg( cmd ) );
181  bool ok;
182  int val ( args.first().toInt( &ok ) );
183  if ( !ok )
184  KCC_ERR( i18n("Failed to convert argument '%1' to integer.")
185  .arg( args.first() ) );
186 
187  if ( cmd == "set-tab-width" )
188  {
189  if ( val < 1 )
190  KCC_ERR( i18n("Width must be at least 1.") );
191  v->setTabWidth( val );
192  }
193  else if ( cmd == "set-indent-width" )
194  {
195  if ( val < 1 )
196  KCC_ERR( i18n("Width must be at least 1.") );
197  v->doc()->config()->setIndentationWidth( val );
198  }
199  else if ( cmd == "set-word-wrap-column" )
200  {
201  if ( val < 2 )
202  KCC_ERR( i18n("Column must be at least 1.") );
203  v->doc()->setWordWrapAt( val );
204  }
205  else if ( cmd == "goto" )
206  {
207  if ( val < 1 )
208  KCC_ERR( i18n("Line must be at least 1") );
209  if ( (uint)val > v->doc()->numLines() )
210  KCC_ERR( i18n("There is not that many lines in this document") );
211  v->gotoLineNumber( val - 1 );
212  }
213  return true;
214  }
215 
216  // ALL commands that takes 1 boolean argument.
217  else if ( cmd == "set-icon-border" ||
218  cmd == "set-folding-markers" ||
219  cmd == "set-line-numbers" ||
220  cmd == "set-replace-tabs" ||
221  cmd == "set-remove-trailing-space" ||
222  cmd == "set-show-tabs" ||
223  cmd == "set-indent-spaces" ||
224  cmd == "set-mixed-indent" ||
225  cmd == "set-word-wrap" ||
226  cmd == "set-wrap-cursor" ||
227  cmd == "set-replace-tabs-save" ||
228  cmd == "set-remove-trailing-space-save" ||
229  cmd == "set-show-indent" )
230  {
231  if ( ! args.count() )
232  KCC_ERR( i18n("Usage: %1 on|off|1|0|true|false").arg( cmd ) );
233  bool enable;
234  if ( getBoolArg( args.first(), &enable ) )
235  {
236  if ( cmd == "set-icon-border" )
237  v->setIconBorder( enable );
238  else if (cmd == "set-folding-markers")
239  v->setFoldingMarkersOn( enable );
240  else if ( cmd == "set-line-numbers" )
241  v->setLineNumbersOn( enable );
242  else if ( cmd == "set-show-indent" )
243  v->renderer()->setShowIndentLines( enable );
244  else if ( cmd == "set-replace-tabs" )
245  setDocFlag( KateDocumentConfig::cfReplaceTabsDyn, enable, v->doc() );
246  else if ( cmd == "set-remove-trailing-space" )
247  setDocFlag( KateDocumentConfig::cfRemoveTrailingDyn, enable, v->doc() );
248  else if ( cmd == "set-show-tabs" )
249  setDocFlag( KateDocumentConfig::cfShowTabs, enable, v->doc() );
250  else if ( cmd == "set-indent-spaces" )
251  setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() );
252  else if ( cmd == "set-mixed-indent" )
253  {
254  // this is special, in that everything is set up -- space-indent is enabled,
255  // and a indent-width is set if it is 0 (to tabwidth/2)
256  setDocFlag( KateDocumentConfig::cfMixedIndent, enable, v->doc() );
257  if ( enable )
258  {
259  setDocFlag( KateDocumentConfig::cfSpaceIndent, enable, v->doc() );
260  if ( ! v->doc()->config()->indentationWidth() )
261  v->doc()->config()->setIndentationWidth( v->tabWidth()/2 );
262  }
263  }
264  else if ( cmd == "set-word-wrap" )
265  v->doc()->setWordWrap( enable );
266  else if ( cmd == "set-remove-trailing-space-save" )
267  setDocFlag( KateDocumentConfig::cfRemoveSpaces, enable, v->doc() );
268  else if ( cmd == "set-wrap-cursor" )
269  setDocFlag( KateDocumentConfig::cfWrapCursor, enable, v->doc() );
270 
271  return true;
272  }
273  else
274  KCC_ERR( i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false")
275  .arg( args.first() ).arg( cmd ) );
276  }
277 
278  // unlikely..
279  KCC_ERR( i18n("Unknown command '%1'").arg(cmd) );
280 }
281 
282 TDECompletion *KateCommands::CoreCommands::completionObject( const TQString &cmd, Kate::View *view )
283 {
284  if ( cmd == "set-highlight" )
285  {
286  KateView *v = (KateView*)view;
287  TQStringList l;
288  for ( uint i = 0; i < v->doc()->hlModeCount(); i++ )
289  l << v->doc()->hlModeName( i );
290 
291  KateCmdShellCompletion *co = new KateCmdShellCompletion();
292  co->setItems( l );
293  co->setIgnoreCase( true );
294  return co;
295  }
296  return 0L;
297 }
298 //END CoreCommands
299 
300 //BEGIN SedReplace
301 static void replace(TQString &s, const TQString &needle, const TQString &with)
302 {
303  int pos=0;
304  while (1)
305  {
306  pos=s.find(needle, pos);
307  if (pos==-1) break;
308  s.replace(pos, needle.length(), with);
309  pos+=with.length();
310  }
311 
312 }
313 
314 static int backslashString(const TQString &haystack, const TQString &needle, int index)
315 {
316  int len=haystack.length();
317  int searchlen=needle.length();
318  bool evenCount=true;
319  while (index<len)
320  {
321  if (haystack[index]=='\\')
322  {
323  evenCount=!evenCount;
324  }
325  else
326  { // isn't a slash
327  if (!evenCount)
328  {
329  if (haystack.mid(index, searchlen)==needle)
330  return index-1;
331  }
332  evenCount=true;
333  }
334  index++;
335 
336  }
337 
338  return -1;
339 }
340 
341 // exchange "\t" for the actual tab character, for example
342 static void exchangeAbbrevs(TQString &str)
343 {
344  // the format is (findreplace)*[nullzero]
345  const char *magic="a\x07t\tn\n";
346 
347  while (*magic)
348  {
349  int index=0;
350  char replace=magic[1];
351  while ((index=backslashString(str, TQChar(*magic), index))!=-1)
352  {
353  str.replace(index, 2, TQChar(replace));
354  index++;
355  }
356  magic++;
357  magic++;
358  }
359 }
360 
361 int KateCommands::SedReplace::sedMagic( KateDocument *doc, int &line,
362  const TQString &find, const TQString &repOld, const TQString &delim,
363  bool noCase, bool repeat,
364  uint startcol, int endcol )
365 {
366  KateTextLine *ln = doc->kateTextLine( line );
367  if ( ! ln || ! ln->length() ) return 0;
368 
369  // HANDLING "\n"s in PATTERN
370  // * Create a list of patterns, splitting PATTERN on (unescaped) "\n"
371  // * insert $s and ^s to match line ends/beginnings
372  // * When matching patterhs after the first one, replace \N with the captured
373  // text.
374  // * If all patterns in the list match sequentiel lines, there is a match, so
375  // * remove line/start to line + patterns.count()-1/patterns.last.length
376  // * handle capatures by putting them in one list.
377  // * the existing insertion is fine, including the line calculation.
378 
379  TQStringList patterns = TQStringList::split( TQRegExp("(^\\\\n|(?![^\\\\])\\\\n)"), find, true );
380 
381  if ( patterns.count() > 1 )
382  {
383  for ( uint i = 0; i < patterns.count(); i++ )
384  {
385  if ( i < patterns.count() - 1 )
386  patterns[i].append("$");
387  if ( i )
388  patterns[i].prepend("^");
389 
390  kdDebug(13025)<<"patterns["<<i<<"] ="<<patterns[i]<<endl;
391  }
392  }
393 
394  TQRegExp matcher(patterns[0], noCase);
395 
396  uint len;
397  int matches = 0;
398 
399  while ( ln->searchText( startcol, matcher, &startcol, &len ) )
400  {
401 
402  if ( endcol >= 0 && startcol + len > (uint)endcol )
403  break;
404 
405  matches++;
406 
407 
408  TQString rep=repOld;
409 
410  // now set the backreferences in the replacement
411  TQStringList backrefs=matcher.capturedTexts();
412  int refnum=1;
413 
414  TQStringList::Iterator i = backrefs.begin();
415  ++i;
416 
417  for (; i!=backrefs.end(); ++i)
418  {
419  // I need to match "\\" or "", but not "\"
420  TQString number=TQString::number(refnum);
421 
422  int index=0;
423  while (index!=-1)
424  {
425  index=backslashString(rep, number, index);
426  if (index>=0)
427  {
428  rep.replace(index, 2, *i);
429  index+=(*i).length();
430  }
431  }
432 
433  refnum++;
434  }
435 
436  replace(rep, "\\\\", "\\");
437  replace(rep, "\\" + delim, delim);
438 
439  doc->removeText( line, startcol, line, startcol + len );
440  doc->insertText( line, startcol, rep );
441 
442  // TODO if replace contains \n,
443  // change the line number and
444  // check for text that needs be searched behind the last inserted newline.
445  int lns = rep.contains('\n');
446  if ( lns )
447  {
448  line += lns;
449 
450  if ( doc->lineLength( line ) > 0 && ( endcol < 0 || (uint)endcol >= startcol + len ) )
451  {
452  // if ( endcol >= startcol + len )
453  endcol -= (startcol + len);
454  uint sc = rep.length() - rep.findRev('\n') - 1;
455  matches += sedMagic( doc, line, find, repOld, delim, noCase, repeat, sc, endcol );
456  }
457  }
458 
459  if (!repeat) break;
460  startcol+=rep.length();
461 
462  // sanity check -- avoid infinite loops eg with %s,.*,,g ;)
463  uint ll = ln->length();
464  if ( ! ll || startcol > ll )
465  break;
466  }
467 
468  return matches;
469 }
470 
471 bool KateCommands::SedReplace::exec (Kate::View *view, const TQString &cmd, TQString &msg)
472 {
473  kdDebug(13025)<<"SedReplace::execCmd( "<<cmd<<" )"<<endl;
474 
475  TQRegExp delim("^[$%]?s\\s*([^\\w\\s])");
476  if ( delim.search( cmd ) < 0 ) return false;
477 
478  bool fullFile=cmd[0]=='%';
479  bool noCase=cmd[cmd.length()-1]=='i' || cmd[cmd.length()-2]=='i';
480  bool repeat=cmd[cmd.length()-1]=='g' || cmd[cmd.length()-2]=='g';
481  bool onlySelect=cmd[0]=='$';
482 
483  TQString d = delim.cap(1);
484  kdDebug(13025)<<"SedReplace: delimiter is '"<<d<<"'"<<endl;
485 
486  TQRegExp splitter( TQString("^[$%]?s\\s*") + d + "((?:[^\\\\\\" + d + "]|\\\\.)*)\\" + d +"((?:[^\\\\\\" + d + "]|\\\\.)*)\\" + d + "[ig]{0,2}$" );
487  if (splitter.search(cmd)<0) return false;
488 
489  TQString find=splitter.cap(1);
490  kdDebug(13025)<< "SedReplace: find=" << find.latin1() <<endl;
491 
492  TQString replace=splitter.cap(2);
493  exchangeAbbrevs(replace);
494  kdDebug(13025)<< "SedReplace: replace=" << replace.latin1() <<endl;
495 
496  if ( find.contains("\\n") )
497  {
498  msg = i18n("Sorry, but Kate is not able to replace newlines, yet");
499  return false;
500  }
501 
502  KateDocument *doc = ((KateView*)view)->doc();
503  if ( ! doc ) return false;
504 
505  doc->editStart();
506 
507  int res = 0;
508 
509  if (fullFile)
510  {
511  uint numLines=doc->numLines();
512  for (int line=0; (uint)line < numLines; line++)
513  {
514  res += sedMagic( doc, line, find, replace, d, !noCase, repeat );
515  if ( ! repeat && res ) break;
516  }
517  }
518  else if (onlySelect)
519  {
520  int startline = doc->selStartLine();
521  uint startcol = doc->selStartCol();
522  int endcol = -1;
523  do {
524  if ( startline == doc->selEndLine() )
525  endcol = doc->selEndCol();
526 
527  res += sedMagic( doc, startline, find, replace, d, !noCase, repeat, startcol, endcol );
528 
529  /*if ( startcol )*/ startcol = 0;
530 
531  startline++;
532  } while ( (int)startline <= doc->selEndLine() );
533  }
534  else // just this line
535  {
536  int line=view->cursorLine();
537  res += sedMagic(doc, line, find, replace, d, !noCase, repeat);
538  }
539 
540  msg = i18n("1 replacement done", "%n replacements done",res );
541 
542  doc->editEnd();
543 
544  return true;
545 }
546 //END SedReplace
547 
548 //BEGIN Character
549 bool KateCommands::Character::exec (Kate::View *view, const TQString &_cmd, TQString &)
550 {
551  TQString cmd = _cmd;
552 
553  // hex, octal, base 9+1
554  TQRegExp num("^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,3})$");
555  if (num.search(cmd)==-1) return false;
556 
557  cmd=num.cap(1);
558 
559  // identify the base
560 
561  unsigned short int number=0;
562  int base=10;
563  if (cmd[0]=='x' || cmd.left(2)=="0x")
564  {
565  cmd.replace(TQRegExp("^0?x"), "");
566  base=16;
567  }
568  else if (cmd[0]=='0')
569  base=8;
570  bool ok;
571  number=cmd.toUShort(&ok, base);
572  if (!ok || number==0) return false;
573  if (number<=255)
574  {
575  char buf[2];
576  buf[0]=(char)number;
577  buf[1]=0;
578  view->insertText(TQString(buf));
579  }
580  else
581  { // do the unicode thing
582  TQChar c(number);
583  view->insertText(TQString(&c, 1));
584  }
585 
586  return true;
587 }
588 //END Character
589 
590 //BEGIN Date
591 bool KateCommands::Date::exec (Kate::View *view, const TQString &cmd, TQString &)
592 {
593  if (cmd.left(4) != "date")
594  return false;
595 
596  if (TQDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)).length() > 0)
597  view->insertText(TQDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)));
598  else
599  view->insertText(TQDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
600 
601  return true;
602 }
603 //END Date
KateAutoIndent::modeNumber
virtual uint modeNumber() const
Mode index of this mode.
Definition: kateautoindent.h:185
KateCmdShellCompletion
A TDECompletion object that completes last ?unquoted? word in the string passed.
Definition: katecmd.h:62
KateCommands::Character::exec
bool exec(class Kate::View *view, const TQString &cmd, TQString &errorMsg)
execute command
Definition: katecmds.cpp:549
KateCommands::CoreCommands::cmds
TQStringList cmds()
supported commands as prefixes
Definition: katecmds.cpp:72
KateCommands::CoreCommands::exec
bool exec(class Kate::View *view, const TQString &cmd, TQString &errorMsg)
execute command
Definition: katecmds.cpp:89
KateCommands::CoreCommands::completionObject
TDECompletion * completionObject(const TQString &cmd, Kate::View *view)
override completionObject from interfaces/document.h .
Definition: katecmds.cpp:282
KateCommands::Date::exec
bool exec(class Kate::View *view, const TQString &cmd, TQString &errorMsg)
execute command
Definition: katecmds.cpp:591
KateCommands::SedReplace::exec
bool exec(class Kate::View *view, const TQString &cmd, TQString &errorMsg)
execute command
Definition: katecmds.cpp:471
KateTextLine
The KateTextLine represents a line of text.
Definition: katetextline.h:42
KateTextLine::length
uint length() const
Returns the length.
Definition: katetextline.h:97
KateTextLine::searchText
bool searchText(uint startCol, const TQString &text, uint *foundAtCol, uint *matchLen, bool casesensitive=true, bool backwards=false)
search given string
Definition: katetextline.cpp:273
Kate::View
The Kate::View text editor interface.
Definition: view.h:45
Kate::View::insertText
virtual void insertText(const TQString &mark)
Insert text at the current cursor position.
Definition: view.h:86
TDECompletion
TDECompletion::setItems
virtual void setItems(const TQStringList &list)
TDECompletion::setIgnoreCase
virtual void setIgnoreCase(bool ignoreCase)
TDEShortcut::contains
bool contains(const KKey &key) const
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
TDEStdAccel::replace
const TDEShortcut & replace()
tdelocale.h

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.1
This website is maintained by Timothy Pearson.