File indexing completed on 2024-05-12 11:57:22
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2011 Kuzmich Svyatoslav 0004 SPDX-FileCopyrightText: 2012-2013 Simon St James <kdedevel@etotheipiplusone.com> 0005 0006 SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "emulatedcommandbar.h" 0010 #include "emulatedcommandbarsetupandteardown.h" 0011 #include "keys.h" 0012 #include "view.h" 0013 #include "vimode/globalstate.h" 0014 #include "vimode/mappings.h" 0015 #include <inputmode/kateviinputmode.h> 0016 #include <katebuffer.h> 0017 #include <kateconfig.h> 0018 #include <katedocument.h> 0019 #include <kateview.h> 0020 #include <vimode/emulatedcommandbar/emulatedcommandbar.h> 0021 #include <vimode/history.h> 0022 0023 #include <QAbstractItemView> 0024 #include <QClipboard> 0025 #include <QCompleter> 0026 #include <QLabel> 0027 #include <QStringListModel> 0028 0029 #include <KActionCollection> 0030 #include <KColorScheme> 0031 0032 QTEST_MAIN(EmulatedCommandBarTest) 0033 0034 using namespace KTextEditor; 0035 using namespace KateVi; 0036 0037 void EmulatedCommandBarTest::EmulatedCommandBarTests() 0038 { 0039 // Ensure that some preconditions for these tests are setup, and (more importantly) 0040 // ensure that they are reverted no matter how these tests end. 0041 EmulatedCommandBarSetUpAndTearDown emulatedCommandBarSetUpAndTearDown(vi_input_mode, kate_view, mainWindow); 0042 0043 // Verify that we can get a non-null pointer to the emulated command bar. 0044 EmulatedCommandBar *emulatedCommandBar = vi_input_mode->viModeEmulatedCommandBar(); 0045 QVERIFY(emulatedCommandBar); 0046 0047 // Should initially be hidden. 0048 QVERIFY(!emulatedCommandBar->isVisible()); 0049 0050 // Test that "/" invokes the emulated command bar (if we are configured to use it) 0051 BeginTest(""); 0052 TestPressKey("/"); 0053 QVERIFY(emulatedCommandBar->isVisible()); 0054 QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("/")); 0055 QVERIFY(emulatedCommandTypeIndicator()->isVisible()); 0056 QVERIFY(emulatedCommandBarTextEdit()); 0057 QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty()); 0058 // Make sure the keypresses end up changing the text. 0059 QVERIFY(emulatedCommandBarTextEdit()->isVisible()); 0060 TestPressKey("foo"); 0061 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 0062 // Make sure ctrl-c dismisses it (assuming we allow Vim to steal the ctrl-c shortcut). 0063 TestPressKey("\\ctrl-c"); 0064 QVERIFY(!emulatedCommandBar->isVisible()); 0065 0066 // Ensure that ESC dismisses it, too. 0067 BeginTest(""); 0068 TestPressKey("/"); 0069 QVERIFY(emulatedCommandBar->isVisible()); 0070 TestPressKey("\\esc"); 0071 QVERIFY(!emulatedCommandBar->isVisible()); 0072 FinishTest(""); 0073 0074 // Ensure that Ctrl-[ dismisses it, too. 0075 BeginTest(""); 0076 TestPressKey("/"); 0077 QVERIFY(emulatedCommandBar->isVisible()); 0078 TestPressKey("\\ctrl-["); 0079 QVERIFY(!emulatedCommandBar->isVisible()); 0080 FinishTest(""); 0081 0082 // Ensure that Enter dismisses it, too. 0083 BeginTest(""); 0084 TestPressKey("/"); 0085 QVERIFY(emulatedCommandBar->isVisible()); 0086 TestPressKey("\\enter"); 0087 QVERIFY(!emulatedCommandBar->isVisible()); 0088 FinishTest(""); 0089 0090 // Ensure that Return dismisses it, too. 0091 BeginTest(""); 0092 TestPressKey("/"); 0093 QVERIFY(emulatedCommandBar->isVisible()); 0094 TestPressKey("\\return"); 0095 QVERIFY(!emulatedCommandBar->isVisible()); 0096 FinishTest(""); 0097 0098 // Ensure that text is always initially empty. 0099 BeginTest(""); 0100 TestPressKey("/a\\enter"); 0101 TestPressKey("/"); 0102 QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty()); 0103 TestPressKey("\\enter"); 0104 FinishTest(""); 0105 0106 // Check backspace works. 0107 BeginTest(""); 0108 TestPressKey("/foo\\backspace"); 0109 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fo")); 0110 TestPressKey("\\enter"); 0111 FinishTest(""); 0112 0113 // Check ctrl-h works. 0114 BeginTest(""); 0115 TestPressKey("/bar\\ctrl-h"); 0116 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ba")); 0117 TestPressKey("\\enter"); 0118 FinishTest(""); 0119 0120 // ctrl-h should dismiss bar when empty. 0121 BeginTest(""); 0122 TestPressKey("/\\ctrl-h"); 0123 QVERIFY(!emulatedCommandBar->isVisible()); 0124 FinishTest(""); 0125 0126 // ctrl-h should not dismiss bar when there is stuff to the left of cursor. 0127 BeginTest(""); 0128 TestPressKey("/a\\ctrl-h"); 0129 QVERIFY(emulatedCommandBar->isVisible()); 0130 TestPressKey("\\enter"); 0131 FinishTest(""); 0132 0133 // ctrl-h should not dismiss bar when bar is not empty, even if there is nothing to the left of cursor. 0134 BeginTest(""); 0135 TestPressKey("/a\\left\\ctrl-h"); 0136 QVERIFY(emulatedCommandBar->isVisible()); 0137 TestPressKey("\\enter"); 0138 FinishTest(""); 0139 0140 // Same for backspace. 0141 BeginTest(""); 0142 TestPressKey("/bar\\backspace"); 0143 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ba")); 0144 TestPressKey("\\enter"); 0145 FinishTest(""); 0146 BeginTest(""); 0147 TestPressKey("/\\backspace"); 0148 QVERIFY(!emulatedCommandBar->isVisible()); 0149 FinishTest(""); 0150 BeginTest(""); 0151 TestPressKey("/a\\backspace"); 0152 QVERIFY(emulatedCommandBar->isVisible()); 0153 TestPressKey("\\enter"); 0154 FinishTest(""); 0155 BeginTest(""); 0156 TestPressKey("/a\\left\\backspace"); 0157 QVERIFY(emulatedCommandBar->isVisible()); 0158 TestPressKey("\\enter"); 0159 FinishTest(""); 0160 0161 // Check ctrl-b works. 0162 BeginTest(""); 0163 TestPressKey("/bar foo xyz\\ctrl-bX"); 0164 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("Xbar foo xyz")); 0165 TestPressKey("\\enter"); 0166 FinishTest(""); 0167 0168 // Check ctrl-e works. 0169 BeginTest(""); 0170 TestPressKey("/bar foo xyz\\ctrl-b\\ctrl-eX"); 0171 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar foo xyzX")); 0172 TestPressKey("\\enter"); 0173 FinishTest(""); 0174 0175 // Check ctrl-w works. 0176 BeginTest(""); 0177 TestPressKey("/foo bar\\ctrl-w"); 0178 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ")); 0179 TestPressKey("\\enter"); 0180 FinishTest(""); 0181 0182 // Check ctrl-w works on empty command bar. 0183 BeginTest(""); 0184 TestPressKey("/\\ctrl-w"); 0185 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("")); 0186 TestPressKey("\\enter"); 0187 FinishTest(""); 0188 0189 // Check ctrl-w works in middle of word. 0190 BeginTest(""); 0191 TestPressKey("/foo bar\\left\\left\\ctrl-w"); 0192 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ar")); 0193 TestPressKey("\\enter"); 0194 FinishTest(""); 0195 0196 // Check ctrl-w leaves the cursor in the right place when in the middle of word. 0197 BeginTest(""); 0198 TestPressKey("/foo bar\\left\\left\\ctrl-wX"); 0199 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo Xar")); 0200 TestPressKey("\\enter"); 0201 FinishTest(""); 0202 0203 // Check ctrl-w works when at the beginning of the text. 0204 BeginTest(""); 0205 TestPressKey("/foo\\left\\left\\left\\ctrl-w"); 0206 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 0207 TestPressKey("\\enter"); 0208 FinishTest(""); 0209 0210 // Check ctrl-w works when the character to the left is a space. 0211 BeginTest(""); 0212 TestPressKey("/foo bar \\ctrl-w"); 0213 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ")); 0214 TestPressKey("\\enter"); 0215 FinishTest(""); 0216 0217 // Check ctrl-w works when all characters to the left of the cursor are spaces. 0218 BeginTest(""); 0219 TestPressKey("/ \\ctrl-w"); 0220 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("")); 0221 TestPressKey("\\enter"); 0222 FinishTest(""); 0223 0224 // Check ctrl-w works when all characters to the left of the cursor are non-spaces. 0225 BeginTest(""); 0226 TestPressKey("/foo\\ctrl-w"); 0227 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("")); 0228 TestPressKey("\\enter"); 0229 FinishTest(""); 0230 0231 // Check ctrl-w does not continue to delete subsequent alphanumerics if the characters to the left of the cursor 0232 // are non-space, non-alphanumerics. 0233 BeginTest(""); 0234 TestPressKey("/foo!!!\\ctrl-w"); 0235 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 0236 TestPressKey("\\enter"); 0237 FinishTest(""); 0238 // Check ctrl-w does not continue to delete subsequent alphanumerics if the characters to the left of the cursor 0239 // are non-space, non-alphanumerics. 0240 BeginTest(""); 0241 TestPressKey("/foo!!!\\ctrl-w"); 0242 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 0243 TestPressKey("\\enter"); 0244 FinishTest(""); 0245 0246 // Check ctrl-w deletes underscores and alphanumerics to the left of the cursor, but stops when it reaches a 0247 // character that is none of these. 0248 BeginTest(""); 0249 TestPressKey("/foo!!!_d1\\ctrl-w"); 0250 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo!!!")); 0251 TestPressKey("\\enter"); 0252 FinishTest(""); 0253 0254 // Check ctrl-w doesn't swallow the spaces preceding the block of non-word chars. 0255 BeginTest(""); 0256 TestPressKey("/foo !!!\\ctrl-w"); 0257 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ")); 0258 TestPressKey("\\enter"); 0259 FinishTest(""); 0260 0261 // Check ctrl-w doesn't swallow the spaces preceding the word. 0262 BeginTest(""); 0263 TestPressKey("/foo 1d_\\ctrl-w"); 0264 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ")); 0265 TestPressKey("\\enter"); 0266 FinishTest(""); 0267 0268 // Check there is a "waiting for register" indicator, initially hidden. 0269 BeginTest(""); 0270 TestPressKey("/"); 0271 QLabel *waitingForRegisterIndicator = emulatedCommandBar->findChild<QLabel *>("waitingforregisterindicator"); 0272 QVERIFY(waitingForRegisterIndicator); 0273 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0274 QCOMPARE(waitingForRegisterIndicator->text(), QString("\"")); 0275 TestPressKey("\\enter"); 0276 FinishTest(""); 0277 0278 // Test that ctrl-r causes it to become visible. It is displayed to the right of the text edit. 0279 BeginTest(""); 0280 TestPressKey("/\\ctrl-r"); 0281 QVERIFY(waitingForRegisterIndicator->isVisible()); 0282 QVERIFY(waitingForRegisterIndicator->x() >= emulatedCommandBarTextEdit()->x() + emulatedCommandBarTextEdit()->width()); 0283 TestPressKey("\\ctrl-c"); 0284 TestPressKey("\\ctrl-c"); 0285 FinishTest(""); 0286 0287 // The first ctrl-c after ctrl-r (when no register entered) hides the waiting for register 0288 // indicator, but not the bar. 0289 BeginTest(""); 0290 TestPressKey("/\\ctrl-r"); 0291 QVERIFY(waitingForRegisterIndicator->isVisible()); 0292 TestPressKey("\\ctrl-c"); 0293 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0294 QVERIFY(emulatedCommandBar->isVisible()); 0295 TestPressKey("\\ctrl-c"); // Dismiss the bar. 0296 FinishTest(""); 0297 0298 // The first ctrl-c after ctrl-r (when no register entered) aborts waiting for register. 0299 BeginTest("foo"); 0300 TestPressKey("\"cyiw/\\ctrl-r\\ctrl-ca"); 0301 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("a")); 0302 TestPressKey("\\ctrl-c"); // Dismiss the bar. 0303 FinishTest("foo"); 0304 0305 // Same as above, but for ctrl-[ instead of ctrl-c. 0306 BeginTest(""); 0307 TestPressKey("/\\ctrl-r"); 0308 QVERIFY(waitingForRegisterIndicator->isVisible()); 0309 TestPressKey("\\ctrl-["); 0310 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0311 QVERIFY(emulatedCommandBar->isVisible()); 0312 TestPressKey("\\ctrl-c"); // Dismiss the bar. 0313 FinishTest(""); 0314 BeginTest("foo"); 0315 TestPressKey("\"cyiw/\\ctrl-r\\ctrl-[a"); 0316 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("a")); 0317 TestPressKey("\\ctrl-c"); // Dismiss the bar. 0318 FinishTest("foo"); 0319 0320 // Check ctrl-r works with registers, and hides the "waiting for register" indicator. 0321 BeginTest("xyz"); 0322 TestPressKey("\"ayiw/foo\\ctrl-ra"); 0323 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fooxyz")); 0324 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0325 TestPressKey("\\enter"); 0326 FinishTest("xyz"); 0327 0328 // Check ctrl-r inserts text at the current cursor position. 0329 BeginTest("xyz"); 0330 TestPressKey("\"ayiw/foo\\left\\ctrl-ra"); 0331 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foxyzo")); 0332 TestPressKey("\\enter"); 0333 FinishTest("xyz"); 0334 0335 // Check ctrl-r ctrl-w inserts word under the cursor, and hides the "waiting for register" indicator. 0336 BeginTest("foo bar xyz"); 0337 TestPressKey("w/\\left\\ctrl-r\\ctrl-w"); 0338 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar")); 0339 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0340 TestPressKey("\\enter"); 0341 FinishTest("foo bar xyz"); 0342 0343 // Check ctrl-r ctrl-w doesn't insert the contents of register w! 0344 BeginTest("foo baz xyz"); 0345 TestPressKey("\"wyiww/\\left\\ctrl-r\\ctrl-w"); 0346 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("baz")); 0347 TestPressKey("\\enter"); 0348 FinishTest("foo baz xyz"); 0349 0350 // Check ctrl-r ctrl-w inserts at the current cursor position. 0351 BeginTest("foo nose xyz"); 0352 TestPressKey("w/bar\\left\\ctrl-r\\ctrl-w"); 0353 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("banoser")); 0354 TestPressKey("\\enter"); 0355 FinishTest("foo nose xyz"); 0356 0357 // Cursor position is at the end of the inserted text after ctrl-r ctrl-w. 0358 BeginTest("foo nose xyz"); 0359 TestPressKey("w/bar\\left\\ctrl-r\\ctrl-wX"); 0360 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("banoseXr")); 0361 TestPressKey("\\enter"); 0362 FinishTest("foo nose xyz"); 0363 0364 // Cursor position is at the end of the inserted register contents after ctrl-r. 0365 BeginTest("xyz"); 0366 TestPressKey("\"ayiw/foo\\left\\ctrl-raX"); 0367 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foxyzXo")); 0368 TestPressKey("\\enter"); 0369 FinishTest("xyz"); 0370 0371 // Insert clipboard contents on ctrl-r +. We implicitly need to test the ability to handle 0372 // shift key key events when waiting for register (they should be ignored). 0373 BeginTest("xyz"); 0374 QApplication::clipboard()->setText("vimodetestclipboardtext"); 0375 TestPressKey("/\\ctrl-r"); 0376 QKeyEvent *shiftKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier); 0377 QApplication::postEvent(emulatedCommandBarTextEdit(), shiftKeyDown); 0378 QApplication::sendPostedEvents(); 0379 TestPressKey("+"); 0380 QKeyEvent *shiftKeyUp = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier); 0381 QApplication::postEvent(emulatedCommandBarTextEdit(), shiftKeyUp); 0382 QApplication::sendPostedEvents(); 0383 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("vimodetestclipboardtext")); 0384 TestPressKey("\\enter"); 0385 FinishTest("xyz"); 0386 0387 // Similarly, test that we can press "ctrl" after ctrl-r without it being taken for a register. 0388 BeginTest("wordundercursor"); 0389 TestPressKey("/\\ctrl-r"); 0390 QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier); 0391 QApplication::postEvent(emulatedCommandBarTextEdit(), ctrlKeyDown); 0392 QApplication::sendPostedEvents(); 0393 QKeyEvent *ctrlKeyUp = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Control, Qt::NoModifier); 0394 QApplication::postEvent(emulatedCommandBarTextEdit(), ctrlKeyUp); 0395 QApplication::sendPostedEvents(); 0396 QVERIFY(waitingForRegisterIndicator->isVisible()); 0397 TestPressKey("\\ctrl-w"); 0398 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordundercursor")); 0399 TestPressKey("\\ctrl-c"); // Dismiss the bar. 0400 FinishTest("wordundercursor"); 0401 0402 // Begin tests for ctrl-g, which is almost identical to ctrl-r save that the contents, when added, 0403 // are escaped for searching. 0404 // Normal register contents/ word under cursor are added as normal. 0405 BeginTest("wordinregisterb wordundercursor"); 0406 TestPressKey("\"byiw"); 0407 TestPressKey("/\\ctrl-g"); 0408 QVERIFY(waitingForRegisterIndicator->isVisible()); 0409 QVERIFY(waitingForRegisterIndicator->x() >= emulatedCommandBarTextEdit()->x() + emulatedCommandBarTextEdit()->width()); 0410 TestPressKey("b"); 0411 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordinregisterb")); 0412 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0413 TestPressKey("\\ctrl-c\\ctrl-cw/\\ctrl-g\\ctrl-w"); 0414 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordundercursor")); 0415 QVERIFY(!waitingForRegisterIndicator->isVisible()); 0416 TestPressKey("\\ctrl-c"); 0417 TestPressKey("\\ctrl-c"); 0418 FinishTest("wordinregisterb wordundercursor"); 0419 0420 // \'s must be escaped when inserted via ctrl-g. 0421 DoTest("foo a\\b\\\\c\\\\\\d", "wYb/\\ctrl-g0\\enterrX", "foo X\\b\\\\c\\\\\\d"); 0422 // $'s must be escaped when inserted via ctrl-g. 0423 DoTest("foo a$b", "wYb/\\ctrl-g0\\enterrX", "foo X$b"); 0424 DoTest("foo a$b$c", "wYb/\\ctrl-g0\\enterrX", "foo X$b$c"); 0425 DoTest("foo a\\$b\\$c", "wYb/\\ctrl-g0\\enterrX", "foo X\\$b\\$c"); 0426 // ^'s must be escaped when inserted via ctrl-g. 0427 DoTest("foo a^b", "wYb/\\ctrl-g0\\enterrX", "foo X^b"); 0428 DoTest("foo a^b^c", "wYb/\\ctrl-g0\\enterrX", "foo X^b^c"); 0429 DoTest("foo a\\^b\\^c", "wYb/\\ctrl-g0\\enterrX", "foo X\\^b\\^c"); 0430 // .'s must be escaped when inserted via ctrl-g. 0431 DoTest("foo axb a.b", "wwYgg/\\ctrl-g0\\enterrX", "foo axb X.b"); 0432 DoTest("foo a\\xb Na\\.b", "fNlYgg/\\ctrl-g0\\enterrX", "foo a\\xb NX\\.b"); 0433 // *'s must be escaped when inserted via ctrl-g 0434 DoTest("foo axxxxb ax*b", "wwYgg/\\ctrl-g0\\enterrX", "foo axxxxb Xx*b"); 0435 DoTest("foo a\\xxxxb Na\\x*X", "fNlYgg/\\ctrl-g0\\enterrX", "foo a\\xxxxb NX\\x*X"); 0436 // /'s must be escaped when inserted via ctrl-g. 0437 DoTest("foo a a/b", "wwYgg/\\ctrl-g0\\enterrX", "foo a X/b"); 0438 DoTest("foo a a/b/c", "wwYgg/\\ctrl-g0\\enterrX", "foo a X/b/c"); 0439 DoTest("foo a a\\/b\\/c", "wwYgg/\\ctrl-g0\\enterrX", "foo a X\\/b\\/c"); 0440 // ['s and ]'s must be escaped when inserted via ctrl-g. 0441 DoTest("foo axb a[xyz]b", "wwYgg/\\ctrl-g0\\enterrX", "foo axb X[xyz]b"); 0442 DoTest("foo a[b", "wYb/\\ctrl-g0\\enterrX", "foo X[b"); 0443 DoTest("foo a[b[c", "wYb/\\ctrl-g0\\enterrX", "foo X[b[c"); 0444 DoTest("foo a\\[b\\[c", "wYb/\\ctrl-g0\\enterrX", "foo X\\[b\\[c"); 0445 DoTest("foo a]b", "wYb/\\ctrl-g0\\enterrX", "foo X]b"); 0446 DoTest("foo a]b]c", "wYb/\\ctrl-g0\\enterrX", "foo X]b]c"); 0447 DoTest("foo a\\]b\\]c", "wYb/\\ctrl-g0\\enterrX", "foo X\\]b\\]c"); 0448 // Test that expressions involving {'s and }'s work when inserted via ctrl-g. 0449 DoTest("foo {", "wYgg/\\ctrl-g0\\enterrX", "foo X"); 0450 DoTest("foo }", "wYgg/\\ctrl-g0\\enterrX", "foo X"); 0451 DoTest("foo aaaaa \\aaaaa a\\{5}", "WWWYgg/\\ctrl-g0\\enterrX", "foo aaaaa \\aaaaa X\\{5}"); 0452 DoTest("foo }", "wYgg/\\ctrl-g0\\enterrX", "foo X"); 0453 // Transform newlines into "\\n" when inserted via ctrl-g. 0454 DoTest(" \nfoo\nfoo\nxyz\nbar\n123", "jjvjjllygg/\\ctrl-g0\\enterrX", " \nfoo\nXoo\nxyz\nbar\n123"); 0455 DoTest(" \nfoo\nfoo\nxyz\nbar\n123", "jjvjjllygg/\\ctrl-g0/e\\enterrX", " \nfoo\nfoo\nxyz\nbaX\n123"); 0456 // Don't do any escaping for ctrl-r, though. 0457 BeginTest("foo .*$^\\/"); 0458 TestPressKey("wY/\\ctrl-r0"); 0459 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".*$^\\/")); 0460 TestPressKey("\\ctrl-c"); 0461 TestPressKey("\\ctrl-c"); 0462 FinishTest("foo .*$^\\/"); 0463 // Ensure that the flag that says "next register insertion should be escaped for searching" 0464 // is cleared if we do ctrl-g but then abort with ctrl-c. 0465 DoTest("foo a$b", "/\\ctrl-g\\ctrl-c\\ctrl-cwYgg/\\ctrl-r0\\enterrX", "Xoo a$b"); 0466 0467 // Ensure that we actually perform a search while typing. 0468 BeginTest("abcd"); 0469 TestPressKey("/c"); 0470 verifyCursorAt(Cursor(0, 2)); 0471 TestPressKey("\\enter"); 0472 FinishTest("abcd"); 0473 0474 // Ensure that the search is from the cursor. 0475 BeginTest("acbcd"); 0476 TestPressKey("ll/c"); 0477 verifyCursorAt(Cursor(0, 3)); 0478 TestPressKey("\\enter"); 0479 FinishTest("acbcd"); 0480 0481 // Reset the cursor to the original position on Ctrl-C 0482 BeginTest("acbcd"); 0483 TestPressKey("ll/c\\ctrl-crX"); 0484 FinishTest("acXcd"); 0485 0486 // Reset the cursor to the original position on Ctrl-[ 0487 BeginTest("acbcd"); 0488 TestPressKey("ll/c\\ctrl-[rX"); 0489 FinishTest("acXcd"); 0490 0491 // Reset the cursor to the original position on ESC 0492 BeginTest("acbcd"); 0493 TestPressKey("ll/c\\escrX"); 0494 FinishTest("acXcd"); 0495 0496 // *Do not* reset the cursor to the original position on Enter. 0497 BeginTest("acbcd"); 0498 TestPressKey("ll/c\\enterrX"); 0499 FinishTest("acbXd"); 0500 0501 // *Do not* reset the cursor to the original position on Return. 0502 BeginTest("acbcd"); 0503 TestPressKey("ll/c\\returnrX"); 0504 FinishTest("acbXd"); 0505 0506 // Should work with mappings. 0507 clearAllMappings(); 0508 vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmapping", "/c<enter>rX", Mappings::Recursive); 0509 BeginTest("acbcd"); 0510 TestPressKey("'testmapping"); 0511 FinishTest("aXbcd"); 0512 clearAllMappings(); 0513 // Don't send keys that were part of a mapping to the emulated command bar. 0514 vi_global->mappings()->add(Mappings::NormalModeMapping, "H", "/a", Mappings::Recursive); 0515 BeginTest("foo a aH"); 0516 TestPressKey("H\\enterrX"); 0517 FinishTest("foo X aH"); 0518 clearAllMappings(); 0519 0520 // Incremental searching from the original position. 0521 BeginTest("foo bar foop fool food"); 0522 TestPressKey("ll/foo"); 0523 verifyCursorAt(Cursor(0, 8)); 0524 TestPressKey("l"); 0525 verifyCursorAt(Cursor(0, 13)); 0526 TestPressKey("\\backspace"); 0527 verifyCursorAt(Cursor(0, 8)); 0528 TestPressKey("\\enter"); 0529 FinishTest("foo bar foop fool food"); 0530 0531 // End up back at the start if no match found 0532 BeginTest("foo bar foop fool food"); 0533 TestPressKey("ll/fool"); 0534 verifyCursorAt(Cursor(0, 13)); 0535 TestPressKey("\\backspacex"); 0536 verifyCursorAt(Cursor(0, 2)); 0537 TestPressKey("\\enter"); 0538 FinishTest("foo bar foop fool food"); 0539 0540 // Wrap around if no match found. 0541 BeginTest("afoom bar foop fool food"); 0542 TestPressKey("lll/foom"); 0543 verifyCursorAt(Cursor(0, 1)); 0544 TestPressKey("\\enter"); 0545 FinishTest("afoom bar foop fool food"); 0546 0547 // SmartCase: match case-insensitively if the search text is all lower-case. 0548 DoTest("foo BaR", "ll/bar\\enterrX", "foo XaR"); 0549 0550 // SmartCase: match case-sensitively if the search text is mixed case. 0551 DoTest("foo BaR bAr", "ll/bAr\\enterrX", "foo BaR XAr"); 0552 0553 // Assume regex by default. 0554 DoTest("foo bwibblear", "ll/b.*ar\\enterrX", "foo Xwibblear"); 0555 0556 // Set the last search pattern. 0557 DoTest("foo bar", "ll/bar\\enterggnrX", "foo Xar"); 0558 0559 // Make sure the last search pattern is a regex, too. 0560 DoTest("foo bwibblear", "ll/b.*ar\\enterggnrX", "foo Xwibblear"); 0561 0562 // 'n' should search case-insensitively if the original search was case-insensitive. 0563 DoTest("foo bAR", "ll/bar\\enterggnrX", "foo XAR"); 0564 0565 // 'n' should search case-sensitively if the original search was case-sensitive. 0566 DoTest("foo bar bAR", "ll/bAR\\enterggnrX", "foo bar XAR"); 0567 0568 // 'N' should search case-insensitively if the original search was case-insensitive. 0569 DoTest("foo bAR xyz", "ll/bar\\enter$NrX", "foo XAR xyz"); 0570 0571 // 'N' should search case-sensitively if the original search was case-sensitive. 0572 DoTest("foo bAR bar", "ll/bAR\\enter$NrX", "foo XAR bar"); 0573 0574 // Don't forget to set the last search to case-insensitive. 0575 DoTest("foo bAR bar", "ll/bAR\\enter^/bar\\enter^nrX", "foo XAR bar"); 0576 0577 // Usage of \C for manually specifying case sensitivity. 0578 // Strip occurrences of "\C" from the pattern to find. 0579 DoTest("foo bar", "/\\\\Cba\\\\Cr\\enterrX", "foo Xar"); 0580 // Be careful about escaping, though! 0581 DoTest("foo \\Cba\\Cr", "/\\\\\\\\Cb\\\\Ca\\\\\\\\C\\\\C\\\\Cr\\enterrX", "foo XCba\\Cr"); 0582 // The item added to the search history should contain all the original \C's. 0583 clearSearchHistory(); 0584 BeginTest("foo \\Cba\\Cr"); 0585 TestPressKey("/\\\\\\\\Cb\\\\Ca\\\\\\\\C\\\\C\\\\Cr\\enterrX"); 0586 QCOMPARE(searchHistory().first(), QString("\\\\Cb\\Ca\\\\C\\C\\Cr")); 0587 FinishTest("foo XCba\\Cr"); 0588 // If there is an escaped C, assume case sensitivity. 0589 DoTest("foo bAr BAr bar", "/ba\\\\Cr\\enterrX", "foo bAr BAr Xar"); 0590 // The last search pattern should be the last search with escaped C's stripped. 0591 DoTest("foo \\Cbar\nfoo \\Cbar", "/\\\\\\\\Cba\\\\C\\\\Cr\\enterggjnrX", "foo \\Cbar\nfoo XCbar"); 0592 // If the last search pattern had an escaped "\C", then the next search should be case-sensitive. 0593 DoTest("foo bar\nfoo bAr BAr bar", "/ba\\\\Cr\\enterggjnrX", "foo bar\nfoo bAr BAr Xar"); 0594 0595 // Don't set the last search parameters if we abort, though. 0596 DoTest("foo bar xyz", "/bar\\enter/xyz\\ctrl-cggnrX", "foo Xar xyz"); 0597 DoTest("foo bar bAr", "/bar\\enter/bA\\ctrl-cggnrX", "foo Xar bAr"); 0598 DoTest("foo bar bar", "/bar\\enter?ba\\ctrl-cggnrX", "foo Xar bar"); 0599 0600 // Don't let ":" trample all over the search parameters, either. 0601 DoTest("foo bar xyz foo", "/bar\\entergg*:yank\\enterggnrX", "foo bar xyz Xoo"); 0602 0603 // Some mirror tests for "?" 0604 0605 // Test that "?" summons the search bar, with empty text and with the "?" indicator. 0606 QVERIFY(!emulatedCommandBar->isVisible()); 0607 BeginTest(""); 0608 TestPressKey("?"); 0609 QVERIFY(emulatedCommandBar->isVisible()); 0610 QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("?")); 0611 QVERIFY(emulatedCommandTypeIndicator()->isVisible()); 0612 QVERIFY(emulatedCommandBarTextEdit()); 0613 QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty()); 0614 TestPressKey("\\enter"); 0615 FinishTest(""); 0616 0617 // Search backwards. 0618 DoTest("foo foo bar foo foo", "ww?foo\\enterrX", "foo Xoo bar foo foo"); 0619 0620 // Reset cursor if we find nothing. 0621 BeginTest("foo foo bar foo foo"); 0622 TestPressKey("ww?foo"); 0623 verifyCursorAt(Cursor(0, 4)); 0624 TestPressKey("d"); 0625 verifyCursorAt(Cursor(0, 8)); 0626 TestPressKey("\\enter"); 0627 FinishTest("foo foo bar foo foo"); 0628 0629 // Wrap to the end if we find nothing. 0630 DoTest("foo foo bar xyz xyz", "ww?xyz\\enterrX", "foo foo bar xyz Xyz"); 0631 0632 // Specify that the last was backwards when using '?' 0633 DoTest("foo foo bar foo foo", "ww?foo\\enter^wwnrX", "foo Xoo bar foo foo"); 0634 0635 // ... and make sure we do the equivalent with "/" 0636 BeginTest("foo foo bar foo foo"); 0637 TestPressKey("ww?foo\\enter^ww/foo"); 0638 QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("/")); 0639 TestPressKey("\\enter^wwnrX"); 0640 FinishTest("foo foo bar Xoo foo"); 0641 0642 // If we are at the beginning of a word, that word is not the first match in a search 0643 // for that word. 0644 DoTest("foo foo foo", "w/foo\\enterrX", "foo foo Xoo"); 0645 DoTest("foo foo foo", "w?foo\\enterrX", "Xoo foo foo"); 0646 // When searching backwards, ensure we can find a match whose range includes the starting cursor position, 0647 // if we allow it to wrap around. 0648 DoTest("foo foofoofoo bar", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo bar"); 0649 // When searching backwards, ensure we can find a match whose range includes the starting cursor position, 0650 // even if we don't allow it to wrap around. 0651 DoTest("foo foofoofoo foofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo foofoofoo"); 0652 // The same, but where we the match ends at the end of the line or document. 0653 DoTest("foo foofoofoo\nfoofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo\nfoofoofoo"); 0654 DoTest("foo foofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo"); 0655 0656 // Searching forwards for just "/" repeats last search. 0657 DoTest("foo bar", "/bar\\entergg//\\enterrX", "foo Xar"); 0658 // The "last search" can be one initiated via e.g. "*". 0659 DoTest("foo bar foo", "/bar\\entergg*gg//\\enterrX", "foo bar Xoo"); 0660 // Searching backwards for just "?" repeats last search. 0661 DoTest("foo bar bar", "/bar\\entergg??\\enterrX", "foo bar Xar"); 0662 // Search forwards treats "?" as a literal. 0663 DoTest("foo ?ba?r", "/?ba?r\\enterrX", "foo Xba?r"); 0664 // As always, be careful with escaping! 0665 DoTest("foo ?ba\\?r", "/?ba\\\\\\\\\\\\?r\\enterrX", "foo Xba\\?r"); 0666 // Searching forwards for just "?" finds literal question marks. 0667 DoTest("foo ??", "/?\\enterrX", "foo X?"); 0668 // Searching backwards for just "/" finds literal forward slashes. 0669 DoTest("foo //", "?/\\enterrX", "foo /X"); 0670 // Searching forwards, stuff after (and including) an unescaped "/" is ignored. 0671 DoTest("foo ba bar bar/xyz", "/bar/xyz\\enterrX", "foo ba Xar bar/xyz"); 0672 // Needs to be unescaped, though! 0673 DoTest("foo bar bar/xyz", "/bar\\\\/xyz\\enterrX", "foo bar Xar/xyz"); 0674 DoTest("foo bar bar\\/xyz", "/bar\\\\\\\\/xyz\\enterrX", "foo bar Xar\\/xyz"); 0675 // Searching backwards, stuff after (and including) an unescaped "?" is ignored. 0676 DoTest("foo bar bar?xyz bar ba", "?bar?xyz\\enterrX", "foo bar bar?xyz Xar ba"); 0677 // Needs to be unescaped, though! 0678 DoTest("foo bar bar?xyz bar ba", "?bar\\\\?xyz\\enterrX", "foo bar Xar?xyz bar ba"); 0679 DoTest("foo bar bar\\?xyz bar ba", "?bar\\\\\\\\?xyz\\enterrX", "foo bar Xar\\?xyz bar ba"); 0680 // If, in a forward search, the first character after the first unescaped "/" is an e, then 0681 // we place the cursor at the end of the word. 0682 DoTest("foo ba bar bar/eyz", "/bar/e\\enterrX", "foo ba baX bar/eyz"); 0683 // Needs to be unescaped, though! 0684 DoTest("foo bar bar/eyz", "/bar\\\\/e\\enterrX", "foo bar Xar/eyz"); 0685 DoTest("foo bar bar\\/xyz", "/bar\\\\\\\\/e\\enterrX", "foo bar barX/xyz"); 0686 // If, in a backward search, the first character after the first unescaped "?" is an e, then 0687 // we place the cursor at the end of the word. 0688 DoTest("foo bar bar?eyz bar ba", "?bar?e\\enterrX", "foo bar bar?eyz baX ba"); 0689 // Needs to be unescaped, though! 0690 DoTest("foo bar bar?eyz bar ba", "?bar\\\\?e\\enterrX", "foo bar Xar?eyz bar ba"); 0691 DoTest("foo bar bar\\?eyz bar ba", "?bar\\\\\\\\?e\\enterrX", "foo bar barX?eyz bar ba"); 0692 // Quick check that repeating the last search and placing the cursor at the end of the match works. 0693 DoTest("foo bar bar", "/bar\\entergg//e\\enterrX", "foo baX bar"); 0694 DoTest("foo bar bar", "?bar\\entergg??e\\enterrX", "foo bar baX"); 0695 // When repeating a change, don't try to convert from Vim to Qt regex again. 0696 DoTest("foo bar()", "/bar()\\entergg//e\\enterrX", "foo bar(X"); 0697 DoTest("foo bar()", "?bar()\\entergg??e\\enterrX", "foo bar(X"); 0698 // If the last search said that we should place the cursor at the end of the match, then 0699 // do this with n & N. 0700 DoTest("foo bar bar foo", "/bar/e\\enterggnrX", "foo baX bar foo"); 0701 DoTest("foo bar bar foo", "/bar/e\\enterggNrX", "foo bar baX foo"); 0702 // Don't do this if that search was aborted, though. 0703 DoTest("foo bar bar foo", "/bar\\enter/bar/e\\ctrl-cggnrX", "foo Xar bar foo"); 0704 DoTest("foo bar bar foo", "/bar\\enter/bar/e\\ctrl-cggNrX", "foo bar Xar foo"); 0705 // "#" and "*" reset the "place cursor at the end of the match" to false. 0706 DoTest("foo bar bar foo", "/bar/e\\enterggw*nrX", "foo Xar bar foo"); 0707 DoTest("foo bar bar foo", "/bar/e\\enterggw#nrX", "foo Xar bar foo"); 0708 0709 // "/" and "?" should be usable as motions. 0710 DoTest("foo bar", "ld/bar\\enter", "fbar"); 0711 // They are not linewise. 0712 DoTest("foo bar\nxyz", "ld/yz\\enter", "fyz"); 0713 DoTest("foo bar\nxyz", "jld?oo\\enter", "fyz"); 0714 // Should be usable in Visual Mode without aborting Visual Mode. 0715 DoTest("foo bar", "lv/bar\\enterd", "far"); 0716 // Same for ?. 0717 DoTest("foo bar", "$hd?oo\\enter", "far"); 0718 DoTest("foo bar", "$hv?oo\\enterd", "fr"); 0719 DoTest("foo bar", "lv?bar\\enterd", "far"); 0720 // If we abort the "/" / "?" motion, the command should be aborted, too. 0721 DoTest("foo bar", "d/bar\\esc", "foo bar"); 0722 DoTest("foo bar", "d/bar\\ctrl-c", "foo bar"); 0723 DoTest("foo bar", "d/bar\\ctrl-[", "foo bar"); 0724 // We should be able to repeat a command using "/" or "?" as the motion. 0725 DoTest("foo bar bar bar", "d/bar\\enter.", "bar bar"); 0726 // The "synthetic" Enter keypress should not be logged as part of the command to be repeated. 0727 DoTest("foo bar bar bar\nxyz", "d/bar\\enter.rX", "Xar bar\nxyz"); 0728 // Counting. 0729 DoTest("foo bar bar bar", "2/bar\\enterrX", "foo bar Xar bar"); 0730 // Counting with wraparound. 0731 DoTest("foo bar bar bar", "4/bar\\enterrX", "foo Xar bar bar"); 0732 // Counting in Visual Mode. 0733 DoTest("foo bar bar bar", "v2/bar\\enterd", "ar bar"); 0734 // Should update the selection in Visual Mode as we search. 0735 BeginTest("foo bar bbc"); 0736 TestPressKey("vl/b"); 0737 QCOMPARE(kate_view->selectionText(), QString("foo b")); 0738 TestPressKey("b"); 0739 QCOMPARE(kate_view->selectionText(), QString("foo bar b")); 0740 TestPressKey("\\ctrl-h"); 0741 QCOMPARE(kate_view->selectionText(), QString("foo b")); 0742 TestPressKey("notexists"); 0743 QCOMPARE(kate_view->selectionText(), QString("fo")); 0744 TestPressKey("\\enter"); // Dismiss bar. 0745 QCOMPARE(kate_view->selectionText(), QString("fo")); 0746 FinishTest("foo bar bbc"); 0747 BeginTest("foo\nxyz\nbar\nbbc"); 0748 TestPressKey("Vj/b"); 0749 QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar")); 0750 TestPressKey("b"); 0751 QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar\nbbc")); 0752 TestPressKey("\\ctrl-h"); 0753 QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar")); 0754 TestPressKey("notexists"); 0755 QCOMPARE(kate_view->selectionText(), QString("foo\nxyz")); 0756 TestPressKey("\\ctrl-c"); // Dismiss bar. 0757 FinishTest("foo\nxyz\nbar\nbbc"); 0758 // Dismissing the search bar in visual mode should leave original selection. 0759 BeginTest("foo bar bbc"); 0760 TestPressKey("vl/\\ctrl-c"); 0761 QCOMPARE(kate_view->selectionText(), QString("fo")); 0762 FinishTest("foo bar bbc"); 0763 BeginTest("foo bar bbc"); 0764 TestPressKey("vl?\\ctrl-c"); 0765 QCOMPARE(kate_view->selectionText(), QString("fo")); 0766 FinishTest("foo bar bbc"); 0767 BeginTest("foo bar bbc"); 0768 TestPressKey("vl/b\\ctrl-c"); 0769 QCOMPARE(kate_view->selectionText(), QString("fo")); 0770 FinishTest("foo bar bbc"); 0771 BeginTest("foo\nbar\nbbc"); 0772 TestPressKey("Vl/b\\ctrl-c"); 0773 QCOMPARE(kate_view->selectionText(), QString("foo")); 0774 FinishTest("foo\nbar\nbbc"); 0775 0776 // Search-highlighting tests. 0777 const QColor searchHighlightColour = kate_view->renderer()->config()->searchHighlightColor(); 0778 BeginTest("foo bar xyz"); 0779 // Sanity test. 0780 const QVector<Kate::TextRange *> rangesInitial = rangesOnFirstLine(); 0781 Q_ASSERT(rangesInitial.isEmpty() && "Assumptions about ranges are wrong - this test is invalid and may need updating!"); 0782 FinishTest("foo bar xyz"); 0783 0784 // Test highlighting single character match. 0785 BeginTest("foo bar xyz"); 0786 TestPressKey("/b"); 0787 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0788 QCOMPARE(rangesOnFirstLine().first()->attribute()->background().color(), searchHighlightColour); 0789 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 0790 QCOMPARE(rangesOnFirstLine().first()->start().column(), 4); 0791 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 0792 QCOMPARE(rangesOnFirstLine().first()->end().column(), 5); 0793 TestPressKey("\\enter"); 0794 FinishTest("foo bar xyz"); 0795 0796 // Test highlighting two character match. 0797 BeginTest("foo bar xyz"); 0798 TestPressKey("/ba"); 0799 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0800 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 0801 QCOMPARE(rangesOnFirstLine().first()->start().column(), 4); 0802 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 0803 QCOMPARE(rangesOnFirstLine().first()->end().column(), 6); 0804 TestPressKey("\\enter"); 0805 FinishTest("foo bar xyz"); 0806 0807 // Test no highlighting if no longer a match. 0808 BeginTest("foo bar xyz"); 0809 TestPressKey("/baz"); 0810 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0811 TestPressKey("\\enter"); 0812 FinishTest("foo bar xyz"); 0813 0814 // Test highlighting on wraparound. 0815 BeginTest(" foo bar xyz"); 0816 TestPressKey("ww/foo"); 0817 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0818 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 0819 QCOMPARE(rangesOnFirstLine().first()->start().column(), 1); 0820 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 0821 QCOMPARE(rangesOnFirstLine().first()->end().column(), 4); 0822 TestPressKey("\\enter"); 0823 FinishTest(" foo bar xyz"); 0824 0825 // Test highlighting backwards 0826 BeginTest("foo bar xyz"); 0827 TestPressKey("$?ba"); 0828 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0829 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 0830 QCOMPARE(rangesOnFirstLine().first()->start().column(), 4); 0831 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 0832 QCOMPARE(rangesOnFirstLine().first()->end().column(), 6); 0833 TestPressKey("\\enter"); 0834 FinishTest("foo bar xyz"); 0835 0836 // Test no highlighting when no match is found searching backwards 0837 BeginTest("foo bar xyz"); 0838 TestPressKey("$?baz"); 0839 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0840 TestPressKey("\\enter"); 0841 FinishTest("foo bar xyz"); 0842 0843 // Test highlight when wrapping around after searching backwards. 0844 BeginTest("foo bar xyz"); 0845 TestPressKey("w?xyz"); 0846 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0847 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 0848 QCOMPARE(rangesOnFirstLine().first()->start().column(), 8); 0849 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 0850 QCOMPARE(rangesOnFirstLine().first()->end().column(), 11); 0851 TestPressKey("\\enter"); 0852 FinishTest("foo bar xyz"); 0853 0854 // Test no highlighting when bar is dismissed. 0855 DoTest("foo bar xyz", "/bar\\ctrl-c", "foo bar xyz"); 0856 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0857 DoTest("foo bar xyz", ":set-nohls\\enter/bar\\enter", "foo bar xyz"); 0858 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0859 DoTest("foo bar xyz", "/bar\\ctrl-[", "foo bar xyz"); 0860 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0861 DoTest("foo bar xyz", ":set-nohls\\enter/bar\\return", "foo bar xyz"); 0862 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0863 DoTest("foo bar xyz", "/bar\\esc", "foo bar xyz"); 0864 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 0865 0866 // Update colour on config change. 0867 BeginTest("foo bar xyz"); 0868 TestPressKey("/xyz"); 0869 const QColor newSearchHighlightColour = QColor(255, 0, 0); 0870 kate_view->renderer()->config()->setSearchHighlightColor(newSearchHighlightColour); 0871 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 0872 QCOMPARE(rangesOnFirstLine().first()->attribute()->background().color(), newSearchHighlightColour); 0873 TestPressKey("\\enter"); 0874 FinishTest("foo bar xyz"); 0875 0876 // Set the background colour appropriately. 0877 KColorScheme currentColorScheme(QPalette::Normal); 0878 const QColor normalBackgroundColour = QPalette().brush(QPalette::Base).color(); 0879 const QColor matchBackgroundColour = currentColorScheme.background(KColorScheme::PositiveBackground).color(); 0880 const QColor noMatchBackgroundColour = currentColorScheme.background(KColorScheme::NegativeBackground).color(); 0881 BeginTest("foo bar xyz"); 0882 TestPressKey("/xyz"); 0883 verifyTextEditBackgroundColour(matchBackgroundColour); 0884 TestPressKey("a"); 0885 verifyTextEditBackgroundColour(noMatchBackgroundColour); 0886 TestPressKey("\\ctrl-w"); 0887 verifyTextEditBackgroundColour(normalBackgroundColour); 0888 TestPressKey("/xyz\\enter/"); 0889 verifyTextEditBackgroundColour(normalBackgroundColour); 0890 TestPressKey("\\enter"); 0891 FinishTest("foo bar xyz"); 0892 0893 // Escape regex's in a Vim-ish style. 0894 // Unescaped ( and ) are always literals. 0895 DoTest("foo bar( xyz", "/bar(\\enterrX", "foo Xar( xyz"); 0896 DoTest("foo bar) xyz", "/bar)\\enterrX", "foo Xar) xyz"); 0897 // + is literal, unless it is already escaped. 0898 DoTest("foo bar+ xyz", "/bar+ \\enterrX", "foo Xar+ xyz"); 0899 DoTest(" foo+AAAAbar", "/foo+A\\\\+bar\\enterrX", " Xoo+AAAAbar"); 0900 DoTest(" foo++++bar", "/foo+\\\\+bar\\enterrX", " Xoo++++bar"); 0901 DoTest(" foo++++bar", "/+\\enterrX", " fooX+++bar"); 0902 // An escaped "\" is a literal, of course. 0903 DoTest("foo x\\y", "/x\\\\\\\\y\\enterrX", "foo X\\y"); 0904 // ( and ), if escaped, are not literals. 0905 DoTest("foo barbarxyz", "/ \\\\(bar\\\\)\\\\+xyz\\enterrX", "foo Xbarbarxyz"); 0906 // Handle escaping correctly if we have an escaped and unescaped bracket next to each other. 0907 DoTest("foo x(A)y", "/x(\\\\(.\\\\))y\\enterrX", "foo X(A)y"); 0908 // |, if unescaped, is literal. 0909 DoTest("foo |bar", "/|\\enterrX", "foo Xbar"); 0910 // |, if escaped, is not a literal. 0911 DoTest("foo xfoo\\y xbary", "/x\\\\(foo\\\\|bar\\\\)y\\enterrX", "foo xfoo\\y Xbary"); 0912 // A single [ is a literal. 0913 DoTest("foo bar[", "/bar[\\enterrX", "foo Xar["); 0914 // A single ] is a literal. 0915 DoTest("foo bar]", "/bar]\\enterrX", "foo Xar]"); 0916 // A matching [ and ] are *not* literals. 0917 DoTest("foo xbcay", "/x[abc]\\\\+y\\enterrX", "foo Xbcay"); 0918 DoTest("foo xbcay", "/[abc]\\\\+y\\enterrX", "foo xXcay"); 0919 DoTest("foo xbaadcdcy", "/x[ab]\\\\+[cd]\\\\+y\\enterrX", "foo Xbaadcdcy"); 0920 // Need to be an unescaped match, though. 0921 DoTest("foo xbcay", "/x[abc\\\\]\\\\+y\\enterrX", "Xoo xbcay"); 0922 DoTest("foo xbcay", "/x\\\\[abc]\\\\+y\\enterrX", "Xoo xbcay"); 0923 DoTest("foo x[abc]]]]]y", "/x\\\\[abc]\\\\+y\\enterrX", "foo X[abc]]]]]y"); 0924 // An escaped '[' between matching unescaped '[' and ']' is treated as a literal '[' 0925 DoTest("foo xb[cay", "/x[a\\\\[bc]\\\\+y\\enterrX", "foo Xb[cay"); 0926 // An escaped ']' between matching unescaped '[' and ']' is treated as a literal ']' 0927 DoTest("foo xb]cay", "/x[a\\\\]bc]\\\\+y\\enterrX", "foo Xb]cay"); 0928 // An escaped '[' not between other square brackets is a literal. 0929 DoTest("foo xb[cay", "/xb\\\\[\\enterrX", "foo Xb[cay"); 0930 DoTest("foo xb[cay", "/\\\\[ca\\enterrX", "foo xbXcay"); 0931 // An escaped ']' not between other square brackets is a literal. 0932 DoTest("foo xb]cay", "/xb\\\\]\\enterrX", "foo Xb]cay"); 0933 DoTest("foo xb]cay", "/\\\\]ca\\enterrX", "foo xbXcay"); 0934 // An unescaped '[' not between other square brackets is a literal. 0935 DoTest("foo xbaba[y", "/x[ab]\\\\+[y\\enterrX", "foo Xbaba[y"); 0936 DoTest("foo xbaba[dcdcy", "/x[ab]\\\\+[[cd]\\\\+y\\enterrX", "foo Xbaba[dcdcy"); 0937 // An unescaped ']' not between other square brackets is a literal. 0938 DoTest("foo xbaba]y", "/x[ab]\\\\+]y\\enterrX", "foo Xbaba]y"); 0939 DoTest("foo xbaba]dcdcy", "/x[ab]\\\\+][cd]\\\\+y\\enterrX", "foo Xbaba]dcdcy"); 0940 // Be more clever about how we identify escaping: the presence of a preceding 0941 // backslash is not always sufficient! 0942 DoTest("foo x\\babay", "/x\\\\\\\\[ab]\\\\+y\\enterrX", "foo X\\babay"); 0943 DoTest("foo x\\[abc]]]]y", "/x\\\\\\\\\\\\[abc]\\\\+y\\enterrX", "foo X\\[abc]]]]y"); 0944 DoTest("foo xa\\b\\c\\y", "/x[abc\\\\\\\\]\\\\+y\\enterrX", "foo Xa\\b\\c\\y"); 0945 DoTest("foo x[abc\\]]]]y", "/x[abc\\\\\\\\\\\\]\\\\+y\\enterrX", "foo X[abc\\]]]]y"); 0946 DoTest("foo xa[\\b\\[y", "/x[ab\\\\\\\\[]\\\\+y\\enterrX", "foo Xa[\\b\\[y"); 0947 DoTest("foo x\\[y", "/x\\\\\\\\[y\\enterrX", "foo X\\[y"); 0948 DoTest("foo x\\]y", "/x\\\\\\\\]y\\enterrX", "foo X\\]y"); 0949 DoTest("foo x\\+y", "/x\\\\\\\\+y\\enterrX", "foo X\\+y"); 0950 // A dot is not a literal, nor is a star. 0951 DoTest("foo bar", "/o.*b\\enterrX", "fXo bar"); 0952 // Escaped dots and stars are literals, though. 0953 DoTest("foo xay x.y", "/x\\\\.y\\enterrX", "foo xay X.y"); 0954 DoTest("foo xaaaay xa*y", "/xa\\\\*y\\enterrX", "foo xaaaay Xa*y"); 0955 // Unescaped curly braces are literals. 0956 DoTest("foo x{}y", "/x{}y\\enterrX", "foo X{}y"); 0957 // Escaped curly brackets are quantifers. 0958 DoTest("foo xaaaaay", "/xa\\\\{5\\\\}y\\enterrX", "foo Xaaaaay"); 0959 // Matching curly brackets where only the first is escaped are also quantifiers. 0960 DoTest("foo xaaaaaybbbz", "/xa\\\\{5}yb\\\\{3}z\\enterrX", "foo Xaaaaaybbbz"); 0961 // Make sure it really is escaped, though! 0962 DoTest("foo xa\\{5}", "/xa\\\\\\\\{5}\\enterrX", "foo Xa\\{5}"); 0963 // Don't crash if the first character is a } 0964 DoTest("foo aaaaay", "/{\\enterrX", "Xoo aaaaay"); 0965 // Vim's '\<' and '\>' map, roughly, to Qt's '\b' 0966 DoTest("foo xbar barx bar", "/bar\\\\>\\enterrX", "foo xXar barx bar"); 0967 DoTest("foo xbar barx bar", "/\\\\<bar\\enterrX", "foo xbar Xarx bar"); 0968 DoTest("foo xbar barx bar ", "/\\\\<bar\\\\>\\enterrX", "foo xbar barx Xar "); 0969 DoTest("foo xbar barx bar", "/\\\\<bar\\\\>\\enterrX", "foo xbar barx Xar"); 0970 DoTest("foo xbar barx\nbar", "/\\\\<bar\\\\>\\enterrX", "foo xbar barx\nXar"); 0971 // Escaped "^" and "$" are treated as literals. 0972 DoTest("foo x^$y", "/x\\\\^\\\\$y\\enterrX", "foo X^$y"); 0973 // Ensure that it is the escaped version of the pattern that is recorded as the last search pattern. 0974 DoTest("foo bar( xyz", "/bar(\\enterggnrX", "foo Xar( xyz"); 0975 0976 // Don't log keypresses sent to the emulated command bar as commands to be repeated via "."! 0977 DoTest("foo", "/diw\\enterciwbar\\ctrl-c.", "bar"); 0978 0979 // Don't leave Visual mode on aborting a search. 0980 DoTest("foo bar", "vw/\\ctrl-cd", "ar"); 0981 DoTest("foo bar", "vw/\\ctrl-[d", "ar"); 0982 0983 // Don't crash on leaving Visual Mode on aborting a search. This is perhaps the most opaque regression 0984 // test ever; what it's testing for is the situation where the synthetic keypress issue by the emulated 0985 // command bar on the "ctrl-[" is sent to the key mapper. This in turn converts it into a weird character 0986 // which is then, upon not being recognised as part of a mapping, sent back around the keypress processing, 0987 // where it ends up being sent to the emulated command bar's text edit, which in turn issues a "text changed" 0988 // event where the text is still empty, which tries to move the cursor to (-1, -1), which causes a crash deep 0989 // within Kate. So, in a nutshell: this test ensures that the keymapper never handles the synthetic keypress :) 0990 DoTest("", "ifoo\\ctrl-cv/\\ctrl-[", "foo"); 0991 0992 // History auto-completion tests. 0993 clearSearchHistory(); 0994 QVERIFY(searchHistory().isEmpty()); 0995 vi_global->searchHistory()->append("foo"); 0996 vi_global->searchHistory()->append("bar"); 0997 QCOMPARE(searchHistory(), 0998 QStringList() << "foo" 0999 << "bar"); 1000 clearSearchHistory(); 1001 QVERIFY(searchHistory().isEmpty()); 1002 1003 // Ensure current search bar text is added to the history if we press enter. 1004 DoTest("foo bar", "/bar\\enter", "foo bar"); 1005 DoTest("foo bar", "/xyz\\enter", "foo bar"); 1006 QCOMPARE(searchHistory(), 1007 QStringList() << "bar" 1008 << "xyz"); 1009 // Interesting - Vim adds the search bar text to the history even if we abort via e.g. ctrl-c, ctrl-[, etc. 1010 clearSearchHistory(); 1011 DoTest("foo bar", "/baz\\ctrl-[", "foo bar"); 1012 QCOMPARE(searchHistory(), QStringList() << "baz"); 1013 clearSearchHistory(); 1014 DoTest("foo bar", "/foo\\esc", "foo bar"); 1015 QCOMPARE(searchHistory(), QStringList() << "foo"); 1016 clearSearchHistory(); 1017 DoTest("foo bar", "/nose\\ctrl-c", "foo bar"); 1018 QCOMPARE(searchHistory(), QStringList() << "nose"); 1019 1020 clearSearchHistory(); 1021 vi_global->searchHistory()->append("foo"); 1022 vi_global->searchHistory()->append("bar"); 1023 QVERIFY(emulatedCommandBarCompleter() != nullptr); 1024 BeginTest("foo bar"); 1025 TestPressKey("/\\ctrl-p"); 1026 verifyCommandBarCompletionVisible(); 1027 // Make sure the completion appears in roughly the correct place: this is a little fragile :/ 1028 const QPoint completerRectTopLeft = emulatedCommandBarCompleter()->popup()->mapToGlobal(emulatedCommandBarCompleter()->popup()->rect().topLeft()); 1029 const QPoint barEditBottomLeft = emulatedCommandBarTextEdit()->mapToGlobal(emulatedCommandBarTextEdit()->rect().bottomLeft()); 1030 QCOMPARE(completerRectTopLeft.x(), barEditBottomLeft.x()); 1031 QVERIFY(qAbs(completerRectTopLeft.y() - barEditBottomLeft.y()) <= 1); 1032 // Will activate the current completion item, activating the search, and dismissing the bar. 1033 TestPressKey("\\enter"); 1034 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1035 // Close the command bar. 1036 FinishTest("foo bar"); 1037 1038 // Don't show completion with an empty search bar. 1039 clearSearchHistory(); 1040 vi_global->searchHistory()->append("foo"); 1041 BeginTest("foo bar"); 1042 TestPressKey("/"); 1043 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1044 TestPressKey("\\enter"); 1045 FinishTest("foo bar"); 1046 1047 // Don't auto-complete, either. 1048 clearSearchHistory(); 1049 vi_global->searchHistory()->append("foo"); 1050 BeginTest("foo bar"); 1051 TestPressKey("/f"); 1052 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1053 TestPressKey("\\enter"); 1054 FinishTest("foo bar"); 1055 1056 clearSearchHistory(); 1057 vi_global->searchHistory()->append("xyz"); 1058 vi_global->searchHistory()->append("bar"); 1059 QVERIFY(emulatedCommandBarCompleter() != nullptr); 1060 BeginTest("foo bar"); 1061 TestPressKey("/\\ctrl-p"); 1062 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar")); 1063 TestPressKey("\\enter"); // Dismiss bar. 1064 FinishTest("foo bar"); 1065 1066 clearSearchHistory(); 1067 vi_global->searchHistory()->append("xyz"); 1068 vi_global->searchHistory()->append("bar"); 1069 vi_global->searchHistory()->append("foo"); 1070 QVERIFY(emulatedCommandBarCompleter() != nullptr); 1071 BeginTest("foo bar"); 1072 TestPressKey("/\\ctrl-p"); 1073 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 1074 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo")); 1075 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0); 1076 TestPressKey("\\ctrl-p"); 1077 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar")); 1078 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar")); 1079 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 1); 1080 TestPressKey("\\ctrl-p"); 1081 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz")); 1082 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz")); 1083 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2); 1084 TestPressKey("\\ctrl-p"); 1085 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 1086 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo")); // Wrap-around 1087 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0); 1088 TestPressKey("\\enter"); // Dismiss bar. 1089 FinishTest("foo bar"); 1090 1091 clearSearchHistory(); 1092 vi_global->searchHistory()->append("xyz"); 1093 vi_global->searchHistory()->append("bar"); 1094 vi_global->searchHistory()->append("foo"); 1095 QVERIFY(emulatedCommandBarCompleter() != nullptr); 1096 BeginTest("foo bar"); 1097 TestPressKey("/\\ctrl-n"); 1098 verifyCommandBarCompletionVisible(); 1099 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz")); 1100 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz")); 1101 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2); 1102 TestPressKey("\\ctrl-n"); 1103 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar")); 1104 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar")); 1105 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 1); 1106 TestPressKey("\\ctrl-n"); 1107 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 1108 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo")); 1109 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0); 1110 TestPressKey("\\ctrl-n"); 1111 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz")); 1112 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz")); // Wrap-around. 1113 QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2); 1114 TestPressKey("\\enter"); // Dismiss bar. 1115 FinishTest("foo bar"); 1116 1117 clearSearchHistory(); 1118 vi_global->searchHistory()->append("xyz"); 1119 vi_global->searchHistory()->append("bar"); 1120 vi_global->searchHistory()->append("foo"); 1121 BeginTest("foo bar"); 1122 TestPressKey("/\\ctrl-n\\ctrl-n"); 1123 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar")); 1124 TestPressKey("\\enter"); // Dismiss bar. 1125 FinishTest("foo bar"); 1126 1127 // If we add something to the history, remove any earliest occurrences (this is what Vim appears to do) 1128 // and append to the end. 1129 clearSearchHistory(); 1130 vi_global->searchHistory()->append("bar"); 1131 vi_global->searchHistory()->append("xyz"); 1132 vi_global->searchHistory()->append("foo"); 1133 vi_global->searchHistory()->append("xyz"); 1134 QCOMPARE(searchHistory(), 1135 QStringList() << "bar" 1136 << "foo" 1137 << "xyz"); 1138 1139 // Push out older entries if we have too many search items in the history. 1140 const int HISTORY_SIZE_LIMIT = 100; 1141 clearSearchHistory(); 1142 for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++) { 1143 vi_global->searchHistory()->append(QString("searchhistoryitem %1").arg(i)); 1144 } 1145 QCOMPARE(searchHistory().size(), HISTORY_SIZE_LIMIT); 1146 QCOMPARE(searchHistory().first(), QString("searchhistoryitem 1")); 1147 QCOMPARE(searchHistory().last(), QString("searchhistoryitem 100")); 1148 vi_global->searchHistory()->append(QString("searchhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1149 QCOMPARE(searchHistory().size(), HISTORY_SIZE_LIMIT); 1150 QCOMPARE(searchHistory().first(), QString("searchhistoryitem 2")); 1151 QCOMPARE(searchHistory().last(), QString("searchhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1152 1153 // Don't add empty searches to the history. 1154 clearSearchHistory(); 1155 DoTest("foo bar", "/\\enter", "foo bar"); 1156 QVERIFY(searchHistory().isEmpty()); 1157 1158 // "*" and "#" should add the relevant word to the search history, enclosed between \< and \> 1159 clearSearchHistory(); 1160 BeginTest("foo bar"); 1161 TestPressKey("*"); 1162 QVERIFY(!searchHistory().isEmpty()); 1163 QCOMPARE(searchHistory().last(), QString("\\<foo\\>")); 1164 TestPressKey("w#"); 1165 QCOMPARE(searchHistory().size(), 2); 1166 QCOMPARE(searchHistory().last(), QString("\\<bar\\>")); 1167 1168 // Auto-complete words from the document on ctrl-space. 1169 // Test that we can actually find a single word and add it to the list of completions. 1170 BeginTest("foo"); 1171 TestPressKey("/\\ctrl- "); 1172 verifyCommandBarCompletionVisible(); 1173 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo")); 1174 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1175 FinishTest("foo"); 1176 1177 // Count digits and underscores as being part of a word. 1178 BeginTest("foo_12"); 1179 TestPressKey("/\\ctrl- "); 1180 verifyCommandBarCompletionVisible(); 1181 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo_12")); 1182 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1183 FinishTest("foo_12"); 1184 1185 // This feels a bit better to me, usability-wise: in the special case of completion from document, where 1186 // the completion list is manually summoned, allow one to press Enter without the bar being dismissed 1187 // (just dismiss the completion list instead). 1188 BeginTest("foo_12"); 1189 TestPressKey("/\\ctrl- \\ctrl-p\\enter"); 1190 QVERIFY(emulatedCommandBar->isVisible()); 1191 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1192 TestPressKey("\\enter"); // Dismiss bar. 1193 FinishTest("foo_12"); 1194 1195 // Check that we can find multiple words on one line. 1196 BeginTest("bar (foo) [xyz]"); 1197 TestPressKey("/\\ctrl- "); 1198 QStringListModel *completerStringListModel = dynamic_cast<QStringListModel *>(emulatedCommandBarCompleter()->model()); 1199 Q_ASSERT(completerStringListModel); 1200 QCOMPARE(completerStringListModel->stringList(), 1201 QStringList() << "bar" 1202 << "foo" 1203 << "xyz"); 1204 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1205 FinishTest("bar (foo) [xyz]"); 1206 1207 // Check that we arrange the found words in case-insensitive sorted order. 1208 BeginTest("D c e a b f"); 1209 TestPressKey("/\\ctrl- "); 1210 verifyCommandBarCompletionsMatches(QStringList() << "a" 1211 << "b" 1212 << "c" 1213 << "D" 1214 << "e" 1215 << "f"); 1216 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1217 FinishTest("D c e a b f"); 1218 1219 // Check that we don't include the same word multiple times. 1220 BeginTest("foo bar bar bar foo"); 1221 TestPressKey("/\\ctrl- "); 1222 verifyCommandBarCompletionsMatches(QStringList() << "bar" 1223 << "foo"); 1224 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1225 FinishTest("foo bar bar bar foo"); 1226 1227 // Check that we search only a narrow portion of the document, around the cursor (4096 lines either 1228 // side, say). 1229 QStringList manyLines; 1230 for (int i = 1; i < 2 * 4096 + 3; i++) { 1231 // Pad the digits so that when sorted alphabetically, they are also sorted numerically. 1232 manyLines << QString("word%1").arg(i, 5, 10, QChar('0')); 1233 } 1234 QStringList allButFirstAndLastOfManyLines = manyLines; 1235 allButFirstAndLastOfManyLines.removeFirst(); 1236 allButFirstAndLastOfManyLines.removeLast(); 1237 1238 BeginTest(manyLines.join("\n")); 1239 TestPressKey("4097j/\\ctrl- "); 1240 verifyCommandBarCompletionsMatches(allButFirstAndLastOfManyLines); 1241 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1242 FinishTest(manyLines.join("\n")); 1243 1244 // "The current word" means the word before the cursor in the command bar, and includes numbers 1245 // and underscores. Make sure also that the completion prefix is set when the completion is first invoked. 1246 BeginTest("foo fee foa_11 foa_11b"); 1247 // Write "bar(foa112$nose" and position cursor before the "2", then invoke completion. 1248 TestPressKey("/bar(foa_112$nose\\left\\left\\left\\left\\left\\left\\ctrl- "); 1249 verifyCommandBarCompletionsMatches(QStringList() << "foa_11" 1250 << "foa_11b"); 1251 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1252 FinishTest("foo fee foa_11 foa_11b"); 1253 1254 // But don't count "-" as being part of the current word. 1255 BeginTest("foo_12"); 1256 TestPressKey("/bar-foo\\ctrl- "); 1257 verifyCommandBarCompletionVisible(); 1258 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo_12")); 1259 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1260 FinishTest("foo_12"); 1261 1262 // Be case insensitive. 1263 BeginTest("foo Fo12 fOo13 FO45"); 1264 TestPressKey("/fo\\ctrl- "); 1265 verifyCommandBarCompletionsMatches(QStringList() << "Fo12" 1266 << "FO45" 1267 << "foo" 1268 << "fOo13"); 1269 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1270 FinishTest("foo Fo12 fOo13 FO45"); 1271 1272 // Feed the current word to complete to the completer as we type/ edit. 1273 BeginTest("foo fee foa foab"); 1274 TestPressKey("/xyz|f\\ctrl- o"); 1275 verifyCommandBarCompletionsMatches(QStringList() << "foa" 1276 << "foab" 1277 << "foo"); 1278 TestPressKey("a"); 1279 verifyCommandBarCompletionsMatches(QStringList() << "foa" 1280 << "foab"); 1281 TestPressKey("\\ctrl-h"); 1282 verifyCommandBarCompletionsMatches(QStringList() << "foa" 1283 << "foab" 1284 << "foo"); 1285 TestPressKey("o"); 1286 verifyCommandBarCompletionsMatches(QStringList() << "foo"); 1287 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1288 FinishTest("foo fee foa foab"); 1289 1290 // Upon selecting a completion with an empty command bar, add the completed text to the command bar. 1291 BeginTest("foo fee fob foables"); 1292 TestPressKey("/\\ctrl- foa\\ctrl-p"); 1293 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foables")); 1294 verifyCommandBarCompletionVisible(); 1295 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1296 FinishTest("foo fee fob foables"); 1297 1298 // If bar is non-empty, replace the word under the cursor. 1299 BeginTest("foo fee foa foab"); 1300 TestPressKey("/xyz|f$nose\\left\\left\\left\\left\\left\\ctrl- oa\\ctrl-p"); 1301 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz|foab$nose")); 1302 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1303 FinishTest("foo fee foa foab"); 1304 1305 // Place the cursor at the end of the completed text. 1306 BeginTest("foo fee foa foab"); 1307 TestPressKey("/xyz|f$nose\\left\\left\\left\\left\\left\\ctrl- oa\\ctrl-p\\enterX"); 1308 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz|foabX$nose")); 1309 TestPressKey("\\ctrl-c"); // Dismiss completion, then bar. 1310 FinishTest("foo fee foa foab"); 1311 1312 // If we're completing from history, though, the entire text gets set, and the completion prefix 1313 // is the beginning of the entire text, not the current word before the cursor. 1314 clearSearchHistory(); 1315 vi_global->searchHistory()->append("foo(bar"); 1316 BeginTest(""); 1317 TestPressKey("/foo(b\\ctrl-p"); 1318 verifyCommandBarCompletionVisible(); 1319 verifyCommandBarCompletionsMatches(QStringList() << "foo(bar"); 1320 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(bar")); 1321 TestPressKey("\\enter"); // Dismiss bar. 1322 FinishTest(""); 1323 1324 // If we're completing from history and we abort the completion via ctrl-c or ctrl-[, we revert the whole 1325 // text to the last manually typed text. 1326 clearSearchHistory(); 1327 vi_global->searchHistory()->append("foo(b|ar"); 1328 BeginTest(""); 1329 TestPressKey("/foo(b\\ctrl-p"); 1330 verifyCommandBarCompletionVisible(); 1331 verifyCommandBarCompletionsMatches(QStringList() << "foo(b|ar"); 1332 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(b|ar")); 1333 TestPressKey("\\ctrl-c"); // Dismiss completion. 1334 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(b")); 1335 TestPressKey("\\enter"); // Dismiss bar. 1336 FinishTest(""); 1337 1338 // Scroll completion list if necessary so that currently selected completion is visible. 1339 BeginTest("a b c d e f g h i j k l m n o p q r s t u v w x y z"); 1340 TestPressKey("/\\ctrl- "); 1341 const int lastItemRow = 25; 1342 const QRect initialLastCompletionItemRect = 1343 emulatedCommandBarCompleter()->popup()->visualRect(emulatedCommandBarCompleter()->popup()->model()->index(lastItemRow, 0)); 1344 QVERIFY(!emulatedCommandBarCompleter()->popup()->rect().contains( 1345 initialLastCompletionItemRect)); // If this fails, then we have an error in the test setup: initially, the last item in the list should be outside of 1346 // the bounds of the popup. 1347 TestPressKey("\\ctrl-n"); 1348 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("z")); 1349 const QRect lastCompletionItemRect = 1350 emulatedCommandBarCompleter()->popup()->visualRect(emulatedCommandBarCompleter()->popup()->model()->index(lastItemRow, 0)); 1351 QVERIFY(emulatedCommandBarCompleter()->popup()->rect().contains(lastCompletionItemRect)); 1352 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1353 FinishTest("a b c d e f g h i j k l m n o p q r s t u v w x y z"); 1354 1355 // Ensure that the completion list changes size appropriately as the number of candidate completions changes. 1356 BeginTest("a ab abc"); 1357 TestPressKey("/\\ctrl- "); 1358 const int initialPopupHeight = emulatedCommandBarCompleter()->popup()->height(); 1359 TestPressKey("ab"); 1360 const int popupHeightAfterEliminatingOne = emulatedCommandBarCompleter()->popup()->height(); 1361 QVERIFY(popupHeightAfterEliminatingOne < initialPopupHeight); 1362 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1363 FinishTest("a ab abc"); 1364 1365 // Ensure that the completion list disappears when no candidate completions are found, but re-appears 1366 // when some are found. 1367 BeginTest("a ab abc"); 1368 TestPressKey("/\\ctrl- "); 1369 TestPressKey("abd"); 1370 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1371 TestPressKey("\\ctrl-h"); 1372 verifyCommandBarCompletionVisible(); 1373 TestPressKey("\\enter\\enter"); // Dismiss completion, then bar. 1374 FinishTest("a ab abc"); 1375 1376 // ctrl-c and ctrl-[ when the completion list is visible should dismiss the completion list, but *not* 1377 // the emulated command bar. TODO - same goes for ESC, but this is harder as KateViewInternal dismisses it 1378 // itself. 1379 BeginTest("a ab abc"); 1380 TestPressKey("/\\ctrl- \\ctrl-cdiw"); 1381 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1382 QVERIFY(emulatedCommandBar->isVisible()); 1383 TestPressKey("\\enter"); // Dismiss bar. 1384 TestPressKey("/\\ctrl- \\ctrl-[diw"); 1385 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1386 QVERIFY(emulatedCommandBar->isVisible()); 1387 TestPressKey("\\enter"); // Dismiss bar. 1388 FinishTest("a ab abc"); 1389 1390 // If we implicitly choose an element from the summoned completion list (by highlighting it, then 1391 // continuing to edit the text), the completion box should not re-appear unless explicitly summoned 1392 // again, even if the current word has a valid completion. 1393 BeginTest("a ab abc"); 1394 TestPressKey("/\\ctrl- \\ctrl-p"); 1395 TestPressKey(".a"); 1396 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1397 TestPressKey("\\enter"); // Dismiss bar. 1398 FinishTest("a ab abc"); 1399 1400 // If we dismiss the summoned completion list via ctrl-c or ctrl-[, it should not re-appear unless explicitly summoned 1401 // again, even if the current word has a valid completion. 1402 BeginTest("a ab abc"); 1403 TestPressKey("/\\ctrl- \\ctrl-c"); 1404 TestPressKey(".a"); 1405 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1406 TestPressKey("\\enter"); 1407 TestPressKey("/\\ctrl- \\ctrl-["); 1408 TestPressKey(".a"); 1409 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1410 TestPressKey("\\enter"); // Dismiss bar. 1411 FinishTest("a ab abc"); 1412 1413 // If we select a completion from an empty bar, but then dismiss it via ctrl-c or ctrl-[, then we 1414 // should restore the empty text. 1415 BeginTest("foo"); 1416 TestPressKey("/\\ctrl- \\ctrl-p"); 1417 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 1418 TestPressKey("\\ctrl-c"); 1419 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1420 QVERIFY(emulatedCommandBar->isVisible()); 1421 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("")); 1422 TestPressKey("\\enter"); // Dismiss bar. 1423 FinishTest("foo"); 1424 BeginTest("foo"); 1425 TestPressKey("/\\ctrl- \\ctrl-p"); 1426 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo")); 1427 TestPressKey("\\ctrl-["); 1428 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1429 QVERIFY(emulatedCommandBar->isVisible()); 1430 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("")); 1431 TestPressKey("\\enter"); // Dismiss bar. 1432 FinishTest("foo"); 1433 1434 // If we select a completion but then dismiss it via ctrl-c or ctrl-[, then we 1435 // should restore the last manually typed word. 1436 BeginTest("fooabc"); 1437 TestPressKey("/f\\ctrl- o\\ctrl-p"); 1438 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fooabc")); 1439 TestPressKey("\\ctrl-c"); 1440 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1441 QVERIFY(emulatedCommandBar->isVisible()); 1442 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fo")); 1443 TestPressKey("\\enter"); // Dismiss bar. 1444 FinishTest("fooabc"); 1445 1446 // If we select a completion but then dismiss it via ctrl-c or ctrl-[, then we 1447 // should restore the word currently being typed to the last manually typed word. 1448 BeginTest("fooabc"); 1449 TestPressKey("/ab\\ctrl- |fo\\ctrl-p"); 1450 TestPressKey("\\ctrl-c"); 1451 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ab|fo")); 1452 TestPressKey("\\enter"); // Dismiss bar. 1453 FinishTest("fooabc"); 1454 1455 // Set the completion prefix for the search history completion as soon as it is shown. 1456 clearSearchHistory(); 1457 vi_global->searchHistory()->append("foo(bar"); 1458 vi_global->searchHistory()->append("xyz"); 1459 BeginTest(""); 1460 TestPressKey("/f\\ctrl-p"); 1461 verifyCommandBarCompletionVisible(); 1462 verifyCommandBarCompletionsMatches(QStringList() << "foo(bar"); 1463 TestPressKey("\\enter"); // Dismiss bar. 1464 FinishTest(""); 1465 1466 // Command Mode (:) tests. 1467 // ":" should summon the command bar, with ":" as the label. 1468 BeginTest(""); 1469 TestPressKey(":"); 1470 QVERIFY(emulatedCommandBar->isVisible()); 1471 QCOMPARE(emulatedCommandTypeIndicator()->text(), QString(":")); 1472 QVERIFY(emulatedCommandTypeIndicator()->isVisible()); 1473 QVERIFY(emulatedCommandBarTextEdit()); 1474 QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty()); 1475 TestPressKey("\\esc"); 1476 FinishTest(""); 1477 1478 // If we have a selection, it should be encoded as a range in the text edit. 1479 BeginTest("d\nb\na\nc"); 1480 TestPressKey("Vjjj:"); 1481 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>")); 1482 TestPressKey("\\esc"); 1483 FinishTest("d\nb\na\nc"); 1484 1485 // If we have a count, it should be encoded as a range in the text edit. 1486 BeginTest("d\nb\na\nc"); 1487 TestPressKey("7:"); 1488 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6")); 1489 TestPressKey("\\esc"); 1490 FinishTest("d\nb\na\nc"); 1491 1492 // Don't go doing an incremental search when we press keys! 1493 BeginTest("foo bar xyz"); 1494 TestPressKey(":bar"); 1495 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 1496 TestPressKey("\\esc"); 1497 FinishTest("foo bar xyz"); 1498 1499 // Execute the command on Enter. 1500 DoTest("d\nb\na\nc", "Vjjj:sort\\enter", "a\nb\nc\nd"); 1501 1502 // Don't crash if we call a non-existent command with a range. 1503 DoTest("123", ":42nonexistentcommand\\enter", "123"); 1504 1505 // Bar background should always be normal for command bar. 1506 BeginTest("foo"); 1507 TestPressKey("/foo\\enter:"); 1508 verifyTextEditBackgroundColour(normalBackgroundColour); 1509 TestPressKey("\\ctrl-c/bar\\enter:"); 1510 verifyTextEditBackgroundColour(normalBackgroundColour); 1511 TestPressKey("\\esc"); 1512 FinishTest("foo"); 1513 1514 const int commandResponseMessageTimeOutMSOverride = QString::fromLatin1(qgetenv("KATE_VIMODE_TEST_COMMANDRESPONSEMESSAGETIMEOUTMS")).toInt(); 1515 const long commandResponseMessageTimeOutMS = (commandResponseMessageTimeOutMSOverride > 0) ? commandResponseMessageTimeOutMSOverride : 2000; 1516 { 1517 // If there is any output from the command, show it in a label for a short amount of time 1518 // (make sure the bar type indicator is hidden, here, as it looks messy). 1519 emulatedCommandBar->setCommandResponseMessageTimeout(commandResponseMessageTimeOutMS); 1520 BeginTest("foo bar xyz"); 1521 const QDateTime timeJustBeforeCommandExecuted = QDateTime::currentDateTime(); 1522 TestPressKey(":commandthatdoesnotexist\\enter"); 1523 QVERIFY(emulatedCommandBar->isVisible()); 1524 QVERIFY(commandResponseMessageDisplay()); 1525 QVERIFY(commandResponseMessageDisplay()->isVisible()); 1526 QVERIFY(!emulatedCommandBarTextEdit()->isVisible()); 1527 QVERIFY(!emulatedCommandTypeIndicator()->isVisible()); 1528 // Be a bit vague about the exact message, due to i18n, etc. 1529 QVERIFY(commandResponseMessageDisplay()->text().contains("commandthatdoesnotexist")); 1530 waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS); 1531 QVERIFY(timeJustBeforeCommandExecuted.msecsTo(QDateTime::currentDateTime()) 1532 >= commandResponseMessageTimeOutMS - 500); // "- 500" because coarse timers can fire up to 500ms *prematurely*. 1533 QVERIFY(!emulatedCommandBar->isVisible()); 1534 // Piggy-back on this test, as the bug we're about to test for would actually make setting 1535 // up the conditions again in a separate test impossible ;) 1536 // When we next summon the bar, the response message should be invisible; the editor visible & editable; 1537 // and the bar type indicator visible again. 1538 TestPressKey("/"); 1539 QVERIFY(!commandResponseMessageDisplay()->isVisible()); 1540 QVERIFY(emulatedCommandBarTextEdit()->isVisible()); 1541 QVERIFY(emulatedCommandBarTextEdit()->isEnabled()); 1542 QVERIFY(emulatedCommandBar->isVisible()); 1543 TestPressKey("\\esc"); // Dismiss the bar. 1544 FinishTest("foo bar xyz"); 1545 } 1546 1547 { 1548 // Show the same message twice in a row. 1549 BeginTest("foo bar xyz"); 1550 TestPressKey(":othercommandthatdoesnotexist\\enter"); 1551 QDateTime startWaitingForMessageToHide = QDateTime::currentDateTime(); 1552 waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS); 1553 TestPressKey(":othercommandthatdoesnotexist\\enter"); 1554 QVERIFY(commandResponseMessageDisplay()->isVisible()); 1555 // Wait for it to disappear again, as a courtesy for the next test. 1556 waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS); 1557 } 1558 1559 { 1560 // Emulated command bar should not steal keypresses when it is merely showing the results of an executed command. 1561 BeginTest("foo bar"); 1562 TestPressKey(":commandthatdoesnotexist\\enterrX"); 1563 Q_ASSERT_X(commandResponseMessageDisplay()->isVisible(), "running test", "Need to increase timeJustBeforeCommandExecuted!"); 1564 FinishTest("Xoo bar"); 1565 } 1566 1567 { 1568 // Don't send the synthetic "enter" keypress (for making search-as-a-motion work) when we finally hide. 1569 BeginTest("foo bar\nbar"); 1570 TestPressKey(":commandthatdoesnotexist\\enter"); 1571 Q_ASSERT_X(commandResponseMessageDisplay()->isVisible(), "running test", "Need to increase timeJustBeforeCommandExecuted!"); 1572 waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4); 1573 TestPressKey("rX"); 1574 FinishTest("Xoo bar\nbar"); 1575 } 1576 1577 { 1578 // The timeout should be cancelled when we invoke the command bar again. 1579 BeginTest(""); 1580 TestPressKey(":commandthatdoesnotexist\\enter"); 1581 TestPressKey(":"); 1582 // Wait ample time for the timeout to fire. Do not use waitForEmulatedCommandBarToHide for this! 1583 QTRY_VERIFY_WITH_TIMEOUT(emulatedCommandBar->isVisible(), commandResponseMessageTimeOutMS * 2); 1584 TestPressKey("\\esc"); // Dismiss the bar. 1585 FinishTest(""); 1586 } 1587 1588 { 1589 // The timeout should not cause kate_view to regain focus if we have manually taken it away. 1590 qDebug() << " NOTE: this test is weirdly fragile, so if it starts failing, comment it out and e-mail me: it may well be more trouble that it's worth."; 1591 BeginTest(""); 1592 TestPressKey(":commandthatdoesnotexist\\enter"); 1593 // Wait for any focus changes to take effect. 1594 QApplication::processEvents(); 1595 QLineEdit *dummyToFocus = new QLineEdit(QString("Sausage"), mainWindow); 1596 // Take focus away from kate_view by giving it to dummyToFocus. 1597 QApplication::setActiveWindow(mainWindow); 1598 kate_view->setFocus(); 1599 mainWindowLayout->addWidget(dummyToFocus); 1600 dummyToFocus->show(); 1601 dummyToFocus->setEnabled(true); 1602 dummyToFocus->setFocus(); 1603 // Allow dummyToFocus to receive focus. 1604 QTRY_VERIFY(dummyToFocus->hasFocus()); 1605 // Wait ample time for the timeout to fire. Do not use waitForEmulatedCommandBarToHide for this - 1606 // the bar never actually hides in this instance, and I think it would take some deep changes in 1607 // Kate to make it do so (the KateCommandLineBar as the same issue). 1608 QTest::qWait(commandResponseMessageTimeOutMS * 2); 1609 QVERIFY(dummyToFocus->hasFocus()); 1610 QVERIFY(emulatedCommandBar->isVisible()); 1611 mainWindowLayout->removeWidget(dummyToFocus); 1612 // Restore focus to the kate_view. 1613 kate_view->setFocus(); 1614 QTRY_VERIFY(kate_view->hasFocus()); 1615 // *Now* wait for the command bar to disappear - giving kate_view focus should trigger it. 1616 waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4); 1617 FinishTest(""); 1618 } 1619 1620 { 1621 // No completion should be shown when the bar is first shown: this gives us an opportunity 1622 // to invoke command history via ctrl-p and ctrl-n. 1623 BeginTest(""); 1624 TestPressKey(":"); 1625 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1626 TestPressKey("\\ctrl-c"); // Dismiss bar 1627 FinishTest(""); 1628 } 1629 1630 { 1631 // Should be able to switch to completion from document, even when we have a completion from commands. 1632 BeginTest("soggy1 soggy2"); 1633 TestPressKey(":so"); 1634 verifyCommandBarCompletionContains(QStringList() << "sort"); 1635 TestPressKey("\\ctrl- "); 1636 verifyCommandBarCompletionsMatches(QStringList() << "soggy1" 1637 << "soggy2"); 1638 TestPressKey("\\ctrl-c"); // Dismiss completer 1639 TestPressKey("\\ctrl-c"); // Dismiss bar 1640 FinishTest("soggy1 soggy2"); 1641 } 1642 1643 { 1644 // If we dismiss the command completion then change the text, it should summon the completion 1645 // again. 1646 BeginTest(""); 1647 TestPressKey(":so"); 1648 TestPressKey("\\ctrl-c"); // Dismiss completer 1649 TestPressKey("r"); 1650 verifyCommandBarCompletionVisible(); 1651 verifyCommandBarCompletionContains(QStringList() << "sort"); 1652 TestPressKey("\\ctrl-c"); // Dismiss completer 1653 TestPressKey("\\ctrl-c"); // Dismiss bar 1654 FinishTest(""); 1655 } 1656 1657 { 1658 // Completion should be dismissed when we are showing command response text. 1659 BeginTest(""); 1660 TestPressKey(":set-au\\enter"); 1661 QVERIFY(commandResponseMessageDisplay()->isVisible()); 1662 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1663 waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4); 1664 FinishTest(""); 1665 } 1666 1667 // If we abort completion via ctrl-c or ctrl-[, we should revert the current word to the last 1668 // manually entered word. 1669 BeginTest(""); 1670 TestPressKey(":se\\ctrl-p"); 1671 verifyCommandBarCompletionVisible(); 1672 QVERIFY(emulatedCommandBarTextEdit()->text() != "se"); 1673 TestPressKey("\\ctrl-c"); // Dismiss completer 1674 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("se")); 1675 TestPressKey("\\ctrl-c"); // Dismiss bar 1676 FinishTest(""); 1677 1678 // In practice, it's annoying if, as we enter ":s/se", completions pop up after the "se": 1679 // for now, only summon completion if we are on the first word in the text. 1680 BeginTest(""); 1681 TestPressKey(":s/se"); 1682 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1683 TestPressKey("\\ctrl-c"); // Dismiss bar 1684 FinishTest(""); 1685 BeginTest(""); 1686 TestPressKey(":.,.+7s/se"); 1687 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1688 TestPressKey("\\ctrl-c"); // Dismiss bar 1689 FinishTest(""); 1690 1691 // Don't blank the text if we activate command history completion with no command history. 1692 BeginTest(""); 1693 clearCommandHistory(); 1694 TestPressKey(":s/se\\ctrl-p"); 1695 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1696 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/se")); 1697 TestPressKey("\\ctrl-c"); // Dismiss bar 1698 FinishTest(""); 1699 1700 // On completion, only update the command in front of the cursor. 1701 BeginTest(""); 1702 clearCommandHistory(); 1703 TestPressKey(":.,.+6s/se\\left\\left\\leftet-auto-in\\ctrl-p"); 1704 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6set-auto-indent/se")); 1705 TestPressKey("\\ctrl-c"); // Dismiss completer. 1706 TestPressKey("\\ctrl-c"); // Dismiss bar 1707 FinishTest(""); 1708 1709 // On completion, place the cursor after the new command. 1710 BeginTest(""); 1711 clearCommandHistory(); 1712 TestPressKey(":.,.+6s/fo\\left\\left\\leftet-auto-in\\ctrl-pX"); 1713 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6set-auto-indentX/fo")); 1714 TestPressKey("\\ctrl-c"); // Dismiss completer. 1715 TestPressKey("\\ctrl-c"); // Dismiss bar 1716 FinishTest(""); 1717 1718 // "The current word", for Commands, can contain "-". 1719 BeginTest(""); 1720 TestPressKey(":set-\\ctrl-p"); 1721 verifyCommandBarCompletionVisible(); 1722 QVERIFY(emulatedCommandBarTextEdit()->text() != "set-"); 1723 QVERIFY(emulatedCommandBarCompleter()->currentCompletion().startsWith(QLatin1String("set-"))); 1724 QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion()); 1725 TestPressKey("\\ctrl-c"); // Dismiss completion. 1726 TestPressKey("\\ctrl-c"); // Dismiss bar. 1727 FinishTest(""); 1728 1729 { 1730 // Don't switch from word-from-document to command-completion just because we press a key, though! 1731 BeginTest("soggy1 soggy2"); 1732 TestPressKey(":\\ctrl- s"); 1733 TestPressKey("o"); 1734 verifyCommandBarCompletionVisible(); 1735 verifyCommandBarCompletionsMatches(QStringList() << "soggy1" 1736 << "soggy2"); 1737 TestPressKey("\\ctrl-c"); // Dismiss completer 1738 TestPressKey("\\ctrl-c"); // Dismiss bar 1739 FinishTest("soggy1 soggy2"); 1740 } 1741 1742 { 1743 // If we're in a place where there is no command completion allowed, don't go hiding the word 1744 // completion as we type. 1745 BeginTest("soggy1 soggy2"); 1746 TestPressKey(":s/s\\ctrl- o"); 1747 verifyCommandBarCompletionVisible(); 1748 verifyCommandBarCompletionsMatches(QStringList() << "soggy1" 1749 << "soggy2"); 1750 TestPressKey("\\ctrl-c"); // Dismiss completer 1751 TestPressKey("\\ctrl-c"); // Dismiss bar 1752 FinishTest("soggy1 soggy2"); 1753 } 1754 1755 { 1756 // Don't show command completion before we start typing a command: we want ctrl-p/n 1757 // to go through command history instead (we'll test for that second part later). 1758 BeginTest("soggy1 soggy2"); 1759 TestPressKey(":"); 1760 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1761 TestPressKey("\\ctrl-cvl:"); 1762 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 1763 TestPressKey("\\ctrl-c"); // Dismiss bar 1764 FinishTest("soggy1 soggy2"); 1765 } 1766 1767 { 1768 // Aborting ":" should leave us in normal mode with no selection. 1769 BeginTest("foo bar"); 1770 TestPressKey("vw:\\ctrl-["); 1771 QVERIFY(kate_view->selectionText().isEmpty()); 1772 TestPressKey("wdiw"); 1773 BeginTest("foo "); 1774 } 1775 1776 // Command history tests. 1777 clearCommandHistory(); 1778 QVERIFY(commandHistory().isEmpty()); 1779 vi_global->commandHistory()->append("foo"); 1780 vi_global->commandHistory()->append("bar"); 1781 QCOMPARE(commandHistory(), 1782 QStringList() << "foo" 1783 << "bar"); 1784 clearCommandHistory(); 1785 QVERIFY(commandHistory().isEmpty()); 1786 1787 // If we add something to the history, remove any earliest occurrences (this is what Vim appears to do) 1788 // and append to the end. 1789 clearCommandHistory(); 1790 vi_global->commandHistory()->append("bar"); 1791 vi_global->commandHistory()->append("xyz"); 1792 vi_global->commandHistory()->append("foo"); 1793 vi_global->commandHistory()->append("xyz"); 1794 QCOMPARE(commandHistory(), 1795 QStringList() << "bar" 1796 << "foo" 1797 << "xyz"); 1798 1799 // Push out older entries if we have too many command items in the history. 1800 clearCommandHistory(); 1801 for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++) { 1802 vi_global->commandHistory()->append(QString("commandhistoryitem %1").arg(i)); 1803 } 1804 QCOMPARE(commandHistory().size(), HISTORY_SIZE_LIMIT); 1805 QCOMPARE(commandHistory().first(), QString("commandhistoryitem 1")); 1806 QCOMPARE(commandHistory().last(), QString("commandhistoryitem 100")); 1807 vi_global->commandHistory()->append(QString("commandhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1808 QCOMPARE(commandHistory().size(), HISTORY_SIZE_LIMIT); 1809 QCOMPARE(commandHistory().first(), QString("commandhistoryitem 2")); 1810 QCOMPARE(commandHistory().last(), QString("commandhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1811 1812 // Don't add empty commands to the history. 1813 clearCommandHistory(); 1814 DoTest("foo bar", ":\\enter", "foo bar"); 1815 QVERIFY(commandHistory().isEmpty()); 1816 1817 clearCommandHistory(); 1818 BeginTest(""); 1819 TestPressKey(":sort\\enter"); 1820 QCOMPARE(commandHistory(), QStringList() << "sort"); 1821 TestPressKey(":yank\\enter"); 1822 QCOMPARE(commandHistory(), 1823 QStringList() << "sort" 1824 << "yank"); 1825 // Add to history immediately: don't wait for the command response display to timeout. 1826 TestPressKey(":commandthatdoesnotexist\\enter"); 1827 QCOMPARE(commandHistory(), 1828 QStringList() << "sort" 1829 << "yank" 1830 << "commandthatdoesnotexist"); 1831 // Vim adds aborted commands to the history too, oddly. 1832 TestPressKey(":abortedcommand\\ctrl-c"); 1833 QCOMPARE(commandHistory(), 1834 QStringList() << "sort" 1835 << "yank" 1836 << "commandthatdoesnotexist" 1837 << "abortedcommand"); 1838 // Only add for commands, not searches! 1839 TestPressKey("/donotaddme\\enter?donotaddmeeither\\enter/donotaddme\\ctrl-c?donotaddmeeither\\ctrl-c"); 1840 QCOMPARE(commandHistory(), 1841 QStringList() << "sort" 1842 << "yank" 1843 << "commandthatdoesnotexist" 1844 << "abortedcommand"); 1845 FinishTest(""); 1846 1847 // Commands should not be added to the search history! 1848 clearCommandHistory(); 1849 clearSearchHistory(); 1850 BeginTest(""); 1851 TestPressKey(":sort\\enter"); 1852 QVERIFY(searchHistory().isEmpty()); 1853 FinishTest(""); 1854 1855 // With an empty command bar, ctrl-p / ctrl-n should go through history. 1856 clearCommandHistory(); 1857 vi_global->commandHistory()->append("command1"); 1858 vi_global->commandHistory()->append("command2"); 1859 BeginTest(""); 1860 TestPressKey(":\\ctrl-p"); 1861 verifyCommandBarCompletionVisible(); 1862 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("command2")); 1863 QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion()); 1864 TestPressKey("\\ctrl-c"); // Dismiss completer 1865 TestPressKey("\\ctrl-c"); // Dismiss bar 1866 FinishTest(""); 1867 clearCommandHistory(); 1868 vi_global->commandHistory()->append("command1"); 1869 vi_global->commandHistory()->append("command2"); 1870 BeginTest(""); 1871 TestPressKey(":\\ctrl-n"); 1872 verifyCommandBarCompletionVisible(); 1873 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("command1")); 1874 QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion()); 1875 TestPressKey("\\ctrl-c"); // Dismiss completer 1876 TestPressKey("\\ctrl-c"); // Dismiss bar 1877 FinishTest(""); 1878 1879 // If we're at a place where command completions are not allowed, ctrl-p/n should go through history. 1880 clearCommandHistory(); 1881 vi_global->commandHistory()->append("s/command1"); 1882 vi_global->commandHistory()->append("s/command2"); 1883 BeginTest(""); 1884 TestPressKey(":s/\\ctrl-p"); 1885 verifyCommandBarCompletionVisible(); 1886 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("s/command2")); 1887 QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion()); 1888 TestPressKey("\\ctrl-c"); // Dismiss completer 1889 TestPressKey("\\ctrl-c"); // Dismiss bar 1890 FinishTest(""); 1891 clearCommandHistory(); 1892 vi_global->commandHistory()->append("s/command1"); 1893 vi_global->commandHistory()->append("s/command2"); 1894 BeginTest(""); 1895 TestPressKey(":s/\\ctrl-n"); 1896 verifyCommandBarCompletionVisible(); 1897 QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("s/command1")); 1898 QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion()); 1899 TestPressKey("\\ctrl-c"); // Dismiss completer 1900 TestPressKey("\\ctrl-c"); // Dismiss bar 1901 FinishTest(""); 1902 1903 // Cancelling word-from-document completion should revert the whole text to what it was before. 1904 BeginTest("sausage bacon"); 1905 TestPressKey(":s/b\\ctrl- \\ctrl-p"); 1906 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/bacon")); 1907 verifyCommandBarCompletionVisible(); 1908 TestPressKey("\\ctrl-c"); // Dismiss completer 1909 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/b")); 1910 TestPressKey("\\ctrl-c"); // Dismiss bar 1911 FinishTest("sausage bacon"); 1912 1913 // "Replace" history tests. 1914 clearReplaceHistory(); 1915 QVERIFY(replaceHistory().isEmpty()); 1916 vi_global->replaceHistory()->append("foo"); 1917 vi_global->replaceHistory()->append("bar"); 1918 QCOMPARE(replaceHistory(), 1919 QStringList() << "foo" 1920 << "bar"); 1921 clearReplaceHistory(); 1922 QVERIFY(replaceHistory().isEmpty()); 1923 1924 // If we add something to the history, remove any earliest occurrences (this is what Vim appears to do) 1925 // and append to the end. 1926 clearReplaceHistory(); 1927 vi_global->replaceHistory()->append("bar"); 1928 vi_global->replaceHistory()->append("xyz"); 1929 vi_global->replaceHistory()->append("foo"); 1930 vi_global->replaceHistory()->append("xyz"); 1931 QCOMPARE(replaceHistory(), 1932 QStringList() << "bar" 1933 << "foo" 1934 << "xyz"); 1935 1936 // Push out older entries if we have too many replace items in the history. 1937 clearReplaceHistory(); 1938 for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++) { 1939 vi_global->replaceHistory()->append(QString("replacehistoryitem %1").arg(i)); 1940 } 1941 QCOMPARE(replaceHistory().size(), HISTORY_SIZE_LIMIT); 1942 QCOMPARE(replaceHistory().first(), QString("replacehistoryitem 1")); 1943 QCOMPARE(replaceHistory().last(), QString("replacehistoryitem 100")); 1944 vi_global->replaceHistory()->append(QString("replacehistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1945 QCOMPARE(replaceHistory().size(), HISTORY_SIZE_LIMIT); 1946 QCOMPARE(replaceHistory().first(), QString("replacehistoryitem 2")); 1947 QCOMPARE(replaceHistory().last(), QString("replacehistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1)); 1948 1949 // Don't add empty replaces to the history. 1950 clearReplaceHistory(); 1951 vi_global->replaceHistory()->append(""); 1952 QVERIFY(replaceHistory().isEmpty()); 1953 1954 // Some misc SedReplace tests. 1955 DoTest("x\\/y", ":s/\\\\//replace/g\\enter", "x\\replacey"); 1956 DoTest("x\\/y", ":s/\\\\\\\\\\\\//replace/g\\enter", "xreplacey"); 1957 DoTest("x\\/y", ":s:/:replace:g\\enter", "x\\replacey"); 1958 DoTest("foo\nbar\nxyz", ":%delete\\enter", ""); 1959 DoTest("foo\nbar\nxyz\nbaz", "jVj:delete\\enter", "foo\nbaz"); 1960 DoTest("foo\nbar\nxyz\nbaz", "j2:delete\\enter", "foo\nbaz"); 1961 1962 // Test that 0 is accepted as a line index (and treated as 1) in a range specifier 1963 DoTest("bar\nbar\nbar", ":0,$s/bar/foo/g\\enter", "foo\nfoo\nfoo"); 1964 DoTest("bar\nbar\nbar", ":1,$s/bar/foo/g\\enter", "foo\nfoo\nfoo"); 1965 DoTest("bar\nbar\nbar", ":0,2s/bar/foo/g\\enter", "foo\nfoo\nbar"); 1966 1967 // On ctrl-d, delete the "search" term in a s/search/replace/xx 1968 BeginTest("foo bar"); 1969 TestPressKey(":s/x\\\\\\\\\\\\/yz/rep\\\\\\\\\\\\/lace/g\\ctrl-d"); 1970 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//rep\\\\\\/lace/g")); 1971 TestPressKey("\\ctrl-c"); // Dismiss bar. 1972 FinishTest("foo bar"); 1973 // Move cursor to position of deleted search term. 1974 BeginTest("foo bar"); 1975 TestPressKey(":s/x\\\\\\\\\\\\/yz/rep\\\\\\\\\\\\/lace/g\\ctrl-dX"); 1976 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/X/rep\\\\\\/lace/g")); 1977 TestPressKey("\\ctrl-c"); // Dismiss bar. 1978 FinishTest("foo bar"); 1979 // Do nothing on ctrl-d in search mode. 1980 BeginTest("foo bar"); 1981 TestPressKey("/s/search/replace/g\\ctrl-d"); 1982 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g")); 1983 TestPressKey("\\ctrl-c?s/searchbackwards/replace/g\\ctrl-d"); 1984 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchbackwards/replace/g")); 1985 TestPressKey("\\ctrl-c"); // Dismiss bar. 1986 FinishTest("foo bar"); 1987 // On ctrl-f, delete "replace" term in a s/search/replace/xx 1988 BeginTest("foo bar"); 1989 TestPressKey(":s/a\\\\\\\\\\\\/bc/rep\\\\\\\\\\\\/lace/g\\ctrl-f"); 1990 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/a\\\\\\/bc//g")); 1991 TestPressKey("\\ctrl-c"); // Dismiss bar. 1992 FinishTest("foo bar"); 1993 // Move cursor to position of deleted replace term. 1994 BeginTest("foo bar"); 1995 TestPressKey(":s:a/bc:replace:g\\ctrl-fX"); 1996 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:a/bc:X:g")); 1997 TestPressKey("\\ctrl-c"); // Dismiss bar. 1998 FinishTest("foo bar"); 1999 // Do nothing on ctrl-d in search mode. 2000 BeginTest("foo bar"); 2001 TestPressKey("/s/search/replace/g\\ctrl-f"); 2002 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g")); 2003 TestPressKey("\\ctrl-c?s/searchbackwards/replace/g\\ctrl-f"); 2004 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchbackwards/replace/g")); 2005 TestPressKey("\\ctrl-c"); // Dismiss bar. 2006 FinishTest("foo bar"); 2007 // Do nothing on ctrl-d / ctrl-f if the current expression is not a sed expression. 2008 BeginTest("foo bar"); 2009 TestPressKey(":s/notasedreplaceexpression::gi\\ctrl-f\\ctrl-dX"); 2010 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/notasedreplaceexpression::giX")); 2011 TestPressKey("\\ctrl-c"); // Dismiss bar. 2012 FinishTest("foo bar"); 2013 // Need to convert Vim-style regex's to Qt one's in Sed Replace. 2014 DoTest("foo xbacba(boo)|[y", ":s/x[abc]\\\\+(boo)|[y/boo/g\\enter", "foo boo"); 2015 DoTest("foo xbacba(boo)|[y\nfoo xbacba(boo)|[y", "Vj:s/x[abc]\\\\+(boo)|[y/boo/g\\enter", "foo boo\nfoo boo"); 2016 // Just convert the search term, please :) 2017 DoTest("foo xbacba(boo)|[y", ":s/x[abc]\\\\+(boo)|[y/boo()/g\\enter", "foo boo()"); 2018 // With an empty search expression, ctrl-d should still position the cursor correctly. 2019 BeginTest("foo bar"); 2020 TestPressKey(":s//replace/g\\ctrl-dX"); 2021 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/X/replace/g")); 2022 TestPressKey("\\ctrl-c"); // Dismiss bar. 2023 TestPressKey(":s::replace:g\\ctrl-dX"); 2024 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:X:replace:g")); 2025 TestPressKey("\\ctrl-c"); // Dismiss bar. 2026 FinishTest("foo bar"); 2027 // With an empty replace expression, ctrl-f should still position the cursor correctly. 2028 BeginTest("foo bar"); 2029 TestPressKey(":s/sear\\\\/ch//g\\ctrl-fX"); 2030 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/sear\\/ch/X/g")); 2031 TestPressKey("\\ctrl-c"); // Dismiss bar. 2032 TestPressKey(":s:sear\\\\:ch::g\\ctrl-fX"); 2033 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:sear\\:ch:X:g")); 2034 TestPressKey("\\ctrl-c"); // Dismiss bar. 2035 FinishTest("foo bar"); 2036 // With both empty search *and* replace expressions, ctrl-f should still position the cursor correctly. 2037 BeginTest("foo bar"); 2038 TestPressKey(":s///g\\ctrl-fX"); 2039 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//X/g")); 2040 TestPressKey("\\ctrl-c"); // Dismiss bar. 2041 TestPressKey(":s:::g\\ctrl-fX"); 2042 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s::X:g")); 2043 TestPressKey("\\ctrl-c"); // Dismiss bar. 2044 FinishTest("foo bar"); 2045 // Should be able to undo ctrl-f or ctrl-d. 2046 BeginTest("foo bar"); 2047 TestPressKey(":s/find/replace/g\\ctrl-d"); 2048 emulatedCommandBarTextEdit()->undo(); 2049 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/find/replace/g")); 2050 TestPressKey("\\ctrl-f"); 2051 emulatedCommandBarTextEdit()->undo(); 2052 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/find/replace/g")); 2053 TestPressKey("\\ctrl-c"); // Dismiss bar. 2054 FinishTest("foo bar"); 2055 // ctrl-f / ctrl-d should cleanly finish sed find/ replace history completion. 2056 clearReplaceHistory(); 2057 clearSearchHistory(); 2058 vi_global->searchHistory()->append("searchxyz"); 2059 vi_global->replaceHistory()->append("replacexyz"); 2060 TestPressKey(":s///g\\ctrl-d\\ctrl-p"); 2061 QVERIFY(emulatedCommandBarCompleter()->popup()->isVisible()); 2062 TestPressKey("\\ctrl-f"); 2063 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchxyz//g")); 2064 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2065 TestPressKey("\\ctrl-p"); 2066 QVERIFY(emulatedCommandBarCompleter()->popup()->isVisible()); 2067 TestPressKey("\\ctrl-d"); 2068 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//replacexyz/g")); 2069 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2070 TestPressKey("\\ctrl-c"); // Dismiss bar. 2071 FinishTest("foo bar"); 2072 // Don't hang if we execute a sed replace with empty search term. 2073 DoTest("foo bar", ":s//replace/g\\enter", "foo bar"); 2074 2075 // ctrl-f & ctrl-d should work even when there is a range expression at the beginning of the sed replace. 2076 BeginTest("foo bar"); 2077 TestPressKey(":'<,'>s/search/replace/g\\ctrl-d"); 2078 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>s//replace/g")); 2079 TestPressKey("\\ctrl-c:.,.+6s/search/replace/g\\ctrl-f"); 2080 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6s/search//g")); 2081 TestPressKey("\\ctrl-c:%s/search/replace/g\\ctrl-f"); 2082 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("%s/search//g")); 2083 // Place the cursor in the right place even when there is a range expression. 2084 TestPressKey("\\ctrl-c:.,.+6s/search/replace/g\\ctrl-fX"); 2085 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6s/search/X/g")); 2086 TestPressKey("\\ctrl-c:%s/search/replace/g\\ctrl-fX"); 2087 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("%s/search/X/g")); 2088 TestPressKey("\\ctrl-c"); // Dismiss bar. 2089 FinishTest("foo bar"); 2090 // Don't crash on ctrl-f/d if we have an empty command. 2091 DoTest("", ":\\ctrl-f\\ctrl-d\\ctrl-c", ""); 2092 // Parser regression test: Don't crash on ctrl-f/d with ".,.+". 2093 DoTest("", ":.,.+\\ctrl-f\\ctrl-d\\ctrl-c", ""); 2094 2095 // Command-completion should be invoked on the command being typed even when preceded by a range expression. 2096 BeginTest(""); 2097 TestPressKey(":0,'>so"); 2098 verifyCommandBarCompletionVisible(); 2099 TestPressKey("\\ctrl-c"); // Dismiss completer 2100 TestPressKey("\\ctrl-c"); // Dismiss bar. 2101 FinishTest(""); 2102 2103 // Command-completion should ignore the range expression. 2104 BeginTest(""); 2105 TestPressKey(":.,.+6so"); 2106 verifyCommandBarCompletionVisible(); 2107 TestPressKey("\\ctrl-c"); // Dismiss completer 2108 TestPressKey("\\ctrl-c"); // Dismiss bar. 2109 FinishTest(""); 2110 2111 // A sed-replace should immediately add the search term to the search history. 2112 clearSearchHistory(); 2113 BeginTest(""); 2114 TestPressKey(":s/search/replace/g\\enter"); 2115 QCOMPARE(searchHistory(), QStringList() << "search"); 2116 FinishTest(""); 2117 2118 // An aborted sed-replace should not add the search term to the search history. 2119 clearSearchHistory(); 2120 BeginTest(""); 2121 TestPressKey(":s/search/replace/g\\ctrl-c"); 2122 QCOMPARE(searchHistory(), QStringList()); 2123 FinishTest(""); 2124 2125 // A non-sed-replace should leave the search history unchanged. 2126 clearSearchHistory(); 2127 BeginTest(""); 2128 TestPressKey(":s,search/replace/g\\enter"); 2129 QCOMPARE(searchHistory(), QStringList()); 2130 FinishTest(""); 2131 2132 // A sed-replace should immediately add the replace term to the replace history. 2133 clearReplaceHistory(); 2134 BeginTest(""); 2135 TestPressKey(":s/search/replace/g\\enter"); 2136 QCOMPARE(replaceHistory(), QStringList() << "replace"); 2137 clearReplaceHistory(); 2138 TestPressKey(":'<,'>s/search/replace1/g\\enter"); 2139 QCOMPARE(replaceHistory(), QStringList() << "replace1"); 2140 FinishTest(""); 2141 2142 // An aborted sed-replace should not add the replace term to the replace history. 2143 clearReplaceHistory(); 2144 BeginTest(""); 2145 TestPressKey(":s/search/replace/g\\ctrl-c"); 2146 QCOMPARE(replaceHistory(), QStringList()); 2147 FinishTest(""); 2148 2149 // A non-sed-replace should leave the replace history unchanged. 2150 clearReplaceHistory(); 2151 BeginTest(""); 2152 TestPressKey(":s,search/replace/g\\enter"); 2153 QCOMPARE(replaceHistory(), QStringList()); 2154 FinishTest(""); 2155 2156 // Misc tests for sed replace. These are for the *generic* Kate sed replace; they should all 2157 // use EmulatedCommandBarTests' built-in command execution stuff (\\:<commandtoexecute>\\\) rather than 2158 // invoking a EmulatedCommandBar and potentially doing some Vim-specific transforms to 2159 // the command. 2160 DoTest("foo foo foo", "\\:s/foo/bar/\\", "bar foo foo"); 2161 DoTest("foo foo xyz foo", "\\:s/foo/bar/g\\", "bar bar xyz bar"); 2162 DoTest("foofooxyzfoo", "\\:s/foo/bar/g\\", "barbarxyzbar"); 2163 DoTest("foofooxyzfoo", "\\:s/foo/b/g\\", "bbxyzb"); 2164 DoTest("ffxyzf", "\\:s/f/b/g\\", "bbxyzb"); 2165 DoTest("ffxyzf", "\\:s/f/bar/g\\", "barbarxyzbar"); 2166 DoTest("foo Foo fOO FOO foo", "\\:s/foo/bar/\\", "bar Foo fOO FOO foo"); 2167 DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/\\", "Foo bar fOO FOO foo"); 2168 DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/g\\", "Foo bar fOO FOO bar"); 2169 DoTest("foo Foo fOO FOO foo", "\\:s/foo/bar/i\\", "bar Foo fOO FOO foo"); 2170 DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/i\\", "bar foo fOO FOO foo"); 2171 DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/gi\\", "bar bar bar bar bar"); 2172 DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/ig\\", "bar bar bar bar bar"); 2173 // There are some oddities to do with how EmulatedCommandBarTest's "execute command directly" stuff works with selected ranges: 2174 // basically, we need to do our selection in Visual mode, then exit back to Normal mode before running the 2175 // command. 2176 DoTest("foo foo\nbar foo foo\nxyz foo foo\nfoo bar foo", "jVj\\esc\\:'<,'>s/foo/bar/\\", "foo foo\nbar bar foo\nxyz bar foo\nfoo bar foo"); 2177 DoTest("foo foo\nbar foo foo\nxyz foo foo\nfoo bar foo", "jVj\\esc\\:'<,'>s/foo/bar/g\\", "foo foo\nbar bar bar\nxyz bar bar\nfoo bar foo"); 2178 DoTest("Foo foo fOO FOO foo", "\\:s/foo/barfoo/g\\", "Foo barfoo fOO FOO barfoo"); 2179 DoTest("Foo foo fOO FOO foo", "\\:s/foo/foobar/g\\", "Foo foobar fOO FOO foobar"); 2180 DoTest("axyzb", "\\:s/a(.*)b/d\\\\1f/\\", "dxyzf"); 2181 DoTest("ayxzzyxzfddeefdb", "\\:s/a([xyz]+)([def]+)b/<\\\\1|\\\\2>/\\", "<yxzzyxz|fddeefd>"); 2182 DoTest("foo", "\\:s/.*//g\\", ""); 2183 DoTest("foo", "\\:s/.*/f/g\\", "f"); 2184 DoTest("foo/bar", "\\:s/foo\\\\/bar/123\\\\/xyz/g\\", "123/xyz"); 2185 DoTest("foo:bar", "\\:s:foo\\\\:bar:123\\\\:xyz:g\\", "123:xyz"); 2186 const bool oldReplaceTabsDyn = kate_document->config()->replaceTabsDyn(); 2187 kate_document->config()->setReplaceTabsDyn(false); 2188 DoTest("foo\tbar", "\\:s/foo\\\\tbar/replace/g\\", "replace"); 2189 DoTest("foo\tbar", "\\:s/foo\\\\tbar/rep\\\\tlace/g\\", "rep\tlace"); 2190 kate_document->config()->setReplaceTabsDyn(oldReplaceTabsDyn); 2191 DoTest("foo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2"); 2192 DoTest("foofoo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2replaceline1\nreplaceline2"); 2193 DoTest("foofoo\nfoo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2replaceline1\nreplaceline2\nfoo"); 2194 DoTest("fooafoob\nfooc\nfood", 2195 "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2/g\\", 2196 "replaceline1\nreplaceline2areplaceline1\nreplaceline2b\nreplaceline1\nreplaceline2c\nfood"); 2197 DoTest("fooafoob\nfooc\nfood", 2198 "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2/\\", 2199 "replaceline1\nreplaceline2afoob\nreplaceline1\nreplaceline2c\nfood"); 2200 DoTest("fooafoob\nfooc\nfood", 2201 "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2\\\\nreplaceline3/g\\", 2202 "replaceline1\nreplaceline2\nreplaceline3areplaceline1\nreplaceline2\nreplaceline3b\nreplaceline1\nreplaceline2\nreplaceline3c\nfood"); 2203 DoTest("foofoo", "\\:s/foo/replace\\\\nfoo/g\\", "replace\nfooreplace\nfoo"); 2204 DoTest("foofoo", "\\:s/foo/replacefoo\\\\nfoo/g\\", "replacefoo\nfooreplacefoo\nfoo"); 2205 DoTest("foofoo", "\\:s/foo/replacefoo\\\\n/g\\", "replacefoo\nreplacefoo\n"); 2206 DoTest("ff", "\\:s/f/f\\\\nf/g\\", "f\nff\nf"); 2207 DoTest("ff", "\\:s/f/f\\\\n/g\\", "f\nf\n"); 2208 DoTest("foo\nbar", "\\:s/foo\\\\n//g\\", "bar"); 2209 DoTest("foo\n\n\nbar", "\\:s/foo(\\\\n)*bar//g\\", ""); 2210 DoTest("foo\n\n\nbar", "\\:s/foo(\\\\n*)bar/123\\\\1456/g\\", "123\n\n\n456"); 2211 DoTest("xAbCy", "\\:s/x(.)(.)(.)y/\\\\L\\\\1\\\\U\\\\2\\\\3/g\\", "aBC"); 2212 DoTest("foo", "\\:s/foo/\\\\a/g\\", "\x07"); 2213 // End "generic" (i.e. not involving any Vi mode tricks/ transformations) sed replace tests: the remaining 2214 // ones should go via the EmulatedCommandBar. 2215 BeginTest("foo foo\nxyz\nfoo"); 2216 TestPressKey(":%s/foo/bar/g\\enter"); 2217 verifyShowsNumberOfReplacementsAcrossNumberOfLines(3, 2); 2218 FinishTest("bar bar\nxyz\nbar"); 2219 2220 // ctrl-p on the first character of the search term in a sed-replace should 2221 // invoke search history completion. 2222 clearSearchHistory(); 2223 vi_global->searchHistory()->append("search"); 2224 BeginTest(""); 2225 TestPressKey(":s/search/replace/g\\ctrl-b\\right\\right\\ctrl-p"); 2226 verifyCommandBarCompletionVisible(); 2227 TestPressKey("\\ctrl-c"); // Dismiss completer 2228 TestPressKey("\\ctrl-c"); // Dismiss bar. 2229 TestPressKey(":'<,'>s/search/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2230 verifyCommandBarCompletionVisible(); 2231 TestPressKey("\\ctrl-c"); // Dismiss completer 2232 TestPressKey("\\ctrl-c"); // Dismiss bar. 2233 FinishTest(""); 2234 2235 // ctrl-p on the last character of the search term in a sed-replace should 2236 // invoke search history completion. 2237 clearSearchHistory(); 2238 vi_global->searchHistory()->append("xyz"); 2239 BeginTest(""); 2240 TestPressKey(":s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\ctrl-p"); 2241 verifyCommandBarCompletionVisible(); 2242 TestPressKey("\\ctrl-c"); // Dismiss completer 2243 TestPressKey("\\ctrl-c"); // Dismiss bar. 2244 QVERIFY(!emulatedCommandBar->isVisible()); 2245 TestPressKey(":'<,'>s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2246 verifyCommandBarCompletionVisible(); 2247 TestPressKey("\\ctrl-c"); // Dismiss completer 2248 TestPressKey("\\ctrl-c"); // Dismiss bar. 2249 FinishTest(""); 2250 2251 // ctrl-p on some arbitrary character of the search term in a sed-replace should 2252 // invoke search history completion. 2253 clearSearchHistory(); 2254 vi_global->searchHistory()->append("xyzaaaaaa"); 2255 BeginTest(""); 2256 TestPressKey(":s/xyzaaaaaa/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2257 verifyCommandBarCompletionVisible(); 2258 TestPressKey("\\ctrl-c"); // Dismiss completer 2259 TestPressKey("\\ctrl-c"); // Dismiss bar. 2260 TestPressKey(":'<,'>s/xyzaaaaaa/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2261 verifyCommandBarCompletionVisible(); 2262 TestPressKey("\\ctrl-c"); // Dismiss completer 2263 TestPressKey("\\ctrl-c"); // Dismiss bar. 2264 FinishTest(""); 2265 2266 // ctrl-p on some character *after" the search term should 2267 // *not* invoke search history completion. 2268 // Note: in s/xyz/replace/g, the "/" after the "z" is counted as part of the find term; 2269 // this allows us to do xyz<ctrl-p> and get completions. 2270 clearSearchHistory(); 2271 clearCommandHistory(); 2272 clearReplaceHistory(); 2273 vi_global->searchHistory()->append("xyz"); 2274 BeginTest(""); 2275 TestPressKey(":s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2276 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2277 TestPressKey("\\ctrl-c"); // Dismiss completer 2278 TestPressKey("\\ctrl-c"); // Dismiss bar. 2279 clearSearchHistory(); 2280 clearCommandHistory(); 2281 TestPressKey(":'<,'>s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2282 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2283 TestPressKey("\\ctrl-c"); // Dismiss completer 2284 TestPressKey("\\ctrl-c"); // Dismiss bar. 2285 2286 // Make sure it's the search history we're invoking. 2287 clearSearchHistory(); 2288 vi_global->searchHistory()->append("xyzaaaaaa"); 2289 BeginTest(""); 2290 TestPressKey(":s//replace/g\\ctrl-b\\right\\right\\ctrl-p"); 2291 verifyCommandBarCompletionVisible(); 2292 verifyCommandBarCompletionsMatches(QStringList() << "xyzaaaaaa"); 2293 TestPressKey("\\ctrl-c"); // Dismiss completer 2294 TestPressKey("\\ctrl-c"); // Dismiss bar. 2295 TestPressKey(":.,.+6s//replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\ctrl-p"); 2296 verifyCommandBarCompletionsMatches(QStringList() << "xyzaaaaaa"); 2297 TestPressKey("\\ctrl-c"); // Dismiss completer 2298 TestPressKey("\\ctrl-c"); // Dismiss bar. 2299 FinishTest(""); 2300 2301 // (Search history should be reversed). 2302 clearSearchHistory(); 2303 vi_global->searchHistory()->append("xyzaaaaaa"); 2304 vi_global->searchHistory()->append("abc"); 2305 vi_global->searchHistory()->append("def"); 2306 BeginTest(""); 2307 TestPressKey(":s//replace/g\\ctrl-b\\right\\right\\ctrl-p"); 2308 verifyCommandBarCompletionVisible(); 2309 verifyCommandBarCompletionsMatches(QStringList() << "def" 2310 << "abc" 2311 << "xyzaaaaaa"); 2312 TestPressKey("\\ctrl-c"); // Dismiss completer 2313 TestPressKey("\\ctrl-c"); // Dismiss bar. 2314 FinishTest(""); 2315 2316 // Completion prefix is the current find term. 2317 clearSearchHistory(); 2318 vi_global->searchHistory()->append("xy:zaaaaaa"); 2319 vi_global->searchHistory()->append("abc"); 2320 vi_global->searchHistory()->append("def"); 2321 vi_global->searchHistory()->append("xy:zbaaaaa"); 2322 vi_global->searchHistory()->append("xy:zcaaaaa"); 2323 BeginTest(""); 2324 TestPressKey(":s//replace/g\\ctrl-dxy:z\\ctrl-p"); 2325 verifyCommandBarCompletionVisible(); 2326 verifyCommandBarCompletionsMatches(QStringList() << "xy:zcaaaaa" 2327 << "xy:zbaaaaa" 2328 << "xy:zaaaaaa"); 2329 TestPressKey("\\ctrl-c"); // Dismiss completer 2330 TestPressKey("\\ctrl-c"); // Dismiss bar. 2331 FinishTest(""); 2332 2333 // Replace entire search term with completion. 2334 clearSearchHistory(); 2335 vi_global->searchHistory()->append("ab,cd"); 2336 vi_global->searchHistory()->append("ab,xy"); 2337 BeginTest(""); 2338 TestPressKey(":s//replace/g\\ctrl-dab,\\ctrl-p\\ctrl-p"); 2339 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/ab,cd/replace/g")); 2340 TestPressKey("\\ctrl-c"); // Dismiss completer 2341 TestPressKey("\\ctrl-c"); // Dismiss bar. 2342 TestPressKey(":'<,'>s//replace/g\\ctrl-dab,\\ctrl-p\\ctrl-p"); 2343 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>s/ab,cd/replace/g")); 2344 TestPressKey("\\ctrl-c"); // Dismiss completer 2345 TestPressKey("\\ctrl-c"); // Dismiss bar. 2346 FinishTest(""); 2347 2348 // Place the cursor at the end of find term. 2349 clearSearchHistory(); 2350 vi_global->searchHistory()->append("ab,xy"); 2351 BeginTest(""); 2352 TestPressKey(":s//replace/g\\ctrl-dab,\\ctrl-pX"); 2353 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/ab,xyX/replace/g")); 2354 TestPressKey("\\ctrl-c"); // Dismiss completer 2355 TestPressKey("\\ctrl-c"); // Dismiss bar. 2356 TestPressKey(":.,.+7s//replace/g\\ctrl-dab,\\ctrl-pX"); 2357 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+7s/ab,xyX/replace/g")); 2358 TestPressKey("\\ctrl-c"); // Dismiss completer 2359 TestPressKey("\\ctrl-c"); // Dismiss bar. 2360 FinishTest(""); 2361 2362 // Leave find term unchanged if there is no search history. 2363 clearSearchHistory(); 2364 BeginTest(""); 2365 TestPressKey(":s/nose/replace/g\\ctrl-b\\right\\right\\right\\ctrl-p"); 2366 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/nose/replace/g")); 2367 TestPressKey("\\ctrl-c"); // Dismiss completer 2368 TestPressKey("\\ctrl-c"); // Dismiss bar. 2369 FinishTest(""); 2370 2371 // Leave cursor position unchanged if there is no search history. 2372 clearSearchHistory(); 2373 BeginTest(""); 2374 TestPressKey(":s/nose/replace/g\\ctrl-b\\right\\right\\right\\ctrl-pX"); 2375 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/nXose/replace/g")); 2376 TestPressKey("\\ctrl-c"); // Dismiss completer 2377 TestPressKey("\\ctrl-c"); // Dismiss bar. 2378 FinishTest(""); 2379 2380 // ctrl-p on the first character of the replace term in a sed-replace should 2381 // invoke replace history completion. 2382 clearSearchHistory(); 2383 clearReplaceHistory(); 2384 clearCommandHistory(); 2385 vi_global->replaceHistory()->append("replace"); 2386 BeginTest(""); 2387 TestPressKey(":s/search/replace/g\\left\\left\\left\\left\\left\\left\\left\\left\\left\\ctrl-p"); 2388 verifyCommandBarCompletionVisible(); 2389 TestPressKey("\\ctrl-c"); // Dismiss completer 2390 TestPressKey("\\ctrl-c"); // Dismiss bar. 2391 TestPressKey(":'<,'>s/search/replace/g\\left\\left\\left\\left\\left\\left\\left\\left\\left\\ctrl-p"); 2392 verifyCommandBarCompletionVisible(); 2393 TestPressKey("\\ctrl-c"); // Dismiss completer 2394 TestPressKey("\\ctrl-c"); // Dismiss bar. 2395 FinishTest(""); 2396 2397 // ctrl-p on the last character of the replace term in a sed-replace should 2398 // invoke replace history completion. 2399 clearReplaceHistory(); 2400 vi_global->replaceHistory()->append("replace"); 2401 BeginTest(""); 2402 TestPressKey(":s/xyz/replace/g\\left\\left\\ctrl-p"); 2403 verifyCommandBarCompletionVisible(); 2404 TestPressKey("\\ctrl-c"); // Dismiss completer 2405 TestPressKey("\\ctrl-c"); // Dismiss bar. 2406 TestPressKey(":'<,'>s/xyz/replace/g\\left\\left\\ctrl-p"); 2407 verifyCommandBarCompletionVisible(); 2408 TestPressKey("\\ctrl-c"); // Dismiss completer 2409 TestPressKey("\\ctrl-c"); // Dismiss bar. 2410 FinishTest(""); 2411 2412 // ctrl-p on some arbitrary character of the search term in a sed-replace should 2413 // invoke search history completion. 2414 clearReplaceHistory(); 2415 vi_global->replaceHistory()->append("replaceaaaaaa"); 2416 BeginTest(""); 2417 TestPressKey(":s/xyzaaaaaa/replace/g\\left\\left\\left\\left\\ctrl-p"); 2418 verifyCommandBarCompletionVisible(); 2419 TestPressKey("\\ctrl-c"); // Dismiss completer 2420 TestPressKey("\\ctrl-c"); // Dismiss bar. 2421 TestPressKey(":'<,'>s/xyzaaaaaa/replace/g\\left\\left\\left\\left\\ctrl-p"); 2422 verifyCommandBarCompletionVisible(); 2423 TestPressKey("\\ctrl-c"); // Dismiss completer 2424 TestPressKey("\\ctrl-c"); // Dismiss bar. 2425 FinishTest(""); 2426 2427 // ctrl-p on some character *after" the replace term should 2428 // *not* invoke replace history completion. 2429 // Note: in s/xyz/replace/g, the "/" after the "e" is counted as part of the replace term; 2430 // this allows us to do replace<ctrl-p> and get completions. 2431 clearSearchHistory(); 2432 clearCommandHistory(); 2433 clearReplaceHistory(); 2434 vi_global->replaceHistory()->append("xyz"); 2435 BeginTest(""); 2436 TestPressKey(":s/xyz/replace/g\\left\\ctrl-p"); 2437 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2438 TestPressKey("\\ctrl-c"); // Dismiss completer 2439 TestPressKey("\\ctrl-c"); // Dismiss bar. 2440 clearSearchHistory(); 2441 clearCommandHistory(); 2442 TestPressKey(":'<,'>s/xyz/replace/g\\left\\ctrl-p"); 2443 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 2444 TestPressKey("\\ctrl-c"); // Dismiss completer 2445 TestPressKey("\\ctrl-c"); // Dismiss bar. 2446 2447 // (Replace history should be reversed). 2448 clearReplaceHistory(); 2449 vi_global->replaceHistory()->append("xyzaaaaaa"); 2450 vi_global->replaceHistory()->append("abc"); 2451 vi_global->replaceHistory()->append("def"); 2452 BeginTest(""); 2453 TestPressKey(":s/search//g\\left\\left\\ctrl-p"); 2454 verifyCommandBarCompletionVisible(); 2455 verifyCommandBarCompletionsMatches(QStringList() << "def" 2456 << "abc" 2457 << "xyzaaaaaa"); 2458 TestPressKey("\\ctrl-c"); // Dismiss completer 2459 TestPressKey("\\ctrl-c"); // Dismiss bar. 2460 FinishTest(""); 2461 2462 // Completion prefix is the current replace term. 2463 clearReplaceHistory(); 2464 vi_global->replaceHistory()->append("xy:zaaaaaa"); 2465 vi_global->replaceHistory()->append("abc"); 2466 vi_global->replaceHistory()->append("def"); 2467 vi_global->replaceHistory()->append("xy:zbaaaaa"); 2468 vi_global->replaceHistory()->append("xy:zcaaaaa"); 2469 BeginTest(""); 2470 TestPressKey(":'<,'>s/replace/search/g\\ctrl-fxy:z\\ctrl-p"); 2471 verifyCommandBarCompletionVisible(); 2472 verifyCommandBarCompletionsMatches(QStringList() << "xy:zcaaaaa" 2473 << "xy:zbaaaaa" 2474 << "xy:zaaaaaa"); 2475 TestPressKey("\\ctrl-c"); // Dismiss completer 2476 TestPressKey("\\ctrl-c"); // Dismiss bar. 2477 FinishTest(""); 2478 2479 // Replace entire search term with completion. 2480 clearReplaceHistory(); 2481 clearSearchHistory(); 2482 vi_global->replaceHistory()->append("ab,cd"); 2483 vi_global->replaceHistory()->append("ab,xy"); 2484 BeginTest(""); 2485 TestPressKey(":s/search//g\\ctrl-fab,\\ctrl-p\\ctrl-p"); 2486 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/ab,cd/g")); 2487 TestPressKey("\\ctrl-c"); // Dismiss completer 2488 TestPressKey("\\ctrl-c"); // Dismiss bar. 2489 TestPressKey(":'<,'>s/search//g\\ctrl-fab,\\ctrl-p\\ctrl-p"); 2490 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>s/search/ab,cd/g")); 2491 TestPressKey("\\ctrl-c"); // Dismiss completer 2492 TestPressKey("\\ctrl-c"); // Dismiss bar. 2493 FinishTest(""); 2494 2495 // Place the cursor at the end of replace term. 2496 clearReplaceHistory(); 2497 vi_global->replaceHistory()->append("ab,xy"); 2498 BeginTest(""); 2499 TestPressKey(":s/search//g\\ctrl-fab,\\ctrl-pX"); 2500 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/ab,xyX/g")); 2501 TestPressKey("\\ctrl-c"); // Dismiss completer 2502 TestPressKey("\\ctrl-c"); // Dismiss bar. 2503 TestPressKey(":.,.+7s/search//g\\ctrl-fab,\\ctrl-pX"); 2504 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+7s/search/ab,xyX/g")); 2505 TestPressKey("\\ctrl-c"); // Dismiss completer 2506 TestPressKey("\\ctrl-c"); // Dismiss bar. 2507 FinishTest(""); 2508 2509 // Leave replace term unchanged if there is no replace history. 2510 clearReplaceHistory(); 2511 BeginTest(""); 2512 TestPressKey(":s/nose/replace/g\\left\\left\\left\\ctrl-p"); 2513 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/nose/replace/g")); 2514 TestPressKey("\\ctrl-c"); // Dismiss completer 2515 TestPressKey("\\ctrl-c"); // Dismiss bar. 2516 FinishTest(""); 2517 2518 // Leave cursor position unchanged if there is no replace history. 2519 clearSearchHistory(); 2520 BeginTest(""); 2521 TestPressKey(":s/nose/replace/g\\left\\left\\left\\left\\ctrl-pX"); 2522 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/nose/replaXce/g")); 2523 TestPressKey("\\ctrl-c"); // Dismiss completer 2524 TestPressKey("\\ctrl-c"); // Dismiss bar. 2525 FinishTest(""); 2526 2527 // Invoke replacement history even when the "find" term is empty. 2528 BeginTest(""); 2529 clearReplaceHistory(); 2530 clearSearchHistory(); 2531 vi_global->replaceHistory()->append("ab,xy"); 2532 vi_global->searchHistory()->append("whoops"); 2533 TestPressKey(":s///g\\ctrl-f\\ctrl-p"); 2534 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//ab,xy/g")); 2535 TestPressKey("\\ctrl-c"); // Dismiss completer 2536 TestPressKey("\\ctrl-c"); // Dismiss bar. 2537 FinishTest(""); 2538 2539 // Move the cursor back to the last manual edit point when aborting completion. 2540 BeginTest(""); 2541 clearSearchHistory(); 2542 vi_global->searchHistory()->append("xyzaaaaa"); 2543 TestPressKey(":s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\righta\\ctrl-p\\ctrl-[X"); 2544 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/xyzaX/replace/g")); 2545 TestPressKey("\\ctrl-c"); // Dismiss completer 2546 TestPressKey("\\ctrl-c"); // Dismiss bar. 2547 FinishTest(""); 2548 2549 // Don't blank the "find" term if there is no search history that begins with the 2550 // current "find" term. 2551 BeginTest(""); 2552 clearSearchHistory(); 2553 vi_global->searchHistory()->append("doesnothavexyzasaprefix"); 2554 TestPressKey(":s//replace/g\\ctrl-dxyz\\ctrl-p"); 2555 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/xyz/replace/g")); 2556 TestPressKey("\\ctrl-c"); // Dismiss completer 2557 TestPressKey("\\ctrl-c"); // Dismiss bar. 2558 FinishTest(""); 2559 2560 // Escape the delimiter if it occurs in a search history term - searching for it likely won't 2561 // work, but at least it won't crash! 2562 BeginTest(""); 2563 clearSearchHistory(); 2564 vi_global->searchHistory()->append("search"); 2565 vi_global->searchHistory()->append("aa/aa\\/a"); 2566 vi_global->searchHistory()->append("ss/ss"); 2567 TestPressKey(":s//replace/g\\ctrl-d\\ctrl-p"); 2568 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/ss\\/ss/replace/g")); 2569 TestPressKey("\\ctrl-p"); 2570 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/aa\\/aa\\/a/replace/g")); 2571 TestPressKey("\\ctrl-p"); 2572 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g")); 2573 TestPressKey("\\ctrl-c"); // Dismiss completer 2574 TestPressKey("\\ctrl-c"); // Dismiss bar. 2575 clearSearchHistory(); // Now do the same, but with a different delimiter. 2576 vi_global->searchHistory()->append("search"); 2577 vi_global->searchHistory()->append("aa:aa\\:a"); 2578 vi_global->searchHistory()->append("ss:ss"); 2579 TestPressKey(":s::replace:g\\ctrl-d\\ctrl-p"); 2580 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:ss\\:ss:replace:g")); 2581 TestPressKey("\\ctrl-p"); 2582 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:aa\\:aa\\:a:replace:g")); 2583 TestPressKey("\\ctrl-p"); 2584 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:search:replace:g")); 2585 TestPressKey("\\ctrl-c"); // Dismiss completer 2586 TestPressKey("\\ctrl-c"); // Dismiss bar. 2587 FinishTest(""); 2588 2589 // Remove \C if occurs in search history. 2590 BeginTest(""); 2591 clearSearchHistory(); 2592 vi_global->searchHistory()->append("s\\Cear\\\\Cch"); 2593 TestPressKey(":s::replace:g\\ctrl-d\\ctrl-p"); 2594 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:sear\\\\Cch:replace:g")); 2595 TestPressKey("\\ctrl-c"); // Dismiss completer 2596 TestPressKey("\\ctrl-c"); // Dismiss bar. 2597 FinishTest(""); 2598 2599 // Don't blank the "replace" term if there is no search history that begins with the 2600 // current "replace" term. 2601 BeginTest(""); 2602 clearReplaceHistory(); 2603 vi_global->replaceHistory()->append("doesnothavexyzasaprefix"); 2604 TestPressKey(":s/search//g\\ctrl-fxyz\\ctrl-p"); 2605 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/xyz/g")); 2606 TestPressKey("\\ctrl-c"); // Dismiss completer 2607 TestPressKey("\\ctrl-c"); // Dismiss bar. 2608 FinishTest(""); 2609 2610 // Escape the delimiter if it occurs in a replace history term - searching for it likely won't 2611 // work, but at least it won't crash! 2612 BeginTest(""); 2613 clearReplaceHistory(); 2614 vi_global->replaceHistory()->append("replace"); 2615 vi_global->replaceHistory()->append("aa/aa\\/a"); 2616 vi_global->replaceHistory()->append("ss/ss"); 2617 TestPressKey(":s/search//g\\ctrl-f\\ctrl-p"); 2618 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/ss\\/ss/g")); 2619 TestPressKey("\\ctrl-p"); 2620 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/aa\\/aa\\/a/g")); 2621 TestPressKey("\\ctrl-p"); 2622 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g")); 2623 TestPressKey("\\ctrl-c"); // Dismiss completer 2624 TestPressKey("\\ctrl-c"); // Dismiss bar. 2625 clearReplaceHistory(); // Now do the same, but with a different delimiter. 2626 vi_global->replaceHistory()->append("replace"); 2627 vi_global->replaceHistory()->append("aa:aa\\:a"); 2628 vi_global->replaceHistory()->append("ss:ss"); 2629 TestPressKey(":s:search::g\\ctrl-f\\ctrl-p"); 2630 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:search:ss\\:ss:g")); 2631 TestPressKey("\\ctrl-p"); 2632 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:search:aa\\:aa\\:a:g")); 2633 TestPressKey("\\ctrl-p"); 2634 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:search:replace:g")); 2635 TestPressKey("\\ctrl-c"); // Dismiss completer 2636 TestPressKey("\\ctrl-c"); // Dismiss bar. 2637 FinishTest(""); 2638 2639 // In search mode, don't blank current text on completion if there is no item in the search history which 2640 // has the current text as a prefix. 2641 BeginTest(""); 2642 clearSearchHistory(); 2643 vi_global->searchHistory()->append("doesnothavexyzasaprefix"); 2644 TestPressKey("/xyz\\ctrl-p"); 2645 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz")); 2646 TestPressKey("\\ctrl-c"); // Dismiss completer 2647 TestPressKey("\\ctrl-c"); // Dismiss bar. 2648 FinishTest(""); 2649 2650 // Don't dismiss the command completion just because the cursor ends up *temporarily* at a place where 2651 // command completion is disallowed when cycling through completions. 2652 BeginTest(""); 2653 TestPressKey(":set/se\\left\\left\\left-\\ctrl-p"); 2654 verifyCommandBarCompletionVisible(); 2655 TestPressKey("\\ctrl-c"); // Dismiss completer 2656 TestPressKey("\\ctrl-c"); // Dismiss bar. 2657 FinishTest(""); 2658 2659 // Don't expand mappings meant for Normal mode in the emulated command bar. 2660 clearAllMappings(); 2661 vi_global->mappings()->add(Mappings::NormalModeMapping, "foo", "xyz", Mappings::NonRecursive); 2662 DoTest("bar foo xyz", "/foo\\enterrX", "bar Xoo xyz"); 2663 clearAllMappings(); 2664 2665 // Incremental search and replace. 2666 QLabel *interactiveSedReplaceLabel = emulatedCommandBar->findChild<QLabel *>("interactivesedreplace"); 2667 QVERIFY(interactiveSedReplaceLabel); 2668 2669 BeginTest("foo"); 2670 TestPressKey(":s/foo/bar/c\\enter"); 2671 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2672 QVERIFY(!commandResponseMessageDisplay()->isVisible()); 2673 QVERIFY(!emulatedCommandBarTextEdit()->isVisible()); 2674 QVERIFY(!emulatedCommandTypeIndicator()->isVisible()); 2675 TestPressKey("\\ctrl-c"); // Dismiss search and replace. 2676 QVERIFY(!emulatedCommandBar->isVisible()); 2677 FinishTest("foo"); 2678 2679 // Clear the flag that stops the command response from being shown after an incremental search and 2680 // replace, and also make sure that the edit and bar type indicator are not forcibly hidden. 2681 BeginTest("foo"); 2682 TestPressKey(":s/foo/bar/c\\enter\\ctrl-c"); 2683 TestPressKey(":s/foo/bar/"); 2684 QVERIFY(emulatedCommandBarTextEdit()->isVisible()); 2685 QVERIFY(emulatedCommandTypeIndicator()->isVisible()); 2686 TestPressKey("\\enter"); 2687 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2688 FinishTest("bar"); 2689 2690 // Hide the incremental search and replace label when we show the bar. 2691 BeginTest("foo"); 2692 TestPressKey(":s/foo/bar/c\\enter\\ctrl-c"); 2693 TestPressKey(":"); 2694 QVERIFY(!interactiveSedReplaceLabel->isVisible()); 2695 TestPressKey("\\ctrl-c"); 2696 FinishTest("foo"); 2697 2698 // The "c" marker can be anywhere in the three chars following the delimiter. 2699 BeginTest("foo"); 2700 TestPressKey(":s/foo/bar/cgi\\enter"); 2701 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2702 TestPressKey("\\ctrl-c"); 2703 FinishTest("foo"); 2704 BeginTest("foo"); 2705 TestPressKey(":s/foo/bar/igc\\enter"); 2706 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2707 TestPressKey("\\ctrl-c"); 2708 FinishTest("foo"); 2709 BeginTest("foo"); 2710 TestPressKey(":s/foo/bar/icg\\enter"); 2711 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2712 TestPressKey("\\ctrl-c"); 2713 FinishTest("foo"); 2714 BeginTest("foo"); 2715 TestPressKey(":s/foo/bar/ic\\enter"); 2716 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2717 TestPressKey("\\ctrl-c"); 2718 FinishTest("foo"); 2719 BeginTest("foo"); 2720 TestPressKey(":s/foo/bar/ci\\enter"); 2721 QVERIFY(interactiveSedReplaceLabel->isVisible()); 2722 TestPressKey("\\ctrl-c"); 2723 FinishTest("foo"); 2724 2725 // Emulated command bar is still active during an incremental search and replace. 2726 BeginTest("foo"); 2727 TestPressKey(":s/foo/bar/c\\enter"); 2728 TestPressKey("idef\\esc"); 2729 FinishTest("foo"); 2730 2731 // Emulated command bar text is not edited during an incremental search and replace. 2732 BeginTest("foo"); 2733 TestPressKey(":s/foo/bar/c\\enter"); 2734 TestPressKey("def"); 2735 QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/foo/bar/c")); 2736 TestPressKey("\\ctrl-c"); 2737 FinishTest("foo"); 2738 2739 // Pressing "n" when there is only a single change we can make aborts incremental search 2740 // and replace. 2741 BeginTest("foo"); 2742 TestPressKey(":s/foo/bar/c\\enter"); 2743 TestPressKey("n"); 2744 QVERIFY(!interactiveSedReplaceLabel->isVisible()); 2745 TestPressKey("ixyz\\esc"); 2746 FinishTest("xyzfoo"); 2747 2748 // Pressing "n" when there is only a single change we can make aborts incremental search 2749 // and replace, and shows the no replacements on no lines. 2750 BeginTest("foo"); 2751 TestPressKey(":s/foo/bar/c\\enter"); 2752 TestPressKey("n"); 2753 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2754 verifyShowsNumberOfReplacementsAcrossNumberOfLines(0, 0); 2755 FinishTest("foo"); 2756 2757 // First possible match is highlighted when we start an incremental search and replace, and 2758 // cleared if we press 'n'. 2759 BeginTest(" xyz 123 foo bar"); 2760 TestPressKey(":s/foo/bar/gc\\enter"); 2761 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 2762 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 2763 QCOMPARE(rangesOnFirstLine().first()->start().column(), 10); 2764 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 2765 QCOMPARE(rangesOnFirstLine().first()->end().column(), 13); 2766 TestPressKey("n"); 2767 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 2768 FinishTest(" xyz 123 foo bar"); 2769 2770 // Second possible match highlighted if we start incremental search and replace and press 'n', 2771 // cleared if we press 'n' again. 2772 BeginTest(" xyz 123 foo foo bar"); 2773 TestPressKey(":s/foo/bar/gc\\enter"); 2774 TestPressKey("n"); 2775 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 2776 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 2777 QCOMPARE(rangesOnFirstLine().first()->start().column(), 14); 2778 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 2779 QCOMPARE(rangesOnFirstLine().first()->end().column(), 17); 2780 TestPressKey("n"); 2781 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size()); 2782 FinishTest(" xyz 123 foo foo bar"); 2783 2784 // Perform replacement if we press 'y' on the first match. 2785 BeginTest(" xyz foo 123 foo bar"); 2786 TestPressKey(":s/foo/bar/gc\\enter"); 2787 TestPressKey("y"); 2788 TestPressKey("\\ctrl-c"); 2789 FinishTest(" xyz bar 123 foo bar"); 2790 2791 // Replacement uses grouping, etc. 2792 BeginTest(" xyz def 123 foo bar"); 2793 TestPressKey(":s/d\\\\(e\\\\)\\\\(f\\\\)/x\\\\1\\\\U\\\\2/gc\\enter"); 2794 TestPressKey("y"); 2795 TestPressKey("\\ctrl-c"); 2796 FinishTest(" xyz xeF 123 foo bar"); 2797 2798 // On replacement, highlight next match. 2799 BeginTest(" xyz foo 123 foo bar"); 2800 TestPressKey(":s/foo/bar/cg\\enter"); 2801 TestPressKey("y"); 2802 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 2803 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 2804 QCOMPARE(rangesOnFirstLine().first()->start().column(), 14); 2805 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 2806 QCOMPARE(rangesOnFirstLine().first()->end().column(), 17); 2807 TestPressKey("\\ctrl-c"); 2808 FinishTest(" xyz bar 123 foo bar"); 2809 2810 // On replacement, if there is no further match, abort incremental search and replace. 2811 BeginTest(" xyz foo 123 foa bar"); 2812 TestPressKey(":s/foo/bar/cg\\enter"); 2813 TestPressKey("y"); 2814 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2815 TestPressKey("ggidone\\esc"); 2816 FinishTest("done xyz bar 123 foa bar"); 2817 2818 // After replacement, the next match is sought after the end of the replacement text. 2819 BeginTest("foofoo"); 2820 TestPressKey(":s/foo/barfoo/cg\\enter"); 2821 TestPressKey("y"); 2822 QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1); 2823 QCOMPARE(rangesOnFirstLine().first()->start().line(), 0); 2824 QCOMPARE(rangesOnFirstLine().first()->start().column(), 6); 2825 QCOMPARE(rangesOnFirstLine().first()->end().line(), 0); 2826 QCOMPARE(rangesOnFirstLine().first()->end().column(), 9); 2827 TestPressKey("\\ctrl-c"); 2828 FinishTest("barfoofoo"); 2829 BeginTest("xffy"); 2830 TestPressKey(":s/f/bf/cg\\enter"); 2831 TestPressKey("yy"); 2832 FinishTest("xbfbfy"); 2833 2834 // Make sure the incremental search bar label contains the "instruction" keypresses. 2835 const QString interactiveSedReplaceShortcuts = "(y/n/a/q/l)"; 2836 BeginTest("foofoo"); 2837 TestPressKey(":s/foo/barfoo/cg\\enter"); 2838 QVERIFY(interactiveSedReplaceLabel->text().contains(interactiveSedReplaceShortcuts)); 2839 TestPressKey("\\ctrl-c"); 2840 FinishTest("foofoo"); 2841 2842 // Make sure the incremental search bar label contains a reference to the text we're going to 2843 // replace with. 2844 // We're going to be a bit vague about the precise text due to localization issues. 2845 BeginTest("fabababbbar"); 2846 TestPressKey(":s/f\\\\([ab]\\\\+\\\\)/1\\\\U\\\\12/c\\enter"); 2847 QVERIFY(interactiveSedReplaceLabel->text().contains("1ABABABBBA2")); 2848 TestPressKey("\\ctrl-c"); 2849 FinishTest("fabababbbar"); 2850 2851 // Replace newlines in the "replace?" message with "\\n" 2852 BeginTest("foo"); 2853 TestPressKey(":s/foo/bar\\\\nxyz\\\\n123/c\\enter"); 2854 QVERIFY(interactiveSedReplaceLabel->text().contains("bar\\nxyz\\n123")); 2855 TestPressKey("\\ctrl-c"); 2856 FinishTest("foo"); 2857 2858 // Update the "confirm replace?" message on pressing "y". 2859 BeginTest("fabababbbar fabbb"); 2860 TestPressKey(":s/f\\\\([ab]\\\\+\\\\)/1\\\\U\\\\12/gc\\enter"); 2861 TestPressKey("y"); 2862 QVERIFY(interactiveSedReplaceLabel->text().contains("1ABBB2")); 2863 QVERIFY(interactiveSedReplaceLabel->text().contains(interactiveSedReplaceShortcuts)); 2864 TestPressKey("\\ctrl-c"); 2865 FinishTest("1ABABABBBA2r fabbb"); 2866 2867 // Update the "confirm replace?" message on pressing "n". 2868 BeginTest("fabababbbar fabab"); 2869 TestPressKey(":s/f\\\\([ab]\\\\+\\\\)/1\\\\U\\\\12/gc\\enter"); 2870 TestPressKey("n"); 2871 QVERIFY(interactiveSedReplaceLabel->text().contains("1ABAB2")); 2872 QVERIFY(interactiveSedReplaceLabel->text().contains(interactiveSedReplaceShortcuts)); 2873 TestPressKey("\\ctrl-c"); 2874 FinishTest("fabababbbar fabab"); 2875 2876 // Cursor is placed at the beginning of first match. 2877 BeginTest(" foo foo foo"); 2878 TestPressKey(":s/foo/bar/c\\enter"); 2879 verifyCursorAt(Cursor(0, 2)); 2880 TestPressKey("\\ctrl-c"); 2881 FinishTest(" foo foo foo"); 2882 2883 // "y" and "n" update the cursor pos. 2884 BeginTest(" foo foo foo"); 2885 TestPressKey(":s/foo/bar/cg\\enter"); 2886 TestPressKey("y"); 2887 verifyCursorAt(Cursor(0, 8)); 2888 TestPressKey("n"); 2889 verifyCursorAt(Cursor(0, 12)); 2890 TestPressKey("\\ctrl-c"); 2891 FinishTest(" bar foo foo"); 2892 2893 // If we end due to a "y" or "n" on the final match, leave the cursor at the beginning of the final match. 2894 BeginTest(" foo"); 2895 TestPressKey(":s/foo/bar/c\\enter"); 2896 TestPressKey("y"); 2897 verifyCursorAt(Cursor(0, 2)); 2898 FinishTest(" bar"); 2899 BeginTest(" foo"); 2900 TestPressKey(":s/foo/bar/c\\enter"); 2901 TestPressKey("n"); 2902 verifyCursorAt(Cursor(0, 2)); 2903 FinishTest(" foo"); 2904 2905 // Respect ranges. 2906 BeginTest("foo foo\nfoo foo\nfoo foo\nfoo foo\n"); 2907 TestPressKey("jVj:s/foo/bar/gc\\enter"); 2908 TestPressKey("ynny"); 2909 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2910 TestPressKey("ggidone \\ctrl-c"); 2911 FinishTest("done foo foo\nbar foo\nfoo bar\nfoo foo\n"); 2912 BeginTest("foo foo\nfoo foo\nfoo foo\nfoo foo\n"); 2913 TestPressKey("jVj:s/foo/bar/gc\\enter"); 2914 TestPressKey("nyyn"); 2915 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2916 TestPressKey("ggidone \\ctrl-c"); 2917 FinishTest("done foo foo\nfoo bar\nbar foo\nfoo foo\n"); 2918 BeginTest("foo foo\nfoo foo\nfoo foo\nfoo foo\n"); 2919 TestPressKey("j:s/foo/bar/gc\\enter"); 2920 TestPressKey("ny"); 2921 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2922 TestPressKey("ggidone \\ctrl-c"); 2923 FinishTest("done foo foo\nfoo bar\nfoo foo\nfoo foo\n"); 2924 BeginTest("foo foo\nfoo foo\nfoo foo\nfoo foo\n"); 2925 TestPressKey("j:s/foo/bar/gc\\enter"); 2926 TestPressKey("yn"); 2927 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2928 TestPressKey("ggidone \\ctrl-c"); 2929 FinishTest("done foo foo\nbar foo\nfoo foo\nfoo foo\n"); 2930 2931 // If no initial match can be found, abort and show a "no replacements" message. 2932 // The cursor position should remain unnchanged. 2933 BeginTest("fab"); 2934 TestPressKey("l:s/fee/bar/c\\enter"); 2935 QVERIFY(commandResponseMessageDisplay()->isVisible()); 2936 verifyShowsNumberOfReplacementsAcrossNumberOfLines(0, 0); 2937 QVERIFY(!interactiveSedReplaceLabel->isVisible()); 2938 TestPressKey("rX"); 2939 BeginTest("fXb"); 2940 2941 // Case-sensitive by default. 2942 BeginTest("foo Foo FOo foo foO"); 2943 TestPressKey(":s/foo/bar/cg\\enter"); 2944 TestPressKey("yyggidone\\esc"); 2945 FinishTest("donebar Foo FOo bar foO"); 2946 2947 // Case-insensitive if "i" flag is used. 2948 BeginTest("foo Foo FOo foo foO"); 2949 TestPressKey(":s/foo/bar/icg\\enter"); 2950 TestPressKey("yyyyyggidone\\esc"); 2951 FinishTest("donebar bar bar bar bar"); 2952 2953 // Only one replacement per-line unless "g" flag is used. 2954 BeginTest("boo foo 123 foo\nxyz foo foo\nfoo foo foo\nxyz\nfoo foo\nfoo 123 foo"); 2955 TestPressKey("jVjjj:s/foo/bar/c\\enter"); 2956 TestPressKey("yynggidone\\esc"); 2957 FinishTest("doneboo foo 123 foo\nxyz bar foo\nbar foo foo\nxyz\nfoo foo\nfoo 123 foo"); 2958 BeginTest("boo foo 123 foo\nxyz foo foo\nfoo foo foo\nxyz\nfoo foo\nfoo 123 foo"); 2959 TestPressKey("jVjjj:s/foo/bar/c\\enter"); 2960 TestPressKey("nnyggidone\\esc"); 2961 FinishTest("doneboo foo 123 foo\nxyz foo foo\nfoo foo foo\nxyz\nbar foo\nfoo 123 foo"); 2962 2963 // If replacement contains new lines, adjust the end line down. 2964 BeginTest("foo\nfoo1\nfoo2\nfoo3"); 2965 TestPressKey("jVj:s/foo/bar\\\\n/gc\\enter"); 2966 TestPressKey("yyggidone\\esc"); 2967 FinishTest("donefoo\nbar\n1\nbar\n2\nfoo3"); 2968 BeginTest("foo\nfoo1\nfoo2\nfoo3"); 2969 TestPressKey("jVj:s/foo/bar\\\\nboo\\\\n/gc\\enter"); 2970 TestPressKey("yyggidone\\esc"); 2971 FinishTest("donefoo\nbar\nboo\n1\nbar\nboo\n2\nfoo3"); 2972 2973 // With "g" and a replacement that involves multiple lines, resume search from the end of the last line added. 2974 BeginTest("foofoo"); 2975 TestPressKey(":s/foo/bar\\\\n/gc\\enter"); 2976 TestPressKey("yyggidone\\esc"); 2977 FinishTest("donebar\nbar\n"); 2978 BeginTest("foofoo"); 2979 TestPressKey(":s/foo/bar\\\\nxyz\\\\nfoo/gc\\enter"); 2980 TestPressKey("yyggidone\\esc"); 2981 FinishTest("donebar\nxyz\nfoobar\nxyz\nfoo"); 2982 2983 // Without "g" and with a replacement that involves multiple lines, resume search from the line after the line just added. 2984 BeginTest("foofoo1\nfoo2\nfoo3"); 2985 TestPressKey("Vj:s/foo/bar\\\\nxyz\\\\nfoo/c\\enter"); 2986 TestPressKey("yyggidone\\esc"); 2987 FinishTest("donebar\nxyz\nfoofoo1\nbar\nxyz\nfoo2\nfoo3"); 2988 2989 // Regression test: handle 'g' when it occurs before 'i' and 'c'. 2990 BeginTest("foo fOo"); 2991 TestPressKey(":s/foo/bar/gci\\enter"); 2992 TestPressKey("yyggidone\\esc"); 2993 FinishTest("donebar bar"); 2994 2995 // When the search terms swallows several lines, move the endline up accordingly. 2996 BeginTest("foo\nfoo1\nfoo\nfoo2\nfoo\nfoo3"); 2997 TestPressKey("V3j:s/foo\\\\nfoo/bar/cg\\enter"); 2998 TestPressKey("yyggidone\\esc"); 2999 FinishTest("donebar1\nbar2\nfoo\nfoo3"); 3000 BeginTest("foo\nfoo\nfoo1\nfoo\nfoo\nfoo2\nfoo\nfoo\nfoo3"); 3001 TestPressKey("V5j:s/foo\\\\nfoo\\\\nfoo/bar/cg\\enter"); 3002 TestPressKey("yyggidone\\esc"); 3003 FinishTest("donebar1\nbar2\nfoo\nfoo\nfoo3"); 3004 // Make sure we still adjust endline down if the replacement text has '\n's. 3005 BeginTest("foo\nfoo\nfoo1\nfoo\nfoo\nfoo2\nfoo\nfoo\nfoo3"); 3006 TestPressKey("V5j:s/foo\\\\nfoo\\\\nfoo/bar\\\\n/cg\\enter"); 3007 TestPressKey("yyggidone\\esc"); 3008 FinishTest("donebar\n1\nbar\n2\nfoo\nfoo\nfoo3"); 3009 3010 // Status reports. 3011 BeginTest("foo"); 3012 TestPressKey(":s/foo/bar/c\\enter"); 3013 TestPressKey("y"); 3014 verifyShowsNumberOfReplacementsAcrossNumberOfLines(1, 1); 3015 FinishTest("bar"); 3016 BeginTest("foo foo foo"); 3017 TestPressKey(":s/foo/bar/gc\\enter"); 3018 TestPressKey("yyy"); 3019 verifyShowsNumberOfReplacementsAcrossNumberOfLines(3, 1); 3020 FinishTest("bar bar bar"); 3021 BeginTest("foo foo foo"); 3022 TestPressKey(":s/foo/bar/gc\\enter"); 3023 TestPressKey("yny"); 3024 verifyShowsNumberOfReplacementsAcrossNumberOfLines(2, 1); 3025 FinishTest("bar foo bar"); 3026 BeginTest("foo\nfoo"); 3027 TestPressKey(":%s/foo/bar/gc\\enter"); 3028 TestPressKey("yy"); 3029 verifyShowsNumberOfReplacementsAcrossNumberOfLines(2, 2); 3030 FinishTest("bar\nbar"); 3031 BeginTest("foo foo\nfoo foo\nfoo foo"); 3032 TestPressKey(":%s/foo/bar/gc\\enter"); 3033 TestPressKey("yynnyy"); 3034 verifyShowsNumberOfReplacementsAcrossNumberOfLines(4, 2); 3035 FinishTest("bar bar\nfoo foo\nbar bar"); 3036 BeginTest("foofoo"); 3037 TestPressKey(":s/foo/bar\\\\nxyz/gc\\enter"); 3038 TestPressKey("yy"); 3039 verifyShowsNumberOfReplacementsAcrossNumberOfLines(2, 1); 3040 FinishTest("bar\nxyzbar\nxyz"); 3041 BeginTest("foofoofoo"); 3042 TestPressKey(":s/foo/bar\\\\nxyz\\\\nboo/gc\\enter"); 3043 TestPressKey("yyy"); 3044 verifyShowsNumberOfReplacementsAcrossNumberOfLines(3, 1); 3045 FinishTest("bar\nxyz\nboobar\nxyz\nboobar\nxyz\nboo"); 3046 // Tricky one: how many lines are "touched" if a single replacement 3047 // swallows multiple lines? I'm going to say the number of lines swallowed. 3048 BeginTest("foo\nfoo\nfoo"); 3049 TestPressKey(":s/foo\\\\nfoo\\\\nfoo/bar/c\\enter"); 3050 TestPressKey("y"); 3051 verifyShowsNumberOfReplacementsAcrossNumberOfLines(1, 3); 3052 FinishTest("bar"); 3053 BeginTest("foo\nfoo\nfoo\n"); 3054 TestPressKey(":s/foo\\\\nfoo\\\\nfoo\\\\n/bar/c\\enter"); 3055 TestPressKey("y"); 3056 verifyShowsNumberOfReplacementsAcrossNumberOfLines(1, 4); 3057 FinishTest("bar"); 3058 3059 // "Undo" undoes last replacement. 3060 BeginTest("foo foo foo foo"); 3061 TestPressKey(":s/foo/bar/cg\\enter"); 3062 TestPressKey("nyynu"); 3063 FinishTest("foo bar foo foo"); 3064 3065 // "l" does the current replacement then exits. 3066 BeginTest("foo foo foo foo foo foo"); 3067 TestPressKey(":s/foo/bar/cg\\enter"); 3068 TestPressKey("nnl"); 3069 verifyShowsNumberOfReplacementsAcrossNumberOfLines(1, 1); 3070 FinishTest("foo foo bar foo foo foo"); 3071 3072 // "q" just exits. 3073 BeginTest("foo foo foo foo foo foo"); 3074 TestPressKey(":s/foo/bar/cg\\enter"); 3075 TestPressKey("yyq"); 3076 verifyShowsNumberOfReplacementsAcrossNumberOfLines(2, 1); 3077 FinishTest("bar bar foo foo foo foo"); 3078 3079 // "a" replaces all remaining, then exits. 3080 BeginTest("foo foo foo foo foo foo"); 3081 TestPressKey(":s/foo/bar/cg\\enter"); 3082 TestPressKey("nna"); 3083 verifyShowsNumberOfReplacementsAcrossNumberOfLines(4, 1); 3084 FinishTest("foo foo bar bar bar bar"); 3085 3086 // The results of "a" can be undone in one go. 3087 BeginTest("foo foo foo foo foo foo"); 3088 TestPressKey(":s/foo/bar/cg\\enter"); 3089 TestPressKey("ya"); 3090 verifyShowsNumberOfReplacementsAcrossNumberOfLines(6, 1); 3091 TestPressKey("u"); 3092 FinishTest("bar foo foo foo foo foo"); 3093 #if 0 3094 // XXX - as of Qt 5.5, simply replaying the correct QKeyEvents does *not* cause shortcuts 3095 // to be triggered, so these tests cannot pass. 3096 // It's possible that a solution involving QTestLib will be workable in the future, though. 3097 3098 { 3099 // Test the test suite: ensure that shortcuts are still being sent and received correctly. 3100 // The test shortcut chosen should be one that does not conflict with built-in Kate ones. 3101 FailsIfSlotNotCalled failsIfActionNotTriggered; 3102 QAction *dummyAction = kate_view->actionCollection()->addAction("Woo"); 3103 dummyAction->setShortcut(QKeySequence("Ctrl+]")); 3104 QVERIFY(connect(dummyAction, SIGNAL(triggered()), &failsIfActionNotTriggered, SLOT(slot()))); 3105 DoTest("foo", "\\ctrl-]", "foo"); 3106 // Processing shortcuts seems to require events to be processed. 3107 while (QApplication::hasPendingEvents()) 3108 { 3109 QApplication::processEvents(); 3110 } 3111 delete dummyAction; 3112 } 3113 { 3114 // Test that shortcuts involving ctrl+<digit> work correctly. 3115 FailsIfSlotNotCalled failsIfActionNotTriggered; 3116 QAction *dummyAction = kate_view->actionCollection()->addAction("Woo"); 3117 dummyAction->setShortcut(QKeySequence("Ctrl+1")); 3118 QVERIFY(connect(dummyAction, SIGNAL(triggered()), &failsIfActionNotTriggered, SLOT(slot()))); 3119 DoTest("foo", "\\ctrl-1", "foo"); 3120 // Processing shortcuts seems to require events to be processed. 3121 while (QApplication::hasPendingEvents()) 3122 { 3123 QApplication::processEvents(); 3124 } 3125 delete dummyAction; 3126 } 3127 { 3128 // Test that shortcuts involving alt+<digit> work correctly. 3129 FailsIfSlotNotCalled failsIfActionNotTriggered; 3130 QAction *dummyAction = kate_view->actionCollection()->addAction("Woo"); 3131 dummyAction->setShortcut(QKeySequence("Alt+1")); 3132 QVERIFY(connect(dummyAction, SIGNAL(triggered()), &failsIfActionNotTriggered, SLOT(slot()))); 3133 DoTest("foo", "\\alt-1", "foo"); 3134 // Processing shortcuts seems to require events to be processed. 3135 while (QApplication::hasPendingEvents()) 3136 { 3137 QApplication::processEvents(); 3138 } 3139 delete dummyAction; 3140 } 3141 #endif 3142 3143 // Find the "Print" action for later use. 3144 QAction *printAction = nullptr; 3145 const auto viewActions = kate_view->actionCollection()->actions(); 3146 for (QAction *action : viewActions) { 3147 if (action->shortcut() == QKeySequence("Ctrl+p")) { 3148 printAction = action; 3149 break; 3150 } 3151 } 3152 3153 // Test that we don't inadvertantly trigger shortcuts in kate_view when typing them in the 3154 // emulated command bar. Requires the above test for shortcuts to be sent and received correctly 3155 // to pass. 3156 { 3157 QVERIFY(mainWindow->isActiveWindow()); 3158 QVERIFY(printAction); 3159 FailsIfSlotCalled failsIfActionTriggered("The kate_view shortcut should not be triggered by typing it in emulated command bar!"); 3160 // Don't invoke Print on failure, as this hangs instead of failing. 3161 // disconnect(printAction, SIGNAL(triggered(bool)), kate_document, SLOT(print())); 3162 connect(printAction, &QAction::triggered, &failsIfActionTriggered, &FailsIfSlotCalled::slot); 3163 DoTest("foo bar foo bar", "/bar\\enterggd/\\ctrl-p\\enter.", "bar"); 3164 // Processing shortcuts seems to require events to be processed. 3165 QApplication::processEvents(); 3166 } 3167 3168 // Test that the interactive search replace does not handle general keypresses like ctrl-p ("invoke 3169 // completion in emulated command bar"). 3170 // Unfortunately, "ctrl-p" in kate_view, which is what will be triggered if this 3171 // test succeeds, hangs due to showing the print dialog, so we need to temporarily 3172 // block the Print action. 3173 clearCommandHistory(); 3174 if (printAction) { 3175 printAction->blockSignals(true); 3176 } 3177 vi_global->commandHistory()->append("s/foo/bar/caa"); 3178 BeginTest("foo"); 3179 TestPressKey(":s/foo/bar/c\\ctrl-b\\enter\\ctrl-p"); 3180 QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible()); 3181 TestPressKey("\\ctrl-c"); 3182 if (printAction) { 3183 printAction->blockSignals(false); 3184 } 3185 FinishTest("foo"); 3186 3187 // The interactive sed replace command is added to the history straight away. 3188 clearCommandHistory(); 3189 BeginTest("foo"); 3190 TestPressKey(":s/foo/bar/c\\enter"); 3191 QCOMPARE(commandHistory(), QStringList() << "s/foo/bar/c"); 3192 TestPressKey("\\ctrl-c"); 3193 FinishTest("foo"); 3194 clearCommandHistory(); 3195 BeginTest("foo"); 3196 TestPressKey(":s/notfound/bar/c\\enter"); 3197 QCOMPARE(commandHistory(), QStringList() << "s/notfound/bar/c"); 3198 TestPressKey("\\ctrl-c"); 3199 FinishTest("foo"); 3200 3201 // Should be usable in mappings. 3202 clearAllMappings(); 3203 vi_global->mappings()->add(Mappings::NormalModeMapping, "H", ":s/foo/bar/gc<enter>nnyyl", Mappings::Recursive); 3204 DoTest("foo foo foo foo foo foo", "H", "foo foo bar bar bar foo"); 3205 clearAllMappings(); 3206 vi_global->mappings()->add(Mappings::NormalModeMapping, "H", ":s/foo/bar/gc<enter>nna", Mappings::Recursive); 3207 DoTest("foo foo foo foo foo foo", "H", "foo foo bar bar bar bar"); 3208 clearAllMappings(); 3209 vi_global->mappings()->add(Mappings::NormalModeMapping, "H", ":s/foo/bar/gc<enter>nnyqggidone<esc>", Mappings::Recursive); 3210 DoTest("foo foo foo foo foo foo", "H", "donefoo foo bar foo foo foo"); 3211 3212 #ifndef Q_OS_MACOS 3213 // Don't swallow "Ctrl+<key>" meant for the text edit. 3214 // On MacOS the QKeySequence for undo is defined as "Ctrl+Z" as well, however it's actually Cmd+Z... 3215 if (QKeySequence::keyBindings(QKeySequence::Undo).contains(QKeySequence("Ctrl+Z"))) { 3216 DoTest("foo bar", "/bar\\ctrl-z\\enterrX", "Xoo bar"); 3217 } else { 3218 qWarning() << "Skipped test: Ctrl+Z is not Undo on this platform"; 3219 } 3220 #endif 3221 3222 // Don't give invalid cursor position to updateCursor in Visual Mode: it will cause a crash! 3223 DoTest("xyz\nfoo\nbar\n123", "/foo\\\\nbar\\\\n\\enterggv//e\\enter\\ctrl-crX", "xyz\nfoo\nbaX\n123"); 3224 DoTest("\nfooxyz\nbar;\n", "/foo.*\\\\n.*;\\enterggv//e\\enter\\ctrl-crX", "\nfooxyz\nbarX\n"); 3225 } 3226 3227 QCompleter *EmulatedCommandBarTest::emulatedCommandBarCompleter() 3228 { 3229 return vi_input_mode->viModeEmulatedCommandBar()->findChild<QCompleter *>("completer"); 3230 } 3231 3232 void EmulatedCommandBarTest::verifyCommandBarCompletionVisible() 3233 { 3234 if (!emulatedCommandBarCompleter()->popup()->isVisible()) { 3235 qDebug() << "Emulated command bar completer not visible."; 3236 QStringListModel *completionModel = qobject_cast<QStringListModel *>(emulatedCommandBarCompleter()->model()); 3237 Q_ASSERT(completionModel); 3238 const QStringList allAvailableCompletions = completionModel->stringList(); 3239 qDebug() << " Completion list: " << allAvailableCompletions; 3240 qDebug() << " Completion prefix: " << emulatedCommandBarCompleter()->completionPrefix(); 3241 bool candidateCompletionFound = false; 3242 for (const QString &availableCompletion : allAvailableCompletions) { 3243 if (availableCompletion.startsWith(emulatedCommandBarCompleter()->completionPrefix())) { 3244 candidateCompletionFound = true; 3245 break; 3246 } 3247 } 3248 if (candidateCompletionFound) { 3249 qDebug() << " The current completion prefix is a prefix of one of the available completions, so either complete() was not called, or the popup was " 3250 "manually hidden since then"; 3251 } else { 3252 qDebug() << " The current completion prefix is not a prefix of one of the available completions; this may or may not be why it is not visible"; 3253 } 3254 } 3255 QVERIFY(emulatedCommandBarCompleter()->popup()->isVisible()); 3256 } 3257 3258 void EmulatedCommandBarTest::verifyCommandBarCompletionsMatches(const QStringList &expectedCompletionList) 3259 { 3260 verifyCommandBarCompletionVisible(); 3261 QStringList actualCompletionList; 3262 for (int i = 0; emulatedCommandBarCompleter()->setCurrentRow(i); i++) { 3263 actualCompletionList << emulatedCommandBarCompleter()->currentCompletion(); 3264 } 3265 if (expectedCompletionList != actualCompletionList) { 3266 qDebug() << "Actual completions:\n " << actualCompletionList << "\n\ndo not match expected:\n" << expectedCompletionList; 3267 } 3268 3269 QCOMPARE(actualCompletionList, expectedCompletionList); 3270 } 3271 3272 void EmulatedCommandBarTest::verifyCommandBarCompletionContains(const QStringList &expectedCompletionList) 3273 { 3274 verifyCommandBarCompletionVisible(); 3275 QStringList actualCompletionList; 3276 3277 for (int i = 0; emulatedCommandBarCompleter()->setCurrentRow(i); i++) { 3278 actualCompletionList << emulatedCommandBarCompleter()->currentCompletion(); 3279 } 3280 3281 for (const QString &expectedCompletion : expectedCompletionList) { 3282 if (!actualCompletionList.contains(expectedCompletion)) { 3283 qDebug() << "Whoops: " << actualCompletionList << " does not contain " << expectedCompletion; 3284 } 3285 QVERIFY(actualCompletionList.contains(expectedCompletion)); 3286 } 3287 } 3288 3289 QLabel *EmulatedCommandBarTest::emulatedCommandTypeIndicator() 3290 { 3291 return emulatedCommandBar()->findChild<QLabel *>("bartypeindicator"); 3292 } 3293 3294 void EmulatedCommandBarTest::verifyCursorAt(const Cursor &expectedCursorPos) 3295 { 3296 QCOMPARE(kate_view->cursorPosition().line(), expectedCursorPos.line()); 3297 QCOMPARE(kate_view->cursorPosition().column(), expectedCursorPos.column()); 3298 } 3299 3300 void EmulatedCommandBarTest::clearSearchHistory() 3301 { 3302 vi_global->searchHistory()->clear(); 3303 } 3304 3305 QStringList EmulatedCommandBarTest::searchHistory() 3306 { 3307 return vi_global->searchHistory()->items(); 3308 } 3309 3310 void EmulatedCommandBarTest::clearCommandHistory() 3311 { 3312 vi_global->commandHistory()->clear(); 3313 } 3314 3315 QStringList EmulatedCommandBarTest::commandHistory() 3316 { 3317 return vi_global->commandHistory()->items(); 3318 } 3319 3320 void EmulatedCommandBarTest::clearReplaceHistory() 3321 { 3322 vi_global->replaceHistory()->clear(); 3323 } 3324 3325 QStringList EmulatedCommandBarTest::replaceHistory() 3326 { 3327 return vi_global->replaceHistory()->items(); 3328 } 3329 3330 QVector<Kate::TextRange *> EmulatedCommandBarTest::rangesOnFirstLine() 3331 { 3332 return kate_document->buffer().rangesForLine(0, kate_view, true); 3333 } 3334 3335 void EmulatedCommandBarTest::verifyTextEditBackgroundColour(const QColor &expectedBackgroundColour) 3336 { 3337 QCOMPARE(emulatedCommandBarTextEdit()->palette().brush(QPalette::Base).color(), expectedBackgroundColour); 3338 } 3339 3340 QLabel *EmulatedCommandBarTest::commandResponseMessageDisplay() 3341 { 3342 QLabel *commandResponseMessageDisplay = emulatedCommandBar()->findChild<QLabel *>("commandresponsemessage"); 3343 Q_ASSERT(commandResponseMessageDisplay); 3344 return commandResponseMessageDisplay; 3345 } 3346 3347 void EmulatedCommandBarTest::waitForEmulatedCommandBarToHide(long int timeout) 3348 { 3349 QTRY_VERIFY_WITH_TIMEOUT(!emulatedCommandBar()->isVisible(), timeout); 3350 } 3351 3352 void EmulatedCommandBarTest::verifyShowsNumberOfReplacementsAcrossNumberOfLines(int numReplacements, int acrossNumLines) 3353 { 3354 QVERIFY(commandResponseMessageDisplay()->isVisible()); 3355 QVERIFY(!emulatedCommandTypeIndicator()->isVisible()); 3356 const QString commandMessageResponseText = commandResponseMessageDisplay()->text(); 3357 const QString expectedNumReplacementsAsString = QString::number(numReplacements); 3358 const QString expectedAcrossNumLinesAsString = QString::number(acrossNumLines); 3359 // Be a bit vague about the actual contents due to e.g. localization. 3360 // TODO - see if we can insist that en_US is available on the Kate Jenkins server and 3361 // insist that we use it ... ? 3362 static const QRegularExpression numReplacementsMessageRegex("^.*(\\d+).*(\\d+).*$"); 3363 const auto match = numReplacementsMessageRegex.match(commandMessageResponseText); 3364 QVERIFY(match.hasMatch()); 3365 const QString actualNumReplacementsAsString = match.captured(1); 3366 const QString actualAcrossNumLinesAsString = match.captured(2); 3367 QCOMPARE(actualNumReplacementsAsString, expectedNumReplacementsAsString); 3368 QCOMPARE(actualAcrossNumLinesAsString, expectedAcrossNumLinesAsString); 3369 } 3370 3371 FailsIfSlotNotCalled::FailsIfSlotNotCalled() 3372 : QObject() 3373 { 3374 } 3375 3376 FailsIfSlotNotCalled::~FailsIfSlotNotCalled() 3377 { 3378 QVERIFY(m_slotWasCalled); 3379 } 3380 3381 void FailsIfSlotNotCalled::slot() 3382 { 3383 m_slotWasCalled = true; 3384 } 3385 3386 FailsIfSlotCalled::FailsIfSlotCalled(const QString &failureMessage) 3387 : QObject() 3388 , m_failureMessage(failureMessage) 3389 { 3390 } 3391 3392 void FailsIfSlotCalled::slot() 3393 { 3394 QFAIL(qPrintable(m_failureMessage.toLatin1())); 3395 } 3396 3397 #include "moc_emulatedcommandbar.cpp"