aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhjk <qtc-committer@nokia.com>2010-06-02 11:09:14 +0200
committerhjk <qtc-committer@nokia.com>2010-06-02 11:25:19 +0200
commit7f97f1f2c2cd103153aca4d1efa4b7e48eb5a804 (patch)
tree7444388e22bfb6a60e72d0fdcfde03e374517f84
parentece25c1b8331d24645b0fbd34a305cc39b45e3dc (diff)
fakevim: synchronize with master
In theory this should have been a backport of the search-related commits 7e8c345a and 46fa3aa7, but they are buried in the middle of the Big Commandline Reorganization. Just taking everything has lower risk and is faster. (cherry picked from commit b67369393ee09fe8115b2bf52aa8debf385d9892)
-rw-r--r--src/plugins/fakevim/fakevimactions.cpp9
-rw-r--r--src/plugins/fakevim/fakevimactions.h2
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp2055
-rw-r--r--src/plugins/fakevim/fakevimhandler.h42
-rw-r--r--src/plugins/fakevim/fakevimoptions.ui7
-rw-r--r--src/plugins/fakevim/fakevimplugin.cpp240
6 files changed, 1385 insertions, 970 deletions
diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp
index f19b5b1d58..a17fbe146c 100644
--- a/src/plugins/fakevim/fakevimactions.cpp
+++ b/src/plugins/fakevim/fakevimactions.cpp
@@ -209,10 +209,13 @@ FakeVimSettings *theFakeVimSettings()
item->setSettingsKey(group, _("IsKeyword"));
instance->insertItem(ConfigIsKeyword, item, _("iskeyword"), _("isk"));
+ // Invented here.
item = new SavedAction(instance);
- item->setText(QCoreApplication::translate("FakeVim::Internal",
- "FakeVim properties..."));
- instance->insertItem(SettingsDialog, item);
+ item->setDefaultValue(false);
+ item->setValue(false);
+ item->setSettingsKey(group, _("ShowMarks"));
+ item->setCheckable(true);
+ instance->insertItem(ConfigShowMarks, item, _("showmarks"), _("sm"));
return instance;
}
diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h
index a05e129c9b..5929376bc6 100644
--- a/src/plugins/fakevim/fakevimactions.h
+++ b/src/plugins/fakevim/fakevimactions.h
@@ -64,7 +64,7 @@ enum FakeVimSettingsCode
ConfigIsKeyword,
// other actions
- SettingsDialog,
+ ConfigShowMarks,
};
class FakeVimSettings : public QObject
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index a2155143f4..799e83f42a 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -56,6 +56,7 @@
// m_tc.position() (== position()). The character below position() is not included
// if the last movement command was exclusive (MoveExclusive).
// The value of m_tc.anchor() is not used.
+//
#include "fakevimhandler.h"
#include "fakevimsyntax.h"
@@ -69,6 +70,7 @@
#include <QtCore/QProcess>
#include <QtCore/QRegExp>
#include <QtCore/QTextStream>
+#include <QtCore/QTimer>
#include <QtCore/QtAlgorithms>
#include <QtCore/QStack>
@@ -126,51 +128,57 @@ namespace Internal {
#define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
const int ParagraphSeparator = 0x00002029;
+typedef QLatin1String _;
using namespace Qt;
+/*! A \e Mode represents one of the basic modes of operation of FakeVim.
+*/
enum Mode
{
InsertMode,
+ ReplaceMode,
CommandMode,
ExMode,
- SearchForwardMode,
- SearchBackwardMode,
};
+/*! A \e SubMode is used for things that require one more data item
+ and are 'nested' behind a \l Mode.
+*/
enum SubMode
{
NoSubMode,
- ChangeSubMode, // used for c
- DeleteSubMode, // used for d
- FilterSubMode, // used for !
- IndentSubMode, // used for =
- RegisterSubMode, // used for "
- ReplaceSubMode, // used for R and r
- ShiftLeftSubMode, // used for <
- ShiftRightSubMode, // used for >
- TransformSubMode, // used for ~/gu/gU
- WindowSubMode, // used for Ctrl-w
- YankSubMode, // used for y
- ZSubMode, // used for z
- CapitalZSubMode // used for Z
+ ChangeSubMode, // Used for c
+ DeleteSubMode, // Used for d
+ FilterSubMode, // Used for !
+ IndentSubMode, // Used for =
+ RegisterSubMode, // Used for "
+ ShiftLeftSubMode, // Used for <
+ ShiftRightSubMode, // Used for >
+ TransformSubMode, // Used for ~/gu/gU
+ WindowSubMode, // Used for Ctrl-w
+ YankSubMode, // Used for y
+ ZSubMode, // Used for z
+ CapitalZSubMode, // Used for Z
+ ReplaceSubMode, // Used for r
};
+/*! A \e SubSubMode is used for things that require one more data item
+ and are 'nested' behind a \l SubMode.
+*/
enum SubSubMode
{
- // typically used for things that require one more data item
- // and are 'nested' behind a mode
NoSubSubMode,
- FtSubSubMode, // used for f, F, t, T
- MarkSubSubMode, // used for m
- BackTickSubSubMode, // used for `
- TickSubSubMode, // used for '
- InvertCaseSubSubMode, // used for ~
- DownCaseSubSubMode, // used for gu
- UpCaseSubSubMode, // used for gU
- ReplaceSubSubMode, // used for r after visual mode
- TextObjectSubSubMode, // used for thing like iw, aW, as etc.
+ FtSubSubMode, // Used for f, F, t, T.
+ MarkSubSubMode, // Used for m.
+ BackTickSubSubMode, // Used for `.
+ TickSubSubMode, // Used for '.
+ InvertCaseSubSubMode, // Used for ~.
+ DownCaseSubSubMode, // Used for gu.
+ UpCaseSubSubMode, // Used for gU.
+ TextObjectSubSubMode, // Used for thing like iw, aW, as etc.
+ SearchSubSubMode,
};
enum VisualMode
@@ -188,14 +196,27 @@ enum MoveType
MoveLineWise,
};
-enum RangeMode
-{
- RangeCharMode, // v
- RangeLineMode, // V
- RangeLineModeExclusive, // like above, but keep one newline when deleting
- RangeBlockMode, // Ctrl-v
- RangeBlockAndTailMode, // Ctrl-v for D and X
-};
+/*!
+ \enum RangeMode
+
+ The \e RangeMode serves as a means to define how the "Range" between
+ the \l cursor and the \l anchor position is to be interpreted.
+
+ \value RangeCharMode Entered by pressing \key v. The range includes
+ all characters between cursor and anchor.
+ \value RangeLineMode Entered by pressing \key V. The range includes
+ all lines between the line of the cursor and
+ the line of the anchor.
+ \value RangeLineModeExclusice Like \l RangeLineMode, but keeps one
+ newline when deleting.
+ \value RangeBlockMode Entered by pressing \key Ctrl-v. The range includes
+ all characters with line and column coordinates
+ between line and columns coordinates of cursor and
+ anchor.
+ \value RangeBlockAndTailMode Like \l RangeBlockMode, but also includes
+ all characters in the affected lines up to the end
+ of these lines.
+*/
enum EventResult
{
@@ -207,8 +228,8 @@ enum EventResult
struct Column
{
Column(int p, int l) : physical(p), logical(l) {}
- int physical; // number of characters in the data
- int logical; // column on screen
+ int physical; // Number of characters in the data.
+ int logical; // Column on screen.
};
struct CursorPosition
@@ -223,33 +244,63 @@ struct CursorPosition
struct Register
{
Register() : rangemode(RangeCharMode) {}
+ Register(const QString &c) : contents(c), rangemode(RangeCharMode) {}
Register(const QString &c, RangeMode m) : contents(c), rangemode(m) {}
QString contents;
RangeMode rangemode;
};
-struct Range
+QDebug operator<<(QDebug ts, const Register &reg)
{
- Range()
- : beginPos(-1), endPos(-1), rangemode(RangeCharMode)
- {}
+ return ts << reg.contents;
+}
- Range(int b, int e, RangeMode m = RangeCharMode)
- : beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
- {}
+struct SearchData
+{
+ SearchData() { init(); }
- QString toString() const
- {
- return QString("%1-%2 (mode: %3)").arg(beginPos).arg(endPos)
- .arg(rangemode);
- }
+ void init() { forward = true; mustMove = true; highlightMatches = true;
+ highlightCursor = true; }
- int beginPos;
- int endPos;
- RangeMode rangemode;
+ QString needle;
+ bool forward;
+ bool mustMove;
+ bool highlightMatches;
+ bool highlightCursor;
};
-QDebug &operator<<(QDebug &ts, const QList<QTextEdit::ExtraSelection> &sels)
+
+Range::Range()
+ : beginPos(-1), endPos(-1), rangemode(RangeCharMode)
+{}
+
+Range::Range(int b, int e, RangeMode m)
+ : beginPos(qMin(b, e)), endPos(qMax(b, e)), rangemode(m)
+{}
+
+QString Range::toString() const
+{
+ return QString("%1-%2 (mode: %3)").arg(beginPos).arg(endPos)
+ .arg(rangemode);
+}
+
+QDebug operator<<(QDebug ts, const Range &range)
+{
+ return ts << '[' << range.beginPos << ',' << range.endPos << ']';
+}
+
+
+
+ExCommand::ExCommand(const QString &c, const QString &a, const Range &r)
+ : cmd(c), hasBang(false), args(a), range(r)
+{}
+
+QDebug operator<<(QDebug ts, const ExCommand &cmd)
+{
+ return ts << cmd.cmd << ' ' << cmd.args << ' ' << cmd.range;
+}
+
+QDebug operator<<(QDebug ts, const QList<QTextEdit::ExtraSelection> &sels)
{
foreach (const QTextEdit::ExtraSelection &sel, sels)
ts << "SEL: " << sel.cursor.anchor() << sel.cursor.position();
@@ -260,11 +311,14 @@ QString quoteUnprintable(const QString &ba)
{
QString res;
for (int i = 0, n = ba.size(); i != n; ++i) {
- QChar c = ba.at(i);
+ const QChar c = ba.at(i);
+ const int cc = c.unicode();
if (c.isPrint())
res += c;
+ else if (cc == '\n')
+ res += _("<CR>");
else
- res += QString("\\x%1").arg(c.unicode(), 2, 16);
+ res += QString("\\x%1").arg(c.unicode(), 2, 16, QLatin1Char('0'));
}
return res;
}
@@ -280,9 +334,9 @@ static bool startsWithWhitespace(const QString &str, int col)
return true;
}
-inline QString msgE20MarkNotSet(const QString &text)
+inline QString msgMarkNotSet(const QString &text)
{
- return FakeVimHandler::tr("E20: Mark '%1' not set").arg(text);
+ return FakeVimHandler::tr("Mark '%1' not set").arg(text);
}
class Input
@@ -294,7 +348,7 @@ public:
explicit Input(QChar x)
: m_key(x.unicode()), m_xkey(x.unicode()), m_modifiers(0), m_text(x) {}
- Input(int k, int m, QString t)
+ Input(int k, int m, const QString &t)
: m_key(k), m_modifiers(m), m_text(t)
{
// m_xkey is only a cache.
@@ -305,11 +359,28 @@ public:
{
return m_xkey >= '0' && m_xkey <= '9';
}
+
bool isKey(int c) const
{
return !m_modifiers && m_key == c;
}
+ bool isBackspace() const
+ {
+ return m_key == Key_Backspace || isControl('h');
+ }
+
+ bool isReturn() const
+ {
+ return m_key == Key_Return;
+ }
+
+ bool isEscape() const
+ {
+ return isKey(Key_Escape) || isKey(27) || isControl('c')
+ || isControl(Key_BracketLeft);
+ }
+
bool is(int c) const
{
return m_xkey == c && (m_modifiers == 0 || m_modifiers == Qt::ShiftModifier);
@@ -328,13 +399,26 @@ public:
bool operator==(const Input &a) const
{
- return a.m_key == m_key && m_text == a.m_text;
+ return a.m_key == m_key && a.m_modifiers == m_modifiers
+ && m_text == a.m_text;
}
+ bool operator!=(const Input &a) const { return !operator==(a); }
+
QString text() const { return m_text; }
+ QChar asChar() const
+ {
+ return (m_text.size() == 1 ? m_text.at(0) : QChar());
+ }
+
int key() const { return m_key; }
+ QDebug dump(QDebug ts) const
+ {
+ return ts << m_key << '-' << m_modifiers << '-'
+ << quoteUnprintable(m_text);
+ }
private:
int m_key;
int m_xkey;
@@ -342,10 +426,68 @@ private:
QString m_text;
};
-typedef QVector<Input> Inputs;
+QDebug operator<<(QDebug ts, const Input &input) { return input.dump(ts); }
+
+class Inputs : public QVector<Input>
+{
+public:
+ Inputs() {}
+ explicit Inputs(const QString &str) { parseFrom(str); }
+ void parseFrom(const QString &str);
+};
+
+
+void Inputs::parseFrom(const QString &str)
+{
+ const int n = str.size();
+ for (int i = 0; i < n; ++i) {
+ uint c0 = str.at(i).unicode(), c1 = 0, c2 = 0, c3 = 0, c4 = 0, c5 = 0;
+ if (i + 1 < n)
+ c1 = str.at(i + 1).unicode();
+ if (i + 2 < n)
+ c2 = str.at(i + 2).unicode();
+ if (i + 3 < n)
+ c3 = str.at(i + 3).unicode();
+ if (i + 4 < n)
+ c4 = str.at(i + 4).unicode();
+ if (i + 5 < n)
+ c5 = str.at(i + 5).unicode();
+ if (c0 == '<') {
+ if ((c1 == 'C' || c1 == 'c') && c2 == '-' && c4 == '>') {
+ uint c = (c3 < 90 ? c3 : c3 - 32);
+ append(Input(c, Qt::ControlModifier, QString(QChar(c - 64))));
+ i += 4;
+ } else {
+ append(Input(QLatin1Char(c0)));
+ }
+ } else {
+ append(Input(QLatin1Char(c0)));
+ }
+ }
+}
+
+class History
+{
+public:
+ History() : m_index(0) {}
+ void append(const QString &item)
+ { //qDebug() << "APP: " << item << m_items;
+ m_items.removeAll(item);
+ m_items.append(item); m_index = m_items.size() - 1; }
+ void down() { m_index = qMin(m_index + 1, m_items.size()); }
+ void up() { m_index = qMax(m_index - 1, 0); }
+ //void clear() { m_items.clear(); m_index = 0; }
+ void restart() { m_index = m_items.size(); }
+ QString current() const { return m_items.value(m_index, QString()); }
+ QStringList items() const { return m_items; }
+private:
+ QStringList m_items;
+ int m_index;
+};
+
// Mappings for a specific mode.
-class ModeMapping : private QList<QPair<Inputs, Inputs> >
+class ModeMapping : public QList<QPair<Inputs, Inputs> >
{
public:
ModeMapping() { test(); }
@@ -375,24 +517,24 @@ public:
}
}
- // Returns 'false' if more input input is needed to decide whether a
- // mapping needs to be applied. If a decision can be made, return 'true',
+ // Returns 'false' if more input is needed to decide whether a mapping
+ // needs to be applied. If a decision can be made, return 'true',
// and replace *input with the mapped data.
- bool mappingDone(Inputs *input) const
+ bool mappingDone(Inputs *inputs) const
{
- Q_UNUSED(input);
// FIXME: inefficient.
for (int i = 0; i != size(); ++i) {
+ const Inputs &haystack = at(i).first;
// A mapping
- if (startsWith(at(i).first, *input)) {
- if (at(i).first.size() != input->size())
+ if (startsWith(haystack, *inputs)) {
+ if (haystack.size() != inputs->size())
return false; // This can be extended.
// Actual mapping.
- *input = at(i).second;
+ *inputs = at(i).second;
return true;
}
}
- // No extensible mapping found. Use input as-is.
+ // No extensible mapping found. Use inputs as-is.
return true;
}
@@ -403,13 +545,14 @@ private:
if (needle.size() > haystack.size())
return false;
for (int i = 0; i != needle.size(); ++i) {
- if (needle.at(i).text() != haystack.at(i).text())
+ if (needle.at(i) != haystack.at(i))
return false;
}
return true;
}
};
+
class FakeVimHandler::Private : public QObject
{
Q_OBJECT
@@ -422,7 +565,7 @@ public:
void handleCommand(const QString &cmd); // Sets m_tc + handleExCommand
void handleExCommand(const QString &cmd);
- // updates marks positions by the difference in positionChange
+ // Updates marks positions by the difference in positionChange.
void fixMarks(int positionAction, int positionChange);
void installEventFilter();
@@ -436,14 +579,16 @@ public:
EventResult handleKey(const Input &);
Q_SLOT EventResult handleKey2();
EventResult handleInsertMode(const Input &);
+ EventResult handleReplaceMode(const Input &);
EventResult handleCommandMode(const Input &);
EventResult handleRegisterMode(const Input &);
- EventResult handleMiniBufferModes(const Input &);
+ EventResult handleExMode(const Input &);
+ EventResult handleSearchSubSubMode(const Input &);
EventResult handleCommandSubSubMode(const Input &);
void finishMovement(const QString &dotCommand = QString());
void finishMovement(const QString &dotCommand, int count);
void resetCommandMode();
- void search(const QString &needle, bool forward, bool incSearch = false);
+ void search(const SearchData &sd);
void highlightMatches(const QString &needle);
void stopIncrementalFind();
@@ -455,18 +600,18 @@ public:
bool atEndOfLine() const
{ return m_tc.atBlockEnd() && m_tc.block().length() > 1; }
- int lastPositionInDocument() const; // last valid pos in doc
+ int lastPositionInDocument() const; // Returns last valid position in doc.
int firstPositionInLine(int line) const; // 1 based line, 0 based pos
int lastPositionInLine(int line) const; // 1 based line, 0 based pos
int lineForPosition(int pos) const; // 1 based line, 0 based pos
QString lineContents(int line) const; // 1 based line
- void setLineContents(int line, const QString &contents) const; // 1 based line
+ void setLineContents(int line, const QString &contents); // 1 based line
int linesOnScreen() const;
int columnsOnScreen() const;
int linesInDocument() const;
- // all zero-based counting
+ // The following use all zero-based counting.
int cursorLineOnScreen() const;
int cursorLineInDocument() const;
int physicalCursorColumnInDocument() const; // as stored in the data
@@ -482,7 +627,7 @@ public:
void setCursorPosition(const CursorPosition &p)
{ setPosition(p.position); scrollToLineInDocument(p.scrollLine); }
- // helper functions for indenting
+ // Helper functions for indenting/
bool isElectricCharacter(QChar c) const;
void indentSelectedText(QChar lastTyped = QChar());
int indentText(const Range &range, QChar lastTyped = QChar());
@@ -500,7 +645,7 @@ public:
void moveToMatchingParanthesis();
void moveToWordBoundary(bool simple, bool forward, bool changeWord = false);
- // to reduce line noise
+ // Convenience wrappers to reduce line noise.
void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
void moveToStartOfLine();
void moveToEndOfLine();
@@ -515,11 +660,11 @@ public:
bool handleFfTt(QString key);
- // helper function for handleExCommand. return 1 based line index.
+ // Helper function for handleExCommand returning 1 based line index.
int readLineCode(QString &cmd);
- void selectRange(int beginLine, int endLine);
void enterInsertMode();
+ void enterReplaceMode();
void enterCommandMode();
void enterExMode();
void showRedMessage(const QString &msg);
@@ -527,20 +672,17 @@ public:
void notImplementedYet();
void updateMiniBuffer();
void updateSelection();
+ void updateCursor();
QWidget *editor() const;
QChar characterAtCursor() const
{ return m_tc.document()->characterAt(m_tc.position()); }
void beginEditBlock() { UNDO_DEBUG("BEGIN EDIT BLOCK"); m_tc.beginEditBlock(); }
void beginEditBlock(int pos) { setUndoPosition(pos); beginEditBlock(); }
void endEditBlock() { UNDO_DEBUG("END EDIT BLOCK"); m_tc.endEditBlock(); }
- void joinPreviousEditBlock() { UNDO_DEBUG("JOIN EDIT BLOCK"); m_tc.joinPreviousEditBlock(); }
-
- // this asks the layer above (e.g. the fake vim plugin or the
- // stand-alone test application to handle the command)
- void passUnknownExCommand(const QString &cmd);
- // this asks the layer above (e.g. the fake vim plugin or the
- // stand-alone test application to handle the set command)
- void passUnknownSetCommand(const QString &cmd);
+ void joinPreviousEditBlock() { UNDO_DEBUG("JOIN"); m_tc.joinPreviousEditBlock(); }
+ void breakEditBlock()
+ { m_tc.beginEditBlock(); m_tc.insertText("x");
+ m_tc.deletePreviousChar(); m_tc.endEditBlock(); }
bool isVisualMode() const { return m_visualMode != NoVisualMode; }
bool isNoVisualMode() const { return m_visualMode == NoVisualMode; }
@@ -556,6 +698,8 @@ public:
void selectBlockTextObject(bool inner, char left, char right);
void selectQuotedStringTextObject(bool inner, int type);
+ Q_SLOT void importSelection();
+
public:
QTextEdit *m_textedit;
QPlainTextEdit *m_plaintextedit;
@@ -570,7 +714,6 @@ public:
QTextCursor m_tc;
int m_oldPosition; // copy from last event to check for external changes
int m_anchor;
- static QHash<int, Register> m_registers;
int m_register;
QString m_mvcount;
QString m_opcount;
@@ -582,10 +725,9 @@ public:
bool m_anchorPastEnd;
bool m_positionPastEnd; // '$' & 'l' in visual mode can move past eol
- bool isSearchMode() const
- { return m_mode == SearchForwardMode || m_mode == SearchBackwardMode; }
int m_gflag; // whether current command started with 'g'
+ QString m_commandPrefix;
QString m_commandBuffer;
QString m_currentFileName;
QString m_currentMessage;
@@ -593,34 +735,44 @@ public:
bool m_lastSearchForward;
bool m_findPending;
QString m_lastInsertion;
+ QString m_lastDeletion;
int anchor() const { return m_anchor; }
int position() const { return m_tc.position(); }
- typedef void (FakeVimHandler::Private::*Transformation)(int, QTextCursor *);
- void transformText(const Range &range, Transformation transformation);
-
- void removeSelectedText();
+ struct TransformationData
+ {
+ TransformationData(const QString &s, const QVariant &d)
+ : from(s), extraData(d) {}
+ QString from;
+ QString to;
+ QVariant extraData;
+ };
+ typedef void (Private::*Transformation)(TransformationData *td);
+ void transformText(const Range &range, Transformation transformation,
+ const QVariant &extraData = QVariant());
+
+ void insertText(const Register &reg);
void removeText(const Range &range);
- void removeTransform(int, QTextCursor *);
+ void removeTransform(TransformationData *td);
- void invertCaseSelectedText();
- void invertCaseTransform(int, QTextCursor *);
+ void invertCase(const Range &range);
+ void invertCaseTransform(TransformationData *td);
- void upCaseSelectedText();
- void upCaseTransform(int, QTextCursor *);
+ void upCase(const Range &range);
+ void upCaseTransform(TransformationData *td);
- void downCaseSelectedText();
- void downCaseTransform(int, QTextCursor *);
+ void downCase(const Range &range);
+ void downCaseTransform(TransformationData *td);
- QChar m_replacingCharacter;
- void replaceSelectedText(); // replace each character with m_replacingCharacter
- void replaceTransform(int, QTextCursor *);
+ void replaceText(const Range &range, const QString &str);
+ void replaceByStringTransform(TransformationData *td);
+ void replaceByCharTransform(TransformationData *td);
- QString selectedText() const { return text(Range(position(), anchor())); }
- QString text(const Range &range) const;
+ QString selectText(const Range &range) const;
+ void setCurrentRange(const Range &range);
+ Range currentRange() const { return Range(position(), anchor(), m_rangemode); }
- void yankSelectedText();
void yankText(const Range &range, int toregister = '"');
void pasteText(bool afterCursor);
@@ -630,37 +782,26 @@ public:
void redo();
void setUndoPosition(int pos);
QMap<int, int> m_undoCursorPosition; // revision -> position
- bool m_beginEditBlock;
// extra data for '.'
void replay(const QString &text, int count);
- void setDotCommand(const QString &cmd) { m_dotCommand = cmd; }
- void setDotCommand(const QString &cmd, int n) { m_dotCommand = cmd.arg(n); }
- QString m_dotCommand;
- bool m_inReplay; // true if we are executing a '.'
+ void setDotCommand(const QString &cmd) { g.dotCommand = cmd; }
+ void setDotCommand(const QString &cmd, int n) { g.dotCommand = cmd.arg(n); }
// extra data for ';'
QString m_semicolonCount;
Input m_semicolonType; // 'f', 'F', 't', 'T'
QString m_semicolonKey;
- // history for '/'
- QString lastSearchString() const;
- static QStringList m_searchHistory;
- int m_searchHistoryIndex;
-
- // history for ':'
- static QStringList m_commandHistory;
- int m_commandHistoryIndex;
-
// visual line mode
void enterVisualMode(VisualMode visualMode);
void leaveVisualMode();
VisualMode m_visualMode;
// marks as lines
+ int mark(int code) const;
+ void setMark(int code, int position);
QHash<int, int> m_marks;
- QString m_oldNeedle;
// vi style configuration
QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
@@ -670,7 +811,6 @@ public:
int m_targetColumn; // -1 if past end of line
int m_visualTargetColumn; // 'l' can move past eol in visual mode only
-
int m_cursorWidth;
// auto-indent
@@ -683,46 +823,67 @@ public:
void handleStartOfLine();
void recordJump();
- void recordNewUndo();
QVector<CursorPosition> m_jumpListUndo;
QVector<CursorPosition> m_jumpListRedo;
QList<QTextEdit::ExtraSelection> m_searchSelections;
+ QTextCursor m_searchCursor;
+ QString m_oldNeedle;
- bool handleExCommandHelper(const QString &cmd); // Returns success.
- QString extractCommand(const QString &line, int *beginLine, int *endLine);
- bool handleExBangCommand(const QString &line);
- bool handleExDeleteCommand(const QString &line);
- bool handleExGotoCommand(const QString &line);
- bool handleExHistoryCommand(const QString &line);
- bool handleExMapCommand(const QString &line);
- bool handleExNormalCommand(const QString &line);
- bool handleExReadCommand(const QString &line);
- bool handleExRedoCommand(const QString &line);
- bool handleExSetCommand(const QString &line);
- bool handleExShiftRightCommand(const QString &line);
- bool handleExSourceCommand(const QString &line);
- bool handleExSubstituteCommand(const QString &line);
- bool handleExWriteCommand(const QString &line);
-
- // All mappings.
- typedef QHash<char, ModeMapping> Mappings;
- static Mappings m_mappings;
-
- QVector<Input> m_pendingInput;
+ bool handleExCommandHelper(const ExCommand &cmd); // Returns success.
+ bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin?
+ bool handleExBangCommand(const ExCommand &cmd);
+ bool handleExDeleteCommand(const ExCommand &cmd);
+ bool handleExGotoCommand(const ExCommand &cmd);
+ bool handleExHistoryCommand(const ExCommand &cmd);
+ bool handleExRegisterCommand(const ExCommand &cmd);
+ bool handleExMapCommand(const ExCommand &cmd);
+ bool handleExNormalCommand(const ExCommand &cmd);
+ bool handleExReadCommand(const ExCommand &cmd);
+ bool handleExRedoCommand(const ExCommand &cmd);
+ bool handleExSetCommand(const ExCommand &cmd);
+ bool handleExShiftCommand(const ExCommand &cmd);
+ bool handleExSourceCommand(const ExCommand &cmd);
+ bool handleExSubstituteCommand(const ExCommand &cmd);
+ bool handleExWriteCommand(const ExCommand &cmd);
void timerEvent(QTimerEvent *ev);
- int m_inputTimer;
void setupCharClass();
int charClass(QChar c, bool simple) const;
signed char m_charClass[256];
+
+ static struct GlobalData
+ {
+ GlobalData()
+ {
+ inReplay = false;
+ inputTimer = -1;
+ }
+
+ // Input.
+ Inputs pendingInput;
+ int inputTimer;
+
+ // Repetition.
+ QString dotCommand;
+ bool inReplay; // true if we are executing a '.'
+
+ // History for searches.
+ History searchHistory;
+
+ // History for :ex commands.
+ History commandHistory;
+
+ QHash<int, Register> registers;
+
+ // All mappings.
+ typedef QHash<char, ModeMapping> Mappings;
+ Mappings mappings;
+ } g;
};
-QStringList FakeVimHandler::Private::m_searchHistory;
-QStringList FakeVimHandler::Private::m_commandHistory;
-QHash<int, Register> FakeVimHandler::Private::m_registers;
-FakeVimHandler::Private::Mappings FakeVimHandler::Private::m_mappings;
+FakeVimHandler::Private::GlobalData FakeVimHandler::Private::g;
FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget)
{
@@ -752,11 +913,8 @@ void FakeVimHandler::Private::init()
m_movetype = MoveInclusive;
m_anchor = 0;
m_cursorWidth = EDITOR(cursorWidth());
- m_inReplay = false;
m_justAutoIndented = 0;
m_rangemode = RangeCharMode;
- m_beginEditBlock = true;
- m_inputTimer = -1;
setupCharClass();
}
@@ -768,6 +926,8 @@ bool FakeVimHandler::Private::wantsOverride(QKeyEvent *ev)
KEY_DEBUG("SHORTCUT OVERRIDE" << key << " PASSING: " << m_passing);
if (key == Key_Escape) {
+ if (m_subsubmode == SearchSubSubMode)
+ return true;
// Not sure this feels good. People often hit Esc several times
if (isNoVisualMode() && m_mode == CommandMode)
return false;
@@ -830,7 +990,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
// Try to compensate for code completion
if (dist > 0 && dist <= physicalCursorColumnInDocument()) {
Range range(m_oldPosition, m_tc.position());
- m_lastInsertion.append(text(range));
+ m_lastInsertion.append(selectText(range));
}
} else if (!isVisualMode()) {
if (atEndOfLine())
@@ -851,8 +1011,8 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
// key = shift(key);
//}
- QTC_ASSERT(
- !(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
+ QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
+ || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
qDebug() << "Cursor at EOL before key handler");
EventResult result = handleKey(Input(key, mods, ev->text()));
@@ -862,8 +1022,8 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
// We fake vi-style end-of-line behaviour
m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
- QTC_ASSERT(
- !(m_mode != InsertMode && m_tc.atBlockEnd() && m_tc.block().length() > 1),
+ QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
+ || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
qDebug() << "Cursor at EOL after key handler");
if (m_fakeEnd)
@@ -872,43 +1032,65 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
EDITOR(setTextCursor(m_tc));
m_oldPosition = m_tc.position();
}
+
+ if (hasConfig(ConfigShowMarks))
+ updateSelection();
+
return result;
}
void FakeVimHandler::Private::installEventFilter()
{
+ EDITOR(viewport()->installEventFilter(q));
EDITOR(installEventFilter(q));
}
void FakeVimHandler::Private::setupWidget()
{
enterCommandMode();
- //EDITOR(setCursorWidth(QFontMetrics(ed->font()).width(QChar('x')));
if (m_textedit) {
m_textedit->setLineWrapMode(QTextEdit::NoWrap);
} else if (m_plaintextedit) {
m_plaintextedit->setLineWrapMode(QPlainTextEdit::NoWrap);
}
m_wasReadOnly = EDITOR(isReadOnly());
- //EDITOR(setReadOnly(true));
updateEditor();
+ importSelection();
+ updateMiniBuffer();
+ updateCursor();
+}
+void FakeVimHandler::Private::importSelection()
+{
QTextCursor tc = EDITOR(textCursor());
+ int pos = tc.position();
+ int anc = tc.anchor();
if (tc.hasSelection()) {
- int pos = tc.position();
- int anc = tc.anchor();
- m_marks['<'] = anc;
- m_marks['>'] = pos;
- m_anchor = anc;
- m_visualMode = VisualCharMode;
- tc.clearSelection();
- EDITOR(setTextCursor(tc));
- m_tc = tc; // needed in updateSelection
- updateSelection();
+ // FIXME: Why?
+ if (pos < anc)
+ --anc;
+ else
+ tc.movePosition(Left, KeepAnchor);
}
-
- updateMiniBuffer();
+ setMark('<', anc);
+ setMark('>', pos);
+ m_anchor = anc;
+ Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
+ if (!tc.hasSelection())
+ m_visualMode = NoVisualMode;
+ else if (mods & Qt::ControlModifier)
+ m_visualMode = VisualBlockMode;
+ else if (mods & Qt::AltModifier)
+ m_visualMode = VisualBlockMode;
+ else if (mods & Qt::ShiftModifier)
+ m_visualMode = VisualLineMode;
+ else
+ m_visualMode = VisualCharMode;
+ m_tc = tc; // needed in updateSelection
+ tc.clearSelection();
+ EDITOR(setTextCursor(tc));
+ updateSelection();
}
void FakeVimHandler::Private::updateEditor()
@@ -924,45 +1106,50 @@ void FakeVimHandler::Private::restoreWidget(int tabSize)
//showBlackMessage(QString());
//updateMiniBuffer();
//EDITOR(removeEventFilter(q));
- EDITOR(setReadOnly(m_wasReadOnly));
- EDITOR(setCursorWidth(m_cursorWidth));
- EDITOR(setOverwriteMode(false));
+ //EDITOR(setReadOnly(m_wasReadOnly));
const int charWidth = QFontMetrics(EDITOR(font())).width(QChar(' '));
EDITOR(setTabStopWidth(charWidth * tabSize));
if (isVisualLineMode()) {
m_tc = EDITOR(textCursor());
- int beginLine = lineForPosition(m_marks['<']);
- int endLine = lineForPosition(m_marks['>']);
+ int beginLine = lineForPosition(mark('<'));
+ int endLine = lineForPosition(mark('>'));
m_tc.setPosition(firstPositionInLine(beginLine), MoveAnchor);
m_tc.setPosition(lastPositionInLine(endLine), KeepAnchor);
EDITOR(setTextCursor(m_tc));
- } else if (isVisualCharMode()) {
+ } else if (isVisualCharMode() || isVisualBlockMode()) {
m_tc = EDITOR(textCursor());
- m_tc.setPosition(m_marks['<'], MoveAnchor);
- m_tc.setPosition(m_marks['>'], KeepAnchor);
+ m_tc.setPosition(mark('<'), MoveAnchor);
+ m_tc.setPosition(mark('>'), KeepAnchor);
EDITOR(setTextCursor(m_tc));
}
m_visualMode = NoVisualMode;
+ // Force "ordinary" cursor.
+ m_mode = InsertMode;
+ m_submode = NoSubMode;
+ m_subsubmode = NoSubSubMode;
+ updateCursor();
updateSelection();
}
EventResult FakeVimHandler::Private::handleKey(const Input &input)
{
- if (m_mode == InsertMode || m_mode == CommandMode) {
- m_pendingInput.append(input);
+ KEY_DEBUG("HANDLE INPUT: " << input);
+ if (m_mode == ExMode)
+ return handleExMode(input);
+ if (m_subsubmode == SearchSubSubMode)
+ return handleSearchSubSubMode(input);
+ if (m_mode == InsertMode || m_mode == ReplaceMode || m_mode == CommandMode) {
+ g.pendingInput.append(input);
const char code = m_mode == InsertMode ? 'i' : 'n';
- if (m_mappings[code].mappingDone(&m_pendingInput))
+ if (g.mappings[code].mappingDone(&g.pendingInput))
return handleKey2();
- if (m_inputTimer != -1)
- killTimer(m_inputTimer);
- m_inputTimer = startTimer(1000);
+ if (g.inputTimer != -1)
+ killTimer(g.inputTimer);
+ g.inputTimer = startTimer(1000);
return EventHandled;
}
- if (m_mode == ExMode || m_mode == SearchForwardMode
- || m_mode == SearchBackwardMode)
- return handleMiniBufferModes(input);
return EventUnhandled;
}
@@ -971,22 +1158,32 @@ EventResult FakeVimHandler::Private::handleKey2()
setUndoPosition(m_tc.position());
if (m_mode == InsertMode) {
EventResult result = EventUnhandled;
- foreach (const Input &in, m_pendingInput) {
+ foreach (const Input &in, g.pendingInput) {
EventResult r = handleInsertMode(in);
if (r == EventHandled)
result = EventHandled;
}
- m_pendingInput.clear();
+ g.pendingInput.clear();
+ return result;
+ }
+ if (m_mode == ReplaceMode) {
+ EventResult result = EventUnhandled;
+ foreach (const Input &in, g.pendingInput) {
+ EventResult r = handleReplaceMode(in);
+ if (r == EventHandled)
+ result = EventHandled;
+ }
+ g.pendingInput.clear();
return result;
}
if (m_mode == CommandMode) {
EventResult result = EventUnhandled;
- foreach (const Input &in, m_pendingInput) {
+ foreach (const Input &in, g.pendingInput) {
EventResult r = handleCommandMode(in);
if (r == EventHandled)
result = EventHandled;
}
- m_pendingInput.clear();
+ g.pendingInput.clear();
return result;
}
return EventUnhandled;
@@ -1020,7 +1217,7 @@ void FakeVimHandler::Private::setAnchor()
if (!isVisualMode()) {
m_anchor = m_tc.position();
} else {
- // m_marks['<'] = m_tc.position();
+ // setMark('<', m_tc.position());
}
}
@@ -1085,14 +1282,14 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
enterExMode();
m_currentMessage.clear();
m_commandBuffer = QString(".,+%1!").arg(qAbs(endLine - beginLine));
- m_commandHistory.append(QString());
- m_commandHistoryIndex = m_commandHistory.size() - 1;
+ //g.commandHistory.append(QString());
updateMiniBuffer();
+ updateCursor();
return;
}
if (isVisualMode())
- m_marks['>'] = m_tc.position();
+ setMark('>', m_tc.position());
if (m_submode == ChangeSubMode
|| m_submode == DeleteSubMode
@@ -1107,7 +1304,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (m_movetype == MoveInclusive) {
if (anchor() <= position()) {
- if ( !m_tc.atBlockEnd())
+ if (!m_tc.atBlockEnd())
moveRight(); // correction
} else {
m_anchor++;
@@ -1124,9 +1321,9 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
}
if (m_submode != TransformSubMode) {
- yankSelectedText();
+ yankText(currentRange(), m_register);
if (m_movetype == MoveLineWise)
- m_registers[m_register].rangemode = RangeLineMode;
+ g.registers[m_register].rangemode = RangeLineMode;
}
m_positionPastEnd = m_anchorPastEnd = false;
@@ -1135,17 +1332,17 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (m_submode == ChangeSubMode) {
if (m_rangemode == RangeLineMode)
m_rangemode = RangeLineModeExclusive;
- removeSelectedText();
+ removeText(currentRange());
if (!dotCommand.isEmpty())
setDotCommand(QLatin1Char('c') + dotCommand);
if (m_movetype == MoveLineWise)
insertAutomaticIndentation(true);
endEditBlock();
+ setUndoPosition(position());
enterInsertMode();
- m_beginEditBlock = false;
m_submode = NoSubMode;
} else if (m_submode == DeleteSubMode) {
- removeSelectedText();
+ removeText(currentRange());
if (!dotCommand.isEmpty())
setDotCommand(QLatin1Char('d') + dotCommand);
if (m_movetype == MoveLineWise)
@@ -1161,7 +1358,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
const int la = lineForPosition(anchor());
const int lp = lineForPosition(position());
if (m_register != '"') {
- setPosition(m_marks[m_register]);
+ setPosition(mark(m_register));
moveToStartOfLine();
} else {
if (anchor() <= position())
@@ -1171,21 +1368,17 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
showBlackMessage(QString("%1 lines yanked").arg(qAbs(la - lp) + 1));
} else if (m_submode == TransformSubMode) {
if (m_subsubmode == InvertCaseSubSubMode) {
- invertCaseSelectedText();
+ invertCase(currentRange());
if (!dotCommand.isEmpty())
setDotCommand(QLatin1Char('~') + dotCommand);
} else if (m_subsubmode == UpCaseSubSubMode) {
- upCaseSelectedText();
+ upCase(currentRange());
if (!dotCommand.isEmpty())
setDotCommand("gU" + dotCommand);
} else if (m_subsubmode == DownCaseSubSubMode) {
- downCaseSelectedText();
+ downCase(currentRange());
if (!dotCommand.isEmpty())
setDotCommand("gu" + dotCommand);
- } else if (m_subsubmode == ReplaceSubSubMode) {
- replaceSelectedText();
- if (!dotCommand.isEmpty())
- setDotCommand("r" + dotCommand);
}
m_submode = NoSubMode;
m_subsubmode = NoSubSubMode;
@@ -1193,28 +1386,26 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (m_movetype == MoveLineWise)
handleStartOfLine();
endEditBlock();
- } else if (m_submode == ReplaceSubMode) {
- m_submode = NoSubMode;
} else if (m_submode == IndentSubMode) {
recordJump();
beginEditBlock();
indentSelectedText();
endEditBlock();
m_submode = NoSubMode;
- updateMiniBuffer();
} else if (m_submode == ShiftRightSubMode) {
recordJump();
shiftRegionRight(1);
m_submode = NoSubMode;
- updateMiniBuffer();
} else if (m_submode == ShiftLeftSubMode) {
recordJump();
shiftRegionLeft(1);
m_submode = NoSubMode;
- updateMiniBuffer();
}
resetCommandMode();
+ updateSelection();
+ updateMiniBuffer();
+ updateCursor();
}
void FakeVimHandler::Private::resetCommandMode()
@@ -1226,14 +1417,19 @@ void FakeVimHandler::Private::resetCommandMode()
m_register = '"';
m_tc.clearSelection();
m_rangemode = RangeCharMode;
-
- updateSelection();
- updateMiniBuffer();
}
void FakeVimHandler::Private::updateSelection()
{
QList<QTextEdit::ExtraSelection> selections = m_searchSelections;
+ if (!m_searchCursor.isNull()) {
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = m_searchCursor;
+ sel.format = m_searchCursor.blockCharFormat();
+ sel.format.setForeground(Qt::white);
+ sel.format.setBackground(Qt::black);
+ selections.append(sel);
+ }
if (isVisualMode()) {
QTextEdit::ExtraSelection sel;
sel.cursor = m_tc;
@@ -1246,7 +1442,7 @@ void FakeVimHandler::Private::updateSelection()
sel.format.setBackground(Qt::black);
#endif
const int cursorPos = m_tc.position();
- const int anchorPos = m_marks['<'];
+ const int anchorPos = mark('<');
//qDebug() << "POS: " << cursorPos << " ANCHOR: " << anchorPos;
if (isVisualCharMode()) {
sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor);
@@ -1287,6 +1483,19 @@ void FakeVimHandler::Private::updateSelection()
}
}
//qDebug() << "SELECTION: " << selections;
+ if (hasConfig(ConfigShowMarks)) {
+ for (QHashIterator<int, int> it(m_marks); it.hasNext(); ) {
+ it.next();
+ QTextEdit::ExtraSelection sel;
+ sel.cursor = m_tc;
+ sel.cursor.setPosition(it.value(), MoveAnchor);
+ sel.cursor.setPosition(it.value() + 1, KeepAnchor);
+ sel.format = m_tc.blockCharFormat();
+ sel.format.setForeground(Qt::blue);
+ sel.format.setBackground(Qt::green);
+ selections.append(sel);
+ }
+ }
emit q->selectionChanged(selections);
}
@@ -1309,17 +1518,13 @@ void FakeVimHandler::Private::updateMiniBuffer()
msg = "-- VISUAL BLOCK --";
}
} else if (m_mode == InsertMode) {
- if (m_submode == ReplaceSubMode)
- msg = "-- REPLACE --";
- else
- msg = "-- INSERT --";
- } else {
- if (m_mode == SearchForwardMode)
- msg += '/';
- else if (m_mode == SearchBackwardMode)
- msg += '?';
- else if (m_mode == ExMode)
- msg += ':';
+ msg = "-- INSERT --";
+ } else if (m_mode == ReplaceMode) {
+ msg = "-- REPLACE --";
+ } else if (!m_commandPrefix.isEmpty()) {
+ //QTC_ASSERT(m_mode == ExMode || m_subsubmode == SearchSubSubMode,
+ // qDebug() << "MODE: " << m_mode << m_subsubmode);
+ msg = m_commandPrefix;
foreach (QChar c, m_commandBuffer) {
if (c.unicode() < 32) {
msg += '^';
@@ -1330,6 +1535,9 @@ void FakeVimHandler::Private::updateMiniBuffer()
}
if (!msg.isEmpty() && m_mode != CommandMode)
msg += QChar(10073); // '|'; // FIXME: Use a real "cursor"
+ } else {
+ QTC_ASSERT(m_mode == CommandMode && m_subsubmode != SearchSubSubMode, /**/);
+ msg = "-- COMMAND --";
}
emit q->commandBufferChanged(msg);
@@ -1337,7 +1545,8 @@ void FakeVimHandler::Private::updateMiniBuffer()
int linesInDoc = linesInDocument();
int l = cursorLineInDocument();
QString status;
- const QString pos = QString::fromLatin1("%1,%2").arg(l + 1).arg(physicalCursorColumnInDocument() + 1);
+ const QString pos = QString::fromLatin1("%1,%2")
+ .arg(l + 1).arg(physicalCursorColumnInDocument() + 1);
// FIXME: physical "-" logical
if (linesInDoc != 0) {
status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4);
@@ -1422,28 +1631,19 @@ EventResult FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
selectQuotedStringTextObject(m_subsubdata.is('i'), input.key());
m_subsubmode = NoSubSubMode;
finishMovement();
- } else if (m_submode == TransformSubMode && m_subsubmode == ReplaceSubSubMode) {
- if (isVisualLineMode())
- m_rangemode = RangeLineMode;
- else if (isVisualBlockMode())
- m_rangemode = RangeBlockMode;
- if (!input.text().isEmpty() && input.text().at(0).isPrint()) {
- leaveVisualMode();
- m_replacingCharacter = input.text().at(0);
- finishMovement();
- }
} else if (m_subsubmode == MarkSubSubMode) {
- m_marks[input.key()] = m_tc.position();
+ setMark(input.asChar().unicode(), m_tc.position());
m_subsubmode = NoSubSubMode;
} else if (m_subsubmode == BackTickSubSubMode
|| m_subsubmode == TickSubSubMode) {
- if (m_marks.contains(input.key())) {
- setPosition(m_marks[input.key()]);
+ int m = mark(input.asChar().unicode());
+ if (m != -1) {
+ setPosition(m);
if (m_subsubmode == TickSubSubMode)
moveToFirstNonBlankOnLine();
finishMovement();
} else {
- showRedMessage(msgE20MarkNotSet(input.text()));
+ showRedMessage(msgMarkNotSet(input.text()));
}
m_subsubmode = NoSubSubMode;
} else {
@@ -1456,7 +1656,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
{
EventResult handled = EventHandled;
- if (input.isKey(Key_Escape) || input.isControl(Key_BracketLeft)) {
+ if (input.isEscape()) {
if (isVisualMode()) {
leaveVisualMode();
} else if (m_submode != NoSubMode) {
@@ -1465,6 +1665,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement();
} else {
resetCommandMode();
+ updateSelection();
+ updateMiniBuffer();
}
} else if (m_subsubmode != NoSubSubMode) {
handleCommandSubSubMode(input);
@@ -1472,9 +1674,33 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
emit q->windowCommandRequested(input.key());
m_submode = NoSubMode;
} else if (m_submode == RegisterSubMode) {
- m_register = input.key();
+ m_register = input.asChar().unicode();
m_submode = NoSubMode;
m_rangemode = RangeLineMode;
+ } else if (m_submode == ReplaceSubMode) {
+ if (isVisualMode()) {
+ if (isVisualLineMode())
+ m_rangemode = RangeLineMode;
+ else if (isVisualBlockMode())
+ m_rangemode = RangeBlockMode;
+ else
+ m_rangemode = RangeCharMode;
+ leaveVisualMode();
+ Range range = currentRange();
+ Transformation tr =
+ &FakeVimHandler::Private::replaceByCharTransform;
+ transformText(range, tr, input.asChar());
+ setPosition(range.beginPos);
+ } else if (count() <= rightDist()) {
+ setAnchor();
+ moveRight(count());
+ replaceText(currentRange(), QString(count(), input.asChar()));
+ moveLeft();
+ setTargetColumn();
+ setDotCommand("%1r" + input.text(), count());
+ }
+ m_submode = NoSubMode;
+ finishMovement();
} else if (m_submode == ChangeSubMode && input.is('c')) { // tested
moveToStartOfLine();
setAnchor();
@@ -1519,12 +1745,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement();
} else if (m_submode == ZSubMode) {
//qDebug() << "Z_MODE " << cursorLineInDocument() << linesOnScreen();
- if (input.isKey(Key_Return) || input.is('t')) {
+ if (input.isReturn() || input.is('t')) {
// Cursor line to top of window.
if (!m_mvcount.isEmpty())
setPosition(firstPositionInLine(count()));
scrollUp(- cursorLineOnScreen());
- if (input.isKey(Key_Return))
+ if (input.isReturn())
moveToFirstNonBlankOnLine();
finishMovement();
} else if (input.is('.') || input.is('z')) {
@@ -1554,23 +1780,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
handleExCommand(QString(QLatin1Char('x')));
else if (input.is('Q'))
handleExCommand("q!");
- } else if (m_submode == ReplaceSubMode) {
- const QString text = input.text();
- if (count() <= (rightDist() + atEndOfLine()) && text.size() == 1
- && (text.at(0).isPrint() || text.at(0).isSpace())) {
- if (atEndOfLine())
- moveLeft();
- setAnchor();
- moveRight(count());
- removeSelectedText();
- m_tc.insertText(QString(count(), text.at(0)));
- m_movetype = MoveExclusive;
- setDotCommand("%1r" + text, count());
- moveLeft();
- }
- setTargetColumn();
- m_submode = NoSubMode;
- finishMovement();
} else if (input.isDigit()) {
if (input.is('0') && m_mvcount.isEmpty()) {
m_movetype = MoveExclusive;
@@ -1601,18 +1810,18 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement();
} else if (input.is(':')) {
enterExMode();
+ g.commandHistory.restart();
m_currentMessage.clear();
m_commandBuffer.clear();
if (isVisualMode())
m_commandBuffer = "'<,'>";
- m_commandHistory.append(QString());
- m_commandHistoryIndex = m_commandHistory.size() - 1;
updateMiniBuffer();
} else if (input.is('/') || input.is('?')) {
+ m_lastSearchForward = input.is('/');
+ g.searchHistory.restart();
if (hasConfig(ConfigUseCoreSearch)) {
// re-use the core dialog.
m_findPending = true;
- m_lastSearchForward = (input.is('/'));
EDITOR(setTextCursor(m_tc));
emit q->findRequested(!m_lastSearchForward);
m_tc = EDITOR(textCursor());
@@ -1620,25 +1829,35 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else {
// FIXME: make core find dialog sufficiently flexible to
// produce the "default vi" behaviour too. For now, roll our own.
- enterExMode(); // to get the cursor disabled
m_currentMessage.clear();
- m_mode = (input.is('/')) ? SearchForwardMode : SearchBackwardMode;
- m_commandBuffer.clear();
- m_searchHistory.append(QString());
- m_searchHistoryIndex = m_searchHistory.size() - 1;
+ m_movetype = MoveExclusive;
+ m_subsubmode = SearchSubSubMode;
+ m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?');
+ m_commandBuffer = QString();
+ updateCursor();
updateMiniBuffer();
}
} else if (input.is('`')) {
m_subsubmode = BackTickSubSubMode;
} else if (input.is('#') || input.is('*')) {
// FIXME: That's not proper vim behaviour
- m_tc.select(QTextCursor::WordUnderCursor);
- QString needle = "\\<" + m_tc.selection().toPlainText() + "\\>";
- m_searchHistory.append(needle);
- m_lastSearchForward = (input.is('*'));
- updateMiniBuffer();
- search(needle, m_lastSearchForward);
- recordJump();
+ QTextCursor tc = m_tc;
+ tc.select(QTextCursor::WordUnderCursor);
+ QString needle = "\\<" + tc.selection().toPlainText() + "\\>";
+ g.searchHistory.append(needle);
+ m_lastSearchForward = input.is('*');
+ m_currentMessage.clear();
+ m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?');
+ m_commandBuffer = needle;
+ SearchData sd;
+ sd.needle = needle;
+ sd.forward = m_lastSearchForward;
+ sd.highlightCursor = false;
+ sd.highlightMatches = true;
+ search(sd);
+ //m_searchCursor = QTextCursor();
+ //updateSelection();
+ //updateMiniBuffer();
} else if (input.is('\'')) {
m_subsubmode = TickSubSubMode;
} else if (input.is('|')) {
@@ -1652,12 +1871,11 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
enterExMode();
m_currentMessage.clear();
m_commandBuffer = "'<,'>!";
- m_commandHistory.append(QString());
- m_commandHistoryIndex = m_commandHistory.size() - 1;
+ //g.commandHistory.append(QString());
updateMiniBuffer();
} else if (input.is('"')) {
m_submode = RegisterSubMode;
- } else if (input.isKey(Key_Return)) {
+ } else if (input.isReturn()) {
moveToStartOfLine();
moveDown();
moveToFirstNonBlankOnLine();
@@ -1693,12 +1911,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if (input.is(',')) {
passShortcuts(true);
} else if (input.is('.')) {
- //qDebug() << "REPEATING" << quoteUnprintable(m_dotCommand) << count();
- QString savedCommand = m_dotCommand;
- m_dotCommand.clear();
+ //qDebug() << "REPEATING" << quoteUnprintable(g.dotCommand) << count()
+ // << input;
+ QString savedCommand = g.dotCommand;
+ g.dotCommand.clear();
replay(savedCommand, count());
enterCommandMode();
- m_dotCommand = savedCommand;
+ g.dotCommand = savedCommand;
} else if (input.is('<') && isNoVisualMode()) {
m_submode = ShiftLeftSubMode;
} else if (input.is('<') && isVisualMode()) {
@@ -1722,12 +1941,16 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement();
} else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) {
leaveVisualMode();
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
m_lastInsertion.clear();
if (!atEndOfLine())
moveRight();
updateMiniBuffer();
} else if (input.is('A')) {
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
moveBehindEndOfLine();
setDotCommand(QString(QLatin1Char('A')));
@@ -1791,14 +2014,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if ((input.is('d') || input.is('x')) && isVisualLineMode()) {
leaveVisualMode();
m_rangemode = RangeLineMode;
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
handleStartOfLine();
} else if ((input.is('d') || input.is('x')) && isVisualBlockMode()) {
leaveVisualMode();
m_rangemode = RangeBlockMode;
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
setPosition(qMin(position(), anchor()));
} else if (input.is('D') && isNoVisualMode()) {
if (atEndOfLine())
@@ -1815,14 +2038,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
leaveVisualMode();
m_rangemode = RangeLineMode;
m_submode = NoSubMode;
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
moveToFirstNonBlankOnLine();
} else if ((input.is('D') || input.is('X')) && isVisualBlockMode()) {
leaveVisualMode();
m_rangemode = RangeBlockAndTailMode;
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
setPosition(qMin(position(), anchor()));
} else if (input.isControl('d')) {
int sline = cursorLineOnScreen();
@@ -1874,8 +2097,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
m_tc.setPosition(firstPositionInLine(n), KeepAnchor);
}
finishMovement(dotCommand);
- } else if (input.is('h') || input.isKey(Key_Left)
- || input.isKey(Key_Backspace) || input.isControl('h')) {
+ } else if (input.is('h') || input.isKey(Key_Left) || input.isBackspace()) {
m_movetype = MoveExclusive;
int n = qMin(count(), leftDist());
if (m_fakeEnd && m_tc.block().length() > 1)
@@ -1890,6 +2112,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement();
} else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) {
setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count());
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
updateMiniBuffer();
if (atEndOfLine())
@@ -1909,6 +2133,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
m_gflag = false;
m_tc.clearSelection();
}
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
} else if (input.isControl('i')) {
if (!m_jumpListRedo.isEmpty()) {
@@ -1930,12 +2156,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
setAnchor();
moveRight();
if (m_gflag) {
- removeSelectedText();
+ removeText(currentRange());
} else {
while (characterAtCursor() == ' '
|| characterAtCursor() == '\t')
moveRight();
- removeSelectedText();
+ removeText(currentRange());
m_tc.insertText(QString(QLatin1Char(' ')));
}
}
@@ -1973,8 +2199,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
handleStartOfLine();
finishMovement();
} else if (input.is('n') || input.is('N')) {
- search(lastSearchString(), m_lastSearchForward);
- recordJump();
+ SearchData sd;
+ sd.needle = g.searchHistory.current();
+ sd.forward = input.is('n') ? m_lastSearchForward : !m_lastSearchForward;
+ sd.highlightCursor = false;
+ sd.highlightMatches = true;
+ search(sd);
} else if (isVisualMode() && (input.is('o') || input.is('O'))) {
int pos = position();
setPosition(anchor());
@@ -1985,20 +2215,28 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
if (m_positionPastEnd)
m_visualTargetColumn = -1;
updateSelection();
- } else if (input.is('o') || input.is('O')) {
- beginEditBlock();
+ } else if (input.is('o')) {
setDotCommand("%1o", count());
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
- m_beginEditBlock = false;
+ beginEditBlock(position());
moveToFirstNonBlankOnLine();
- if (input.is('O'))
- moveToStartOfLine();
- else
- moveBehindEndOfLine();
- m_tc.insertText("\n");
- if (input.is('O'))
- moveUp();
- insertAutomaticIndentation(input.is('o'));
+ moveBehindEndOfLine();
+ insertText(Register("\n"));
+ insertAutomaticIndentation(true);
+ endEditBlock();
+ } else if (input.is('O')) {
+ setDotCommand("%1O", count());
+ setUndoPosition(position());
+ breakEditBlock();
+ enterInsertMode();
+ beginEditBlock(position());
+ moveToFirstNonBlankOnLine();
+ moveToStartOfLine();
+ insertText(Register("\n"));
+ moveUp();
+ insertAutomaticIndentation(false);
endEditBlock();
} else if (input.isControl('o')) {
if (!m_jumpListUndo.isEmpty()) {
@@ -2011,19 +2249,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
setTargetColumn();
setDotCommand("%1p", count());
finishMovement();
- } else if (isVisualMode() && input.is('r')) {
- m_submode = TransformSubMode;
- m_subsubmode = ReplaceSubSubMode;
} else if (input.is('r')) {
m_submode = ReplaceSubMode;
- setDotCommand(QString(QLatin1Char('r')));
} else if (!isVisualMode() && input.is('R')) {
- // FIXME: right now we repeat the insertion count() times,
- // but not the deletion
- m_lastInsertion.clear();
- enterInsertMode();
- m_submode = ReplaceSubMode;
- setDotCommand(QString(QLatin1Char('R')));
+ setUndoPosition(position());
+ breakEditBlock();
+ enterReplaceMode();
updateMiniBuffer();
} else if (input.isControl('r')) {
redo();
@@ -2033,11 +2264,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
moveLeft();
setAnchor();
moveRight(qMin(count(), rightDist()));
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
setDotCommand("%1s", count());
m_opcount.clear();
m_mvcount.clear();
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
} else if (input.is('S')) {
if (!isVisualMode()) {
@@ -2046,8 +2279,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
setPosition(lastPositionInLine(line + count() - 1));
}
setDotCommand("%1S", count());
+ setUndoPosition(position());
+ breakEditBlock();
enterInsertMode();
- m_beginEditBlock = false;
m_submode = ChangeSubMode;
m_movetype = MoveLineWise;
finishMovement();
@@ -2116,8 +2350,8 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
if (leftDist() > 0) {
setAnchor();
moveLeft(qMin(count(), leftDist()));
- yankSelectedText();
- removeSelectedText();
+ yankText(currentRange(), m_register);
+ removeText(currentRange());
}
finishMovement();
} else if ((m_submode == YankSubMode && input.is('y'))
@@ -2143,14 +2377,14 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|| (input.is('Y') && isVisualLineMode())
|| (input.is('Y') && isVisualCharMode())) {
m_rangemode = RangeLineMode;
- yankSelectedText();
+ yankText(currentRange(), m_register);
setPosition(qMin(position(), anchor()));
moveToStartOfLine();
leaveVisualMode();
finishMovement();
} else if ((input.is('y') || input.is('Y')) && isVisualBlockMode()) {
m_rangemode = RangeBlockMode;
- yankSelectedText();
+ yankText(currentRange(), m_register);
setPosition(qMin(position(), anchor()));
leaveVisualMode();
finishMovement();
@@ -2159,18 +2393,19 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if (input.is('Z')) {
m_submode = CapitalZSubMode;
} else if (!m_gflag && input.is('~') && !isVisualMode()) {
+ m_movetype = MoveExclusive;
if (!atEndOfLine()) {
beginEditBlock();
setAnchor();
moveRight(qMin(count(), rightDist()));
if (input.is('~')) {
- invertCaseSelectedText();
+ invertCase(currentRange());
setDotCommand("%1~", count());
} else if (input.is('u')) {
- downCaseSelectedText();
+ downCase(currentRange());
setDotCommand("%1gu", count());
} else if (input.is('U')) {
- upCaseSelectedText();
+ upCase(currentRange());
setDotCommand("%1gU", count());
}
endEditBlock();
@@ -2180,6 +2415,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|| (m_gflag && input.is('u') && !isVisualMode())
|| (m_gflag && input.is('U') && !isVisualMode())) {
m_gflag = false;
+ m_movetype = MoveExclusive;
if (atEndOfLine())
moveLeft();
setAnchor();
@@ -2194,6 +2430,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
|| (m_gflag && input.is('u') && isVisualMode())
|| (m_gflag && input.is('U') && isVisualMode())) {
m_gflag = false;
+ m_movetype = MoveExclusive;
if (isVisualLineMode())
m_rangemode = RangeLineMode;
else if (isVisualBlockMode())
@@ -2220,7 +2457,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
} else if (input.is(Key_Delete)) {
setAnchor();
moveRight(qMin(1, rightDist()));
- removeSelectedText();
+ removeText(currentRange());
} else if (input.is(Key_BracketLeft) || input.is(Key_BracketRight)) {
} else if (input.isControl(Key_BracketRight)) {
@@ -2241,13 +2478,36 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
return handled;
}
+EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
+{
+ if (input.isEscape()) {
+ moveLeft(qMin(1, leftDist()));
+ setTargetColumn();
+ m_submode = NoSubMode;
+ m_mode = CommandMode;
+ finishMovement();
+ } else {
+ joinPreviousEditBlock();
+ if (!atEndOfLine()) {
+ setAnchor();
+ moveRight();
+ m_lastDeletion += selectText(Range(position(), anchor()));
+ removeText(currentRange());
+ }
+ const QString text = input.text();
+ m_lastInsertion += text;
+ insertText(text);
+ endEditBlock();
+ }
+ return EventHandled;
+}
+
EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
{
//const int key = input.key;
//const QString &text = input.text;
- if (input.isKey(Key_Escape) || input.isKey(27) || input.isControl('c') ||
- input.isControl(Key_BracketLeft)) {
+ if (input.isEscape()) {
if (isVisualBlockMode() && !m_lastInsertion.contains('\n')) {
leaveVisualMode();
joinPreviousEditBlock();
@@ -2257,7 +2517,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
setTargetColumn();
for (int i = 0; i < m_visualInsertCount; ++i) {
moveDown();
- m_tc.insertText(m_lastInsertion);
+ insertText(m_lastInsertion);
}
moveLeft(1);
Range range(pos, position(), RangeBlockMode);
@@ -2266,32 +2526,26 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
setDotCommand("p");
endEditBlock();
} else {
- // normal insertion. start with '1', as one instance was
- // already physically inserted while typing
- QString data = m_lastInsertion;
- for (int i = 1; i < count(); ++i) {
- m_tc.insertText(m_lastInsertion);
+ // Normal insertion. Start with '1', as one instance was
+ // already physically inserted while typing.
+ QString data;
+ for (int i = 1; i < count(); ++i)
data += m_lastInsertion;
- }
+ insertText(data);
moveLeft(qMin(1, leftDist()));
setTargetColumn();
leaveVisualMode();
- recordNewUndo();
}
- m_dotCommand += m_lastInsertion;
- m_dotCommand += QChar(27);
+ g.dotCommand += m_lastInsertion;
+ g.dotCommand += QChar(27);
enterCommandMode();
m_submode = NoSubMode;
} else if (input.isKey(Key_Insert)) {
- if (m_submode == ReplaceSubMode) {
- EDITOR(setCursorWidth(m_cursorWidth));
- EDITOR(setOverwriteMode(false));
- m_submode = NoSubMode;
- } else {
- EDITOR(setCursorWidth(m_cursorWidth));
- EDITOR(setOverwriteMode(true));
- m_submode = ReplaceSubMode;
- }
+ if (m_mode == ReplaceMode)
+ m_mode = InsertMode;
+ else
+ m_mode = ReplaceMode;
+ updateCursor();
} else if (input.isKey(Key_Left)) {
moveLeft(count());
setTargetColumn();
@@ -2320,13 +2574,13 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
moveBehindEndOfLine();
setTargetColumn();
m_lastInsertion.clear();
- } else if (input.isKey(Key_Return)) {
+ } else if (input.isReturn()) {
m_submode = NoSubMode;
- m_tc.insertBlock();
+ insertText(Register("\n"));
m_lastInsertion += "\n";
insertAutomaticIndentation(true);
setTargetColumn();
- } else if (input.isKey(Key_Backspace) || input.isControl('h')) {
+ } else if (input.isBackspace()) {
joinPreviousEditBlock();
m_justAutoIndented = 0;
if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) {
@@ -2345,6 +2599,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
m_lastInsertion.clear(); // FIXME
} else {
m_tc.deletePreviousChar();
+ fixMarks(position(), -1);
m_lastInsertion.chop(1);
}
setTargetColumn();
@@ -2367,7 +2622,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
const int col = physicalCursorColumnInDocument();
QString str = QString(ts - col % ts, ' ');
m_lastInsertion.append(str);
- m_tc.insertText(str);
+ insertText(str);
setTargetColumn();
} else if (input.isControl('d')) {
// remove one level of indentation from the current line
@@ -2390,33 +2645,21 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
//} else if (key >= control('a') && key <= control('z')) {
// // ignore these
} else if (!input.text().isEmpty()) {
- const QString text = input.text();
- if (m_beginEditBlock) {
- beginEditBlock();
- m_beginEditBlock = false;
- } else {
- joinPreviousEditBlock();
- }
+ joinPreviousEditBlock();
m_justAutoIndented = 0;
+ const QString text = input.text();
m_lastInsertion.append(text);
- if (m_submode == ReplaceSubMode) {
- if (atEndOfLine())
- m_submode = NoSubMode;
- else
- m_tc.deleteChar();
- }
- m_tc.insertText(text);
+ insertText(text);
if (hasConfig(ConfigSmartIndent) && isElectricCharacter(text.at(0))) {
const QString leftText = m_tc.block().text()
.left(m_tc.position() - 1 - m_tc.block().position());
if (leftText.simplified().isEmpty()) {
- Range range(position(), position());
- range.rangemode = m_rangemode;
+ Range range(position(), position(), m_rangemode);
indentText(range, text.at(0));
}
}
- if (!m_inReplay)
+ if (!g.inReplay)
emit q->completionRequested();
setTargetColumn();
endEditBlock();
@@ -2427,15 +2670,15 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
return EventHandled;
}
-EventResult FakeVimHandler::Private::handleMiniBufferModes(const Input &input)
+EventResult FakeVimHandler::Private::handleExMode(const Input &input)
{
- if (input.isKey(Key_Escape) || input.isControl('c')
- || input.isControl(Key_BracketLeft)) {
+ if (input.isEscape()) {
m_commandBuffer.clear();
enterCommandMode();
updateMiniBuffer();
- } else if (input.isKey(Key_Backspace)) {
+ } else if (input.isBackspace()) {
if (m_commandBuffer.isEmpty()) {
+ m_commandPrefix.clear();
enterCommandMode();
} else {
m_commandBuffer.chop(1);
@@ -2446,74 +2689,109 @@ EventResult FakeVimHandler::Private::handleMiniBufferModes(const Input &input)
if (!m_commandBuffer.isEmpty())
m_commandBuffer.chop(1);
updateMiniBuffer();
- } else if (input.isKey(Key_Return) && m_mode == ExMode) {
+ } else if (input.isReturn()) {
if (!m_commandBuffer.isEmpty()) {
- m_commandHistory.takeLast();
- m_commandHistory.append(m_commandBuffer);
+ //g.commandHistory.takeLast();
+ g.commandHistory.append(m_commandBuffer);
handleExCommand(m_commandBuffer);
- if (m_textedit || m_plaintextedit) {
+ if (m_textedit || m_plaintextedit)
leaveVisualMode();
- }
}
- } else if (input.isKey(Key_Return) && isSearchMode()
- && !hasConfig(ConfigIncSearch)) {
- if (!m_commandBuffer.isEmpty()) {
- m_searchHistory.takeLast();
- m_searchHistory.append(m_commandBuffer);
- m_lastSearchForward = (m_mode == SearchForwardMode);
- search(lastSearchString(), m_lastSearchForward);
- recordJump();
- }
- enterCommandMode();
updateMiniBuffer();
- } else if ((input.isKey(Key_Up) || input.isKey(Key_PageUp)) && isSearchMode()) {
- // FIXME: This and the three cases below are wrong as vim
- // takes only matching entries in the history into account.
- if (m_searchHistoryIndex > 0) {
- --m_searchHistoryIndex;
- showBlackMessage(m_searchHistory.at(m_searchHistoryIndex));
- }
- } else if ((input.isKey(Key_Up) || input.isKey(Key_PageUp)) && m_mode == ExMode) {
- if (m_commandHistoryIndex > 0) {
- --m_commandHistoryIndex;
- showBlackMessage(m_commandHistory.at(m_commandHistoryIndex));
- }
- } else if ((input.isKey(Key_Down) || input.isKey(Key_PageDown)) && isSearchMode()) {
- if (m_searchHistoryIndex < m_searchHistory.size() - 1) {
- ++m_searchHistoryIndex;
- showBlackMessage(m_searchHistory.at(m_searchHistoryIndex));
- }
- } else if ((input.isKey(Key_Down) || input.isKey(Key_PageDown)) && m_mode == ExMode) {
- if (m_commandHistoryIndex < m_commandHistory.size() - 1) {
- ++m_commandHistoryIndex;
- showBlackMessage(m_commandHistory.at(m_commandHistoryIndex));
- }
+ } else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
+ g.commandHistory.up();
+ m_commandBuffer = g.commandHistory.current();
+ updateMiniBuffer();
+ } else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
+ g.commandHistory.down();
+ m_commandBuffer = g.commandHistory.current();
+ updateMiniBuffer();
} else if (input.isKey(Key_Tab)) {
m_commandBuffer += QChar(9);
updateMiniBuffer();
- } else if (input.isKey(Key_Return) && isSearchMode()
- && hasConfig(ConfigIncSearch)) {
+ } else if (!input.text().isEmpty()) {
+ m_commandBuffer += input.text();
+ updateMiniBuffer();
+ } else {
+ qDebug() << "IGNORED IN EX-MODE: " << input.key() << input.text();
+ return EventUnhandled;
+ }
+ return EventHandled;
+}
+
+EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
+{
+ if (input.isEscape()) {
+ m_commandBuffer.clear();
+ m_searchCursor = QTextCursor();
+ updateSelection();
+ enterCommandMode();
+ updateMiniBuffer();
+ } else if (input.isBackspace()) {
+ if (m_commandBuffer.isEmpty()) {
+ m_commandPrefix.clear();
+ m_searchCursor = QTextCursor();
+ enterCommandMode();
+ } else {
+ m_commandBuffer.chop(1);
+ }
+ updateMiniBuffer();
+ } else if (input.isKey(Key_Left)) {
+ if (!m_commandBuffer.isEmpty())
+ m_commandBuffer.chop(1);
+ updateMiniBuffer();
+ } else if (input.isReturn()) {
+ m_searchCursor = QTextCursor();
+ QString needle = m_commandBuffer;
+ if (!needle.isEmpty()) {
+ g.searchHistory.append(needle);
+ if (!hasConfig(ConfigIncSearch)) {
+ SearchData sd;
+ sd.needle = needle;
+ sd.forward = m_lastSearchForward;
+ sd.highlightCursor = false;
+ sd.highlightMatches = true;
+ search(sd);
+ }
+ finishMovement(m_commandPrefix + needle + "\n");
+ }
enterCommandMode();
- QString needle = m_commandBuffer.mid(1); // FIXME: why
highlightMatches(needle);
updateMiniBuffer();
- } else if (isSearchMode() && hasConfig(ConfigIncSearch)) {
- m_commandBuffer = m_commandBuffer.mid(1); // FIXME: why
- QString needle = m_commandBuffer + input.text();
- search(needle, m_lastSearchForward, true);
+ } else if (input.isKey(Key_Up) || input.isKey(Key_PageUp)) {
+ // FIXME: This and the three cases below are wrong as vim
+ // takes only matching entries in the history into account.
+ g.searchHistory.up();
+ showBlackMessage(g.searchHistory.current());
+ } else if (input.isKey(Key_Down) || input.isKey(Key_PageDown)) {
+ g.searchHistory.down();
+ showBlackMessage(g.searchHistory.current());
+ } else if (input.isKey(Key_Tab)) {
+ m_commandBuffer += QChar(9);
updateMiniBuffer();
- recordJump();
} else if (!input.text().isEmpty()) {
m_commandBuffer += input.text();
updateMiniBuffer();
- } else {
- qDebug() << "IGNORED IN MINIBUFFER MODE: " << input.key() << input.text();
- return EventUnhandled;
}
+
+ if (hasConfig(ConfigIncSearch) && !input.isReturn() && !input.isEscape()) {
+ SearchData sd;
+ sd.needle = m_commandBuffer;
+ sd.forward = m_lastSearchForward;
+ sd.mustMove = false;
+ sd.highlightCursor = true;
+ sd.highlightMatches = false;
+ search(sd);
+ }
+
+ //else {
+ // qDebug() << "IGNORED IN SEARCH MODE: " << input.key() << input.text();
+ // return EventUnhandled;
+ //}
return EventHandled;
}
-// 1 based.
+// This uses 1 based line counting.
int FakeVimHandler::Private::readLineCode(QString &cmd)
{
//qDebug() << "CMD: " << cmd;
@@ -2521,19 +2799,32 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
return -1;
QChar c = cmd.at(0);
cmd = cmd.mid(1);
- if (c == '.')
+ if (c == '.') {
+ if (cmd.isEmpty())
+ return cursorLineInDocument() + 1;
+ QChar c1 = cmd.at(0);
+ if (c1 == '+' || c1 == '-') {
+ // Repeat for things like .+4
+ cmd = cmd.mid(1);
+ return cursorLineInDocument() + readLineCode(cmd);
+ }
return cursorLineInDocument() + 1;
+ }
if (c == '$')
return linesInDocument();
if (c == '\'' && !cmd.isEmpty()) {
- int mark = m_marks.value(cmd.at(0).unicode());
- if (!mark) {
- showRedMessage(msgE20MarkNotSet(cmd.at(0)));
+ if (cmd.isEmpty()) {
+ showRedMessage(msgMarkNotSet(QString()));
+ return -1;
+ }
+ int m = mark(cmd.at(0).unicode());
+ if (m == -1) {
+ showRedMessage(msgMarkNotSet(cmd.at(0)));
cmd = cmd.mid(1);
return -1;
}
cmd = cmd.mid(1);
- return lineForPosition(mark);
+ return lineForPosition(m);
}
if (c == '-') {
int n = readLineCode(cmd);
@@ -2544,10 +2835,9 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
return cursorLineInDocument() + 1 + (n == -1 ? 1 : n);
}
if (c == '\'' && !cmd.isEmpty()) {
- int pos = m_marks.value(cmd.at(0).unicode(), -1);
- //qDebug() << " MARK: " << cmd.at(0) << pos << lineForPosition(pos);
+ int pos = mark(cmd.at(0).unicode());
if (pos == -1) {
- showRedMessage(msgE20MarkNotSet(cmd.at(0)));
+ showRedMessage(msgMarkNotSet(cmd.at(0)));
cmd = cmd.mid(1);
return -1;
}
@@ -2566,24 +2856,16 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
//qDebug() << "N: " << n;
return n;
}
- // not parsed
+ // Parsing failed.
cmd = c + cmd;
return -1;
}
-void FakeVimHandler::Private::selectRange(int beginLine, int endLine)
+void FakeVimHandler::Private::setCurrentRange(const Range &range)
{
- if (beginLine == -1)
- beginLine = cursorLineInDocument();
- if (endLine == -1)
- endLine = cursorLineInDocument();
- if (beginLine > endLine)
- qSwap(beginLine, endLine);
- setAnchor(firstPositionInLine(beginLine));
- if (endLine == linesInDocument())
- setPosition(lastPositionInLine(endLine));
- else
- setPosition(firstPositionInLine(endLine + 1));
+ setAnchor(range.beginPos);
+ setPosition(range.endPos);
+ m_rangemode = range.rangemode;
}
// use handleExCommand for invoking commands that might move the cursor
@@ -2594,71 +2876,46 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd)
EDITOR(setTextCursor(m_tc));
}
-QString FakeVimHandler::Private::extractCommand(const QString &line,
- int *beginLine, int *endLine)
-{
- QString cmd = line;
- *beginLine = -1;
- *endLine = -1;
-
- // FIXME: that seems to be different for %w and %s
- if (cmd.startsWith(QLatin1Char('%')))
- cmd = "1,$" + cmd.mid(1);
-
- int lineNumber = readLineCode(cmd);
- if (lineNumber != -1)
- *beginLine = lineNumber;
-
- if (cmd.startsWith(',')) {
- cmd = cmd.mid(1);
- lineNumber = readLineCode(cmd);
- if (lineNumber != -1)
- *endLine = lineNumber;
- }
- //qDebug() << "RANGE: " << beginLine << endLine << cmd << lineNumber << m_marks;
- return cmd;
-}
-
-bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
+bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd)
// :substitute
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- if (cmd.startsWith(QLatin1String("substitute")))
- cmd = cmd.mid(10);
- else if (cmd.startsWith('s') && line.size() > 1
- && !isalpha(cmd.at(1).unicode()))
- cmd = cmd.mid(1);
+ QString line = cmd.cmd + ' ' + cmd.args;
+ line = line.trimmed();
+ if (line.startsWith(_("substitute")))
+ line = line.mid(10);
+ else if (line.startsWith('s') && line.size() > 1
+ && !isalpha(line.at(1).unicode()))
+ line = line.mid(1);
else
return false;
+
// we have /{pattern}/{string}/[flags] now
- if (cmd.isEmpty())
+ if (line.isEmpty())
return false;
- const QChar separator = cmd.at(0);
+ const QChar separator = line.at(0);
int pos1 = -1;
int pos2 = -1;
int i;
- for (i = 1; i < cmd.size(); ++i) {
- if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+ for (i = 1; i < line.size(); ++i) {
+ if (line.at(i) == separator && line.at(i - 1) != '\\') {
pos1 = i;
break;
}
}
if (pos1 == -1)
return false;
- for (++i; i < cmd.size(); ++i) {
- if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+ for (++i; i < line.size(); ++i) {
+ if (line.at(i) == separator && line.at(i - 1) != '\\') {
pos2 = i;
break;
}
}
if (pos2 == -1)
- pos2 = cmd.size();
+ pos2 = line.size();
- QString needle = cmd.mid(1, pos1 - 1);
- const QString replacement = cmd.mid(pos1 + 1, pos2 - pos1 - 1);
- QString flags = cmd.mid(pos2 + 1);
+ QString needle = line.mid(1, pos1 - 1);
+ const QString replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
+ QString flags = line.mid(pos2 + 1);
needle.replace('$', '\n');
needle.replace("\\\n", "\\$");
@@ -2666,6 +2923,8 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
if (flags.contains('i'))
pattern.setCaseSensitivity(Qt::CaseInsensitive);
const bool global = flags.contains('g');
+ const int beginLine = lineForPosition(cmd.range.beginPos);
+ const int endLine = lineForPosition(cmd.range.endPos);
beginEditBlock();
for (int line = endLine; line >= beginLine; --line) {
QString origText = lineContents(line);
@@ -2700,19 +2959,12 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
return true;
}
-bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
+bool FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map
{
- int pos1 = line.indexOf(QLatin1Char(' '));
- if (pos1 == -1)
- return false;
- int pos2 = line.indexOf(QLatin1Char(' '), pos1 + 1);
- if (pos2 == -1)
- return false;
-
QByteArray modes;
enum Type { Map, Noremap, Unmap } type;
- QByteArray cmd = line.left(pos1).toLatin1();
+ QByteArray cmd = cmd0.cmd.toLatin1();
// Strange formatting. But everything else is even uglier.
if (cmd == "map") { modes = "nvo"; type = Map; } else
@@ -2750,45 +3002,48 @@ bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
else
return false;
- QString lhs = line.mid(pos1 + 1, pos2 - pos1 - 1);
- QString rhs = line.mid(pos2 + 1);
+ const int pos = cmd0.args.indexOf(QLatin1Char(' '));
+ if (pos == -1) {
+ // FIXME: Dump mappings here.
+ //qDebug() << g.mappings;
+ return true;;
+ }
+
+ QString lhs = cmd0.args.left(pos);
+ QString rhs = cmd0.args.mid(pos + 1);
Inputs key;
- foreach (QChar c, lhs)
- key.append(Input(c));
+ key.parseFrom(lhs);
//qDebug() << "MAPPING: " << modes << lhs << rhs;
switch (type) {
case Unmap:
foreach (char c, modes)
- if (m_mappings.contains(c))
- m_mappings[c].remove(key);
+ if (g.mappings.contains(c))
+ g.mappings[c].remove(key);
break;
case Map:
rhs = rhs; // FIXME: expand rhs.
// Fall through.
case Noremap: {
- Inputs inputs;
- foreach (QChar c, rhs)
- inputs.append(Input(c));
+ Inputs inputs(rhs);
foreach (char c, modes)
- m_mappings[c].insert(key, inputs);
+ g.mappings[c].insert(key, inputs);
break;
}
}
return true;
}
-bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :history
+bool FakeVimHandler::Private::handleExHistoryCommand(const ExCommand &cmd)
{
- static QRegExp reHistory("^his(tory)?( (.*))?$");
- if (reHistory.indexIn(cmd) == -1)
+ // :history
+ if (cmd.cmd != "his" && cmd.cmd != "history")
return false;
- QString arg = reHistory.cap(3);
- if (arg.isEmpty()) {
+ if (cmd.args.isEmpty()) {
QString info;
info += "# command history\n";
int i = 0;
- foreach (const QString &item, m_commandHistory) {
+ foreach (const QString &item, g.commandHistory.items()) {
++i;
info += QString("%1 %2\n").arg(i, -8).arg(item);
}
@@ -2800,164 +3055,176 @@ bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :his
return true;
}
-bool FakeVimHandler::Private::handleExSetCommand(const QString &cmd) // :set
+bool FakeVimHandler::Private::handleExRegisterCommand(const ExCommand &cmd)
+{
+ // :reg and :di[splay]
+ if (cmd.cmd != "reg" && cmd.cmd != "registers"
+ && cmd.cmd != "di" && cmd.cmd != "display")
+ return false;
+
+ QByteArray regs = cmd.args.toLatin1();
+ if (regs.isEmpty()) {
+ regs = "\"0123456789";
+ QHashIterator<int, Register> it(g.registers);
+ while (it.hasNext()) {
+ it.next();
+ if (it.key() > '9')
+ regs += char(it.key());
+ }
+ }
+ QString info;
+ info += "--- Registers ---\n";
+ foreach (char reg, regs) {
+ QString value = quoteUnprintable(g.registers[reg].contents);
+ info += QString("\"%1 %2\n").arg(reg).arg(value);
+ }
+ emit q->extraInformationChanged(info);
+ updateMiniBuffer();
+ return true;
+}
+
+bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd)
{
- static QRegExp reSet("^set?( (.*))?$");
- if (reSet.indexIn(cmd) == -1)
+ // :set
+ if (cmd.cmd != "se" && cmd.cmd != "set")
return false;
showBlackMessage(QString());
- QString arg = reSet.cap(2);
- SavedAction *act = theFakeVimSettings()->item(arg);
- if (arg.isEmpty()) {
- theFakeVimSetting(SettingsDialog)->trigger(QVariant());
- } else if (act && act->value().type() == QVariant::Bool) {
- // boolean config to be switched on
+ SavedAction *act = theFakeVimSettings()->item(cmd.args);
+ QTC_ASSERT(!cmd.args.isEmpty(), /**/); // Handled by plugin.
+ if (act && act->value().type() == QVariant::Bool) {
+ // Boolean config to be switched on.
bool oldValue = act->value().toBool();
if (oldValue == false)
act->setValue(true);
else if (oldValue == true)
{} // nothing to do
} else if (act) {
- // non-boolean to show
- showBlackMessage(arg + '=' + act->value().toString());
- } else if (arg.startsWith(QLatin1String("no"))
- && (act = theFakeVimSettings()->item(arg.mid(2)))) {
- // boolean config to be switched off
+ // Non-boolean to show.
+ showBlackMessage(cmd.args + '=' + act->value().toString());
+ } else if (cmd.args.startsWith(_("no"))
+ && (act = theFakeVimSettings()->item(cmd.args.mid(2)))) {
+ // Boolean config to be switched off.
bool oldValue = act->value().toBool();
if (oldValue == true)
act->setValue(false);
else if (oldValue == false)
{} // nothing to do
- } else if (arg.contains('=')) {
- // non-boolean config to set
- int p = arg.indexOf('=');
- act = theFakeVimSettings()->item(arg.left(p));
+ } else if (cmd.args.contains('=')) {
+ // Non-boolean config to set.
+ int p = cmd.args.indexOf('=');
+ act = theFakeVimSettings()->item(cmd.args.left(p));
if (act)
- act->setValue(arg.mid(p + 1));
+ act->setValue(cmd.args.mid(p + 1));
} else {
- passUnknownSetCommand(arg);
+ showRedMessage(FakeVimHandler::tr("Unknown option: ") + cmd.args);
}
updateMiniBuffer();
updateEditor();
return true;
}
-bool FakeVimHandler::Private::handleExNormalCommand(const QString &cmd) // :normal
+bool FakeVimHandler::Private::handleExNormalCommand(const ExCommand &cmd)
{
- static QRegExp reNormal("^norm(al)?( (.*))?$");
- if (reNormal.indexIn(cmd) == -1)
+ // :normal
+ if (cmd.cmd != "norm" && cmd.cmd != "normal")
return false;
- //qDebug() << "REPLAY: " << reNormal.cap(3);
- replay(reNormal.cap(3), 1);
+ //qDebug() << "REPLAY NORMAL: " << quoteUnprintable(reNormal.cap(3));
+ replay(cmd.args, 1);
return true;
}
-bool FakeVimHandler::Private::handleExDeleteCommand(const QString &line) // :d
+bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- static QRegExp reDelete("^d( (.*))?$");
- if (reDelete.indexIn(cmd) != -1)
+ // :delete
+ if (cmd.cmd != "d" && cmd.cmd != "delete")
return false;
- selectRange(beginLine, endLine);
- QString reg = reDelete.cap(2);
- QString text = selectedText();
- removeSelectedText();
+ setCurrentRange(cmd.range);
+ QString reg = cmd.args;
+ QString text = selectText(cmd.range);
+ removeText(currentRange());
if (!reg.isEmpty()) {
- Register &r = m_registers[reg.at(0).unicode()];
+ Register &r = g.registers[reg.at(0).unicode()];
r.contents = text;
r.rangemode = RangeLineMode;
}
return true;
}
-bool FakeVimHandler::Private::handleExWriteCommand(const QString &line)
- // :w, :x, :q, :wq, ...
+bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd)
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
- if (reWrite.indexIn(cmd) == -1) // :w and :x
+ // :w, :x, :wq, ...
+ //static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
+ if (cmd.cmd != "w" && cmd.cmd != "x" && cmd.cmd != "wq")
return false;
- bool noArgs = (beginLine == -1);
+ int beginLine = lineForPosition(cmd.range.beginPos);
+ int endLine = lineForPosition(cmd.range.endPos);
+ const bool noArgs = (beginLine == -1);
if (beginLine == -1)
beginLine = 0;
if (endLine == -1)
endLine = linesInDocument();
//qDebug() << "LINES: " << beginLine << endLine;
- int indexOfSpace = cmd.indexOf(QChar(' '));
- QString prefix;
- if (indexOfSpace < 0)
- prefix = cmd;
- else
- prefix = cmd.left(indexOfSpace);
- bool forced = prefix.contains(QChar('!'));
- bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
- bool quitAll = quit && prefix.contains(QChar('a'));
- QString fileName = reWrite.cap(2);
+ QString prefix = cmd.args;
+ const bool forced = cmd.hasBang;
+ //const bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
+ //const bool quitAll = quit && prefix.contains(QChar('a'));
+ QString fileName = cmd.args;
if (fileName.isEmpty())
fileName = m_currentFileName;
QFile file1(fileName);
- bool exists = file1.exists();
+ const bool exists = file1.exists();
if (exists && !forced && !noArgs) {
showRedMessage(FakeVimHandler::tr
- ("File '%1' exists (add ! to override)").arg(fileName));
+ ("File \"%1\" exists (add ! to override)").arg(fileName));
} else if (file1.open(QIODevice::ReadWrite)) {
+ // Nobody cared, so act ourselves.
file1.close();
QTextCursor tc = m_tc;
Range range(firstPositionInLine(beginLine),
firstPositionInLine(endLine), RangeLineMode);
- QString contents = text(range);
+ QString contents = selectText(range);
m_tc = tc;
- //qDebug() << "LINES: " << beginLine << endLine;
- bool handled = false;
- emit q->writeFileRequested(&handled, fileName, contents);
- // nobody cared, so act ourselves
- if (!handled) {
- //qDebug() << "HANDLING MANUAL SAVE TO " << fileName;
- QFile::remove(fileName);
- QFile file2(fileName);
- if (file2.open(QIODevice::ReadWrite)) {
- QTextStream ts(&file2);
- ts << contents;
- } else {
- showRedMessage(FakeVimHandler::tr
- ("Cannot open file '%1' for writing").arg(fileName));
- }
+ QFile::remove(fileName);
+ QFile file2(fileName);
+ if (file2.open(QIODevice::ReadWrite)) {
+ QTextStream ts(&file2);
+ ts << contents;
+ } else {
+ showRedMessage(FakeVimHandler::tr
+ ("Cannot open file \"%1\" for writing").arg(fileName));
}
- // check result by reading back
+ // Check result by reading back.
QFile file3(fileName);
file3.open(QIODevice::ReadOnly);
QByteArray ba = file3.readAll();
showBlackMessage(FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
.arg(fileName).arg(exists ? " " : " [New] ")
.arg(ba.count('\n')).arg(ba.size()));
- if (quitAll)
- passUnknownExCommand(forced ? "qa!" : "qa");
- else if (quit)
- passUnknownExCommand(forced ? "q!" : "q");
+ //if (quitAll)
+ // passUnknownExCommand(forced ? "qa!" : "qa");
+ //else if (quit)
+ // passUnknownExCommand(forced ? "q!" : "q");
} else {
showRedMessage(FakeVimHandler::tr
- ("Cannot open file '%1' for reading").arg(fileName));
+ ("Cannot open file \"%1\" for reading").arg(fileName));
}
return true;
}
-bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
+bool FakeVimHandler::Private::handleExReadCommand(const ExCommand &cmd)
{
- if (!line.startsWith(QLatin1String("r ")))
+ // :read
+ if (cmd.cmd != "r" && cmd.cmd != "read")
return false;
beginEditBlock();
moveToStartOfLine();
setTargetColumn();
moveDown();
- m_currentFileName = line.mid(2);
+ m_currentFileName = cmd.args;
QFile file(m_currentFileName);
file.open(QIODevice::ReadOnly);
QTextStream ts(&file);
@@ -2969,28 +3236,28 @@ bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
return true;
}
-bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
+bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- if (!cmd.startsWith(QLatin1Char('!')))
+ if (!cmd.cmd.startsWith(QLatin1Char('!')))
return false;
- selectRange(beginLine, endLine);
- int targetPosition = firstPositionInLine(beginLine);
- QString command = cmd.mid(1).trimmed();
- QString text = selectedText();
+ setCurrentRange(cmd.range);
+ int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
+ QString command = QString(cmd.cmd.mid(1) + ' ' + cmd.args).trimmed();
+ QString text = selectText(cmd.range);
QProcess proc;
- proc.start(cmd.mid(1));
+ proc.start(command);
proc.waitForStarted();
+#ifdef Q_OS_WIN
+ text.replace(_("\n"), _("\r\n"));
+#endif
proc.write(text.toUtf8());
proc.closeWriteChannel();
proc.waitForFinished();
QString result = QString::fromUtf8(proc.readAllStandardOutput());
beginEditBlock(targetPosition);
- removeSelectedText();
- m_tc.insertText(result);
+ removeText(currentRange());
+ insertText(result);
setPosition(targetPosition);
endEditBlock();
leaveVisualMode();
@@ -3000,26 +3267,29 @@ bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
return true;
}
-bool FakeVimHandler::Private::handleExShiftRightCommand(const QString &line) // :>
+bool FakeVimHandler::Private::handleExShiftCommand(const ExCommand &cmd)
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- if (!cmd.startsWith(QLatin1Char('>')))
+ if (cmd.cmd != "<" && cmd.cmd != ">")
return false;
- m_anchor = firstPositionInLine(beginLine);
- setPosition(firstPositionInLine(endLine));
- shiftRegionRight(1);
+ setCurrentRange(cmd.range);
+ int count = qMin(1, cmd.args.toInt());
+ if (cmd.cmd == "<")
+ shiftRegionLeft(count);
+ else
+ shiftRegionRight(count);
leaveVisualMode();
- showBlackMessage(FakeVimHandler::tr("%n lines >ed %1 time", 0,
- (endLine - beginLine + 1)).arg(1));
+ const int beginLine = lineForPosition(cmd.range.beginPos);
+ const int endLine = lineForPosition(cmd.range.endPos);
+ showBlackMessage(FakeVimHandler::tr("%n lines %1ed %2 time", 0,
+ (endLine - beginLine + 1)).arg(cmd.cmd).arg(count));
return true;
}
-bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
+bool FakeVimHandler::Private::handleExRedoCommand(const ExCommand &cmd)
{
- if (line != "red" && line != "redo")
+ // :redo
+ if (cmd.cmd != "red" && cmd.cmd != "redo")
return false;
redo();
@@ -3027,26 +3297,25 @@ bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
return true;
}
-bool FakeVimHandler::Private::handleExGotoCommand(const QString &line) // :<nr>
+bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd)
{
- int beginLine, endLine;
- QString cmd = extractCommand(line, &beginLine, &endLine);
-
- if (!cmd.isEmpty())
+ // :<nr>
+ if (!cmd.cmd.isEmpty())
return false;
+ const int beginLine = lineForPosition(cmd.range.beginPos);
setPosition(firstPositionInLine(beginLine));
showBlackMessage(QString());
return true;
}
-bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :source
+bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd)
{
- int pos = line.indexOf(' ');
- if (line.leftRef(pos) != "so" && line.leftRef(pos) != "source")
+ // :source
+ if (cmd.cmd != "so" && cmd.cmd != "source")
return false;
- QString fileName = line.mid(pos + 1);
+ QString fileName = cmd.args;
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
showRedMessage(FakeVimHandler::tr("Can't open file %1").arg(fileName));
@@ -3079,119 +3348,137 @@ bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :sou
void FakeVimHandler::Private::handleExCommand(const QString &line0)
{
QString line = line0; // Make sure we have a copy to prevent aliasing.
+ // FIXME: that seems to be different for %w and %s
+ if (line.startsWith(QLatin1Char('%')))
+ line = "1,$" + line.mid(1);
+
+ int beginLine = readLineCode(line);
+ int endLine = -1;
+ if (line.startsWith(',')) {
+ line = line.mid(1);
+ endLine = readLineCode(line);
+ }
+ if (beginLine != -1 && endLine == -1)
+ endLine = beginLine;
+ const int beginPos = firstPositionInLine(beginLine);
+ const int endPos = lastPositionInLine(endLine);
+ ExCommand cmd;
+ const QString arg0 = line.section(' ', 0, 0);
+ cmd.cmd = arg0;
+ cmd.args = line.mid(arg0.size() + 1).trimmed();
+ cmd.range = Range(beginPos, endPos, RangeLineMode);
+ cmd.hasBang = arg0.endsWith('!');
+ if (cmd.hasBang)
+ cmd.cmd.chop(1);
+ //qDebug() << "CMD: " << cmd;
+
enterCommandMode();
showBlackMessage(QString());
- if (handleExCommandHelper(line))
- return;
- int beginLine, endLine;
- passUnknownExCommand(extractCommand(line, &beginLine, &endLine));
+ if (!handleExCommandHelper(cmd))
+ showRedMessage(tr("Not an editor command: %1").arg(cmd.cmd));
}
-bool FakeVimHandler::Private::handleExCommandHelper(const QString &line)
+bool FakeVimHandler::Private::handleExCommandHelper(const ExCommand &cmd)
{
- return handleExGotoCommand(line)
- || handleExBangCommand(line)
- || handleExHistoryCommand(line)
- || handleExMapCommand(line)
- || handleExNormalCommand(line)
- || handleExReadCommand(line)
- || handleExRedoCommand(line)
- || handleExSetCommand(line)
- || handleExShiftRightCommand(line)
- || handleExSourceCommand(line)
- || handleExSubstituteCommand(line)
- || handleExWriteCommand(line);
+ return handleExPluginCommand(cmd)
+ || handleExGotoCommand(cmd)
+ || handleExBangCommand(cmd)
+ || handleExHistoryCommand(cmd)
+ || handleExRegisterCommand(cmd)
+ || handleExDeleteCommand(cmd)
+ || handleExMapCommand(cmd)
+ || handleExNormalCommand(cmd)
+ || handleExReadCommand(cmd)
+ || handleExRedoCommand(cmd)
+ || handleExSetCommand(cmd)
+ || handleExShiftCommand(cmd)
+ || handleExSourceCommand(cmd)
+ || handleExSubstituteCommand(cmd)
+ || handleExWriteCommand(cmd);
}
-void FakeVimHandler::Private::passUnknownExCommand(const QString &cmd)
+bool FakeVimHandler::Private::handleExPluginCommand(const ExCommand &cmd)
{
EDITOR(setTextCursor(m_tc));
- emit q->handleExCommandRequested(cmd);
+ bool handled = false;
+ emit q->handleExCommandRequested(&handled, cmd);
if (m_plaintextedit || m_textedit)
m_tc = EDITOR(textCursor());
-}
-
-void FakeVimHandler::Private::passUnknownSetCommand(const QString &arg)
-{
- bool handled = false;
- emit q->handleSetCommandRequested(&handled, arg);
- if (!handled) {
- showRedMessage(FakeVimHandler::tr("E512: Unknown option: ") + arg);
- }
+ //qDebug() << "HANDLER REQUEST: " << cmd.cmd << handled;
+ return handled;
}
static void vimPatternToQtPattern(QString *needle, QTextDocument::FindFlags *flags)
{
// FIXME: Rough mapping of a common case
- if (needle->startsWith(QLatin1String("\\<")) && needle->endsWith(QLatin1String("\\>")))
+ if (needle->startsWith(_("\\<")) && needle->endsWith(_("\\>")))
(*flags) |= QTextDocument::FindWholeWords;
- needle->remove(QLatin1String("\\<")); // start of word
- needle->remove(QLatin1String("\\>")); // end of word
+ needle->remove(_("\\<")); // start of word
+ needle->remove(_("\\>")); // end of word
//qDebug() << "NEEDLE " << needle0 << needle;
}
-void FakeVimHandler::Private::search(const QString &needle0, bool forward,
- bool incSearch)
+void FakeVimHandler::Private::search(const SearchData &sd)
{
- showBlackMessage((forward ? '/' : '?') + needle0);
- CursorPosition origPosition = cursorPosition();
+ if (sd.needle.isEmpty())
+ return;
+
+ const bool incSearch = hasConfig(ConfigIncSearch);
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
- if (!forward)
+ if (!sd.forward)
flags |= QTextDocument::FindBackward;
- QString needle = needle0;
+ QString needle = sd.needle;
vimPatternToQtPattern(&needle, &flags);
- if (forward)
- m_tc.movePosition(Right, MoveAnchor, 1);
+ const int oldLine = cursorLineInDocument() - cursorLineOnScreen();
- int oldLine = cursorLineInDocument() - cursorLineOnScreen();
+ int startPos = position();
+ if (sd.mustMove)
+ sd.forward ? ++startPos : --startPos;
- EDITOR(setTextCursor(m_tc));
- if (EDITOR(find(needle, flags))) {
- m_tc = EDITOR(textCursor());
- m_tc.setPosition(m_tc.anchor());
- // making this unconditional feels better, but is not "vim like"
- if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
- scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
- if (!incSearch)
- highlightMatches(needle);
- } else {
- m_tc.setPosition(forward ? 0 : lastPositionInDocument());
- EDITOR(setTextCursor(m_tc));
- if (EDITOR(find(needle, flags))) {
- m_tc = EDITOR(textCursor());
- m_tc.setPosition(m_tc.anchor());
- if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
- scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
+ m_searchCursor = QTextCursor();
+ QTextCursor tc = m_tc.document()->find(needle, startPos, flags);
+ if (tc.isNull()) {
+ int startPos = sd.forward ? 0 : lastPositionInDocument();
+ tc = m_tc.document()->find(needle, startPos, flags);
+ if (tc.isNull()) {
if (!incSearch) {
- if (forward)
- showRedMessage(FakeVimHandler::tr("search hit BOTTOM, continuing at TOP"));
- else
- showRedMessage(FakeVimHandler::tr("search hit TOP, continuing at BOTTOM"));
- highlightMatches(needle);
- }
- } else {
- if (!incSearch)
highlightMatches(QString());
- setCursorPosition(origPosition);
- if (!incSearch)
showRedMessage(FakeVimHandler::tr("Pattern not found: ") + needle);
+ }
+ updateSelection();
+ return;
+ }
+ if (!incSearch) {
+ QString msg = sd.forward
+ ? FakeVimHandler::tr("search hit BOTTOM, continuing at TOP")
+ : FakeVimHandler::tr("search hit TOP, continuing at BOTTOM");
+ showRedMessage(msg);
}
}
- if (incSearch) {
- QTextEdit::ExtraSelection sel;
- sel.cursor = m_tc;
- sel.format = m_tc.blockCharFormat();
- sel.format.setForeground(Qt::white);
- sel.format.setBackground(Qt::black);
- sel.cursor.setPosition(m_tc.position(), MoveAnchor);
- sel.cursor.setPosition(m_tc.position() + needle.size(), KeepAnchor);
- QList<QTextEdit::ExtraSelection> selections = m_searchSelections;
- selections.append(sel);
- emit q->selectionChanged(selections);
+
+ // Set Cursor.
+ tc.setPosition(qMin(tc.position(), tc.anchor()), MoveAnchor);
+ tc.clearSelection();
+ m_tc = tc;
+ EDITOR(setTextCursor(m_tc));
+
+ // Making this unconditional feels better, but is not "vim like".
+ if (oldLine != cursorLineInDocument() - cursorLineOnScreen())
+ scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2);
+
+ if (incSearch && sd.highlightCursor) {
+ m_searchCursor = m_tc;
+ m_searchCursor.setPosition(m_tc.position(), MoveAnchor);
+ m_searchCursor.setPosition(m_tc.position() + needle.size(), KeepAnchor);
}
setTargetColumn();
+
+ if (sd.highlightMatches)
+ highlightMatches(needle);
+ updateSelection();
+ recordJump();
}
void FakeVimHandler::Private::highlightMatches(const QString &needle0)
@@ -3202,7 +3489,6 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
return;
m_oldNeedle = needle0;
m_searchSelections.clear();
-
if (!needle0.isEmpty()) {
QTextCursor tc = m_tc;
tc.movePosition(StartOfDocument, MoveAnchor);
@@ -3210,18 +3496,16 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
QString needle = needle0;
vimPatternToQtPattern(&needle, &flags);
-
-
- EDITOR(setTextCursor(tc));
- while (EDITOR(find(needle, flags))) {
- tc = EDITOR(textCursor());
+ while (1) {
+ tc = tc.document()->find(needle, tc.position(), flags);
+ if (tc.isNull())
+ break;
QTextEdit::ExtraSelection sel;
sel.cursor = tc;
sel.format = tc.blockCharFormat();
sel.format.setBackground(QColor(177, 177, 0));
m_searchSelections.append(sel);
tc.movePosition(Right, MoveAnchor);
- EDITOR(setTextCursor(tc));
}
}
updateSelection();
@@ -3247,8 +3531,7 @@ void FakeVimHandler::Private::indentSelectedText(QChar typedChar)
int beginLine = qMin(lineForPosition(position()), lineForPosition(anchor()));
int endLine = qMax(lineForPosition(position()), lineForPosition(anchor()));
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
+ Range range(anchor(), position(), m_rangemode);
indentText(range, typedChar);
setPosition(firstPositionInLine(beginLine));
@@ -3266,8 +3549,10 @@ int FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
int amount = 0;
// lineForPosition has returned 1-based line numbers
- emit q->indentRegion(&amount, beginLine-1, endLine-1, typedChar);
-
+ emit q->indentRegion(&amount, beginLine - 1, endLine - 1, typedChar);
+ fixMarks(firstPositionInLine(beginLine), amount);
+ if (beginLine != endLine)
+ showBlackMessage("MARKS ARE OFF NOW");
return amount;
}
@@ -3313,7 +3598,7 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat)
int targetPos = anchor();
if (beginLine > endLine) {
qSwap(beginLine, endLine);
- targetPos = position();
+ targetPos = position();
}
const int shift = config(ConfigShiftWidth).toInt() * repeat;
const int tab = config(ConfigTabStop).toInt();
@@ -3635,12 +3920,7 @@ int FakeVimHandler::Private::lastPositionInDocument() const
return block.position() + block.length() - 1;
}
-QString FakeVimHandler::Private::lastSearchString() const
-{
- return m_searchHistory.empty() ? QString() : m_searchHistory.back();
-}
-
-QString FakeVimHandler::Private::text(const Range &range) const
+QString FakeVimHandler::Private::selectText(const Range &range) const
{
if (range.rangemode == RangeCharMode) {
QTextCursor tc = m_tc;
@@ -3688,34 +3968,35 @@ QString FakeVimHandler::Private::text(const Range &range) const
return contents;
}
-void FakeVimHandler::Private::yankSelectedText()
-{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
- yankText(range, m_register);
-}
-
void FakeVimHandler::Private::yankText(const Range &range, int toregister)
{
- Register &reg = m_registers[toregister];
- reg.contents = text(range);
+ Register &reg = g.registers[toregister];
+ reg.contents = selectText(range);
reg.rangemode = range.rangemode;
//qDebug() << "YANKED: " << reg.contents;
}
void FakeVimHandler::Private::transformText(const Range &range,
- Transformation transformFunc)
+ Transformation transformFunc, const QVariant &extra)
{
QTextCursor tc = m_tc;
switch (range.rangemode) {
case RangeCharMode: {
+ // This can span multiple lines.
+ beginEditBlock();
tc.setPosition(range.beginPos, MoveAnchor);
tc.setPosition(range.endPos, KeepAnchor);
- (this->*transformFunc)(range.beginPos, &tc);
+ TransformationData td(tc.selectedText(), extra);
+ (this->*transformFunc)(&td);
+ tc.removeSelectedText();
+ fixMarks(range.beginPos, td.to.size() - td.from.size());
+ tc.insertText(td.to);
+ endEditBlock();
return;
}
case RangeLineMode:
case RangeLineModeExclusive: {
+ beginEditBlock(range.beginPos);
tc.setPosition(range.beginPos, MoveAnchor);
tc.movePosition(StartOfLine, MoveAnchor);
tc.setPosition(range.endPos, KeepAnchor);
@@ -3737,7 +4018,12 @@ void FakeVimHandler::Private::transformText(const Range &range,
tc.movePosition(Right, KeepAnchor, 1);
}
}
- (this->*transformFunc)(range.beginPos, &tc);
+ TransformationData td(tc.selectedText(), extra);
+ (this->*transformFunc)(&td);
+ tc.removeSelectedText();
+ fixMarks(range.beginPos, td.to.size() - td.from.size());
+ tc.insertText(td.to);
+ endEditBlock();
return;
}
case RangeBlockAndTailMode:
@@ -3757,7 +4043,11 @@ void FakeVimHandler::Private::transformText(const Range &range,
int eCol = qMin(endColumn + 1, block.length() - 1);
tc.setPosition(block.position() + bCol, MoveAnchor);
tc.setPosition(block.position() + eCol, KeepAnchor);
- (this->*transformFunc)(block.position() + bCol, &tc);
+ TransformationData td(tc.selectedText(), extra);
+ (this->*transformFunc)(&td);
+ tc.removeSelectedText();
+ fixMarks(block.position() + bCol, td.to.size() - td.from.size());
+ tc.insertText(td.to);
block = block.previous();
}
endEditBlock();
@@ -3765,11 +4055,12 @@ void FakeVimHandler::Private::transformText(const Range &range,
}
}
-void FakeVimHandler::Private::removeSelectedText()
+void FakeVimHandler::Private::insertText(const Register &reg)
{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
- removeText(range);
+ QTC_ASSERT(reg.rangemode == RangeCharMode,
+ qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
+ fixMarks(position(), reg.contents.length());
+ m_tc.insertText(reg.contents);
}
void FakeVimHandler::Private::removeText(const Range &range)
@@ -3777,100 +4068,69 @@ void FakeVimHandler::Private::removeText(const Range &range)
transformText(range, &FakeVimHandler::Private::removeTransform);
}
-void FakeVimHandler::Private::removeTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::removeTransform(TransformationData *td)
{
- fixMarks(updateMarksAfter, tc->selectionStart() - tc->selectionEnd());
- tc->removeSelectedText();
+ Q_UNUSED(td);
}
-void FakeVimHandler::Private::downCaseSelectedText()
+void FakeVimHandler::Private::downCase(const Range &range)
{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
transformText(range, &FakeVimHandler::Private::downCaseTransform);
}
-void FakeVimHandler::Private::downCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::downCaseTransform(TransformationData *td)
{
- Q_UNUSED(updateMarksAfter);
- QString str = tc->selectedText();
- tc->removeSelectedText();
- for (int i = str.size(); --i >= 0; ) {
- QChar c = str.at(i);
- str[i] = c.toLower();
- }
- tc->insertText(str);
+ td->to = td->from.toLower();
}
-void FakeVimHandler::Private::upCaseSelectedText()
+void FakeVimHandler::Private::upCase(const Range &range)
{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
transformText(range, &FakeVimHandler::Private::upCaseTransform);
}
-void FakeVimHandler::Private::upCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::upCaseTransform(TransformationData *td)
{
- Q_UNUSED(updateMarksAfter);
- QString str = tc->selectedText();
- tc->removeSelectedText();
- for (int i = str.size(); --i >= 0; ) {
- QChar c = str.at(i);
- str[i] = c.toUpper();
- }
- tc->insertText(str);
+ td->to = td->from.toUpper();
}
-void FakeVimHandler::Private::invertCaseSelectedText()
+void FakeVimHandler::Private::invertCase(const Range &range)
{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
transformText(range, &FakeVimHandler::Private::invertCaseTransform);
}
-void FakeVimHandler::Private::invertCaseTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::invertCaseTransform(TransformationData *td)
{
- Q_UNUSED(updateMarksAfter);
- QString str = tc->selectedText();
- tc->removeSelectedText();
- for (int i = str.size(); --i >= 0; ) {
- QChar c = str.at(i);
- str[i] = c.isUpper() ? c.toLower() : c.toUpper();
- }
- tc->insertText(str);
+ foreach (QChar c, td->from)
+ td->to += c.isUpper() ? c.toLower() : c.toUpper();
}
-void FakeVimHandler::Private::replaceSelectedText()
+void FakeVimHandler::Private::replaceText(const Range &range, const QString &str)
{
- Range range(anchor(), position());
- range.rangemode = m_rangemode;
- transformText(range, &FakeVimHandler::Private::replaceTransform);
+ Transformation tr = &FakeVimHandler::Private::replaceByStringTransform;
+ transformText(range, tr, str);
}
-void FakeVimHandler::Private::replaceTransform(int updateMarksAfter, QTextCursor *tc)
+void FakeVimHandler::Private::replaceByStringTransform(TransformationData *td)
{
- Q_UNUSED(updateMarksAfter);
- QString str = tc->selectedText();
- tc->removeSelectedText();
- for (int i = str.size(); --i >= 0; ) {
- QChar c = str.at(i);
- str[i] = (c.toAscii() == '\n' || c.toAscii() == '\0') ? QChar('\n') : m_replacingCharacter;
- }
- tc->insertText(str);
+ td->to = td->extraData.toString();
+}
+
+void FakeVimHandler::Private::replaceByCharTransform(TransformationData *td)
+{
+ td->to = QString(td->from.size(), td->extraData.toChar());
}
void FakeVimHandler::Private::pasteText(bool afterCursor)
{
- const QString text = m_registers[m_register].contents;
+ const QString text = g.registers[m_register].contents;
const QStringList lines = text.split(QChar('\n'));
- switch (m_registers[m_register].rangemode) {
+ switch (g.registers[m_register].rangemode) {
case RangeCharMode: {
m_targetColumn = 0;
for (int i = count(); --i >= 0; ) {
if (afterCursor && rightDist() > 0)
moveRight();
- fixMarks(position(), text.length());
- m_tc.insertText(text);
+ insertText(text);
if (!afterCursor && atEndOfLine())
moveLeft();
moveLeft();
@@ -3884,8 +4144,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
for (int i = count(); --i >= 0; ) {
if (afterCursor)
moveDown();
- fixMarks(position(), text.length());
- m_tc.insertText(text);
+ insertText(text);
moveUp(lines.size() - 1);
}
moveToFirstNonBlankOnLine();
@@ -3910,8 +4169,8 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
} else {
tc.movePosition(Right, MoveAnchor, col - 1 + afterCursor);
}
- qDebug() << "INSERT " << line << " AT " << tc.position()
- << "COL: " << col;
+ //qDebug() << "INSERT " << line << " AT " << tc.position()
+ // << "COL: " << col;
fixMarks(position(), line.length());
tc.insertText(line);
tc.movePosition(StartOfLine, MoveAnchor);
@@ -3931,16 +4190,38 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
}
//FIXME: This needs to called after undo/insert
-void FakeVimHandler::Private::fixMarks(int positionAction, int positionChange)
-{
- QHashIterator<int, int> i(m_marks);
- while (i.hasNext()) {
- i.next();
- if (i.value() >= positionAction) {
- if (i.value() + positionChange > 0)
- m_marks[i.key()] = i.value() + positionChange;
- else
- m_marks.remove(i.key());
+// The position 'from' is the cursor position after the change. If 'delta'
+// is positive there was a string of size 'delta' inserted after 'from'
+// and consequently all marks beyond 'from + delta' need to be incremented
+// by 'delta'. If text was removed, 'delta' is negative. All marks between
+// 'from' and 'from - delta' need to be removed, everything behing
+// 'from - delta' adjusted by 'delta'.
+void FakeVimHandler::Private::fixMarks(int from, int delta)
+{
+ //qDebug() << "ADJUSTING MARKS FROM " << from << " BY " << delta;
+ if (delta == 0)
+ return;
+ QHashIterator<int, int> it(m_marks);
+ while (it.hasNext()) {
+ it.next();
+ int pos = it.value();
+ if (delta > 0) {
+ // Inserted text.
+ if (pos >= from) {
+ //qDebug() << "MODIFIED: " << it.key() << pos;
+ setMark(it.key(), pos + delta);
+ }
+ } else {
+ // Removed text.
+ if (pos < from) {
+ // Nothing to do.
+ } else if (pos < from - delta) {
+ //qDebug() << "GONE: " << it.key();
+ m_marks.remove(it.key());
+ } else {
+ //qDebug() << "MODIFIED: " << it.key() << pos;
+ setMark(it.key(), pos + delta);
+ }
}
}
}
@@ -3950,13 +4231,14 @@ QString FakeVimHandler::Private::lineContents(int line) const
return m_tc.document()->findBlockByNumber(line - 1).text();
}
-void FakeVimHandler::Private::setLineContents(int line, const QString &contents) const
+void FakeVimHandler::Private::setLineContents(int line, const QString &contents)
{
QTextBlock block = m_tc.document()->findBlockByNumber(line - 1);
QTextCursor tc = m_tc;
tc.setPosition(block.position());
tc.setPosition(block.position() + block.length() - 1, KeepAnchor);
tc.removeSelectedText();
+ fixMarks(block.position(), block.length() - contents.size());
tc.insertText(contents);
}
@@ -3983,8 +4265,8 @@ void FakeVimHandler::Private::enterVisualMode(VisualMode visualMode)
setAnchor();
m_positionPastEnd = m_anchorPastEnd = false;
m_visualMode = visualMode;
- m_marks['<'] = m_tc.position();
- m_marks['>'] = m_tc.position();
+ setMark('<', m_tc.position());
+ setMark('>', m_tc.position());
updateMiniBuffer();
updateSelection();
}
@@ -4011,11 +4293,16 @@ QWidget *FakeVimHandler::Private::editor() const
void FakeVimHandler::Private::undo()
{
//qDebug() << " CURSOR POS: " << m_undoCursorPosition;
- int current = m_tc.document()->availableUndoSteps();
- //endEditBlock();
+ QTextDocument *doc = m_tc.document();
+ // FIXME: That's only an approximaxtion. The real solution might
+ // be to store marks and old userData with QTextBlock setUserData
+ // and retrieve them afterward.
+ const int current = doc->availableUndoSteps();
+ const int oldCount = doc->characterCount();
EDITOR(undo());
- //beginEditBlock();
- int rev = m_tc.document()->availableUndoSteps();
+ const int delta = doc->characterCount() - oldCount;
+ fixMarks(position(), delta);
+ const int rev = doc->availableUndoSteps();
if (current == rev)
showBlackMessage(FakeVimHandler::tr("Already at oldest change"));
else
@@ -4023,17 +4310,20 @@ void FakeVimHandler::Private::undo()
if (m_undoCursorPosition.contains(rev))
m_tc.setPosition(m_undoCursorPosition[rev]);
+ setTargetColumn();
if (atEndOfLine())
moveLeft();
}
void FakeVimHandler::Private::redo()
{
- int current = m_tc.document()->availableUndoSteps();
- //endEditBlock();
+ QTextDocument *doc = m_tc.document();
+ const int current = m_tc.document()->availableUndoSteps();
+ const int oldCount = doc->characterCount();
EDITOR(redo());
- //beginEditBlock();
- int rev = m_tc.document()->availableUndoSteps();
+ const int delta = doc->characterCount() - oldCount;
+ fixMarks(position(), delta);
+ const int rev = doc->availableUndoSteps();
if (rev == current)
showBlackMessage(FakeVimHandler::tr("Already at newest change"));
else
@@ -4041,32 +4331,63 @@ void FakeVimHandler::Private::redo()
if (m_undoCursorPosition.contains(rev))
m_tc.setPosition(m_undoCursorPosition[rev]);
+ setTargetColumn();
+}
+
+void FakeVimHandler::Private::updateCursor()
+{
+ if (m_mode == ExMode || m_subsubmode == SearchSubSubMode) {
+ EDITOR(setCursorWidth(0));
+ EDITOR(setOverwriteMode(false));
+ } else if (m_mode == InsertMode) {
+ EDITOR(setCursorWidth(m_cursorWidth));
+ EDITOR(setOverwriteMode(false));
+ } else {
+ EDITOR(setCursorWidth(m_cursorWidth));
+ EDITOR(setOverwriteMode(true));
+ }
+}
+
+void FakeVimHandler::Private::enterReplaceMode()
+{
+ m_mode = ReplaceMode;
+ m_submode = NoSubMode;
+ m_subsubmode = NoSubSubMode;
+ m_commandPrefix.clear();
+ m_lastInsertion.clear();
+ m_lastDeletion.clear();
+ updateCursor();
}
void FakeVimHandler::Private::enterInsertMode()
{
- EDITOR(setCursorWidth(m_cursorWidth));
- EDITOR(setOverwriteMode(false));
- //leaveVisualMode();
m_mode = InsertMode;
+ m_submode = NoSubMode;
+ m_subsubmode = NoSubSubMode;
+ m_commandPrefix.clear();
m_lastInsertion.clear();
- m_beginEditBlock = true;
+ m_lastDeletion.clear();
+ updateCursor();
}
void FakeVimHandler::Private::enterCommandMode()
{
- EDITOR(setCursorWidth(m_cursorWidth));
- EDITOR(setOverwriteMode(true));
if (atEndOfLine())
moveLeft();
m_mode = CommandMode;
+ m_submode = NoSubMode;
+ m_subsubmode = NoSubSubMode;
+ m_commandPrefix.clear();
+ updateCursor();
}
void FakeVimHandler::Private::enterExMode()
{
- EDITOR(setCursorWidth(0));
- EDITOR(setOverwriteMode(false));
m_mode = ExMode;
+ m_submode = NoSubMode;
+ m_subsubmode = NoSubSubMode;
+ m_commandPrefix = ":";
+ updateCursor();
}
void FakeVimHandler::Private::recordJump()
@@ -4076,13 +4397,6 @@ void FakeVimHandler::Private::recordJump()
UNDO_DEBUG("jumps: " << m_jumpListUndo);
}
-void FakeVimHandler::Private::recordNewUndo()
-{
- //endEditBlock();
- UNDO_DEBUG("---- BREAK ----");
- //beginEditBlock();
-}
-
Column FakeVimHandler::Private::indentation(const QString &line) const
{
int ts = config(ConfigTabStop).toInt();
@@ -4128,7 +4442,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
++pos;
text.truncate(pos);
// FIXME: handle 'smartindent' and 'cindent'
- m_tc.insertText(text);
+ insertText(text);
m_justAutoIndented = text.size();
}
}
@@ -4139,6 +4453,7 @@ bool FakeVimHandler::Private::removeAutomaticIndentation()
return false;
m_tc.movePosition(StartOfLine, KeepAnchor);
m_tc.removeSelectedText();
+ fixMarks(m_tc.position(), -m_justAutoIndented);
m_lastInsertion.chop(m_justAutoIndented);
m_justAutoIndented = 0;
return true;
@@ -4152,18 +4467,17 @@ void FakeVimHandler::Private::handleStartOfLine()
void FakeVimHandler::Private::replay(const QString &command, int n)
{
- //qDebug() << "REPLAY: " << command;
- m_inReplay = true;
+ //qDebug() << "REPLAY: " << quoteUnprintable(command);
+ g.inReplay = true;
for (int i = n; --i >= 0; ) {
foreach (QChar c, command) {
//qDebug() << " REPLAY: " << QString(c);
handleKey(Input(c));
}
}
- m_inReplay = false;
+ g.inReplay = false;
}
-
void FakeVimHandler::Private::selectWordTextObject(bool inner)
{
Q_UNUSED(inner); // FIXME
@@ -4172,7 +4486,7 @@ void FakeVimHandler::Private::selectWordTextObject(bool inner)
setAnchor();
// FIXME: Rework the 'anchor' concept.
if (isVisualMode())
- m_marks['<'] = m_tc.position();
+ setMark('<', m_tc.position());
moveToWordBoundary(false, true, true);
m_movetype = MoveInclusive;
}
@@ -4185,7 +4499,7 @@ void FakeVimHandler::Private::selectWORDTextObject(bool inner)
setAnchor();
// FIXME: Rework the 'anchor' concept.
if (isVisualMode())
- m_marks['<'] = m_tc.position();
+ setMark('<', m_tc.position());
moveToWordBoundary(true, true, true);
m_movetype = MoveInclusive;
}
@@ -4213,6 +4527,18 @@ void FakeVimHandler::Private::selectQuotedStringTextObject(bool inner, int type)
Q_UNUSED(type);
}
+int FakeVimHandler::Private::mark(int code) const
+{
+ // FIXME: distinguish local and global marks.
+ //qDebug() << "MARK: " << code << m_marks.value(code, -1) << m_marks;
+ return m_marks.value(code, -1);
+}
+
+void FakeVimHandler::Private::setMark(int code, int position)
+{
+ // FIXME: distinguish local and global marks.
+ m_marks[code] = position;
+}
///////////////////////////////////////////////////////////////////////
//
@@ -4240,6 +4566,30 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev)
{
bool active = theFakeVimSetting(ConfigUseFakeVim)->value().toBool();
+ // Catch mouse events on the viewport.
+ QWidget *viewport = 0;
+ if (d->m_plaintextedit)
+ viewport = d->m_plaintextedit->viewport();
+ else if (d->m_textedit)
+ viewport = d->m_textedit->viewport();
+ if (ob == viewport) {
+ if (active && ev->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
+ if (mev->button() == Qt::LeftButton) {
+ d->importSelection();
+ //return true;
+ }
+ }
+ if (active && ev->type() == QEvent::MouseButtonPress) {
+ QMouseEvent *mev = static_cast<QMouseEvent *>(ev);
+ if (mev->button() == Qt::LeftButton) {
+ d->m_visualMode = NoVisualMode;
+ d->updateSelection();
+ }
+ }
+ return QObject::eventFilter(ob, ev);
+ }
+
if (active && ev->type() == QEvent::Shortcut) {
d->passShortcuts(false);
return false;
@@ -4314,6 +4664,11 @@ void FakeVimHandler::setCurrentFileName(const QString &fileName)
d->m_currentFileName = fileName;
}
+QString FakeVimHandler::currentFileName() const
+{
+ return d->m_currentFileName;
+}
+
void FakeVimHandler::showBlackMessage(const QString &msg)
{
d->showBlackMessage(msg);
diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h
index 7543d8cf86..4e877d31c8 100644
--- a/src/plugins/fakevim/fakevimhandler.h
+++ b/src/plugins/fakevim/fakevimhandler.h
@@ -38,6 +38,38 @@
namespace FakeVim {
namespace Internal {
+enum RangeMode
+{
+ RangeCharMode, // v
+ RangeLineMode, // V
+ RangeLineModeExclusive,
+ RangeBlockMode, // Ctrl-v
+ RangeBlockAndTailMode, // Ctrl-v for D and X
+};
+
+struct Range
+{
+ Range();
+ Range(int b, int e, RangeMode m = RangeCharMode);
+ QString toString() const;
+
+ int beginPos;
+ int endPos;
+ RangeMode rangemode;
+};
+
+struct ExCommand
+{
+ ExCommand() : hasBang(false) {}
+ ExCommand(const QString &cmd, const QString &args = QString(),
+ const Range &range = Range());
+
+ QString cmd;
+ bool hasBang;
+ QString args;
+ Range range;
+};
+
class FakeVimHandler : public QObject
{
Q_OBJECT
@@ -53,6 +85,8 @@ public:
public slots:
void setCurrentFileName(const QString &fileName);
+ QString currentFileName() const;
+
void showBlackMessage(const QString &msg);
void showRedMessage(const QString &msg);
@@ -76,8 +110,6 @@ signals:
void statusDataChanged(const QString &msg);
void extraInformationChanged(const QString &msg);
void selectionChanged(const QList<QTextEdit::ExtraSelection> &selection);
- void writeFileRequested(bool *handled,
- const QString &fileName, const QString &contents);
void writeAllRequested(QString *error);
void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
void checkForElectricCharacter(bool *result, QChar c);
@@ -86,8 +118,7 @@ signals:
void windowCommandRequested(int key);
void findRequested(bool reverse);
void findNextRequested(bool reverse);
- void handleExCommandRequested(const QString &cmd);
- void handleSetCommandRequested(bool *handled, const QString &cmd);
+ void handleExCommandRequested(bool *handled, const ExCommand &cmd);
public:
class Private;
@@ -101,4 +132,7 @@ private:
} // namespace Internal
} // namespace FakeVim
+Q_DECLARE_METATYPE(FakeVim::Internal::ExCommand);
+
+
#endif // FAKEVIM_HANDLER_H
diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui
index 6a9f52b5ab..450a862906 100644
--- a/src/plugins/fakevim/fakevimoptions.ui
+++ b/src/plugins/fakevim/fakevimoptions.ui
@@ -66,6 +66,13 @@
</property>
</widget>
</item>
+ <item row="2" column="2">
+ <widget class="QCheckBox" name="checkBoxShowMarks">
+ <property name="text">
+ <string>Show position of text marks</string>
+ </property>
+ </widget>
+ </item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxSmartTab">
<property name="text">
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index a698cb01aa..5c66cec078 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -73,9 +73,9 @@
#include <indenter.h>
#include <QtCore/QDebug>
+#include <QtCore/QFile>
#include <QtCore/QtPlugin>
#include <QtCore/QObject>
-#include <QtCore/QPoint>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>
@@ -120,6 +120,8 @@ const char * const CMD_FILE_PREV = "FakeVim.SwitchFilePrev";
namespace FakeVim {
namespace Internal {
+typedef QMap<QString, QRegExp> CommandMap;
+
class FakeVimOptionPage : public Core::IOptionsPage
{
Q_OBJECT
@@ -168,6 +170,8 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent)
m_ui.checkBoxHlSearch);
m_group.insert(theFakeVimSetting(ConfigShiftWidth),
m_ui.spinBoxShiftWidth);
+ m_group.insert(theFakeVimSetting(ConfigShowMarks),
+ m_ui.checkBoxShowMarks);
m_group.insert(theFakeVimSetting(ConfigSmartTab),
m_ui.checkBoxSmartTab);
@@ -199,8 +203,8 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent)
QTextStream(&m_searchKeywords)
<< ' ' << m_ui.checkBoxAutoIndent->text()
<< ' ' << m_ui.checkBoxExpandTab->text()
+ << ' ' << m_ui.checkBoxShowMarks->text()
<< ' ' << m_ui.checkBoxSmartIndent->text()
- << ' ' << m_ui.checkBoxExpandTab->text()
<< ' ' << m_ui.checkBoxHlSearch->text()
<< ' ' << m_ui.checkBoxIncSearch->text()
<< ' ' << m_ui.checkBoxSmartTab->text()
@@ -278,16 +282,12 @@ Q_DECLARE_METATYPE(CommandItem*);
namespace FakeVim {
namespace Internal {
-static QMap<QString, QRegExp> s_exCommandMap;
-static QMap<QString, QRegExp> s_defaultExCommandMap;
-
-
class FakeVimExCommandsPage : public Core::CommandMappings
{
Q_OBJECT
public:
- FakeVimExCommandsPage() {}
+ FakeVimExCommandsPage(FakeVimPluginPrivate *q) : m_q(q) {}
// IOptionsPage
QString id() const { return QLatin1String(Constants::SETTINGS_EX_CMDS_ID); }
@@ -298,6 +298,8 @@ public:
QWidget *createPage(QWidget *parent);
void initialize();
+ CommandMap &exCommandMap();
+ CommandMap &defaultExCommandMap();
public slots:
void commandChanged(QTreeWidgetItem *current);
@@ -309,6 +311,7 @@ public slots:
private:
void setRegex(const QString &regex);
QList<CommandItem *> m_citems;
+ FakeVimPluginPrivate *m_q;
};
QWidget *FakeVimExCommandsPage::createPage(QWidget *parent)
@@ -341,15 +344,16 @@ void FakeVimExCommandsPage::initialize()
QTreeWidgetItem *item = new QTreeWidgetItem;
ci->m_cmd = c;
ci->m_item = item;
- m_citems << ci;
+ m_citems.append(ci);
const QString name = uidm->stringForUniqueIdentifier(c->id());
const int pos = name.indexOf(QLatin1Char('.'));
const QString section = name.left(pos);
- const QString subId = name.mid(pos+1);
+ const QString subId = name.mid(pos + 1);
if (!sections.contains(section)) {
- QTreeWidgetItem *categoryItem = new QTreeWidgetItem(commandList(), QStringList() << section);
+ QTreeWidgetItem *categoryItem =
+ new QTreeWidgetItem(commandList(), QStringList() << section);
QFont f = categoryItem->font(0);
f.setBold(true);
categoryItem->setFont(0, f);
@@ -361,14 +365,16 @@ void FakeVimExCommandsPage::initialize()
item->setText(0, subId);
if (c->action()) {
- QString text = c->hasAttribute(Command::CA_UpdateText) && !c->defaultText().isNull() ? c->defaultText() : c->action()->text();
+ QString text = c->hasAttribute(Command::CA_UpdateText)
+ && !c->defaultText().isNull()
+ ? c->defaultText() : c->action()->text();
text.remove(QRegExp("&(?!&)"));
item->setText(1, text);
} else {
item->setText(1, c->shortcut()->whatsThis());
}
- if (s_exCommandMap.contains(name)) {
- ci->m_regex = s_exCommandMap[name].pattern();
+ if (exCommandMap().contains(name)) {
+ ci->m_regex = exCommandMap()[name].pattern();
} else {
ci->m_regex.clear();
}
@@ -376,7 +382,7 @@ void FakeVimExCommandsPage::initialize()
item->setText(2, ci->m_regex);
item->setData(0, Qt::UserRole, qVariantFromValue(ci));
- if (ci->m_regex != s_defaultExCommandMap[name].pattern())
+ if (ci->m_regex != defaultExCommandMap()[name].pattern())
setModified(item, true);
}
@@ -407,10 +413,10 @@ void FakeVimExCommandsPage::targetIdentifierChanged()
if (current->data(0, Qt::UserRole).isValid()) {
citem->m_regex = targetEdit()->text();
current->setText(2, citem->m_regex);
- s_exCommandMap[name] = QRegExp(citem->m_regex);
+ exCommandMap()[name] = QRegExp(citem->m_regex);
}
- if (citem->m_regex != s_defaultExCommandMap[name].pattern())
+ if (citem->m_regex != defaultExCommandMap()[name].pattern())
setModified(current, true);
else
setModified(current, false);
@@ -429,8 +435,8 @@ void FakeVimExCommandsPage::resetTargetIdentifier()
if (current && current->data(0, Qt::UserRole).isValid()) {
CommandItem *citem = qVariantValue<CommandItem *>(current->data(0, Qt::UserRole));
const QString &name = uidm->stringForUniqueIdentifier(citem->m_cmd->id());
- if (s_defaultExCommandMap.contains(name))
- setRegex(s_defaultExCommandMap[name].pattern());
+ if (defaultExCommandMap().contains(name))
+ setRegex(defaultExCommandMap()[name].pattern());
else
setRegex(QString());
}
@@ -446,8 +452,8 @@ void FakeVimExCommandsPage::defaultAction()
UniqueIDManager *uidm = UniqueIDManager::instance();
foreach (CommandItem *item, m_citems) {
const QString &name = uidm->stringForUniqueIdentifier(item->m_cmd->id());
- if (s_defaultExCommandMap.contains(name)) {
- item->m_regex = s_defaultExCommandMap[name].pattern();
+ if (defaultExCommandMap().contains(name)) {
+ item->m_regex = defaultExCommandMap()[name].pattern();
} else {
item->m_regex.clear();
}
@@ -479,6 +485,7 @@ public:
FakeVimPluginPrivate(FakeVimPlugin *);
~FakeVimPluginPrivate();
friend class FakeVimPlugin;
+ friend class FakeVimExCommandsPage;
bool initialize();
void aboutToShutdown();
@@ -499,12 +506,10 @@ private slots:
void showCommandBuffer(const QString &contents);
void showExtraInformation(const QString &msg);
void changeSelection(const QList<QTextEdit::ExtraSelection> &selections);
- void writeFile(bool *handled, const QString &fileName, const QString &contents);
void moveToMatchingParenthesis(bool *moved, bool *forward, QTextCursor *cursor);
void checkForElectricCharacter(bool *result, QChar c);
void indentRegion(int *amount, int beginLine, int endLine, QChar typedChar);
- void handleExCommand(const QString &cmd);
- void handleSetCommand(bool *handled, QString cmd);
+ void handleExCommand(bool *handled, const ExCommand &cmd);
void handleDelayedQuitAll(bool forced);
void handleDelayedQuit(bool forced, Core::IEditor *editor);
@@ -523,11 +528,16 @@ private:
FakeVimExCommandsPage *m_fakeVimExCommandsPage;
QHash<Core::IEditor *, FakeVimHandler *> m_editorToHandler;
- void triggerAction(const QString& code);
- void setActionChecked(const QString& code, bool check);
+ void triggerAction(const QString &code);
+ void setActionChecked(const QString &code, bool check);
void readSettings(QSettings *settings);
void writeSettings(QSettings *settings);
+
+ CommandMap &exCommandMap() { return m_exCommandMap; }
+ CommandMap &defaultExCommandMap() { return m_exCommandMap; }
+ CommandMap m_exCommandMap;
+ CommandMap m_defaultExCommandMap;
};
} // namespace Internal
@@ -538,23 +548,22 @@ FakeVimPluginPrivate::FakeVimPluginPrivate(FakeVimPlugin *plugin)
q = plugin;
m_fakeVimOptionsPage = 0;
m_fakeVimExCommandsPage = 0;
-
- s_defaultExCommandMap[Constants::CMD_FILE_NEXT] =
+ defaultExCommandMap()[Constants::CMD_FILE_NEXT] =
QRegExp("^n(ext)?!?( (.*))?$");
- s_defaultExCommandMap[Constants::CMD_FILE_PREV] =
+ defaultExCommandMap()[Constants::CMD_FILE_PREV] =
QRegExp("^(N(ext)?|prev(ious)?)!?( (.*))?$");
- s_defaultExCommandMap[CppTools::Constants::SWITCH_HEADER_SOURCE] =
+ defaultExCommandMap()[CppTools::Constants::SWITCH_HEADER_SOURCE] =
QRegExp("^A$");
- s_defaultExCommandMap[ProjectExplorer::Constants::BUILD] =
- QRegExp("^make$");
- s_defaultExCommandMap["Coreplugin.OutputPane.previtem"] =
+ defaultExCommandMap()["Coreplugin.OutputPane.previtem"] =
QRegExp("^(cN(ext)?|cp(revious)?)!?( (.*))?$");
- s_defaultExCommandMap["Coreplugin.OutputPane.nextitem"] =
+ defaultExCommandMap()["Coreplugin.OutputPane.nextitem"] =
QRegExp("^cn(ext)?!?( (.*))?$");
- s_defaultExCommandMap[CppEditor::Constants::JUMP_TO_DEFINITION] =
+ defaultExCommandMap()[CppEditor::Constants::JUMP_TO_DEFINITION] =
QRegExp("^tag?$");
- s_defaultExCommandMap[Core::Constants::GO_BACK] =
+ defaultExCommandMap()[Core::Constants::GO_BACK] =
QRegExp("^pop?$");
+ defaultExCommandMap()[QLatin1String("QtCreator.Locate")] =
+ QRegExp("^e$");
}
FakeVimPluginPrivate::~FakeVimPluginPrivate()
@@ -587,7 +596,7 @@ bool FakeVimPluginPrivate::initialize()
q->addObject(m_fakeVimOptionsPage);
theFakeVimSettings()->readSettings(Core::ICore::instance()->settings());
- m_fakeVimExCommandsPage = new FakeVimExCommandsPage;
+ m_fakeVimExCommandsPage = new FakeVimExCommandsPage(this);
q->addObject(m_fakeVimExCommandsPage);
readSettings(Core::ICore::instance()->settings());
@@ -607,8 +616,6 @@ bool FakeVimPluginPrivate::initialize()
connect(editorManager, SIGNAL(editorOpened(Core::IEditor*)),
this, SLOT(editorOpened(Core::IEditor*)));
- connect(theFakeVimSetting(SettingsDialog), SIGNAL(triggered()),
- this, SLOT(showSettingsDialog()));
connect(theFakeVimSetting(ConfigUseFakeVim), SIGNAL(valueChanged(QVariant)),
this, SLOT(setUseFakeVim(QVariant)));
connect(theFakeVimSetting(ConfigReadVimRc), SIGNAL(valueChanged(QVariant)),
@@ -624,7 +631,7 @@ bool FakeVimPluginPrivate::initialize()
cmd->setAttribute(Command::CA_Hide);
connect(switchFilePrevAction, SIGNAL(triggered()), this, SLOT(switchFilePrev()));
- // Delayed operatiosn
+ // Delayed operations.
connect(this, SIGNAL(delayedQuitRequested(bool,Core::IEditor*)),
this, SLOT(handleDelayedQuit(bool,Core::IEditor*)), Qt::QueuedConnection);
connect(this, SIGNAL(delayedQuitAllRequested(bool)),
@@ -644,14 +651,14 @@ void FakeVimPluginPrivate::writeSettings(QSettings *settings)
settings->beginWriteArray(QLatin1String(exCommandMapGroup));
int count = 0;
- typedef QMap<QString, QRegExp>::const_iterator Iterator;
- const Iterator end = s_exCommandMap.constEnd();
- for (Iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
+ typedef CommandMap::const_iterator Iterator;
+ const Iterator end = exCommandMap().constEnd();
+ for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
const QString &id = it.key();
const QRegExp &re = it.value();
- if ((s_defaultExCommandMap.contains(id) && s_defaultExCommandMap[id] != re)
- || (!s_defaultExCommandMap.contains(id) && !re.pattern().isEmpty())) {
+ if ((defaultExCommandMap().contains(id) && defaultExCommandMap()[id] != re)
+ || (!defaultExCommandMap().contains(id) && !re.pattern().isEmpty())) {
settings->setArrayIndex(count);
settings->setValue(QLatin1String(idKey), id);
settings->setValue(QLatin1String(reKey), re.pattern());
@@ -664,14 +671,14 @@ void FakeVimPluginPrivate::writeSettings(QSettings *settings)
void FakeVimPluginPrivate::readSettings(QSettings *settings)
{
- s_exCommandMap = s_defaultExCommandMap;
+ exCommandMap() = defaultExCommandMap();
int size = settings->beginReadArray(QLatin1String(exCommandMapGroup));
for (int i = 0; i < size; ++i) {
settings->setArrayIndex(i);
const QString id = settings->value(QLatin1String(idKey)).toString();
const QString re = settings->value(QLatin1String(reKey)).toString();
- s_exCommandMap[id] = QRegExp(re);
+ exCommandMap()[id] = QRegExp(re);
}
settings->endArray();
}
@@ -702,18 +709,18 @@ void FakeVimPluginPrivate::showSettingsDialog()
QLatin1String(Constants::SETTINGS_ID));
}
-void FakeVimPluginPrivate::triggerAction(const QString& code)
+void FakeVimPluginPrivate::triggerAction(const QString &code)
{
Core::ActionManager *am = Core::ICore::instance()->actionManager();
QTC_ASSERT(am, return);
Core::Command *cmd = am->command(code);
- QTC_ASSERT(cmd, return);
+ QTC_ASSERT(cmd, qDebug() << "UNKNOW CODE: " << code; return);
QAction *action = cmd->action();
QTC_ASSERT(action, return);
action->trigger();
}
-void FakeVimPluginPrivate::setActionChecked(const QString& code, bool check)
+void FakeVimPluginPrivate::setActionChecked(const QString &code, bool check)
{
Core::ActionManager *am = Core::ICore::instance()->actionManager();
QTC_ASSERT(am, return);
@@ -826,8 +833,6 @@ void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
this, SLOT(showExtraInformation(QString)));
connect(handler, SIGNAL(commandBufferChanged(QString)),
this, SLOT(showCommandBuffer(QString)));
- connect(handler, SIGNAL(writeFileRequested(bool*,QString,QString)),
- this, SLOT(writeFile(bool*,QString,QString)));
connect(handler, SIGNAL(selectionChanged(QList<QTextEdit::ExtraSelection>)),
this, SLOT(changeSelection(QList<QTextEdit::ExtraSelection>)));
connect(handler, SIGNAL(moveToMatchingParenthesis(bool*,bool*,QTextCursor*)),
@@ -845,10 +850,8 @@ void FakeVimPluginPrivate::editorOpened(Core::IEditor *editor)
connect(handler, SIGNAL(findNextRequested(bool)),
this, SLOT(findNext(bool)));
- connect(handler, SIGNAL(handleExCommandRequested(QString)),
- this, SLOT(handleExCommand(QString)));
- connect(handler, SIGNAL(handleSetCommandRequested(bool *,QString)),
- this, SLOT(handleSetCommand(bool *,QString)));
+ connect(handler, SIGNAL(handleExCommandRequested(bool*,ExCommand)),
+ this, SLOT(handleExCommand(bool*,ExCommand)));
handler->setCurrentFileName(editor->file()->fileName());
handler->installEventFilter();
@@ -909,33 +912,12 @@ void FakeVimPluginPrivate::checkForElectricCharacter(bool *result, QChar c)
*result = bt->isElectricCharacter(c);
}
-void FakeVimPluginPrivate::writeFile(bool *handled,
- const QString &fileName, const QString &contents)
-{
- Q_UNUSED(contents)
-
- FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
- if (!handler)
- return;
-
- Core::IEditor *editor = m_editorToHandler.key(handler);
- if (editor && editor->file()->fileName() == fileName) {
- // Handle that as a special case for nicer interaction with core
- Core::IFile *file = editor->file();
- Core::ICore::instance()->fileManager()->blockFileChange(file);
- file->save(fileName);
- Core::ICore::instance()->fileManager()->unblockFileChange(file);
- *handled = true;
- }
-}
-
-void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
+void FakeVimPluginPrivate::handleExCommand(bool *handled, const ExCommand &cmd)
{
- static QRegExp reWriteAll("^wa(ll)?!?$");
- static QRegExp reQuit("^q!?$");
- static QRegExp reQuitAll("^qa!?$");
-
using namespace Core;
+ //qDebug() << "PLUGIN HANDLE: " << cmd.cmd;
+
+ *handled = false;
FakeVimHandler *handler = qobject_cast<FakeVimHandler *>(sender());
if (!handler)
@@ -944,7 +926,27 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
EditorManager *editorManager = EditorManager::instance();
QTC_ASSERT(editorManager, return);
- if (reWriteAll.indexIn(cmd) != -1) {
+ *handled = true;
+ if (cmd.cmd == "w" || cmd.cmd == "write") {
+ Core::IEditor *editor = m_editorToHandler.key(handler);
+ const QString fileName = handler->currentFileName();
+ if (editor && editor->file()->fileName() == fileName) {
+ // Handle that as a special case for nicer interaction with core
+ Core::IFile *file = editor->file();
+ Core::ICore::instance()->fileManager()->blockFileChange(file);
+ file->save(fileName);
+ Core::ICore::instance()->fileManager()->unblockFileChange(file);
+ // Check result by reading back.
+ QFile file3(fileName);
+ file3.open(QIODevice::ReadOnly);
+ QByteArray ba = file3.readAll();
+ handler->showBlackMessage(FakeVimHandler::tr("\"%1\" %2 %3L, %4C written")
+ .arg(fileName).arg(" ")
+ .arg(ba.count('\n')).arg(ba.size()));
+ } else {
+ handler->showRedMessage(tr("File not saved"));
+ }
+ } else if (cmd.cmd == "wa" || cmd.cmd == "wall") {
// :wa
FileManager *fm = ICore::instance()->fileManager();
QList<IFile *> toSave = fm->modifiedFiles();
@@ -953,43 +955,47 @@ void FakeVimPluginPrivate::handleExCommand(const QString &cmd)
handler->showBlackMessage(tr("Saving succeeded"));
else
handler->showRedMessage(tr("%n files not saved", 0, failed.size()));
- } else if (reQuit.indexIn(cmd) != -1) {
- // :q
- bool forced = cmd.contains(QChar('!'));
- emit delayedQuitRequested(forced, m_editorToHandler.key(handler));
- } else if (reQuitAll.indexIn(cmd) != -1) {
+ } else if (cmd.cmd == "q" || cmd.cmd == "quit") {
+ // :q[uit]
+ emit delayedQuitRequested(cmd.hasBang, m_editorToHandler.key(handler));
+ } else if (cmd.cmd == "qa" || cmd.cmd == "qall") {
// :qa
- bool forced = cmd.contains(QChar('!'));
- emit delayedQuitAllRequested(forced);
+ emit delayedQuitAllRequested(cmd.hasBang);
+ } else if (cmd.cmd == "sp" || cmd.cmd == "split") {
+ // :sp[lit]
+ triggerAction(Core::Constants::SPLIT);
+ } else if (cmd.cmd == "vs" || cmd.cmd == "vsplit") {
+ // :vs[plit]
+ triggerAction(Core::Constants::SPLIT_SIDE_BY_SIDE);
+ } else if (cmd.cmd == "mak" || cmd.cmd == "make") {
+ // :mak[e][!] [arguments]
+ triggerAction(ProjectExplorer::Constants::BUILD);
+ } else if (cmd.cmd == "se" || cmd.cmd == "set") {
+ if (cmd.args.isEmpty()) {
+ // :set
+ showSettingsDialog();
+ } else if (cmd.args == "ic" || cmd.args == "ignorecase") {
+ // :set noic
+ setActionChecked(Find::Constants::CASE_SENSITIVE, false);
+ *handled = false; // Let the handler see it as well.
+ } else if (cmd.args == "noic" || cmd.args == "noignorecase") {
+ // :set noic
+ setActionChecked(Find::Constants::CASE_SENSITIVE, true);
+ *handled = false; // Let the handler see it as well.
+ }
} else {
- typedef QMap<QString, QRegExp>::const_iterator Iterator;
- const Iterator end = s_exCommandMap.constEnd();
- for (Iterator it = s_exCommandMap.constBegin(); it != end; ++it) {
+ // Check whether one of the configure commands matches.
+ typedef CommandMap::const_iterator Iterator;
+ const Iterator end = exCommandMap().constEnd();
+ for (Iterator it = exCommandMap().constBegin(); it != end; ++it) {
const QString &id = it.key();
const QRegExp &re = it.value();
-
- if (!re.pattern().isEmpty() && re.indexIn(cmd) != -1) {
+ if (!re.pattern().isEmpty() && re.indexIn(cmd.cmd) != -1) {
triggerAction(id);
return;
}
}
-
- handler->showRedMessage(tr("Not an editor command: %1").arg(cmd));
- }
-}
-
-void FakeVimPluginPrivate::handleSetCommand(bool *handled, QString cmd)
-{
- *handled = false;
- bool value = true;
- if (cmd.startsWith("no")) {
- value = false;
- cmd = cmd.mid(2);
- }
-
- if (cmd == "ic" || cmd == "ignorecase") {
- setActionChecked(Find::Constants::CASE_SENSITIVE, value);
- *handled = true;
+ *handled = false;
}
}
@@ -1064,8 +1070,7 @@ void FakeVimPluginPrivate::indentRegion(int *amount, int beginLine, int endLine,
const QTextDocument *doc = bt->document();
const TextEditor::TextBlockIterator docStart(doc->begin());
QTextBlock cur = doc->findBlockByNumber(beginLine);
- for(int i = beginLine; i<= endLine; ++i)
- {
+ for (int i = beginLine; i <= endLine; ++i) {
if (typedChar == 0 && cur.text().simplified().isEmpty()) {
// clear empty lines
*amount = 0;
@@ -1130,6 +1135,17 @@ void FakeVimPluginPrivate::switchFilePrev()
switchFile(true);
}
+CommandMap &FakeVimExCommandsPage::exCommandMap()
+{
+ return m_q->exCommandMap();
+}
+
+CommandMap &FakeVimExCommandsPage::defaultExCommandMap()
+{
+ return m_q->defaultExCommandMap();
+}
+
+
///////////////////////////////////////////////////////////////////////
//
// FakeVimPlugin