From b2235b5ca20e59e60f7065e571375d6d42246afd Mon Sep 17 00:00:00 2001
From: James Linse <jameslinse@gmail.com>
Date: Wed, 16 Sep 2009 14:16:21 +0200
Subject: [PATCH] Fixed yanking and deleting using marks ma "ay'a Fixed yanking
 with e (ye) Fixed ce followed by . Initial implementation for mark updates
 (marks should stay on the same line after adding/deleting lines) Fixed yank
 with Y Added fakevim tests for yanking using marks and yanking using Y. Fixed
 yanking with marks when a mark was set to a blank line. Combined yy and Y to
 use the same yanking method.

Merge-request: 1314
Reviewed-by: hjk <qtc-committer@nokia.com>
---
 src/plugins/fakevim/fakevimhandler.cpp | 105 ++++++++++++++++++-------
 tests/auto/fakevim/main.cpp            |  20 +++++
 2 files changed, 96 insertions(+), 29 deletions(-)

diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index ee3e3216e1a..49bf5df7932 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -249,6 +249,7 @@ public:
     bool wantsOverride(QKeyEvent *ev);
     void handleCommand(const QString &cmd); // sets m_tc + handleExCommand
     void handleExCommand(const QString &cmd);
+    void fixMarks(int positionAction, int positionChange); //Updates marks positions by the difference in positionChange
 
     void installEventFilter();
     void setupWidget();
@@ -746,10 +747,12 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         enterInsertMode();
         m_submode = NoSubMode;
     } else if (m_submode == DeleteSubMode) {
-        if (m_movetype == MoveInclusive)
-            moveRight(); // correction
-        if (anchor() >= position())
-           m_anchor++;
+        if (m_rangemode == RangeCharMode) {
+           if (m_movetype == MoveInclusive)
+               moveRight(); // correction
+           if (anchor() >= position())
+              m_anchor++;
+        }
         if (!dotCommand.isEmpty())
             setDotCommand("d" + dotCommand);
         yankSelectedText();
@@ -761,8 +764,13 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
             setTargetColumn();
     } else if (m_submode == YankSubMode) {
         yankSelectedText();
-        setPosition(m_savedYankPosition);
         m_submode = NoSubMode;
+        if (m_register != '"') {
+            setPosition(m_marks[m_register]);
+            moveToStartOfLine();
+        } else {
+            setPosition(m_savedYankPosition);
+        }
     } else if (m_submode == ReplaceSubMode) {
         m_submode = NoSubMode;
     } else if (m_submode == IndentSubMode) {
@@ -941,6 +949,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
     } else if (m_submode == RegisterSubMode) {
         m_register = key;
         m_submode = NoSubMode;
+        m_rangemode = RangeLineMode;
     } else if (m_submode == ChangeSubMode && key == 'c') { // tested
         moveDown(count() - 1);
         moveToEndOfLine();
@@ -964,14 +973,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
         moveToFirstNonBlankOnLine();
         setTargetColumn(); 
         finishMovement();
-    } else if (m_submode == YankSubMode && key == 'y') {
-        m_movetype = MoveLineWise;
-        int endPos = firstPositionInLine(lineForPosition(position()) + count() - 1);
-        Range range(position(), endPos, RangeLineMode);
-        ///range.extendByLines(count() - 1);
-        yankText(range);
-        m_submode = NoSubMode;
-        finishMovement();
     } else if (m_submode == ShiftLeftSubMode && key == '<') {
         setAnchor();
         moveDown(count() - 1);
@@ -1232,9 +1233,16 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
     } else if (key == control('c')) {
         showBlackMessage("Type Alt-v,Alt-v  to quit FakeVim mode");
     } else if (key == 'd' && m_visualMode == NoVisualMode) {
-        if (atEndOfLine())
-            moveLeft();
-        setAnchor();
+        if (m_rangemode == RangeLineMode) {
+            m_savedYankPosition = m_tc.position();
+            moveToEndOfLine();
+            setAnchor();
+            setPosition(m_savedYankPosition);
+        } else {
+            if (atEndOfLine())
+                moveLeft();
+            setAnchor();
+        }
         m_opcount = m_mvcount;
         m_mvcount.clear();
         m_submode = DeleteSubMode;
@@ -1271,7 +1279,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
     } else if (key == 'e') { // tested
         m_movetype = MoveInclusive;
         moveToWordBoundary(false, true);
-        finishMovement();
+        finishMovement("e");
     } else if (key == 'E') {
         m_movetype = MoveInclusive;
         moveToWordBoundary(true, true);
@@ -1512,13 +1520,30 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
             removeSelectedText();
         }
         finishMovement();
+    } else if ((m_submode == YankSubMode && key == 'y')
+            || (key == 'Y' && m_visualMode == NoVisualMode))  {
+        const int line = cursorLineInDocument() + 1;
+        m_savedYankPosition = position();
+        setAnchor(firstPositionInLine(line));
+        setPosition(lastPositionInLine(line+count() - 1));
+        if (count() > 1) 
+            showBlackMessage(QString("%1 lines yanked").arg(count()));
+        m_rangemode = RangeLineMode;
+        m_movetype = MoveLineWise;
+        m_submode = YankSubMode;
+        finishMovement();
     } else if (key == 'y' && m_visualMode == NoVisualMode) {
-        m_savedYankPosition = m_tc.position();
-        if (atEndOfLine())
-            moveLeft();
-        setAnchor();
+        if (m_rangemode == RangeLineMode) {
+            m_savedYankPosition = position();
+            setAnchor(firstPositionInLine(cursorLineInDocument() + 1));
+        } else {
+            m_savedYankPosition = position();
+            if (atEndOfLine())
+                moveLeft();
+            setAnchor();
+            m_rangemode = RangeCharMode;
+        }
         m_submode = YankSubMode;
-        m_rangemode = RangeCharMode;
     } else if (key == 'y' && m_visualMode == VisualCharMode) {
         Range range(position(), anchor(), RangeCharMode);
         range.endPos++; // MoveInclusive
@@ -1526,13 +1551,6 @@ EventResult FakeVimHandler::Private::handleCommandMode(int key, int unmodified,
         setPosition(qMin(position(), anchor()));
         leaveVisualMode();
         finishMovement();
-    } else if (key == 'Y' && m_visualMode == NoVisualMode)  {
-        const int line = cursorLineInDocument() + 1;
-        selectRange(line, line + count() - 1);
-        m_rangemode = RangeLineMode;
-        yankSelectedText();
-        setPosition(qMin(position(), anchor()));
-        finishMovement();
     } else if ((key == 'y' && m_visualMode == VisualLineMode)
             || (key == 'Y' && m_visualMode == VisualLineMode)
             || (key == 'Y' && m_visualMode == VisualCharMode)) {
@@ -2476,6 +2494,12 @@ QString FakeVimHandler::Private::text(const Range &range) const
         tc.setPosition(range.endPos, KeepAnchor);
         return tc.selection().toPlainText();
     }
+    if (range.rangemode == RangeLineMode) {
+        QTextCursor tc = m_tc;
+        tc.setPosition(firstPositionInLine(lineForPosition(range.beginPos)), MoveAnchor);
+        tc.setPosition(firstPositionInLine(lineForPosition(range.endPos)+1), KeepAnchor);
+        return tc.selection().toPlainText();
+    }
     // FIXME: Performance?
     int beginLine = lineForPosition(range.beginPos);
     int endLine = lineForPosition(range.endPos);
@@ -2536,6 +2560,7 @@ void FakeVimHandler::Private::removeText(const Range &range)
         case RangeCharMode: {
             tc.setPosition(range.beginPos, MoveAnchor);
             tc.setPosition(range.endPos, KeepAnchor);
+            fixMarks(range.beginPos, tc.selectionStart() - tc.selectionEnd());
             tc.removeSelectedText();
             return;
         }
@@ -2545,6 +2570,7 @@ void FakeVimHandler::Private::removeText(const Range &range)
             tc.setPosition(range.endPos, KeepAnchor);
             tc.movePosition(EndOfLine, KeepAnchor);
             tc.movePosition(Right, KeepAnchor, 1);
+            fixMarks(range.beginPos, tc.selectionStart() - tc.selectionEnd());
             tc.removeSelectedText();
             return;
         }
@@ -2564,6 +2590,7 @@ void FakeVimHandler::Private::removeText(const Range &range)
                 int eCol = qMin(endColumn, block.length() - 1);
                 tc.setPosition(block.position() + bCol, MoveAnchor);
                 tc.setPosition(block.position() + eCol, KeepAnchor);
+                fixMarks(block.position() + bCol, tc.selectionStart() - tc.selectionEnd());
                 tc.removeSelectedText();
                 block = block.previous();
             }
@@ -2582,6 +2609,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor && rightDist() > 0)
                     moveRight();
+                fixMarks(position(), text.length());
                 m_tc.insertText(text);
                 moveLeft();
             }
@@ -2593,6 +2621,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor)
                     moveDown();
+                fixMarks(position(), text.length());
                 m_tc.insertText(text);
                 moveUp(lines.size() - 1);
             }
@@ -2611,16 +2640,19 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
                 tc.movePosition(StartOfLine, MoveAnchor);
                 if (col >= block.length()) {
                     tc.movePosition(EndOfLine, MoveAnchor);
+                    fixMarks(position(), QString(col - line.size() + 1, QChar(' ')).length());
                     tc.insertText(QString(col - line.size() + 1, QChar(' ')));
                 } else { 
                     tc.movePosition(Right, MoveAnchor, col);
                 }
                 qDebug() << "INSERT " << line << " AT " << tc.position()
                     << "COL: " << col;
+                fixMarks(position(), line.length());
                 tc.insertText(line);
                 tc.movePosition(StartOfLine, MoveAnchor);
                 tc.movePosition(Down, MoveAnchor, 1);
                 if (tc.position() >= lastPositionInDocument() - 1) {
+                    fixMarks(position(), QString(QChar('\n')).length());
                     tc.insertText(QString(QChar('\n')));
                     tc.movePosition(Up, MoveAnchor, 1);
                 }
@@ -2632,6 +2664,21 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
     }
 }
 
+//FIXME: This needs to called after undo/insert
+void FakeVimHandler::Private::fixMarks(int positionAction, int positionChange)
+{
+    QHashIterator<int, int> i(m_marks);
+    while (i.hasNext()) {
+        i.next();
+        if (i.value() >= positionAction) { 
+            if (i.value() + positionChange > 0) 
+                m_marks[i.key()] = i.value() + positionChange;
+            else
+                m_marks.remove(i.key());
+        }
+    }
+}
+
 int FakeVimHandler::Private::firstPositionInLine(int line) const
 {
     return m_tc.document()->findBlockByNumber(line - 1).position();
diff --git a/tests/auto/fakevim/main.cpp b/tests/auto/fakevim/main.cpp
index cf674adcbe7..d3e71f5032b 100644
--- a/tests/auto/fakevim/main.cpp
+++ b/tests/auto/fakevim/main.cpp
@@ -73,7 +73,9 @@ private slots:
     void command_up();
     void command_w();
     void command_yyp();
+    void command_Yp();
     void command_Gyyp();
+    void command_ma_yank();
 
     // special tests
     void test_i_cw_i();
@@ -485,6 +487,24 @@ void tst_FakeVim::command_yyp()
     check("yyp", lmid(0, 4) + "\n" + lmid(4, 1) + "\n@" + lmid(4));
 }
 
+void tst_FakeVim::command_Yp()
+{
+    setup();
+    move("4j",   "@int main");
+    check("Yp", lmid(0, 4) + "\n" + lmid(4, 1) + "\n@" + lmid(4));
+}
+
+void tst_FakeVim::command_ma_yank()
+{
+    setup();
+    check("ma", "@" + lmid(0));
+    move("4j",   "@int main");
+    check("mb", lmid(0,4) + "\n@" + lmid(4));
+    check("\"ay'a", "@" + lmid(0));
+    check("'b", lmid(0,4) + "\n@" + lmid(4));
+    check("\"ap", lmid(0,5) + "\n@" + lmid(0,4) +"\n" + lmid(4));
+}
+
 void tst_FakeVim::command_Gyyp()
 {
     qWarning("FIXME");
-- 
GitLab