From 5a809353d9288a5150bdb3a6ac30ca31644454c5 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: Fri, 19 Oct 2012 19:47:18 +0200 Subject: [PATCH] fakevim: Fix insert modes Change-Id: I8efb89e6931be2c37cfaf82f0aa053317c6b8d93 Reviewed-by: hjk --- src/plugins/fakevim/fakevim_test.cpp | 146 ++++++++++++++++++------- src/plugins/fakevim/fakevimhandler.cpp | 27 +++-- src/plugins/fakevim/fakevimplugin.h | 1 + 3 files changed, 128 insertions(+), 46 deletions(-) diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index 6fcd7d97e22..2aa2d2ddc8b 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -114,7 +114,9 @@ static const QString helpFormat = } while (false) // Test undo, redo and repeat of last single command. This doesn't test cursor position. -#define INTEGRITY() \ +// Set afterEnd to true if cursor position after undo and redo differs at the end of line +// (e.g. undoing 'A' operation moves cursor at the end of line and redo moves it one char right). +#define INTEGRITY(afterEnd) \ do { \ data.doKeys(""); \ const int newPosition = data.position(); \ @@ -123,7 +125,8 @@ static const QString helpFormat = KEYS("u", data.oldText); \ const QTextCursor tc = data.cursor(); \ const int pos = tc.position(); \ - const int col = tc.positionInBlock(); \ + const int col = tc.positionInBlock() \ + + ((afterEnd && tc.positionInBlock() + 2 == tc.block().length()) ? 1 : 0); \ const int line = tc.block().blockNumber(); \ const QTextDocument *doc = data.editor()->document(); \ KEYS("", textWithCursor(redo, doc->findBlockByNumber(line), col)); \ @@ -278,6 +281,62 @@ void FakeVimPlugin::test_vim_movement() KEYS("$a", "abc def" X N "ghi"); } +void FakeVimPlugin::test_vim_insert() +{ + TestData data; + setup(&data); + + // basic insert text + data.setText("ab" X "c" N "def"); + KEYS("i 123", "ab 123" X "c" N "def"); + INTEGRITY(false); + + data.setText("ab" X "c" N "def"); + KEYS("a 123", "abc 123" X N "def"); + INTEGRITY(true); + + data.setText("ab" X "c" N "def"); + KEYS("I 123", " 123" X "abc" N "def"); + INTEGRITY(false); + + data.setText("abc" N "def"); + KEYS("A 123", "abc 123" X N "def"); + INTEGRITY(true); + + data.setText("abc" N "def"); + KEYS("o 123", "abc" N " 123" X N "def"); + INTEGRITY(false); + + data.setText("abc" N "def"); + KEYS("O 123", " 123" X N "abc" N "def"); + INTEGRITY(false); + + // insert text [count] times + data.setText("ab" X "c" N "def"); + KEYS("3i 123", "ab 123 123 12" X "3c" N "def"); + INTEGRITY(false); + + data.setText("ab" X "c" N "def"); + KEYS("3a 123", "abc 123 123 12" X "3" N "def"); + INTEGRITY(true); + + data.setText("ab" X "c" N "def"); + KEYS("3I 123", " 123 123 12" X "3abc" N "def"); + INTEGRITY(false); + + data.setText("abc" N "def"); + KEYS("3A 123", "abc 123 123 12" X "3" N "def"); + INTEGRITY(true); + + data.setText("abc" N "def"); + KEYS("3o 123", "abc" N " 123" N " 123" N " 12" X "3" N "def"); + INTEGRITY(false); + + data.setText("abc" N "def"); + KEYS("3O 123", " 123" N " 123" N " 12" X "3" N "abc" N "def"); + INTEGRITY(false); +} + void FakeVimPlugin::test_vim_fFtT() { TestData data; @@ -306,18 +365,18 @@ void FakeVimPlugin::test_vim_transform_numbers() data.setText("8"); KEYS("", X "9"); - INTEGRITY(); + INTEGRITY(false); KEYS("", X "8"); - INTEGRITY(); + INTEGRITY(false); KEYS("", X "9"); KEYS("", "1" X "0"); KEYS("", "1" X "1"); KEYS("5", "1" X "6"); - INTEGRITY(); + INTEGRITY(false); KEYS("10", "2" X "6"); KEYS("h100", "12" X "6"); KEYS("100", "2" X "6"); - INTEGRITY(); + INTEGRITY(false); KEYS("10", "1" X "6"); KEYS("5", "1" X "1"); KEYS("5", X "6"); @@ -356,33 +415,33 @@ void FakeVimPlugin::test_vim_delete() data.setText("123" N "456"); KEYS("x", "23" N "456"); - INTEGRITY(); + INTEGRITY(false); KEYS("dd", "456"); - INTEGRITY(); + INTEGRITY(false); KEYS("2x", "6"); - INTEGRITY(); + INTEGRITY(false); KEYS("dd", ""); - INTEGRITY(); + INTEGRITY(false); data.setText("void main()"); KEYS("dt(", "()"); - INTEGRITY(); + INTEGRITY(false); data.setText("void main()"); KEYS("df(", ")"); - INTEGRITY(); + INTEGRITY(false); data.setText("void " X "main()"); KEYS("D", "void "); - INTEGRITY(); + INTEGRITY(false); KEYS("ggd$", ""); data.setText("abc def ghi"); KEYS("2dw", X "ghi"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc def ghi"); KEYS("d2w", X "ghi"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc " N " def" N " ghi" N "jkl"); KEYS("3dw", X "jkl"); @@ -396,7 +455,7 @@ void FakeVimPlugin::test_vim_delete() // delete on an empty line data.setText("a" N X "" N " b"); KEYS("d$", "a" N X "" N " b"); - INTEGRITY(); + INTEGRITY(false); // delete in empty document data.setText(""); @@ -413,11 +472,11 @@ void FakeVimPlugin::test_vim_delete_inner_word() data.setText("abc def ghi jkl"); KEYS("3diw", X " ghi jkl"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc " X " def"); KEYS("diw", "abc" X "def"); - INTEGRITY(); + INTEGRITY(false); KEYS("diw", ""); data.setText("abc " N " def"); @@ -460,9 +519,9 @@ void FakeVimPlugin::test_vim_delete_a_word() data.setText("abc" X " def ghi"); KEYS("daw", "abc" X " ghi"); - INTEGRITY(); + INTEGRITY(false); KEYS("daw", "ab" X "c"); - INTEGRITY(); + INTEGRITY(false); KEYS("daw", ""); data.setText(X " ghi jkl"); @@ -471,7 +530,7 @@ void FakeVimPlugin::test_vim_delete_a_word() data.setText("abc def ghi jkl"); KEYS("3daw", X "jkl"); - INTEGRITY(); + INTEGRITY(false); // remove trailing spaces data.setText("abc " N " def" N " ghi" N "jkl"); @@ -500,7 +559,7 @@ void FakeVimPlugin::test_vim_change_a_word() data.setText("abc " X "def ghi"); KEYS("caw#", "abc #" X "ghi"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc d" X "ef ghi"); KEYS("caw#", "abc #" X "ghi"); data.setText("abc de" X "f ghi"); @@ -508,7 +567,7 @@ void FakeVimPlugin::test_vim_change_a_word() data.setText("abc de" X "f ghi jkl"); KEYS("2caw#", "abc #" X "jkl"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc" X " def ghi jkl"); KEYS("2caw#", "abc#" X " jkl"); @@ -532,12 +591,12 @@ void FakeVimPlugin::test_vim_change_replace() // change empty line data.setText("a" N X "" N " b"); KEYS("ccABC", "a" N "ABC" X N " b"); - INTEGRITY(); + INTEGRITY(false); // change on empty line data.setText("a" N X "" N " b"); KEYS("c$ABC", "a" N "AB" X "C" N " b"); - INTEGRITY(); + INTEGRITY(false); KEYS("u", "a" N X "" N " b"); KEYS("rA", "a" N X "" N " b"); @@ -566,7 +625,7 @@ void FakeVimPlugin::test_vim_change_replace() " int i = 0;" X N "}" N ""); - INTEGRITY(); + INTEGRITY(false); KEYS("uS" "int i = 0;" N "int j = 1;", "int main()" N @@ -585,12 +644,12 @@ void FakeVimPlugin::test_vim_block_selection() data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("f(", "int main" X "(int /* (unused) */, char *argv[]);"); KEYS("da(", "int main" X ";"); - INTEGRITY(); + INTEGRITY(false); data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("f(", "int main" X "(int /* (unused) */, char *argv[]);"); KEYS("di(", "int main(" X ");"); - INTEGRITY(); + INTEGRITY(false); data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("2f)", "int main(int /* (unused) */, char *argv[]" X ");"); @@ -604,12 +663,12 @@ void FakeVimPlugin::test_vim_block_selection() KEYS("2f{l", "{ { {" X " } } }"); KEYS("da{", "{ { " X " } }"); KEYS("da{", "{ " X " }"); - INTEGRITY(); + INTEGRITY(false); data.setText("{ { { } } }"); KEYS("2f{l", "{ { {" X " } } }"); KEYS("2da{", "{ " X " }"); - INTEGRITY(); + INTEGRITY(false); data.setText("{" N " { " N " } " N "}"); KEYS("di{", "{" N "}"); @@ -629,7 +688,7 @@ void FakeVimPlugin::test_vim_repeat() data.setText("abc" N "def" N "ghi"); KEYS("dd", X "def" N "ghi"); KEYS(".", X "ghi"); - INTEGRITY(); + INTEGRITY(false); // delete to next word data.setText("abc def ghi jkl"); @@ -787,7 +846,7 @@ void FakeVimPlugin::test_vim_indent() " " X "ghi" N " jkl" N "mno"); - INTEGRITY(); + INTEGRITY(false); KEYS("k3<<", "abc" N X "def" N @@ -810,7 +869,7 @@ void FakeVimPlugin::test_vim_indent() data.setText("abc"); KEYS(">>", " " X "abc"); - INTEGRITY(); + INTEGRITY(false); data.setText("abc"); data.doCommand("set shiftwidth=2"); @@ -828,7 +887,7 @@ void FakeVimPlugin::test_vim_indent() data.doCommand("set shiftwidth=7"); data.setText("abc"); KEYS(">>", "\t\t abc"); - INTEGRITY(); + INTEGRITY(false); } void FakeVimPlugin::test_vim_marks() @@ -869,7 +928,7 @@ void FakeVimPlugin::test_vim_copy_paste() data.setText("123" N "456"); KEYS("yyp", "123" N X "123" N "456"); KEYS("2p", "123" N "123" N X "123" N "123" N "456"); - INTEGRITY(); + INTEGRITY(false); data.setText("123 456"); KEYS("yw2P", "123 123" X " 123 456"); @@ -1022,7 +1081,7 @@ void FakeVimPlugin::test_vim_code_autoindent() " return 0;" X N "}" N ""); - INTEGRITY(); + INTEGRITY(false); KEYS("O" "int i = 0;", "int main()" N "{" N @@ -1030,7 +1089,7 @@ void FakeVimPlugin::test_vim_code_autoindent() " return 0;" N "}" N ""); - INTEGRITY(); + INTEGRITY(false); KEYS("ddO" "int i = 0;" N "int j = 0;", "int main()" N "{" N @@ -1068,7 +1127,18 @@ void FakeVimPlugin::test_vim_code_autoindent() "{" N X "}" N ""); - INTEGRITY(); + INTEGRITY(false); + + // autoindent + data.doCommand("set nosmartindent"); + data.setText("abc" N "def"); + KEYS("3o 123", "abc" N " 123" N " 123" N " 12" X "3" N "def"); + INTEGRITY(false); + + data.setText("abc" N "def"); + KEYS("3O 123", " 123" N " 123" N " 12" X "3" N "abc" N "def"); + INTEGRITY(false); + data.doCommand("set smartindent"); } void FakeVimPlugin::test_vim_code_folding() diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index bcec9e33b8c..9a8f7908be4 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -2954,13 +2954,13 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) finishMovement(); } else if ((!isVisualMode() && input.is('a')) || (isVisualMode() && input.is('A'))) { leaveVisualMode(); - setUndoPosition(); breakEditBlock(); enterInsertMode(); - setDotCommand(QString(QLatin1Char('a'))); + setDotCommand("%1a", count()); m_lastInsertion.clear(); if (!atEndOfLine()) moveRight(); + setUndoPosition(); updateMiniBuffer(); } else if (input.is('A')) { breakEditBlock(); @@ -2969,6 +2969,7 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) setAnchor(); enterInsertMode(); setDotCommand(QString(QLatin1Char('A'))); + setDotCommand("%1A", count()); m_lastInsertion.clear(); updateMiniBuffer(); } else if (input.isControl('a')) { @@ -3151,7 +3152,7 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) handleStartOfLine(); finishMovement(); } else if (!isVisualMode() && (input.is('i') || input.isKey(Key_Insert))) { - setDotCommand(QString(QLatin1Char('i'))); // setDotCommand("%1i", count()); + setDotCommand("%1i", count()); breakEditBlock(); enterInsertMode(); updateMiniBuffer(); @@ -3169,7 +3170,7 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input) if (input.is('I')) { setUndoPosition(); - setDotCommand(QString(QLatin1Char('I'))); // setDotCommand("%1I", count()); + setDotCommand("%1I", count()); if (isVisualMode()) { int beginLine = lineForPosition(anchor()); int endLine = lineForPosition(position()); @@ -3288,6 +3289,7 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input) } beginEditBlock(); insertText(QString("\n")); + m_lastInsertion += '\n'; if (!appendLine) moveUp(); insertAutomaticIndentation(insertAfter); @@ -3638,15 +3640,24 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) } else { // 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); + const int repeat = count(); + if (repeat > 1) { + const QString text = m_lastInsertion; + for (int i = 1; i < repeat; ++i) { + m_lastInsertion.truncate(0); + foreach (const QChar &c, text) + handleInsertMode(Input(c)); + } + m_lastInsertion = text; + } moveLeft(qMin(1, leftDist())); setTargetColumn(); leaveVisualMode(); breakEditBlock(); } + // If command is 'o' or 'O' don't include the first line feed in dot command. + if (g.dotCommand.endsWith(QChar('o'), Qt::CaseInsensitive)) + m_lastInsertion.remove(0, 1); g.dotCommand += m_lastInsertion; g.dotCommand += QChar(27); enterCommandMode(); diff --git a/src/plugins/fakevim/fakevimplugin.h b/src/plugins/fakevim/fakevimplugin.h index aa8f03edde7..89d6a4d8c3b 100644 --- a/src/plugins/fakevim/fakevimplugin.h +++ b/src/plugins/fakevim/fakevimplugin.h @@ -61,6 +61,7 @@ private: private slots: void cleanup(); void test_vim_movement(); + void test_vim_insert(); void test_vim_fFtT(); void test_vim_transform_numbers(); void test_vim_delete();