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