summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/fakevim/fakevim_test.cpp23
-rw-r--r--src/plugins/fakevim/fakevimhandler.cpp140
2 files changed, 141 insertions, 22 deletions
diff --git a/src/plugins/fakevim/fakevim_test.cpp b/src/plugins/fakevim/fakevim_test.cpp
index e744de6bb4..43f7057041 100644
--- a/src/plugins/fakevim/fakevim_test.cpp
+++ b/src/plugins/fakevim/fakevim_test.cpp
@@ -954,12 +954,29 @@ void FakeVimPlugin::test_vim_search()
KEYS("n", X "abc abc abc abc");
KEYS("N", "abc " X "abc abc abc");
- NOT_IMPLEMENTED
+ // search is greedy
+ data.doCommand("set ws");
+ data.setText("abc" N "def" N "abc" N "ghi abc jkl");
+ KEYS("/[a-z]*<CR>", "abc" N X "def" N "abc" N "ghi abc jkl");
+ KEYS("2n", "abc" N "def" N "abc" N X "ghi abc jkl");
+ KEYS("3n", "abc" N "def" N "abc" N "ghi abc" X " jkl");
+ KEYS("3N", "abc" N "def" N "abc" N X "ghi abc jkl");
+ KEYS("2N", "abc" N X "def" N "abc" N "ghi abc jkl");
+
+ data.setText("a.b.c" N "" N "d.e.f");
+ KEYS("/[a-z]*<CR>", "a" X ".b.c" N "" N "d.e.f");
+ KEYS("n", "a." X "b.c" N "" N "d.e.f");
+ KEYS("2n", "a.b." X "c" N "" N "d.e.f");
+ KEYS("n", "a.b.c" N X "" N "d.e.f");
+ KEYS("n", "a.b.c" N "" N X "d.e.f");
+ KEYS("2N", "a.b." X "c" N "" N "d.e.f");
+ KEYS("2n", "a.b.c" N "" N X "d.e.f");
+
// 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("/\\w\\{2}<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");
KEYS("2n2N", X "abc" N "def" N "ghi");
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 96af57bb9f..011a8848ad 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -452,6 +452,94 @@ static QRegExp vimPatternToQtPattern(QString needle, bool smartcase)
return QRegExp(pattern);
}
+static bool afterEndOfLine(const QTextDocument *doc, int position)
+{
+ return doc->characterAt(position) == ParagraphSeparator
+ && doc->findBlock(position).length() > 1;
+}
+
+static void searchForward(QTextCursor *tc, QRegExp &needleExp, int *repeat)
+{
+ const QTextDocument *doc = tc->document();
+ const int startPos = tc->position();
+
+ // Search from beginning of line so that matched text is the same.
+ tc->movePosition(StartOfLine);
+
+ // forward to current position
+ *tc = doc->find(needleExp, *tc);
+ while (!tc->isNull() && tc->anchor() < startPos) {
+ if (!tc->hasSelection())
+ tc->movePosition(Right);
+ if (tc->atBlockEnd())
+ tc->movePosition(Right);
+ *tc = doc->find(needleExp, *tc);
+ }
+
+ if (tc->isNull())
+ return;
+
+ --*repeat;
+
+ while (*repeat > 0) {
+ if (!tc->hasSelection())
+ tc->movePosition(Right);
+ if (tc->atBlockEnd())
+ tc->movePosition(Right);
+ *tc = doc->find(needleExp, *tc);
+ if (tc->isNull())
+ return;
+ --*repeat;
+ }
+
+ if (!tc->isNull() && afterEndOfLine(doc, tc->anchor()))
+ tc->movePosition(Left);
+}
+
+static void searchBackward(QTextCursor *tc, QRegExp &needleExp, int *repeat)
+{
+ // Search from beginning of line so that matched text is the same.
+ QTextBlock block = tc->block();
+ QString line = block.text();
+
+ int i = line.indexOf(needleExp, 0);
+ while (i != -1 && i < tc->positionInBlock()) {
+ --*repeat;
+ i = line.indexOf(needleExp, i + qMax(1, needleExp.matchedLength()));
+ if (i == line.size())
+ i = -1;
+ }
+
+ if (i == tc->positionInBlock())
+ --*repeat;
+
+ while (*repeat > 0) {
+ block = block.previous();
+ if (!block.isValid())
+ break;
+ line = block.text();
+ i = line.indexOf(needleExp, 0);
+ while (i != -1) {
+ --*repeat;
+ i = line.indexOf(needleExp, i + qMax(1, needleExp.matchedLength()));
+ if (i == line.size())
+ i = -1;
+ }
+ }
+
+ if (!block.isValid()) {
+ *tc = QTextCursor();
+ return;
+ }
+
+ i = line.indexOf(needleExp, 0);
+ while (*repeat < 0) {
+ i = line.indexOf(needleExp, i + qMax(1, needleExp.matchedLength()));
+ ++*repeat;
+ }
+ tc->setPosition(block.position() + i);
+}
+
static bool substituteText(QString *text, QRegExp &pattern, const QString &replacement,
bool global)
{
@@ -2360,8 +2448,7 @@ void FakeVimHandler::Private::fixSelection()
// Omit first character in selection if it's line break on non-empty line.
int start = anchor();
int end = position();
- if (document()->characterAt(start) == ParagraphSeparator
- && start > 0 && document()->characterAt(start - 1) != ParagraphSeparator) {
+ if (afterEndOfLine(document(), start) && start > 0) {
start = qMin(start + 1, end);
if (m_submode == DeleteSubMode && !atDocumentEnd())
setAnchorAndPosition(start, end + 1);
@@ -5072,23 +5159,44 @@ void FakeVimHandler::Private::searchBalanced(bool forward, QChar needle, QChar o
QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos, int count,
bool showMessages)
{
- QTextDocument::FindFlags flags = QTextDocument::FindCaseSensitively;
- if (!sd.forward)
- flags |= QTextDocument::FindBackward;
-
QRegExp needleExp = vimPatternToQtPattern(sd.needle, hasConfig(ConfigSmartCase));
+ if (!needleExp.isValid()) {
+ if (showMessages) {
+ QString error = needleExp.errorString();
+ showMessage(MessageError,
+ FakeVimHandler::tr("Invalid regular expression: %1").arg(error));
+ }
+ if (sd.highlightMatches)
+ highlightMatches(QString());
+ return QTextCursor();
+ }
- QTextCursor tc = document()->find(needleExp, startPos + (sd.forward ? 1 : -1), flags);
int repeat = count;
- while (!tc.isNull() && --repeat >= 1)
- tc = document()->find(needleExp, tc, flags);
+ const int pos = startPos + (sd.forward ? 1 : -1);
+
+ QTextCursor tc;
+ if (pos >= 0 && pos < document()->characterCount()) {
+ tc = QTextCursor(document());
+ tc.setPosition(pos);
+ if (sd.forward && afterEndOfLine(document(), pos))
+ tc.movePosition(Right);
+
+ if (!tc.isNull()) {
+ if (sd.forward)
+ searchForward(&tc, needleExp, &repeat);
+ else
+ searchBackward(&tc, needleExp, &repeat);
+ }
+ }
if (tc.isNull()) {
if (hasConfig(ConfigWrapScan)) {
- int newStartPos = sd.forward ? 0 : lastPositionInDocument(true);
- tc = document()->find(needleExp, newStartPos, flags);
- while (!tc.isNull() && --repeat >= 1)
- tc = document()->find(needleExp, tc, flags);
+ tc = QTextCursor(document());
+ tc.movePosition(sd.forward ? StartOfDocument : EndOfDocument);
+ if (sd.forward)
+ searchForward(&tc, needleExp, &repeat);
+ else
+ searchBackward(&tc, needleExp, &repeat);
if (tc.isNull()) {
if (showMessages) {
showMessage(MessageError,
@@ -5108,12 +5216,6 @@ QTextCursor FakeVimHandler::Private::search(const SearchData &sd, int startPos,
}
}
- if (tc.isNull() && !needleExp.isValid() && showMessages) {
- QString error = needleExp.errorString();
- showMessage(MessageError,
- FakeVimHandler::tr("Invalid regular expression: %1").arg(error));
- }
-
if (sd.highlightMatches)
highlightMatches(needleExp.pattern());