Commit 4503ce66 authored by Lukas Holecek's avatar Lukas Holecek Committed by hjk
Browse files

fakevim: Improved searching



Reset cursor position if search is canceled and always search from
initial cursor position if search expression changes.

Implemented Vim's wrapscan (ws) option.

Task-number: QTCREATORBUG-7251

Change-Id: Ic709cc4fb9dacdb94fbd17f85ac9b75738d5578c
Reviewed-by: default avatarhjk <qthjk@ovi.com>
parent c4b9cff3
......@@ -426,17 +426,68 @@ void FakeVimPlugin::test_vim_search()
data.setText("abc" N "def" N "ghi");
KEYS("/ghi<CR>", "abc" N "def" N X "ghi");
KEYS("gg/\\w\\{3}<CR>", X "abc" N "def" N "ghi");
KEYS("n", "abc" N X "def" N "ghi");
KEYS("gg/\\w\\{3}<CR>", "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<ESC>", X "abc" N "def" N "ghi");
KEYS("/x", X "abc" N "def" N "ghi");
KEYS("/x<CR>", X "abc" N "def" N "ghi");
KEYS("/x<ESC>", X "abc" N "def" N "ghi");
KEYS("?def<ESC>", X "abc" N "def" N "ghi");
KEYS("?x", X "abc" N "def" N "ghi");
KEYS("?x<CR>", X "abc" N "def" N "ghi");
KEYS("?x<ESC>", X "abc" N "def" N "ghi");
// search [count] times
data.setText("abc" N "def" N "ghi");
KEYS("/\\w\\{3}<CR>", "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}<CR>", 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<CR>", "abc abc abc " X "abc");
KEYS("2?abc<CR>", "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. '<ab>c' forward but not 'a<bc>' backward
data.setText("abc" N "def" N "ghi");
KEYS("/\\w\\{2}<CR>", 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()
......
......@@ -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"));
......
......@@ -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)
......
......@@ -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<QTextEdit::ExtraSelection> 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))
......
......@@ -66,6 +66,13 @@
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QCheckBox" name="checkBoxWrapScan">
<property name="text">
<string>Use wrapscan</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="checkBoxExpandTab">
<property name="text">
......@@ -73,7 +80,7 @@
</property>
</widget>
</item>
<item row="3" column="2">
<item row="4" column="2">
<widget class="QCheckBox" name="checkBoxShowMarks">
<property name="text">
<string>Show position of text marks</string>
......@@ -87,7 +94,7 @@
</property>
</widget>
</item>
<item row="4" column="2">
<item row="5" column="2">
<widget class="QCheckBox" name="checkBoxPassControlKey">
<property name="toolTip">
<string>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.</string>
......
......@@ -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()));
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment