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"