File indexing completed on 2024-04-28 03:57:11

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