File indexing completed on 2024-05-12 15:45:14

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2014 Miquel Sabaté Solà <mikisabate@gmail.com>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "keys.h"
0009 #include "emulatedcommandbarsetupandteardown.h"
0010 #include "fakecodecompletiontestmodel.h"
0011 #include "vimode/globalstate.h"
0012 #include "vimode/mappings.h"
0013 #include <KLocalizedString>
0014 #include <inputmode/kateviinputmode.h>
0015 #include <kateconfig.h>
0016 #include <katedocument.h>
0017 #include <kateview.h>
0018 #include <vimode/emulatedcommandbar/emulatedcommandbar.h>
0019 #include <vimode/keymapper.h>
0020 #include <vimode/keyparser.h>
0021 
0022 using namespace KTextEditor;
0023 using KateVi::KeyParser;
0024 using KateVi::Mappings;
0025 
0026 QTEST_MAIN(KeysTest)
0027 
0028 // BEGIN: KeysTest
0029 
0030 void KeysTest::MappingTests()
0031 {
0032     //     QVERIFY(false);
0033     const int mappingTimeoutMSOverride = QString::fromLocal8Bit(qgetenv("KATE_VIMODE_TEST_MAPPINGTIMEOUTMS")).toInt();
0034     const int mappingTimeoutMS = (mappingTimeoutMSOverride > 0) ? mappingTimeoutMSOverride : 2000;
0035     KateViewConfig::global()->setValue(KateViewConfig::ViInputModeStealKeys, true); // For tests involving e.g. <c-a>
0036     {
0037         // Check storage and retrieval of mapping recursion.
0038         clearAllMappings();
0039 
0040         vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello", Mappings::Recursive);
0041         QVERIFY(vi_global->mappings()->isRecursive(Mappings::NormalModeMapping, "'"));
0042 
0043         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "ihello", Mappings::NonRecursive);
0044         QVERIFY(!vi_global->mappings()->isRecursive(Mappings::NormalModeMapping, "a"));
0045     }
0046 
0047     clearAllMappings();
0048 
0049     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "<esc>ihello<esc>^aworld<esc>", Mappings::Recursive);
0050     DoTest("", "'", "hworldello");
0051 
0052     // Ensure that the non-mapping logged keypresses are cleared before we execute a mapping
0053     vi_global->mappings()->add(Mappings::NormalModeMapping, "'a", "rO", Mappings::Recursive);
0054     DoTest("X", "'a", "O");
0055 
0056     {
0057         // Check that '123 is mapped after the timeout, given that we also have mappings that
0058         // extend it (e.g. '1234, '12345, etc) and which it itself extends ('1, '12, etc).
0059         clearAllMappings();
0060         BeginTest("");
0061         vi_input_mode_manager->keyMapper()->setMappingTimeout(mappingTimeoutMS);
0062         ;
0063         QString consectiveDigits;
0064         for (int i = 1; i < 9; i++) {
0065             consectiveDigits += QString::number(i);
0066             vi_global->mappings()->add(Mappings::NormalModeMapping, '\'' + consectiveDigits, "iMapped from " + consectiveDigits + "<esc>", Mappings::Recursive);
0067         }
0068         TestPressKey("'123");
0069         QCOMPARE(kate_document->text(), QString()); // Shouldn't add anything until after the timeout!
0070         QTest::qWait(2 * mappingTimeoutMS);
0071         FinishTest("Mapped from 123");
0072     }
0073 
0074     // Mappings are not "counted": any count entered applies to the first command/ motion in the mapped sequence,
0075     // and is not used to replay the entire mapped sequence <count> times in a row.
0076     clearAllMappings();
0077     vi_global->mappings()->add(Mappings::NormalModeMapping, "'downmapping", "j", Mappings::Recursive);
0078     vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmapping", "ifoo<esc>ibar<esc>", Mappings::Recursive);
0079     vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmotionmapping", "lj", Mappings::Recursive);
0080     DoTest("AAAA\nXXXX\nXXXX\nXXXX\nXXXX\nBBBB\nCCCC\nDDDD", "jd3'downmapping", "AAAA\nBBBB\nCCCC\nDDDD");
0081     DoTest("", "5'testmapping", "foofoofoofoofobaro");
0082     DoTest("XXXX\nXXXX\nXXXX\nXXXX", "3'testmotionmappingrO", "XXXX\nXXXO\nXXXX\nXXXX");
0083 
0084     // Regression test for a weird mistake I made: *completely* remove all counting for the
0085     // first command in the sequence; don't just set it to 1! If it is set to 1, then "%"
0086     // will mean "go to position 1 percent of the way through the document" rather than
0087     // go to matching item.
0088     clearAllMappings();
0089     vi_global->mappings()->add(Mappings::NormalModeMapping, "gl", "%", Mappings::Recursive);
0090     DoTest("0\n1\n2\n3\n4\n5\nfoo bar(xyz) baz", "jjjjjjwdgl", "0\n1\n2\n3\n4\n5\nfoo  baz");
0091 
0092     // Test that countable mappings work even when triggered by timeouts.
0093     clearAllMappings();
0094     vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmapping", "ljrO", Mappings::Recursive);
0095     vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmappingdummy", "dummy", Mappings::Recursive);
0096     BeginTest("XXXX\nXXXX\nXXXX\nXXXX");
0097     vi_input_mode_manager->keyMapper()->setMappingTimeout(mappingTimeoutMS);
0098     ;
0099     TestPressKey("3'testmapping");
0100     QTest::qWait(2 * mappingTimeoutMS);
0101     FinishTest("XXXX\nXXXO\nXXXX\nXXXX");
0102 
0103     // Test that telescoping mappings don't interfere with built-in commands. Assumes that gp
0104     // is implemented and working.
0105     clearAllMappings();
0106     vi_global->mappings()->add(Mappings::NormalModeMapping, "gdummy", "idummy", Mappings::Recursive);
0107     DoTest("hello", "yiwgpx", "hhellollo");
0108 
0109     // Test that we can map a sequence of keys that extends a built-in command and use
0110     // that sequence without the built-in command firing.
0111     // Once again, assumes that gp is implemented and working.
0112     clearAllMappings();
0113     vi_global->mappings()->add(Mappings::NormalModeMapping, "gpa", "idummy", Mappings::Recursive);
0114     DoTest("hello", "yiwgpa", "dummyhello");
0115 
0116     // Test that we can map a sequence of keys that extends a built-in command and still
0117     // have the original built-in command fire if we timeout after entering that command.
0118     // Once again, assumes that gp is implemented and working.
0119     clearAllMappings();
0120     vi_global->mappings()->add(Mappings::NormalModeMapping, "gpa", "idummy", Mappings::Recursive);
0121     BeginTest("hello");
0122     vi_input_mode_manager->keyMapper()->setMappingTimeout(mappingTimeoutMS);
0123     ;
0124     TestPressKey("yiwgp");
0125     QTest::qWait(2 * mappingTimeoutMS);
0126     TestPressKey("x");
0127     FinishTest("hhellollo");
0128 
0129     // Test that something that starts off as a partial mapping following a command
0130     // (the "g" in the first "dg" is a partial mapping of "gj"), when extended to something
0131     // that is definitely not a mapping ("gg"), results in the full command being executed ("dgg").
0132     clearAllMappings();
0133     vi_global->mappings()->add(Mappings::NormalModeMapping, "gj", "aj", Mappings::Recursive);
0134     DoTest("foo\nbar\nxyz", "jjdgg", "");
0135 
0136     // Make sure that a mapped sequence of commands is merged into a single undo-able edit.
0137     clearAllMappings();
0138     vi_global->mappings()->add(Mappings::NormalModeMapping, "'a", "ofoo<esc>ofoo<esc>ofoo<esc>", Mappings::Recursive);
0139     DoTest("bar", "'au", "bar");
0140 
0141     // Make sure that a counted mapping is merged into a single undoable edit.
0142     clearAllMappings();
0143     vi_global->mappings()->add(Mappings::NormalModeMapping, "'a", "ofoo<esc>", Mappings::Recursive);
0144     DoTest("bar", "5'au", "bar");
0145 
0146     // Some test setup for non-recursive mapping g -> gj (cf: bug:314415)
0147     // Firstly: work out the expected result of gj (this might be fragile as default settings
0148     // change, etc.).  We use BeginTest & FinishTest for the setup and teardown etc, but this is
0149     // not an actual test - it's just computing the expected result of the real test!
0150     const QString multiVirtualLineText =
0151         "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
0152         "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo "
0153         "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo";
0154     ensureKateViewVisible(); // Needs to be visible in order for virtual lines to make sense.
0155     KateViewConfig::global()->setDynWordWrap(true);
0156     BeginTest(multiVirtualLineText);
0157     TestPressKey("gjrX");
0158     const QString expectedAfterVirtualLineDownAndChange = kate_document->text();
0159     Q_ASSERT_X(expectedAfterVirtualLineDownAndChange.contains("X") && !expectedAfterVirtualLineDownAndChange.startsWith('X'),
0160                "setting up j->gj testcase data",
0161                "gj doesn't seem to have worked correctly!");
0162     FinishTest(expectedAfterVirtualLineDownAndChange);
0163 
0164     // Test that non-recursive mappings are not expanded.
0165     clearAllMappings();
0166     vi_global->mappings()->add(Mappings::NormalModeMapping, "j", "gj", Mappings::NonRecursive);
0167     DoTest(multiVirtualLineText, "jrX", expectedAfterVirtualLineDownAndChange);
0168     KateViewConfig::global()->setDynWordWrap(false);
0169 
0170     // Test that recursive mappings are expanded.
0171     clearAllMappings();
0172     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "X", Mappings::Recursive);
0173     vi_global->mappings()->add(Mappings::NormalModeMapping, "X", "rx", Mappings::Recursive);
0174     DoTest("foo", "la", "fxo");
0175 
0176     // Test that the flag that stops mappings being expanded is reset after the mapping has been executed.
0177     clearAllMappings();
0178     vi_global->mappings()->add(Mappings::NormalModeMapping, "j", "gj", Mappings::NonRecursive);
0179     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "X", Mappings::Recursive);
0180     vi_global->mappings()->add(Mappings::NormalModeMapping, "X", "rx", Mappings::Recursive);
0181     DoTest("foo", "jla", "fxo");
0182 
0183     // Even if we start with a recursive mapping, as soon as we hit one that is not recursive, we should stop
0184     // expanding.
0185     clearAllMappings();
0186     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "X", Mappings::NonRecursive);
0187     vi_global->mappings()->add(Mappings::NormalModeMapping, "X", "r.", Mappings::Recursive);
0188     vi_global->mappings()->add(Mappings::NormalModeMapping, "i", "a", Mappings::Recursive);
0189     DoTest("foo", "li", "oo");
0190 
0191     // Regression test: Using a mapping may trigger a call to updateSelection(), which can change the mode
0192     // from VisualLineMode to plain VisualMode.
0193     clearAllMappings();
0194     vi_global->mappings()->add(Mappings::VisualModeMapping, "gA", "%", Mappings::NonRecursive);
0195     DoTest("xyz\nfoo\n{\nbar\n}", "jVjgAdgglP", "foo\n{\nbar\n}\nxyz");
0196     // Piggy back on the previous test with a regression test for issue where, if gA is mapped to %, vgly
0197     // will yank one more character than it should.
0198     DoTest("foo(bar)X", "vgAyp", "ffoo(bar)oo(bar)X");
0199     // Make sure that a successful mapping does not break the "if we select stuff externally in Normal mode,
0200     // we should switch to Visual Mode" thing.
0201     clearAllMappings();
0202     vi_global->mappings()->add(Mappings::NormalModeMapping, "gA", "%", Mappings::NonRecursive);
0203     BeginTest("foo bar xyz()");
0204     TestPressKey("gAr.");
0205     kate_view->setSelection(Range(0, 1, 0, 4)); // Actually selects "oo " (i.e. without the "b").
0206     TestPressKey("d");
0207     FinishTest("fbar xyz(.");
0208 
0209     // Regression tests for BUG:260655
0210     clearAllMappings();
0211     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "f", Mappings::NonRecursive);
0212     vi_global->mappings()->add(Mappings::NormalModeMapping, "d", "i", Mappings::NonRecursive);
0213     DoTest("foo dar", "adr.", "foo .ar");
0214     clearAllMappings();
0215     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "F", Mappings::NonRecursive);
0216     vi_global->mappings()->add(Mappings::NormalModeMapping, "d", "i", Mappings::NonRecursive);
0217     DoTest("foo dar", "$adr.", "foo .ar");
0218     clearAllMappings();
0219     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "t", Mappings::NonRecursive);
0220     vi_global->mappings()->add(Mappings::NormalModeMapping, "d", "i", Mappings::NonRecursive);
0221     DoTest("foo dar", "adr.", "foo.dar");
0222     clearAllMappings();
0223     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "T", Mappings::NonRecursive);
0224     vi_global->mappings()->add(Mappings::NormalModeMapping, "d", "i", Mappings::NonRecursive);
0225     DoTest("foo dar", "$adr.", "foo d.r");
0226     clearAllMappings();
0227     vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "r", Mappings::NonRecursive);
0228     vi_global->mappings()->add(Mappings::NormalModeMapping, "d", "i", Mappings::NonRecursive);
0229     DoTest("foo dar", "ad", "doo dar");
0230     // Feel free to map the keypress after that, though.
0231     DoTest("foo dar", "addber\\esc", "berdoo dar");
0232     // Also, be careful about how we interpret "waiting for find char/ replace char"
0233     DoTest("foo dar", "ffas", "soo dar");
0234 
0235     // Ignore raw "Ctrl", "Shift", "Meta" and "Alt" keys, which will almost certainly end up being pressed as
0236     // we try to trigger mappings that contain these keys.
0237     clearAllMappings();
0238     {
0239         // Ctrl.
0240         vi_global->mappings()->add(Mappings::NormalModeMapping, "<c-a><c-b>", "ictrl<esc>", Mappings::NonRecursive);
0241         BeginTest("");
0242         QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
0243         QApplication::postEvent(kate_view->focusProxy(), ctrlKeyDown);
0244         QApplication::sendPostedEvents();
0245         TestPressKey("\\ctrl-a");
0246         ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
0247         QApplication::postEvent(kate_view->focusProxy(), ctrlKeyDown);
0248         QApplication::sendPostedEvents();
0249         TestPressKey("\\ctrl-b");
0250         FinishTest("ctrl");
0251     }
0252     {
0253         // Shift.
0254         vi_global->mappings()->add(Mappings::NormalModeMapping, "<c-a>C", "ishift<esc>", Mappings::NonRecursive);
0255         BeginTest("");
0256         QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
0257         QApplication::postEvent(kate_view->focusProxy(), ctrlKeyDown);
0258         QApplication::sendPostedEvents();
0259         TestPressKey("\\ctrl-a");
0260         QKeyEvent *shiftKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier);
0261         QApplication::postEvent(kate_view->focusProxy(), shiftKeyDown);
0262         QApplication::sendPostedEvents();
0263         TestPressKey("C");
0264         FinishTest("shift");
0265     }
0266     {
0267         // Alt.
0268         vi_global->mappings()->add(Mappings::NormalModeMapping, "<c-a><a-b>", "ialt<esc>", Mappings::NonRecursive);
0269         BeginTest("");
0270         QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
0271         QApplication::postEvent(kate_view->focusProxy(), ctrlKeyDown);
0272         QApplication::sendPostedEvents();
0273         TestPressKey("\\ctrl-a");
0274         QKeyEvent *altKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Alt, Qt::NoModifier);
0275         QApplication::postEvent(kate_view->focusProxy(), altKeyDown);
0276         QApplication::sendPostedEvents();
0277         TestPressKey("\\alt-b");
0278         FinishTest("alt");
0279     }
0280     {
0281         // Meta.
0282         vi_global->mappings()->add(Mappings::NormalModeMapping, "<c-a><m-b>", "imeta<esc>", Mappings::NonRecursive);
0283         BeginTest("");
0284         QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
0285         QApplication::postEvent(kate_view->focusProxy(), ctrlKeyDown);
0286         QApplication::sendPostedEvents();
0287         TestPressKey("\\ctrl-a");
0288         QKeyEvent *metaKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Meta, Qt::NoModifier);
0289         QApplication::postEvent(kate_view->focusProxy(), metaKeyDown);
0290         QApplication::sendPostedEvents();
0291         TestPressKey("\\meta-b");
0292         FinishTest("meta");
0293     }
0294     {
0295         // Can have mappings in Visual mode, distinct from Normal mode..
0296         clearAllMappings();
0297         vi_global->mappings()->add(Mappings::VisualModeMapping, "a", "3l", Mappings::NonRecursive);
0298         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "inose<esc>", Mappings::NonRecursive);
0299         DoTest("0123456", "lvad", "056");
0300 
0301         // The recursion in Visual Mode is distinct from that of  Normal mode.
0302         clearAllMappings();
0303         vi_global->mappings()->add(Mappings::VisualModeMapping, "b", "<esc>", Mappings::NonRecursive);
0304         vi_global->mappings()->add(Mappings::VisualModeMapping, "a", "b", Mappings::NonRecursive);
0305         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "b", Mappings::Recursive);
0306         DoTest("XXX\nXXX", "lvajd", "XXX");
0307         clearAllMappings();
0308         vi_global->mappings()->add(Mappings::VisualModeMapping, "b", "<esc>", Mappings::NonRecursive);
0309         vi_global->mappings()->add(Mappings::VisualModeMapping, "a", "b", Mappings::Recursive);
0310         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "b", Mappings::NonRecursive);
0311         DoTest("XXX\nXXX", "lvajd", "XXX\nXXX");
0312 
0313         // A Visual mode mapping applies to all Visual modes (line, block, etc).
0314         clearAllMappings();
0315         vi_global->mappings()->add(Mappings::VisualModeMapping, "a", "2j", Mappings::NonRecursive);
0316         DoTest("123\n456\n789", "lvad", "19");
0317         DoTest("123\n456\n789", "l\\ctrl-vad", "13\n46\n79");
0318         DoTest("123\n456\n789", "lVad", "");
0319         // Same for recursion.
0320         clearAllMappings();
0321         vi_global->mappings()->add(Mappings::VisualModeMapping, "b", "2j", Mappings::NonRecursive);
0322         vi_global->mappings()->add(Mappings::VisualModeMapping, "a", "b", Mappings::Recursive);
0323         DoTest("123\n456\n789", "lvad", "19");
0324         DoTest("123\n456\n789", "l\\ctrl-vad", "13\n46\n79");
0325         DoTest("123\n456\n789", "lVad", "");
0326 
0327         // Can clear Visual mode mappings.
0328         clearAllMappings();
0329         vi_global->mappings()->add(Mappings::VisualModeMapping, "h", "l", Mappings::Recursive);
0330         vi_global->mappings()->clear(Mappings::VisualModeMapping);
0331         DoTest("123\n456\n789", "lvhd", "3\n456\n789");
0332         DoTest("123\n456\n789", "l\\ctrl-vhd", "3\n456\n789");
0333         DoTest("123\n456\n789", "lVhd", "456\n789");
0334         vi_global->mappings()->add(Mappings::VisualModeMapping, "h", "l", Mappings::Recursive);
0335         vi_global->mappings()->clear(Mappings::VisualModeMapping);
0336         DoTest("123\n456\n789", "lvhd", "3\n456\n789");
0337         DoTest("123\n456\n789", "l\\ctrl-vhd", "3\n456\n789");
0338         DoTest("123\n456\n789", "lVhd", "456\n789");
0339         vi_global->mappings()->add(Mappings::VisualModeMapping, "h", "l", Mappings::Recursive);
0340         vi_global->mappings()->clear(Mappings::VisualModeMapping);
0341         DoTest("123\n456\n789", "lvhd", "3\n456\n789");
0342         DoTest("123\n456\n789", "l\\ctrl-vhd", "3\n456\n789");
0343         DoTest("123\n456\n789", "lVhd", "456\n789");
0344     }
0345     {
0346         // Can have mappings in Insert mode.
0347         clearAllMappings();
0348         vi_global->mappings()->add(Mappings::InsertModeMapping, "a", "xyz", Mappings::NonRecursive);
0349         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "inose<esc>", Mappings::NonRecursive);
0350         DoTest("foo", "ia\\esc", "xyzfoo");
0351 
0352         // Recursion for Insert mode.
0353         clearAllMappings();
0354         vi_global->mappings()->add(Mappings::InsertModeMapping, "b", "c", Mappings::NonRecursive);
0355         vi_global->mappings()->add(Mappings::InsertModeMapping, "a", "b", Mappings::NonRecursive);
0356         DoTest("", "ia\\esc", "b");
0357         clearAllMappings();
0358         vi_global->mappings()->add(Mappings::InsertModeMapping, "b", "c", Mappings::NonRecursive);
0359         vi_global->mappings()->add(Mappings::InsertModeMapping, "a", "b", Mappings::Recursive);
0360         DoTest("", "ia\\esc", "c");
0361 
0362         clearAllMappings();
0363         // Clear mappings for Insert mode.
0364         vi_global->mappings()->add(Mappings::InsertModeMapping, "a", "b", Mappings::NonRecursive);
0365         vi_global->mappings()->clear(Mappings::InsertModeMapping);
0366         DoTest("", "ia\\esc", "a");
0367     }
0368 
0369     {
0370         EmulatedCommandBarSetUpAndTearDown vimStyleCommandBarTestsSetUpAndTearDown(vi_input_mode, kate_view, mainWindow);
0371         // Can have mappings in Emulated Command Bar.
0372         clearAllMappings();
0373         vi_global->mappings()->add(Mappings::CommandModeMapping, "a", "xyz", Mappings::NonRecursive);
0374         DoTest(" a xyz", "/a\\enterrX", " a Xyz");
0375         // Use mappings from Normal mode as soon as we exit command bar via Enter.
0376         vi_global->mappings()->add(Mappings::NormalModeMapping, "a", "ixyz<c-c>", Mappings::NonRecursive);
0377         DoTest(" a xyz", "/a\\entera", " a xyzxyz");
0378         // Multiple mappings.
0379         vi_global->mappings()->add(Mappings::CommandModeMapping, "b", "123", Mappings::NonRecursive);
0380         DoTest("  xyz123", "/ab\\enterrX", "  Xyz123");
0381         // Recursive mappings.
0382         vi_global->mappings()->add(Mappings::CommandModeMapping, "b", "a", Mappings::Recursive);
0383         DoTest("  xyz", "/b\\enterrX", "  Xyz");
0384         // Can clear all.
0385         vi_global->mappings()->clear(Mappings::CommandModeMapping);
0386         DoTest("  ab xyz xyz123", "/ab\\enterrX", "  Xb xyz xyz123");
0387     }
0388 
0389     // Test that not *both* of the mapping and the mapped keys are logged for repetition via "."
0390     clearAllMappings();
0391     vi_global->mappings()->add(Mappings::NormalModeMapping, "ixyz", "iabc", Mappings::NonRecursive);
0392     vi_global->mappings()->add(Mappings::NormalModeMapping, "gl", "%", Mappings::NonRecursive);
0393     DoTest("", "ixyz\\esc.", "ababcc");
0394     DoTest("foo()X\nbarxyz()Y", "cglbaz\\escggj.", "bazX\nbazY");
0395 
0396     // Regression test for a crash when executing a mapping that switches to Normal mode.
0397     clearAllMappings();
0398     vi_global->mappings()->add(Mappings::VisualModeMapping, "h", "d", Mappings::Recursive);
0399     DoTest("foo", "vlh", "o");
0400 
0401     {
0402         // Test that we can set/ unset mappings from the command-line.
0403         clearAllMappings();
0404         DoTest("", "\\:nn foo ibar<esc>\\foo", "bar");
0405 
0406         // "nn" is not recursive.
0407         clearAllMappings();
0408         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0409         DoTest("xxx", "\\:nn foo l\\foorX", "xXx");
0410 
0411         // "no" is not recursive.
0412         clearAllMappings();
0413         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0414         DoTest("xxx", "\\:no foo l\\foorX", "xXx");
0415 
0416         // "noremap" is not recursive.
0417         clearAllMappings();
0418         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0419         DoTest("xxx", "\\:noremap foo l\\foorX", "xXx");
0420 
0421         // "nm" is recursive.
0422         clearAllMappings();
0423         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0424         DoTest("xxx", "\\:nm foo l\\foorX", "abXxxx");
0425 
0426         // "nmap" is recursive.
0427         clearAllMappings();
0428         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0429         DoTest("xxx", "\\:nmap foo l\\foorX", "abXxxx");
0430 
0431         // Unfortunately, "map" is a reserved word :/
0432         clearAllMappings();
0433         vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "iabc<esc>", Mappings::NonRecursive);
0434         DoTest("xxx", "\\:map foo l\\foorX", "abXxxx", ShouldFail, "'map' is reserved for other stuff in Kate command line");
0435 
0436         // nunmap works in normal mode.
0437         clearAllMappings();
0438         vi_global->mappings()->add(Mappings::NormalModeMapping, "w", "ciwabc<esc>", Mappings::NonRecursive);
0439         vi_global->mappings()->add(Mappings::NormalModeMapping, "b", "ciwxyz<esc>", Mappings::NonRecursive);
0440         DoTest(" 123 456 789", "\\:nunmap b\\WWwbrX", " 123 Xbc 789");
0441 
0442         // nmap and nunmap whose "from" is a complex encoded expression.
0443         clearAllMappings();
0444         BeginTest("123");
0445         TestPressKey("\\:nmap <c-9> ciwxyz<esc>\\");
0446         TestPressKey("\\ctrl-9");
0447         FinishTest("xyz");
0448         BeginTest("123");
0449         TestPressKey("\\:nunmap <c-9>\\");
0450         TestPressKey("\\ctrl-9");
0451         FinishTest("123");
0452 
0453         // vmap works in Visual mode and is recursive.
0454         clearAllMappings();
0455         vi_global->mappings()->add(Mappings::VisualModeMapping, "l", "d", Mappings::NonRecursive);
0456         DoTest("abco", "\\:vmap foo l\\v\\rightfoogU", "co");
0457 
0458         // vmap does not work in Normal mode.
0459         clearAllMappings();
0460         DoTest("xxx", "\\:vmap foo l\\foorX", "xxx\nrX");
0461 
0462         // vm works in Visual mode and is recursive.
0463         clearAllMappings();
0464         vi_global->mappings()->add(Mappings::VisualModeMapping, "l", "d", Mappings::NonRecursive);
0465         DoTest("abco", "\\:vm foo l\\v\\rightfoogU", "co");
0466 
0467         // vn works in Visual mode and is not recursive.
0468         clearAllMappings();
0469         vi_global->mappings()->add(Mappings::VisualModeMapping, "l", "d", Mappings::NonRecursive);
0470         DoTest("abco", "\\:vn foo l\\v\\rightfoogU", "ABCo");
0471 
0472         // vnoremap works in Visual mode and is not recursive.
0473         clearAllMappings();
0474         vi_global->mappings()->add(Mappings::VisualModeMapping, "l", "d", Mappings::NonRecursive);
0475         DoTest("abco", "\\:vnoremap foo l\\v\\rightfoogU", "ABCo");
0476 
0477         // vunmap works in Visual Mode.
0478         clearAllMappings();
0479         vi_global->mappings()->add(Mappings::VisualModeMapping, "l", "w", Mappings::NonRecursive);
0480         vi_global->mappings()->add(Mappings::VisualModeMapping, "gU", "2b", Mappings::NonRecursive);
0481         DoTest("foo bar xyz", "\\:vunmap gU\\wvlgUd", "foo BAR Xyz");
0482 
0483         // imap works in Insert mode and is recursive.
0484         clearAllMappings();
0485         vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "d", Mappings::NonRecursive);
0486         DoTest("", "\\:imap foo l\\ifoo\\esc", "d");
0487 
0488         // im works in Insert mode and is recursive.
0489         clearAllMappings();
0490         vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "d", Mappings::NonRecursive);
0491         DoTest("", "\\:im foo l\\ifoo\\esc", "d");
0492 
0493         // ino works in Insert mode and is not recursive.
0494         clearAllMappings();
0495         vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "d", Mappings::NonRecursive);
0496         DoTest("", "\\:ino foo l\\ifoo\\esc", "l");
0497 
0498         // inoremap works in Insert mode and is not recursive.
0499         clearAllMappings();
0500         vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "d", Mappings::NonRecursive);
0501         DoTest("", "\\:inoremap foo l\\ifoo\\esc", "l");
0502 
0503         // iunmap works in Insert mode.
0504         clearAllMappings();
0505         vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "d", Mappings::NonRecursive);
0506         vi_global->mappings()->add(Mappings::InsertModeMapping, "m", "e", Mappings::NonRecursive);
0507         DoTest("", "\\:iunmap l\\ilm\\esc", "le");
0508 
0509         {
0510             EmulatedCommandBarSetUpAndTearDown vimStyleCommandBarTestsSetUpAndTearDown(vi_input_mode, kate_view, mainWindow);
0511             // cmap works in emulated command bar and is recursive.
0512             // NOTE: need to do the cmap call using the direct execution (i.e. \\:cmap blah blah\\), *not* using
0513             // the emulated command bar (:cmap blah blah\\enter), as this will be subject to mappings, which
0514             // can interfere with the tests!
0515             clearAllMappings();
0516             vi_global->mappings()->add(Mappings::CommandModeMapping, "l", "d", Mappings::NonRecursive);
0517             DoTest(" l d foo", "\\:cmap foo l\\/foo\\enterrX", " l X foo");
0518 
0519             // cm works in emulated command bar and is recursive.
0520             clearAllMappings();
0521             vi_global->mappings()->add(Mappings::CommandModeMapping, "l", "d", Mappings::NonRecursive);
0522             DoTest(" l d foo", "\\:cm foo l\\/foo\\enterrX", " l X foo");
0523 
0524             // cnoremap works in emulated command bar and is recursive.
0525             clearAllMappings();
0526             vi_global->mappings()->add(Mappings::CommandModeMapping, "l", "d", Mappings::NonRecursive);
0527             DoTest(" l d foo", "\\:cnoremap foo l\\/foo\\enterrX", " X d foo");
0528 
0529             // cno works in emulated command bar and is recursive.
0530             clearAllMappings();
0531             vi_global->mappings()->add(Mappings::CommandModeMapping, "l", "d", Mappings::NonRecursive);
0532             DoTest(" l d foo", "\\:cno foo l\\/foo\\enterrX", " X d foo");
0533 
0534             // cunmap works in emulated command bar.
0535             clearAllMappings();
0536             vi_global->mappings()->add(Mappings::CommandModeMapping, "l", "d", Mappings::NonRecursive);
0537             vi_global->mappings()->add(Mappings::CommandModeMapping, "m", "e", Mappings::NonRecursive);
0538             DoTest(" de le", "\\:cunmap l\\/lm\\enterrX", " de Xe");
0539         }
0540 
0541         // Can use <space> to signify a space.
0542         clearAllMappings();
0543         DoTest("", "\\:nn h<space> i<space>a<space>b<esc>\\h ", " a b");
0544     }
0545 
0546     // More recursion tests - don't lose characters from a Recursive mapping if it looks like they might
0547     // be part of a different mapping (but end up not being so).
0548     // (Here, the leading "i" in "irecursive<c-c>" could be part of the mapping "ihello<c-c>").
0549     clearAllMappings();
0550     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>", Mappings::Recursive);
0551     vi_global->mappings()->add(Mappings::NormalModeMapping, "ihello<c-c>", "irecursive<c-c>", Mappings::Recursive);
0552     DoTest("", "'", "recursive");
0553 
0554     // Capslock in insert mode is not handled by Vim nor by KateViewInternal, and ends up
0555     // being sent to KateViInputModeManager::handleKeypress twice (it could be argued that this is
0556     // incorrect behaviour on the part of KateViewInternal), which can cause infinite
0557     // recursion if we are not careful about identifying replayed rejected keypresses.
0558     BeginTest("foo bar");
0559     TestPressKey("i");
0560     QKeyEvent *capslockKeyPress = new QKeyEvent(QEvent::KeyPress, Qt::Key_CapsLock, Qt::NoModifier);
0561     QApplication::postEvent(kate_view->focusProxy(), capslockKeyPress);
0562     QApplication::sendPostedEvents();
0563     FinishTest("foo bar");
0564 
0565     // Mapping the u and the U commands to other keys.
0566     clearAllMappings();
0567     vi_global->mappings()->add(Mappings::NormalModeMapping, "t", "u", Mappings::Recursive);
0568     vi_global->mappings()->add(Mappings::NormalModeMapping, "r", "U", Mappings::Recursive);
0569     DoTest("", "ihello\\esct", "");
0570     DoTest("", "ihello\\esctr", "hello");
0571 
0572     // <nop>
0573     clearAllMappings();
0574     vi_global->mappings()->add(Mappings::NormalModeMapping, "l", "<nop>", Mappings::Recursive);
0575     DoTest("Hello", "lrr", "rello");
0576     clearAllMappings();
0577     vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "<nop>", Mappings::Recursive);
0578     DoTest("Hello", "sl\\esc", "ello");
0579     clearAllMappings();
0580     vi_global->mappings()->add(Mappings::InsertModeMapping, "l", "<nop>abc", Mappings::Recursive);
0581     DoTest("Hello", "sl\\esc", "abcello");
0582 
0583     // Clear mappings for subsequent tests.
0584     clearAllMappings();
0585 
0586     {
0587         // Test that g<up> and g<down> work as gk and gj (BUG: 418486)
0588         ensureKateViewVisible(); // Needs to be visible in order for virtual lines to make sense.
0589         KateViewConfig::global()->setDynWordWrap(true);
0590 
0591         BeginTest(multiVirtualLineText);
0592         TestPressKey("gjrX");
0593         const QString expectedAfterVirtualLineDownAndChange = kate_document->text();
0594         QVERIFY(expectedAfterVirtualLineDownAndChange.contains("X") && !expectedAfterVirtualLineDownAndChange.startsWith('X'));
0595         FinishTest(expectedAfterVirtualLineDownAndChange);
0596 
0597         BeginTest(multiVirtualLineText);
0598         TestPressKey("g\\downrX");
0599         const QString expectedAfterVirtualLineDownAndChangeCursor = kate_document->text();
0600         QVERIFY(expectedAfterVirtualLineDownAndChangeCursor == expectedAfterVirtualLineDownAndChange);
0601         FinishTest(expectedAfterVirtualLineDownAndChangeCursor);
0602 
0603         BeginTest(multiVirtualLineText);
0604         TestPressKey("gkrX");
0605         const QString expectedAfterVirtualLineUpAndChange = kate_document->text();
0606         QVERIFY(expectedAfterVirtualLineUpAndChange.contains("X") && !expectedAfterVirtualLineUpAndChange.endsWith('X'));
0607         FinishTest(expectedAfterVirtualLineUpAndChange);
0608 
0609         BeginTest(multiVirtualLineText);
0610         TestPressKey("g\\uprX");
0611         const QString expectedAfterVirtualLineUpAndChangeCursor = kate_document->text();
0612         QVERIFY(expectedAfterVirtualLineUpAndChangeCursor == expectedAfterVirtualLineUpAndChange);
0613         FinishTest(expectedAfterVirtualLineUpAndChangeCursor);
0614 
0615         KateViewConfig::global()->setDynWordWrap(false);
0616     }
0617 }
0618 
0619 void KeysTest::LeaderTests()
0620 {
0621     // Clean slate.
0622     KateViewConfig::global()->setValue(KateViewConfig::ViInputModeStealKeys, true);
0623     clearAllMappings();
0624 
0625     // By default the backslash character is the leader. The default leader
0626     // is picked from the config. If we don't want to mess this from other
0627     // tests, it's better if we mock the config.
0628     const QString viTestKConfigFileName = QStringLiteral("vimodetest-leader-katevimoderc");
0629     KConfig viTestKConfig(viTestKConfigFileName);
0630     vi_global->mappings()->setLeader(QChar());
0631     vi_global->readConfig(&viTestKConfig);
0632     vi_global->mappings()->add(Mappings::NormalModeMapping, "<leader>i", "ii", Mappings::Recursive);
0633     DoTest("", "\\\\i", "i");
0634 
0635     // We can change the leader and it will work.
0636     clearAllMappings();
0637     vi_global->readConfig(&viTestKConfig);
0638     vi_global->mappings()->setLeader(QChar::fromLatin1(','));
0639     vi_global->mappings()->add(Mappings::NormalModeMapping, "<leader>i", "ii", Mappings::Recursive);
0640     DoTest("", ",i", "i");
0641 
0642     // Mixing up the <leader> with its value.
0643     clearAllMappings();
0644     vi_global->readConfig(&viTestKConfig);
0645     vi_global->mappings()->setLeader(QChar::fromLatin1(','));
0646     vi_global->mappings()->add(Mappings::NormalModeMapping, "<leader>,", "ii", Mappings::Recursive);
0647     DoTest("", ",,", "i");
0648     vi_global->mappings()->add(Mappings::NormalModeMapping, ",<leader>", "ii", Mappings::Recursive);
0649     DoTest("", ",,", "i");
0650 
0651     // It doesn't work outside normal mode.
0652     clearAllMappings();
0653     vi_global->readConfig(&viTestKConfig);
0654     vi_global->mappings()->setLeader(QChar::fromLatin1(','));
0655     vi_global->mappings()->add(Mappings::InsertModeMapping, "<leader>i", "ii", Mappings::Recursive);
0656     DoTest("", "i,ii", ",ii");
0657 
0658     // Clear mappings for subsequent tests.
0659     clearAllMappings();
0660 }
0661 
0662 void KeysTest::ParsingTests()
0663 {
0664     // BUG #298726
0665     const QChar char_o_diaeresis(246);
0666 
0667     // Test that we can correctly translate finnish key ö
0668     QKeyEvent *k = new QKeyEvent(QEvent::KeyPress, 214, Qt::NoModifier, 47, 246, 16400, char_o_diaeresis);
0669     QCOMPARE(KeyParser::self()->KeyEventToQChar(*k), QChar(246));
0670 
0671     // Test that it can be used in mappings
0672     clearAllMappings();
0673     vi_global->mappings()->add(Mappings::NormalModeMapping, char_o_diaeresis, "ifoo", Mappings::Recursive);
0674     DoTest("hello", QString("ll%1bar").arg(char_o_diaeresis), "hefoobarllo");
0675 
0676     // Test that <cr> is parsed like <enter>
0677     QCOMPARE(KeyParser::self()->vi2qt("cr"), int(Qt::Key_Enter));
0678     const QString &enter = KeyParser::self()->encodeKeySequence(QLatin1String("<cr>"));
0679     QCOMPARE(KeyParser::self()->decodeKeySequence(enter), QLatin1String("<cr>"));
0680 }
0681 
0682 void KeysTest::AltGr()
0683 {
0684     QKeyEvent *altGrDown;
0685     QKeyEvent *altGrUp;
0686     // Test Alt-gr still works - this isn't quite how things work in "real-life": in real-life, something like
0687     // Alt-gr+7 would be a "{", but I don't think this can be reproduced without sending raw X11
0688     // keypresses to Qt, so just duplicate the keypress events we would receive if we pressed
0689     // Alt-gr+7 (that is: Alt-gr down; "{"; Alt-gr up).
0690 
0691     // Ensure we have auto brackets off, or the test will fail
0692     kate_view->config()->setValue(KateViewConfig::AutoBrackets, false);
0693 
0694     BeginTest("");
0695     TestPressKey("i");
0696     altGrDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_AltGr, Qt::NoModifier);
0697     QApplication::postEvent(kate_view->focusProxy(), altGrDown);
0698     QApplication::sendPostedEvents();
0699     // Not really Alt-gr and 7, but this is the key event that is reported by Qt if we press that.
0700     QKeyEvent *altGrAnd7 = new QKeyEvent(QEvent::KeyPress, Qt::Key_BraceLeft, Qt::GroupSwitchModifier, "{");
0701     QApplication::postEvent(kate_view->focusProxy(), altGrAnd7);
0702     QApplication::sendPostedEvents();
0703     altGrUp = new QKeyEvent(QEvent::KeyRelease, Qt::Key_AltGr, Qt::NoModifier);
0704     QApplication::postEvent(kate_view->focusProxy(), altGrUp);
0705     QApplication::sendPostedEvents();
0706     TestPressKey("\\ctrl-c");
0707     FinishTest("{");
0708 
0709     // French Bepo keyabord AltGr + Shift + s = Ă™ = Unicode(0x00D9);
0710     const QString ugrave = QString(QChar(0x00D9));
0711     BeginTest("");
0712     TestPressKey("i");
0713     altGrDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_AltGr, Qt::NoModifier);
0714     QApplication::postEvent(kate_view->focusProxy(), altGrDown);
0715     QApplication::sendPostedEvents();
0716     altGrDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::ShiftModifier | Qt::GroupSwitchModifier);
0717     QApplication::postEvent(kate_view->focusProxy(), altGrDown);
0718     QApplication::sendPostedEvents();
0719     QKeyEvent *altGrAndUGrave = new QKeyEvent(QEvent::KeyPress, Qt::Key_Ugrave, Qt::ShiftModifier | Qt::GroupSwitchModifier, ugrave);
0720     qDebug() << QString("%1").arg(altGrAndUGrave->modifiers(), 10, 16);
0721     QApplication::postEvent(kate_view->focusProxy(), altGrAndUGrave);
0722     QApplication::sendPostedEvents();
0723     altGrUp = new QKeyEvent(QEvent::KeyRelease, Qt::Key_AltGr, Qt::NoModifier);
0724     QApplication::postEvent(kate_view->focusProxy(), altGrUp);
0725     QApplication::sendPostedEvents();
0726     FinishTest(ugrave);
0727 }
0728 
0729 void KeysTest::MacroTests()
0730 {
0731     // Update the status on qa.
0732     const QString macroIsRecordingStatus = QLatin1String("(") + i18n("recording") + QLatin1String(")");
0733     clearAllMacros();
0734     BeginTest("");
0735     QVERIFY(!kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0736     TestPressKey("qa");
0737     QVERIFY(kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0738     TestPressKey("q");
0739     QVERIFY(!kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0740     FinishTest("");
0741 
0742     // The closing "q" is not treated as the beginning of a new "begin recording macro" command.
0743     clearAllMacros();
0744     BeginTest("foo");
0745     TestPressKey("qaqa");
0746     QVERIFY(!kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0747     TestPressKey("xyz\\esc");
0748     FinishTest("fxyzoo");
0749 
0750     // Record and playback a single keypress into macro register "a".
0751     clearAllMacros();
0752     DoTest("foo bar", "qawqgg@arX", "foo Xar");
0753     // Two macros - make sure the old one is cleared.
0754     clearAllMacros();
0755     DoTest("123 foo bar xyz", "qawqqabqggww@arX", "123 Xoo bar xyz");
0756 
0757     // Update the status on qb.
0758     clearAllMacros();
0759     BeginTest("");
0760     QVERIFY(!kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0761     TestPressKey("qb");
0762     QVERIFY(kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0763     TestPressKey("q");
0764     QVERIFY(!kate_view->viewModeHuman().contains(macroIsRecordingStatus));
0765     FinishTest("");
0766 
0767     // Record and playback a single keypress into macro register "b".
0768     clearAllMacros();
0769     DoTest("foo bar", "qbwqgg@brX", "foo Xar");
0770 
0771     // More complex macros.
0772     clearAllMacros();
0773     DoTest("foo", "qcrXql@c", "XXo");
0774 
0775     // Re-recording a macro should only clear that macro.
0776     clearAllMacros();
0777     DoTest("foo 123", "qaraqqbrbqqbrBqw@a", "Boo a23");
0778 
0779     // Empty macro clears it.
0780     clearAllMacros();
0781     DoTest("", "qaixyz\\ctrl-cqqaq@a", "xyz");
0782 
0783     // Hold two macros in memory simultanenously so both can be played.
0784     clearAllMacros();
0785     DoTest("foo 123", "qaraqqbrbqw@al@b", "boo ab3");
0786 
0787     // Do more complex things, including switching modes and using ctrl codes.
0788     clearAllMacros();
0789     DoTest("foo bar", "qainose\\ctrl-c~qw@a", "nosEfoo nosEbar");
0790     clearAllMacros();
0791     DoTest("foo bar", "qayiwinose\\ctrl-r0\\ctrl-c~qw@a", "nosefoOfoo nosebaRbar");
0792     clearAllMacros();
0793     DoTest("foo bar", "qavldqw@a", "o r");
0794     // Make sure we can use "q" in insert mode while recording a macro.
0795     clearAllMacros();
0796     DoTest("foo bar", "qaiqueequeg\\ctrl-cqw@a", "queequegfoo queequegbar");
0797     // Can invoke a macro in Visual Mode.
0798     clearAllMacros();
0799     DoTest("foo bar", "qa~qvlll@a", "FOO Bar");
0800     // Invoking a macro in Visual Mode does not exit Visual Mode.
0801     clearAllMacros();
0802     DoTest("foo bar", "qallqggv@a~", "FOO bar");
0803     ;
0804     // Can record & macros in Visual Mode for playback in Normal Mode.
0805     clearAllMacros();
0806     DoTest("foo bar", "vqblq\\ctrl-c@b~", "foO bar");
0807     // Recording a macro in Visual Mode does not exit Visual Mode.
0808     clearAllMacros();
0809     DoTest("foo bar", "vqblql~", "FOO bar");
0810     // Recognize correctly numbered registers
0811     clearAllMacros();
0812     DoTest("foo", "q1iX\\escq@1", "XXfoo");
0813 
0814     {
0815         // Ensure that we can call emulated command bar searches, and that we don't record
0816         // synthetic keypresses.
0817         EmulatedCommandBarSetUpAndTearDown vimStyleCommandBarTestsSetUpAndTearDown(vi_input_mode, kate_view, mainWindow);
0818         clearAllMacros();
0819         DoTest("foo bar\nblank line", "qa/bar\\enterqgg@arX", "foo Xar\nblank line");
0820         // More complex searching stuff.
0821         clearAllMacros();
0822         DoTest("foo 123foo123\nbar 123bar123", "qayiw/\\ctrl-r0\\enterrXqggj@a", "foo 123Xoo123\nbar 123Xar123");
0823     }
0824 
0825     // Expand mappings,  but don't do *both* original keypresses and executed keypresses.
0826     clearAllMappings();
0827     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>", Mappings::Recursive);
0828     clearAllMacros();
0829     DoTest("", "qa'q@a", "hellhelloo");
0830     // Actually, just do the mapped keypresses, not the executed mappings (like Vim).
0831     clearAllMappings();
0832     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>", Mappings::Recursive);
0833     clearAllMacros();
0834     BeginTest("");
0835     TestPressKey("qa'q");
0836     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "igoodbye<c-c>", Mappings::Recursive);
0837     TestPressKey("@a");
0838     FinishTest("hellgoodbyeo");
0839     // Clear the "stop recording macro keypresses because we're executing a mapping" when the mapping has finished
0840     // executing.
0841     clearAllMappings();
0842     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>", Mappings::Recursive);
0843     clearAllMacros();
0844     DoTest("", "qa'ixyz\\ctrl-cq@a", "hellxyhellxyzozo");
0845     // ... make sure that *all* mappings have finished, though: take into account recursion.
0846     clearAllMappings();
0847     clearAllMacros();
0848     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>", Mappings::Recursive);
0849     vi_global->mappings()->add(Mappings::NormalModeMapping, "ihello<c-c>", "irecursive<c-c>", Mappings::Recursive);
0850     DoTest("", "qa'q@a", "recursivrecursivee");
0851     clearAllMappings();
0852     clearAllMacros();
0853     vi_global->mappings()->add(Mappings::NormalModeMapping, "'", "ihello<c-c>ixyz<c-c>", Mappings::Recursive);
0854     vi_global->mappings()->add(Mappings::NormalModeMapping, "ihello<c-c>", "irecursive<c-c>", Mappings::Recursive);
0855     DoTest("", "qa'q@a", "recursivxyrecursivxyzeze");
0856 
0857     clearAllMappings();
0858     clearAllMacros();
0859     // Don't save the trailing "q" with macros, and also test that we can call one macro from another,
0860     // without one of the macros being repeated.
0861     DoTest("", "qaixyz\\ctrl-cqqb@aq@b", "xyxyxyzzz");
0862     clearAllMappings();
0863     clearAllMacros();
0864     // More stringent test that macros called from another macro aren't repeated - requires more nesting
0865     // of macros ('a' calls 'b' calls 'c').
0866     DoTest("",
0867            "qciC\\ctrl-cq"
0868            "qb@ciB\\ctrl-cq"
0869            "qa@biA\\ctrl-cq"
0870            "dd@a",
0871            "ABC");
0872     // Don't crash if we invoke a non-existent macro.
0873     clearAllMacros();
0874     DoTest("", "@x", "");
0875     // Make macros "counted".
0876     clearAllMacros();
0877     DoTest("XXXX\nXXXX\nXXXX\nXXXX", "qarOljq3@a", "OXXX\nXOXX\nXXOX\nXXXO");
0878 
0879     // A macro can be undone with one undo.
0880     clearAllMacros();
0881     DoTest("foo bar", "qaciwxyz\\ctrl-ci123\\ctrl-cqw@au", "xy123z bar");
0882     // As can a counted macro.
0883     clearAllMacros();
0884     DoTest("XXXX\nXXXX\nXXXX\nXXXX", "qarOljq3@au", "OXXX\nXXXX\nXXXX\nXXXX");
0885 
0886     {
0887         EmulatedCommandBarSetUpAndTearDown vimStyleCommandBarTestsSetUpAndTearDown(vi_input_mode, kate_view, mainWindow);
0888         // Make sure we can macro-ise an interactive sed replace.
0889         clearAllMacros();
0890         DoTest("foo foo foo foo\nfoo foo foo foo", "qa:s/foo/bar/gc\\enteryynyAdone\\escqggj@a", "bar bar foo bardone\nbar bar foo bardone");
0891         // Make sure the closing "q" in the interactive sed replace isn't mistaken for a macro's closing "q".
0892         clearAllMacros();
0893         DoTest("foo foo foo foo\nfoo foo foo foo", "qa:s/foo/bar/gc\\enteryyqAdone\\escqggj@a", "bar bar foo foodone\nbar bar foo foodone");
0894         clearAllMacros();
0895         DoTest("foo foo foo foo\nfoo foo foo foo", "qa:s/foo/bar/gc\\enteryyqqAdone\\escggj@aAdone\\esc", "bar bar foo foodone\nbar bar foo foodone");
0896     }
0897 
0898     clearAllMappings();
0899     clearAllMacros();
0900     // Expand mapping in an executed macro, if the invocation of the macro "@a" is a prefix of a mapping M, and
0901     // M ends up not being triggered.
0902     vi_global->mappings()->add(Mappings::NormalModeMapping, "@aaaa", "idummy<esc>", Mappings::Recursive);
0903     vi_global->mappings()->add(Mappings::NormalModeMapping, "S", "ixyz<esc>", Mappings::Recursive);
0904     DoTest("", "qaSq@abrX", "Xyxyzz");
0905     clearAllMappings();
0906 
0907     // Can't play old version of macro while recording new version.
0908     clearAllMacros();
0909     DoTest("", "qaiaaa\\ctrl-cqqa@aq", "aaa");
0910 
0911     // Can't play the macro while recording it.
0912     clearAllMacros();
0913     DoTest("", "qaiaaa\\ctrl-c@aq", "aaa");
0914 
0915     // "@@" plays back macro "a" if "a" was the last macro we played back.
0916     clearAllMacros();
0917     DoTest("", "qaia\\ctrl-cq@adiw@@", "a");
0918     // "@@" plays back macro "b" if "b" was the last macro we played back.
0919     clearAllMacros();
0920     DoTest("", "qbib\\ctrl-cq@bdiw@@", "b");
0921     // "@@" does nothing if no macro was previously played.
0922     clearAllMacros();
0923     DoTest("", "qaia\\ctrl-cq@@", "a");
0924     // Nitpick: "@@" replays the last played back macro, even if that macro had not been defined
0925     // when it was first played back.
0926     clearAllMacros();
0927     DoTest("", "@aqaia\\ctrl-cq@@", "aa");
0928     // "@@" is counted.
0929     clearAllMacros();
0930     DoTest("", "qaia\\ctrl-cq@adiw5@@", "aaaaa");
0931 
0932     // Test that we can save and restore a single macro.
0933     const QString viTestKConfigFileName = "vimodetest-katevimoderc";
0934     {
0935         clearAllMacros();
0936         KConfig viTestKConfig(viTestKConfigFileName);
0937         BeginTest("");
0938         TestPressKey("qaia\\ctrl-cq");
0939         vi_global->writeConfig(&viTestKConfig);
0940         viTestKConfig.sync();
0941         // Overwrite macro "a", and clear the document.
0942         TestPressKey("qaidummy\\ctrl-cqdd");
0943         vi_global->readConfig(&viTestKConfig);
0944         TestPressKey("@a");
0945         FinishTest("a");
0946     }
0947 
0948     {
0949         // Test that we can save and restore several macros.
0950         clearAllMacros();
0951         const QString viTestKConfigFileName = "vimodetest-katevimoderc";
0952         KConfig viTestKConfig(viTestKConfigFileName);
0953         BeginTest("");
0954         TestPressKey("qaia\\ctrl-cqqbib\\ctrl-cq");
0955         vi_global->writeConfig(&viTestKConfig);
0956         viTestKConfig.sync();
0957         // Overwrite macros "a" & "b", and clear the document.
0958         TestPressKey("qaidummy\\ctrl-cqqbidummy\\ctrl-cqdd");
0959         vi_global->readConfig(&viTestKConfig);
0960         TestPressKey("@a@b");
0961         FinishTest("ba");
0962     }
0963 
0964     // Ensure that we don't crash when a "repeat change" occurs in a macro we execute.
0965     clearAllMacros();
0966     DoTest("", "qqixyz\\ctrl-c.q@qdd", "");
0967     // Don't record both the "." *and* the last-change keypresses when recording a macro;
0968     // just record the "."
0969     clearAllMacros();
0970     DoTest("", "ixyz\\ctrl-cqq.qddi123\\ctrl-c@q", "121233");
0971 
0972     // Test dealing with auto-completion.
0973     FakeCodeCompletionTestModel *fakeCodeCompletionModel = new FakeCodeCompletionTestModel(kate_view);
0974     kate_view->registerCompletionModel(fakeCodeCompletionModel);
0975     // Completion tests require a visible kate_view.
0976     ensureKateViewVisible();
0977     // Want Vim mode to intercept ctrl-p, ctrl-n shortcuts, etc.
0978     const bool oldStealKeys = KateViewConfig::global()->viInputModeStealKeys();
0979     KateViewConfig::global()->setValue(KateViewConfig::ViInputModeStealKeys, true);
0980 
0981     // Don't invoke completion via ctrl-space when replaying a macro.
0982     clearAllMacros();
0983     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
0984     fakeCodeCompletionModel->setFailTestOnInvocation(false);
0985     BeginTest("");
0986     TestPressKey("qqico\\ctrl- \\ctrl-cq");
0987     fakeCodeCompletionModel->setFailTestOnInvocation(true);
0988     TestPressKey("@q");
0989     FinishTest("ccoo");
0990 
0991     // Don't invoke completion via ctrl-p when replaying a macro.
0992     clearAllMacros();
0993     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
0994     fakeCodeCompletionModel->setFailTestOnInvocation(false);
0995     BeginTest("");
0996     TestPressKey("qqico\\ctrl-p\\ctrl-cq");
0997     fakeCodeCompletionModel->setFailTestOnInvocation(true);
0998     TestPressKey("@q");
0999     FinishTest("ccoo");
1000 
1001     // Don't invoke completion via ctrl-n when replaying a macro.
1002     clearAllMacros();
1003     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1004     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1005     BeginTest("");
1006     TestPressKey("qqico\\ctrl-n\\ctrl-cq");
1007     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1008     TestPressKey("@q");
1009     FinishTest("ccoo");
1010 
1011     // An "enter" in insert mode when no completion is activated (so, a newline)
1012     // is treated as a newline when replayed as a macro, even if completion is
1013     // active when the "enter" is replayed.
1014     clearAllMacros();
1015     fakeCodeCompletionModel->setCompletions(QStringList()); // Prevent any completions.
1016     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1017     fakeCodeCompletionModel->clearWasInvoked();
1018     BeginTest("");
1019     TestPressKey("qqicompl\\enterX\\ctrl-cqdddd");
1020     QVERIFY(!fakeCodeCompletionModel->wasInvoked()); // Error in test setup!
1021     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1022     fakeCodeCompletionModel->forceInvocationIfDocTextIs("compl");
1023     fakeCodeCompletionModel->clearWasInvoked();
1024     TestPressKey("@q");
1025     QVERIFY(fakeCodeCompletionModel->wasInvoked()); // Error in test setup!
1026     fakeCodeCompletionModel->doNotForceInvocation();
1027     FinishTest("compl\nX");
1028     // Same for "return".
1029     clearAllMacros();
1030     fakeCodeCompletionModel->setCompletions(QStringList()); // Prevent any completions.
1031     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1032     fakeCodeCompletionModel->clearWasInvoked();
1033     BeginTest("");
1034     TestPressKey("qqicompl\\returnX\\ctrl-cqdddd");
1035     QVERIFY(!fakeCodeCompletionModel->wasInvoked()); // Error in test setup!
1036     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1037     fakeCodeCompletionModel->forceInvocationIfDocTextIs("compl");
1038     fakeCodeCompletionModel->clearWasInvoked();
1039     TestPressKey("@q");
1040     QVERIFY(fakeCodeCompletionModel->wasInvoked()); // Error in test setup!
1041     fakeCodeCompletionModel->doNotForceInvocation();
1042     FinishTest("compl\nX");
1043 
1044     // If we do a plain-text completion in a macro, this should be repeated when we replay it.
1045     clearAllMacros();
1046     BeginTest("");
1047     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1048     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1049     TestPressKey("qqicompl\\ctrl- \\enter\\ctrl-cq");
1050     kate_document->clear();
1051     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1052     TestPressKey("@q");
1053     FinishTest("completionA");
1054 
1055     // Should replace only the current word when we repeat the completion.
1056     clearAllMacros();
1057     BeginTest("compl");
1058     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1059     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1060     TestPressKey("qqfla\\ctrl- \\enter\\ctrl-cq");
1061     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1062     kate_document->setText("(compl)");
1063     TestPressKey("gg@q");
1064     FinishTest("(completionA)");
1065 
1066     // Tail-clearing completions should be undoable with one undo.
1067     clearAllMacros();
1068     BeginTest("compl");
1069     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1070     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1071     TestPressKey("qqfla\\ctrl- \\enter\\ctrl-cq");
1072     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1073     kate_document->setText("(compl)");
1074     TestPressKey("gg@qu");
1075     FinishTest("(compl)");
1076 
1077     // Should be able to store multiple completions.
1078     clearAllMacros();
1079     BeginTest("");
1080     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1081     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1082     TestPressKey("qqicom\\ctrl-p\\enter com\\ctrl-p\\ctrl-p\\enter\\ctrl-cq");
1083     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1084     TestPressKey("dd@q");
1085     FinishTest("completionC completionB");
1086 
1087     // Clear the completions for a macro when we start recording.
1088     clearAllMacros();
1089     BeginTest("");
1090     fakeCodeCompletionModel->setCompletions({"completionOrig"});
1091     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1092     TestPressKey("qqicom\\ctrl- \\enter\\ctrl-cq");
1093     fakeCodeCompletionModel->setCompletions({"completionSecond"});
1094     TestPressKey("ddqqicom\\ctrl- \\enter\\ctrl-cq");
1095     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1096     TestPressKey("dd@q");
1097     FinishTest("completionSecond");
1098 
1099     // Completions are per macro.
1100     clearAllMacros();
1101     BeginTest("");
1102     fakeCodeCompletionModel->setCompletions({"completionA"});
1103     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1104     TestPressKey("qaicom\\ctrl- \\enter\\ctrl-cq");
1105     fakeCodeCompletionModel->setCompletions({"completionB"});
1106     TestPressKey("ddqbicom\\ctrl- \\enter\\ctrl-cq");
1107     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1108     TestPressKey("dd@aA\\enter\\ctrl-c@b");
1109     FinishTest("completionA\ncompletionB");
1110 
1111     // Make sure completions work with recursive macros.
1112     clearAllMacros();
1113     BeginTest("");
1114     fakeCodeCompletionModel->setCompletions({"completionA1", "completionA2"});
1115     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1116     // Record 'a', which calls the (non-yet-existent) macro 'b'.
1117     TestPressKey("qaicom\\ctrl- \\enter\\ctrl-cA\\enter\\ctrl-c@bA\\enter\\ctrl-cicom\\ctrl- \\ctrl-p\\enter\\ctrl-cq");
1118     // Clear document and record 'b'.
1119     fakeCodeCompletionModel->setCompletions({"completionB"});
1120     TestPressKey("ggdGqbicom\\ctrl- \\enter\\ctrl-cq");
1121     TestPressKey("dd@a");
1122     FinishTest("completionA1\ncompletionB\ncompletionA2");
1123 
1124     // Test that non-tail-removing completions are respected.
1125     // Note that there is no way (in general) to determine if a completion was
1126     // non-tail-removing, so we explicitly set the config to false.
1127     const bool oldRemoveTailOnCompletion = KateViewConfig::global()->wordCompletionRemoveTail();
1128     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1129     const bool oldReplaceTabsDyn = kate_document->config()->replaceTabsDyn();
1130     kate_document->config()->setReplaceTabsDyn(false);
1131     fakeCodeCompletionModel->setRemoveTailOnComplete(false);
1132     clearAllMacros();
1133     BeginTest("compTail");
1134     fakeCodeCompletionModel->setCompletions({"completionA", "completionB", "completionC"});
1135     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1136     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1137     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1138     kate_document->setText("compTail");
1139     TestPressKey("gg@q");
1140     FinishTest("completionATail");
1141 
1142     // A "word" consists of letters & numbers, plus "_".
1143     clearAllMacros();
1144     BeginTest("(123_compTail");
1145     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1146     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1147     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1148     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1149     kate_document->setText("(123_compTail");
1150     TestPressKey("gg@q");
1151     FinishTest("(123_completionATail");
1152 
1153     // Correctly remove word if we are set to remove tail.
1154     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1155     clearAllMacros();
1156     BeginTest("(123_compTail)");
1157     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1158     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1159     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1160     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1161     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1162     kate_document->setText("(123_compTail)");
1163     TestPressKey("gg@q");
1164     FinishTest("(123_completionA)");
1165 
1166     // Again, a "word" consists of letters & numbers & underscores.
1167     clearAllMacros();
1168     BeginTest("(123_compTail_456)");
1169     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1170     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1171     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1172     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1173     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1174     kate_document->setText("(123_compTail_456)");
1175     TestPressKey("gg@q");
1176     FinishTest("(123_completionA)");
1177 
1178     // Actually, let whether the tail is swallowed or not depend on the value when the
1179     // completion occurred, not when we replay it.
1180     clearAllMacros();
1181     BeginTest("(123_compTail_456)");
1182     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1183     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1184     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1185     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1186     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1187     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1188     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1189     kate_document->setText("(123_compTail_456)");
1190     TestPressKey("gg@q");
1191     FinishTest("(123_completionA)");
1192     clearAllMacros();
1193     BeginTest("(123_compTail_456)");
1194     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1195     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1196     fakeCodeCompletionModel->setRemoveTailOnComplete(false);
1197     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1198     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-cq");
1199     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1200     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1201     kate_document->setText("(123_compTail_456)");
1202     TestPressKey("gg@q");
1203     FinishTest("(123_completionATail_456)");
1204 
1205     // Can have remove-tail *and* non-remove-tail completions in one macro.
1206     clearAllMacros();
1207     BeginTest("(123_compTail_456)\n(123_compTail_456)");
1208     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1209     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1210     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1211     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1212     TestPressKey("qqfTi\\ctrl- \\enter\\ctrl-c");
1213     fakeCodeCompletionModel->setRemoveTailOnComplete(false);
1214     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1215     TestPressKey("j^fTi\\ctrl- \\enter\\ctrl-cq");
1216     kate_document->setText("(123_compTail_456)\n(123_compTail_456)");
1217     TestPressKey("gg@q");
1218     FinishTest("(123_completionA)\n(123_completionATail_456)");
1219 
1220     // Can repeat plain-text completions when there is no word to the left of the cursor.
1221     clearAllMacros();
1222     BeginTest("");
1223     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1224     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1225     TestPressKey("qqi\\ctrl- \\enter\\ctrl-cq");
1226     kate_document->clear();
1227     TestPressKey("gg@q");
1228     FinishTest("123_completionA");
1229 
1230     // Shouldn't swallow the letter under the cursor if we're not swallowing tails.
1231     clearAllMacros();
1232     BeginTest("");
1233     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1234     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1235     fakeCodeCompletionModel->setRemoveTailOnComplete(false);
1236     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1237     TestPressKey("qqi\\ctrl- \\enter\\ctrl-cq");
1238     kate_document->setText("oldwordshouldbeuntouched");
1239     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1240     TestPressKey("gg@q");
1241     FinishTest("123_completionAoldwordshouldbeuntouched");
1242 
1243     // ... but do if we are swallowing tails.
1244     clearAllMacros();
1245     BeginTest("");
1246     fakeCodeCompletionModel->setCompletions({"123_completionA"});
1247     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1248     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1249     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1250     TestPressKey("qqi\\ctrl- \\enter\\ctrl-cq");
1251     kate_document->setText("oldwordshouldbedeleted");
1252     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1253     TestPressKey("gg@q");
1254     FinishTest("123_completionA");
1255 
1256     // Completion of functions.
1257     // Currently, not removing the tail on function completion is not supported.
1258     fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1259     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1260     // A completed, no argument function "function()" is repeated correctly.
1261     BeginTest("");
1262     fakeCodeCompletionModel->setCompletions({"function()"});
1263     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1264     TestPressKey("qqifunc\\ctrl- \\enter\\ctrl-cq");
1265     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1266     TestPressKey("dd@q");
1267     FinishTest("function()");
1268 
1269     // Cursor is placed after the closing bracket when completion a no-arg function.
1270     BeginTest("");
1271     fakeCodeCompletionModel->setCompletions({"function()"});
1272     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1273     TestPressKey("qqifunc\\ctrl- \\enter.something();\\ctrl-cq");
1274     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1275     TestPressKey("dd@q");
1276     FinishTest("function().something();");
1277 
1278     // A function taking some arguments, repeated where there is no opening bracket to
1279     // merge with, is repeated as "function()").
1280     BeginTest("");
1281     fakeCodeCompletionModel->setCompletions({"function(...)"});
1282     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1283     TestPressKey("qqifunc\\ctrl- \\enter\\ctrl-cq");
1284     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1285     TestPressKey("dd@q");
1286     FinishTest("function()");
1287 
1288     // A function taking some arguments, repeated where there is no opening bracket to
1289     // merge with, places the cursor after the opening bracket.
1290     BeginTest("");
1291     fakeCodeCompletionModel->setCompletions({"function(...)"});
1292     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1293     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1294     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1295     TestPressKey("dd@q");
1296     FinishTest("function(firstArg)");
1297 
1298     // A function taking some arguments, recorded where there was an opening bracket to merge
1299     // with but repeated where there is no such bracket, is repeated as "function()" and the
1300     // cursor placed appropriately.
1301     BeginTest("(<-Mergeable opening bracket)");
1302     fakeCodeCompletionModel->setCompletions({"function(...)"});
1303     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1304     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1305     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1306     TestPressKey("dd@q");
1307     FinishTest("function(firstArg)");
1308 
1309     // A function taking some arguments, recorded where there was no opening bracket to merge
1310     // with but repeated where there is such a bracket, is repeated as "function" and the
1311     // cursor moved to after the merged opening bracket.
1312     BeginTest("");
1313     fakeCodeCompletionModel->setCompletions({"function(...)"});
1314     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1315     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1316     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1317     kate_document->setText("(<-firstArg goes here)");
1318     TestPressKey("gg@q");
1319     FinishTest("function(firstArg<-firstArg goes here)");
1320 
1321     // A function taking some arguments, recorded where there was an opening bracket to merge
1322     // with and repeated where there is also such a bracket, is repeated as "function" and the
1323     // cursor moved to after the merged opening bracket.
1324     BeginTest("(<-mergeablebracket)");
1325     fakeCodeCompletionModel->setCompletions({"function(...)"});
1326     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1327     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1328     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1329     kate_document->setText("(<-firstArg goes here)");
1330     TestPressKey("gg@q");
1331     FinishTest("function(firstArg<-firstArg goes here)");
1332 
1333     // The mergeable bracket can be separated by whitespace; the cursor is still placed after the
1334     // opening bracket.
1335     BeginTest("");
1336     fakeCodeCompletionModel->setCompletions({"function(...)"});
1337     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1338     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1339     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1340     kate_document->setText("   \t (<-firstArg goes here)");
1341     TestPressKey("gg@q");
1342     FinishTest("function   \t (firstArg<-firstArg goes here)");
1343 
1344     // Whitespace only, though!
1345     BeginTest("");
1346     fakeCodeCompletionModel->setCompletions({"function(...)"});
1347     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1348     TestPressKey("qqifunc\\ctrl- \\enterfirstArg\\ctrl-cq");
1349     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1350     kate_document->setText("|   \t ()");
1351     TestPressKey("gg@q");
1352     FinishTest("function(firstArg)|   \t ()");
1353 
1354     // The opening bracket can actually be after the current word (with optional whitespace).
1355     // Note that this wouldn't be the case if we weren't swallowing tails when completion functions,
1356     // but this is not currently supported.
1357     BeginTest("function");
1358     fakeCodeCompletionModel->setCompletions({"function(...)"});
1359     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1360     TestPressKey("qqfta\\ctrl- \\enterfirstArg\\ctrl-cq");
1361     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1362     kate_document->setText("functxyz    (<-firstArg goes here)");
1363     TestPressKey("gg@q");
1364     FinishTest("function    (firstArg<-firstArg goes here)");
1365 
1366     // Regression test for weird issue with replaying completions when the character to the left of the cursor
1367     // is not a word char.
1368     BeginTest("");
1369     fakeCodeCompletionModel->setCompletions({"completionA"});
1370     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1371     TestPressKey("qqciw\\ctrl- \\enter\\ctrl-cq");
1372     TestPressKey("ddi.xyz\\enter123\\enter456\\ctrl-cggl"); // Position cursor just after the "."
1373     TestPressKey("@q");
1374     FinishTest(".completionA\n123\n456");
1375     BeginTest("");
1376     fakeCodeCompletionModel->setCompletions({"completionA"});
1377     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1378     TestPressKey("qqciw\\ctrl- \\enter\\ctrl-cq");
1379     TestPressKey("ddi.xyz.abc\\enter123\\enter456\\ctrl-cggl"); // Position cursor just after the "."
1380     TestPressKey("@q");
1381     FinishTest(".completionA.abc\n123\n456");
1382 
1383     // Functions taking no arguments are never bracket-merged.
1384     BeginTest("");
1385     fakeCodeCompletionModel->setCompletions({"function()"});
1386     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1387     TestPressKey("qqifunc\\ctrl- \\enter.something();\\ctrl-cq");
1388     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1389     kate_document->setText("(<-don't merge this bracket)");
1390     TestPressKey("gg@q");
1391     FinishTest("function().something();(<-don't merge this bracket)");
1392 
1393     // Not-removing-tail when completing functions is not currently supported,
1394     // so ignore the "do-not-remove-tail" settings when we try this.
1395     BeginTest("funct");
1396     fakeCodeCompletionModel->setCompletions({"function(...)"});
1397     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1398     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1399     TestPressKey("qqfta\\ctrl- \\enterfirstArg\\ctrl-cq");
1400     kate_document->setText("functxyz");
1401     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1402     TestPressKey("gg@q");
1403     FinishTest("function(firstArg)");
1404     BeginTest("funct");
1405     fakeCodeCompletionModel->setCompletions({"function()"});
1406     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1407     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1408     TestPressKey("qqfta\\ctrl- \\enter\\ctrl-cq");
1409     kate_document->setText("functxyz");
1410     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1411     TestPressKey("gg@q");
1412     FinishTest("function()");
1413     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1414 
1415     // Deal with cases where completion ends with ";".
1416     BeginTest("");
1417     fakeCodeCompletionModel->setCompletions({"function();"});
1418     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1419     TestPressKey("qqifun\\ctrl- \\enter\\ctrl-cq");
1420     kate_document->clear();
1421     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1422     TestPressKey("gg@q");
1423     FinishTest("function();");
1424     BeginTest("");
1425     fakeCodeCompletionModel->setCompletions({"function();"});
1426     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1427     TestPressKey("qqifun\\ctrl- \\enterX\\ctrl-cq");
1428     kate_document->clear();
1429     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1430     TestPressKey("gg@q");
1431     FinishTest("function();X");
1432     BeginTest("");
1433     fakeCodeCompletionModel->setCompletions({"function(...);"});
1434     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1435     TestPressKey("qqifun\\ctrl- \\enter\\ctrl-cq");
1436     kate_document->clear();
1437     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1438     TestPressKey("gg@q");
1439     FinishTest("function();");
1440     BeginTest("");
1441     fakeCodeCompletionModel->setCompletions({"function(...);"});
1442     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1443     TestPressKey("qqifun\\ctrl- \\enterX\\ctrl-cq");
1444     kate_document->clear();
1445     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1446     TestPressKey("gg@q");
1447     FinishTest("function(X);");
1448     // Tests for completions ending in ";" where bracket merging should happen on replay.
1449     // NB: bracket merging when recording is impossible with completions that end in ";".
1450     BeginTest("");
1451     fakeCodeCompletionModel->setCompletions({"function(...);"});
1452     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1453     TestPressKey("qqifun\\ctrl- \\enter\\ctrl-cq");
1454     kate_document->setText("(<-mergeable bracket");
1455     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1456     TestPressKey("gg@q");
1457     FinishTest("function(<-mergeable bracket");
1458     BeginTest("");
1459     fakeCodeCompletionModel->setCompletions({"function(...);"});
1460     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1461     TestPressKey("qqifun\\ctrl- \\enterX\\ctrl-cq");
1462     kate_document->setText("(<-mergeable bracket");
1463     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1464     TestPressKey("gg@q");
1465     FinishTest("function(X<-mergeable bracket");
1466     // Don't merge no arg functions.
1467     BeginTest("");
1468     fakeCodeCompletionModel->setCompletions({"function();"});
1469     fakeCodeCompletionModel->setFailTestOnInvocation(false);
1470     TestPressKey("qqifun\\ctrl- \\enterX\\ctrl-cq");
1471     kate_document->setText("(<-mergeable bracket");
1472     fakeCodeCompletionModel->setFailTestOnInvocation(true);
1473     TestPressKey("gg@q");
1474     FinishTest("function();X(<-mergeable bracket");
1475 
1476     {
1477         const QString viTestKConfigFileName = "vimodetest-katevimoderc";
1478         KConfig viTestKConfig(viTestKConfigFileName);
1479         // Test loading and saving of macro completions.
1480         clearAllMacros();
1481         BeginTest("funct\nnoa\ncomtail\ncomtail\ncom");
1482         fakeCodeCompletionModel->setCompletions({"completionA", "functionwithargs(...)", "noargfunction()"});
1483         fakeCodeCompletionModel->setFailTestOnInvocation(false);
1484         // Record 'a'.
1485         TestPressKey("qafta\\ctrl- \\enterfirstArg\\ctrl-c"); // Function with args.
1486         TestPressKey("\\enterea\\ctrl- \\enter\\ctrl-c"); // Function no args.
1487         fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1488         KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1489         TestPressKey("\\enterfti\\ctrl- \\enter\\ctrl-c"); // Cut off tail.
1490         fakeCodeCompletionModel->setRemoveTailOnComplete(false);
1491         KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, false);
1492         TestPressKey("\\enterfti\\ctrl- \\enter\\ctrl-cq"); // Don't cut off tail.
1493         fakeCodeCompletionModel->setRemoveTailOnComplete(true);
1494         KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, true);
1495         // Record 'b'.
1496         fakeCodeCompletionModel->setCompletions({"completionB", "semicolonfunctionnoargs();", "semicolonfunctionwithargs(...);"});
1497         TestPressKey("\\enterqbea\\ctrl- \\enter\\ctrl-cosemicolonfunctionw\\ctrl- \\enterX\\ctrl-cosemicolonfunctionn\\ctrl- \\enterX\\ctrl-cq");
1498         // Save.
1499         vi_global->writeConfig(&viTestKConfig);
1500         viTestKConfig.sync();
1501         // Overwrite 'a' and 'b' and their completions.
1502         fakeCodeCompletionModel->setCompletions({"blah1"});
1503         kate_document->setText("");
1504         TestPressKey("ggqaiblah\\ctrl- \\enter\\ctrl-cq");
1505         TestPressKey("ddqbiblah\\ctrl- \\enter\\ctrl-cq");
1506         // Reload.
1507         vi_global->readConfig(&viTestKConfig);
1508         // Replay reloaded.
1509         fakeCodeCompletionModel->setFailTestOnInvocation(true);
1510         kate_document->setText("funct\nnoa\ncomtail\ncomtail\ncom");
1511         TestPressKey("gg@a\\enter@b");
1512         FinishTest(
1513             "functionwithargs(firstArg)\nnoargfunction()\ncompletionA\ncompletionAtail\ncompletionB\nsemicolonfunctionwithargs(X);\nsemicolonfunctionnoargs();"
1514             "X");
1515     }
1516 
1517     // Check that undo/redo operations work properly with macros.
1518     {
1519         clearAllMacros();
1520         BeginTest("");
1521         TestPressKey("ihello\\ctrl-cqauq");
1522         TestPressKey("@a\\enter");
1523         FinishTest("");
1524     }
1525     {
1526         clearAllMacros();
1527         BeginTest("");
1528         TestPressKey("ihello\\ctrl-cui.bye\\ctrl-cu");
1529         TestPressKey("qa\\ctrl-r\\enterq");
1530         TestPressKey("@a\\enter");
1531         FinishTest(".bye");
1532     }
1533 
1534     // When replaying a last change in the process of replaying a macro, take the next completion
1535     // event from the last change completions log, rather than the macro completions log.
1536     // Ensure that the last change completions log is kept up to date even while we're replaying the macro.
1537     if (false) { // FIXME: test currently fails in newer Qt >= 5.11, but works with Qt 5.10
1538         clearAllMacros();
1539         BeginTest("");
1540         fakeCodeCompletionModel->setCompletions({"completionMacro", "completionRepeatLastChange"});
1541         fakeCodeCompletionModel->setFailTestOnInvocation(false);
1542         TestPressKey("qqicompletionM\\ctrl- \\enter\\ctrl-c");
1543         TestPressKey("a completionRep\\ctrl- \\enter\\ctrl-c");
1544         TestPressKey(".q");
1545         qDebug() << "text: " << kate_document->text();
1546         kate_document->clear();
1547         TestPressKey("gg@q");
1548         FinishTest("completionMacro completionRepeatLastChange completionRepeatLastChange");
1549     }
1550 
1551     KateViewConfig::global()->setValue(KateViewConfig::WordCompletionRemoveTail, oldRemoveTailOnCompletion);
1552     kate_document->config()->setReplaceTabsDyn(oldReplaceTabsDyn);
1553 
1554     kate_view->unregisterCompletionModel(fakeCodeCompletionModel);
1555     delete fakeCodeCompletionModel;
1556     fakeCodeCompletionModel = nullptr;
1557     // Hide the kate_view for subsequent tests.
1558     kate_view->hide();
1559     mainWindow->hide();
1560     KateViewConfig::global()->setValue(KateViewConfig::ViInputModeStealKeys, oldStealKeys);
1561 }
1562 
1563 void KeysTest::MarkTests()
1564 {
1565     // Difference between ` and '
1566     DoTest("  a\n    b", "jmak'aii", "  a\n    ib");
1567     DoTest("  a\n    b", "jmak`aii", "  a\ni    b");
1568 
1569     // Last edit markers.
1570     DoTest("foo", "ean\\escgg`.r.", "foo.");
1571     DoTest("foo", "ean\\escgg`[r[", "foo[");
1572     DoTest("foo", "ean\\escgg`]r]", "foo]");
1573     DoTest("foo bar", "ean\\escgg`]r]", "foon]bar");
1574     DoTest("", "ibar\\escgg`.r.", "ba.");
1575     DoTest("", "ibar\\escgggUiw`.r.", ".AR");
1576     DoTest("", "2ibar\\escgg`]r]", "barba]");
1577     DoTest("", "2ibar\\escgg`[r[", "[arbar");
1578     DoTest("", "3ibar\\escgg`.r.", "barbar.ar"); // Vim is weird.
1579     DoTest("", "abar\\esc.gg`]r]", "barba]");
1580     DoTest("foo bar", "wgUiwgg`]r]", "foo BA]");
1581     DoTest("foo bar", "wgUiwgg`.r.", "foo .AR");
1582     DoTest("foo bar", "gUiwgg`]r.", "FO. bar");
1583     DoTest("foo bar", "wdiwgg`[r[", "foo[");
1584     DoTest("foo bar", "wdiwgg`]r]", "foo]");
1585     DoTest("foo bar", "wdiwgg`.r.", "foo.");
1586     DoTest("foo bar", "wciwnose\\escgg`.r.", "foo nos.");
1587     DoTest("foo bar", "wciwnose\\escgg`[r[", "foo [ose");
1588     DoTest("foo bar", "wciwnose\\escgg`]r]", "foo nos]");
1589     DoTest("foo", "~ibar\\escgg`[r[", "F[aroo");
1590     DoTest("foo bar", "lragg`.r.", "f.o bar");
1591     DoTest("foo bar", "lragg`[r[", "f[o bar");
1592     DoTest("foo bar", "lragg`]r]", "f]o bar");
1593     DoTest("", "ifoo\\ctrl-hbar\\esc`[r[", "[obar");
1594     DoTest("", "ifoo\\ctrl-wbar\\esc`[r[", "[ar");
1595     DoTest("", "if\\ctrl-hbar\\esc`[r[", "[ar");
1596     DoTest("", "5ofoo\\escgg`[r[", "\n[oo\nfoo\nfoo\nfoo\nfoo");
1597     DoTest("", "5ofoo\\escgg`]r]", "\nfoo\nfoo\nfoo\nfoo\nfo]");
1598     DoTest("", "5ofoo\\escgg`.r.", "\nfoo\nfoo\nfoo\nfoo\n.oo");
1599     DoTest("foo", "yyp`[r[", "foo\n[oo");
1600     DoTest("xyz\nfoo", "ja\\returnbar\\esc`[r[", "xyz\n[\nbaroo");
1601     DoTest("foo", "lrayypgg`[r[", "fao\n[ao");
1602     DoTest("foo", "l~u`[r[", "[oo");
1603     DoTest("foo", "l~u`.r.", ".oo");
1604     DoTest("foo", "l~u`]r]", "]oo");
1605     DoTest("foo", "lia\\escu`[r[", "[oo");
1606     DoTest("foo", "lia\\escu`.r.", ".oo");
1607     DoTest("foo", "lia\\escu`]r]", "]oo");
1608     DoTest("foo", "l~u~`[r[", "f[o");
1609     DoTest("foo\nbar\nxyz", "jyypu`[r[", "foo\nbar\n[yz");
1610     DoTest("foo\nbar\nxyz", "jyypu`.r.", "foo\nbar\n.yz");
1611     DoTest("foo\nbar\nxyz", "jyypu`]r]", "foo\nbar\n]yz");
1612     DoTest("foo\nbar\nxyz\n123", "jdju`[r[", "foo\n[ar\nxyz\n123");
1613     DoTest("foo\nbar\nxyz\n123", "jdju`.r.", "foo\n.ar\nxyz\n123");
1614     DoTest("foo\nbar\nxyz\n123", "jdju`]r]", "foo\nbar\n]yz\n123");
1615     DoTest("foo\nbar\nxyz\n123", "jVj~u\\esc`[r[", "foo\n[ar\nxyz\n123", ShouldFail, "Vim is weird.");
1616 }
1617 
1618 // END: KeysTest
1619 
1620 #include "moc_keys.cpp"