Browse Source

vim-mode: going back to Normal mode from insert mode will clear auto indent and auto list

Le Tan 8 years ago
parent
commit
4b1e256308
6 changed files with 112 additions and 82 deletions
  1. 48 0
      src/utils/veditutils.cpp
  2. 12 0
      src/utils/veditutils.h
  3. 39 10
      src/utils/vvim.cpp
  4. 3 2
      src/utils/vvim.h
  5. 10 61
      src/vmdeditoperations.cpp
  6. 0 9
      src/vmdeditoperations.h

+ 48 - 0
src/utils/veditutils.cpp

@@ -352,3 +352,51 @@ void VEditUtils::scrollBlockInPage(QTextEdit *p_edit,
 
     p_edit->ensureCursorVisible();
 }
+
+bool VEditUtils::isListBlock(const QTextBlock &p_block, int *p_seq)
+{
+    QString text = p_block.text();
+    QRegExp regExp("^\\s*(-|\\d+\\.)\\s");
+
+    if (p_seq) {
+        *p_seq = -1;
+    }
+
+    int regIdx = regExp.indexIn(text);
+    if (regIdx == -1) {
+        return false;
+    }
+
+    V_ASSERT(regExp.captureCount() == 1);
+    QString markText = regExp.capturedTexts()[1];
+    if (markText != "-") {
+        V_ASSERT(markText.endsWith('.'));
+        bool ok = false;
+        int num = markText.left(markText.size() - 1).toInt(&ok, 10);
+        V_ASSERT(ok);
+        if (p_seq) {
+            *p_seq = num;
+        }
+    }
+
+    return true;
+}
+
+bool VEditUtils::isSpaceToBlockStart(const QTextBlock &p_block, int p_posInBlock)
+{
+    if (p_posInBlock <= 0) {
+        return true;
+    }
+
+    QString text = p_block.text();
+    V_ASSERT(text.size() >= p_posInBlock);
+    return text.left(p_posInBlock).trimmed().isEmpty();
+}
+
+void VEditUtils::deleteIndentAndListMark(QTextCursor &p_cursor)
+{
+    V_ASSERT(!p_cursor.hasSelection());
+    p_cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
+    p_cursor.removeSelectedText();
+}
+

+ 12 - 0
src/utils/veditutils.h

@@ -84,6 +84,18 @@ public:
                                   int p_blockNum,
                                   int p_dest);
 
+    // Check if @p_block is a auto list block.
+    // @p_seq will be the seq number of the ordered list, or -1.
+    // Returns true if it is an auto list block.
+    static bool isListBlock(const QTextBlock &p_block, int *p_seq = NULL);
+
+    // If the start of @p_block to postition @p_posInBlock are spaces.
+    static bool isSpaceToBlockStart(const QTextBlock &p_block, int p_posInBlock);
+
+    // @p_cursor is positioned right after auto indetn and auto list.
+    // Need to call setTextCursor() to make it take effect.
+    static void deleteIndentAndListMark(QTextCursor &p_cursor);
+
 private:
     VEditUtils() {}
 };

+ 39 - 10
src/utils/vvim.cpp

@@ -351,9 +351,9 @@ static bool isControlModifier(int p_modifiers)
 #endif
 }
 
-bool VVim::handleKeyPressEvent(QKeyEvent *p_event, bool *p_autoIndented)
+bool VVim::handleKeyPressEvent(QKeyEvent *p_event, int *p_autoIndentPos)
 {
-    bool ret = handleKeyPressEvent(p_event->key(), p_event->modifiers(), p_autoIndented);
+    bool ret = handleKeyPressEvent(p_event->key(), p_event->modifiers(), p_autoIndentPos);
     if (ret) {
         p_event->accept();
     }
@@ -361,23 +361,47 @@ bool VVim::handleKeyPressEvent(QKeyEvent *p_event, bool *p_autoIndented)
     return ret;
 }
 
-bool VVim::handleKeyPressEvent(int key, int modifiers, bool *p_autoIndented)
+bool VVim::handleKeyPressEvent(int key, int modifiers, int *p_autoIndentPos)
 {
     bool ret = false;
     bool resetPositionInBlock = true;
     Key keyInfo(key, modifiers);
     bool unindent = false;
-
-    if (p_autoIndented) {
-        *p_autoIndented = false;
-    }
+    int autoIndentPos = -1;
 
     // Handle Insert mode key press.
     if (VimMode::Insert == m_mode) {
         if (key == Qt::Key_Escape
             || (key == Qt::Key_BracketLeft && isControlModifier(modifiers))) {
+            // See if we need to cancel auto indent.
+            bool cancelAutoIndent = false;
+            if (p_autoIndentPos && *p_autoIndentPos > -1) {
+                // Cancel the auto indent/list if the pos is the same and cursor is at
+                // the end of a block.
+                QTextCursor cursor = m_editor->textCursor();
+                QTextBlock block = cursor.block();
+                if (cursor.position() == *p_autoIndentPos && !cursor.hasSelection()) {
+                    if (VEditUtils::isListBlock(block)) {
+                        if (cursor.atBlockEnd()) {
+                            cancelAutoIndent = true;
+                        }
+                    } else if (VEditUtils::isSpaceToBlockStart(block,
+                                                               cursor.positionInBlock())) {
+                        cancelAutoIndent = true;
+                    }
+                }
+
+                if (cancelAutoIndent) {
+                    autoIndentPos = -1;
+                    VEditUtils::deleteIndentAndListMark(cursor);
+                    m_editor->setTextCursor(cursor);
+                }
+            }
+
             // Clear selection and enter Normal mode.
-            clearSelection();
+            if (!cancelAutoIndent) {
+                clearSelection();
+            }
 
             setMode(VimMode::Normal);
             goto clear_accept;
@@ -766,8 +790,8 @@ bool VVim::handleKeyPressEvent(int key, int modifiers, bool *p_autoIndented)
                 cursor.endEditBlock();
                 m_editor->setTextCursor(cursor);
 
-                if (p_autoIndented && textInserted) {
-                    *p_autoIndented = true;
+                if (textInserted) {
+                    autoIndentPos = cursor.position();
                 }
 
                 setMode(VimMode::Insert);
@@ -1679,6 +1703,11 @@ clear_accept:
 accept:
     ret = true;
 
+    // Only alter the autoIndentPos when the key is handled by Vim.
+    if (p_autoIndentPos) {
+        *p_autoIndentPos = autoIndentPos;
+    }
+
 exit:
     m_resetPositionInBlock = resetPositionInBlock;
     emit vimStatusUpdated(this);

+ 3 - 2
src/utils/vvim.h

@@ -147,8 +147,9 @@ public:
     };
 
     // Handle key press event.
+    // @p_autoIndentPos: the cursor position of last auto indent.
     // Returns true if the event is consumed and need no more handling.
-    bool handleKeyPressEvent(QKeyEvent *p_event, bool *p_autoIndented = NULL);
+    bool handleKeyPressEvent(QKeyEvent *p_event, int *p_autoIndentPos = NULL);
 
     // Return current mode.
     VimMode getMode() const;
@@ -449,7 +450,7 @@ private:
     };
 
     // Returns true if the event is consumed and need no more handling.
-    bool handleKeyPressEvent(int key, int modifiers, bool *p_autoIndented = NULL);
+    bool handleKeyPressEvent(int key, int modifiers, int *p_autoIndentPos = NULL);
 
     // Reset all key state info.
     void resetState();

+ 10 - 61
src/vmdeditoperations.cpp

@@ -193,15 +193,8 @@ bool VMdEditOperations::insertImage()
 
 bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
 {
-    bool autoIndentedVim = false;
     if (m_editConfig->m_enableVimMode
-        && m_vim->handleKeyPressEvent(p_event, &autoIndentedVim)) {
-        if (autoIndentedVim) {
-            m_autoIndentPos = m_editor->textCursor().position();
-        } else {
-            m_autoIndentPos = -1;
-        }
-
+        && m_vim->handleKeyPressEvent(p_event, &m_autoIndentPos)) {
         return true;
     }
 
@@ -383,7 +376,8 @@ bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event)
             // If it is a Tab key following auto list, increase the indent level.
             QTextBlock block = cursor.block();
             int seq = -1;
-            if (m_autoIndentPos == cursor.position() && isListBlock(block, &seq)) {
+            if (m_autoIndentPos == cursor.position()
+                && VEditUtils::isListBlock(block, &seq)) {
                 QTextCursor blockCursor(block);
                 blockCursor.beginEditBlock();
                 blockCursor.insertText(text);
@@ -418,7 +412,8 @@ bool VMdEditOperations::handleKeyBackTab(QKeyEvent *p_event)
     QTextBlock block = doc->findBlock(cursor.selectionStart());
     bool continueAutoIndent = false;
     int seq = -1;
-    if (cursor.position() == m_autoIndentPos && isListBlock(block, &seq) &&
+    if (cursor.position() == m_autoIndentPos
+        && VEditUtils::isListBlock(block, &seq) &&
         !cursor.hasSelection()) {
         continueAutoIndent = true;
     }
@@ -668,17 +663,19 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
         QTextCursor cursor = m_editor->textCursor();
         QTextBlock block = cursor.block();
         if (cursor.position() == m_autoIndentPos && !cursor.hasSelection()) {
-            if (isListBlock(block)) {
+            if (VEditUtils::isListBlock(block)) {
                 if (cursor.atBlockEnd()) {
                     cancelAutoIndent = true;
                 }
-            } else if (isSpaceToBlockStart(block, cursor.positionInBlock())) {
+            } else if (VEditUtils::isSpaceToBlockStart(block,
+                                                       cursor.positionInBlock())) {
                 cancelAutoIndent = true;
             }
         }
         if (cancelAutoIndent) {
             m_autoIndentPos = -1;
-            deleteIndentAndListMark();
+            VEditUtils::deleteIndentAndListMark(cursor);
+            m_editor->setTextCursor(cursor);
             return true;
         }
     }
@@ -711,35 +708,6 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
     return handled;
 }
 
-bool VMdEditOperations::isListBlock(const QTextBlock &p_block, int *p_seq)
-{
-    QString text = p_block.text();
-    QRegExp regExp("^\\s*(-|\\d+\\.)\\s");
-
-    if (p_seq) {
-        *p_seq = -1;
-    }
-
-    int regIdx = regExp.indexIn(text);
-    if (regIdx == -1) {
-        return false;
-    }
-
-    V_ASSERT(regExp.captureCount() == 1);
-    QString markText = regExp.capturedTexts()[1];
-    if (markText != "-") {
-        V_ASSERT(markText.endsWith('.'));
-        bool ok = false;
-        int num = markText.left(markText.size() - 1).toInt(&ok, 10);
-        V_ASSERT(ok);
-        if (p_seq) {
-            *p_seq = num;
-        }
-    }
-
-    return true;
-}
-
 void VMdEditOperations::changeListBlockSeqNumber(QTextBlock &p_block, int p_seq)
 {
     QString text = p_block.text();
@@ -774,25 +742,6 @@ void VMdEditOperations::changeListBlockSeqNumber(QTextBlock &p_block, int p_seq)
     cursor.insertText(QString::number(p_seq));
 }
 
-bool VMdEditOperations::isSpaceToBlockStart(const QTextBlock &p_block, int p_posInBlock)
-{
-    if (p_posInBlock <= 0) {
-        return true;
-    }
-    QString text = p_block.text();
-    V_ASSERT(text.size() >= p_posInBlock);
-    return text.left(p_posInBlock).trimmed().isEmpty();
-}
-
-void VMdEditOperations::deleteIndentAndListMark()
-{
-    QTextCursor cursor = m_editor->textCursor();
-    V_ASSERT(!cursor.hasSelection());
-    cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
-    cursor.removeSelectedText();
-    m_editor->setTextCursor(cursor);
-}
-
 bool VMdEditOperations::insertTitle(int p_level)
 {
     Q_ASSERT(p_level > 0 && p_level < 7);

+ 0 - 9
src/vmdeditoperations.h

@@ -42,15 +42,6 @@ private:
     bool handleKeyReturn(QKeyEvent *p_event);
     bool handleKeyBracketLeft(QKeyEvent *p_event);
     bool insertTitle(int p_level);
-    void deleteIndentAndListMark();
-
-    // Check if @p_block is a auto list block.
-    // @p_seq will be the seq number of the ordered list, or -1.
-    // Returns true if it is an auto list block.
-    bool isListBlock(const QTextBlock &p_block, int *p_seq = NULL);
-
-    // If the start of @p_block to postition @p_posInBlock are spaces.
-    bool isSpaceToBlockStart(const QTextBlock &p_block, int p_posInBlock);
 
     // Change the sequence number of a list block.
     void changeListBlockSeqNumber(QTextBlock &p_block, int p_seq);