[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [ktexteditor] src: Move SearchMode into its own source files.
From:       Simon St James <kdedevel () etotheipiplusone ! com>
Date:       2016-06-17 8:18:10
Message-ID: E1bDoyg-0002ZN-LW () scm ! kde ! org
[Download RAW message or body]

Git commit f021d6eba80ebedc11bd79d2926fc315a4ea2fc9 by Simon St James.
Committed on 17/06/2016 at 08:14.
Pushed by sstjames into branch 'master'.

Move SearchMode into its own source files.

M  +1    -0    src/CMakeLists.txt
M  +1    -356  src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
M  +1    -33   src/vimode/emulatedcommandbar/emulatedcommandbar.h
A  +373  -0    src/vimode/emulatedcommandbar/searchmode.cpp     [License: UNKNOWN]  *
A  +55   -0    src/vimode/emulatedcommandbar/searchmode.h     [License: UNKNOWN]  *

The files marked with a * at the end have a non valid license. Please read: \
http://techbase.kde.org/Policies/Licensing_Policy and use the headers which are \
listed at that page.


http://commits.kde.org/ktexteditor/f021d6eba80ebedc11bd79d2926fc315a4ea2fc9

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9e4dc5b..51374c7 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -280,6 +280,7 @@ if (BUILD_VIMODE)
     vimode/emulatedcommandbar/completer.cpp
     vimode/emulatedcommandbar/activemode.cpp
     vimode/emulatedcommandbar/interactivesedreplacemode.cpp
+    vimode/emulatedcommandbar/searchmode.cpp
     vimode/commandrangeexpressionparser.cpp
     vimode/keymapper.cpp
     vimode/marks.cpp
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp index 00b0355..513de48 100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.cpp
@@ -30,6 +30,7 @@
 #include <vimode/modes/normalvimode.h>
 #include "matchhighlighter.h"
 #include "interactivesedreplacemode.h"
+#include "searchmode.h"
 
 #include <vimode/cmds.h>
 #include <vimode/modes/visualvimode.h>
@@ -41,7 +42,6 @@
 #include "../registers.h"
 #include "../searcher.h"
 
-#include <KColorScheme>
 #include <KLocalizedString>
 
 #include <QLineEdit>
@@ -56,153 +56,6 @@ using namespace KateVi;
 
 namespace
 {
-bool isCharEscaped(const QString &string, int charPos)
-{
-    if (charPos == 0) {
-        return false;
-    }
-    int numContiguousBackslashesToLeft = 0;
-    charPos--;
-    while (charPos >= 0 && string[charPos] == QLatin1Char('\\')) {
-        numContiguousBackslashesToLeft++;
-        charPos--;
-    }
-    return ((numContiguousBackslashesToLeft % 2) == 1);
-}
-
-QString toggledEscaped(const QString &originalString, QChar escapeChar)
-{
-    int searchFrom = 0;
-    QString toggledEscapedString = originalString;
-    do {
-        const int indexOfEscapeChar = toggledEscapedString.indexOf(escapeChar, \
                searchFrom);
-        if (indexOfEscapeChar == -1) {
-            break;
-        }
-        if (!isCharEscaped(toggledEscapedString, indexOfEscapeChar)) {
-            // Escape.
-            toggledEscapedString.replace(indexOfEscapeChar, 1, QLatin1String("\\") + \
                escapeChar);
-            searchFrom = indexOfEscapeChar + 2;
-        } else {
-            // Unescape.
-            toggledEscapedString.remove(indexOfEscapeChar - 1, 1);
-            searchFrom = indexOfEscapeChar;
-        }
-    } while (true);
-
-    return toggledEscapedString;
-}
-
-QString ensuredCharEscaped(const QString &originalString, QChar charToEscape)
-{
-    QString escapedString = originalString;
-    for (int i = 0; i < escapedString.length(); i++) {
-        if (escapedString[i] == charToEscape && !isCharEscaped(escapedString, i)) {
-            escapedString.replace(i, 1, QLatin1String("\\") + charToEscape);
-        }
-    }
-    return escapedString;
-}
-
-QString vimRegexToQtRegexPattern(const QString &vimRegexPattern)
-{
-    QString qtRegexPattern = vimRegexPattern;
-    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('('));
-    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char(')'));
-    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('+'));
-    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('|'));
-    qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char('?'));
-    {
-        // All curly brackets, except the closing curly bracket of a matching pair \
                where the opening bracket is escaped,
-        // must have their escaping toggled.
-        bool lookingForMatchingCloseBracket = false;
-        QList<int> matchingClosedCurlyBracketPositions;
-        for (int i = 0; i < qtRegexPattern.length(); i++) {
-            if (qtRegexPattern[i] == QLatin1Char('{') && \
                isCharEscaped(qtRegexPattern, i)) {
-                lookingForMatchingCloseBracket = true;
-            }
-            if (qtRegexPattern[i] == QLatin1Char('}') && \
                lookingForMatchingCloseBracket && qtRegexPattern[i - 1] != \
                QLatin1Char('\\')) {
-                matchingClosedCurlyBracketPositions.append(i);
-            }
-        }
-        if (matchingClosedCurlyBracketPositions.isEmpty()) {
-            // Escape all {'s and }'s - there are no matching pairs.
-            qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('{'));
-            qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('}'));
-        } else {
-            // Ensure that every chunk of qtRegexPattern that does *not* contain a \
                curly closing bracket
-            // that is matched have their { and } escaping toggled.
-            QString qtRegexPatternNonMatchingCurliesToggled;
-            int previousNonMatchingClosedCurlyPos = 0; // i.e. the position of the \
                last character which is either
-            // not a curly closing bracket, or is a curly closing bracket
-            // that is not matched.
-            foreach (int matchingClosedCurlyPos, \
                matchingClosedCurlyBracketPositions) {
-                QString chunkExcludingMatchingCurlyClosed = \
qtRegexPattern.mid(previousNonMatchingClosedCurlyPos, matchingClosedCurlyPos - \
                previousNonMatchingClosedCurlyPos);
-                chunkExcludingMatchingCurlyClosed = \
                toggledEscaped(chunkExcludingMatchingCurlyClosed, QLatin1Char('{'));
-                chunkExcludingMatchingCurlyClosed = \
                toggledEscaped(chunkExcludingMatchingCurlyClosed, QLatin1Char('}'));
-                qtRegexPatternNonMatchingCurliesToggled += \
                chunkExcludingMatchingCurlyClosed +
-                        qtRegexPattern[matchingClosedCurlyPos];
-                previousNonMatchingClosedCurlyPos = matchingClosedCurlyPos + 1;
-            }
-            QString chunkAfterLastMatchingClosedCurly = \
                qtRegexPattern.mid(matchingClosedCurlyBracketPositions.last() + 1);
-            chunkAfterLastMatchingClosedCurly = \
                toggledEscaped(chunkAfterLastMatchingClosedCurly, QLatin1Char('{'));
-            chunkAfterLastMatchingClosedCurly = \
                toggledEscaped(chunkAfterLastMatchingClosedCurly, QLatin1Char('}'));
-            qtRegexPatternNonMatchingCurliesToggled += \
                chunkAfterLastMatchingClosedCurly;
-
-            qtRegexPattern = qtRegexPatternNonMatchingCurliesToggled;
-        }
-
-    }
-
-    // All square brackets, *except* for those that are a) unescaped; and b) form a \
                matching pair, must be
-    // escaped.
-    bool lookingForMatchingCloseBracket = false;
-    int openingBracketPos = -1;
-    QList<int> matchingSquareBracketPositions;
-    for (int i = 0; i < qtRegexPattern.length(); i++) {
-        if (qtRegexPattern[i] == QLatin1Char('[') && !isCharEscaped(qtRegexPattern, \
                i) && !lookingForMatchingCloseBracket) {
-            lookingForMatchingCloseBracket = true;
-            openingBracketPos = i;
-        }
-        if (qtRegexPattern[i] == QLatin1Char(']') && lookingForMatchingCloseBracket \
                && !isCharEscaped(qtRegexPattern, i)) {
-            lookingForMatchingCloseBracket = false;
-            matchingSquareBracketPositions.append(openingBracketPos);
-            matchingSquareBracketPositions.append(i);
-        }
-    }
-
-    if (matchingSquareBracketPositions.isEmpty()) {
-        // Escape all ['s and ]'s - there are no matching pairs.
-        qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char('['));
-        qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char(']'));
-    } else {
-        // Ensure that every chunk of qtRegexPattern that does *not* contain one of \
                the matching pairs of
-        // square brackets have their square brackets escaped.
-        QString qtRegexPatternNonMatchingSquaresMadeLiteral;
-        int previousNonMatchingSquareBracketPos = 0; // i.e. the position of the \
                last character which is
-        // either not a square bracket, or is a square bracket but
-        // which is not matched.
-        foreach (int matchingSquareBracketPos, matchingSquareBracketPositions) {
-            QString chunkExcludingMatchingSquareBrackets = \
qtRegexPattern.mid(previousNonMatchingSquareBracketPos, matchingSquareBracketPos - \
                previousNonMatchingSquareBracketPos);
-            chunkExcludingMatchingSquareBrackets = \
                ensuredCharEscaped(chunkExcludingMatchingSquareBrackets, \
                QLatin1Char('['));
-            chunkExcludingMatchingSquareBrackets = \
                ensuredCharEscaped(chunkExcludingMatchingSquareBrackets, \
                QLatin1Char(']'));
-            qtRegexPatternNonMatchingSquaresMadeLiteral += \
                chunkExcludingMatchingSquareBrackets + \
                qtRegexPattern[matchingSquareBracketPos];
-            previousNonMatchingSquareBracketPos = matchingSquareBracketPos + 1;
-        }
-        QString chunkAfterLastMatchingSquareBracket = \
                qtRegexPattern.mid(matchingSquareBracketPositions.last() + 1);
-        chunkAfterLastMatchingSquareBracket = \
                ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, \
                QLatin1Char('['));
-        chunkAfterLastMatchingSquareBracket = \
                ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, \
                QLatin1Char(']'));
-        qtRegexPatternNonMatchingSquaresMadeLiteral += \
                chunkAfterLastMatchingSquareBracket;
-
-        qtRegexPattern = qtRegexPatternNonMatchingSquaresMadeLiteral;
-    }
-
-    qtRegexPattern = qtRegexPattern.replace(QLatin1String("\\>"), \
                QLatin1String("\\b"));
-    qtRegexPattern = qtRegexPattern.replace(QLatin1String("\\<"), \
                QLatin1String("\\b"));
-
-    return qtRegexPattern;
-}
-
 /**
  * @return \a originalRegex but escaped in such a way that a Qt regex search for
  * the resulting string will match the string \a originalRegex.
@@ -221,73 +74,6 @@ QString escapedForSearchingAsLiteral(const QString \
                &originalQtRegex)
     escapedForSearchingAsLiteral.replace(QLatin1Char('\n'), QLatin1String("\\n"));
     return escapedForSearchingAsLiteral;
 }
-
-QStringList reversed(const QStringList &originalList)
-{
-    QStringList reversedList = originalList;
-    std::reverse(reversedList.begin(), reversedList.end());
-    return reversedList;
-}
-
-QString withCaseSensitivityMarkersStripped(const QString &originalSearchTerm)
-{
-    // Only \C is handled, for now - I'll implement \c if someone asks for it.
-    int pos = 0;
-    QString caseSensitivityMarkersStripped = originalSearchTerm;
-    while (pos < caseSensitivityMarkersStripped.length()) {
-        if (caseSensitivityMarkersStripped.at(pos) == QLatin1Char('C') && \
                isCharEscaped(caseSensitivityMarkersStripped, pos)) {
-            caseSensitivityMarkersStripped.replace(pos - 1, 2, QString());
-            pos--;
-        }
-        pos++;
-    }
-    return caseSensitivityMarkersStripped;
-}
-
-int findPosOfSearchConfigMarker(const QString &searchText, const bool \
                isSearchBackwards)
-{
-    const QChar searchConfigMarkerChar = (isSearchBackwards ? QLatin1Char('?') : \
                QLatin1Char('/'));
-    for (int pos = 0; pos < searchText.length(); pos++) {
-        if (searchText.at(pos) == searchConfigMarkerChar) {
-            if (!isCharEscaped(searchText, pos)) {
-                return pos;
-            }
-        }
-    }
-    return -1;
-}
-
-bool isRepeatLastSearch(const QString &searchText, const bool isSearchBackwards)
-{
-    const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, \
                isSearchBackwards);
-    if (posOfSearchConfigMarker != -1) {
-        if (searchText.leftRef(posOfSearchConfigMarker).isEmpty()) {
-            return true;
-        }
-    }
-    return false;
-}
-
-bool shouldPlaceCursorAtEndOfMatch(const QString &searchText, const bool \
                isSearchBackwards)
-{
-    const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, \
                isSearchBackwards);
-    if (posOfSearchConfigMarker != -1) {
-        if (searchText.length() > posOfSearchConfigMarker + 1 && \
                searchText.at(posOfSearchConfigMarker + 1) == QLatin1Char('e')) {
-            return true;
-        }
-    }
-    return false;
-}
-
-QString withSearchConfigRemoved(const QString &originalSearchText, const bool \
                isSearchBackwards)
-{
-    const int posOfSearchConfigMarker = \
                findPosOfSearchConfigMarker(originalSearchText, isSearchBackwards);
-    if (posOfSearchConfigMarker == -1) {
-        return originalSearchText;
-    } else {
-        return originalSearchText.left(posOfSearchConfigMarker);
-    }
-}
 }
 
 EmulatedCommandBar::EmulatedCommandBar(InputModeManager *viInputModeManager, QWidget \
*parent) @@ -649,147 +435,6 @@ void EmulatedCommandBar::hideAllWidgetsExcept(QWidget* \
widgetToKeepVisible)  
 }
 
-EmulatedCommandBar::SearchMode::SearchMode(EmulatedCommandBar* emulatedCommandBar, \
                MatchHighlighter* matchHighlighter, KTextEditor::ViewPrivate* view, \
                QLineEdit* edit)
-    : ActiveMode ( emulatedCommandBar, matchHighlighter),
-      m_emulatedCommandBar(emulatedCommandBar),
-      m_view(view),
-      m_edit(edit)
-{
-}
-
-void EmulatedCommandBar::SearchMode::init ( \
                EmulatedCommandBar::SearchMode::SearchDirection searchDirection)
-{
-    m_searchDirection = searchDirection;
-    m_startingCursorPos = m_view->cursorPosition();
-}
-
-void EmulatedCommandBar::SearchMode::setViInputModeManager ( InputModeManager* \
                viInputModeManager )
-{
-    m_viInputModeManager = viInputModeManager;
-}
-
-bool EmulatedCommandBar::SearchMode::handleKeyPress ( const QKeyEvent* keyEvent )
-{
-    Q_UNUSED(keyEvent);
-    return false;
-}
-
-void EmulatedCommandBar::SearchMode::editTextChanged ( const QString& newText )
-{
-    QString qtRegexPattern = newText;
-    const bool searchBackwards = (m_searchDirection == SearchDirection::Backward);
-    const bool placeCursorAtEndOfMatch = \
                shouldPlaceCursorAtEndOfMatch(qtRegexPattern, searchBackwards);
-    if (isRepeatLastSearch(qtRegexPattern, searchBackwards)) {
-        qtRegexPattern = m_viInputModeManager->searcher()->getLastSearchPattern();
-    } else {
-        qtRegexPattern = withSearchConfigRemoved(qtRegexPattern, searchBackwards);
-        qtRegexPattern = vimRegexToQtRegexPattern(qtRegexPattern);
-    }
-
-    // Decide case-sensitivity via SmartCase (note: if the expression contains \C, \
                the "case-sensitive" marker, then
-    // we will be case-sensitive "by coincidence", as it were.).
-    bool caseSensitive = true;
-    if (qtRegexPattern.toLower() == qtRegexPattern) {
-        caseSensitive = false;
-    }
-
-    qtRegexPattern = withCaseSensitivityMarkersStripped(qtRegexPattern);
-
-    m_currentSearchParams.pattern = qtRegexPattern;
-    m_currentSearchParams.isCaseSensitive = caseSensitive;
-    m_currentSearchParams.isBackwards = searchBackwards;
-    m_currentSearchParams.shouldPlaceCursorAtEndOfMatch = placeCursorAtEndOfMatch;
-
-    // The "count" for the current search is not shared between Visual & Normal \
                mode, so we need to pick
-    // the right one to handle the counted search.
-    int c = m_viInputModeManager->getCurrentViModeHandler()->getCount();
-    KTextEditor::Range match = \
m_viInputModeManager->searcher()->findPattern(m_currentSearchParams, \
m_startingCursorPos, c, false /* Don't add incremental searches to search history \
                */);
-
-    if (match.isValid()) {
-        // The returned range ends one past the last character of the match, so \
                adjust.
-        KTextEditor::Cursor realMatchEnd = KTextEditor::Cursor(match.end().line(), \
                match.end().column() - 1);
-        if (realMatchEnd.column() == -1) {
-            realMatchEnd = KTextEditor::Cursor(realMatchEnd.line() - 1, \
                m_view->doc()->lineLength(realMatchEnd.line() - 1));
-        }
-        moveCursorTo(placeCursorAtEndOfMatch ? realMatchEnd :  match.start());
-        setBarBackground(SearchMode::MatchFound);
-    } else {
-        moveCursorTo(m_startingCursorPos);
-        if (!m_edit->text().isEmpty()) {
-            setBarBackground(SearchMode::NoMatchFound);
-        } else {
-            setBarBackground(SearchMode::Normal);
-        }
-    }
-
-    updateMatchHighlight(match);
-}
-
-void EmulatedCommandBar::SearchMode::deactivate(bool wasAborted)
-{
-    // "Deactivate" can be called multiple times between init()'s, so only reset the \
                cursor once!
-    if (m_startingCursorPos.isValid()) {
-        if (wasAborted) {
-            moveCursorTo(m_startingCursorPos);
-        }
-    }
-    m_startingCursorPos = KTextEditor::Cursor::invalid();
-    setBarBackground(SearchMode::Normal);
-    // Send a synthetic keypress through the system that signals whether the search \
                was aborted or
-    // not.  If not, the keypress will "complete" the search motion, thus triggering \
                it.
-    // We send to KateViewInternal as it updates the status bar and removes the "?".
-    const Qt::Key syntheticSearchCompletedKey = (wasAborted ? \
                static_cast<Qt::Key>(0) : Qt::Key_Enter);
-    QKeyEvent syntheticSearchCompletedKeyPress(QEvent::KeyPress, \
                syntheticSearchCompletedKey, Qt::NoModifier);
-    m_isSendingSyntheticSearchCompletedKeypress = true;
-    QApplication::sendEvent(m_view->focusProxy(), \
                &syntheticSearchCompletedKeyPress);
-    m_isSendingSyntheticSearchCompletedKeypress = false;
-    if (!wasAborted) {
-        // Search was actually executed, so store it as the last search.
-        m_viInputModeManager->searcher()->setLastSearchParams(m_currentSearchParams);
                
-    }
-    // Append the raw text of the search to the search history (i.e. without \
                conversion
-    // from Vim-style regex; without case-sensitivity markers stripped; etc.
-    // Vim does this even if the search was aborted, so we follow suit.
-    m_viInputModeManager->globalState()->searchHistory()->append(m_edit->text());
-}
-
-CompletionStartParams EmulatedCommandBar::SearchMode::completionInvoked ( \
                Completer::CompletionInvocation invocationType )
-{
-    Q_UNUSED(invocationType);
-    return activateSearchHistoryCompletion();
-}
-
-void EmulatedCommandBar::SearchMode::completionChosen()
-{
-    // Choose completion with Enter/ Return -> close bar (the search will have \
                already taken effect at this point), marking as not aborted .
-    close(false);
-}
-
-CompletionStartParams \
                EmulatedCommandBar::SearchMode::activateSearchHistoryCompletion()
-{
-    return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->searchHistory()->items()), \
                0);
-}
-
-void EmulatedCommandBar::SearchMode::setBarBackground ( \
                EmulatedCommandBar::SearchMode::BarBackgroundStatus status )
-{
-    QPalette barBackground(m_edit->palette());
-    switch (status) {
-    case MatchFound: {
-        KColorScheme::adjustBackground(barBackground, \
                KColorScheme::PositiveBackground);
-        break;
-    }
-    case NoMatchFound: {
-        KColorScheme::adjustBackground(barBackground, \
                KColorScheme::NegativeBackground);
-        break;
-    }
-    case Normal: {
-        barBackground = QPalette();
-        break;
-    }
-    }
-    m_edit->setPalette(barBackground);
-}
-
 EmulatedCommandBar::CommandMode::CommandMode ( EmulatedCommandBar* \
emulatedCommandBar, MatchHighlighter* matchHighlighter, KTextEditor::ViewPrivate* \
view,  QLineEdit* edit, InteractiveSedReplaceMode *interactiveSedReplaceMode, \
Completer* completer)  : ActiveMode ( emulatedCommandBar, matchHighlighter ),
       m_edit(edit),
diff --git a/src/vimode/emulatedcommandbar/emulatedcommandbar.h \
b/src/vimode/emulatedcommandbar/emulatedcommandbar.h index 736a6dc..3831f0b 100644
--- a/src/vimode/emulatedcommandbar/emulatedcommandbar.h
+++ b/src/vimode/emulatedcommandbar/emulatedcommandbar.h
@@ -40,6 +40,7 @@ namespace KateVi
 {
 class MatchHighlighter;
 class InteractiveSedReplaceMode;
+class SearchMode;
 
 /**
  * A KateViewBarWidget that attempts to emulate some of the features of Vim's own \
command bar, @@ -87,39 +88,6 @@ private:
     QScopedPointer<MatchHighlighter> m_matchHighligher;
     QScopedPointer<Completer> m_completer;
 
-    class SearchMode : public ActiveMode
-    {
-    public:
-        SearchMode(EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
                matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit);
-        virtual ~SearchMode()
-        {
-        };
-        enum class SearchDirection { Forward, Backward };
-        void init(SearchDirection);
-        void setViInputModeManager(InputModeManager *viInputModeManager);
-        virtual bool handleKeyPress ( const QKeyEvent* keyEvent );
-        virtual void editTextChanged(const QString &newText);
-        virtual CompletionStartParams \
                completionInvoked(Completer::CompletionInvocation invocationType);
-        virtual void completionChosen();
-        virtual void deactivate(bool wasAborted);
-        bool isSendingSyntheticSearchCompletedKeypress() const
-        {
-            return m_isSendingSyntheticSearchCompletedKeypress;
-        }
-    private:
-        EmulatedCommandBar *m_emulatedCommandBar = nullptr;
-        KTextEditor::ViewPrivate *m_view = nullptr;
-        InputModeManager *m_viInputModeManager = nullptr;
-        QLineEdit *m_edit = nullptr;
-        SearchDirection m_searchDirection;
-        KTextEditor::Cursor m_startingCursorPos;
-        KateVi::Searcher::SearchParams m_currentSearchParams;
-        CompletionStartParams activateSearchHistoryCompletion();
-        enum BarBackgroundStatus { Normal, MatchFound, NoMatchFound };
-        void setBarBackground(BarBackgroundStatus status);
-        bool m_isSendingSyntheticSearchCompletedKeypress = false;
-    };
-
     class CommandMode : public ActiveMode
     {
     public:
diff --git a/src/vimode/emulatedcommandbar/searchmode.cpp \
b/src/vimode/emulatedcommandbar/searchmode.cpp new file mode 100644
index 0000000..20c0128
--- /dev/null
+++ b/src/vimode/emulatedcommandbar/searchmode.cpp
@@ -0,0 +1,373 @@
+#include "searchmode.h"
+
+#include <vimode/inputmodemanager.h>
+#include <vimode/modes/modebase.h>
+#include "../globalstate.h"
+#include "../history.h"
+#include "kateview.h"
+#include "katedocument.h"
+
+#include <KColorScheme>
+
+#include <QLineEdit>
+#include <QApplication>
+
+using namespace KateVi;
+
+namespace
+{
+    bool isCharEscaped(const QString &string, int charPos)
+    {
+        if (charPos == 0) {
+            return false;
+        }
+        int numContiguousBackslashesToLeft = 0;
+        charPos--;
+        while (charPos >= 0 && string[charPos] == QLatin1Char('\\')) {
+            numContiguousBackslashesToLeft++;
+            charPos--;
+        }
+        return ((numContiguousBackslashesToLeft % 2) == 1);
+    }
+
+    QString toggledEscaped(const QString &originalString, QChar escapeChar)
+    {
+        int searchFrom = 0;
+        QString toggledEscapedString = originalString;
+        do {
+            const int indexOfEscapeChar = toggledEscapedString.indexOf(escapeChar, \
searchFrom); +            if (indexOfEscapeChar == -1) {
+                break;
+            }
+            if (!isCharEscaped(toggledEscapedString, indexOfEscapeChar)) {
+                // Escape.
+                toggledEscapedString.replace(indexOfEscapeChar, 1, \
QLatin1String("\\") + escapeChar); +                searchFrom = indexOfEscapeChar + \
2; +            } else {
+                // Unescape.
+                toggledEscapedString.remove(indexOfEscapeChar - 1, 1);
+                searchFrom = indexOfEscapeChar;
+            }
+        } while (true);
+
+        return toggledEscapedString;
+    }
+
+    int findPosOfSearchConfigMarker(const QString &searchText, const bool \
isSearchBackwards) +    {
+        const QChar searchConfigMarkerChar = (isSearchBackwards ? QLatin1Char('?') : \
QLatin1Char('/')); +        for (int pos = 0; pos < searchText.length(); pos++) {
+            if (searchText.at(pos) == searchConfigMarkerChar) {
+                if (!isCharEscaped(searchText, pos)) {
+                    return pos;
+                }
+            }
+        }
+        return -1;
+    }
+
+    bool isRepeatLastSearch(const QString &searchText, const bool isSearchBackwards)
+    {
+        const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, \
isSearchBackwards); +        if (posOfSearchConfigMarker != -1) {
+            if (searchText.leftRef(posOfSearchConfigMarker).isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    bool shouldPlaceCursorAtEndOfMatch(const QString &searchText, const bool \
isSearchBackwards) +    {
+        const int posOfSearchConfigMarker = findPosOfSearchConfigMarker(searchText, \
isSearchBackwards); +        if (posOfSearchConfigMarker != -1) {
+            if (searchText.length() > posOfSearchConfigMarker + 1 && \
searchText.at(posOfSearchConfigMarker + 1) == QLatin1Char('e')) { +                \
return true; +            }
+        }
+        return false;
+    }
+
+    QString withSearchConfigRemoved(const QString &originalSearchText, const bool \
isSearchBackwards) +    {
+        const int posOfSearchConfigMarker = \
findPosOfSearchConfigMarker(originalSearchText, isSearchBackwards); +        if \
(posOfSearchConfigMarker == -1) { +            return originalSearchText;
+        } else {
+            return originalSearchText.left(posOfSearchConfigMarker);
+        }
+    }
+}
+
+QString KateVi::vimRegexToQtRegexPattern(const QString &vimRegexPattern)
+{
+    QString qtRegexPattern = vimRegexPattern;
+    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('('));
+    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char(')'));
+    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('+'));
+    qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('|'));
+    qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char('?'));
+    {
+        // All curly brackets, except the closing curly bracket of a matching pair \
where the opening bracket is escaped, +        // must have their escaping toggled.
+        bool lookingForMatchingCloseBracket = false;
+        QList<int> matchingClosedCurlyBracketPositions;
+        for (int i = 0; i < qtRegexPattern.length(); i++) {
+            if (qtRegexPattern[i] == QLatin1Char('{') && \
isCharEscaped(qtRegexPattern, i)) { +                lookingForMatchingCloseBracket = \
true; +            }
+            if (qtRegexPattern[i] == QLatin1Char('}') && \
lookingForMatchingCloseBracket && qtRegexPattern[i - 1] != QLatin1Char('\\')) { +     \
matchingClosedCurlyBracketPositions.append(i); +            }
+        }
+        if (matchingClosedCurlyBracketPositions.isEmpty()) {
+            // Escape all {'s and }'s - there are no matching pairs.
+            qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('{'));
+            qtRegexPattern = toggledEscaped(qtRegexPattern, QLatin1Char('}'));
+        } else {
+            // Ensure that every chunk of qtRegexPattern that does *not* contain a \
curly closing bracket +            // that is matched have their { and } escaping \
toggled. +            QString qtRegexPatternNonMatchingCurliesToggled;
+            int previousNonMatchingClosedCurlyPos = 0; // i.e. the position of the \
last character which is either +            // not a curly closing bracket, or is a \
curly closing bracket +            // that is not matched.
+            foreach (int matchingClosedCurlyPos, \
matchingClosedCurlyBracketPositions) { +                QString \
chunkExcludingMatchingCurlyClosed = \
qtRegexPattern.mid(previousNonMatchingClosedCurlyPos, matchingClosedCurlyPos - \
previousNonMatchingClosedCurlyPos); +                \
chunkExcludingMatchingCurlyClosed = toggledEscaped(chunkExcludingMatchingCurlyClosed, \
QLatin1Char('{')); +                chunkExcludingMatchingCurlyClosed = \
toggledEscaped(chunkExcludingMatchingCurlyClosed, QLatin1Char('}')); +                \
qtRegexPatternNonMatchingCurliesToggled += chunkExcludingMatchingCurlyClosed + +      \
qtRegexPattern[matchingClosedCurlyPos]; +                \
previousNonMatchingClosedCurlyPos = matchingClosedCurlyPos + 1; +            }
+            QString chunkAfterLastMatchingClosedCurly = \
qtRegexPattern.mid(matchingClosedCurlyBracketPositions.last() + 1); +            \
chunkAfterLastMatchingClosedCurly = toggledEscaped(chunkAfterLastMatchingClosedCurly, \
QLatin1Char('{')); +            chunkAfterLastMatchingClosedCurly = \
toggledEscaped(chunkAfterLastMatchingClosedCurly, QLatin1Char('}')); +            \
qtRegexPatternNonMatchingCurliesToggled += chunkAfterLastMatchingClosedCurly; +
+            qtRegexPattern = qtRegexPatternNonMatchingCurliesToggled;
+        }
+
+    }
+
+    // All square brackets, *except* for those that are a) unescaped; and b) form a \
matching pair, must be +    // escaped.
+    bool lookingForMatchingCloseBracket = false;
+    int openingBracketPos = -1;
+    QList<int> matchingSquareBracketPositions;
+    for (int i = 0; i < qtRegexPattern.length(); i++) {
+        if (qtRegexPattern[i] == QLatin1Char('[') && !isCharEscaped(qtRegexPattern, \
i) && !lookingForMatchingCloseBracket) { +            lookingForMatchingCloseBracket \
= true; +            openingBracketPos = i;
+        }
+        if (qtRegexPattern[i] == QLatin1Char(']') && lookingForMatchingCloseBracket \
&& !isCharEscaped(qtRegexPattern, i)) { +            lookingForMatchingCloseBracket = \
false; +            matchingSquareBracketPositions.append(openingBracketPos);
+            matchingSquareBracketPositions.append(i);
+        }
+    }
+
+    if (matchingSquareBracketPositions.isEmpty()) {
+        // Escape all ['s and ]'s - there are no matching pairs.
+        qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char('['));
+        qtRegexPattern = ensuredCharEscaped(qtRegexPattern, QLatin1Char(']'));
+    } else {
+        // Ensure that every chunk of qtRegexPattern that does *not* contain one of \
the matching pairs of +        // square brackets have their square brackets escaped.
+        QString qtRegexPatternNonMatchingSquaresMadeLiteral;
+        int previousNonMatchingSquareBracketPos = 0; // i.e. the position of the \
last character which is +        // either not a square bracket, or is a square \
bracket but +        // which is not matched.
+        foreach (int matchingSquareBracketPos, matchingSquareBracketPositions) {
+            QString chunkExcludingMatchingSquareBrackets = \
qtRegexPattern.mid(previousNonMatchingSquareBracketPos, matchingSquareBracketPos - \
previousNonMatchingSquareBracketPos); +            \
chunkExcludingMatchingSquareBrackets = \
ensuredCharEscaped(chunkExcludingMatchingSquareBrackets, QLatin1Char('[')); +         \
chunkExcludingMatchingSquareBrackets = \
ensuredCharEscaped(chunkExcludingMatchingSquareBrackets, QLatin1Char(']')); +         \
qtRegexPatternNonMatchingSquaresMadeLiteral += chunkExcludingMatchingSquareBrackets + \
qtRegexPattern[matchingSquareBracketPos]; +            \
previousNonMatchingSquareBracketPos = matchingSquareBracketPos + 1; +        }
+        QString chunkAfterLastMatchingSquareBracket = \
qtRegexPattern.mid(matchingSquareBracketPositions.last() + 1); +        \
chunkAfterLastMatchingSquareBracket = \
ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, QLatin1Char('[')); +        \
chunkAfterLastMatchingSquareBracket = \
ensuredCharEscaped(chunkAfterLastMatchingSquareBracket, QLatin1Char(']')); +        \
qtRegexPatternNonMatchingSquaresMadeLiteral += chunkAfterLastMatchingSquareBracket; +
+        qtRegexPattern = qtRegexPatternNonMatchingSquaresMadeLiteral;
+    }
+
+    qtRegexPattern = qtRegexPattern.replace(QLatin1String("\\>"), \
QLatin1String("\\b")); +    qtRegexPattern = \
qtRegexPattern.replace(QLatin1String("\\<"), QLatin1String("\\b")); +
+    return qtRegexPattern;
+}
+
+QString KateVi::ensuredCharEscaped(const QString &originalString, QChar \
charToEscape) +{
+    QString escapedString = originalString;
+    for (int i = 0; i < escapedString.length(); i++) {
+        if (escapedString[i] == charToEscape && !isCharEscaped(escapedString, i)) {
+            escapedString.replace(i, 1, QLatin1String("\\") + charToEscape);
+        }
+    }
+    return escapedString;
+}
+
+QString KateVi::withCaseSensitivityMarkersStripped(const QString \
&originalSearchTerm) +{
+    // Only \C is handled, for now - I'll implement \c if someone asks for it.
+    int pos = 0;
+    QString caseSensitivityMarkersStripped = originalSearchTerm;
+    while (pos < caseSensitivityMarkersStripped.length()) {
+        if (caseSensitivityMarkersStripped.at(pos) == QLatin1Char('C') && \
isCharEscaped(caseSensitivityMarkersStripped, pos)) { +            \
caseSensitivityMarkersStripped.replace(pos - 1, 2, QString()); +            pos--;
+        }
+        pos++;
+    }
+    return caseSensitivityMarkersStripped;
+}
+
+QStringList KateVi::reversed(const QStringList &originalList)
+{
+    QStringList reversedList = originalList;
+    std::reverse(reversedList.begin(), reversedList.end());
+    return reversedList;
+}
+
+SearchMode::SearchMode(EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit) +    : ActiveMode \
( emulatedCommandBar, matchHighlighter), +      \
m_emulatedCommandBar(emulatedCommandBar), +      m_view(view),
+      m_edit(edit)
+{
+}
+
+void SearchMode::init ( SearchMode::SearchDirection searchDirection)
+{
+    m_searchDirection = searchDirection;
+    m_startingCursorPos = m_view->cursorPosition();
+}
+
+void SearchMode::setViInputModeManager ( InputModeManager* viInputModeManager )
+{
+    m_viInputModeManager = viInputModeManager;
+}
+
+bool SearchMode::handleKeyPress ( const QKeyEvent* keyEvent )
+{
+    Q_UNUSED(keyEvent);
+    return false;
+}
+
+void SearchMode::editTextChanged ( const QString& newText )
+{
+    QString qtRegexPattern = newText;
+    const bool searchBackwards = (m_searchDirection == SearchDirection::Backward);
+    const bool placeCursorAtEndOfMatch = \
shouldPlaceCursorAtEndOfMatch(qtRegexPattern, searchBackwards); +    if \
(isRepeatLastSearch(qtRegexPattern, searchBackwards)) { +        qtRegexPattern = \
m_viInputModeManager->searcher()->getLastSearchPattern(); +    } else {
+        qtRegexPattern = withSearchConfigRemoved(qtRegexPattern, searchBackwards);
+        qtRegexPattern = vimRegexToQtRegexPattern(qtRegexPattern);
+    }
+
+    // Decide case-sensitivity via SmartCase (note: if the expression contains \C, \
the "case-sensitive" marker, then +    // we will be case-sensitive "by coincidence", \
as it were.). +    bool caseSensitive = true;
+    if (qtRegexPattern.toLower() == qtRegexPattern) {
+        caseSensitive = false;
+    }
+
+    qtRegexPattern = withCaseSensitivityMarkersStripped(qtRegexPattern);
+
+    m_currentSearchParams.pattern = qtRegexPattern;
+    m_currentSearchParams.isCaseSensitive = caseSensitive;
+    m_currentSearchParams.isBackwards = searchBackwards;
+    m_currentSearchParams.shouldPlaceCursorAtEndOfMatch = placeCursorAtEndOfMatch;
+
+    // The "count" for the current search is not shared between Visual & Normal \
mode, so we need to pick +    // the right one to handle the counted search.
+    int c = m_viInputModeManager->getCurrentViModeHandler()->getCount();
+    KTextEditor::Range match = \
m_viInputModeManager->searcher()->findPattern(m_currentSearchParams, \
m_startingCursorPos, c, false /* Don't add incremental searches to search history \
*/); +
+    if (match.isValid()) {
+        // The returned range ends one past the last character of the match, so \
adjust. +        KTextEditor::Cursor realMatchEnd = \
KTextEditor::Cursor(match.end().line(), match.end().column() - 1); +        if \
(realMatchEnd.column() == -1) { +            realMatchEnd = \
KTextEditor::Cursor(realMatchEnd.line() - 1, \
m_view->doc()->lineLength(realMatchEnd.line() - 1)); +        }
+        moveCursorTo(placeCursorAtEndOfMatch ? realMatchEnd :  match.start());
+        setBarBackground(SearchMode::MatchFound);
+    } else {
+        moveCursorTo(m_startingCursorPos);
+        if (!m_edit->text().isEmpty()) {
+            setBarBackground(SearchMode::NoMatchFound);
+        } else {
+            setBarBackground(SearchMode::Normal);
+        }
+    }
+
+    updateMatchHighlight(match);
+}
+
+void SearchMode::deactivate(bool wasAborted)
+{
+    // "Deactivate" can be called multiple times between init()'s, so only reset the \
cursor once! +    if (m_startingCursorPos.isValid()) {
+        if (wasAborted) {
+            moveCursorTo(m_startingCursorPos);
+        }
+    }
+    m_startingCursorPos = KTextEditor::Cursor::invalid();
+    setBarBackground(SearchMode::Normal);
+    // Send a synthetic keypress through the system that signals whether the search \
was aborted or +    // not.  If not, the keypress will "complete" the search motion, \
thus triggering it. +    // We send to KateViewInternal as it updates the status bar \
and removes the "?". +    const Qt::Key syntheticSearchCompletedKey = (wasAborted ? \
static_cast<Qt::Key>(0) : Qt::Key_Enter); +    QKeyEvent \
syntheticSearchCompletedKeyPress(QEvent::KeyPress, syntheticSearchCompletedKey, \
Qt::NoModifier); +    m_isSendingSyntheticSearchCompletedKeypress = true;
+    QApplication::sendEvent(m_view->focusProxy(), \
&syntheticSearchCompletedKeyPress); +    m_isSendingSyntheticSearchCompletedKeypress \
= false; +    if (!wasAborted) {
+        // Search was actually executed, so store it as the last search.
+        m_viInputModeManager->searcher()->setLastSearchParams(m_currentSearchParams);
 +    }
+    // Append the raw text of the search to the search history (i.e. without \
conversion +    // from Vim-style regex; without case-sensitivity markers stripped; \
etc. +    // Vim does this even if the search was aborted, so we follow suit.
+    m_viInputModeManager->globalState()->searchHistory()->append(m_edit->text());
+}
+
+CompletionStartParams SearchMode::completionInvoked ( \
Completer::CompletionInvocation invocationType ) +{
+    Q_UNUSED(invocationType);
+    return activateSearchHistoryCompletion();
+}
+
+void SearchMode::completionChosen()
+{
+    // Choose completion with Enter/ Return -> close bar (the search will have \
already taken effect at this point), marking as not aborted . +    close(false);
+}
+
+CompletionStartParams SearchMode::activateSearchHistoryCompletion()
+{
+    return CompletionStartParams::createModeSpecific(reversed(m_viInputModeManager->globalState()->searchHistory()->items()), \
0); +}
+
+void SearchMode::setBarBackground ( SearchMode::BarBackgroundStatus status )
+{
+    QPalette barBackground(m_edit->palette());
+    switch (status) {
+    case MatchFound: {
+        KColorScheme::adjustBackground(barBackground, \
KColorScheme::PositiveBackground); +        break;
+    }
+    case NoMatchFound: {
+        KColorScheme::adjustBackground(barBackground, \
KColorScheme::NegativeBackground); +        break;
+    }
+    case Normal: {
+        barBackground = QPalette();
+        break;
+    }
+    }
+    m_edit->setPalette(barBackground);
+}
diff --git a/src/vimode/emulatedcommandbar/searchmode.h \
b/src/vimode/emulatedcommandbar/searchmode.h new file mode 100644
index 0000000..f691536
--- /dev/null
+++ b/src/vimode/emulatedcommandbar/searchmode.h
@@ -0,0 +1,55 @@
+#ifndef KATEVI_EMULATED_COMMAND_BAR_SEARCHMODE_H
+#define KATEVI_EMULATED_COMMAND_BAR_SEARCHMODE_H
+
+#include "activemode.h"
+#include "../searcher.h"
+
+namespace KTextEditor {
+    class ViewPrivate;
+}
+
+#include <KTextEditor/Cursor>
+
+namespace KateVi
+{
+class EmulatedCommandBar;
+QString vimRegexToQtRegexPattern(const QString &vimRegexPattern); // TODO - move \
these generic helper functions into their own file? +QString \
withCaseSensitivityMarkersStripped(const QString &originalSearchTerm); +QString \
ensuredCharEscaped(const QString &originalString, QChar charToEscape); +QStringList \
reversed(const QStringList &originalList); +
+class SearchMode : public ActiveMode
+{
+public:
+    SearchMode(EmulatedCommandBar* emulatedCommandBar, MatchHighlighter* \
matchHighlighter, KTextEditor::ViewPrivate* view, QLineEdit* edit); +    virtual \
~SearchMode() +    {
+    };
+    enum class SearchDirection { Forward, Backward };
+    void init(SearchDirection);
+    void setViInputModeManager(InputModeManager *viInputModeManager);
+    virtual bool handleKeyPress ( const QKeyEvent* keyEvent );
+    virtual void editTextChanged(const QString &newText);
+    virtual CompletionStartParams completionInvoked(Completer::CompletionInvocation \
invocationType); +    virtual void completionChosen();
+    virtual void deactivate(bool wasAborted);
+    bool isSendingSyntheticSearchCompletedKeypress() const
+    {
+        return m_isSendingSyntheticSearchCompletedKeypress;
+    }
+private:
+    EmulatedCommandBar *m_emulatedCommandBar = nullptr;
+    KTextEditor::ViewPrivate *m_view = nullptr;
+    InputModeManager *m_viInputModeManager = nullptr;
+    QLineEdit *m_edit = nullptr;
+    SearchDirection m_searchDirection;
+    KTextEditor::Cursor m_startingCursorPos;
+    KateVi::Searcher::SearchParams m_currentSearchParams;
+    CompletionStartParams activateSearchHistoryCompletion();
+    enum BarBackgroundStatus { Normal, MatchFound, NoMatchFound };
+    void setBarBackground(BarBackgroundStatus status);
+    bool m_isSendingSyntheticSearchCompletedKeypress = false;
+};
+}
+
+#endif


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic