From 80bc682d2ebc12ae12f04479aa82de162bb6dd62 Mon Sep 17 00:00:00 2001
From: hjk <qtc-committer@nokia.com>
Date: Tue, 14 Sep 2010 14:04:13 +0200
Subject: [PATCH] fakevim: more selection refactoring

---
 src/plugins/fakevim/fakevimactions.cpp    |   7 -
 src/plugins/fakevim/fakevimactions.h      |   1 -
 src/plugins/fakevim/fakevimhandler.cpp    | 402 ++++++++++------------
 src/plugins/fakevim/fakevimoptions.ui     |  10 -
 src/plugins/fakevim/fakevimplugin.cpp     |   2 -
 src/plugins/texteditor/basetexteditor.cpp |   2 +-
 6 files changed, 181 insertions(+), 243 deletions(-)

diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp
index 49db4d3b016..a17fbe146c1 100644
--- a/src/plugins/fakevim/fakevimactions.cpp
+++ b/src/plugins/fakevim/fakevimactions.cpp
@@ -132,13 +132,6 @@ FakeVimSettings *theFakeVimSettings()
     item->setValue(false);
     instance->insertItem(ConfigReadVimRc, item);
 
-    item = new SavedAction(instance);
-    item->setValue(true);
-    item->setDefaultValue(true);
-    item->setSettingsKey(group, _("ExportSelection"));
-    item->setCheckable(true);
-    instance->insertItem(ConfigExportSelection, item);
-
     item = new SavedAction(instance);
     item->setValue(true);
     item->setDefaultValue(true);
diff --git a/src/plugins/fakevim/fakevimactions.h b/src/plugins/fakevim/fakevimactions.h
index 19284391ac5..3ff9c5c587b 100644
--- a/src/plugins/fakevim/fakevimactions.h
+++ b/src/plugins/fakevim/fakevimactions.h
@@ -43,7 +43,6 @@ enum FakeVimSettingsCode
 {
     ConfigUseFakeVim,
     ConfigReadVimRc,
-    ConfigExportSelection,
 
     ConfigStartOfLine,
     ConfigHlSearch,
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index acb8f954cf9..b952386ae57 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -52,8 +52,8 @@
 //   to the right of the QTextCursor's position().
 //
 //   A current "region of interest"
-//   spans between m_anchor (== anchor()), i.e. the character below anchor()), and
-//   m_position(). The character below position() is not included
+//   spans between anchor(), (i.e. the character below anchor()), and
+//   position(). The character below position() is not included
 //   if the last movement command was exclusive (MoveExclusive).
 //
 
@@ -582,9 +582,9 @@ private:
 
 
 #define WITH_CURSOR(s) do { \
-        QTextCursor tc = EDITOR(textCursor()); \
+        QTextCursor tc = cursor(); \
         s; \
-        EDITOR(setTextCursor(tc)); \
+        setCursor(tc); \
     } while (0)
 
 class FakeVimHandler::Private : public QObject
@@ -635,8 +635,8 @@ public:
     QTextBlock block() const { return cursor().block(); }
     int leftDist() const { return position() - block().position(); }
     int rightDist() const { return block().length() - leftDist() - 1; }
-    bool atEndOfLine() const
-        { return cursor().atBlockEnd() && block().length() > 1; }
+    bool atBlockEnd() const { return cursor().atBlockEnd(); }
+    bool atEndOfLine() const { return atBlockEnd() && block().length() > 1; }
 
     int lastPositionInDocument() const; // Returns last valid position in doc.
     int firstPositionInLine(int line) const; // 1 based line, 0 based pos
@@ -691,8 +691,23 @@ public:
     void moveBehindEndOfLine();
     void moveUp(int n = 1) { moveDown(-n); }
     void moveDown(int n = 1); // { m_tc.movePosition(Down, MoveAnchor, n); }
-    void moveRight(int n = 1) { WITH_CURSOR(tc.movePosition(Right, MoveAnchor, n)); }
-    void moveLeft(int n = 1) { WITH_CURSOR(tc.movePosition(Left, MoveAnchor, n)); }
+    void dump(const char *msg) const {
+        qDebug() << msg << "POS: " << anchor() << position()
+            << "EXT: " << m_oldExternalAnchor << m_oldExternalPosition
+            << "INT: " << m_oldInternalAnchor << m_oldInternalPosition
+            << "VISUAL: " << m_visualMode
+            << "MOVEMODE: " << currentMoveMode();
+    }
+    QTextCursor::MoveMode currentMoveMode() const
+        { return isVisualMode() ? KeepAnchor : MoveAnchor; }
+    void moveRight(int n = 1) {
+        //dump("RIGHT 1");
+        WITH_CURSOR(tc.movePosition(Right, currentMoveMode(), n));
+        //dump("RIGHT 2");
+    }
+    void moveLeft(int n = 1) {
+        WITH_CURSOR(tc.movePosition(Left, currentMoveMode(), n));
+    }
     void setAnchor() {
         WITH_CURSOR(
             int pos = tc.position();
@@ -700,25 +715,30 @@ public:
         );
     }
     void setAnchor(int position) {
+        //dump("BEGIN SET ANCHOR");
         WITH_CURSOR(
             tc.setPosition(tc.anchor(), MoveAnchor);
             tc.setPosition(position, KeepAnchor);
         );
+        //dump("END SET ANCHOR");
     }
     void setPosition(int position) {
         WITH_CURSOR(tc.setPosition(position, KeepAnchor));
     }
     void movePosition(int position) {
+        //dump("BEGIN MOVE POSITION");
         if (isVisualMode())
             setPosition(position);
         else
-            setPositionAndAnchor(position, position);
+            setAnchorAndPosition(position, position);
+        //dump("END MOVE POSITION");
     }
-    void setPositionAndAnchor(int position, int anchor) {
+    void setAnchorAndPosition(int anchor, int position) {
         WITH_CURSOR(
             tc.setPosition(anchor, MoveAnchor);
             tc.setPosition(position, KeepAnchor);
         );
+        //dump("SET A+P");
     }
     QTextCursor cursor() const { return EDITOR(textCursor()); }
     void setCursor(const QTextCursor &tc) { EDITOR(setTextCursor(tc)); }
@@ -783,7 +803,10 @@ public:
     SubMode m_submode;
     SubSubMode m_subsubmode;
     Input m_subsubdata;
-    int m_oldPosition; // copy from last event to check for external changes
+    int m_oldExternalPosition; // copy from last event to check for external changes
+    int m_oldExternalAnchor;
+    int m_oldInternalPosition; // copy from last event to check for external changes
+    int m_oldInternalAnchor;
     int m_register;
     QString m_mvcount;
     QString m_opcount;
@@ -792,7 +815,6 @@ public:
     int m_visualInsertCount;
 
     bool m_fakeEnd;
-    bool m_fakeBlock;
     bool m_anchorPastEnd;
     bool m_positionPastEnd; // '$' & 'l' in visual mode can move past eol
 
@@ -868,6 +890,7 @@ public:
     void enterVisualMode(VisualMode visualMode);
     void leaveVisualMode();
     VisualMode m_visualMode;
+    VisualMode m_oldVisualMode;
 
     // marks as lines
     int mark(int code) const;
@@ -964,7 +987,7 @@ FakeVimHandler::Private::Private(FakeVimHandler *parent, QWidget *widget)
     q = parent;
     m_textedit = qobject_cast<QTextEdit *>(widget);
     m_plaintextedit = qobject_cast<QPlainTextEdit *>(widget);
-    //new Highlighter(EDITOR(document()), &pythonRules);
+    //new Highlighter(document(), &pythonRules);
     init();
 }
 
@@ -976,12 +999,13 @@ void FakeVimHandler::Private::init()
     m_passing = false;
     m_findPending = false;
     m_fakeEnd = false;
-    m_fakeBlock = false;
-    m_positionPastEnd = m_anchorPastEnd = false;
+    m_positionPastEnd = false;
+    m_anchorPastEnd = false;
     m_lastSearchForward = true;
     m_register = '"';
     m_gflag = false;
     m_visualMode = NoVisualMode;
+    m_oldVisualMode = NoVisualMode;
     m_targetColumn = 0;
     m_visualTargetColumn = 0;
     m_movetype = MoveInclusive;
@@ -989,6 +1013,10 @@ void FakeVimHandler::Private::init()
     m_justAutoIndented = 0;
     m_rangemode = RangeCharMode;
     m_ctrlVActive = false;
+    m_oldInternalAnchor = -1;
+    m_oldInternalPosition = -1;
+    m_oldExternalAnchor = -1;
+    m_oldExternalPosition = -1;
 
     setupCharClass();
 }
@@ -1055,7 +1083,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     }
 
     // Fake "End of line"
-    //m_tc = EDITOR(textCursor());
+    //m_tc = cursor();
 
     //bool hasBlock = false;
     //emit q->requestHasBlockSelection(&hasBlock);
@@ -1067,8 +1095,10 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     importSelection();
 
     // Position changed externally
+/*
     if (position() != m_oldPosition) {
         setTargetColumn();
+        qDebug() << "POSITION CHANGED EXTERNALLY";
         if (m_mode == InsertMode) {
             int dist = position() - m_oldPosition;
             // Try to compensate for code completion
@@ -1081,13 +1111,11 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
                 moveLeft();
         }
     }
-
+*/
     WITH_CURSOR(tc.setVisualNavigation(true));
 
     if (m_fakeEnd)
         moveRight();
-    if (m_fakeBlock)
-        moveLeft();
 
     //if ((mods & Qt::ControlModifier) != 0) {
     //    if (key >= Key_A && key <= Key_Z)
@@ -1098,7 +1126,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     //}
 
     //QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
-    //        || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
+    //        || !atBlockEnd() || block().length() <= 1,
     //    qDebug() << "Cursor at EOL before key handler");
 
     EventResult result = handleKey(Input(key, mods, ev->text()));
@@ -1107,18 +1135,14 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
     if (m_textedit || m_plaintextedit) {
         // We fake vi-style end-of-line behaviour
         m_fakeEnd = atEndOfLine() && m_mode == CommandMode && !isVisualBlockMode();
-        m_fakeBlock = position() > anchor() && isVisualBlockMode();
 
         //QTC_ASSERT(m_mode == InsertMode || m_mode == ReplaceMode
-        //        || !m_tc.atBlockEnd() || m_tc.block().length() <= 1,
+        //        || !atBlockEnd() || block().length() <= 1,
         //    qDebug() << "Cursor at EOL after key handler");
         if (m_fakeEnd)
             moveLeft();
-        if (m_fakeBlock)
-            moveRight();
 
-        //EDITOR(setTextCursor(m_tc));
-        m_oldPosition = position();
+        //m_oldPosition = position();
     }
 
     if (hasConfig(ConfigShowMarks))
@@ -1153,72 +1177,75 @@ void FakeVimHandler::Private::setupWidget()
 
 void FakeVimHandler::Private::exportSelection()
 {
-    QTextCursor tc = EDITOR(textCursor());
-    int pos = position();
-    int anc = anchor();
-    qDebug() << "EXPORT: " << pos << anc << m_visualMode;
-
-#if 0
-
-    if (!hasConfig(ConfigExportSelection))
-        return;
-
-    // FIXME: That's hacky and does not work for block selections
-    // and the clipboard is not filled if the selections are updated
-    // using the keyboard.
-    QTextCursor tc = EDITOR(textCursor());
+    updateCursorShape();
     int pos = position();
     int anc = anchor();
-    if (m_visualMode == VisualBlockMode) {
-        //(pos > anc) ? ++pos : ++anc;
-        //if (anc > pos)
-        //    ++anc;
-        tc.setPosition(anc, MoveAnchor);
-        tc.setPosition(pos, KeepAnchor);
-        EDITOR(setTextCursor(tc));
-        emit q->requestSetBlockSelection(true);
-    } else if (m_visualMode == VisualLineMode) {
-        int posLine = lineForPosition(pos);
-        int ancLine = lineForPosition(anc);
-        if (anc < pos) {
-            pos = lastPositionInLine(posLine);
-            anc = firstPositionInLine(ancLine);
+    m_oldInternalPosition = pos;
+    m_oldInternalAnchor = anc;
+    if (isVisualMode()) {
+        if (pos >= anc)
+            setAnchorAndPosition(anc, pos + 1);
+        else
+            setAnchorAndPosition(anc + 1, pos);
+
+        if (m_visualMode == VisualBlockMode) {
+            emit q->requestSetBlockSelection(false);
+            emit q->requestSetBlockSelection(true);
+        } else if (m_visualMode == VisualLineMode) {
+            const int posLine = lineForPosition(pos);
+            const int ancLine = lineForPosition(anc);
+            if (anc < pos) {
+                pos = lastPositionInLine(posLine);
+                anc = firstPositionInLine(ancLine);
+            } else {
+                pos = firstPositionInLine(posLine);
+                anc = lastPositionInLine(ancLine);
+            }
+            setAnchorAndPosition(anc, pos);
+        } else if (m_visualMode == VisualCharMode) {
+            /* Nothing */
         } else {
-            pos = firstPositionInLine(posLine);
-            anc = lastPositionInLine(ancLine);
+            QTC_ASSERT(false, /**/);
         }
-        tc.setPosition(anc, MoveAnchor);
-        tc.setPosition(pos, KeepAnchor);
-        EDITOR(setTextCursor(tc));
-    } else if (m_visualMode == VisualCharMode) {
-        tc.setPosition(anc, MoveAnchor);
-        tc.setPosition(pos, KeepAnchor);
-        EDITOR(setTextCursor(tc));
+    } else {
+        setAnchorAndPosition(pos, pos);
     }
-#endif
+    m_oldExternalPosition = position();
+    m_oldExternalAnchor = anchor();
+    m_oldVisualMode = m_visualMode;
 }
 
 void FakeVimHandler::Private::importSelection()
 {
     bool hasBlock = false;
     emit q->requestHasBlockSelection(&hasBlock);
-    qDebug() << "IMPORT BLOCK 2:" << hasBlock;
-
-    QTextCursor tc = EDITOR(textCursor());
-    setMark('<', tc.anchor());
-    setMark('>', tc.position());
-    Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
-    if (!tc.hasSelection())
-        m_visualMode = NoVisualMode;
-    else if (mods & Qt::ControlModifier)
-        m_visualMode = VisualBlockMode;
-    else if (mods & Qt::AltModifier)
-        m_visualMode = VisualBlockMode;
-    else if (mods & Qt::ShiftModifier)
-        m_visualMode = VisualLineMode;
-    else
-        m_visualMode = VisualCharMode;
-    qDebug() << "IMPORT: " << hasBlock << m_visualMode;
+
+    if (position() == m_oldExternalPosition
+            && anchor() == m_oldExternalAnchor) {
+        // Undo drawing correction.
+        m_visualMode = m_oldVisualMode;
+        setAnchorAndPosition(m_oldInternalAnchor, m_oldInternalPosition);
+        //setMark('<', m_oldInternalAnchor);
+        //setMark('>', m_oldInternalPosition);
+    } else {
+        // Import new selection.
+        Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
+        if (cursor().hasSelection()) {
+            if (mods & Qt::ControlModifier)
+                m_visualMode = VisualBlockMode;
+            else if (mods & Qt::AltModifier)
+                m_visualMode = VisualBlockMode;
+            else if (mods & Qt::ShiftModifier)
+                m_visualMode = VisualLineMode;
+            else
+                m_visualMode = VisualCharMode;
+        } else {
+            m_visualMode = NoVisualMode;
+        }
+        //dump("IS @");
+        //setMark('<', tc.anchor());
+        //setMark('>', tc.position());
+    }
 }
 
 void FakeVimHandler::Private::updateEditor()
@@ -1236,17 +1263,6 @@ void FakeVimHandler::Private::restoreWidget(int tabSize)
     //EDITOR(setReadOnly(m_wasReadOnly));
     const int charWidth = QFontMetrics(EDITOR(font())).width(QChar(' '));
     EDITOR(setTabStopWidth(charWidth * tabSize));
-
-    if (isVisualLineMode()) {
-        const int beginLine = lineForPosition(mark('<'));
-        const int endLine = lineForPosition(mark('>'));
-        const int firstPos = firstPositionInLine(beginLine);
-        const int lastPos = lastPositionInLine(endLine);
-        setPositionAndAnchor(firstPos, lastPos);
-    } else if (isVisualCharMode() || isVisualBlockMode()) {
-        setPositionAndAnchor(mark('<'), mark('>'));
-    }
-
     m_visualMode = NoVisualMode;
     // Force "ordinary" cursor.
     m_mode = InsertMode;
@@ -1322,9 +1338,9 @@ void FakeVimHandler::Private::stopIncrementalFind()
 {
     if (m_findPending) {
         m_findPending = false;
-        QTextCursor tc = EDITOR(textCursor());
+        QTextCursor tc = cursor();
         tc.setPosition(tc.selectionStart());
-        EDITOR(setTextCursor(tc));
+        setCursor(tc);
     }
 }
 
@@ -1338,7 +1354,7 @@ void FakeVimHandler::Private::moveDown(int n)
 {
 #if 0
     // does not work for "hidden" documents like in the autotests
-    m_tc.movePosition(Down, MoveAnchor, n);
+    tc.movePosition(Down, MoveAnchor, n);
 #else
     const int col = position() - block().position();
     const int lastLine = document()->lastBlock().blockNumber();
@@ -1354,7 +1370,7 @@ void FakeVimHandler::Private::moveToEndOfLine()
 {
 #if 0
     // does not work for "hidden" documents like in the autotests
-    m_tc.movePosition(EndOfLine, MoveAnchor);
+    tc.movePosition(EndOfLine, MoveAnchor);
 #else
     const int pos = block().position() + block().length() - 2;
     setPosition(qMax(block().position(), pos));
@@ -1372,7 +1388,7 @@ void FakeVimHandler::Private::moveToStartOfLine()
 {
 #if 0
     // does not work for "hidden" documents like in the autotests
-    m_tc.movePosition(StartOfLine, MoveAnchor);
+    tc.movePosition(StartOfLine, MoveAnchor);
 #else
     setPosition(block().position());
 #endif
@@ -1385,7 +1401,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand, int coun
 
 void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
 {
-    //qDebug() << "ANCHOR: " << position() << anchor();
+    //dump("FINISH MOVEMENT");
     if (m_submode == FilterSubMode) {
         int beginLine = lineForPosition(anchor());
         int endLine = lineForPosition(position());
@@ -1399,15 +1415,17 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         return;
     }
 
-    if (isVisualMode())
-        setMark('>', position());
+    //if (isVisualMode())
+    //    setMark('>', position());
 
     if (m_submode == ChangeSubMode
         || m_submode == DeleteSubMode
         || m_submode == YankSubMode
         || m_submode == TransformSubMode) {
+
         if (m_submode != YankSubMode)
             beginEditBlock();
+
         if (m_movetype == MoveLineWise)
             m_rangemode = (m_submode == ChangeSubMode)
                 ? RangeLineModeExclusive
@@ -1416,21 +1434,21 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         if (m_movetype == MoveInclusive) {
             if (anchor() <= position()) {
                 if (!cursor().atBlockEnd())
-                    moveRight(); // correction
+                    setPosition(position() + 1); // correction
             } else {
-                qDebug() << "FIXME A";
-                //m_anchor++;
+                setAnchorAndPosition(anchor() + 1, position());
             }
         }
 
         if (m_positionPastEnd) {
+            const int anc = anchor();
             moveBehindEndOfLine();
             moveRight();
+            setAnchorAndPosition(anc, position());
         }
 
         if (m_anchorPastEnd) {
-            qDebug() << "FIXME B";
-            //m_anchor++;
+            setAnchorAndPosition(anchor() + 1, position());
         }
 
         if (m_submode != TransformSubMode) {
@@ -1543,61 +1561,6 @@ void FakeVimHandler::Private::updateSelection()
         sel.format.setBackground(Qt::black);
         selections.append(sel);
     }
-#if 0
-    if (isVisualMode()) {
-        QTextEdit::ExtraSelection sel;
-        sel.cursor = m_tc;
-        sel.format = m_tc.blockCharFormat();
-#if 0
-        sel.format.setFontWeight(QFont::Bold);
-        sel.format.setFontUnderline(true);
-#else
-        sel.format.setForeground(Qt::white);
-        sel.format.setBackground(Qt::black);
-#endif
-        const int cursorPos = m_tc.position();
-        const int anchorPos = mark('<');
-        //qDebug() << "POS: " << cursorPos << " ANCHOR: " << anchorPos;
-        if (isVisualCharMode()) {
-            sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor);
-            sel.cursor.setPosition(qMax(cursorPos, anchorPos) + 1, KeepAnchor);
-            selections.append(sel);
-        } else if (isVisualLineMode()) {
-            sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor);
-            sel.cursor.movePosition(StartOfLine, MoveAnchor);
-            sel.cursor.setPosition(qMax(cursorPos, anchorPos), KeepAnchor);
-            sel.cursor.movePosition(EndOfLine, KeepAnchor);
-            selections.append(sel);
-        } else if (isVisualBlockMode()) {
-            QTextCursor tc = m_tc;
-            tc.setPosition(anchorPos);
-            int anchorColumn = tc.positionInBlock();
-            int cursorColumn = m_tc.positionInBlock();
-            int anchorRow    = tc.blockNumber();
-            int cursorRow    = m_tc.blockNumber();
-            int startColumn  = qMin(anchorColumn, cursorColumn);
-            int endColumn    = qMax(anchorColumn, cursorColumn);
-            int diffRow      = cursorRow - anchorRow;
-            if (anchorRow > cursorRow) {
-                tc.setPosition(cursorPos);
-                diffRow = -diffRow;
-            }
-            tc.movePosition(StartOfLine, MoveAnchor);
-            for (int i = 0; i <= diffRow; ++i) {
-                if (startColumn < tc.block().length() - 1) {
-                    int last = qMin(tc.block().length(), endColumn + 1);
-                    int len = last - startColumn;
-                    sel.cursor = tc;
-                    sel.cursor.movePosition(Right, MoveAnchor, startColumn);
-                    sel.cursor.movePosition(Right, KeepAnchor, len);
-                    selections.append(sel);
-                }
-                tc.movePosition(Down, MoveAnchor, 1);
-            }
-        }
-    }
-#endif
-    //qDebug() << "SELECTION: " << selections;
     if (hasConfig(ConfigShowMarks)) {
         for (QHashIterator<int, int> it(m_marks); it.hasNext(); ) {
             it.next();
@@ -1611,6 +1574,7 @@ void FakeVimHandler::Private::updateSelection()
             selections.append(sel);
         }
     }
+    //qDebug() << "SELECTION: " << selections;
     emit q->selectionChanged(selections);
 }
 
@@ -2185,11 +2149,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is('D') && isNoVisualMode()) {
         if (atEndOfLine())
             moveLeft();
-        setAnchor();
         m_submode = DeleteSubMode;
+        const int anchor = position();
         moveDown(qMax(count() - 1, 0));
         m_movetype = MoveInclusive;
         moveToEndOfLine();
+        setAnchorAndPosition(anchor, position());
         setDotCommand(QString(QLatin1Char('D')));
         finishMovement();
     } else if ((input.is('D') || input.is('X')) &&
@@ -2265,7 +2230,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         setTargetColumn();
         finishMovement("%1h", count());
     } else if (input.is('H')) {
-        EDITOR(setTextCursor(EDITOR(cursorForPosition(QPoint(0, 0)))));
+        setCursor(EDITOR(cursorForPosition(QPoint(0, 0))));
         moveDown(qMax(count() - 1, 0));
         handleStartOfLine();
         finishMovement();
@@ -2304,7 +2269,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is('j') || input.isKey(Key_Down)
             || input.isControl('j') || input.isControl('n')) {
         m_movetype = MoveLineWise;
-        setAnchor();
         moveDown(count());
         finishMovement("%1j", count());
     } else if (input.is('J')) {
@@ -2313,16 +2277,16 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         if (m_submode == NoSubMode) {
             for (int i = qMax(count(), 2) - 1; --i >= 0; ) {
                 moveBehindEndOfLine();
-                setAnchor();
+                int anc = position();
                 moveRight();
                 if (m_gflag) {
-                    removeText(currentRange());
+                    removeText(Range(position(), anc));
                 } else {
                     while (characterAtCursor() == ' '
                         || characterAtCursor() == '\t')
                         moveRight();
-                    removeText(currentRange());
-                    WITH_CURSOR(insertText(QString(QLatin1Char(' '))));
+                    removeText(Range(position(), anc));
+                    cursor().insertText(QString(QLatin1Char(' ')));
                 }
             }
             if (!m_gflag)
@@ -2332,22 +2296,19 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         finishMovement();
     } else if (input.is('k') || input.isKey(Key_Up) || input.isControl('p')) {
         m_movetype = MoveLineWise;
-        setAnchor();
         moveUp(count());
         finishMovement("%1k", count());
     } else if (input.is('l') || input.isKey(Key_Right) || input.is(' ')) {
         m_movetype = MoveExclusive;
-        setAnchor();
         bool pastEnd = count() >= rightDist() - 1;
         moveRight(qMax(0, qMin(count(), rightDist() - (m_submode == NoSubMode))));
         setTargetColumn();
-        if (pastEnd && isVisualMode()) {
+        if (pastEnd && isVisualMode())
             m_visualTargetColumn = -1;
-        }
         finishMovement("%1l", count());
     } else if (input.is('L')) {
         QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()))));
-        EDITOR(setTextCursor(tc));
+        setCursor(tc);
         moveUp(qMax(count(), 1));
         handleStartOfLine();
         finishMovement();
@@ -2357,7 +2318,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         m_subsubmode = MarkSubSubMode;
     } else if (input.is('M')) {
         QTextCursor tc = EDITOR(cursorForPosition(QPoint(0, EDITOR(height()) / 2)));
-        EDITOR(setTextCursor(tc));
+        setCursor(tc);
         handleStartOfLine();
         finishMovement();
     } else if (input.is('n') || input.is('N')) {
@@ -2369,7 +2330,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         search(sd);
     } else if (isVisualMode() && (input.is('o') || input.is('O'))) {
         int pos = position();
-        setPositionAndAnchor(anchor(), pos);
+        setAnchorAndPosition(pos, anchor());
         std::swap(m_marks['<'], m_marks['>']);
         std::swap(m_positionPastEnd, m_anchorPastEnd);
         setTargetColumn();
@@ -2434,10 +2395,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         breakEditBlock();
         enterInsertMode();
     } else if (input.is('S')) {
+        beginEditBlock();
         if (!isVisualMode()) {
             const int line = cursorLine() + 1;
-            setAnchor(firstPositionInLine(line));
-            setPosition(lastPositionInLine(line + count() - 1));
+            const int anc = firstPositionInLine(line);
+            const int pos = lastPositionInLine(line + count() - 1);
+            setAnchorAndPosition(anc, pos);
         }
         setDotCommand("%1S", count());
         setUndoPosition(position());
@@ -2445,6 +2408,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         enterInsertMode();
         m_submode = ChangeSubMode;
         m_movetype = MoveLineWise;
+        endEditBlock();
         finishMovement();
     } else if (m_gflag && input.is('t')) {
         m_gflag = false;
@@ -2502,9 +2466,9 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
         m_submode = WindowSubMode;
     } else if (input.is('x') && isNoVisualMode()) { // = "dl"
         m_movetype = MoveExclusive;
-        setAnchor();
         m_submode = DeleteSubMode;
-        moveRight(qMin(count(), rightDist()));
+        const int n = qMin(count(), rightDist());
+        setAnchorAndPosition(position(), position() + n);
         setDotCommand("%1x", count());
         finishMovement();
     } else if (input.is('X')) {
@@ -3424,6 +3388,8 @@ bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
     int targetPosition = firstPositionInLine(lineForPosition(cmd.range.beginPos));
     QString command = QString(cmd.cmd.mid(1) + ' ' + cmd.args).trimmed();
     QString text = selectText(cmd.range);
+    qDebug() << "RANGE: " << cmd.range;
+    qDebug() << "TEXT: " << text;
     QProcess proc;
     proc.start(command);
     proc.waitForStarted();
@@ -3632,10 +3598,10 @@ void FakeVimHandler::Private::searchBalanced(bool forward, QChar needle, QChar o
             --level;
         if (level == 0) {
             const int oldLine = cursorLine() - cursorLineOnScreen();
-            setAnchor(pos);
-            //m_tc.setPosition(pos, MoveAnchor);
-            //m_tc.clearSelection();
-            //EDITOR(setTextCursor(m_tc));
+            QTextCursor tc = cursor();
+            tc.setPosition(pos, MoveAnchor);
+            tc.clearSelection();
+            setCursor(tc);
             // Making this unconditional feels better, but is not "vim like".
             if (oldLine != cursorLine() - cursorLineOnScreen())
                 scrollToLine(cursorLine() - linesOnScreen() / 2);
@@ -3688,23 +3654,17 @@ void FakeVimHandler::Private::search(const SearchData &sd)
         }
     }
 
-    EDITOR(setTextCursor(tc));
-    const int size = position() - anchor();
-    // Set Cursor.
-    //WITH_CURSOR(
-    //    tc.setPosition(qMin(tc.position(), tc.anchor()), MoveAnchor);
-    //    tc.clearSelection();
-    //);
+    // Set Cursor. In contrast to the main editor we have the cursor
+    // position befor the anchor position.
+    setAnchorAndPosition(tc.position(), tc.anchor());
 
     // Making this unconditional feels better, but is not "vim like".
     if (oldLine != cursorLine() - cursorLineOnScreen())
         scrollToLine(cursorLine() - linesOnScreen() / 2);
 
-    if (incSearch && sd.highlightCursor) {
+    if (incSearch && sd.highlightCursor)
         m_searchCursor = cursor();
-        m_searchCursor.setPosition(cursor().position(), MoveAnchor);
-        m_searchCursor.setPosition(cursor().position() + size, KeepAnchor);
-    }
+
     setTargetColumn();
 
     if (sd.highlightMatches)
@@ -3947,7 +3907,6 @@ void FakeVimHandler::Private::moveToWordBoundary(bool simple, bool forward, bool
     }
     while (repeat >= 0) {
         QChar c = doc->characterAt(position() + (forward ? 1 : -1));
-        //qDebug() << "EXAMINING: " << c << " AT " << position();
         int thisClass = charClass(c, simple);
         if (thisClass != lastClass && (lastClass != 0 || changeWord))
             --repeat;
@@ -3967,13 +3926,13 @@ void FakeVimHandler::Private::moveToWordBoundary(bool simple, bool forward, bool
 
 bool FakeVimHandler::Private::handleFfTt(QString key)
 {
-/*
     int key0 = key.size() == 1 ? key.at(0).unicode() : 0;
     int oldPos = position();
     // m_subsubmode \in { 'f', 'F', 't', 'T' }
     bool forward = m_subsubdata.is('f') || m_subsubdata.is('t');
     int repeat = count();
     QTextDocument *doc = document();
+    QTextCursor tc = cursor();
     QTextBlock block = this->block();
     int n = block.position();
     if (forward)
@@ -3995,12 +3954,13 @@ bool FakeVimHandler::Private::handleFfTt(QString key)
                 ++pos;
 
             if (forward)
-                m_tc.movePosition(Right, KeepAnchor, pos - m_tc.position());
+                tc.movePosition(Right, KeepAnchor, pos - tc.position());
             else
-                m_tc.movePosition(Left, KeepAnchor, m_tc.position() - pos);
+                tc.movePosition(Left, KeepAnchor, tc.position() - pos);
             break;
         }
     }
+    setCursor(tc);
     if (repeat == 0) {
         setTargetColumn();
         return true;
@@ -4008,13 +3968,11 @@ bool FakeVimHandler::Private::handleFfTt(QString key)
         setPosition(oldPos);
         return false;
     }
-*/
     return false;
 }
 
 void FakeVimHandler::Private::moveToNextWord(bool simple, bool deleteWord)
 {
-/*
     int repeat = count();
     int n = lastPositionInDocument();
     int lastClass = charClass(characterAtCursor(), simple);
@@ -4028,34 +3986,31 @@ void FakeVimHandler::Private::moveToNextWord(bool simple, bool deleteWord)
         lastClass = thisClass;
         moveRight();
         if (deleteWord) {
-            if (m_tc.atBlockEnd())
+            if (atBlockEnd())
                 --repeat;
         } else {
-            if (m_tc.block().length() == 1) // empty line
+            if (block().length() == 1) // empty line
                 --repeat;
         }
         if (repeat == 0)
             break;
-        if (m_tc.position() == n)
+        if (position() == n)
             break;
     }
     setTargetColumn();
-*/
 }
 
 void FakeVimHandler::Private::moveToMatchingParanthesis()
 {
-/*
     bool moved = false;
     bool forward = false;
 
-    emit q->moveToMatchingParenthesis(&moved, &forward, &m_tc);
-
-    if (moved && forward) {
-        m_tc.movePosition(Left, KeepAnchor, 1);
-    }
+    QTextCursor tc = cursor();
+    emit q->moveToMatchingParenthesis(&moved, &forward, &tc);
+    if (moved && forward)
+        tc.movePosition(Left, KeepAnchor, 1);
+    setCursor(tc);
     setTargetColumn();
-*/
 }
 
 int FakeVimHandler::Private::cursorLineOnScreen() const
@@ -4328,6 +4283,7 @@ void FakeVimHandler::Private::insertText(const Register &reg)
 
 void FakeVimHandler::Private::removeText(const Range &range)
 {
+    //qDebug() << "REMOVE: " << range;
     transformText(range, &FakeVimHandler::Private::removeTransform);
 }
 
@@ -4527,11 +4483,13 @@ int FakeVimHandler::Private::lineForPosition(int pos) const
 
 void FakeVimHandler::Private::enterVisualMode(VisualMode visualMode)
 {
-    setAnchor();
-    m_positionPastEnd = m_anchorPastEnd = false;
+    m_positionPastEnd = false;
+    m_anchorPastEnd = false;
     m_visualMode = visualMode;
-    setMark('<', position());
-    setMark('>', position());
+    const int pos = position();
+    //setMark('<', pos);
+    //setMark('>', pos + 1);
+    setAnchorAndPosition(pos, pos);
     updateMiniBuffer();
     updateSelection();
 }
@@ -4604,7 +4562,7 @@ void FakeVimHandler::Private::updateCursorShape()
     if (m_mode == ExMode || m_subsubmode == SearchSubSubMode) {
         EDITOR(setCursorWidth(0));
         EDITOR(setOverwriteMode(false));
-    } else if (m_mode == InsertMode) {
+    } else if (m_mode == InsertMode || isVisualMode()) {
         EDITOR(setCursorWidth(m_cursorWidth));
         EDITOR(setOverwriteMode(false));
     } else {
@@ -4755,8 +4713,8 @@ void FakeVimHandler::Private::selectWordTextObject(bool inner)
     moveToWordBoundary(false, false, true);
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
-    if (isVisualMode())
-        setMark('<', cursor().position());
+    //if (isVisualMode())
+    //    setMark('<', cursor().position());
     moveToWordBoundary(false, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4768,8 +4726,8 @@ void FakeVimHandler::Private::selectWORDTextObject(bool inner)
     moveToWordBoundary(true, false, true);
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
-    if (isVisualMode())
-        setMark('<', cursor().position());
+    //if (isVisualMode())
+    //    setMark('<', cursor().position());
     moveToWordBoundary(true, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4798,9 +4756,9 @@ void FakeVimHandler::Private::selectBlockTextObject(bool inner, char left, char
     if (inner && document()->characterAt(p1) == ParagraphSeparator)
         ++p1;
     const int p2 = tc2.position() - inner - sright.size();
-    setMark('>', p1);
-    setMark('<', p2);
-    setPositionAndAnchor(p1, p2);
+    //setMark('>', p1);
+    //setMark('<', p2);
+    setAnchorAndPosition(p2, p1);
     m_movetype = MoveInclusive;
 }
 
diff --git a/src/plugins/fakevim/fakevimoptions.ui b/src/plugins/fakevim/fakevimoptions.ui
index 51f19c49111..450a8629065 100644
--- a/src/plugins/fakevim/fakevimoptions.ui
+++ b/src/plugins/fakevim/fakevimoptions.ui
@@ -73,16 +73,6 @@
         </property>
        </widget>
       </item>
-      <item row="3" column="2">
-       <widget class="QCheckBox" name="checkBoxExportSelection">
-        <property name="text">
-         <string>Export selected text automatically</string>
-        </property>
-        <property name="toolTip">
-         <string>This might slow down editing</string>
-        </property>
-       </widget>
-      </item>
       <item row="3" column="0" colspan="2">
        <widget class="QCheckBox" name="checkBoxSmartTab">
         <property name="text">
diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp
index 5ac99bca9ab..4a953495eac 100644
--- a/src/plugins/fakevim/fakevimplugin.cpp
+++ b/src/plugins/fakevim/fakevimplugin.cpp
@@ -169,8 +169,6 @@ QWidget *FakeVimOptionPage::createPage(QWidget *parent)
         m_ui.spinBoxShiftWidth);
     m_group.insert(theFakeVimSetting(ConfigShowMarks),
         m_ui.checkBoxShowMarks);
-    m_group.insert(theFakeVimSetting(ConfigExportSelection),
-        m_ui.checkBoxExportSelection);
 
     m_group.insert(theFakeVimSetting(ConfigSmartTab),
         m_ui.checkBoxSmartTab);
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index 87062a84b5c..4f333373182 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -5792,8 +5792,8 @@ void BaseTextEditor::setBlockSelection(bool on)
         d->m_inBlockSelectionMode = on;
         if (on)
             d->m_blockSelection.fromSelection(tabSettings(), textCursor());
-        viewport()->update();
     }
+    viewport()->update();
 }
 
 bool BaseTextEditor::hasBlockSelection() const
-- 
GitLab