aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/fakevim/fakevimhandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/fakevim/fakevimhandler.cpp')
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp135
1 files changed, 81 insertions, 54 deletions
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 50385d9c6a..e18599d707 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -29,28 +29,33 @@
#include "fakevimhandler.h"
-// Please do not add any direct dependencies to other Qt Creator code here.
-// Instead emit signals and let the FakeVimPlugin channel the information to
-// Qt Creator. The idea is to keep this file here in a "clean" state that
-// allows easy reuse with any QTextEdit or QPlainTextEdit derived class.
-
-
-// Some conventions:
//
-// Use 1 based line numbers and 0 based column numbers. Even though
-// the 1 based line are not nice it matches vim's and QTextEdit's 'line'
-// concepts.
+// ATTENTION:
+//
+// 1 Please do not add any direct dependencies to other Qt Creator code here.
+// Instead emit signals and let the FakeVimPlugin channel the information to
+// Qt Creator. The idea is to keep this file here in a "clean" state that
+// allows easy reuse with any QTextEdit or QPlainTextEdit derived class.
+//
+// 2 There are a few auto tests located in ../../../tests/auto/fakevim.
+// Commands that are covered there are marked as "// tested" below.
+//
+// 3 Some conventions:
//
-// Do not pass QTextCursor etc around unless really needed. Convert
-// early to line/column.
+// Use 1 based line numbers and 0 based column numbers. Even though
+// the 1 based line are not nice it matches vim's and QTextEdit's 'line'
+// concepts.
//
-// There is always a "current" cursor (m_tc). A current "region of interest"
-// spans between m_anchor (== anchor()) and m_tc.position() (== position())
-// The value of m_tc.anchor() is not used.
+// Do not pass QTextCursor etc around unless really needed. Convert
+// early to line/column.
+//
+// There is always a "current" cursor (m_tc). A current "region of interest"
+// spans between m_anchor (== anchor()) and m_tc.position() (== position())
+// The value of m_tc.anchor() is not used.
+//
#include <utils/qtcassert.h>
-
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtCore/QObject>
@@ -278,7 +283,7 @@ public:
typedef QTextCursor::MoveOperation MoveOperation;
typedef QTextCursor::MoveMode MoveMode;
void moveToEndOfDocument() { m_tc.movePosition(EndOfDocument, MoveAnchor); }
- void moveToStartOfLine() { m_tc.movePosition(StartOfLine, MoveAnchor); }
+ void moveToStartOfLine();
void moveToEndOfLine();
void moveUp(int n = 1) { moveDown(-n); }
void moveDown(int n = 1); // { m_tc.movePosition(Down, MoveAnchor, n); }
@@ -353,6 +358,8 @@ public:
// 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 '.'
@@ -613,8 +620,9 @@ void FakeVimHandler::Private::moveDown(int n)
m_tc.movePosition(Down, MoveAnchor, n);
#else
const int col = m_tc.position() - m_tc.block().position();
- const int line = m_tc.block().blockNumber();
- const QTextBlock &block = m_tc.document()->findBlockByNumber(line + n);
+ const int lastLine = m_tc.document()->lastBlock().blockNumber();
+ const int targetLine = qMax(0, qMin(lastLine, m_tc.block().blockNumber() + n));
+ const QTextBlock &block = m_tc.document()->findBlockByNumber(targetLine);
const int pos = block.position();
setPosition(pos + qMin(block.length() - 1, col));
moveToTargetColumn();
@@ -632,6 +640,17 @@ void FakeVimHandler::Private::moveToEndOfLine()
#endif
}
+void FakeVimHandler::Private::moveToStartOfLine()
+{
+#if 0
+ // does not work for "hidden" documents like in the autotests
+ m_tc.movePosition(StartOfLine, MoveAnchor);
+#else
+ const QTextBlock &block = m_tc.block();
+ setPosition(block.position());
+#endif
+}
+
void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
{
//qDebug() << "ANCHOR: " << position() << anchor();
@@ -656,7 +675,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (anchor() >= position())
m_anchor++;
if (!dotCommand.isEmpty())
- m_dotCommand = "c" + dotCommand;
+ setDotCommand("c" + dotCommand);
QString text = removeSelectedText();
//qDebug() << "CHANGING TO INSERT MODE" << text;
m_registers[m_register] = text;
@@ -668,7 +687,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
if (anchor() >= position())
m_anchor++;
if (!dotCommand.isEmpty())
- m_dotCommand = "d" + dotCommand;
+ setDotCommand("d" + dotCommand);
m_registers[m_register] = removeSelectedText();
m_submode = NoSubMode;
if (atEndOfLine())
@@ -694,8 +713,6 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
updateMiniBuffer();
}
- moveToTargetColumn();
-
m_moveType = MoveInclusive;
m_mvcount.clear();
m_opcount.clear();
@@ -847,13 +864,19 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
} else if (m_submode == RegisterSubMode) {
m_register = key;
m_submode = NoSubMode;
- } else if (m_submode == ChangeSubMode && key == 'c') {
- moveToStartOfLine();
+ } else if (m_submode == ChangeSubMode && key == 'c') { // tested
+ moveDown(count() - 1);
+ moveToEndOfLine();
+ moveLeft();
setAnchor();
- moveDown(count());
+ moveToStartOfLine();
+ setTargetColumn();
+ moveUp(count() - 1);
m_moveType = MoveLineWise;
- finishMovement("c");
- } else if (m_submode == DeleteSubMode && key == 'd') {
+ m_lastInsertion.clear();
+ setDotCommand("%1cc", count());
+ finishMovement();
+ } else if (m_submode == DeleteSubMode && key == 'd') { // tested
moveToStartOfLine();
setAnchor();
moveDown(count());
@@ -869,19 +892,19 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
setAnchor();
moveDown(count() - 1);
m_moveType = MoveLineWise;
- m_dotCommand = QString("%1<<").arg(count());
+ setDotCommand("%1<<", count());
finishMovement();
} else if (m_submode == ShiftRightSubMode && key == '>') {
setAnchor();
moveDown(count() - 1);
m_moveType = MoveLineWise;
- m_dotCommand = QString("%1>>").arg(count());
+ setDotCommand("%1>>", count());
finishMovement();
} else if (m_submode == IndentSubMode && key == '=') {
setAnchor();
moveDown(count() - 1);
m_moveType = MoveLineWise;
- m_dotCommand = QString("%1>>").arg(count());
+ setDotCommand("%1>>", count());
finishMovement();
} else if (m_submode == ZSubMode) {
//qDebug() << "Z_MODE " << cursorLineInDocument() << linesOnScreen();
@@ -928,7 +951,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
m_tc.insertText(QString(count(), text.at(0)));
m_moveType = MoveExclusive;
m_submode = NoSubMode;
- m_dotCommand = QString("%1r%2").arg(count()).arg(text);
+ setDotCommand("%1r" + text, count());
finishMovement();
} else {
m_submode = NoSubMode;
@@ -1125,7 +1148,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
handleStartOfLine();
scrollToLineInDocument(cursorLineInDocument() - sline);
finishMovement();
- } else if (key == 'e') {
+ } else if (key == 'e') { // tested
m_moveType = MoveInclusive;
moveToWordBoundary(false, true);
finishMovement();
@@ -1175,13 +1198,13 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
handleStartOfLine();
finishMovement();
} else if (key == 'i') {
- m_dotCommand = "i"; //QString("%1i").arg(count());
+ setDotCommand("i"); // setDotCommand("%1i", count());
enterInsertMode();
updateMiniBuffer();
if (atEndOfLine())
moveLeft();
} else if (key == 'I') {
- m_dotCommand = "I"; //QString("%1I").arg(count());
+ setDotCommand("I"); // setDotCommand("%1I", count());
enterInsertMode();
if (m_gflag)
moveToStartOfLine();
@@ -1256,7 +1279,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
search(lastSearchString(), !m_lastSearchForward);
recordJump();
} else if (key == 'o' || key == 'O') {
- m_dotCommand = QString("%1o").arg(count());
+ setDotCommand("%1o", count());
enterInsertMode();
moveToFirstNonBlankOnLine();
if (key == 'O')
@@ -1293,18 +1316,18 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
moveLeft();
}
}
- m_dotCommand = QString("%1p").arg(count());
+ setDotCommand("%1p", count());
finishMovement();
} else if (key == 'r') {
m_submode = ReplaceSubMode;
- m_dotCommand = "r";
+ setDotCommand("r");
} else if (key == 'R') {
// FIXME: right now we repeat the insertion count() times,
// but not the deletion
m_lastInsertion.clear();
m_mode = InsertMode;
m_submode = ReplaceSubMode;
- m_dotCommand = "R";
+ setDotCommand("R");
} else if (key == control('r')) {
redo();
} else if (key == 's') {
@@ -1313,7 +1336,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
setAnchor();
moveRight(qMin(count(), rightDist()));
m_registers[m_register] = removeSelectedText();
- m_dotCommand = "s"; //QString("%1s").arg(count());
+ setDotCommand("s"); // setDotCommand("%1s", count());
m_opcount.clear();
m_mvcount.clear();
enterInsertMode();
@@ -1340,7 +1363,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
enterVisualMode(VisualLineMode);
} else if (key == control('v')) {
enterVisualMode(VisualBlockMode);
- } else if (key == 'w') {
+ } else if (key == 'w') { // tested
// Special case: "cw" and "cW" work the same as "ce" and "cE" if the
// cursor is on a non-blank.
if (m_submode == ChangeSubMode) {
@@ -1369,7 +1392,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
setAnchor();
m_submode = DeleteSubMode;
moveRight(qMin(count(), rightDist()));
- m_dotCommand = QString("%1x").arg(count());
+ setDotCommand("%1x", count());
finishMovement();
} else if (key == 'X') {
if (leftDist() > 0) {
@@ -1957,16 +1980,16 @@ void FakeVimHandler::Private::highlightMatches(const QString &needle0)
void FakeVimHandler::Private::moveToFirstNonBlankOnLine()
{
- QTextBlock block = m_tc.block();
QTextDocument *doc = m_tc.document();
- m_tc.movePosition(StartOfLine, KeepAnchor);
- int firstPos = m_tc.position();
+ const QTextBlock &block = m_tc.block();
+ int firstPos = block.position();
for (int i = firstPos, n = firstPos + block.length(); i < n; ++i) {
if (!doc->characterAt(i).isSpace()) {
- m_tc.setPosition(i, KeepAnchor);
+ setPosition(i);
return;
}
}
+ setPosition(block.position());
}
void FakeVimHandler::Private::indentRegion(QChar typedChar)
@@ -1978,7 +2001,7 @@ void FakeVimHandler::Private::indentRegion(QChar typedChar)
qSwap(beginLine, endLine);
int amount = 0;
emit q->indentRegion(&amount, beginLine, endLine, typedChar);
- m_dotCommand = QString("%1==").arg(endLine - beginLine + 1);
+ setDotCommand("%1==", endLine - beginLine + 1);
}
void FakeVimHandler::Private::shiftRegionRight(int repeat)
@@ -2000,7 +2023,7 @@ void FakeVimHandler::Private::shiftRegionRight(int repeat)
setPosition(firstPos);
moveToFirstNonBlankOnLine();
- m_dotCommand = QString("%1>>").arg(endLine - beginLine + 1);
+ setDotCommand("%1>>", endLine - beginLine + 1);
}
void FakeVimHandler::Private::shiftRegionLeft(int repeat)
@@ -2037,17 +2060,20 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat)
setPosition(firstPos);
moveToFirstNonBlankOnLine();
- m_dotCommand = QString("%1<<").arg(endLine - beginLine + 1);
+ setDotCommand("%1<<", endLine - beginLine + 1);
}
void FakeVimHandler::Private::moveToTargetColumn()
{
- if (m_targetColumn == -1 || m_tc.block().length() <= m_targetColumn) {
- const QTextBlock &block = m_tc.block();
+ const QTextBlock &block = m_tc.block();
+ int col = m_tc.position() - m_tc.block().position();
+ if (col == m_targetColumn)
+ return;
+ //qDebug() << "CORRECTING COLUMN FROM: " << col << "TO" << m_targetColumn;
+ if (m_targetColumn == -1 || m_tc.block().length() <= m_targetColumn)
m_tc.setPosition(block.position() + block.length() - 1, KeepAnchor);
- } else {
+ else
m_tc.setPosition(m_tc.block().position() + m_targetColumn, KeepAnchor);
- }
}
/* if simple is given:
@@ -2075,7 +2101,7 @@ void FakeVimHandler::Private::moveToWordBoundary(bool simple, bool forward)
int lastClass = -1;
while (true) {
QChar c = doc->characterAt(m_tc.position() + (forward ? 1 : -1));
- qDebug() << "EXAMINING: " << c << " AT " << position();
+ //qDebug() << "EXAMINING: " << c << " AT " << position();
int thisClass = charClass(c, simple);
if (thisClass != lastClass && lastClass != 0)
--repeat;
@@ -2319,6 +2345,7 @@ QString FakeVimHandler::Private::removeSelectedText()
m_tc.setPosition(pos, KeepAnchor);
QString from = m_tc.selection().toPlainText();
m_tc.removeSelectedText();
+ setAnchor();
return from;
}