// Copyright (C) 2016 Lukas Holecek // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 /*! * Tests for FakeVim plugin. * All test are based on Vim behaviour. */ #include "fakevimhandler.h" #include #include #include #include #include #include #include #include //TESTED_COMPONENT=src/plugins/fakevim /*! * Tests after this macro will be skipped and warning printed. * Uncomment it to test a feature -- if tests succeeds it should be removed from the test. */ #define NOT_IMPLEMENTED QSKIP("Not fully implemented!"); // Text cursor representation in comparisons. #define X "|" // More distinct line separator in code. #define N "\n" // Document line start and end string in error text. #define LINE_START "\t\t<" #define LINE_END ">\n" using namespace TextEditor; namespace FakeVim::Internal { QString _(const char *c) { return QLatin1String(c); } QString _(const QByteArray &c) { return QLatin1String(c); } QString _(const QString &c) { return c; } class FakeVimTester final : public QObject { Q_OBJECT private slots: void cleanup(); void test_vim_movement(); void test_vim_target_column_normal(); void test_vim_target_column_visual_char(); void test_vim_target_column_visual_block(); void test_vim_target_column_visual_line(); void test_vim_target_column_insert(); void test_vim_target_column_replace(); void test_vim_insert(); void test_vim_fFtT(); void test_vim_transform_numbers(); void test_vim_delete(); void test_vim_delete_inner_word(); void test_vim_delete_a_word(); void test_vim_change_a_word(); void test_vim_change_replace(); void test_vim_block_selection(); void test_vim_block_selection_insert(); void test_vim_delete_inner_paragraph(); void test_vim_delete_a_paragraph(); void test_vim_change_inner_paragraph(); void test_vim_change_a_paragraph(); void test_vim_select_inner_paragraph(); void test_vim_select_a_paragraph(); void test_vim_repeat(); void test_vim_search(); void test_vim_indent(); void test_vim_marks(); void test_vim_jumps(); void test_vim_current_column(); void test_vim_copy_paste(); void test_vim_undo_redo(); void test_vim_letter_case(); void test_vim_code_autoindent(); void test_vim_code_folding(); void test_vim_code_completion(); void test_vim_substitute(); void test_vim_ex_commandbuffer_paste(); void test_vim_ex_yank(); void test_vim_ex_delete(); void test_vim_ex_change(); void test_vim_ex_shift(); void test_vim_ex_move(); void test_vim_ex_join(); void test_advanced_commands(); //public: // void changeStatusData(const QString &info) { m_statusData = info; } // void changeStatusMessage(const QString &info, int) { m_statusMessage = info; } // void changeExtraInformation(const QString &info) { m_infoMessage = info; } //private slots: // // functional tests void test_vim_indentation(); // command mode void test_vim_command_oO(); void test_vim_command_put_at_eol(); void test_vim_command_Cxx_down_dot(); void test_vim_command_Gyyp(); void test_vim_command_J(); void test_vim_command_Yp(); void test_vim_command_cc(); void test_vim_command_cw(); void test_vim_command_cj(); void test_vim_command_ck(); void test_vim_command_c_dollar(); void test_vim_command_C(); void test_vim_command_dd(); void test_vim_command_dd_2(); void test_vim_command_d_dollar(); void test_vim_command_dgg(); void test_vim_command_dG(); void test_vim_command_dj(); void test_vim_command_dk(); void test_vim_command_D(); void test_vim_command_dfx_down(); void test_vim_command_dollar(); void test_vim_command_down(); void test_vim_command_dw(); void test_vim_command_e(); void test_vim_command_i(); void test_vim_command_left(); void test_vim_command_ma_yank(); void test_vim_command_r(); void test_vim_command_right(); void test_vim_command_up(); void test_vim_command_w(); void test_vim_command_x(); void test_vim_command_yyp(); void test_vim_command_y_dollar(); void test_vim_command_percent(); void test_vim_visual_d(); void test_vim_Visual_d(); void test_vim_visual_block_D(); // Plugin emulation void test_vim_commentary_emulation(); void test_vim_commentary_file_names(); void test_vim_replace_with_register_emulation(); void test_vim_exchange_emulation(); void test_vim_arg_text_obj_emulation(); void test_vim_surround_emulation(); void test_macros(); void test_vim_qtcreator(); // special tests void test_i_cw_i(); // map test should be last one since it changes default behaviour void test_map(); //private: // QString m_statusMessage; // QString m_statusData; // QString m_infoMessage; private: struct TestData; void setup(TestData *data); }; using SetupTestCallback = void (*)(QString *, FakeVimHandler **, QWidget **); static SetupTestCallback setupTest = nullptr; QObject *createFakeVimTester(SetupTestCallback cb) { setupTest = cb; return new FakeVimTester; } // Format of message after comparison fails (used by KEYS, COMMAND). static const QString helpFormat = _( "\n\tBefore command [%1]:\n" \ LINE_START "%2" LINE_END \ "\n\tAfter the command:\n" \ LINE_START "%3" LINE_END \ "\n\tShould be:\n" \ LINE_START "%4" LINE_END); static QByteArray textWithCursor(const QByteArray &text, int position) { return (position == -1) ? text : (text.left(position) + X + text.mid(position)); } static QByteArray textWithCursor(const QByteArray &text, const QTextBlock &block, int column) { const int pos = block.position() + qMin(column, qMax(0, block.length() - 2)); return text.left(pos) + X + text.mid(pos); } // Compare document contents with a expectedText. // Also check cursor position if the expectedText contains | chracter. // Send keys and check if the expected result is same as document contents. // Escape is always prepended to keys so that previous command is cancelled. #define KEYS(keys, expectedText) \ do { \ QByteArray beforeText(data.text()); \ int beforePosition = data.position(); \ data.doKeys(keys); \ QByteArray actual(data.text()); \ QByteArray expected = expectedText; \ QByteArray desc = data.fixup(_(keys), beforeText, actual, expected, beforePosition); \ QVERIFY2(actual == expected, desc.constData()); \ } while (false) // Run Ex command and check if the expected result is same as document contents. #define COMMAND(cmd, expectedText) \ do { \ QByteArray beforeText(data.text()); \ int beforePosition = data.position(); \ data.doCommand(cmd); \ QByteArray actual(data.text()); \ QByteArray expected = expectedText; \ QByteArray desc = data.fixup(_(":" cmd), beforeText, actual, expected, beforePosition); \ QVERIFY2(actual == expected, desc.constData()); \ } while (false) // Test undo, redo and repeat of last single command. This doesn't test cursor position. // 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(); \ const int oldPosition = data.oldPosition; \ const QByteArray redo = data.text(); \ KEYS("u", data.oldText); \ const QTextCursor tc = data.cursor(); \ const int pos = tc.position(); \ 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)); \ KEYS("u", textWithCursor(data.oldText, pos)); \ data.setPosition(oldPosition); \ KEYS(".", textWithCursor(redo, newPosition)); \ } while (false) const QByteArray testLines = /* 0 1 2 3 4 */ /* 0123456789012345678901234567890123457890 */ "\n" "#include \n" "#include \n" "\n" "int main(int argc, char *argv[])\n" "{\n" " QApplication app(argc, argv);\n" "\n" " return app.exec();\n" "}\n"; const QList l = testLines.split('\n'); static QByteArray bajoin(const QList &balist) { QByteArray res; for (int i = 0; i < balist.size(); ++i) { if (i) res += '\n'; res += balist.at(i); } return res; } // Insert cursor char at pos, negative counts from back. static QByteArray cursor(int line, int column) { const int col = column >= 0 ? column : l[line].size() + column; QList res = l.mid(0, line) << textWithCursor(l[line], col); res.append(l.mid(line + 1)); return bajoin(res); } static QByteArray lmid(int i, int n = -1) { return bajoin(l.mid(i, n)); } // Data for tests containing BaseTextEditorWidget and FakeVimHAndler. struct FakeVimTester::TestData { FakeVimHandler *handler; QWidget *edit; QString title; int oldPosition; QByteArray oldText; TextEditorWidget *editor() const { return qobject_cast(edit); } QTextCursor cursor() const { return editor()->textCursor(); } QByteArray fixup(const QString &cmd, QByteArray &before, QByteArray &actual, QByteArray &expected, int beforePosition) { oldPosition = beforePosition; oldText = before; if (expected.contains(X)) { before = textWithCursor(before, beforePosition); actual = textWithCursor(actual, position()); } return helpFormat .arg(cmd) .arg(QString::fromLatin1(before.replace('\n', LINE_END LINE_START))) .arg(QString::fromLatin1(actual.replace('\n', LINE_END LINE_START))) .arg(QString::fromLatin1(expected.replace('\n', LINE_END LINE_START))).toLatin1(); } int position() const { return cursor().position(); } void setPosition(int position) { handler->setTextCursorPosition(position); } QByteArray text() const { return editor()->toPlainText().toUtf8(); } void doCommand(const QString &cmd) { handler->handleCommand(cmd); } void doCommand(const char *cmd) { doCommand(_(cmd)); } void doKeys(const QString &keys) { handler->handleInput(keys); QTRY_VERIFY(editor()->textDocument()->syntaxHighlighter()->syntaxHighlighterUpToDate()); } void doKeys(const char *keys) { doKeys(_(keys)); } void setText(const char *text) { doKeys(""); QByteArray str = text; int i = str.indexOf(X); if (i != -1) str.remove(i, 1); else i = 0; editor()->document()->setPlainText(_(str)); QTRY_VERIFY(editor()->textDocument()->syntaxHighlighter()->syntaxHighlighterUpToDate()); setPosition(i); QCOMPARE(position(), i); } // Simulate text completion by inserting text directly to editor widget (bypassing FakeVim). void completeText(const char *text) { QTextCursor tc = editor()->textCursor(); tc.insertText(_(text)); editor()->setTextCursor(tc); QTRY_VERIFY(editor()->textDocument()->syntaxHighlighter()->syntaxHighlighterUpToDate()); } // Simulate external position change. void jump(const char *textWithCursorPosition) { int pos = QString(_(textWithCursorPosition)).indexOf(_(X)); QTextCursor tc = editor()->textCursor(); tc.setPosition(pos); editor()->setTextCursor(tc); QCOMPARE(QByteArray(textWithCursorPosition), textWithCursor(text(), position())); } int lines() const { QTextDocument *doc = editor()->document(); Q_ASSERT(doc != nullptr); return doc->lineCount(); } // Enter command mode and go to start. void reset() { handler->handleInput(_("gg0")); } }; void FakeVimTester::setup(TestData *data) { setupTest(&data->title, &data->handler, &data->edit); data->reset(); data->doCommand("| set nopasskeys" "| set nopasscontrolkey" "| set smartindent" "| set autoindent"); } void FakeVimTester::cleanup() { Core::EditorManager::closeAllEditors(false); } void FakeVimTester::test_vim_indentation() { TestData data; setup(&data); data.doCommand("set expandtab"); data.doCommand("set tabstop=4"); data.doCommand("set shiftwidth=4"); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4); QCOMPARE(data.handler->tabExpand(3), _(" ")); QCOMPARE(data.handler->tabExpand(4), _(" ")); QCOMPARE(data.handler->tabExpand(5), _(" ")); QCOMPARE(data.handler->tabExpand(6), _(" ")); QCOMPARE(data.handler->tabExpand(7), _(" ")); QCOMPARE(data.handler->tabExpand(8), _(" ")); QCOMPARE(data.handler->tabExpand(9), _(" ")); data.doCommand("set expandtab"); data.doCommand("set tabstop=8"); data.doCommand("set shiftwidth=4"); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8); QCOMPARE(data.handler->tabExpand(3), _(" ")); QCOMPARE(data.handler->tabExpand(4), _(" ")); QCOMPARE(data.handler->tabExpand(5), _(" ")); QCOMPARE(data.handler->tabExpand(6), _(" ")); QCOMPARE(data.handler->tabExpand(7), _(" ")); QCOMPARE(data.handler->tabExpand(8), _(" ")); QCOMPARE(data.handler->tabExpand(9), _(" ")); data.doCommand("set noexpandtab"); data.doCommand("set tabstop=4"); data.doCommand("set shiftwidth=4"); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4); QCOMPARE(data.handler->tabExpand(3), _(" ")); QCOMPARE(data.handler->tabExpand(4), _("\t")); QCOMPARE(data.handler->tabExpand(5), _("\t ")); QCOMPARE(data.handler->tabExpand(6), _("\t ")); QCOMPARE(data.handler->tabExpand(7), _("\t ")); QCOMPARE(data.handler->tabExpand(8), _("\t\t")); QCOMPARE(data.handler->tabExpand(9), _("\t\t ")); data.doCommand("set noexpandtab"); data.doCommand("set tabstop=8"); data.doCommand("set shiftwidth=4"); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8); QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3); QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8); QCOMPARE(data.handler->tabExpand(3), _(" ")); QCOMPARE(data.handler->tabExpand(4), _(" ")); QCOMPARE(data.handler->tabExpand(5), _(" ")); QCOMPARE(data.handler->tabExpand(6), _(" ")); QCOMPARE(data.handler->tabExpand(7), _(" ")); QCOMPARE(data.handler->tabExpand(8), _("\t")); QCOMPARE(data.handler->tabExpand(9), _("\t ")); } void FakeVimTester::test_vim_movement() { TestData data; setup(&data); // vertical movement data.setText("123" N "456" N "789" N "abc"); KEYS("", X "123" N "456" N "789" N "abc"); KEYS("j", "123" N X "456" N "789" N "abc"); KEYS("G", "123" N "456" N "789" N X "abc"); KEYS("k", "123" N "456" N X "789" N "abc"); KEYS("2k", X "123" N "456" N "789" N "abc"); KEYS("k", X "123" N "456" N "789" N "abc"); KEYS("jj", "123" N "456" N X "789" N "abc"); KEYS("gg", X "123" N "456" N "789" N "abc"); // horizontal movement data.setText(" " X "x" "x" "x" "x"); KEYS("", " " X "x" "x" "x" "x"); KEYS("h", X " " "x" "x" "x" "x"); KEYS("l", " " X "x" "x" "x" "x"); KEYS("3l", " " "x" "x" "x" X "x"); KEYS("2h", " " "x" X "x" "x" "x"); KEYS("$", " " "x" "x" "x" X "x"); KEYS("^", " " X "x" "x" "x" "x"); KEYS("0", X " " "x" "x" "x" "x"); // skip words data.setText("123 " "456" "." "789 " "abc"); KEYS("b", X "123 " "456" "." "789 " "abc"); KEYS("w", "123 " X "456" "." "789 " "abc"); KEYS("2w", "123 " "456" "." X "789 " "abc"); KEYS("3w", "123 " "456" "." "789 " "ab" X "c"); KEYS("3b", "123 " "456" X "." "789 " "abc"); data.setText("123 " "456.789 " "abc " "def"); KEYS("B", X "123 " "456.789 " "abc " "def"); KEYS("W", "123 " X "456.789 " "abc " "def"); KEYS("2W", "123 " "456.789 " "abc " X "def"); KEYS("B", "123 " "456.789 " X "abc " "def"); KEYS("2B", X "123 " "456.789 " "abc " "def"); KEYS("4W", "123 " "456.789 " "abc " "de" X "f"); data.setText("assert(abc);"); KEYS("w", "assert" X "(abc);"); KEYS("w", "assert(" X "abc);"); KEYS("w", "assert(abc" X ");"); KEYS("w", "assert(abc)" X ";"); data.setText("123" N "45." "6" N "" N " " N "789"); KEYS("3w", "123" N "45." X "6" N "" N " " N "789"); // From Vim help (motion.txt): An empty line is also considered to be a word. KEYS("w", "123" N "45." "6" N X "" N " " N "789"); KEYS("w", "123" N "45." "6" N "" N " " N X "789"); KEYS("b", "123" N "45." "6" N X "" N " " N "789"); KEYS("4b", X "123" N "45." "6" N "" N " " N "789"); KEYS("3e", "123" N "45" X "." "6" N "" N " " N "789"); KEYS("e", "123" N "45" "." X "6" N "" N " " N "789"); // Command "e" does not stop on empty lines ("ge" does). KEYS("e", "123" N "45" "." "6" N "" N " " N "78" X "9"); KEYS("ge", "123" N "45" "." "6" N X "" N " " N "789"); KEYS("2ge", "123" N "45" X "." "6" N "" N " " N "789"); // do not move behind end of line in normal mode data.setText("abc def" N "ghi"); KEYS("$h", "abc d" X "ef" N "ghi"); data.setText("abc def" N "ghi"); KEYS("4e", "abc def" N "gh" X "i"); data.setText("abc def" N "ghi"); KEYS("$i", "abc de" X "f" N "ghi"); // move behind end of line in insert mode data.setText("abc def" N "ghi"); KEYS("i", "abc def" X N "ghi"); data.setText("abc def" N "ghi"); KEYS("A", "abc def" X N "ghi"); data.setText("abc def" N "ghi"); KEYS("$a", "abc def" X N "ghi"); data.setText("abc" N "def ghi"); KEYS("i", "abc" N "def ghi" X); data.setText("abc" N "def ghi"); KEYS("i", "abc" N "de" X "f ghi"); data.setText("abc" N "def ghi"); KEYS("a", "abc" N "def" X " ghi"); // paragraph movement data.setText("abc" N N "def"); KEYS("}", "abc" N X N "def"); KEYS("}", "abc" N N "de" X "f"); KEYS("{", "abc" N X N "def"); KEYS("{", X "abc" N N "def"); data.setText("abc" N N N N "def"); KEYS("}", "abc" N X N N N "def"); KEYS("}", "abc" N N N N "de" X "f"); KEYS("3{", "abc" N N N N "de" X "f"); KEYS("{", "abc" N N N X N "def"); KEYS("{", X "abc" N N N N "def"); KEYS("3}", X "abc" N N N N "def"); data.setText("abc def"); KEYS("}", "abc de" X "f"); KEYS("{", X "abc def"); // bracket movement commands data.setText( "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("]]", "void a()" N X "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("]]", "void a()" N "{" N "}" N "" N "int b()" N X "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("2[[", X "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("4]]", "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N X ""); KEYS("2[]", "void a()" N "{" N X "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("][", "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N X "}" N ""); KEYS("][", "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N X ""); } void FakeVimTester::test_vim_target_column_normal() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); // normal mode movement KEYS("", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" X "e" N "" N "k" "l" "m" "n"); KEYS("k", "a" "b" X "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("3j", "a" "b" "c" N "d" "e" N "" N "k" "l" "m" X "n"); KEYS("02k", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("2k", "a" "b" X "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("jj2|", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" N "k" X "l" "m" "n"); KEYS("gg", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("^k", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); } void FakeVimTester::test_vim_target_column_visual_char() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("v", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" X N "" N "k" "l" "m" "n"); KEYS("k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("3j", "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n" X); KEYS("02k", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("2k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("jj2|", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" N "k" X "l" "m" "n"); KEYS("gg", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("^k", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("lO", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); } void FakeVimTester::test_vim_target_column_visual_block() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("", "a" X "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" X "e" N "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" X N "" N "k" "l" "m" "n"); KEYS("k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("3j", "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n" X); KEYS("02k", "a" "b" "c" N "d" X "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("2k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("jj2|", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" N "k" "l" X "m" "n"); KEYS("gg", "a" X "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" X "e" N "" N "k" "l" "m" "n"); KEYS("^k", "a" X "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("lO", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); } void FakeVimTester::test_vim_target_column_visual_line() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("lV", "a" X "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("Vj", "a" "b" "c" N "d" X "e" N "" N "k" "l" "m" "n"); KEYS("Vj", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("Vj", "a" "b" "c" N "d" "e" N "" N "k" X "l" "m" "n"); KEYS("Vgg", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); NOT_IMPLEMENTED // Movement inside selection is not supported. } void FakeVimTester::test_vim_target_column_insert() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("i", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" X N "" N "k" "l" "m" "n"); KEYS("k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("3j", "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n" X); KEYS("02k", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("2k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("2|", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" N "k" X "l" "m" "n"); KEYS("gg", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("^", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); } void FakeVimTester::test_vim_target_column_replace() { TestData data; setup(&data); data.setText("a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("i", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" X N "" N "k" "l" "m" "n"); KEYS("k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("3j", "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n" X); KEYS("02k", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N X "" N "k" "l" "m" "n"); KEYS("$", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("2k", "a" "b" "c" X N "d" "e" N "" N "k" "l" "m" "n"); KEYS("2|", "a" "b" "c" N "d" "e" N "" X N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N "d" "e" N "" N "k" X "l" "m" "n"); KEYS("gg", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); KEYS("j", "a" "b" "c" N X "d" "e" N "" N "k" "l" "m" "n"); KEYS("^", X "a" "b" "c" N "d" "e" N "" N "k" "l" "m" "n"); } void FakeVimTester::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); // data.setText("abc" N "d" X "ef"); KEYS("ixX", "abc" N "dX" X "f"); data.doKeys(""); KEYS("i", "abc" N "dXf" X); data.setText("ab" X "c" N "def"); KEYS("irX", "ab" X "X" N "def"); data.setText("abc" N "def"); KEYS("Ax", "ab" X N "def"); data.setText("abc" N "de" X "f"); KEYS("i0x", "abc" N "x" X "def"); data.setText("abc" N "de" X "f"); KEYS("iggx", "x" X "abc" N "def"); data.setText("abc" N "def" N "ghi"); KEYS("ivjlolx", "a" X "f" N "ghi"); // to toggle between insert and replace mode data.setText("abc" N "def"); KEYS("XYZxyz", "XYZxy" X "z" N "def"); KEYS("" "0j" "XYZ", "XYZxyz" N "XYZ" X "f"); // dot command for insert data.setText("abc" N "def"); KEYS("ixXy", "xX" X "ybc" N "def"); KEYS("0j.", "xXybc" N "xX" X "yef"); data.setText("abc" N "def"); KEYS("xXY", "xXb" X "Y" N "def"); KEYS("0j.", "xXbY" N X "Yef"); data.setText("abc" N "def"); KEYS("xX", "xXbc" N X "def"); KEYS(".", "xXbc" N "x" X "Xef"); data.setText("abc" N "def"); KEYS("2oXYZ.", "abc" N "XYZ" N "XYZ" N "XYZ" N "XY" X "Z" N "def"); // delete in insert mode is part of dot command data.setText("abc" N "def"); KEYS("iXY", "XY" X "bc" N "def"); data.doKeys(""); KEYS("0j.", "XYbc" N "X" X "Yef"); data.setText("abc" N "def"); KEYS("2iXY", "XYX" X "Yc" N "def"); KEYS("0j.", "XYXYc" N "XYX" X "Yf"); data.setText("abc" N "def"); KEYS("iXY", "XY" X "bc" N "def"); data.doKeys(""); KEYS("0j.", "XYbc" N "X" X "Yef"); data.setText("ab" X "c" N "def"); KEYS("iXY", "aXY" X "c" N "def"); data.doKeys(""); KEYS("j.", "aXYc" N "dX" X "Yf"); // insert in visual mode data.setText(" a" X "bcde" N " fghij" N " klmno"); KEYS("v2l" "2Ixyz", "xyzxy" X "z abcde" N " fghij" N " klmno"); KEYS("u", X " abcde" N " fghij" N " klmno"); KEYS("", X "xyzxyz abcde" N " fghij" N " klmno"); KEYS("$.", "xyzxyz abcdxyzxy" X "ze" N " fghij" N " klmno"); // repeat only last insertion data.setText(" abc" N " def" N " ghi"); KEYS("2l" "2i" "XYZ" "j" "123", " XYZabc" N " def12" X "3" N " ghi"); KEYS("0l.", " XYZabc" N " 12" X "3 def123" N " ghi"); // insert nothing KEYS("i", " XYZabc" N " 1" X "23 def123" N " ghi"); KEYS(".", " XYZabc" N " " X "123 def123" N " ghi"); // repeat insert with special characters data.setText("ab" X "c" N "def"); KEYS("2idown>", "abc" N "def"); INTEGRITY(false); data.setText(" ab" X "c" N " def"); KEYS("2Iend>", " abc" N " def"); KEYS("u", " " X "abc" N " def"); KEYS(".", " abc" N " def"); } void FakeVimTester::test_vim_fFtT() { TestData data; setup(&data); data.setText("123()456" N "a(b(c)d)e"); KEYS("t(", "12" X "3()456" N "a(b(c)d)e"); KEYS("lt(", "123" X "()456" N "a(b(c)d)e"); KEYS("0j2t(", "123()456" N "a(" X "b(c)d)e"); KEYS("l2T(", "123()456" N "a(b" X "(c)d)e"); KEYS("l2T(", "123()456" N "a(" X "b(c)d)e"); KEYS("T(", "123()456" N "a(" X "b(c)d)e"); KEYS("ggf(", "123" X "()456" N "a(b(c)d)e"); KEYS("lf(", "123(" X ")456" N "a(b(c)d)e"); KEYS("0j2f(", "123()456" N "a(b" X "(c)d)e"); KEYS("2F(", "123()456" N "a(b" X "(c)d)e"); KEYS("l2F(", "123()456" N "a" X "(b(c)d)e"); KEYS("F(", "123()456" N "a" X "(b(c)d)e"); data.setText("abc def" N "ghi " X "jkl"); KEYS("vFgx", "abc def" N X "kl"); KEYS("u", "abc def" N X "ghi jkl"); KEYS("tk", "abc def" N "ghi " X "jkl"); KEYS("dTg", "abc def" N "g" X "jkl"); INTEGRITY(false); KEYS("u", "abc def" N "g" X "hi jkl"); KEYS("f .", "abc def" N "g" X " jkl"); KEYS("u", "abc def" N "g" X "hi jkl"); KEYS("rg$;", "abc def" N "gg" X "i jkl"); // repeat with ; data.setText("int main() { return (x > 0) ? 0 : (x - 1); }"); KEYS("f(", "int main" X "() { return (x > 0) ? 0 : (x - 1); }"); KEYS(";", "int main() { return " X "(x > 0) ? 0 : (x - 1); }"); KEYS(";", "int main() { return (x > 0) ? 0 : " X "(x - 1); }"); KEYS(";", "int main() { return (x > 0) ? 0 : " X "(x - 1); }"); KEYS("02;", "int main() { return " X "(x > 0) ? 0 : (x - 1); }"); KEYS("2;", "int main() { return " X "(x > 0) ? 0 : (x - 1); }"); KEYS("0t(", "int mai" X "n() { return (x > 0) ? 0 : (x - 1); }"); KEYS(";", "int main() { return" X " (x > 0) ? 0 : (x - 1); }"); KEYS("3;", "int main() { return" X " (x > 0) ? 0 : (x - 1); }"); KEYS("2;", "int main() { return (x > 0) ? 0 :" X " (x - 1); }"); } void FakeVimTester::test_vim_transform_numbers() { TestData data; setup(&data); data.setText("8"); KEYS("", X "9"); INTEGRITY(false); KEYS("", X "8"); INTEGRITY(false); KEYS("", X "9"); KEYS("", "1" X "0"); KEYS("", "1" X "1"); KEYS("5", "1" X "6"); INTEGRITY(false); KEYS("10", "2" X "6"); KEYS("h100", "12" X "6"); KEYS("100", "2" X "6"); INTEGRITY(false); KEYS("10", "1" X "6"); KEYS("5", "1" X "1"); KEYS("5", X "6"); KEYS("6", X "0"); KEYS("", "-" X "1"); KEYS("h10", "-1" X "1"); KEYS("h100", "-11" X "1"); KEYS("h889", "-100" X "0"); // increase nearest number data.setText("x-x+x: 1 2 3 -4 5"); KEYS("8", "x-x+x: " X "9 2 3 -4 5"); KEYS("l8", "x-x+x: 9 1" X "0 3 -4 5"); KEYS("l8", "x-x+x: 9 10 1" X "1 -4 5"); KEYS("l16", "x-x+x: 9 10 11 1" X "2 5"); KEYS("w18", "x-x+x: 9 10 11 12 -1" X "3"); KEYS("hh13", "x-x+x: 9 10 11 12 " X "0"); KEYS("B12", "x-x+x: 9 10 11 " X "0 0"); KEYS("B11", "x-x+x: 9 10 " X "0 0 0"); KEYS("B10", "x-x+x: 9 " X "0 0 0 0"); KEYS("B9", "x-x+x: " X "0 0 0 0 0"); KEYS("B9", "x-x+x: -" X "9 0 0 0 0"); data.setText("-" X "- 1 --"); KEYS("", "-- " X "0 --"); KEYS("u", "-" X "- 1 --"); KEYS("", "-" X "- 0 --"); KEYS("", "-- -" X "2 --"); KEYS("2", "-- " X "1 --"); KEYS("2", "-- " X "4 --"); KEYS(".", "-- " X "6 --"); KEYS("u", "-- " X "4 --"); KEYS("", "-- " X "6 --"); // hexadecimal and octal numbers data.setText("0x0 0x1 -1 07 08"); KEYS("3", "0x" X "3 0x1 -1 07 08"); KEYS("7", "0x" X "a 0x1 -1 07 08"); KEYS("9", "0x1" X "3 0x1 -1 07 08"); // if last letter in hexadecimal number is capital then all letters are capital KEYS("ifA", "0x1f" X "A3 0x1 -1 07 08"); KEYS("9", "0x1FA" X "C 0x1 -1 07 08"); KEYS("w1022", "0x1FAC 0x3f" X "f -1 07 08"); KEYS("w.", "0x1FAC 0x3ff 102" X "1 07 08"); // octal number KEYS("w.", "0x1FAC 0x3ff 1021 0200" X "5 08"); // non-octal number with leading zeroes KEYS("w.", "0x1FAC 0x3ff 1021 02005 103" X "0"); // preserve width of hexadecimal and octal numbers data.setText("0x0001"); KEYS("", "0x000" X "2"); KEYS("10", "0x000" X "c"); KEYS(".", "0x001" X "6"); KEYS("999", "0x03f" X "d"); KEYS("99999", "0x18a9" X "c"); data.setText("0001"); KEYS("", "000" X "2"); KEYS("10", "001" X "4"); KEYS("999", "0176" X "3"); data.setText("0x0100"); KEYS("", "0x00f" X "f"); data.setText("0100"); KEYS("", "007" X "7"); } void FakeVimTester::test_vim_delete() { TestData data; setup(&data); data.setText("123" N "456"); KEYS("x", "23" N "456"); INTEGRITY(false); KEYS("dd", "456"); INTEGRITY(false); KEYS("2x", "6"); INTEGRITY(false); KEYS("dd", ""); INTEGRITY(false); // delete character / word / line in insert mode data.setText("123" N "456 789"); KEYS("A", "12" N "456 789"); KEYS("", "" N "456 789"); KEYS("jA", "" N "456 "); data.setText("void main()"); KEYS("dt(", "()"); INTEGRITY(false); data.setText("void main()"); KEYS("df(", ")"); INTEGRITY(false); data.setText("void " X "main()"); KEYS("D", "void "); INTEGRITY(false); KEYS("ggd$", ""); data.setText("abc def ghi"); KEYS("2dw", X "ghi"); INTEGRITY(false); data.setText("abc def ghi"); KEYS("d2w", X "ghi"); INTEGRITY(false); data.setText("abc " N " def" N " ghi" N "jkl"); KEYS("3dw", X "jkl"); data.setText("abc " N " def" N " ghi" N "jkl"); KEYS("d3w", X "jkl"); // delete empty line data.setText("a" N X "" N " b"); KEYS("dd", "a" N " " X "b"); // delete on an empty line data.setText("a" N X "" N " b"); KEYS("d$", "a" N X "" N " b"); INTEGRITY(false); // delete in empty document data.setText(""); KEYS("dd", X); // delete to start of line data.setText(" abc" N " de" X "f" N " ghi"); KEYS("d0", " abc" N X "f" N " ghi"); INTEGRITY(false); data.setText(" abc" N " de" X "f" N " ghi"); KEYS("d^", " abc" N " " X "f" N " ghi"); INTEGRITY(false); // delete to mark data.setText("abc " X "def ghi"); KEYS("ma" "3l" "d`a", "abc " X " ghi"); KEYS("u" "gg" "d`a", X "def ghi"); // delete lines data.setText(" abc" N " de" X "f" N " ghi" N " jkl"); KEYS("dj", " abc" N " " X "jkl"); INTEGRITY(false); data.setText(" abc" N " def" N " gh" X "i" N " jkl"); KEYS("dk", " abc" N " " X "jkl"); INTEGRITY(false); // delete with copy to a register data.setText("abc" N "def"); KEYS("\"xd$", X "" N "def"); KEYS("\"xp", "ab" X "c" N "def"); KEYS("2\"xp", "abcabcab" X "c" N "def"); /* QTCREATORBUG-9289 */ data.setText("abc" N "def"); KEYS("$" "dw", "a" X "b" N "def"); KEYS("dw", X "a" N "def"); KEYS("dw", X "" N "def"); KEYS("dw", X "def"); data.setText("abc" N "def ghi"); KEYS("2dw", X "ghi"); data.setText("abc" N X "" N "def"); KEYS("dw", "abc" N X "def"); KEYS("k$" "dw", "a" X "b" N "def"); KEYS("j$h" "dw", "ab" N X "d"); data.setText("abc" N "def"); KEYS("2lvx", "a" X "b" N "def"); KEYS("vlx", "a" X "def"); data.setText("abc" N "def"); KEYS("2lvox", "a" X "b" N "def"); KEYS("vlox", "a" X "def"); // bracket movement command data.setText( "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("d]]", X "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("u", X "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); // When ]] is used after an operator, then also stops below a '}' in the first column. KEYS("jd]]", "void a()" N X "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); KEYS("u", "void a()" N X "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N ""); // do nothing on failed movement KEYS("Gd5[[", "void a()" N "{" N "}" N "" N "int b()" N "{ return 0; }" N "" N "int c()" N "{ return 0;" N "}" N X ""); } void FakeVimTester::test_vim_delete_inner_word() { TestData data; setup(&data); data.setText("abc def ghi"); KEYS("wlldiw", "abc " X " ghi"); data.setText("abc def ghi jkl"); KEYS("3diw", X " ghi jkl"); INTEGRITY(false); data.setText("abc " X " def"); KEYS("diw", "abc" X "def"); INTEGRITY(false); KEYS("diw", ""); data.setText("abc " N " def"); KEYS("3diw", X "def"); data.setText("abc " N " def" N " ghi"); KEYS("4diw", " " X "ghi"); data.setText("ab" X "c " N " def" N " ghi"); KEYS("4diw", " " X "ghi"); data.setText("a b" X "c " N " def" N " ghi"); KEYS("4diw", "a" X " " N " ghi"); data.setText("abc def" N "ghi"); KEYS("2diw", X "def" N "ghi"); data.setText("abc def" N "ghi"); KEYS("3diw", X "" N "ghi"); data.setText("x" N X "" N "" N " "); KEYS("diw", "x" N X "" N "" N " "); data.setText("x" N X "" N "" N " "); KEYS("2diw", "x" N " " X " "); data.setText("x" N X "" N "" N "" N "" N " "); KEYS("3diw", "x" N " " X " "); data.setText("x" N X "" N "" N "" N "" N "" N " "); KEYS("3diw", "x" N X "" N " "); data.setText("x" N X "" N "" N "" N "" N "" N "" N " "); KEYS("4diw", "x" N X "" N " "); // delete single-character-word data.setText("a " X "b c"); KEYS("diw", "a " X " c"); } void FakeVimTester::test_vim_delete_a_word() { TestData data; setup(&data); data.setText("abc def ghi"); KEYS("wlldaw", "abc " X "ghi"); data.setText("abc def ghi jkl"); KEYS("wll2daw", "abc " X "jkl"); data.setText("abc" X " def ghi"); KEYS("daw", "abc" X " ghi"); INTEGRITY(false); KEYS("daw", "ab" X "c"); INTEGRITY(false); KEYS("daw", ""); data.setText(X " ghi jkl"); KEYS("daw", X " jkl"); KEYS("ldaw", X " "); data.setText("abc def ghi jkl"); KEYS("3daw", X "jkl"); INTEGRITY(false); // remove trailing spaces data.setText("abc " N " def" N " ghi" N "jkl"); KEYS("3daw", X "jkl"); data.setText("abc " N " def" N " ghi" N "jkl"); KEYS("3daw", X "jkl"); data.setText("abc def" N "ghi"); KEYS("2daw", X "" N "ghi"); data.setText("x" N X "" N "" N " "); KEYS("daw", "x" N " " X " "); data.setText("x" N X "" N "" N "" N "" N " "); KEYS("2daw", "x" N " " X " "); data.setText("x" N X "" N "" N "" N "" N "" N " "); KEYS("2daw", "x" N X "" N " "); data.setText("x" N X "" N "" N "" N "" N "" N "" N " "); KEYS("3daw", "x" N " " X " "); // delete single-character-word data.setText("a," X "b,c"); KEYS("daw", "a," X ",c"); // delete a word with visual selection data.setText(X "a" N "" N "b"); KEYS("vawd", X "" N "" N "b"); data.setText(X "a" N "" N "b"); KEYS("Vawd", X "" N "" N "b"); data.setText("abc def g" X "hi"); KEYS("vawd", "abc de" X "f"); KEYS("u", "abc def" X " ghi"); // backward visual selection data.setText("abc def g" X "hi"); KEYS("vhawd", "abc " X "i"); data.setText("abc def gh" X "i"); KEYS("vhawd", "abc de" X "f"); data.setText("abc def gh" X "i"); KEYS("vh2awd", "ab" X "c"); } void FakeVimTester::test_vim_change_a_word() { TestData data; setup(&data); data.setText("abc " X "def ghi"); KEYS("caw#", "abc #" X "ghi"); INTEGRITY(false); data.setText("abc d" X "ef ghi"); KEYS("caw#", "abc #" X "ghi"); data.setText("abc de" X "f ghi"); KEYS("caw#", "abc #" X "ghi"); data.setText("abc de" X "f ghi jkl"); KEYS("2caw#", "abc #" X "jkl"); INTEGRITY(false); data.setText("abc" X " def ghi jkl"); KEYS("2caw#", "abc#" X " jkl"); data.setText("abc " X " def ghi jkl"); KEYS("2caw#", "abc#" X " jkl"); data.setText(" abc " N " def" N " ghi" N " jkl"); KEYS("3caw#", "#" X N " jkl"); // change single-character-word data.setText("a " X "b c"); KEYS("ciwX", "a " X "X c"); KEYS("cawZ", "a " X "Zc"); } void FakeVimTester::test_vim_change_replace() { TestData data; setup(&data); // preserve lines in replace mode data.setText("abc" N "def"); KEYS("llvjhrX", "ab" X "X" N "XXf"); // change empty line data.setText("a" N X "" N " b"); KEYS("ccABC", "a" N "ABC" X N " b"); INTEGRITY(false); // change on empty line data.setText("a" N X "" N " b"); KEYS("c$ABC", "a" N "AB" X "C" N " b"); INTEGRITY(false); KEYS("u", "a" N X "" N " b"); KEYS("rA", "a" N X "" N " b"); // change in empty document data.setText(""); KEYS("ccABC", "ABC" X); data.doKeys(""); KEYS("u", ""); KEYS("SABC", "ABC" X); data.doKeys(""); KEYS("u", ""); KEYS("sABC", "ABC" X); data.doKeys(""); KEYS("u", ""); KEYS("rA", "" X); // indentation with change data.doCommand("set expandtab"); data.doCommand("set shiftwidth=2"); data.setText("int main()" N "{" N " " X " return 0;" N "}" N ""); KEYS("cc" "int i = 0;", "int main()" N "{" N " int i = 0;" X N "}" N ""); INTEGRITY(false); KEYS("uS" "int i = 0;" N "int j = 1;", "int main()" N "{" N " int i = 0;" N " int j = 1;" X N "}" N ""); // change to start of line data.setText(" abc" N " de" X "f" N " ghi"); KEYS("c0123", " abc" N "12" X "3f" N " ghi"); INTEGRITY(false); data.setText(" abc" N " de" X "f" N " ghi"); KEYS("c^123", " abc" N " 12" X "3f" N " ghi"); INTEGRITY(false); // change to mark data.setText("abc " X "def ghi"); KEYS("ma" "3l" "c`a123", "abc 12" X "3 ghi"); KEYS("u" "gg" "c`a123", "12" X "3def ghi"); // change lines data.setText(" abc" N " de" X "f" N " ghi" N " jkl"); KEYS("cj123", " abc" N " 12" X "3" N " jkl"); INTEGRITY(false); data.setText(" abc" N " def" N " gh" X "i" N " jkl"); KEYS("ck123", " abc" N " 12" X "3" N " jkl"); INTEGRITY(false); data.setText("abc" N X "def"); KEYS("sXYZ", "abc" N "XYZ" X "ef"); INTEGRITY(false); data.setText("abc" N X "def"); KEYS("2sXYZ", "abc" N "XY" X "Zf"); INTEGRITY(false); data.setText("abc" N X "def"); KEYS("6sXYZ", "abc" N "XY" X "Z"); INTEGRITY(false); // insert in visual block mode data.setText( "abc" N "d" X "ef" N "" N "jkl" N "mno" N ); KEYS("2j2sXYZ", "abc" N "dXY" X "Zf" N "" N "jXYZl" N "mno" N ); INTEGRITY(false); data.setText( "abc" N "de" X "f" N "" N "jkl" N "mno" N ); KEYS("2jh2sXYZ", "abc" N "dXY" X "Z" N "" N "jXYZ" N "mno" N ); INTEGRITY(false); // change with copy to a register data.setText("abc" N "def"); KEYS("\"xCxyz", "xy" X "z" N "def"); KEYS("\"xp", "xyzab" X "c" N "def"); KEYS("2\"xp", "xyzabcabcab" X "c" N "def"); } void FakeVimTester::test_vim_block_selection() { TestData data; setup(&data); data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("f(", "int main" X "(int /* (unused) */, char *argv[]);"); KEYS("da(", "int main" X ";"); 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(false); data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("2f)", "int main(int /* (unused) */, char *argv[]" X ");"); KEYS("da(", "int main" X ";"); data.setText("int main(int /* (unused) */, char *argv[]);"); KEYS("2f)", "int main(int /* (unused) */, char *argv[]" X ");"); KEYS("di(", "int main(" X ");"); data.setText("{ { { } } }"); KEYS("2f{l", "{ { {" X " } } }"); KEYS("da{", "{ { " X " } }"); KEYS("da{", "{ " X " }"); INTEGRITY(false); data.setText("{ { { } } }"); KEYS("2f{l", "{ { {" X " } } }"); KEYS("2da{", "{ " X " }"); INTEGRITY(false); data.setText("{" N " { " N " } " N "}"); KEYS("di{", "{" N "}"); data.setText("(" X "())"); KEYS("di(", "((" X "))"); data.setText("\"\""); KEYS("di\"", "\"" X "\""); // visual selection data.setText("(abc()" X "(def))"); KEYS("vi(d", "(abc()(" X "))"); KEYS("u", "(abc()(" X "def))"); KEYS("", "(abc()(" X "))"); KEYS("va(d", "(abc()" X ")"); KEYS("u", "(abc()" X "())"); KEYS("", "(abc()" X ")"); data.setText("\"abc" X "\"\"def\""); KEYS("vi\"d", "\"" X "\"\"def\""); /* QTCREATORBUG-9190 */ data.setText(" abcd" N " efgh" N " ijkl" N " mnop" N ""); data.doKeys("2lj" "" "jl"); data.doKeys("x"); COMMAND("", " abcd" N " e" X "h" N " il" N " mnop" N ""); COMMAND(":undo", " abcd" N " e" X "fgh" N " ijkl" N " mnop" N ""); data.doKeys(""); data.doKeys("j"); data.doKeys("l"); data.doKeys("x"); COMMAND("", " abcd" N " e" X "h" N " il" N " mnop" N ""); COMMAND(":undo", " abcd" N " e" X "fgh" N " ijkl" N " mnop" N ""); data.doKeys("gv"); data.doKeys("j"); data.doKeys("h"); data.doKeys("x"); COMMAND("", " abcd" N " e" X "gh" N " ikl" N " mop" N ""); COMMAND(":undo", " abcd" N " e" X "fgh" N " ijkl" N " mnop" N ""); data.doCommand("set passkeys"); data.doKeys("gv"); data.doKeys("k"); data.doKeys("l"); data.doKeys("r-"); COMMAND("", " abcd" N " e" X "--h" N " i--l" N " mnop" N ""); COMMAND(":undo", " abcd" N " e" X "fgh" N " ijkl" N " mnop" N ""); data.doKeys("gv"); data.doKeys("j"); data.doKeys("o"); data.doKeys("k"); data.doKeys("h"); data.doKeys("r9"); COMMAND("", " " X "999d" N " 999h" N " 999l" N " 999p" N ""); COMMAND(":undo", " " X "abcd" N " efgh" N " ijkl" N " mnop" N ""); data.doCommand("set nopasskeys"); // repeat change inner data.setText("(abc)" N "def" N "(ghi)"); KEYS("ci(xyz", "(xy" X "z)" N "def" N "(ghi)"); KEYS("j.", "(xyz)" N "de" X "f" N "(ghi)"); KEYS("j.", "(xyz)" N "def" N "(xy" X "z)"); // quoted string data.setText("\"abc" X "\"\"def\""); KEYS("di\"", "\"" X "\"\"def\""); KEYS("u", "\"" X "abc\"\"def\""); KEYS("", "\"" X "\"\"def\""); /* QTCREATORBUG-12128 */ data.setText("abc \"def\" ghi \"jkl\" mno"); KEYS("di\"", "abc \"" X "\" ghi \"jkl\" mno"); KEYS("u", "abc \"" X "def\" ghi \"jkl\" mno"); KEYS("3l" "di\"", "abc \"" X "\" ghi \"jkl\" mno"); KEYS("di\"", "abc \"" X "\" ghi \"jkl\" mno"); KEYS("tj" "di\"", "abc \"\" ghi \"" X "\" mno"); KEYS("l" "di\"", "abc \"\" ghi \"\"" X " mno"); NOT_IMPLEMENTED // quoted string with escaped character data.setText("\"abc\""); KEYS("di\"", "\"abc\"\"" X "\""); KEYS("u", "\"abc\"\"" X "def\""); } void FakeVimTester::test_vim_block_selection_insert() { TestData data; setup(&data); // insert in visual block mode data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr"); KEYS("2j" "2I" "XYZ", "abc" N "d" X "XYZXYZef" N "jXYZXYZkl" N "mXYZXYZno" N "pqr"); INTEGRITY(false); data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr"); KEYS("2j" "2A" "XYZ", "abc" N "d" X "eXYZXYZf" N "jkXYZXYZl" N "mnXYZXYZo" N "pqr"); INTEGRITY(false); data.setText("abc" N "de" X "f" N "" N "jkl" N "mno"); KEYS("2jh" "2I" "XYZ", "abc" N "d" X "XYZXYZef" N "" N "jXYZXYZkl" N "mno"); INTEGRITY(false); /* QTCREATORBUG-11378 */ data.setText( " abcd" N " efgh" N " ijkl" N " mnop" N ""); KEYS("3j$AXYZ", X " abcdXYZ" N " efghXYZ" N " ijklXYZ" N " mnopXYZ" N ""); data.setText( " abcd" N " ef" N " ghijk" N " lm" N ""); KEYS("3j$AXYZ", X " abcdXYZ" N " efXYZ" N " ghijkXYZ" N " lmXYZ" N ""); data.setText( "a" N "" N "b" N "" N ); KEYS("j$jAXYZ", "a" N "|XYZ" N "bXYZ" N "" N ); data.setText( "abc" N "" N "def" N ); KEYS("l2jAXYZ", "a" X "bXYZc" N " XYZ" N "deXYZf" N ); } void FakeVimTester::test_vim_delete_inner_paragraph() { TestData data; setup(&data); data.setText( "abc" N "def" N "" N "" N "ghi" N "" N "jkl" N ); KEYS("dip", X "" N "" N "ghi" N "" N "jkl" N ); KEYS("dip", X "ghi" N "" N "jkl" N ); KEYS("2dip", X "jkl" N ); } void FakeVimTester::test_vim_delete_a_paragraph() { TestData data; setup(&data); data.setText( "abc" N "def" N "" N "" N "ghi" N "" N "jkl" N ); KEYS("dap", X "ghi" N "" N "jkl" N ); KEYS("dap", X "jkl" N ); KEYS("u", X "ghi" N "" N "jkl" N ); data.setText( "abc" N "" N "" N "def" ); KEYS("Gdap", X "abc" ); } void FakeVimTester::test_vim_change_inner_paragraph() { TestData data; setup(&data); data.setText( "abc" N "def" N "" N "" N "ghi" N "" N "jkl" N ); KEYS("cipXXX", "XX" X "X" N "" N "" N "ghi" N "" N "jkl" N ); KEYS("3j" "cipYYY", "XXX" N "" N "" N "YY" X "Y" N "" N "jkl" N ); } void FakeVimTester::test_vim_change_a_paragraph() { TestData data; setup(&data); data.setText( "abc" N "def" N "" N "" N "ghi" N "" N "jkl" N ); KEYS("4j" "capXXX", "abc" N "def" N "" N "" N "XX" X "X" N "jkl" N ); KEYS("gg" "capYYY", "YY" X "Y" N "XXX" N "jkl" N ); data.setText( "abc" N "" N "" N "def" ); KEYS("GcapXXX", "abc" N "XX" X "X" ); } void FakeVimTester::test_vim_select_inner_paragraph() { TestData data; setup(&data); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("vip" "r-", "" N X "---" N "---" N "" N "ghi" ); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("vip" ":s/^/-", "" N "-abc" N X "-def" N "" N "ghi" ); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("v2ip" ":s/^/-", "" N "-abc" N "-def" N X "-" N "ghi" ); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("Vj" "ip" ":s/^/-", "" N "-abc" N "-def" N X "-" N "ghi" ); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("vj" "ip" ":s/^/-", "" N "-abc" N "-def" N "-" N "ghi" ); data.setText( "" N X "abc" N "def" N "ghi" N "" N "jkl" ); KEYS("vj" "ip" ":s/^/-", "" N "-abc" N "-def" N "-ghi" N "" N "jkl" ); data.setText( "" N X "abc" N "def" N "" N "ghi" ); KEYS("vip" "r-", "" N X "---" N "---" N "" N "ghi" ); data.setText( "abc" N "" N "def" ); KEYS("G" "vip" "r-", "abc" N "" N "---" ); data.setText( "" N "" N "ghi" ); KEYS("vip" ":s/^/-", "-" N "-" N "ghi" ); data.setText( "" N "ghi" ); KEYS("vip" "ip" ":s/^/-", "-" N X "-ghi" ); data.setText( "abc" N "" N "" ); KEYS("j" "vip" ":s/^/-", "abc" N "-" N "-" ); // Don't move anchor if it's on different line. data.setText( "" N "abc" N X "def" N "ghi" N "" N "jkl" ); KEYS("vj" "ip" ":s/^/-", "" N "abc" N "-def" N "-ghi" N X "-" N "jkl" ); // Don't change selection mode if anchor is on different line. data.setText( "" N "abc" N X "def" N "ghi" N "" N "jkl" ); KEYS("vj" "2ip" "r-", "" N "abc" N X "---" N "---" N "" N "-kl" ); KEYS("gv" ":s/^/X", "" N "abc" N "X---" N "X---" N "X" N X "X-kl" ); data.setText( "" N "abc" N X "def" N "ghi" N "" N "jkl" ); KEYS("j" "2ip" "r-", "" N "abc" N X "-ef" N "-hi" N "" N "-kl" ); KEYS("gv" "IX", "" N "abc" N "X-ef" N "X-hi" N "X" N "X-kl" ); } void FakeVimTester::test_vim_select_a_paragraph() { TestData data; setup(&data); data.setText( "abc" N "def" N "" N "ghi" ); KEYS("vap" ":s/^/-", "-abc" N "-def" N "-" N "ghi" ); data.setText( "" N "abc" N "def" N "" N "ghi" ); KEYS("vap" ":s/^/-", "-" N "-abc" N "-def" N "" N "ghi" ); data.setText( "abc" N "def" N "" ); KEYS("j" "vap" ":s/^/-", "-abc" N "-def" N "-" ); data.setText( "" N "abc" N "def" ); KEYS("j" "vap" ":s/^/-", "-" N "-abc" N "-def" ); } void FakeVimTester::test_vim_repeat() { TestData data; setup(&data); // delete line data.setText("abc" N "def" N "ghi"); KEYS("dd", X "def" N "ghi"); KEYS(".", X "ghi"); INTEGRITY(false); // delete to next word data.setText("abc def ghi jkl"); KEYS("dw", X "def ghi jkl"); KEYS("w.", "def " X "jkl"); KEYS("gg.", X "jkl"); // change in word data.setText("WORD text"); KEYS("ciwWORD", "WOR" X "D text"); KEYS("w.", "WORD WOR" X "D"); /* QTCREATORBUG-7248 */ data.setText("test tex" X "t"); KEYS("vbcWORD", "test " "WOR" X "D"); KEYS("bb.", "WOR" X "D WORD"); // delete selected range data.setText("abc def ghi jkl"); KEYS("viwd", X " def ghi jkl"); KEYS(".", X "f ghi jkl"); KEYS(".", X "hi jkl"); // delete two lines data.setText("abc" N "def" N "ghi" N "jkl" N "mno"); KEYS("Vjx", X "ghi" N "jkl" N "mno"); KEYS(".", X "mno"); // delete three lines data.setText("abc" N "def" N "ghi" N "jkl" N "mno" N "pqr" N "stu"); KEYS("d2j", X "jkl" N "mno" N "pqr" N "stu"); KEYS(".", X "stu"); // replace block selection data.setText("abcd" N "d" X "efg" N "ghij" N "jklm"); KEYS("jlrX", "abcd" N "d" X "XXg" N "gXXj" N "jklm"); KEYS("gg.", "XXcd" N "XXXg" N "gXXj" N "jklm"); } void FakeVimTester::test_vim_search() { TestData data; setup(&data); data.setText("abc" N "def" N "ghi"); KEYS("/ghi", "abc" N "def" N X "ghi"); KEYS("gg/\\w\\{3}", "abc" N X "def" N "ghi"); KEYS("n", "abc" N "def" N X "ghi"); KEYS("N", "abc" N X "def" N "ghi"); KEYS("N", X "abc" N "def" N "ghi"); // return to search-start position on escape or not found KEYS("/def", X "abc" N "def" N "ghi"); KEYS("/x", X "abc" N "def" N "ghi"); KEYS("/x", X "abc" N "def" N "ghi"); KEYS("/x", X "abc" N "def" N "ghi"); KEYS("/ghX", X "abc" N "def" N "ghi"); KEYS("?def", X "abc" N "def" N "ghi"); KEYS("?x", X "abc" N "def" N "ghi"); KEYS("?x", X "abc" N "def" N "ghi"); KEYS("?x", X "abc" N "def" N "ghi"); // set wrapscan (search wraps at end of file) data.doCommand("set ws"); // search [count] times data.setText("abc" N "def" N "ghi"); KEYS("/\\w\\{3}", "abc" N X "def" N "ghi"); KEYS("2n", X "abc" N "def" N "ghi"); KEYS("2N", "abc" N X "def" N "ghi"); KEYS("2/\\w\\{3}", X "abc" N "def" N "ghi"); data.setText("abc" N "def" N "abc" N "ghi abc jkl"); KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl"); KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); KEYS("2*", "abc" N "def" N X "abc" N "ghi abc jkl"); KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); KEYS("#", "abc" N "def" N "abc" N "ghi " X "abc jkl"); KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl"); KEYS("2#", "abc" N "def" N "abc" N "ghi " X "abc jkl"); data.doCommand("set nows"); data.setText("abc" N "def" N "abc" N "ghi abc jkl"); KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl"); KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl"); KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); data.setText("abc" N "def" N "ab" X "c" N "ghi abc jkl"); KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); // search with g* and g# data.doCommand("set nows"); data.setText("bc" N "abc" N "abcd" N "bc" N "b"); KEYS("g*", "bc" N "a" X "bc" N "abcd" N "bc" N "b"); KEYS("n", "bc" N "abc" N "a" X "bcd" N "bc" N "b"); KEYS("n", "bc" N "abc" N "abcd" N X "bc" N "b"); KEYS("n", "bc" N "abc" N "abcd" N X "bc" N "b"); KEYS("g#", "bc" N "abc" N "a" X "bcd" N "bc" N "b"); KEYS("n", "bc" N "a" X "bc" N "abcd" N "bc" N "b"); KEYS("N", "bc" N "abc" N "a" X "bcd" N "bc" N "b"); KEYS("3n", "bc" N "abc" N "a" X "bcd" N "bc" N "b"); KEYS("2n", X "bc" N "abc" N "abcd" N "bc" N "b"); /* QTCREATORBUG-7251 */ data.setText("abc abc abc abc"); KEYS("$?abc", "abc abc abc " X "abc"); KEYS("2?abc", "abc " X "abc abc abc"); KEYS("n", X "abc abc abc abc"); KEYS("N", "abc " X "abc abc abc"); // search is greedy data.doCommand("set ws"); data.setText("abc" N "def" N "abc" N "ghi abc jkl"); KEYS("/[a-z]*", "abc" N X "def" N "abc" N "ghi abc jkl"); KEYS("2n", "abc" N "def" N "abc" N X "ghi abc jkl"); KEYS("3n", "abc" N "def" N "abc" N "ghi abc" X " jkl"); KEYS("3N", "abc" N "def" N "abc" N X "ghi abc jkl"); KEYS("2N", "abc" N X "def" N "abc" N "ghi abc jkl"); data.setText("a.b.c" N "" N "d.e.f"); KEYS("/[a-z]*", "a" X ".b.c" N "" N "d.e.f"); KEYS("n", "a." X "b.c" N "" N "d.e.f"); KEYS("2n", "a.b." X "c" N "" N "d.e.f"); KEYS("n", "a.b.c" N X "" N "d.e.f"); KEYS("n", "a.b.c" N "" N X "d.e.f"); KEYS("2N", "a.b." X "c" N "" N "d.e.f"); KEYS("2n", "a.b.c" N "" N X "d.e.f"); // find same stuff forward and backward, // i.e. 'c' forward but not 'a' backward data.setText("abc" N "def" N "ghi"); KEYS("/\\w\\{2}", "abc" N X "def" N "ghi"); KEYS("n", "abc" N "def" N X "ghi"); KEYS("N", "abc" N X "def" N "ghi"); KEYS("N", X "abc" N "def" N "ghi"); KEYS("2n2N", X "abc" N "def" N "ghi"); // delete to match data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("2l" "d/ghi", "ab" X "ghi abc jkl" N "xyz"); data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("l" "d2/abc", "a" X "abc jkl" N "xyz"); data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("d/abc", X "abc" N "ghi abc jkl" N "xyz"); KEYS(".", "abc jkl" N "xyz"); data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("/abc" "l" "dn", "abc" N "def" N "a" X "abc jkl" N "xyz"); data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("2/abc" "h" "dN", "abc" N "def" N X " abc jkl" N "xyz"); KEYS("c/xxx" "h" "dN", "abc" N "def" N X " abc jkl" N "xyz"); data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("l" "v2/abc" "x", "abc jkl" N "xyz"); // don't leave visual mode after search failed or is cancelled data.setText("abc" N "def" N "abc" N "ghi abc jkl" N "xyz"); KEYS("vj" "/abc" "x", X "ef" N "abc" N "ghi abc jkl" N "xyz"); KEYS("vj" "/xxx" "x", X "bc" N "ghi abc jkl" N "xyz"); // insert word under cursor (C-R C-W) data.setText("abc def ghi def."); KEYS("fe/", "abc def ghi " X "def."); // insert register (C-R{register}) data.setText("abc def ghi def."); KEYS("feyiw/0", "abc def ghi " X "def."); // insert non-existing register data.setText("abc def ghi def."); KEYS("feyiw/adef", "abc def ghi " X "def."); // abort C-R via Esc data.doCommand("set noincsearch"); data.setText("abc def ghi def."); KEYS("fe/def", "abc def ghi " X "def."); } void FakeVimTester::test_vim_indent() { TestData data; setup(&data); data.doCommand("set expandtab"); data.doCommand("set shiftwidth=4"); data.setText( "abc" N "def" N "ghi" N "jkl" N "mno"); KEYS("j3>>", "abc" N " " X "def" N " ghi" N " jkl" N "mno"); KEYS("j2>>", "abc" N " def" N " " X "ghi" N " jkl" N "mno"); KEYS("2<<", "abc" N " def" N " " X "ghi" N " jkl" N "mno"); INTEGRITY(false); KEYS("k3<<", "abc" N X "def" N "ghi" N "jkl" N "mno"); data.setText( "abc" N "def" N "ghi" N "jkl" N "mno"); KEYS("jj>j", "abc" N "def" N " " X "ghi" N " jkl" N "mno"); data.setText("abc"); KEYS(">>", " " X "abc"); INTEGRITY(false); data.setText("abc"); data.doCommand("set shiftwidth=2"); KEYS(">>", " " X "abc"); data.setText("abc"); data.doCommand("set noexpandtab"); data.doCommand("set tabstop=2"); data.doCommand("set shiftwidth=7"); // shiftwidth = TABS * tabstop + SPACES // 7 = 3 * 2 + 1 KEYS(">>", "\t\t\t abc"); data.doCommand("set tabstop=3"); data.doCommand("set shiftwidth=7"); data.setText("abc"); KEYS(">>", "\t\t abc"); INTEGRITY(false); // indent inner block data.doCommand("set expandtab"); data.doCommand("set shiftwidth=2"); data.setText("int main()" N "{" N "int i = 0;" N X "return i;" N "}" N ""); KEYS(">i{", "int main()" N "{" N " " X "int i = 0;" N " return i;" N "}" N ""); KEYS(">i}", "int main()" N "{" N " " X "int i = 0;" N " return i;" N "}" N ""); KEYS("i{", "int main() {" N " " X "return i;" N "}" N ""); KEYS("l>i}", "int main() {" N " " X "return i;" N "}" N ""); KEYS("lG" "`x", "a" X "bc" N "df" N "ghi"); KEYS("uG" "`x", "abc" N "d" X "ef" N "ghi"); KEYS("G" "`x", "a" X "bc" N "df" N "ghi"); } void FakeVimTester::test_vim_jumps() { TestData data; setup(&data); // last position data.setText(" abc" N " def" N " ghi"); KEYS("G", " abc" N " def" N " " X "ghi"); KEYS("`'", X " abc" N " def" N " ghi"); KEYS("`'", " abc" N " def" N " " X "ghi"); KEYS("''", " " X "abc" N " def" N " ghi"); KEYS("", " abc" N " def" N " " X "ghi"); KEYS("", " " X "abc" N " def" N " ghi"); KEYS("lgUlhj", " aBc" N " " X "def" N " ghi"); KEYS("`.", " a" X "Bc" N " def" N " ghi"); KEYS("`'", " aBc" N " " X "def" N " ghi"); KEYS("'.", " " X "aBc" N " def" N " ghi"); KEYS("G", " aBc" N " def" N " " X "ghi"); KEYS("u", " a" X "bc" N " def" N " ghi"); KEYS("`'", " abc" N " def" N " " X "ghi"); KEYS("", " a" X "Bc" N " def" N " ghi"); KEYS("jd$", " aBc" N " " X "d" N " ghi"); KEYS("''", " aBc" N " d" N " " X "ghi"); KEYS("`'", " aBc" N " " X "d" N " ghi"); KEYS("u", " aBc" N " d" X "ef" N " ghi"); KEYS("''", " aBc" N " " X "def" N " ghi"); KEYS("`'", " aBc" N " d" X "ef" N " ghi"); // record external position changes data.setText("abc" N "def" N "g" X "hi"); data.jump("abc" N "de" X "f" N "ghi"); KEYS("", "abc" N "def" N "g" X "hi"); KEYS("", "abc" N "de" X "f" N "ghi"); data.jump("ab" X "c" N "def" N "ghi"); KEYS("", "abc" N "de" X "f" N "ghi"); KEYS("", "abc" N "def" N "g" X "hi"); } void FakeVimTester::test_vim_current_column() { // Check if column is correct after command and vertical cursor movement. TestData data; setup(&data); // always at end of line after data.setText(" abc" N " def 123" N "" N " ghi"); KEYS("", " abc" N " def 12" X "3" N "" N " ghi"); KEYS("", " abc" N " def 123" N "" N " gh" X "i"); KEYS("", " abc" N " def 123" N X "" N " ghi"); KEYS("", " abc" N " def 12" X "3" N "" N " ghi"); // ... in insert KEYS("i", " abc" X N " def 123" N "" N " ghi"); data.doKeys(""); KEYS("i", " abc" N " def 123" X N "" N " ghi"); // vertical movement doesn't reset column data.setText(" abc" N " def 1" X "23" N "" N " ghi"); KEYS("", " ab" X "c" N " def 123" N "" N " ghi"); KEYS("", " abc" N " def 1" X "23" N "" N " ghi"); KEYS("", " abc" N " def 123" N "" N " gh" X "i"); KEYS("", " abc" N " def 1" X "23" N "" N " ghi"); KEYS("^jj", " abc" N " def 123" N "" N " " X "ghi"); KEYS("kk", " abc" N " " X "def 123" N "" N " ghi"); // yiw, yaw data.setText(" abc" N " def" N " ghi"); KEYS("e", " abc" N " de" X "f" N " ghi"); KEYS("b", " abc" N " def" N " " X "ghi"); KEYS("ll", " abc" N " de" X "f" N " ghi"); KEYS("yiw", " abc" N " " X "def" N " ghi"); KEYS("llyaw", " " X "abc" N " def" N " ghi"); // insert data.setText(" abc" N " def" N " ghi"); KEYS("lljj", " abc" N " def" N " " X "ghi"); KEYS("i123", " abc" N " def" X N " 123ghi"); data.doKeys(""); KEYS("a456", " abc" N " def456" X N " 123ghi"); data.setText(" abc" N X " def 123" N "" N " ghi"); KEYS("A", " abc" N " def 123" N "" N " ghi" X); data.doKeys(""); KEYS("A", " abc" N " def" X " 123" N "" N " ghi"); data.doKeys(""); KEYS("A", " abc" N " def 123" X N "" N " ghi"); data.setText(" abc" N X " def 123" N "" N " ghi"); KEYS("I", " abc" N " def 123" N "" N " " X "ghi"); // change data.setText(" abc" N " d" X "ef" N " ghi"); KEYS("cc", " " X "abc" N " " N " ghi"); data.setText(" abc" N " d" X "ef" N " ghi"); KEYS("ccx", " xabc" N " " N " g" X "hi"); } void FakeVimTester::test_vim_copy_paste() { TestData data; setup(&data); data.setText("123" N "456"); KEYS("llyy2P", X "123" N "123" N "123" N "456"); 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(false); data.setText("123 456"); KEYS("yw2P", "123 123" X " 123 456"); KEYS("2p", "123 123 123 123" X " 123 456"); data.setText("123" N "456"); KEYS("2yyp", "123" N X "123" N "456" N "456"); data.setText("123" N "456"); KEYS("2yyP", X "123" N "456" N "123" N "456"); data.setText("123" N "456" N "789"); KEYS("ddp", "456" N X "123" N "789"); // block-select middle column, copy and paste twice data.setText("123" N "456"); KEYS("lj\"xy2\"xp", "12" X "223" N "45556"); data.setText("123" N "456" N "789"); KEYS("wyiw" "wviwp", "123" N "456" N "45" X "6"); // QTCREATORBUG-8148 data.setText("abc"); KEYS("yyp", "abc" N X "abc"); KEYS("4p", "abc" N "abc" N X "abc" N "abc" N "abc" N "abc"); // cursor position after yank data.setText("ab" X "c" N "def"); KEYS("Vjy", X "abc" N "def"); data.setText("ab" X "c" N "def"); KEYS("jhhy", X "abc" N "def"); data.setText("ab" X "c" N "def"); KEYS("yj", "ab" X "c" N "def"); data.setText("abc" N "de" X "f"); KEYS("yk", "ab" X "c" N "def"); data.setText("ab" X "c" N "def"); KEYS("yy", "ab" X "c" N "def"); KEYS("2yy", "ab" X "c" N "def"); // copy empty line data.setText(X "a" N "" N "b"); KEYS("Vjy", X "a" N "" N "b"); KEYS("p", "a" N X "a" N "" N "" N "b"); // registers data.setText(X "abc" N "def" N "ghi"); KEYS("\"xyy", X "abc" N "def" N "ghi"); KEYS("\"xp", "abc" N X "abc" N "def" N "ghi"); KEYS("j\"yyy", "abc" N "abc" N X "def" N "ghi"); KEYS("gg\"yP", X "def" N "abc" N "abc" N "def" N "ghi"); KEYS("\"xP", X "abc" N "def" N "abc" N "abc" N "def" N "ghi"); // QTCREATORBUG-25281 data.setText(X "abc" N "def" N "ghi"); KEYS("\"xyy", X "abc" N "def" N "ghi"); KEYS("\"xp", "abc" N X "abc" N "def" N "ghi"); KEYS("j", "abc" N "abc" N X "def" N "ghi"); KEYS("yy", "abc" N "abc" N X "def" N "ghi"); KEYS("\"xp", "abc" N "abc" N "def" N X "abc" N "ghi"); KEYS(".", "abc" N "abc" N "def" N "abc" N X "abc" N "ghi"); KEYS("\"xP", "abc" N "abc" N "def" N "abc" N X "abc" N "abc" N "ghi"); KEYS(".", "abc" N "abc" N "def" N "abc" N X "abc" N "abc" N "abc" N "ghi"); // delete to black hole register data.setText("aaa bbb ccc"); KEYS("yiww\"_diwP", "aaa aaa ccc"); data.setText("aaa bbb ccc"); KEYS("yiwwdiwP", "aaa bbb ccc"); // yank register is only used for y{motion} commands data.setText("aaa bbb ccc"); KEYS("yiwwdiw\"0P", "aaa aaa ccc"); // paste register in insert mode data.setText("aaa bbb ccc "); KEYS("yiwA0", "aaa bbb ccc aaa"); KEYS("x", "aaa bbb ccc aaax"); KEYS("dd", ""); data.setText("aaa bbb"); KEYS("\"ayawAa", "aaa bbbaaa "); } void FakeVimTester::test_vim_undo_redo() { TestData data; setup(&data); data.setText("abc def" N "xyz" N "123"); KEYS("ddu", X "abc def" N "xyz" N "123"); COMMAND("redo", X "xyz" N "123"); COMMAND("undo", X "abc def" N "xyz" N "123"); COMMAND("redo", X "xyz" N "123"); KEYS("dd", X "123"); KEYS("3x", X ""); KEYS("uuu", X "abc def" N "xyz" N "123"); KEYS("", X "xyz" N "123"); KEYS("2", X ""); KEYS("3u", X "abc def" N "xyz" N "123"); KEYS("wved", "abc" X " " N "xyz" N "123"); KEYS("2w", "abc " N "xyz" N X "123"); KEYS("u", "abc " X "def" N "xyz" N "123"); KEYS("", "abc" X " " N "xyz" N "123"); KEYS("10ugg", X "abc def" N "xyz" N "123"); KEYS("A xxx", "abc def xx" X "x" N "xyz" N "123"); KEYS("A yyy", "abc def xxx yy" X "y" N "xyz" N "123"); KEYS("u", "abc def xx" X "x" N "xyz" N "123"); KEYS("u", "abc de" X "f" N "xyz" N "123"); KEYS("", "abc def" X " xxx" N "xyz" N "123"); KEYS("", "abc def xxx" X " yyy" N "xyz" N "123"); KEYS("izzz", "abc def xxxzz" X "z yyy" N "xyz" N "123"); KEYS("", "abc def xxxzz" X "z yyy" N "xyz" N "123"); KEYS("u", "abc def xxx" X " yyy" N "xyz" N "123"); data.setText("abc" N X "def"); KEYS("oxyz", "abc" N "def" N "xy" X "z"); KEYS("u", "abc" N X "def"); // undo paste lines data.setText("abc" N); KEYS("yy2p", "abc" N X "abc" N "abc" N); KEYS("yy3p", "abc" N "abc" N X "abc" N "abc" N "abc" N "abc" N); KEYS("u", "abc" N X "abc" N "abc" N); KEYS("u", X "abc" N); KEYS("", X "abc" N "abc" N "abc" N); KEYS("", "abc" N X "abc" N "abc" N "abc" N "abc" N "abc" N); KEYS("u", "abc" N X "abc" N "abc" N); KEYS("u", X "abc" N); // undo paste block data.setText("abc" N "def" N "ghi"); KEYS("jyp", "a" X "abc" N "ddef" N "ghi"); KEYS("2p", "aa" X "aabc" N "ddddef" N "ghi"); KEYS("3p", "aaa" X "aaaabc" N "dddddddef" N "ghi"); KEYS("u", "aa" X "aabc" N "ddddef" N "ghi"); KEYS("u", "a" X "abc" N "ddef" N "ghi"); // undo indent data.doCommand("set expandtab"); data.doCommand("set shiftwidth=4"); data.setText("abc" N "def"); KEYS(">>", " " X "abc" N "def"); KEYS(">>", " " X "abc" N "def"); KEYS("<<", " " X "abc" N "def"); KEYS("<<", X "abc" N "def"); KEYS("u", " " X "abc" N "def"); KEYS("u", " " X "abc" N "def"); KEYS("u", " " X "abc" N "def"); KEYS("u", X "abc" N "def"); KEYS("", X " abc" N "def"); KEYS("", " " X " abc" N "def"); KEYS("", " ab" X "c" N "def"); KEYS("", "ab" X "c" N "def"); KEYS("", "ab" X "c" N "def"); data.setText("abc" N "def"); KEYS("2>>", " " X "abc" N " def"); KEYS("u", X "abc" N "def"); KEYS("", X " abc" N " def"); KEYS("u", X "abc" N "def"); KEYS(">j", " " X "abc" N " def"); KEYS("u", X "abc" N "def"); KEYS("", X " abc" N " def"); // undo replace line data.setText("abc" N " def" N "ghi"); KEYS("jlllSxyz", "abc" N "xyz" N "ghi"); KEYS("u", "abc" N " " X "def" N "ghi"); } void FakeVimTester::test_vim_letter_case() { TestData data; setup(&data); // set command ~ not to behave as g~ data.doCommand("set notildeop"); // upper- and lower-case data.setText("abc DEF"); KEYS("~", "A" X "bc DEF"); INTEGRITY(false); KEYS("4~", "ABC d" X "EF"); INTEGRITY(false); data.setText("abc DEF" N "ghi"); KEYS("l9~", "aBC de" X "f" N "ghi"); KEYS(".", "aBC de" X "F" N "ghi"); KEYS("h.", "aBC dE" X "f" N "ghi"); // set command ~ to behave as g~ data.doCommand("set tildeop"); data.setText("abc DEF" N "ghi JKL"); KEYS("ll~j", "ABC def" N "GHI jkl"); data.setText("abc DEF"); KEYS("lv3l~", "a" X "BC dEF"); KEYS("v4lU", "a" X "BC DEF"); KEYS("v4$u", "a" X "bc def"); KEYS("v4$gU", "a" X "BC DEF"); KEYS("gu$", "a" X "bc def"); KEYS("lg~~", X "ABC DEF"); KEYS(".", X "abc def"); KEYS("gUiw", X "ABC def"); data.setText(" ab" X "c" N "def"); KEYS("2gUU", " " X "ABC" N "DEF"); KEYS("u", " " X "abc" N "def"); KEYS("", " " X "ABC" N "DEF"); // undo, redo and dot command data.setText(" abcde" N " fgh" N " ijk"); KEYS("3l" "2l2j" "U", " a" X "BCDe" N " fGH" N " iJK"); KEYS("u", " a" X "bcde" N " fgh" N " ijk"); KEYS("", " a" X "BCDe" N " fGH" N " iJK"); KEYS("u", " a" X "bcde" N " fgh" N " ijk"); KEYS("h.", " " X "ABCde" N " FGH" N " IJK"); KEYS("u", " " X "abcde" N " fgh" N " ijk"); KEYS("h.", " " X " ABcde" N " FGh" N " IJk"); KEYS("u", " " X " abcde" N " fgh" N " ijk"); KEYS("j.", " abcde" N " " X " FGh" N " IJk"); KEYS("u", " abcde" N " " X " fgh" N " ijk"); } void FakeVimTester::test_vim_code_autoindent() { TestData data; setup(&data); data.doCommand("set nopassnewline"); data.doCommand("set expandtab"); data.doCommand("set shiftwidth=3"); data.setText("int main()" N X "{" N "}" N ""); KEYS("o" "return 0;", "int main()" N "{" N " return 0;" X N "}" N ""); INTEGRITY(false); KEYS("O" "int i = 0;", "int main()" N "{" N " int i = 0;" X N " return 0;" N "}" N ""); INTEGRITY(false); KEYS("ddO" "int i = 0;" N "int j = 0;", "int main()" N "{" N " int i = 0;" N " int j = 0;" X N " return 0;" N "}" N ""); data.doKeys(""); KEYS("^i" "int x = 1;" N, "int main()" N "{" N " int i = 0;" N " int x = 1;" N " " X "int j = 0;" N " return 0;" N "}" N ""); data.doKeys(""); KEYS("c2k" "if (true) {" N ";" N "}", "int main()" N "{" N " if (true) {" N " ;" N " }" X N " return 0;" N "}" N ""); data.doKeys(""); KEYS("jci{" "return 1;", "int main()" N "{" N " return 1;" X N "}" N ""); data.doKeys(""); KEYS("di{", "int main()" N "{" N X "}" N ""); 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 FakeVimTester::test_vim_code_folding() { TestData data; setup(&data); data.setText("int main()" N "{" N " return 0;" N "}" N ""); // fold/unfold function block data.doKeys("zc"); QCOMPARE(data.lines(), 2); data.doKeys("zo"); QCOMPARE(data.lines(), 5); data.doKeys("za"); QCOMPARE(data.lines(), 2); // delete whole block KEYS("dd", ""); // undo/redo KEYS("u", "int main()" N "{" N " return 0;" N "}" N ""); KEYS("", ""); // change block KEYS("uggzo", X "int main()" N "{" N " return 0;" N "}" N ""); KEYS("ccvoid f()", "void f(" X ")" N "{" N " return 0;" N "}" N ""); KEYS("uzc.", "void f(" X ")" N ""); // open/close folds recursively data.setText("int main()" N "{" N " if (true) {" N " return 0;" N " } else {" N " // comment" N " " X "return 2" N " }" N "}" N ""); int lines = data.lines(); // close else block data.doKeys("zc"); QCOMPARE(data.lines(), lines - 3); // close function block data.doKeys("zc"); QCOMPARE(data.lines(), lines - 8); // jumping to a line opens all its parent folds data.doKeys("6gg"); QCOMPARE(data.lines(), lines); // close recursively data.doKeys("zC"); QCOMPARE(data.lines(), lines - 8); data.doKeys("za"); QCOMPARE(data.lines(), lines - 3); data.doKeys("6gg"); QCOMPARE(data.lines(), lines); data.doKeys("zA"); QCOMPARE(data.lines(), lines - 8); data.doKeys("za"); QCOMPARE(data.lines(), lines - 3); // close all folds data.doKeys("zM"); QCOMPARE(data.lines(), lines - 8); data.doKeys("zo"); QCOMPARE(data.lines(), lines - 4); data.doKeys("zM"); QCOMPARE(data.lines(), lines - 8); // open all folds data.doKeys("zR"); QCOMPARE(data.lines(), lines); // delete folded lined if deleting to the end of the first folding line data.doKeys("zMgg"); //QTRY_COMPARE(data.lines(), lines - 8); QCOMPARE(data.lines(), lines - 8); KEYS("wwd$", "int main" N ""); // undo KEYS("u", "int main" X "()" N "{" N " if (true) {" N " return 0;" N " } else {" N " // comment" N " return 2" N " }" N "}" N ""); NOT_IMPLEMENTED // Opening folds recursively isn't supported (previous position in fold isn't restored). } void FakeVimTester::test_vim_code_completion() { // Test completion by simply bypassing FakeVim and inserting text directly in editor widget. TestData data; setup(&data); data.setText( "int test1Var;" N "int test2Var;" N "int main() {" N " " X ";" N "}" N ""); data.doKeys("i" "te"); data.completeText("st"); data.doKeys("1"); data.completeText("Var"); KEYS(" = 0", "int test1Var;" N "int test2Var;" N "int main() {" N " test1Var = " X "0;" N "}" N ""); data.doKeys("o" "te"); data.completeText("st"); data.doKeys("2"); data.completeText("Var"); KEYS(" = 1;", "int test1Var;" N "int test2Var;" N "int main() {" N " test1Var = 0;" N " test2Var = 1" X ";" N "}" N ""); data.doKeys(""); // repeat text insertion with completion KEYS(".", "int test1Var;" N "int test2Var;" N "int main() {" N " test1Var = 0;" N " test2Var = 1;" N " test2Var = 1" X ";" N "}" N ""); } void FakeVimTester::test_vim_substitute() { TestData data; setup(&data); data.setText("abcabc"); COMMAND("s/abc/123/", X "123abc"); COMMAND("u", X "abcabc"); COMMAND("s/abc/123/g", X "123123"); COMMAND("u", X "abcabc"); data.setText("abc" N "def"); COMMAND("%s/^/ -- /", " -- abc" N " " X "-- def"); COMMAND("u", X "abc" N "def"); data.setText(" abc" N " def"); COMMAND("%s/$/./", " abc." N " " X "def."); data.setText("abc" N "def"); COMMAND("%s/.*/(&)", "(abc)" N X "(def)"); COMMAND("u", X "abc" N "def"); COMMAND("%s/.*/X/g", "X" N X "X"); data.setText("abc" N "" N "def"); COMMAND("%s/^\\|$/--", "--abc" N "--" N X "--def"); COMMAND("u", X "abc" N "" N "def"); COMMAND("%s/^\\|$/--/g", "--abc--" N "--" N X "--def--"); // captures data.setText("abc def ghi"); COMMAND("s/\\w\\+/'&'/g", X "'abc' 'def' 'ghi'"); COMMAND("u", X "abc def ghi"); COMMAND("s/\\w\\+/'\\&'/g", X "'&' '&' '&'"); COMMAND("u", X "abc def ghi"); COMMAND("s/\\(\\w\\{3}\\)/(\\1)/g", X "(abc) (def) (ghi)"); COMMAND("u", X "abc def ghi"); COMMAND("s/\\(\\w\\{3}\\) \\(\\w\\{3\\}\\)/\\2 \\1 \\\\1/g", X "def abc \\1 ghi"); // case-insensitive data.setText("abc ABC abc"); COMMAND("s/ABC/123/gi", X "123 123 123"); // replace on a line data.setText("abc" N "def" N "ghi"); COMMAND("2s/^/ + /", "abc" N " " X "+ def" N "ghi"); COMMAND("1s/^/ * /", " " X "* abc" N " + def" N "ghi"); COMMAND("$s/^/ - /", " * abc" N " + def" N " " X "- ghi"); // replace on lines data.setText("abc" N "def" N "ghi"); COMMAND("2,$s/^/ + /", "abc" N " + def" N " " X "+ ghi"); COMMAND("1,2s/^/ * /", " * abc" N " " X "* + def" N " + ghi"); COMMAND("3,3s/^/ - /", " * abc" N " * + def" N " " X "- + ghi"); COMMAND("%s/\\( \\S \\)*//g", "abc" N "def" N X "ghi"); // last substitution data.setText("abc" N "def" N "ghi"); COMMAND("%s/DEF/+&/i", "abc" N X "+def" N "ghi"); COMMAND("&&", "abc" N X "++def" N "ghi"); COMMAND("&", "abc" N X "++def" N "ghi"); COMMAND("&&", "abc" N X "++def" N "ghi"); COMMAND("&i", "abc" N X "+++def" N "ghi"); COMMAND("s", "abc" N X "+++def" N "ghi"); COMMAND("&&i", "abc" N X "++++def" N "ghi"); // search for last substitute pattern data.setText("abc" N "def" N "ghi"); COMMAND("%s/def/def", "abc" N X "def" N "ghi"); KEYS("gg", X "abc" N "def" N "ghi"); COMMAND("\\&", "abc" N X "def" N "ghi"); // substitute last selection data.setText("abc" N "def" N "ghi" N "jkl"); KEYS("jVj:s/^/*", "abc" N "*def" N X "*ghi" N "jkl"); COMMAND("'<,'>s/^/*", "abc" N "**def" N X "**ghi" N "jkl"); KEYS("u", "abc" N X "*def" N "*ghi" N "jkl"); KEYS("gv:s/^/+", "abc" N "+*def" N X "+*ghi" N "jkl"); // replace empty string data.setText("abc"); COMMAND("s//--/g", "--a--b--c"); // remove characters data.setText("abc def"); COMMAND("s/[abde]//g", "c f"); COMMAND("undo | s/[bcef]//g", "a d"); COMMAND("undo | s/\\w//g", " "); COMMAND("undo | s/f\\|$/-/g", "abc de-"); // modifiers data.setText("abC dEfGh"); COMMAND("s/b...E/\\u&", "aBC dEfGh"); COMMAND("undo | s/b...E/\\U&/g", "aBC DEfGh"); COMMAND("undo | s/C..E/\\l&/g", "abc dEfGh"); COMMAND("undo | s/b...E/\\L&/g", "abc defGh"); COMMAND("undo | s/\\(b...E\\)/\\u\\1/g", "aBC dEfGh"); COMMAND("undo | s/\\(b...E\\)/\\U\\1/g", "aBC DEfGh"); COMMAND("undo | s/\\(C..E\\)/\\l\\1/g", "abc dEfGh"); COMMAND("undo | s/\\(b...E\\)/\\L\\1/g", "abc defGh"); // replace 1 backslash with 1 forward slash (separator: /) data.setText(R"(abc\def)"); COMMAND(R"(s/\\/\/)", X "abc/def"); // replace 1 backslash with X normal on line (separator: /) data.setText(R"(abc\def\ghi)"); COMMAND(R"(s/\\/X/g)", X "abcXdefXghi"); // replace 1 backslash with 1 forward slash on line (separator: /) data.setText(R"(abc\def\ghi)"); COMMAND(R"(s/\\/\//g)", X "abc/def/ghi"); // replace 1 backslash with 1 forward slash data.setText(R"(abc\def)"); COMMAND(R"(s#\\#/)", X "abc/def"); // replace 1 backslash with 1 forward slash on line data.setText(R"(abc\def\ghi)"); COMMAND(R"(s#\\#/#g)", X "abc/def/ghi"); // replace 2 backslash with 2 forward slash data.setText(R"(abc\\def)"); COMMAND(R"(s#\\\\#//)", X "abc//def"); // replace 2 backslash with 2 forward slash on line data.setText(R"(abc\\def\\ghi)"); COMMAND(R"(s#\\\\#//#g)", X "abc//def//ghi"); // replace 1 backslash with 1 forward slash last char data.setText(R"(abc\)"); COMMAND(R"(s#\\#/)", X "abc/"); // replace 1 backslash with 1 forward slash first char data.setText(R"(\abc)"); COMMAND(R"(s#\\#/)", X "/abc"); // replace 1 # with 2 # on line data.setText(R"(abc#def#ghi)"); COMMAND(R"(s#\##\#\##g)", X "abc##def##ghi"); // replace 2 # with 4 # on line data.setText(R"(abc##def##ghi)"); COMMAND(R"(s#\#\##\#\#\#\##g)", X "abc####def####ghi"); } void FakeVimTester::test_vim_ex_commandbuffer_paste() { TestData data; setup(&data); data.setText("abc def abc def xyz"); KEYS("fyyiw0:s//0/g", "xyz def xyz def xyz"); } void FakeVimTester::test_vim_ex_yank() { TestData data; setup(&data); data.setText("abc" N "def"); COMMAND("y x", X "abc" N "def"); KEYS("\"xp", "abc" N X "abc" N "def"); COMMAND("u", X "abc" N "def"); COMMAND("redo", X "abc" N "abc" N "def"); KEYS("uw", "abc" N X "def"); COMMAND("1y y", "abc" N X "def"); KEYS("\"yP", "abc" N X "abc" N "def"); COMMAND("u", "abc" N X "def"); COMMAND("-1,$y x", "abc" N X "def"); KEYS("\"xP", "abc" N X "abc" N "def" N "def"); COMMAND("u", "abc" N X "def"); COMMAND("$-1y", "abc" N X "def"); KEYS("P", "abc" N X "abc" N "def"); COMMAND("u", "abc" N X "def"); data.setText("abc" N "def"); KEYS("\"xy$", X "abc" N "def"); KEYS("\"xP", "ab" X "cabc" N "def"); data.setText( "abc def" N "ghi jkl" N ); KEYS("yiwp", "aab" X "cbc def" N "ghi jkl" N ); KEYS("u", X "abc def" N "ghi jkl" N ); KEYS("\"0p", "aab" X "cbc def" N "ghi jkl" N ); KEYS("\"xyiw", X "aabcbc def" N "ghi jkl" N ); KEYS("\"0p", "aab" X "cabcbc def" N "ghi jkl" N ); KEYS("\"xp", "aabcaabcb" X "cabcbc def" N "ghi jkl" N ); // register " is last yank data.setText( "abc def" N "ghi jkl" N ); KEYS("yiwp\"xyiw\"\"p", "aaabcb" X "cabcbc def" N "ghi jkl" N ); // uppercase register appends to lowercase data.setText( "abc" N "def" N "ghi" N ); KEYS("\"zdd" "\"zp", "def" N X "abc" N "ghi" N ); KEYS("k\"Zyy" "jj\"zp", "def" N "abc" N "ghi" N X "abc" N "def" N ); KEYS("k\"Zdd" "j\"Zp", "def" N "abc" N "abc" N "def" N X "abc" N "def" N "ghi" N ); KEYS("\"zdk" "gg\"zp", "def" N X "def" N "abc" N "abc" N "abc" N "def" N "ghi" N ); } void FakeVimTester::test_vim_ex_delete() { TestData data; setup(&data); data.setText("abc" N X "def" N "ghi" N "jkl"); COMMAND("d", "abc" N X "ghi" N "jkl"); COMMAND("1,2d", X "jkl"); COMMAND("u", X "abc" N "ghi" N "jkl"); COMMAND("u", "abc" N X "def" N "ghi" N "jkl"); KEYS("p", "abc" N "def" N X "abc" N "ghi" N "ghi" N "jkl"); COMMAND("set ws|" "/abc/,/ghi/d|" "set nows", X "ghi" N "jkl"); COMMAND("u", X "abc" N "def" N "abc" N "ghi" N "ghi" N "jkl"); COMMAND("2,/abc/d3", "abc" N "def" N X "jkl"); COMMAND("u", "abc" N "def" N X "abc" N "ghi" N "ghi" N "jkl"); COMMAND("5,.+1d", "abc" N "def" N "abc" N X "jkl"); } void FakeVimTester::test_vim_ex_change() { TestData data; setup(&data); data.setText("abc" N X "def" N "ghi" N "jkl"); KEYS(":cxxx0", "abc" N X "xxx" N "ghi" N "jkl"); KEYS(":-1,+1cXXX0", X "XXX" N "jkl"); } void FakeVimTester::test_vim_ex_shift() { TestData data; setup(&data); data.doCommand("set expandtab"); data.doCommand("set shiftwidth=2"); data.setText("abc" N X "def" N "ghi" N "jkl"); COMMAND(">", "abc" N " " X "def" N "ghi" N "jkl"); COMMAND(">>", "abc" N " " X "def" N "ghi" N "jkl"); COMMAND("<", "abc" N " " X "def" N "ghi" N "jkl"); COMMAND("<<", "abc" N X "def" N "ghi" N "jkl"); } void FakeVimTester::test_vim_ex_move() { TestData data; setup(&data); data.setText("abc" N "def" N "ghi" N "jkl"); COMMAND("m +1", "def" N X "abc" N "ghi" N "jkl"); COMMAND("u", X "abc" N "def" N "ghi" N "jkl"); COMMAND("redo", X "def" N "abc" N "ghi" N "jkl"); COMMAND("m -2", X "def" N "abc" N "ghi" N "jkl"); COMMAND("2m0", X "abc" N "def" N "ghi" N "jkl"); COMMAND("m $-2", "def" N X "abc" N "ghi" N "jkl"); KEYS("`'", X "def" N "abc" N "ghi" N "jkl"); KEYS("Vj:m+2", "ghi" N "def" N X "abc" N "jkl"); KEYS("u", X "def" N "abc" N "ghi" N "jkl"); // move visual selection with indentation data.doCommand("set expandtab"); data.doCommand("set shiftwidth=2"); data.doCommand("vnoremap :m'>+gv="); data.doCommand("vnoremap :m-2gv="); data.setText( "int x;" N "int y;" N "int main() {" N " if (true) {" N " }" N "}" N ""); KEYS("Vj", "int main() {" N " int x;" N " int y;" N " if (true) {" N " }" N "}" N ""); KEYS("gv", "int main() {" N " if (true) {" N " int x;" N " int y;" N " }" N "}" N ""); KEYS("gv", "int main() {" N " int x;" N " int y;" N " if (true) {" N " }" N "}" N ""); data.doCommand("vunmap "); data.doCommand("vunmap "); } void FakeVimTester::test_vim_ex_join() { TestData data; setup(&data); data.setText(" abc" N X " def" N " ghi" N " jkl"); COMMAND("j", " abc" N " " X "def ghi" N " jkl"); COMMAND("u", " abc" N X " def" N " ghi" N " jkl"); COMMAND("1j3", " " X "abc def ghi" N " jkl"); COMMAND("u", X " abc" N " def" N " ghi" N " jkl"); } void FakeVimTester::test_advanced_commands() { TestData data; setup(&data); // subcommands data.setText("abc" N " xxx" N " xxx" N "def"); COMMAND("%s/xxx/ZZZ/g|%s/ZZZ/OOO/g", "abc" N " OOO" N " " X "OOO" N "def"); // undo/redo all subcommands COMMAND(":undo", "abc" N X " xxx" N " xxx" N "def"); COMMAND(":redo", "abc" N X " OOO" N " OOO" N "def"); // redundant characters COMMAND(" ::: %s/\\S\\S\\S/ZZZ/g |" " :: : : %s/ZZZ/XXX/g ", "XXX" N " XXX" N " XXX" N X "XXX"); // bar character in regular expression is not command separator data.setText("abc"); COMMAND("%s/a\\|b\\||/X/g|%s/[^X]/Y/g", "XXY"); } void FakeVimTester::test_map() { TestData data; setup(&data); data.setText("abc def"); data.doCommand("map C ix"); data.doCommand("map c iXXX"); data.doCommand("imap c YYY"); KEYS("C", " x" X " abc def"); data.doCommand("map C "); KEYS("C", " x" X " abc def"); data.doCommand("map C i"); KEYS("C", " " X " abc def"); KEYS("ccc", " XXXYYY YYY" X " abc def"); // unmap KEYS(":unmap cccc", "YYY" X " "); KEYS(":iunmap cccc", X "c"); data.doCommand("unmap C"); data.setText("abc def"); data.doCommand("imap x ((()))"); KEYS("x", X "bc def"); KEYS("ix", "((( bc))" X ") def"); data.doCommand("iunmap x"); data.setText("abc def"); data.doCommand("map 3l"); KEYS("", "abc" X " def"); KEYS("", "abc de" X "f"); // map vs. noremap data.setText("abc def"); data.doCommand("map x 3l"); data.doCommand("map X x"); KEYS("X", "abc" X " def"); data.doCommand("noremap X x"); KEYS("X", "abc" X "def"); data.doCommand("unmap X"); data.doCommand("unmap x"); // limit number of recursions in mappings data.doCommand("map X Y"); data.doCommand("map Y Z"); data.doCommand("map Z X"); KEYS("X", "abc" X "def"); data.doCommand("map Z i"); KEYS("X", "abc" X " def"); data.doCommand("unmap X"); data.doCommand("unmap Y"); data.doCommand("unmap Z"); // imcomplete mapping data.setText("abc"); data.doCommand("map Xa ia"); data.doCommand("map Xb ib"); data.doCommand("map X ic"); KEYS("Xa", X "aabc"); KEYS("Xb", X "baabc"); KEYS("Xic", X "ccbaabc"); // unmap data.doCommand("unmap Xa"); KEYS("Xa", X "cccbaabc"); data.doCommand("unmap Xb"); KEYS("Xb", X "ccccbaabc"); data.doCommand("unmap X"); KEYS("Xb", X "ccccbaabc"); KEYS("X", X "ccccbaabc"); // recursive mapping data.setText("abc"); data.doCommand("map X Y"); data.doCommand("map XXX i1"); data.doCommand("map Y i2"); data.doCommand("map YZ i3"); data.doCommand("map _ i "); KEYS("_XXX_", X " 1 abc"); KEYS("XX_0", X " 22 1 abc"); KEYS("XXXXZ_0", X " 31 22 1 abc"); KEYS("XXXXX_0", X " 221 31 22 1 abc"); KEYS("XXZ", X "32 221 31 22 1 abc"); data.doCommand("unmap X"); data.doCommand("unmap XXX"); data.doCommand("unmap Y"); data.doCommand("unmap YZ"); data.doCommand("unmap _"); // shift modifier data.setText("abc"); data.doCommand("map x i1"); data.doCommand("map X i2"); KEYS("x", X "1abc"); KEYS("X", X "21abc"); data.doCommand("map i3"); KEYS("X", X "321abc"); data.doCommand("map X i4"); KEYS("X", X "4321abc"); KEYS("x", X "14321abc"); data.doCommand("unmap x"); data.doCommand("unmap X"); // undo/redo mapped input data.setText("abc def ghi"); data.doCommand("map X dwea xyz3l"); KEYS("X", "def xyz g" X "hi"); KEYS("u", X "abc def ghi"); KEYS("", X "def xyz ghi"); data.doCommand("unmap X"); data.setText("abc" N " def" N " ghi"); data.doCommand("map X jdd"); KEYS("X", "abc" N " " X "ghi"); KEYS("u", "abc" N X " def" N " ghi"); KEYS("", "abc" N X " ghi"); data.doCommand("unmap X"); data.setText("abc" N "def" N "ghi"); data.doCommand("map X jAxxxyyy"); KEYS("X", "abc" N "defxxx" N "yy" X "y" N "ghi"); KEYS("u", "abc" N "de" X "f" N "ghi"); KEYS("", "abc" N "def" X "xxx" N "yyy" N "ghi"); data.doCommand("unmap X"); /* QTCREATORBUG-7913 */ data.setText(""); data.doCommand("noremap l k|noremap k j|noremap j h"); KEYS("ikkk", "kk" X "k"); KEYS("rj", "kk" X "j"); data.doCommand("unmap l|unmap k|unmap j"); // bad mapping data.setText(X "abc" N "def"); data.doCommand("map X Zxx"); KEYS("X", X "abc" N "def"); // cancelled mapping data.doCommand("map X fxxx"); KEYS("X", X "abc" N "def"); data.doCommand("map X ciXxx"); KEYS("X", X "abc" N "def"); data.doCommand("map Y Xxx"); KEYS("Y", X "abc" N "def"); data.doCommand("unmap X|unmap Y"); // correct mapping after bad one data.setText("abc" N "def"); data.doCommand("map X Y"); data.doCommand("map Y X"); data.doCommand("map Xx xxx"); KEYS("Xr2", X "2bc" N "def"); data.doCommand("unmap X|unmap x|unmap Y"); // data.setText("abc def"); data.doCommand("imap X :%s/def/xxx/"); KEYS("iX", "abc xxx"); data.doCommand("iunmap X"); // Test mappings in UTF-8 encoding. data.setText("abc" N "def"); data.doKeys(QString::fromUtf8(":no \xc5\xaf xiX")); KEYS("oxyz", "abc" N "xy" X "z" N "def"); KEYS(QString::fromUtf8("\xc5\xaf"), "abc" N "x" X "Xy" N "def"); /* QTCREATORBUG-8774 */ data.setText("abc" N "def"); data.doCommand(QString::fromUtf8("no \xc3\xb8 l|no l k|no k j|no j h")); KEYS(QString::fromUtf8("\xc3\xb8"), "a" X "bc" N "def"); data.doCommand(QString::fromUtf8("unmap \xc3\xb8|unmap l|unmap k|unmap j")); // Don't handle mapping in sub-modes that are not followed by movement command. data.setText("abc" N "def"); data.doCommand("map Axy z"); KEYS("", "abc" N "x" X "y z" N "def"); KEYS("r", "abc" N "x" X " z" N "def"); KEYS("f", "abc" N "x " X " z" N "def"); KEYS("t", "abc" N "x " X " z" N "def"); data.doCommand("unmap "); // operator-pending mappings data.setText("abc def" N "ghi jkl"); data.doCommand("omap aw"); KEYS("cX", X "Xdef" N "ghi jkl"); data.doCommand("onoremap iwX"); KEYS("cY", "X" X "Y" N "ghi jkl"); data.doCommand("ono l"); KEYS("d", X "X" N "ghi jkl"); data.doCommand("unmap "); data.setText("abc def" N "ghi jkl"); data.doCommand("onoremap iwwX 3iwX Y"); KEYS("ciwwX Z", "X Y " X "Z" N "ghi jkl"); data.doCommand("unmap X"); // use mapping for in insert data.setText("ab" X "c def" N "ghi jkl"); data.doCommand("inoremap jk "); KEYS("jll" "I__jk", "ab" X "__c def" N "gh__i jkl"); INTEGRITY(false); data.doCommand("unmap jk"); // shouldn't unmap for insert mode KEYS("ijk", "a" X "b__c def" N "gh__i jkl"); data.doCommand("iunmap jk"); KEYS("ijk", "aj" X "kb__c def" N "gh__i jkl"); } void FakeVimTester::test_vim_command_cc() { TestData data; setup(&data); data.setText( "|123" N "456" N "789" N "abc"); KEYS("cc456", "45|6" N "456" N "789" N "abc"); KEYS("ccabc", "ab|c" N "456" N "789" N "abc"); KEYS(".", "ab|c" N "456" N "789" N "abc"); KEYS("j", "abc" N "45|6" N "789" N "abc"); KEYS(".", "abc" N "ab|c" N "789" N "abc"); KEYS("kkk", "ab|c" N "abc" N "789" N "abc"); KEYS("3ccxyz", "xy|z" N "abc"); } void FakeVimTester::test_vim_command_cw() { TestData data; setup(&data); data.setText(X "123 456"); KEYS("cwx", X "x 456"); } void FakeVimTester::test_vim_command_cj() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("cj", l[0]+"\n|" + '\n' + lmid(3)); KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1,2)+'\n' + '\n' + lmid(3)); KEYS("u", l[0]+"\n|" + '\n' + lmid(3)); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("cjabc", l[0]+"\nab|c\n" + lmid(3)); KEYS("u", cursor(2, 0)); KEYS("gg", cursor(0, 0)); KEYS(".", "ab|c\n" + lmid(2)); } void FakeVimTester::test_vim_command_ck() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("ck", "|\n" + lmid(2)); KEYS("P", '|' + lmid(0,2)+'\n' + '\n' + lmid(2)); } void FakeVimTester::test_vim_command_c_dollar() { TestData data; setup(&data); data.setText(testLines); KEYS("j", cursor(1, 0)); KEYS("$", cursor(1, -1)); KEYS("c$", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2)); KEYS("c$", l[0]+'\n' + l[1].left(l[1].length()-3)+'|'+l[1][l[1].length()-3]+'\n' + lmid(2)); KEYS("0c$abc", l[0]+'\n' + "ab|c\n" + lmid(2)); KEYS("0c$abc", l[0]+'\n' + "ab|c\n" + lmid(2)); } void FakeVimTester::test_vim_command_C() { TestData data; setup(&data); data.setText(testLines); KEYS("j", cursor(1, 0)); KEYS("Cabc", l[0] + "\nab|c\n" + lmid(2)); KEYS("Cabc", l[0] + "\nabab|c\n" + lmid(2)); KEYS("$Cabc", l[0] + "\nababab|c\n" + lmid(2)); KEYS("0C", l[0] + "\n|\n" + lmid(2)); KEYS("0Cabc", l[0] + "\nab|c\n" + lmid(2)); } void FakeVimTester::test_vim_command_dw() { TestData data; setup(&data); data.setText(testLines); KEYS("dw", "|#include \n" + lmid(2)); KEYS("dw", "|include \n" + lmid(2)); KEYS("dw", "|\n" + lmid(2)); KEYS("dw", "|QtCore>\n" + lmid(2)); KEYS("dw", "|>\n" + lmid(2)); KEYS("dw", "|\n" + lmid(2)); // Real vim has this intermediate step, too KEYS("dw", "|#include \n" + lmid(3)); KEYS("dw", "|include \n" + lmid(3)); KEYS("dw", "|\n" + lmid(3)); KEYS("dw", "|QtGui>\n" + lmid(3)); KEYS("dw", "|>\n" + lmid(3)); } void FakeVimTester::test_vim_command_dd() { TestData data; setup(&data); data.setText(testLines); KEYS("j", cursor(1, 0)); KEYS("dd", l[0] + "\n|" + lmid(2)); KEYS(".", l[0] + "\n|" + lmid(3)); KEYS("3dd", l[0] + "\n |QApplication app(argc, argv);\n" + lmid(7)); KEYS("4l", l[0] + "\n QApp|lication app(argc, argv);\n" + lmid(7)); KEYS("dd", l[0] + "\n|" + lmid(7)); KEYS(".", l[0] + "\n |return app.exec();\n" + lmid(9)); KEYS("dd", l[0] + "\n|" + lmid(9)); } void FakeVimTester::test_vim_command_dd_2() { TestData data; setup(&data); data.setText(testLines); KEYS("j", cursor(1, 0)); KEYS("dd", l[0] + "\n|" + lmid(2)); KEYS("p", l[0] + '\n' + l[2] + "\n|" + l[1] + '\n' + lmid(3)); KEYS("u", l[0] + "\n|" + lmid(2)); } void FakeVimTester::test_vim_command_d_dollar() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("$d$", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2)); KEYS("0d$", l[0] + '\n'+"|\n" + lmid(2)); } void FakeVimTester::test_vim_command_dj() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("dj", l[0]+"\n|" + lmid(3)); KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1)); KEYS("0", lmid(0,1)+'\n' + '|'+lmid(1)); KEYS("dj", l[0]+"\n|" + lmid(3)); KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1)); KEYS("05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2)); KEYS("dj", l[0]+"\n|" + lmid(3)); KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1)); KEYS("dj", l[0]+"\n|" + lmid(3)); KEYS("p", lmid(0,1)+'\n' + lmid(3,1)+'\n' + '|'+lmid(1,2)+'\n' + lmid(4)); } void FakeVimTester::test_vim_command_dk() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("dk", '|' + lmid(2)); KEYS("P", '|' + lmid(0)); KEYS("j0", l[0]+ "\n|" + lmid(1)); KEYS("dk", '|' + lmid(2)); KEYS("P", '|' + lmid(0)); KEYS("j05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2)); KEYS("dk", '|' + lmid(2)); KEYS("P", '|' + lmid(0)); KEYS("j05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2)); KEYS("dk", '|' + lmid(2)); KEYS("p", lmid(2,1)+'\n' + '|' + lmid(0,2)+'\n' + lmid(3)); } void FakeVimTester::test_vim_command_dgg() { TestData data; setup(&data); data.setText(testLines); KEYS("Gk", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2)); KEYS("dgg", "|"); KEYS("u", '|' + lmid(0)); } void FakeVimTester::test_vim_command_dG() { TestData data; setup(&data); data.setText(testLines); KEYS("dG", "|"); KEYS("u", '|' + lmid(0)); KEYS("j", cursor(1, 0)); KEYS("dG", "|"); KEYS("u", l[0]+'\n' + '|' + lmid(1)); KEYS("Gk", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2)); NOT_IMPLEMENTED // include movement to first column, as otherwise the result depends on the 'startofline' setting KEYS("dG0", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2,1)); KEYS("dG0", lmid(0, l.size()-3)+'\n' + '|'+lmid(l.size()-3,1)); } void FakeVimTester::test_vim_command_D() { TestData data; setup(&data); data.setText(testLines); KEYS("j", cursor(1, 0)); KEYS("$D", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2)); KEYS("0D", l[0] + "\n|\n" + lmid(2)); } void FakeVimTester::test_vim_command_dollar() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("j$", cursor(2, -1)); KEYS("2j", cursor(4, -1)); } void FakeVimTester::test_vim_command_down() { TestData data; setup(&data); data.setText(testLines); KEYS("j", l[0]+ "\n|" + lmid(1)); KEYS("3j", lmid(0,4)+'\n' + "|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("4j", lmid(0,8)+'\n' + "| return app.exec();\n" + lmid(9)); } void FakeVimTester::test_vim_command_dfx_down() { TestData data; setup(&data); data.setText(testLines); KEYS("j4l", l[0] + "\n#inc|lude \n" + lmid(2)); //NOT_IMPLEMENTED KEYS("df ", l[0] + "\n#inc|\n" + lmid(2)); KEYS("j", l[0] + "\n#inc\n#inc|lude \n" + lmid(3)); KEYS(".", l[0] + "\n#inc\n#inc|\n" + lmid(3)); KEYS("u", l[0] + "\n#inc\n#inc|lude \n" + lmid(3)); KEYS("u", l[0] + "\n#inc|lude \n" + lmid(2)); } void FakeVimTester::test_vim_command_Cxx_down_dot() { TestData data; setup(&data); data.setText(testLines); KEYS("j4l", l[0] + "\n#inc|lude \n" + lmid(2)); KEYS("Cxx", l[0] + "\n#incx|x\n" + lmid(2)); KEYS("j", l[0] + "\n#incxx\n#incl|ude \n" + lmid(3)); KEYS(".", l[0] + "\n#incxx\n#inclx|x\n" + lmid(3)); } void FakeVimTester::test_vim_command_e() { TestData data; setup(&data); data.setText(testLines); KEYS("e", lmid(0,1)+'\n' + "|#include \n" + lmid(2)); KEYS("e", lmid(0,1)+'\n' + "#includ|e \n" + lmid(2)); KEYS("e", lmid(0,1)+'\n' + "#include |\n" + lmid(2)); KEYS("3e", lmid(0,2)+'\n' + "|#include \n" + lmid(3)); KEYS("e", lmid(0,2)+'\n' + "#includ|e \n" + lmid(3)); KEYS("e", lmid(0,2)+'\n' + "#include |\n" + lmid(3)); KEYS("e", lmid(0,2)+'\n' + "#include \n" + lmid(3)); KEYS("4e", lmid(0,4)+'\n' + "int main|(int argc, char *argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(in|t argc, char *argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int arg|c, char *argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int argc|, char *argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int argc, cha|r *argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char |*argv[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char *arg|v[])\n" + lmid(5)); KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char *argv[]|)\n" + lmid(5)); KEYS("e", lmid(0,5)+'\n' + "|{\n" + lmid(6)); KEYS("10k","|\n" + lmid(1)); // home. } void FakeVimTester::test_vim_command_i() { TestData data; setup(&data); data.setText(testLines); // empty insertion at start of document KEYS("i", '|' + testLines); KEYS("u", '|' + testLines); // small insertion at start of document KEYS("ix", "|x" + testLines); KEYS("u", '|' + testLines); COMMAND("redo", "|x" + testLines); KEYS("u", '|' + testLines); // small insertion at start of document KEYS("ixxx", "xx|x" + testLines); KEYS("u", '|' + testLines); // combine insertions KEYS("i1", "|1" + testLines); KEYS("i2", "|21" + testLines); KEYS("i3", "|321" + testLines); KEYS("u", "|21" + testLines); KEYS("u", "|1" + testLines); KEYS("u", '|' + testLines); KEYS("ia", "|a" + testLines); KEYS("ibx", "b|xa" + testLines); KEYS("icyy", "bcy|yxa" + testLines); KEYS("u", "b|xa" + testLines); KEYS("u", "|a" + testLines); COMMAND("redo", "|bxa" + testLines); KEYS("u", "|a" + testLines); } void FakeVimTester::test_vim_command_left() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("h", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("$", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5)); KEYS("h", lmid(0, 4) + "\nint main(int argc, char *argv[|])\n" + lmid(5)); KEYS("3h", lmid(0, 4) + "\nint main(int argc, char *ar|gv[])\n" + lmid(5)); KEYS("50h", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); } void FakeVimTester::test_vim_command_r() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("$", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5)); KEYS("rx", lmid(0, 4) + "\nint main(int argc, char *argv[]|x\n" + lmid(5)); KEYS("2h", lmid(0, 4) + "\nint main(int argc, char *argv|[]x\n" + lmid(5)); KEYS("4ra", lmid(0, 4) + "\nint main(int argc, char *argv|[]x\n" + lmid(5)); KEYS("3rb", lmid(0, 4) + "\nint main(int argc, char *argvbb|b\n" + lmid(5)); KEYS("2rc", lmid(0, 4) + "\nint main(int argc, char *argvbb|b\n" + lmid(5)); KEYS("h2rc",lmid(0, 4) + "\nint main(int argc, char *argvbc|c\n" + lmid(5)); } void FakeVimTester::test_vim_command_right() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("l", lmid(0, 4) + "\ni|nt main(int argc, char *argv[])\n" + lmid(5)); KEYS("3l", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5)); KEYS("50l", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5)); } void FakeVimTester::test_vim_command_up() { TestData data; setup(&data); data.setText(testLines); KEYS("9j", lmid(0, 9) + "\n|}\n"); KEYS("k", lmid(0, 8) + "\n| return app.exec();\n" + lmid(9)); KEYS("4k", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("3k", lmid(0, 1) + "\n|#include \n" + lmid(2)); KEYS("k", cursor(0, 0)); KEYS("2k", cursor(0, 0)); } void FakeVimTester::test_vim_command_w() { TestData data; setup(&data); data.setText(testLines); KEYS("w", lmid(0,1)+'\n' + "|#include \n" + lmid(2)); KEYS("w", lmid(0,1)+'\n' + "#|include \n" + lmid(2)); KEYS("w", lmid(0,1)+'\n' + "#include |\n" + lmid(2)); KEYS("3w", lmid(0,2)+'\n' + "|#include \n" + lmid(3)); KEYS("w", lmid(0,2)+'\n' + "#|include \n" + lmid(3)); KEYS("w", lmid(0,2)+'\n' + "#include |\n" + lmid(3)); KEYS("w", lmid(0,2)+'\n' + "#include <|QtGui>\n" + lmid(3)); KEYS("4w", lmid(0,4)+'\n' + "int |main(int argc, char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main|(int argc, char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(|int argc, char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int |argc, char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int argc|, char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int argc, |char *argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char |*argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char *|argv[])\n" + lmid(5)); KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char *argv|[])\n" + lmid(5)); KEYS("w", lmid(0,5)+'\n' + "|{\n" + lmid(6)); } void FakeVimTester::test_vim_command_yyp() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("yyp", lmid(0, 4) + '\n' + lmid(4, 1) + "\n|" + lmid(4)); } void FakeVimTester::test_vim_command_y_dollar() { TestData data; setup(&data); data.setText(testLines); KEYS("j", l[0]+"\n|" + lmid(1)); KEYS("$y$p", l[0]+'\n'+ l[1]+"|>\n" + lmid(2)); KEYS("$y$p", l[0]+'\n'+ l[1]+">|>\n" + lmid(2)); KEYS("$y$P", l[0]+'\n'+ l[1]+">|>>\n" + lmid(2)); KEYS("$y$P", l[0]+'\n'+ l[1]+">>|>>\n" + lmid(2)); } void FakeVimTester::test_vim_command_percent() { TestData data; setup(&data); data.setText( "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("%", "bool f(int arg1" X ") {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("%", "bool f" X "(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("$h%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N X "}" N ); KEYS("%", "bool f(int arg1) " X "{" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("j%", "bool f(int arg1) {" N " Q_ASSERT" X "(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0" X ");" N " if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("j%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true; else if (arg1 <= 0" X ") return false;" N "}" N ); KEYS("0%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0" X ") return true; else if (arg1 <= 0) return false;" N "}" N ); KEYS("%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " if " X "(arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); // jump to 50% of buffer KEYS("50%", "bool f(int arg1) {" N " Q_ASSERT(arg1 >= 0);" N " " X "if (arg1 > 0) return true; else if (arg1 <= 0) return false;" N "}" N ); } void FakeVimTester::test_vim_command_Yp() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("Yp", lmid(0, 4) + '\n' + lmid(4, 1) + "\n|" + lmid(4)); } void FakeVimTester::test_vim_command_ma_yank() { TestData data; setup(&data); data.setText(testLines); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("ygg", '|' + lmid(0)); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("p", lmid(0,5) + "\n|" + lmid(0,4) +'\n' + lmid(4)); data.setText(testLines); KEYS("gg", '|' + lmid(0)); KEYS("ma", '|' + lmid(0)); KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5)); KEYS("mb", lmid(0,4) + "\n|" + lmid(4)); KEYS("\"ay'a", '|' + lmid(0)); KEYS("'b", lmid(0,4) + "\n|" + lmid(4)); KEYS("\"ap", lmid(0,5) + "\n|" + lmid(0,4) +'\n' + lmid(4)); } void FakeVimTester::test_vim_command_Gyyp() { TestData data; setup(&data); data.setText(testLines); KEYS("Gk", lmid(0, l.size()-2) + "\n|" + lmid(l.size()-2)); KEYS("yyp", lmid(0) + '|' + lmid(9, 1)+'\n'); } void FakeVimTester::test_i_cw_i() { TestData data; setup(&data); data.setText(testLines); KEYS("j", l[0] + "\n|" + lmid(1)); KEYS("ixx", l[0] + "\nx|x" + lmid(1)); KEYS("cwyy", l[0] + "\nxy|y" + lmid(1)); KEYS("iaa", l[0] + "\nxya|ay" + lmid(1)); } void FakeVimTester::test_vim_command_J() { TestData data; setup(&data); data.setText(testLines); KEYS("4j4l", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5)); KEYS("J", lmid(0, 5) + "| " + lmid(5)); KEYS("u", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5)); COMMAND("redo", lmid(0, 4) + "\nint |main(int argc, char *argv[]) " + lmid(5)); KEYS("3J", lmid(0, 5) + " " + lmid(5, 1) + " " + lmid(6, 1).mid(4) + "| " + lmid(7)); KEYS("uu", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5)); COMMAND("redo", lmid(0, 4) + "\nint |main(int argc, char *argv[]) " + lmid(5)); // Joining comments data.doCommand("set formatoptions=f"); data.setText("// abc" N "// def"); KEYS("J", "// abc def"); data.setText("/*" N X "* abc" N "* def" N "*/"); KEYS("J", "/*" N "* abc def" N "*/"); data.setText("# abc" N "# def"); KEYS("J", "# abc def"); } void FakeVimTester::test_vim_command_put_at_eol() { TestData data; setup(&data); data.setText(testLines); KEYS("j$", cursor(1, -1)); KEYS("y$", cursor(1, -1)); KEYS("p", lmid(0,2)+"|>\n" + lmid(2)); KEYS("p", lmid(0,2)+">|>\n" + lmid(2)); KEYS("$", lmid(0,2)+">|>\n" + lmid(2)); KEYS("P", lmid(0,2)+">|>>\n" + lmid(2)); } void FakeVimTester::test_vim_command_oO() { TestData data; setup(&data); data.setText(testLines); KEYS("gg", '|' + lmid(0)); KEYS("Ol1", "l|1\n" + lmid(0)); KEYS("gg", "|l1\n" + lmid(0)); KEYS("ol2", "l1\n" "l|2\n" + lmid(0)); KEYS("Gk$", "l1\n" "l2\n" + lmid(0,l.size()-2)+'\n' + '|'+lmid(l.size()-2)); KEYS("ol-1", "l1\n" "l2\n" + lmid(0) + "l-|1\n"); KEYS("Gk", "l1\n" "l2\n" + lmid(0) + "|l-1\n"); KEYS("Ol-2", "l1\n" "l2\n" + lmid(0) + "l-|2\n" + "l-1\n"); } void FakeVimTester::test_vim_command_x() { TestData data; setup(&data); data.setText(testLines); KEYS("x", '|' + lmid(0)); KEYS("j$", cursor(1, -1)); KEYS("x", lmid(0,1)+'\n' + l[1].left(l[1].length()-2)+'|'+l[1].mid(l[1].length()-2,1)+'\n' + lmid(2)); } void FakeVimTester::test_vim_visual_d() { TestData data; setup(&data); data.setText(testLines); KEYS("vd", '|' + lmid(1)); KEYS("u", '|' + lmid(0)); KEYS("vx", '|' + lmid(1)); KEYS("u", '|' + lmid(0)); KEYS("vjd", '|' + lmid(1).mid(1)); KEYS("u", '|' + lmid(0)); KEYS("j", lmid(0, 1)+'\n' + '|' + lmid(1)); KEYS("vd", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1)); KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1)); KEYS("vx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1)); KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1)); KEYS("vhx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1)); KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1)); KEYS("vlx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(2)); KEYS("P", lmid(0, 1)+'\n' + lmid(1).left(1)+'|'+lmid(1).mid(1)); KEYS("vhd", lmid(0, 1)+'\n' + '|' + lmid(1).mid(2)); KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1)); KEYS("v$d", lmid(0, 1)+'\n' + '|' + lmid(2)); KEYS("v$od", lmid(0, 1)+'\n' + '|' + lmid(3)); KEYS("$v$x", lmid(0, 1)+'\n' + lmid(3,1) + '|' + lmid(4)); KEYS("0v$d", lmid(0, 1)+'\n' + '|' + lmid(5)); KEYS("$v0d", lmid(0, 1)+'\n' + "|\n" + lmid(6)); KEYS("v$o0k$d", '|' + lmid(6)); } void FakeVimTester::test_vim_Visual_d() { TestData data; setup(&data); data.setText(testLines); KEYS("Vd", '|' + lmid(1)); KEYS("V2kd", '|' + lmid(2)); KEYS("u", '|' + lmid(1)); KEYS("u", '|' + lmid(0)); KEYS("j", lmid(0,1)+'\n' + '|' + lmid(1)); KEYS("V$d", lmid(0,1)+'\n' + '|' + lmid(2)); KEYS("$V$$d", lmid(0,1)+'\n' + '|' + lmid(3)); KEYS("Vkx", '|' + lmid(4)); KEYS("P", '|' + lmid(0,1)+'\n' + lmid(3)); } void FakeVimTester::test_vim_visual_block_D() { TestData data; setup(&data); data.setText("abc def" N "ghi" N "" N "jklm"); KEYS("l3j", "abc def" N "ghi" N "" N "jk" X "lm"); KEYS("D", X "a" N "g" N "" N "j"); KEYS("u", "a" X "bc def" N "ghi" N "" N "jklm"); KEYS("", X "a" N "g" N "" N "j"); KEYS("u", "a" X "bc def" N "ghi" N "" N "jklm"); KEYS(".", X "a" N "g" N "" N "j"); } void FakeVimTester::test_vim_commentary_emulation() { TestData data; setup(&data); data.doCommand("set commentary"); // Commenting a single line data.setText("abc" N "def"); KEYS("gcc", X "// abc" N "def"); KEYS("gcc", X "abc" N "def"); KEYS(".", X "// abc" N "def"); // Multiple lines data.setText("abc" N " def" N "ghi"); KEYS("gcj", X "// abc" N " // def" N "ghi"); KEYS("gcj", X "abc" N " def" N "ghi"); KEYS("gc2j", X "// abc" N " // def" N "// ghi"); KEYS("gcj", X "abc" N " def" N "// ghi"); KEYS(".", X "// abc" N " // def" N "// ghi"); // Visual mode data.setText("abc" N "def"); KEYS("Vjgc", X "// abc" N "// def"); KEYS(".", X "abc" N "def"); } void FakeVimTester::test_vim_commentary_file_names() { TestData data; setup(&data); data.doCommand("set commentary"); // Default is "//" data.setText("abc"); KEYS("gcc", X "// abc"); // pri and pro data.handler->setCurrentFileName("Test.pri"); data.setText("abc"); KEYS("gcc", X "# abc"); data.handler->setCurrentFileName("Test.pro"); KEYS("gcc", X "abc"); // .h .hpp .cpp data.handler->setCurrentFileName("Test.h"); data.setText("abc"); KEYS("gcc", X "// abc"); data.handler->setCurrentFileName("Test.hpp"); KEYS("gcc", X "abc"); data.handler->setCurrentFileName("Test.cpp"); KEYS("gcc", X "// abc"); } void FakeVimTester::test_vim_replace_with_register_emulation() { TestData data; setup(&data); data.doCommand("set replacewithregister"); // Simple replace data.setText("abc def ghi"); KEYS("yw", "abc def ghi"); KEYS("w", "abc " X "def ghi"); KEYS("grw", "abc " X "abc ghi"); KEYS("w", "abc abc " X "ghi"); KEYS(".", "abc abc " X "abc "); // Registers data.setText("abc def ghi jkl mno"); KEYS("\"xyiw", "abc def ghi jkl mno"); KEYS("w", "abc " X "def ghi jkl mno"); KEYS("yiw", "abc " X "def ghi jkl mno"); KEYS("w", "abc def " X "ghi jkl mno"); KEYS("griw", "abc def " X "def jkl mno"); KEYS("w", "abc def def " X "jkl mno"); KEYS("\"xgriw", "abc def def " X "abc mno"); KEYS("w", "abc def def abc " X "mno"); KEYS(".", "abc def def abc " X "abc"); // Replace entire line data.setText("abc" N "def" N "ghi" N "jkhl"); KEYS("yyj", "abc" N X "def" N "ghi" N "jkhl"); KEYS("grr", "abc" N X "abc" N "ghi" N "jkhl"); KEYS("j", "abc" N "abc" N X "ghi" N "jkhl"); KEYS(".", "abc" N "abc" N X "abc" N "jkhl"); // Visual line mode data.setText("abc" N "def" N "ghi" N "jkhl"); KEYS("yyj", "abc" N X "def" N "ghi" N "jkhl"); KEYS("Vgr", "abc" N X "abc" N "ghi" N "jkhl"); KEYS("j", "abc" N "abc" N X "ghi" N "jkhl"); KEYS(".", "abc" N "abc" N X "abc" N "jkhl"); // Visual char mode data.setText("abc defghi"); KEYS("yiw", "abc defghi"); KEYS("w", "abc defghi"); KEYS("v4lgr", "abc abci"); } void FakeVimTester::test_vim_exchange_emulation() { TestData data; setup(&data); data.doCommand("set exchange"); // Simple exchange data.setText("abc def"); KEYS("cxiw", "abc def"); KEYS("W", "abc " X "def"); KEYS(".", "def abc"); // Clearing pending exchange data.setText("abc def ghi"); KEYS("cxiw", "abc def ghi"); KEYS("cxc", "abc def ghi"); KEYS("W", "abc " X "def ghi"); KEYS("cxiw", "abc def" X " ghi"); KEYS("W", "abc def " X "ghi"); KEYS(".", "abc ghi def"); // Exchange line data.setText("abc" N "def"); KEYS("cxx", "abc" N "def"); KEYS("j", "abc" N "def"); KEYS(".", "def" N "abc"); } void FakeVimTester::test_vim_arg_text_obj_emulation() { TestData data; setup(&data); data.doCommand("set argtextobj"); data.setText("foo(int" X " i, double d, float f)"); KEYS("dia", "foo(" X ", double d, float f)"); KEYS("wdia", "foo(, " X ", float f)"); KEYS("wdia", "foo(, , " X ")"); data.setText("foo(int" X " i, double d, float f, long l)"); KEYS("daa", "foo(" X "double d, float f, long l)"); KEYS("WWdaa", "foo(double d" X ", long l)"); KEYS("Wdaa", "foo(double d)"); KEYS("daa", "foo()"); data.setText("foo(std::map map)"); KEYS("dia", "foo()"); data.setText("foo(const C c" X " = C(bar, baz))"); KEYS("dia", "foo()"); } void FakeVimTester::test_vim_surround_emulation() { TestData data; setup(&data); data.doCommand("set surround"); // ys and ds data.setText("abc"); KEYS(R"(ysawb)", R"((abc))"); KEYS(R"(ysabB)", R"({(abc)})"); KEYS(R"(ysaB])", R"([{(abc)}])"); KEYS(R"(ysa]>)", R"(<[{(abc)}]>)"); KEYS(R"(ysa>")", R"("<[{(abc)}]>")"); KEYS(R"(ysa"')", R"('"<[{(abc)}]>"')"); KEYS(R"(ds')", R"("<[{(abc)}]>")"); KEYS(R"(ds")", R"(<[{(abc)}]>)"); KEYS(R"(ds>)", R"([{(abc)}])"); KEYS(R"(ds])", R"({(abc)})"); KEYS(R"(ds})", R"((abc))"); KEYS(R"(ds))", R"(abc)"); data.setText("abc d|ef ghi"); KEYS("ysiWb", "abc (def) ghi"); KEYS(".", "abc ((def)) ghi"); KEYS("dsb", "abc (def) ghi"); KEYS(".", "abc def ghi"); KEYS("ysaWb", "abc (def) ghi"); KEYS(".", "abc ((def)) ghi"); KEYS("dsb", "abc (def) ghi"); KEYS(".", "abc def ghi"); // yss data.setText("\t" "abc"); KEYS("yssb", "\t" "(abc)"); KEYS(".", "\t" "((abc))"); // Surround with function data.setText("abc"); KEYS("ysiWftest", "test(abc)"); KEYS(".", "test(test(abc))"); // yS puts text on a new line data.setText("abc"); KEYS("ySsB", "{" N "abc" N "}"); // cs data.setText("(abc)"); KEYS(R"(csbB)", R"({abc})"); KEYS(R"(csB])", R"([abc])"); KEYS(R"(cs]>)", R"()"); KEYS(R"(cs>")", R"("abc")"); KEYS(R"(cs"')", R"('abc')"); // Visual line mode data.setText("abc" N); KEYS("VSB", "{" N "abc" N "}" N); // Visual char mode data.setText("abc"); KEYS("vlSB", "{ab}c"); // Visual block mode data.setText("abc" N "def"); KEYS("ljSB", "{ab}c" N "{de}f"); } void FakeVimTester::test_macros() { TestData data; setup(&data); // execute register content data.setText("r1" N "r2r3"); KEYS("\"xy$", X "r1" N "r2r3"); KEYS("@x", X "11" N "r2r3"); INTEGRITY(false); data.doKeys("j\"xy$"); KEYS("@x", "11" N X "32r3"); INTEGRITY(false); data.setText("3"); KEYS("\"xy$", X "3"); KEYS("@x", X "6"); KEYS("@x", X "9"); KEYS("2@x", "1" X "5"); KEYS("2@@", "2" X "1"); KEYS("@@", "2" X "4"); // Raw characters for macro recording. #define ESC "\x1b" #define ENTER "\n" // record data.setText("abc" N "def"); KEYS("qx" "A" ENTER "- xyz" ESC "rZjI- opq" ENTER ESC "q" , "abc" N "- xyZ" N "- opq" N X "def"); KEYS("@x" , "abc" N "- xyZ" N "- opq" N "def" N "- opq" N X "- xyZ"); data.setText(" 1 2 3" N " 4 5 6" N " 7 8 9"); KEYS("qx" "wrXj" "q", " X 2 3" N " 4 5 6" N " 7 8 9"); KEYS("2@x", " X 2 3" N " 4 X 6" N " 7 8 X"); data.setText("abc" N "def"); KEYS("qxi xyz q", "ab xyz" X " c" N "def"); KEYS("j0@x", "ab xyz c" N "de xyz" X " f"); data.setText("abc" N "def"); data.doCommand("unmap "); KEYS("qxq", X "abc" N "def"); data.doCommand("noremap ddp"); KEYS("@x", "def" N X "abc"); KEYS("gg@x", "abc" N X "def"); data.doCommand("unmap "); data.setText(" abc xyz>." N " def xyz>." N " ghi xyz>." N " jkl xyz>."); KEYS("qq" "^wdf>j" "q", " abc ." N " def " X "xyz>." N " ghi xyz>." N " jkl xyz>."); KEYS("2@q", " abc ." N " def ." N " ghi ." N " jkl " X "xyz>."); // record command line data.setText("abc" N "def"); KEYS("qq" ":s/./*/g" "iX" "q", X "Xabc" N "def"); KEYS("@q", X "XXabc" N "def"); KEYS("qq" ":s/./*/g" "iY" "q", X "YXXabc" N "def"); KEYS("@q", X "YYXXabc" N "def"); KEYS("qq" ":s/./*/g" "q", X "*******" N "def"); KEYS("j@q", "*******" N X "***"); // record repeating last command data.setText("abc" N "def"); KEYS(":s/./-/g", X "---" N "def"); KEYS("u", X "abc" N "def"); KEYS("qq" ":" "q", X "---" N "def"); KEYS(":s/./!/g", X "!!!" N "def"); KEYS("j@q", "!!!" N X "!!!"); } void FakeVimTester::test_vim_qtcreator() { TestData data; setup(&data); // Pass input keys in insert mode to underlying editor widget. data.doCommand("set passkeys"); data.setText("" N ""); KEYS("i" "void f(int arg1) {// TODO;", "void f(int arg1) {" N " // TODO" N " ;" X N "}" N ""); data.doKeys(""); KEYS("cc" "assert(arg1 != 0", "void f(int arg1) {" N " // TODO" N " assert(arg1 != 0" X ")" N "}" N ""); data.doKeys(""); KEYS("k" "." "A;", "void f(int arg1) {" N " assert(arg1 != 0);" X N " assert(arg1 != 0)" N "}" N ""); data.doKeys(""); KEYS("j.", "void f(int arg1) {" N " assert(arg1 != 0);" N " assert(arg1 != 0)" X ";" N "}" N ""); KEYS("4b2#", "void f(int " X "arg1) {" N " assert(arg1 != 0);" N " assert(arg1 != 0);" N "}" N ""); KEYS("e" "a, int arg2 = 0" "n", "void f(int " X "arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg1 != 0);" N "}" N ""); // Record macro. KEYS("2j" "qa" "" "f!" "2s>=" "q", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg2 >" X "= 0);" N "}" N ""); // Replay macro. KEYS("n" "@a", "void f(int arg1, int arg2 = 0) {" N " assert(arg2 >" X "= 0);" N " assert(arg2 >= 0);" N "}" N ""); // Undo. KEYS("u", "void f(int arg1, int arg2 = 0) {" N " assert(" X "arg1 != 0);" N " assert(arg2 >= 0);" N "}" N ""); KEYS("u", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg2 " X "!= 0);" N "}" N ""); KEYS("u", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(" X "arg1 != 0);" N "}" N ""); KEYS("u", "void f(int arg1" X ") {" N " assert(arg1 != 0);" N " assert(arg1 != 0);" N "}" N ""); KEYS("u", "void f(int arg1) {" N " assert(arg1 != 0);" N " assert(arg1 != 0" X ")" N "}" N ""); KEYS("u", "void f(int arg1) {" N " assert(arg1 != 0" X ")" N " assert(arg1 != 0)" N "}" N ""); KEYS("u", "void f(int arg1) {" N " " X "// TODO" N " assert(arg1 != 0)" N "}" N ""); KEYS("u", "void f(int arg1) {" N " // TODO" N " " X ";" N "}" N ""); // Redo and occasional undo. KEYS("", "void f(int arg1) {" N " // TODO" N " " X "assert(arg1 != 0)" N "}" N ""); KEYS("", "void f(int arg1) {" N " " X "assert(arg1 != 0)" N " assert(arg1 != 0)" N "}" N ""); KEYS("", "void f(int arg1) {" N " assert(arg1 != 0)" X ";" N " assert(arg1 != 0)" N "}" N ""); KEYS("u", "void f(int arg1) {" N " assert(arg1 != 0" X ")" N " assert(arg1 != 0)" N "}" N ""); KEYS("", "void f(int arg1) {" N " assert(arg1 != 0)" X ";" N " assert(arg1 != 0)" N "}" N ""); KEYS("", "void f(int arg1) {" N " assert(arg1 != 0);" N " assert(arg1 != 0)" X ";" N "}" N ""); KEYS("", "void f(int arg1" X ", int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg1 != 0);" N "}" N ""); KEYS("", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(" X "arg2 != 0);" N "}" N ""); KEYS("", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg2 " X ">= 0);" N "}" N ""); KEYS("", "void f(int arg1, int arg2 = 0) {" N " assert(" X "arg2 >= 0);" N " assert(arg2 >= 0);" N "}" N ""); KEYS("3u", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(" X "arg1 != 0);" N "}" N ""); // Repeat last command. KEYS("w.", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 != 0);" N " assert(arg1 >" X "= 0);" N "}" N ""); KEYS("kdd", "void f(int arg1, int arg2 = 0) {" N " " X "assert(arg1 >= 0);" N "}" N ""); // Make mistakes. KEYS("43" "2oif (arg321 > 0) return true;", "void f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true" X ";" N "}" N ""); // Jumps around and change stuff. KEYS("gg" "ciw" "bool", "bool" X " f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true;" N "}" N ""); data.doKeys(""); KEYS("`'", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true" X ";" N "}" N ""); KEYS("caW" " false;", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return false;" X N "}" N ""); data.doKeys(""); KEYS("k.", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return false" X ";" N " if (arg1 > 0) return false;" N "}" N ""); // Undo/redo again. KEYS("u", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return" X " true;" N " if (arg1 > 0) return false;" N "}" N ""); KEYS("u", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return" X " true;" N "}" N ""); KEYS("", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return" X " false;" N "}" N ""); KEYS("u", "bool f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return" X " true;" N "}" N ""); KEYS("u", X "void f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true;" N "}" N ""); // Record long insert mode. KEYS("qb" "4s" "bool" // 1 "" "Q_ASSERT" // 2 "" "2" // 3 "2w" "1" // 4 ":s/true/false" // 5 "q", "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N " " X " if (arg2 > 1) return false;" N "}" N ""); KEYS("u", // 5 "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N X " if (arg2 > 1) return true;" N "}" N ""); KEYS("u", // 4 "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg2 > " X "0) return true;" N "}" N ""); KEYS("u", // 3 "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1" X " > 0) return true;" N "}" N ""); KEYS("u", // 2 "bool f(int arg1, int arg2 = 0) {" N " " X "assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true;" N "}" N ""); KEYS("u", // 1 X "void f(int arg1, int arg2 = 0) {" N " assert(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg1 > 0) return true;" N "}" N ""); // Replay. KEYS("@b", "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N " " X " if (arg2 > 1) return false;" N "}" N ""); // Return to the first change. KEYS("99u" "", X "void f(int arg1) {" N " // TODO" N " ;" N "}" N ""); KEYS("", "void f(int arg1) {" N " // TODO" N " " X "assert(arg1 != 0)" N "}" N ""); KEYS("", "void f(int arg1) {" N " " X "assert(arg1 != 0)" N " assert(arg1 != 0)" N "}" N ""); // Return to the last change. KEYS("99", "bool f(int arg1, int arg2 = 0) {" N " Q_ASSERT(arg1 >= 0);" N " if (arg1 > 0) return true;" N " if (arg2 > 1) return false;" N "}" N ""); // Macros data.setText( "void f(int arg1) {" N "}" N ""); KEYS("2o" "#ifdef HAS_FEATUREdoSomething();" "#else" "doSomethingElse2();" "#endif" "", "void f(int arg1) {" N "#ifdef HAS_FEATURE" N " doSomething();" N "#else" N " doSomething2();" N "#endif" N "#ifdef HAS_FEATURE" N " doSomething();" N "#else" N " doSomething2();" N "#endi" X "f" N "}" N ""); } } // FakeVim::Internal #include "fakevim_test.moc"