forked from qt-creator/qt-creator
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: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -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()));
|
||||
|
Reference in New Issue
Block a user