/* This file is part of the KDE libraries and the Kate part. * * Copyright (C) 2003-2005 Anders Lund * Copyright (C) 2001-2010 Christoph Cullmann * Copyright (C) 2001 Charles Samuels * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "katecmds.h" #include "katedocument.h" #include "kateview.h" #include "kateconfig.h" #include "kateautoindent.h" #include "katetextline.h" #include "katesyntaxmanager.h" #include "kateglobal.h" #include "katerenderer.h" #include "katecmd.h" #include #include #include #include #include #include //BEGIN CoreCommands KateCommands::CoreCommands* KateCommands::CoreCommands::m_instance = 0; // this returns wheather the string s could be converted to // a bool value, one of on|off|1|0|true|false. the argument val is // set to the extracted value in case of success static bool getBoolArg( const QString &t, bool *val ) { bool res( false ); QString s = t.toLower(); res = (s == "on" || s == "1" || s == "true"); if ( res ) { *val = true; return true; } res = (s == "off" || s == "0" || s == "false"); if ( res ) { *val = false; return true; } return false; } const QStringList &KateCommands::CoreCommands::cmds() { static QStringList l; if (l.isEmpty()) l << "indent" << "unindent" << "cleanindent" << "fold" << "tfold" << "unfold" << "comment" << "uncomment" << "goto" << "kill-line" << "set-tab-width" << "set-replace-tabs" << "set-show-tabs" << "set-indent-width" << "set-indent-mode" << "set-auto-indent" << "set-line-numbers" << "set-folding-markers" << "set-icon-border" << "set-indent-pasted-text" << "set-word-wrap" << "set-word-wrap-column" << "set-replace-tabs-save" << "set-remove-trailing-spaces" << "set-highlight" << "set-mode" << "set-show-indent" << "print"; return l; } bool KateCommands::CoreCommands::help(KTextEditor::View *, const QString &cmd, QString &msg) { QString realcmd=cmd.trimmed(); if (realcmd=="indent") { msg=i18n("

indent

" "

Indents the selected lines or the current line

"); return true; } else if (realcmd=="unindent") { msg=i18n("

unindent

" "

Unindents the selected lines or current line.

"); return true; } else if (realcmd=="cleanindent") { msg=i18n("

cleanindent

" "

Cleans up the indentation of the selected lines or current line according to the indentation settings in the document.

"); return true; } else if (realcmd=="comment") { msg=i18n("

comment

" "

Inserts comment markers to make the selection or selected lines or current line a comment according to the text format as defined by the syntax highlight definition for the document.

"); return true; } else if (realcmd=="uncomment") { msg=i18n("

uncomment

" "

Removes comment markers from the selection or selected lines or current line according to the text format as defined by the syntax highlight definition for the document.

"); return true; } else if (realcmd=="goto") { msg=i18n("

goto line number

" "

This command navigates to the specified line number.

"); return true; } else if (realcmd=="set-indent-pasted-text") { msg=i18n("

set-indent-pasted-text enable

" "

If enabled, indentation of text pasted from the clipboard is adjusted using the current indenter.

" "

Possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="kill-line") { msg=i18n("Deletes the current line."); return true; } else if (realcmd=="set-tab-width") { msg=i18n("

set-tab-width width

" "

Sets the tab width to the number width

"); return true; } else if (realcmd=="set-replace-tab") { msg=i18n("

set-replace-tab enable

" "

If enabled, tabs are replaced with spaces as you type.

" "

Possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-show-tabs") { msg=i18n("

set-show-tabs enable

" "

If enabled, TAB characters and trailing whitespace will be visualized by a small dot.

" "

Possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-remove-trailing-spaces") { msg=i18n("

set-remove-trailing-spaces mode

" "

Removes the trailing spaces in the document depending on the mode.

" "

Possible values:" "

    " "
  • none: never remove trailing spaces.
  • " "
  • modified: remove trailing spaces only of modified lines.
  • " "
  • all: remove trailing spaces in the entire document.
  • " "

"); return true; } else if (realcmd=="set-indent-width") { msg=i18n("

set-indent-width width

" "

Sets the indentation width to the number width. Used only if you are indenting with spaces.

"); return true; } else if (realcmd=="set-indent-mode") { msg=i18n("

set-indent-mode mode

" "

The mode parameter is a value as seen in the Tools - Indentation menu

"); return true; } else if (realcmd=="set-auto-indent") { msg=i18n("

set-auto-indent enable

" "

Enable or disable autoindentation.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-line-numbers") { msg=i18n("

set-line-numbers enable

" "

Sets the visibility of the line numbers pane.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-folding-markers") { msg=i18n("

set-folding-markers enable

" "

Sets the visibility of the folding markers pane.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-icon-border") { msg=i18n("

set-icon-border enable

" "

Sets the visibility of the icon border.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-word-wrap") { msg=i18n("

set-word-wrap enable

" "

Enables dynamic word wrap according to enable

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-word-wrap-column") { msg=i18n("

set-word-wrap-column width

" "

Sets the line width for hard wrapping to width. This is used if you are having your text wrapped automatically.

"); return true; } else if (realcmd=="set-replace-tabs-save") { msg=i18n("

set-replace-tabs-save enable

" "

When enabled, tabs will be replaced with whitespace whenever the document is saved.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="set-highlight") { msg=i18n("

set-highlight highlight

" "

Sets the syntax highlighting system for the document. The argument must be a valid highlight name, as seen in the Tools → Highlighting menu. This command provides an autocompletion list for its argument.

"); return true; } else if (realcmd=="set-mode") { msg=i18n("

set-mode mode

" "

Sets the mode as seen in Tools - Mode

"); return true; } else if (realcmd=="set-show-indent") { msg=i18n("

set-show-indent enable

" "

If enabled, indentation will be visualized by a vertical dotted line.

" "

possible true values: 1 on true
" "possible false values: 0 off false

"); return true; } else if (realcmd=="print") { msg=i18n("

Open the Print dialog to print the current document.

"); return true; } else return false; } bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg) { return exec( view, _cmd, errorMsg, KTextEditor::Range::invalid() ); } bool KateCommands::CoreCommands::exec(KTextEditor::View *view, const QString &_cmd, QString &errorMsg, const KTextEditor::Range& range) { #define KCC_ERR(s) { errorMsg=s; return false; } // cast it hardcore, we know that it is really a kateview :) KateView *v = static_cast(view); if ( ! v ) KCC_ERR( i18n("Could not access view") ); //create a list of args QStringList args(_cmd.split( QRegExp("\\s+"), QString::SkipEmptyParts)) ; QString cmd ( args.takeFirst() ); // ALL commands that takes no arguments. if ( cmd == "indent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), 1 ); } v->doc()->editEnd(); } else { v->indent(); } return true; } else if ( cmd == "unindent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), -1 ); } v->doc()->editEnd(); } else { v->unIndent(); } return true; } else if ( cmd == "cleanindent" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->indent( KTextEditor::Range(line, 0, line, 0), 0 ); } v->doc()->editEnd(); } else { v->cleanIndent(); } return true; } else if ( cmd == "fold" ) { return (v->textFolding().newFoldingRange (range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Persistent | Kate::TextFolding::Folded) != -1); } else if ( cmd == "tfold" ) { return (v->textFolding().newFoldingRange (range.isValid() ? range : v->selectionRange(), Kate::TextFolding::Folded) != -1); } else if ( cmd == "unfold" ) { QVector > startingRanges = v->textFolding().foldingRangesStartingOnLine (v->cursorPosition().line()); bool unfolded = false; for (int i = 0; i < startingRanges.size(); ++i) { if (startingRanges[i].second & Kate::TextFolding::Folded) { unfolded = v->textFolding().unfoldRange (startingRanges[i].first) || unfolded; } } return unfolded; } else if ( cmd == "comment" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->comment( v, line, 0, 1 ); } v->doc()->editEnd(); } else { v->comment(); } return true; } else if ( cmd == "uncomment" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->comment( v, line, 0, -1 ); } v->doc()->editEnd(); } else { v->uncomment(); } return true; } else if ( cmd == "kill-line" ) { if ( range.isValid() ) { v->doc()->editStart(); for ( int line = range.start().line(); line <= range.end().line(); line++ ) { v->doc()->removeLine( range.start().line() ); } v->doc()->editEnd(); } else { v->killLine(); } return true; } else if ( cmd == "print" ) { v->doc()->printDialog(); return true; } // ALL commands that take a string argument else if ( cmd == "set-indent-mode" || cmd == "set-highlight" || cmd == "set-mode" ) { // need at least one item, otherwise args.first() crashes if ( ! args.count() ) KCC_ERR( i18n("Missing argument. Usage: %1 ", cmd ) ); if ( cmd == "set-indent-mode" ) { v->doc()->config()->setIndentationMode( args.join(" ") ); v->doc()->rememberUserDidSetIndentationMode (); return true; } else if ( cmd == "set-highlight" ) { if ( v->doc()->setHighlightingMode( args.first()) ) { static_cast(v->doc())->setDontChangeHlOnSave (); return true; } KCC_ERR( i18n("No such highlighting '%1'", args.first() ) ); } else if ( cmd == "set-mode" ) { if ( v->doc()->setMode( args.first()) ) return true; KCC_ERR( i18n("No such mode '%1'", args.first() ) ); } } // ALL commands that takes exactly one integer argument. else if ( cmd == "set-tab-width" || cmd == "set-indent-width" || cmd == "set-word-wrap-column" || cmd == "goto" ) { // find a integer value > 0 if ( ! args.count() ) KCC_ERR( i18n("Missing argument. Usage: %1 ", cmd ) ); bool ok; int val ( args.first().toInt( &ok, 10 ) ); // use base 10 even if the string starts with '0' if ( !ok ) KCC_ERR( i18n("Failed to convert argument '%1' to integer.", args.first() ) ); if ( cmd == "set-tab-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->doc()->config()->setTabWidth( val ); } else if ( cmd == "set-indent-width" ) { if ( val < 1 ) KCC_ERR( i18n("Width must be at least 1.") ); v->doc()->config()->setIndentationWidth( val ); } else if ( cmd == "set-word-wrap-column" ) { if ( val < 2 ) KCC_ERR( i18n("Column must be at least 1.") ); v->doc()->setWordWrapAt( val ); } else if ( cmd == "goto" ) { if ( args.first().at(0) == '-' || args.first().at(0) == '+' ) { // if the number starts with a minus or plus sign, add/subract the number val = v->cursorPosition().line() + val; } else { val--; // convert given line number to the internal representation of line numbers } // constrain cursor to the range [0, number of lines] if ( val < 0 ) { val = 0; } else if ( val > v->doc()->lines()-1 ) { val = v->doc()->lines()-1; } v->setCursorPosition( KTextEditor::Cursor( val, 0 ) ); return true; } return true; } // ALL commands that takes 1 boolean argument. else if ( cmd == "set-icon-border" || cmd == "set-folding-markers" || cmd == "set-indent-pasted-text" || cmd == "set-line-numbers" || cmd == "set-replace-tabs" || cmd == "set-show-tabs" || cmd == "set-word-wrap" || cmd == "set-wrap-cursor" || cmd == "set-replace-tabs-save" || cmd == "set-show-indent" ) { if ( ! args.count() ) KCC_ERR( i18n("Usage: %1 on|off|1|0|true|false", cmd ) ); bool enable = false; KateDocumentConfig * const config = v->doc()->config(); if ( getBoolArg( args.first(), &enable ) ) { if ( cmd == "set-icon-border" ) v->setIconBorder( enable ); else if (cmd == "set-folding-markers") v->setFoldingMarkersOn( enable ); else if ( cmd == "set-line-numbers" ) v->setLineNumbersOn( enable ); else if ( cmd == "set-show-indent" ) v->renderer()->setShowIndentLines( enable ); else if (cmd == "set-indent-pasted-text") config->setIndentPastedText( enable ); else if ( cmd == "set-replace-tabs" ) config->setReplaceTabsDyn( enable ); else if ( cmd == "set-show-tabs" ) config->setShowTabs( enable ); else if ( cmd == "set-show-trailing-spaces" ) config->setShowSpaces( enable ); else if ( cmd == "set-word-wrap" ) v->doc()->setWordWrap( enable ); return true; } else KCC_ERR( i18n("Bad argument '%1'. Usage: %2 on|off|1|0|true|false", args.first() , cmd ) ); } else if ( cmd == "set-remove-trailing-spaces" ) { // need at least one item, otherwise args.first() crashes if ( args.count() != 1 ) KCC_ERR( i18n("Usage: set-remove-trailing-spaces 0|-|none or 1|+|mod|modified or 2|*|all") ); QString tmp = args.first().toLower().trimmed(); if (tmp == "1" || tmp == "modified" || tmp == "mod" || tmp == "+") { v->doc()->config()->setRemoveSpaces(1); } else if (tmp == "2" || tmp == "all" || tmp == "*") { v->doc()->config()->setRemoveSpaces(2); } else { v->doc()->config()->setRemoveSpaces(0); } } // unlikely.. KCC_ERR( i18n("Unknown command '%1'", cmd) ); } bool KateCommands::CoreCommands::supportsRange(const QString &range) { static QStringList l; if (l.isEmpty()) l << "indent" << "unindent" << "cleanindent" << "comment" << "uncomment" << "kill-line" << "fold" << "tfold"; return l.contains(range); } KCompletion *KateCommands::CoreCommands::completionObject( KTextEditor::View *view, const QString &cmd ) { Q_UNUSED(view) if ( cmd == "set-highlight" ) { QStringList l; for ( int i = 0; i < KateHlManager::self()->highlights(); i++ ) l << KateHlManager::self()->hlName (i); KateCmdShellCompletion *co = new KateCmdShellCompletion(); co->setItems( l ); co->setIgnoreCase( true ); return co; } else if ( cmd == "set-remove-trailing-spaces" ) { QStringList l; l << "none" << "modified" << "all"; KateCmdShellCompletion *co = new KateCmdShellCompletion(); co->setItems( l ); co->setIgnoreCase( true ); return co; } else if ( cmd == "set-indent-mode" ) { QStringList l = KateAutoIndent::listIdentifiers(); KateCmdShellCompletion *co = new KateCmdShellCompletion(); co->setItems( l ); co->setIgnoreCase( true ); return co; } return 0L; } //END CoreCommands // BEGIN AppCommands KateCommands::AppCommands* KateCommands::AppCommands::m_instance = 0; KateCommands::AppCommands::AppCommands() : KTextEditor::Command() { re_write.setPattern("w"); // temporarily add :w //re_write.setPattern("w(a)?"); //re_quit.setPattern("(w)?q?(a)?"); //re_exit.setPattern("x(a)?"); //re_changeBuffer.setPattern("b(n|p)"); //re_edit.setPattern("e(dit)?"); //re_new.setPattern("(v)?new"); } const QStringList& KateCommands::AppCommands::cmds() { static QStringList l; if (l.empty()) { //l << "q" << "qa" << "w" << "wq" << "wa" << "wqa" << "x" << "xa" //<< "bn" << "bp" << "new" << "vnew" << "e" << "edit" << "enew"; l << "w"; } return l; } // commands that don't need to live in the hosting application should be // implemented here. things such as quitting and splitting the view can not be // done from the editor part and needs to be implemented in the hosting // application. bool KateCommands::AppCommands::exec(KTextEditor::View *view, const QString &cmd, QString &msg ) { QStringList args(cmd.split( QRegExp("\\s+"), QString::SkipEmptyParts)) ; QString command( args.takeFirst() ); QString file = args.join(QString(' ')); if (re_write.exactMatch(command)) { // w, wa /* if (!re_write.cap(1).isEmpty()) { // [a]ll view->document()->saveAll(); msg = i18n("All documents written to disk"); } else { // w*/ // Save file if (file.isEmpty()) { view->document()->documentSave(); } else { KUrl base = view->document()->url(); KUrl url( base.isValid() ? base : KUrl( QDir::homePath() ), file ); view->document()->saveAs( url ); } msg = i18n("Document written to disk"); } return true; } bool KateCommands::AppCommands::help(KTextEditor::View *view, const QString &cmd, QString &msg) { Q_UNUSED(view); if (re_write.exactMatch(cmd)) { msg = i18n("

w/wa — write document(s) to disk

" "

Usage: w[a]

" "

Writes the current document(s) to disk. " "It can be called in two ways:
" " w — writes the current document to disk
" " wa — writes all document to disk.

" "

If no file name is associated with the document, " "a file dialog will be shown.

"); return true; } return false; } //END AppCommands //BEGIN SedReplace KateCommands::SedReplace* KateCommands::SedReplace::m_instance = 0; static int backslashString(const QString &haystack, const QString &needle, int index) { int len = haystack.length(); int searchlen = needle.length(); bool evenCount = true; while (index < len) { if (haystack[index] == '\\') { evenCount = !evenCount; } else { // isn't a slash if (!evenCount) { if (haystack.mid(index, searchlen) == needle) return index - 1; } evenCount = true; } ++index; } return -1; } // exchange "\t" for the actual tab character, for example static void exchangeAbbrevs(QString &str) { // the format is (findreplace)*[nullzero] const char *magic = "a\x07t\tn\n"; while (*magic) { int index = 0; char replace = magic[1]; while ((index = backslashString(str, QString (QChar::fromAscii(*magic)), index)) != -1) { str.replace(index, 2, QChar(replace)); ++index; } ++magic; ++magic; } } bool KateCommands::SedReplace::exec (KTextEditor::View *view, const QString &cmd, QString &msg) { return exec(view, cmd, msg, KTextEditor::Range::invalid()); } bool KateCommands::SedReplace::exec (class KTextEditor::View *view, const QString &cmd, QString &msg, const KTextEditor::Range &r) { kDebug(13025) << "SedReplace::execCmd( " << cmd << " )"; if (r.isValid()) { kDebug(13025) << "Range: " << r; } int findBeginPos = -1; int findEndPos = -1; int replaceBeginPos = -1; int replaceEndPos = -1; QString delimiter; if (!parse(cmd, delimiter, findBeginPos, findEndPos, replaceBeginPos, replaceEndPos)) { return false; } const QString searchParamsString = cmd.mid(cmd.lastIndexOf(delimiter)); const bool noCase = searchParamsString.contains('i'); const bool repeat = searchParamsString.contains('g'); const bool interactive = searchParamsString.contains('c'); QString find = cmd.mid(findBeginPos, findEndPos - findBeginPos + 1); kDebug(13025) << "SedReplace: find =" << find; QString replace = cmd.mid(replaceBeginPos, replaceEndPos - replaceBeginPos + 1); exchangeAbbrevs(replace); kDebug(13025) << "SedReplace: replace =" << replace; if (find.isEmpty()) { // Nothing to do. return true; } KateView *kateView = static_cast(view); KateDocument *doc = kateView->doc(); if ( !doc ) return false; // Only current line ... int startLine = kateView->cursorPosition().line(); int endLine = kateView->cursorPosition().line(); // ... unless a range was provided. if (r.isValid()) { startLine = r.start().line(); endLine = r.end().line(); } QSharedPointer interactiveSedReplacer(new InteractiveSedReplacer(doc, find, replace, !noCase, !repeat, startLine, endLine)); if (interactive) { kDebug(13025) << "Interactive sedreplace is only currently supported with Vi mode plus Vi emulated command bar."; return false; } kateView->setSearchPattern(find); interactiveSedReplacer->replaceAllRemaining(); msg = interactiveSedReplacer->finalStatusReportMessage(); return true; } bool KateCommands::SedReplace::parse(const QString& sedReplaceString, QString& destDelim, int& destFindBeginPos, int& destFindEndPos, int& destReplaceBeginPos, int& destReplaceEndPos) { // valid delimiters are all non-word, non-space characters plus '_' QRegExp delim("^s\\s*([^\\w\\s]|_)"); if ( delim.indexIn( sedReplaceString ) < 0 ) return false; QString d = delim.cap(1); kDebug(13025) << "SedReplace: delimiter is '" << d << "'"; QRegExp splitter( QString("^s\\s*") + d + "((?:[^\\\\\\" + d + "]|\\\\.)*)\\" + d + "((?:[^\\\\\\" + d + "]|\\\\.)*)(\\" + d + "[igc]{0,3})?$" ); if (splitter.indexIn(sedReplaceString) < 0) return false; const QString find = splitter.cap(1); const QString replace = splitter.cap(2); destDelim = d; destFindBeginPos = splitter.pos(1); destFindEndPos = splitter.pos(1) + find.length() - 1; destReplaceBeginPos = splitter.pos(2); destReplaceEndPos = splitter.pos(2) + replace.length() - 1; return true; } KateCommands::SedReplace::InteractiveSedReplacer::InteractiveSedReplacer(KateDocument* doc, const QString& findPattern, const QString& replacePattern, bool caseSensitive, bool onlyOnePerLine, int startLine, int endLine) : m_findPattern(findPattern), m_replacePattern(replacePattern), m_onlyOnePerLine(onlyOnePerLine), m_endLine(endLine), m_doc(doc), m_regExpSearch(doc, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive), m_numReplacementsDone(0), m_numLinesTouched(0), m_lastChangedLineNum(-1) { m_currentSearchPos = KTextEditor::Cursor(startLine, 0); } KTextEditor::Range KateCommands::SedReplace::InteractiveSedReplacer::currentMatch() { QVector matches = fullCurrentMatch(); if (matches.isEmpty()) { return KTextEditor::Range::invalid(); } if (matches.first().start().line() > m_endLine) { return KTextEditor::Range::invalid(); } return matches.first(); } void KateCommands::SedReplace::InteractiveSedReplacer::skipCurrentMatch() { const KTextEditor::Range currentMatch = this->currentMatch(); m_currentSearchPos = currentMatch.end(); if (m_onlyOnePerLine && currentMatch.start().line() == m_currentSearchPos.line()) { m_currentSearchPos = KTextEditor::Cursor(m_currentSearchPos.line() + 1, 0); } } void KateCommands::SedReplace::InteractiveSedReplacer::replaceCurrentMatch() { const KTextEditor::Range currentMatch = this->currentMatch(); const QString currentMatchText = m_doc->text(currentMatch); const QString replacementText = replacementTextForCurrentMatch(); m_doc->editBegin(); m_doc->removeText(currentMatch); m_doc->insertText(currentMatch.start(), replacementText); m_doc->editEnd(); // Begin next search from directly after replacement. if (!replacementText.contains('\n')) { const int moveChar = currentMatch.isEmpty() ? 1 : 0; // if the search was for \s*, make sure we advance a char const int col = currentMatch.start().column() + replacementText.length() + moveChar; m_currentSearchPos = KTextEditor::Cursor(currentMatch.start().line(), col); } else { m_currentSearchPos = KTextEditor::Cursor(currentMatch.start().line() + replacementText.count('\n'), replacementText.length() - replacementText.lastIndexOf('\n') - 1); } if (m_onlyOnePerLine) { // Drop down to next line. m_currentSearchPos = KTextEditor::Cursor(m_currentSearchPos.line() + 1, 0); } // Adjust end line down by the number of new newlines just added, minus the number taken away. m_endLine += replacementText.count('\n'); m_endLine -= currentMatchText.count('\n'); m_numReplacementsDone++; if (m_lastChangedLineNum != currentMatch.start().line()) { // Counting "swallowed" lines as being "touched". m_numLinesTouched += currentMatchText.count('\n') + 1; } m_lastChangedLineNum = m_currentSearchPos.line(); } void KateCommands::SedReplace::InteractiveSedReplacer::replaceAllRemaining() { m_doc->editBegin(); while (currentMatch().isValid()) { replaceCurrentMatch(); } m_doc->editEnd(); } QString KateCommands::SedReplace::InteractiveSedReplacer::currentMatchReplacementConfirmationMessage() { return i18n("replace with %1?", replacementTextForCurrentMatch().replace('\n', "\\n")); } QString KateCommands::SedReplace::InteractiveSedReplacer::finalStatusReportMessage() { return i18ncp("%2 is the translation of the next message", "1 replacement done on %2", "%1 replacements done on %2", m_numReplacementsDone, i18ncp("substituted into the previous message", "1 line", "%1 lines", m_numLinesTouched)); } const QVector< KTextEditor::Range > KateCommands::SedReplace::InteractiveSedReplacer::fullCurrentMatch() { if (m_currentSearchPos > m_doc->documentEnd()) { return QVector(); } return m_regExpSearch.search(m_findPattern, KTextEditor::Range(m_currentSearchPos, m_doc->documentEnd())); } QString KateCommands::SedReplace::InteractiveSedReplacer::replacementTextForCurrentMatch() { const KTextEditor::Range currentMatch = this->currentMatch(); const QVector captureRanges = fullCurrentMatch(); QStringList captureTexts; foreach(const KTextEditor::Range& captureRange, captureRanges) { captureTexts << m_doc->text(captureRange); } const QString replacementText = m_regExpSearch.buildReplacement(m_replacePattern, captureTexts, 0); return replacementText; } //END SedReplace //BEGIN Character KateCommands::Character* KateCommands::Character::m_instance = 0; bool KateCommands::Character::help (class KTextEditor::View *, const QString &cmd, QString &msg) { if (cmd.trimmed()=="char") { msg = i18n("

char identifier

" "

This command allows you to insert literal characters by their numerical identifier, in decimal, octal or hexadecimal form.

" "

Examples:

    " "
  • char 234
  • " "
  • char 0x1234
  • " "

"); return true; } return false; } bool KateCommands::Character::exec (KTextEditor::View *view, const QString &_cmd, QString &) { QString cmd = _cmd; // hex, octal, base 9+1 QRegExp num("^char *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,5})$"); if (num.indexIn(cmd)==-1) return false; cmd=num.cap(1); // identify the base unsigned short int number=0; int base=10; if (cmd[0]=='x' || cmd.startsWith(QLatin1String("0x"))) { cmd.remove(QRegExp("^0?x")); base=16; } else if (cmd[0]=='0') base=8; bool ok; number=cmd.toUShort(&ok, base); if (!ok || number==0) return false; if (number<=255) { char buf[2]; buf[0]=(char)number; buf[1]=0; view->document()->insertText(view->cursorPosition(), QString(buf)); } else { // do the unicode thing QChar c(number); view->document()->insertText(view->cursorPosition(), QString(&c, 1)); } return true; } //END Character //BEGIN Date KateCommands::Date* KateCommands::Date::m_instance = 0; bool KateCommands::Date::help (class KTextEditor::View *, const QString &cmd, QString &msg) { if (cmd.trimmed()=="date") { msg = i18n("

date or date format

" "

Inserts a date/time string as defined by the specified format, or the format yyyy-MM-dd hh:mm:ss if none is specified.

" "

Possible format specifiers are:" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "
dThe day as number without a leading zero (1-31).
ddThe day as number with a leading zero (01-31).
dddThe abbreviated localized day name (e.g. 'Mon'..'Sun').
ddddThe long localized day name (e.g. 'Monday'..'Sunday').
MThe month as number without a leading zero (1-12).
MMThe month as number with a leading zero (01-12).
MMMThe abbreviated localized month name (e.g. 'Jan'..'Dec').
yyThe year as two digit number (00-99).
yyyyThe year as four digit number (1752-8000).
hThe hour without a leading zero (0..23 or 1..12 if AM/PM display).
hhThe hour with a leading zero (00..23 or 01..12 if AM/PM display).
mThe minute without a leading zero (0..59).
mmThe minute with a leading zero (00..59).
sThe second without a leading zero (0..59).
ssThe second with a leading zero (00..59).
zThe milliseconds without leading zeroes (0..999).
zzzThe milliseconds with leading zeroes (000..999).
APUse AM/PM display. AP will be replaced by either \"AM\" or \"PM\".
apUse am/pm display. ap will be replaced by either \"am\" or \"pm\".

"); return true; } return false; } bool KateCommands::Date::exec (KTextEditor::View *view, const QString &cmd, QString &) { if (!cmd.startsWith(QLatin1String("date"))) return false; if (QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5)).length() > 0) view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString(cmd.mid(5, cmd.length()-5))); else view->document()->insertText(view->cursorPosition(), QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")); return true; } //END Date // kate: space-indent on; indent-width 2; replace-tabs on;