[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [ktexteditor] src: Move CommandMode into its own source files.
From: Simon St James <kdedevel () etotheipiplusone ! com>
Date: 2016-06-17 8:18:10
Message-ID: E1bDoyg-0002ZN-Mr () scm ! kde ! org
[Download RAW message or body]
Git commit 765d8e684c37432c17c0bde30473f472b64ea0f3 by Simon St James.
Committed on 17/06/2016 at 08:14.
Pushed by sstjames into branch 'master'.
Move CommandMode into its own source files.
M +1 -0 src/CMakeLists.txt
M +5 -3 src/include/ktexteditor/command.h
A +394 -0 src/vimode/emulatedcommandbar/commandmode.cpp [License: UNKNOWN] \
* A +80 -0 src/vimode/emulatedcommandbar/commandmode.h [License: UNKNOWN] \
* M +1 -378 src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
M +1 -57 src/vimode/emulatedcommandbar/emulatedcommandbar.h
The files marked with a * at the end have a non valid license. Please read: \
http://techbase.kde.org/Policies/Licensing_Policy and use the headers which are \
listed at that page.
http://commits.kde.org/ktexteditor/765d8e684c37432c17c0bde30473f472b64ea0f3
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 51374c7..25ac61a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -281,6 +281,7 @@ if (BUILD_VIMODE)
vimode/emulatedcommandbar/activemode.cpp
vimode/emulatedcommandbar/interactivesedreplacemode.cpp
vimode/emulatedcommandbar/searchmode.cpp
+ vimode/emulatedcommandbar/commandmode.cpp
vimode/commandrangeexpressionparser.cpp
vimode/keymapper.cpp
vimode/marks.cpp
diff --git a/src/include/ktexteditor/command.h b/src/include/ktexteditor/command.h
index f65d11b..3d57ef4 100644
--- a/src/include/ktexteditor/command.h
+++ b/src/include/ktexteditor/command.h
@@ -24,6 +24,8 @@
#include <ktexteditor_export.h>
#include <ktexteditor/range.h>
+#include <KCompletion>
+
#include <QObject>
class QStringList;
@@ -112,7 +114,7 @@ public:
{
return m_cmds;
}
-
+
/**
* Find out if a given command can act on a range. This is used for checking
* if a command should be called when the user also gave a range or if an
@@ -130,7 +132,7 @@ public:
* of replaced strings as \p msg, like "16 replacements made." If an error
* occurred in the usage it would return \e false and set the \p msg to
* something like "missing argument." or such.
- *
+ *
* If a non-invalid range is given, the command shall be executed on that range.
* supportsRange() tells if the command supports that.
*
@@ -198,7 +200,7 @@ private:
* the command list this command got constructed with
*/
const QStringList m_cmds;
-
+
/**
* Private d-pointer
*/
diff --git a/src/vimode/emulatedcommandbar/commandmode.cpp \
b/src/vimode/emulatedcommandbar/commandmode.cpp new file mode 100644
index 0000000..215b5d0
--- /dev/null
+++ b/src/vimode/emulatedcommandbar/commandmode.cpp
@@ -0,0 +1,394 @@
+#include "commandmode.h"
+
+#include "emulatedcommandbar.h"
+#include "interactivesedreplacemode.h"
+#include "searchmode.h"
+#include "../commandrangeexpressionparser.h"
+
+#include <vimode/appcommands.h>
+#include <vimode/cmds.h>
+#include <vimode/inputmodemanager.h>
+#include "../globalstate.h"
+#include "../history.h"
+
+#include "katescriptmanager.h"
+#include "katecmds.h"
+
+#include <KLocalizedString>
+
+#include <QLineEdit>
+#include <QWhatsThis>
+
+using namespace KateVi;
+
+CommandMode::CommandMode ( EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit, \
InteractiveSedReplaceMode *interactiveSedReplaceMode, Completer* completer) + : \
ActiveMode ( emulatedCommandBar, matchHighlighter ), + m_edit(edit),
+ m_view(view),
+ m_interactiveSedReplaceMode(interactiveSedReplaceMode),
+ m_completer(completer)
+{
+ QList<KTextEditor::Command *> cmds;
+
+ cmds.push_back(KateCommands::CoreCommands::self());
+ cmds.push_back(Commands::self());
+ cmds.push_back(AppCommands::self());
+ cmds.push_back(SedReplace::self());
+ cmds.push_back(BufferCommands::self());
+
+ Q_FOREACH (KTextEditor::Command *cmd, \
KateScriptManager::self()->commandLineScripts()) { + cmds.push_back(cmd);
+ }
+
+ Q_FOREACH (KTextEditor::Command *cmd, cmds) {
+ QStringList l = cmd->cmds();
+
+ for (int z = 0; z < l.count(); z++) {
+ m_cmdDict.insert(l[z], cmd);
+ }
+
+ m_cmdCompletion.insertItems(l);
+ }
+}
+
+void CommandMode::setViInputModeManager ( InputModeManager* viInputModeManager )
+{
+ m_viInputModeManager = viInputModeManager;
+}
+
+bool CommandMode::handleKeyPress ( const QKeyEvent* keyEvent )
+{
+ if (keyEvent->modifiers() == Qt::ControlModifier && (keyEvent->key() == \
Qt::Key_D || keyEvent->key() == Qt::Key_F)) { + \
CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression(); + \
if (parsedSedExpression.parsedSuccessfully) { + const bool clearFindTerm = \
(keyEvent->key() == Qt::Key_D); + if (clearFindTerm) {
+ m_edit->setSelection(parsedSedExpression.findBeginPos, \
parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + 1); + \
m_edit->insert(QString()); + } else {
+ // Clear replace term.
+ m_edit->setSelection(parsedSedExpression.replaceBeginPos, \
parsedSedExpression.replaceEndPos - parsedSedExpression.replaceBeginPos + 1); + \
m_edit->insert(QString()); + }
+ }
+ return true;
+ }
+ return false;
+}
+
+void CommandMode::editTextChanged ( const QString& newText )
+{
+ Q_UNUSED(newText); // We read the current text from m_edit.
+ if (m_completer->isCompletionActive())
+ return;
+ // Command completion doesn't need to be manually invoked.
+ if (!withoutRangeExpression().isEmpty() && \
!m_completer->isNextTextChangeDueToCompletionChange()) { + // ... However, \
command completion mode should not be automatically invoked if this is not the \
current leading + // word in the text edit (it gets annoying if completion \
pops up after ":s/se" etc). + const bool commandBeforeCursorIsLeading = \
(commandBeforeCursorBegin() == rangeExpression().length()); + if \
(commandBeforeCursorIsLeading) { + CompletionStartParams \
completionStartParams = activateCommandCompletion(); + \
startCompletion(completionStartParams); + }
+ }
+}
+
+void CommandMode::deactivate ( bool wasAborted )
+{
+ if (wasAborted) {
+ // Appending the command to the history when it is executed is handled \
elsewhere; we can't + // do it inside closed() as we may still be showing the \
command response display. + \
m_viInputModeManager->globalState()->commandHistory()->append(m_edit->text()); + \
// With Vim, aborting a command returns us to Normal mode, even if we were in Visual \
Mode. + // If we switch from Visual to Normal mode, we need to clear the \
selection. + m_view->clearSelection();
+ }
+
+}
+
+CompletionStartParams CommandMode::completionInvoked(Completer::CompletionInvocation \
invocationType) +{
+ CompletionStartParams completionStartParams;
+ if (invocationType == Completer::CompletionInvocation::ExtraContext)
+ {
+ if (isCursorInFindTermOfSed()) {
+ completionStartParams = activateSedFindHistoryCompletion();
+ } else if (isCursorInReplaceTermOfSed()) {
+ completionStartParams = activateSedReplaceHistoryCompletion();
+ } else {
+ completionStartParams = activateCommandHistoryCompletion();
+ }
+ }
+ else
+ {
+ // Normal context, so boring, ordinary History completion.
+ completionStartParams = activateCommandHistoryCompletion();
+ }
+ return completionStartParams;
+}
+
+void CommandMode::completionChosen()
+{
+ QString commandToExecute = m_edit->text();
+ CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ if (parsedSedExpression.parsedSuccessfully) {
+ const QString originalFindTerm = sedFindTerm();
+ const QString convertedFindTerm = \
vimRegexToQtRegexPattern(originalFindTerm); + const QString \
commandWithSedSearchRegexConverted = withSedFindTermReplacedWith(convertedFindTerm); \
+ m_viInputModeManager->globalState()->searchHistory()->append(originalFindTerm);
+ const QString replaceTerm = sedReplaceTerm();
+ m_viInputModeManager->globalState()->replaceHistory()->append(replaceTerm);
+ commandToExecute = commandWithSedSearchRegexConverted;
+ }
+
+ const QString commandResponseMessage = executeCommand(commandToExecute);
+ // Don't close the bar if executing the command switched us to Interactive Sed \
Replace mode. + if (!m_interactiveSedReplaceMode->isActive()) {
+ if (commandResponseMessage.isEmpty()) {
+ m_emulatedCommandBar->hideMe();
+ } else {
+ closeWithStatusMessage(commandResponseMessage);
+ }
+ }
+ m_viInputModeManager->globalState()->commandHistory()->append(m_edit->text());
+
+}
+
+QString CommandMode::executeCommand ( const QString& commandToExecute )
+{
+ // Silently ignore leading space characters and colon characters (for vi-heads).
+ uint n = 0;
+ const uint textlen = commandToExecute.length();
+ while ((n < textlen) && commandToExecute[n].isSpace()) {
+ n++;
+ }
+
+ if (n >= textlen) {
+ return QString();
+ }
+
+ QString commandResponseMessage;
+ QString cmd = commandToExecute.mid(n);
+
+ KTextEditor::Range range = \
CommandRangeExpressionParser(m_viInputModeManager).parseRange(cmd, cmd); +
+ if (cmd.length() > 0) {
+ KTextEditor::Command *p = queryCommand(cmd);
+ KateViCommandInterface *ci = dynamic_cast<KateViCommandInterface*>(p);
+
+ if (ci) {
+ ci->setViInputModeManager(m_viInputModeManager);
+ ci->setViGlobal(m_viInputModeManager->globalState());
+ }
+
+ // The following commands changes the focus themselves, so bar should be \
hidden before execution. +
+ // We got a range and a valid command, but the command does not inherit the \
RangeCommand + // extension. Bail out.
+ if (range.isValid() && !p->supportsRange(cmd)) {
+ commandResponseMessage = i18n("Error: No range allowed for command \
\"%1\".", cmd); + } else {
+ if (p) {
+ if (p->exec(m_view, cmd, commandResponseMessage, range)) {
+
+ if (commandResponseMessage.length() > 0) {
+ commandResponseMessage = i18n("Success: ") + \
commandResponseMessage; + }
+ } else {
+ if (commandResponseMessage.length() > 0) {
+ if (commandResponseMessage.contains(QLatin1Char('\n'))) {
+ // multiline error, use widget with more space
+ \
QWhatsThis::showText(m_emulatedCommandBar->mapToGlobal(QPoint(0, 0)), \
commandResponseMessage); + }
+ } else {
+ commandResponseMessage = i18n("Command \"%1\" failed.", \
cmd); + }
+ }
+ } else {
+ commandResponseMessage = i18n("No such command: \"%1\"", cmd);
+ }
+ }
+ }
+
+ // the following commands change the focus themselves
+ if (!QRegExp(QLatin1String("buffer|b|new|vnew|bp|bprev|bn|bnext|bf|bfirst|bl|blast|edit|e")).exactMatch(cmd.split(QLatin1String(" \
")).at(0))) { + m_view->setFocus();
+ }
+
+ m_viInputModeManager->reset();
+ return commandResponseMessage;
+
+}
+
+
+QString CommandMode::withoutRangeExpression()
+{
+ const QString originalCommand = m_edit->text();
+ return originalCommand.mid(rangeExpression().length());
+}
+
+QString CommandMode::rangeExpression()
+{
+ const QString command = m_edit->text();
+ return CommandRangeExpressionParser(m_viInputModeManager).parseRangeString(command);
+}
+
+CommandMode::ParsedSedExpression CommandMode::parseAsSedExpression()
+{
+ const QString commandWithoutRangeExpression = withoutRangeExpression();
+ ParsedSedExpression parsedSedExpression;
+ QString delimiter;
+ parsedSedExpression.parsedSuccessfully = \
SedReplace::parse(commandWithoutRangeExpression, delimiter, \
parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos, \
parsedSedExpression.replaceBeginPos, parsedSedExpression.replaceEndPos); + if \
(parsedSedExpression.parsedSuccessfully) { + parsedSedExpression.delimiter = \
delimiter.at(0); + if (parsedSedExpression.replaceBeginPos == -1) {
+ if (parsedSedExpression.findBeginPos != -1) {
+ // The replace term was empty, and a quirk of the regex used is that \
replaceBeginPos will be -1. + // It's actually the position after the \
first occurrence of the delimiter after the end of the find pos. + \
parsedSedExpression.replaceBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.findEndPos) + 1; \
+ parsedSedExpression.replaceEndPos = \
parsedSedExpression.replaceBeginPos - 1; + } else {
+ // Both find and replace terms are empty; replace term is at the \
third occurrence of the delimiter. + \
parsedSedExpression.replaceBeginPos = 0; + for (int delimiterCount = \
1; delimiterCount <= 3; delimiterCount++) { + \
parsedSedExpression.replaceBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.replaceBeginPos \
+ 1); + }
+ parsedSedExpression.replaceEndPos = \
parsedSedExpression.replaceBeginPos - 1; + }
+ }
+ if (parsedSedExpression.findBeginPos == -1) {
+ // The find term was empty, and a quirk of the regex used is that \
findBeginPos will be -1. + // It's actually the position after the first \
occurrence of the delimiter. + parsedSedExpression.findBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter) + 1; + \
parsedSedExpression.findEndPos = parsedSedExpression.findBeginPos - 1; + }
+
+ }
+
+ if (parsedSedExpression.parsedSuccessfully) {
+ parsedSedExpression.findBeginPos += rangeExpression().length();
+ parsedSedExpression.findEndPos += rangeExpression().length();
+ parsedSedExpression.replaceBeginPos += rangeExpression().length();
+ parsedSedExpression.replaceEndPos += rangeExpression().length();
+ }
+ return parsedSedExpression;
+
+}
+
+QString CommandMode::sedFindTerm()
+{
+ const QString command = m_edit->text();
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ Q_ASSERT(parsedSedExpression.parsedSuccessfully);
+ return command.mid(parsedSedExpression.findBeginPos, \
parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + 1); +}
+
+QString CommandMode::sedReplaceTerm()
+{
+ const QString command = m_edit->text();
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ Q_ASSERT(parsedSedExpression.parsedSuccessfully);
+ return command.mid(parsedSedExpression.replaceBeginPos, \
parsedSedExpression.replaceEndPos - parsedSedExpression.replaceBeginPos + 1); +}
+
+QString CommandMode::withSedFindTermReplacedWith ( const QString& newFindTerm )
+{
+ const QString command = m_edit->text();
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ Q_ASSERT(parsedSedExpression.parsedSuccessfully);
+ return command.mid(0, parsedSedExpression.findBeginPos) +
+ newFindTerm +
+ command.mid(parsedSedExpression.findEndPos + 1);
+}
+
+QString CommandMode::withSedDelimiterEscaped ( const QString& text )
+{
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ QString delimiterEscaped = ensuredCharEscaped(text, \
parsedSedExpression.delimiter); + return delimiterEscaped;
+}
+
+bool CommandMode::isCursorInFindTermOfSed()
+{
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ return parsedSedExpression.parsedSuccessfully && (m_edit->cursorPosition() >= \
parsedSedExpression.findBeginPos && m_edit->cursorPosition() <= \
parsedSedExpression.findEndPos + 1); +}
+
+bool CommandMode::isCursorInReplaceTermOfSed()
+{
+ ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ return parsedSedExpression.parsedSuccessfully && m_edit->cursorPosition() >= \
parsedSedExpression.replaceBeginPos && m_edit->cursorPosition() <= \
parsedSedExpression.replaceEndPos + 1; +}
+
+int CommandMode::commandBeforeCursorBegin()
+{
+ const QString textWithoutRangeExpression = withoutRangeExpression();
+ const int cursorPositionWithoutRangeExpression = m_edit->cursorPosition() - \
rangeExpression().length(); + int commandBeforeCursorBegin = \
cursorPositionWithoutRangeExpression - 1; + while (commandBeforeCursorBegin >= 0 \
&& (textWithoutRangeExpression[commandBeforeCursorBegin].isLetterOrNumber() || \
textWithoutRangeExpression[commandBeforeCursorBegin] == QLatin1Char('_') || \
textWithoutRangeExpression[commandBeforeCursorBegin] == QLatin1Char('-'))) { + \
commandBeforeCursorBegin--; + }
+ commandBeforeCursorBegin++;
+ commandBeforeCursorBegin += rangeExpression().length();
+ return commandBeforeCursorBegin;
+}
+
+CompletionStartParams CommandMode::activateCommandCompletion()
+{
+ return CompletionStartParams::createModeSpecific(m_cmdCompletion.items(), \
commandBeforeCursorBegin()); +}
+
+CompletionStartParams CommandMode::activateCommandHistoryCompletion()
+{
+ return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->commandHistory()->items()), \
0); +}
+
+CompletionStartParams CommandMode::activateSedFindHistoryCompletion()
+{
+ if (m_viInputModeManager->globalState()->searchHistory()->isEmpty())
+ {
+ return CompletionStartParams::invalid();
+ }
+ CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->searchHistory()->items()),
+ \
parsedSedExpression.findBeginPos, + \
[this] (const QString& completion) -> QString { return \
withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(completion)); }); +}
+
+CompletionStartParams CommandMode::activateSedReplaceHistoryCompletion()
+{
+ if (m_viInputModeManager->globalState()->replaceHistory()->isEmpty())
+ {
+ return CompletionStartParams::invalid();
+ }
+ CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
+ return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->replaceHistory()->items()),
+ \
parsedSedExpression.replaceBeginPos, + \
[this] (const QString& completion) -> QString { return \
withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(completion)); }); +}
+
+KTextEditor::Command* CommandMode::queryCommand ( const QString& cmd ) const
+{
+ // a command can be named ".*[\w\-]+" with the constrain that it must
+ // contain at least one letter.
+ int f = 0;
+ bool b = false;
+
+ // special case: '-' and '_' can be part of a command name, but if the
+ // command is 's' (substitute), it should be considered the delimiter and
+ // should not be counted as part of the command name
+ if (cmd.length() >= 2 && cmd.at(0) == QLatin1Char('s') && (cmd.at(1) == \
QLatin1Char('-') || cmd.at(1) == QLatin1Char('_'))) { + return \
m_cmdDict.value(QStringLiteral("s")); + }
+
+ for (; f < cmd.length(); f++) {
+ if (cmd[f].isLetter()) {
+ b = true;
+ }
+ if (b && (! cmd[f].isLetterOrNumber() && cmd[f] != QLatin1Char('-') && \
cmd[f] != QLatin1Char('_'))) { + break;
+ }
+ }
+ return m_cmdDict.value(cmd.left(f));
+
+}
diff --git a/src/vimode/emulatedcommandbar/commandmode.h \
b/src/vimode/emulatedcommandbar/commandmode.h new file mode 100644
index 0000000..f160315
--- /dev/null
+++ b/src/vimode/emulatedcommandbar/commandmode.h
@@ -0,0 +1,80 @@
+#ifndef KATEVI_EMULATED_COMMAND_BAR_COMMANDMODE_H
+#define KATEVI_EMULATED_COMMAND_BAR_COMMANDMODE_H
+
+#include "activemode.h"
+
+#include <KTextEditor/Command>
+
+#include <QHash>
+
+namespace KTextEditor {
+ class ViewPrivate;
+}
+
+namespace KateVi
+{
+class EmulatedCommandBar;
+class MatchHighlighter;
+class InteractiveSedReplaceMode;
+class Completer;
+class InputModeManager;
+
+class CommandMode : public ActiveMode
+{
+public:
+ CommandMode(EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit, \
InteractiveSedReplaceMode *interactiveSedReplaceMode, Completer* completer); + \
virtual ~CommandMode() + {
+ }
+ void setViInputModeManager(InputModeManager *viInputModeManager);
+ virtual bool handleKeyPress ( const QKeyEvent* keyEvent );
+ virtual void editTextChanged(const QString &newText);
+ virtual CompletionStartParams completionInvoked(Completer::CompletionInvocation \
invocationType); + virtual void completionChosen();
+ void deactivate(bool wasAborted);
+ QString executeCommand(const QString &commandToExecute);
+private:
+ CompletionStartParams activateCommandCompletion();
+ CompletionStartParams activateCommandHistoryCompletion();
+ CompletionStartParams activateSedFindHistoryCompletion();
+ CompletionStartParams activateSedReplaceHistoryCompletion();
+ QString withoutRangeExpression();
+ QString rangeExpression();
+ QString withSedFindTermReplacedWith(const QString &newFindTerm);
+ QString withSedDelimiterEscaped(const QString &text);
+ bool isCursorInFindTermOfSed();
+ bool isCursorInReplaceTermOfSed();
+ QString sedFindTerm();
+ QString sedReplaceTerm();
+ /**
+ * Stuff to do with expressions of the form:
+ *
+ * s/find/replace/<sedflags>
+ */
+ struct ParsedSedExpression {
+ bool parsedSuccessfully;
+ int findBeginPos;
+ int findEndPos;
+ int replaceBeginPos;
+ int replaceEndPos;
+ QChar delimiter;
+ };
+ /**
+ * The "range expression" is the (optional) expression before the command \
that describes + * the range over which the command should be run e.g. '<,'>. \
@see CommandRangeExpressionParser + */
+ CommandMode::ParsedSedExpression parseAsSedExpression();
+ void replaceCommandBeforeCursorWith(const QString &newCommand);
+ int commandBeforeCursorBegin();
+ QLineEdit *m_edit;
+ InputModeManager *m_viInputModeManager = nullptr;
+ KTextEditor::ViewPrivate *m_view;
+ InteractiveSedReplaceMode *m_interactiveSedReplaceMode;
+ Completer *m_completer;
+ KCompletion m_cmdCompletion;
+ QHash<QString, KTextEditor::Command *> m_cmdDict;
+ KTextEditor::Command *queryCommand(const QString &cmd) const;
+};
+}
+
+#endif
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp index 513de48..7ee21a1 100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
@@ -31,24 +31,18 @@
#include "matchhighlighter.h"
#include "interactivesedreplacemode.h"
#include "searchmode.h"
+#include "commandmode.h"
-#include <vimode/cmds.h>
#include <vimode/modes/visualvimode.h>
-#include <vimode/appcommands.h>
#include "../history.h"
-#include "katecmds.h"
-#include "katescriptmanager.h"
#include "../registers.h"
#include "../searcher.h"
-#include <KLocalizedString>
-
#include <QLineEdit>
#include <QVBoxLayout>
#include <QLabel>
#include <QApplication>
-#include <QWhatsThis>
#include <algorithm>
@@ -435,374 +429,3 @@ void EmulatedCommandBar::hideAllWidgetsExcept(QWidget* \
widgetToKeepVisible)
}
-EmulatedCommandBar::CommandMode::CommandMode ( EmulatedCommandBar* \
emulatedCommandBar, MatchHighlighter* matchHighlighter, KTextEditor::ViewPrivate* \
view, QLineEdit* edit, InteractiveSedReplaceMode *interactiveSedReplaceMode, \
Completer* completer)
- : ActiveMode ( emulatedCommandBar, matchHighlighter ),
- m_edit(edit),
- m_view(view),
- m_interactiveSedReplaceMode(interactiveSedReplaceMode),
- m_completer(completer)
-{
- QList<KTextEditor::Command *> cmds;
-
- cmds.push_back(KateCommands::CoreCommands::self());
- cmds.push_back(Commands::self());
- cmds.push_back(AppCommands::self());
- cmds.push_back(SedReplace::self());
- cmds.push_back(BufferCommands::self());
-
- Q_FOREACH (KTextEditor::Command *cmd, \
KateScriptManager::self()->commandLineScripts()) {
- cmds.push_back(cmd);
- }
-
- Q_FOREACH (KTextEditor::Command *cmd, cmds) {
- QStringList l = cmd->cmds();
-
- for (int z = 0; z < l.count(); z++) {
- m_cmdDict.insert(l[z], cmd);
- }
-
- m_cmdCompletion.insertItems(l);
- }
-}
-
-void EmulatedCommandBar::CommandMode::setViInputModeManager ( InputModeManager* \
viInputModeManager )
-{
- m_viInputModeManager = viInputModeManager;
-}
-
-bool EmulatedCommandBar::CommandMode::handleKeyPress ( const QKeyEvent* keyEvent )
-{
- if (keyEvent->modifiers() == Qt::ControlModifier && (keyEvent->key() == \
Qt::Key_D || keyEvent->key() == Qt::Key_F)) {
- CommandMode::ParsedSedExpression parsedSedExpression = \
parseAsSedExpression();
- if (parsedSedExpression.parsedSuccessfully) {
- const bool clearFindTerm = (keyEvent->key() == Qt::Key_D);
- if (clearFindTerm) {
- m_edit->setSelection(parsedSedExpression.findBeginPos, \
parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + \
1);
- m_edit->insert(QString());
- } else {
- // Clear replace term.
- m_edit->setSelection(parsedSedExpression.replaceBeginPos, \
parsedSedExpression.replaceEndPos - \
parsedSedExpression.replaceBeginPos + 1);
- m_edit->insert(QString());
- }
- }
- return true;
- }
- return false;
-}
-
-void EmulatedCommandBar::CommandMode::editTextChanged ( const QString& newText )
-{
- Q_UNUSED(newText); // We read the current text from m_edit.
- if (m_completer->isCompletionActive())
- return;
- // Command completion doesn't need to be manually invoked.
- if (!withoutRangeExpression().isEmpty() && \
!m_completer->isNextTextChangeDueToCompletionChange()) {
- // ... However, command completion mode should not be automatically invoked \
if this is not the current leading
- // word in the text edit (it gets annoying if completion pops up after \
":s/se" etc).
- const bool commandBeforeCursorIsLeading = (commandBeforeCursorBegin() == \
rangeExpression().length());
- if (commandBeforeCursorIsLeading) {
- CompletionStartParams completionStartParams = \
activateCommandCompletion();
- startCompletion(completionStartParams);
- }
- }
-}
-
-void EmulatedCommandBar::CommandMode::deactivate ( bool wasAborted )
-{
- if (wasAborted) {
- // Appending the command to the history when it is executed is handled \
elsewhere; we can't
- // do it inside closed() as we may still be showing the command response \
display.
- m_viInputModeManager->globalState()->commandHistory()->append(m_edit->text());
- // With Vim, aborting a command returns us to Normal mode, even if we were \
in Visual Mode.
- // If we switch from Visual to Normal mode, we need to clear the selection.
- m_view->clearSelection();
- }
-
-}
-
-CompletionStartParams \
EmulatedCommandBar::CommandMode::completionInvoked(Completer::CompletionInvocation \
invocationType)
-{
- CompletionStartParams completionStartParams;
- if (invocationType == Completer::CompletionInvocation::ExtraContext)
- {
- if (isCursorInFindTermOfSed()) {
- completionStartParams = activateSedFindHistoryCompletion();
- } else if (isCursorInReplaceTermOfSed()) {
- completionStartParams = activateSedReplaceHistoryCompletion();
- } else {
- completionStartParams = activateCommandHistoryCompletion();
- }
- }
- else
- {
- // Normal context, so boring, ordinary History completion.
- completionStartParams = activateCommandHistoryCompletion();
- }
- return completionStartParams;
-}
-
-void EmulatedCommandBar::CommandMode::completionChosen()
-{
- QString commandToExecute = m_edit->text();
- CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- if (parsedSedExpression.parsedSuccessfully) {
- const QString originalFindTerm = sedFindTerm();
- const QString convertedFindTerm = \
vimRegexToQtRegexPattern(originalFindTerm);
- const QString commandWithSedSearchRegexConverted = \
withSedFindTermReplacedWith(convertedFindTerm);
- m_viInputModeManager->globalState()->searchHistory()->append(originalFindTerm);
- const QString replaceTerm = sedReplaceTerm();
- m_viInputModeManager->globalState()->replaceHistory()->append(replaceTerm);
- commandToExecute = commandWithSedSearchRegexConverted;
- }
-
- const QString commandResponseMessage = executeCommand(commandToExecute);
- // Don't close the bar if executing the command switched us to Interactive Sed \
Replace mode.
- if (!m_interactiveSedReplaceMode->isActive()) {
- if (commandResponseMessage.isEmpty()) {
- m_emulatedCommandBar->hideMe();
- } else {
- closeWithStatusMessage(commandResponseMessage);
- }
- }
- m_viInputModeManager->globalState()->commandHistory()->append(m_edit->text());
-
-}
-
-QString EmulatedCommandBar::CommandMode::executeCommand ( const QString& \
commandToExecute )
-{
- // Silently ignore leading space characters and colon characters (for vi-heads).
- uint n = 0;
- const uint textlen = commandToExecute.length();
- while ((n < textlen) && commandToExecute[n].isSpace()) {
- n++;
- }
-
- if (n >= textlen) {
- return QString();
- }
-
- QString commandResponseMessage;
- QString cmd = commandToExecute.mid(n);
-
- KTextEditor::Range range = \
CommandRangeExpressionParser(m_viInputModeManager).parseRange(cmd, \
cmd);
-
- if (cmd.length() > 0) {
- KTextEditor::Command *p = queryCommand(cmd);
- KateViCommandInterface *ci = dynamic_cast<KateViCommandInterface*>(p);
-
- if (ci) {
- ci->setViInputModeManager(m_viInputModeManager);
- ci->setViGlobal(m_viInputModeManager->globalState());
- }
-
- // The following commands changes the focus themselves, so bar should be \
hidden before execution.
-
- // We got a range and a valid command, but the command does not inherit the \
RangeCommand
- // extension. Bail out.
- if (range.isValid() && !p->supportsRange(cmd)) {
- commandResponseMessage = i18n("Error: No range allowed for command \
\"%1\".", cmd);
- } else {
- if (p) {
- if (p->exec(m_view, cmd, commandResponseMessage, range)) {
-
- if (commandResponseMessage.length() > 0) {
- commandResponseMessage = i18n("Success: ") + \
commandResponseMessage;
- }
- } else {
- if (commandResponseMessage.length() > 0) {
- if (commandResponseMessage.contains(QLatin1Char('\n'))) {
- // multiline error, use widget with more space
- \
QWhatsThis::showText(m_emulatedCommandBar->mapToGlobal(QPoint(0, 0)), \
commandResponseMessage);
- }
- } else {
- commandResponseMessage = i18n("Command \"%1\" failed.", \
cmd);
- }
- }
- } else {
- commandResponseMessage = i18n("No such command: \"%1\"", cmd);
- }
- }
- }
-
- // the following commands change the focus themselves
- if (!QRegExp(QLatin1String("buffer|b|new|vnew|bp|bprev|bn|bnext|bf|bfirst|bl|blast|edit|e")).exactMatch(cmd.split(QLatin1String(" \
")).at(0))) {
- m_view->setFocus();
- }
-
- m_viInputModeManager->reset();
- return commandResponseMessage;
-
-}
-
-
-QString EmulatedCommandBar::CommandMode::withoutRangeExpression()
-{
- const QString originalCommand = m_edit->text();
- return originalCommand.mid(rangeExpression().length());
-}
-
-QString EmulatedCommandBar::CommandMode::rangeExpression()
-{
- const QString command = m_edit->text();
- return CommandRangeExpressionParser(m_viInputModeManager).parseRangeString(command);
-}
-
-EmulatedCommandBar::CommandMode::ParsedSedExpression \
EmulatedCommandBar::CommandMode::parseAsSedExpression()
-{
- const QString commandWithoutRangeExpression = withoutRangeExpression();
- ParsedSedExpression parsedSedExpression;
- QString delimiter;
- parsedSedExpression.parsedSuccessfully = \
SedReplace::parse(commandWithoutRangeExpression, delimiter, \
parsedSedExpression.findBeginPos, parsedSedExpression.findEndPos, \
parsedSedExpression.replaceBeginPos, \
parsedSedExpression.replaceEndPos);
- if (parsedSedExpression.parsedSuccessfully) {
- parsedSedExpression.delimiter = delimiter.at(0);
- if (parsedSedExpression.replaceBeginPos == -1) {
- if (parsedSedExpression.findBeginPos != -1) {
- // The replace term was empty, and a quirk of the regex used is that \
replaceBeginPos will be -1.
- // It's actually the position after the first occurrence of the \
delimiter after the end of the find pos.
- parsedSedExpression.replaceBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter, \
parsedSedExpression.findEndPos) + 1;
- parsedSedExpression.replaceEndPos = \
parsedSedExpression.replaceBeginPos - 1;
- } else {
- // Both find and replace terms are empty; replace term is at the \
third occurrence of the delimiter.
- parsedSedExpression.replaceBeginPos = 0;
- for (int delimiterCount = 1; delimiterCount <= 3; delimiterCount++) \
{
- parsedSedExpression.replaceBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter, parsedSedExpression.replaceBeginPos \
+ 1);
- }
- parsedSedExpression.replaceEndPos = \
parsedSedExpression.replaceBeginPos - 1;
- }
- }
- if (parsedSedExpression.findBeginPos == -1) {
- // The find term was empty, and a quirk of the regex used is that \
findBeginPos will be -1.
- // It's actually the position after the first occurrence of the \
delimiter.
- parsedSedExpression.findBeginPos = \
commandWithoutRangeExpression.indexOf(delimiter) + 1;
- parsedSedExpression.findEndPos = parsedSedExpression.findBeginPos - 1;
- }
-
- }
-
- if (parsedSedExpression.parsedSuccessfully) {
- parsedSedExpression.findBeginPos += rangeExpression().length();
- parsedSedExpression.findEndPos += rangeExpression().length();
- parsedSedExpression.replaceBeginPos += rangeExpression().length();
- parsedSedExpression.replaceEndPos += rangeExpression().length();
- }
- return parsedSedExpression;
-
-}
-
-QString EmulatedCommandBar::CommandMode::sedFindTerm()
-{
- const QString command = m_edit->text();
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- Q_ASSERT(parsedSedExpression.parsedSuccessfully);
- return command.mid(parsedSedExpression.findBeginPos, \
parsedSedExpression.findEndPos - parsedSedExpression.findBeginPos + \
1);
-}
-
-QString EmulatedCommandBar::CommandMode::sedReplaceTerm()
-{
- const QString command = m_edit->text();
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- Q_ASSERT(parsedSedExpression.parsedSuccessfully);
- return command.mid(parsedSedExpression.replaceBeginPos, \
parsedSedExpression.replaceEndPos - \
parsedSedExpression.replaceBeginPos + 1);
-}
-
-QString EmulatedCommandBar::CommandMode::withSedFindTermReplacedWith ( const \
QString& newFindTerm )
-{
- const QString command = m_edit->text();
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- Q_ASSERT(parsedSedExpression.parsedSuccessfully);
- return command.mid(0, parsedSedExpression.findBeginPos) +
- newFindTerm +
- command.mid(parsedSedExpression.findEndPos + 1);
-}
-
-QString EmulatedCommandBar::CommandMode::withSedDelimiterEscaped ( const QString& \
text )
-{
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- QString delimiterEscaped = ensuredCharEscaped(text, \
parsedSedExpression.delimiter);
- return delimiterEscaped;
-}
-
-bool EmulatedCommandBar::CommandMode::isCursorInFindTermOfSed()
-{
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- return parsedSedExpression.parsedSuccessfully && (m_edit->cursorPosition() >= \
parsedSedExpression.findBeginPos && m_edit->cursorPosition() <= \
parsedSedExpression.findEndPos + 1);
-}
-
-bool EmulatedCommandBar::CommandMode::isCursorInReplaceTermOfSed()
-{
- ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- return parsedSedExpression.parsedSuccessfully && m_edit->cursorPosition() >= \
parsedSedExpression.replaceBeginPos && m_edit->cursorPosition() <= \
parsedSedExpression.replaceEndPos + 1;
-}
-
-int EmulatedCommandBar::CommandMode::commandBeforeCursorBegin()
-{
- const QString textWithoutRangeExpression = withoutRangeExpression();
- const int cursorPositionWithoutRangeExpression = m_edit->cursorPosition() - \
rangeExpression().length();
- int commandBeforeCursorBegin = cursorPositionWithoutRangeExpression - 1;
- while (commandBeforeCursorBegin >= 0 && \
(textWithoutRangeExpression[commandBeforeCursorBegin].isLetterOrNumber() || \
textWithoutRangeExpression[commandBeforeCursorBegin] == QLatin1Char('_') || \
textWithoutRangeExpression[commandBeforeCursorBegin] == \
QLatin1Char('-'))) {
- commandBeforeCursorBegin--;
- }
- commandBeforeCursorBegin++;
- commandBeforeCursorBegin += rangeExpression().length();
- return commandBeforeCursorBegin;
-}
-
-CompletionStartParams EmulatedCommandBar::CommandMode::activateCommandCompletion()
-{
- return CompletionStartParams::createModeSpecific(m_cmdCompletion.items(), \
commandBeforeCursorBegin());
-}
-
-CompletionStartParams \
EmulatedCommandBar::CommandMode::activateCommandHistoryCompletion()
-{
- return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->commandHistory()->items()), \
0);
-}
-
-CompletionStartParams \
EmulatedCommandBar::CommandMode::activateSedFindHistoryCompletion()
-{
- if (m_viInputModeManager->globalState()->searchHistory()->isEmpty())
- {
- return CompletionStartParams::invalid();
- }
- CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->searchHistory()->items()),
- \
parsedSedExpression.findBeginPos,
- [this] (const QString& \
completion) -> QString { return \
withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(completion)); \
});
-}
-
-CompletionStartParams \
EmulatedCommandBar::CommandMode::activateSedReplaceHistoryCompletion()
-{
- if (m_viInputModeManager->globalState()->replaceHistory()->isEmpty())
- {
- return CompletionStartParams::invalid();
- }
- CommandMode::ParsedSedExpression parsedSedExpression = parseAsSedExpression();
- return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->replaceHistory()->items()),
- \
parsedSedExpression.replaceBeginPos,
- [this] (const QString& \
completion) -> QString { return \
withCaseSensitivityMarkersStripped(withSedDelimiterEscaped(completion)); \
});
-}
-
-KTextEditor::Command* EmulatedCommandBar::CommandMode::queryCommand ( const QString& \
cmd ) const
-{
- // a command can be named ".*[\w\-]+" with the constrain that it must
- // contain at least one letter.
- int f = 0;
- bool b = false;
-
- // special case: '-' and '_' can be part of a command name, but if the
- // command is 's' (substitute), it should be considered the delimiter and
- // should not be counted as part of the command name
- if (cmd.length() >= 2 && cmd.at(0) == QLatin1Char('s') && (cmd.at(1) == \
QLatin1Char('-') || cmd.at(1) == QLatin1Char('_'))) {
- return m_cmdDict.value(QStringLiteral("s"));
- }
-
- for (; f < cmd.length(); f++) {
- if (cmd[f].isLetter()) {
- b = true;
- }
- if (b && (! cmd[f].isLetterOrNumber() && cmd[f] != QLatin1Char('-') && \
cmd[f] != QLatin1Char('_'))) {
- break;
- }
- }
- return m_cmdDict.value(cmd.left(f));
-
-}
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.h \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.h index 3831f0b..09d4485 100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.h
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.h
@@ -41,6 +41,7 @@ namespace KateVi
class MatchHighlighter;
class InteractiveSedReplaceMode;
class SearchMode;
+class CommandMode;
/**
* A KateViewBarWidget that attempts to emulate some of the features of Vim's own \
command bar, @@ -87,63 +88,6 @@ private:
friend class ActiveMode;
QScopedPointer<MatchHighlighter> m_matchHighligher;
QScopedPointer<Completer> m_completer;
-
- class CommandMode : public ActiveMode
- {
- public:
- CommandMode(EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit, \
InteractiveSedReplaceMode *interactiveSedReplaceMode, Completer* \
completer);
- virtual ~CommandMode()
- {
- }
- void setViInputModeManager(InputModeManager *viInputModeManager);
- virtual bool handleKeyPress ( const QKeyEvent* keyEvent );
- virtual void editTextChanged(const QString &newText);
- virtual CompletionStartParams \
completionInvoked(Completer::CompletionInvocation invocationType);
- virtual void completionChosen();
- void deactivate(bool wasAborted);
- QString executeCommand(const QString &commandToExecute);
- private:
- CompletionStartParams activateCommandCompletion();
- CompletionStartParams activateCommandHistoryCompletion();
- CompletionStartParams activateSedFindHistoryCompletion();
- CompletionStartParams activateSedReplaceHistoryCompletion();
- QString withoutRangeExpression();
- QString rangeExpression();
- QString withSedFindTermReplacedWith(const QString &newFindTerm);
- QString withSedDelimiterEscaped(const QString &text);
- bool isCursorInFindTermOfSed();
- bool isCursorInReplaceTermOfSed();
- QString sedFindTerm();
- QString sedReplaceTerm();
- /**
- * Stuff to do with expressions of the form:
- *
- * s/find/replace/<sedflags>
- */
- struct ParsedSedExpression {
- bool parsedSuccessfully;
- int findBeginPos;
- int findEndPos;
- int replaceBeginPos;
- int replaceEndPos;
- QChar delimiter;
- };
- /**
- * The "range expression" is the (optional) expression before the command \
that describes
- * the range over which the command should be run e.g. '<,'>. @see \
CommandRangeExpressionParser
- */
- CommandMode::ParsedSedExpression parseAsSedExpression();
- void replaceCommandBeforeCursorWith(const QString &newCommand);
- int commandBeforeCursorBegin();
- QLineEdit *m_edit;
- InputModeManager *m_viInputModeManager = nullptr;
- KTextEditor::ViewPrivate *m_view;
- InteractiveSedReplaceMode *m_interactiveSedReplaceMode;
- Completer *m_completer;
- KCompletion m_cmdCompletion;
- QHash<QString, KTextEditor::Command *> m_cmdDict;
- KTextEditor::Command *queryCommand(const QString &cmd) const;
- };
QScopedPointer<InteractiveSedReplaceMode> m_interactiveSedReplaceMode;
QScopedPointer<SearchMode> m_searchMode;
QScopedPointer<CommandMode> m_commandMode;
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic