diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp index af207111bf9..50b5967403d 100644 --- a/src/plugins/fakevim/fakevim_test.cpp +++ b/src/plugins/fakevim/fakevim_test.cpp @@ -426,17 +426,68 @@ void FakeVimPlugin::test_vim_search() data.setText("abc" N "def" N "ghi"); KEYS("/ghi", "abc" N "def" N X "ghi"); - KEYS("gg/\\w\\{3}", X "abc" N "def" N "ghi"); - KEYS("n", "abc" N X "def" N "ghi"); + KEYS("gg/\\w\\{3}", "abc" N X "def" N "ghi"); + KEYS("n", "abc" N "def" N X "ghi"); + KEYS("N", "abc" N X "def" N "ghi"); KEYS("N", X "abc" N "def" N "ghi"); - NOT_IMPLEMENTED - KEYS("2n", "abc" N "def" N X "ghi"); - KEYS("2N", X "abc" N "def" N "ghi"); + // return to search-start position on escape or not found + KEYS("/def", X "abc" N "def" N "ghi"); + KEYS("/x", X "abc" N "def" N "ghi"); + KEYS("/x", X "abc" N "def" N "ghi"); + KEYS("/x", X "abc" N "def" N "ghi"); + + KEYS("?def", X "abc" N "def" N "ghi"); + KEYS("?x", X "abc" N "def" N "ghi"); + KEYS("?x", X "abc" N "def" N "ghi"); + KEYS("?x", X "abc" N "def" N "ghi"); + + // search [count] times + data.setText("abc" N "def" N "ghi"); + KEYS("/\\w\\{3}", "abc" N X "def" N "ghi"); + KEYS("2n", X "abc" N "def" N "ghi"); + KEYS("2N", "abc" N X "def" N "ghi"); + KEYS("2/\\w\\{3}", X "abc" N "def" N "ghi"); + + // set wrapscan (search wraps at end of file) + data.doCommand("set ws"); + data.setText("abc" N "def" N "abc" N "ghi abc jkl"); + KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl"); + KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); + KEYS("2*", "abc" N "def" N X "abc" N "ghi abc jkl"); + KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); + KEYS("#", "abc" N "def" N "abc" N "ghi " X "abc jkl"); + KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl"); + KEYS("2#", "abc" N "def" N "abc" N "ghi " X "abc jkl"); + + data.doCommand("set nows"); + data.setText("abc" N "def" N "abc" N "ghi abc jkl"); + KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl"); + KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); + KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl"); + KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl"); + KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); + KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); + + data.setText("abc" N "def" N "ab" X "c" N "ghi abc jkl"); + KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl"); /* QTCREATORBUG-7251 */ data.setText("abc abc abc abc"); KEYS("$?abc", "abc abc abc " X "abc"); + KEYS("2?abc", "abc " X "abc abc abc"); + KEYS("n", X "abc abc abc abc"); + KEYS("N", "abc " X "abc abc abc"); + + NOT_IMPLEMENTED + // find same stuff forward and backward, + // i.e. 'c' forward but not 'a' backward + data.setText("abc" N "def" N "ghi"); + KEYS("/\\w\\{2}", X "abc" N "def" N "ghi"); + KEYS("2n", "abc" N "def" N X "ghi"); + KEYS("N", "abc" N X "def" N "ghi"); + KEYS("N", X "abc" N "def" N "ghi"); + KEYS("2n2N", X "abc" N "def" N "ghi"); } void FakeVimPlugin::test_vim_indent() diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp index 59a6dfb035d..4e5fac08be6 100644 --- a/src/plugins/fakevim/fakevimactions.cpp +++ b/src/plugins/fakevim/fakevimactions.cpp @@ -218,6 +218,13 @@ FakeVimSettings *theFakeVimSettings() item->setCheckable(true); instance->insertItem(ConfigSmartCase, item, _("smartcase"), _("scs")); + item = new SavedAction(instance); + item->setDefaultValue(true); + item->setValue(true); + item->setSettingsKey(group, _("WrapScan")); item->setCheckable(true); + item->setCheckable(true); + instance->insertItem(ConfigWrapScan, item, _("wrapscan"), _("ws")); + item = new SavedAction(instance); item->setDefaultValue(_("indent,eol,start")); item->setSettingsKey(group, _("Backspace")); diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h index d52bf98cdf1..fe72770c280 100644 --- a/src/plugins/fakevim/fakevimactions.h +++ b/src/plugins/fakevim/fakevimactions.h @@ -53,9 +53,11 @@ enum FakeVimSettingsCode ConfigExpandTab, ConfigAutoIndent, ConfigSmartIndent, + ConfigIncSearch, ConfigUseCoreSearch, ConfigSmartCase, + ConfigWrapScan, // indent allow backspacing over autoindent // eol allow backspacing over line breaks (join lines) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 82c3b1205d1..c4fcd0f28d9 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -297,14 +297,12 @@ struct SearchData SearchData() { forward = true; - mustMove = true; highlightMatches = true; highlightCursor = true; } QString needle; bool forward; - bool mustMove; bool highlightMatches; bool highlightCursor; }; @@ -887,6 +885,7 @@ public: void finishMovement(const QString &dotCommand, int count); void resetCommandMode(); void search(const SearchData &sd); + void searchNext(bool forward = true); void searchBalanced(bool forward, QChar needle, QChar other); void highlightMatches(const QString &needle); void stopIncrementalFind(); @@ -1222,6 +1221,8 @@ public: QList m_searchSelections; QTextCursor m_searchCursor; + int m_searchStartPosition; + int m_searchFromScreenLine; QString m_oldNeedle; QString m_lastSubstituteFlags; QRegExp m_lastSubstitutePattern; @@ -1326,6 +1327,8 @@ void FakeVimHandler::Private::init() m_oldPosition = -1; m_lastChangePosition = -1; m_breakEditBlock = false; + m_searchStartPosition = 0; + m_searchFromScreenLine = 0; setupCharClass(); } @@ -2002,9 +2005,10 @@ void FakeVimHandler::Private::updateMiniBuffer() QString msg; int cursorPos = -1; + bool interactive = (m_mode == ExMode || m_subsubmode == SearchSubSubMode); if (m_passing) { msg = "-- PASSING -- "; - } else if (!m_currentMessage.isEmpty()) { + } else if (!m_currentMessage.isEmpty() && !interactive) { msg = m_currentMessage; } else if (m_mode == CommandMode && isVisualMode()) { if (isVisualCharMode()) { @@ -2019,10 +2023,8 @@ void FakeVimHandler::Private::updateMiniBuffer() } else if (m_mode == ReplaceMode) { msg = "-- REPLACE --"; } else if (!m_commandPrefix.isEmpty()) { - //QTC_ASSERT(m_mode == ExMode || m_subsubmode == SearchSubSubMode, - // qDebug() << "MODE: " << m_mode << m_subsubmode); msg = m_commandPrefix + m_commandBuffer.display(); - if (m_mode != CommandMode) + if (interactive) cursorPos = m_commandPrefix.size() + m_commandBuffer.cursorPos(); } else { QTC_CHECK(m_mode == CommandMode && m_subsubmode != SearchSubSubMode); @@ -2394,6 +2396,8 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) m_movetype = MoveExclusive; m_subsubmode = SearchSubSubMode; m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?'); + m_searchStartPosition = position(); + m_searchFromScreenLine = firstVisibleLine(); m_commandBuffer.clear(); updateMiniBuffer(); } @@ -2410,18 +2414,8 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input) setAnchorAndPosition(tc.position(), tc.anchor()); g.searchHistory.append(needle); m_lastSearchForward = input.is('*'); - m_currentMessage.clear(); - m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?'); - m_commandBuffer.setContents(needle); - SearchData sd; - sd.needle = needle; - sd.forward = m_lastSearchForward; - sd.highlightCursor = false; - sd.highlightMatches = true; - search(sd); - //m_searchCursor = QTextCursor(); - //updateSelection(); - //updateMiniBuffer(); + searchNext(); + finishMovement(); } else if (input.is('\'')) { m_subsubmode = TickSubSubMode; if (m_submode != NoSubMode) @@ -2810,12 +2804,8 @@ EventResult FakeVimHandler::Private::handleCommandMode2(const Input &input) } setPosition(cursor().selectionStart()); } else { - SearchData sd; - sd.needle = g.searchHistory.current(); - sd.forward = input.is('n') ? m_lastSearchForward : !m_lastSearchForward; - sd.highlightCursor = false; - sd.highlightMatches = true; - search(sd); + searchNext(input.is('n')); + finishMovement(); } } else if (isVisualMode() && (input.is('o') || input.is('O'))) { int pos = position(); @@ -3445,6 +3435,8 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input) m_commandBuffer.clear(); g.searchHistory.append(m_searchCursor.selectedText()); m_searchCursor = QTextCursor(); + setPosition(m_searchStartPosition); + scrollToLine(m_searchFromScreenLine); updateSelection(); enterCommandMode(); updateMiniBuffer(); @@ -3477,6 +3469,8 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input) search(sd); } finishMovement(m_commandPrefix + needle + '\n'); + } else { + finishMovement(); } enterCommandMode(); highlightMatches(needle); @@ -3500,7 +3494,6 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input) SearchData sd; sd.needle = m_commandBuffer.contents(); sd.forward = m_lastSearchForward; - sd.mustMove = false; sd.highlightCursor = true; sd.highlightMatches = false; search(sd); @@ -4258,7 +4251,6 @@ void FakeVimHandler::Private::search(const SearchData &sd) if (sd.needle.isEmpty()) return; - const bool incSearch = hasConfig(ConfigIncSearch); QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively; if (!sd.forward) flags |= QTextDocument::FindBackward; @@ -4267,29 +4259,36 @@ void FakeVimHandler::Private::search(const SearchData &sd) const int oldLine = cursorLine() - cursorLineOnScreen(); - int startPos = position(); - if (sd.mustMove) - sd.forward ? ++startPos : --startPos; + int startPos = m_searchStartPosition + (sd.forward ? 1 : -1); m_searchCursor = QTextCursor(); + int repeat = count(); QTextCursor tc = document()->find(needleExp, startPos, flags); + while (!tc.isNull() && --repeat >= 1) + tc = document()->find(needleExp, tc, flags); + if (tc.isNull()) { - int startPos = sd.forward ? 0 : lastPositionInDocument(); - tc = document()->find(needleExp, startPos, flags); - if (tc.isNull()) { - if (!incSearch) { + if (hasConfig(ConfigWrapScan)) { + int startPos = sd.forward ? 0 : lastPositionInDocument(); + tc = document()->find(needleExp, startPos, flags); + while (!tc.isNull() && --repeat >= 1) + tc = document()->find(needleExp, tc, flags); + if (tc.isNull()) { highlightMatches(QString()); - showRedMessage(FakeVimHandler::tr("Pattern not found: %1") - .arg(needleExp.pattern())); + showRedMessage(FakeVimHandler::tr("Pattern not found: %1").arg(sd.needle)); + updateSelection(); + return; } - updateSelection(); - return; - } - if (!incSearch) { QString msg = sd.forward ? FakeVimHandler::tr("search hit BOTTOM, continuing at TOP") : FakeVimHandler::tr("search hit TOP, continuing at BOTTOM"); showRedMessage(msg); + } else { + QString msg = sd.forward + ? FakeVimHandler::tr("search hit BOTTOM without match for: %1") + : FakeVimHandler::tr("search hit TOP without match for: %1"); + showRedMessage(msg.arg(sd.needle)); + return; } } @@ -4303,7 +4302,7 @@ void FakeVimHandler::Private::search(const SearchData &sd) if (oldLine != cursorLine() - cursorLineOnScreen()) scrollToLine(cursorLine() - linesOnScreen() / 2); - if (incSearch && sd.highlightCursor) + if (sd.highlightCursor) m_searchCursor = cursor(); setTargetColumn(); @@ -4313,6 +4312,21 @@ void FakeVimHandler::Private::search(const SearchData &sd) updateSelection(); } +void FakeVimHandler::Private::searchNext(bool forward) +{ + SearchData sd; + sd.needle = g.searchHistory.current(); + sd.forward = forward ? m_lastSearchForward : !m_lastSearchForward; + sd.highlightCursor = false; + sd.highlightMatches = true; + m_searchStartPosition = position(); + m_currentMessage.clear(); + search(sd); + + m_commandPrefix = QLatin1Char(m_lastSearchForward ? '/' : '?'); + m_commandBuffer.setContents(sd.needle); +} + void FakeVimHandler::Private::highlightMatches(const QString &needle) { if (!hasConfig(ConfigHlSearch)) diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui index ff324ce7c80..66a3aa17044 100644 --- a/src/plugins/fakevim/fakevimoptions.ui +++ b/src/plugins/fakevim/fakevimoptions.ui @@ -66,6 +66,13 @@ + + + + Use wrapscan + + + @@ -73,7 +80,7 @@ - + Show position of text marks @@ -87,7 +94,7 @@ - + Pass key sequences like Ctrl-S to Qt Creator core instead of interpreting them in FakeVim. This gives easier access to Qt Creator core functionality at the price of losing some features of FakeVim. diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index fe018422fc8..e24ca6f7249 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -234,12 +234,15 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent) m_ui.checkBoxAutoIndent); m_group.insert(theFakeVimSetting(ConfigSmartIndent), m_ui.checkBoxSmartIndent); + m_group.insert(theFakeVimSetting(ConfigIncSearch), m_ui.checkBoxIncSearch); m_group.insert(theFakeVimSetting(ConfigUseCoreSearch), m_ui.checkBoxUseCoreSearch); m_group.insert(theFakeVimSetting(ConfigSmartCase), m_ui.checkBoxSmartCase); + m_group.insert(theFakeVimSetting(ConfigWrapScan), + m_ui.checkBoxWrapScan); connect(m_ui.pushButtonCopyTextEditorSettings, SIGNAL(clicked()), SLOT(copyTextEditorSettings()));