From 4b1e2563087b81e34967d37b500ff017fac3dcd9 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Wed, 28 Jun 2017 22:04:54 +0800 Subject: [PATCH] vim-mode: going back to Normal mode from insert mode will clear auto indent and auto list --- src/utils/veditutils.cpp | 48 ++++++++++++++++++++++++++ src/utils/veditutils.h | 12 +++++++ src/utils/vvim.cpp | 49 +++++++++++++++++++++------ src/utils/vvim.h | 5 +-- src/vmdeditoperations.cpp | 71 ++++++--------------------------------- src/vmdeditoperations.h | 9 ----- 6 files changed, 112 insertions(+), 82 deletions(-) diff --git a/src/utils/veditutils.cpp b/src/utils/veditutils.cpp index 55696753..e6b1b16f 100644 --- a/src/utils/veditutils.cpp +++ b/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(); +} + diff --git a/src/utils/veditutils.h b/src/utils/veditutils.h index 7e521bbd..dd4a2450 100644 --- a/src/utils/veditutils.h +++ b/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() {} }; diff --git a/src/utils/vvim.cpp b/src/utils/vvim.cpp index db63064b..a8f70842 100644 --- a/src/utils/vvim.cpp +++ b/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); diff --git a/src/utils/vvim.h b/src/utils/vvim.h index 79889aea..9277ebc6 100644 --- a/src/utils/vvim.h +++ b/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(); diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index e9dbbd10..239cc867 100644 --- a/src/vmdeditoperations.cpp +++ b/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); diff --git a/src/vmdeditoperations.h b/src/vmdeditoperations.h index 5cdcc625..a5fa4143 100644 --- a/src/vmdeditoperations.h +++ b/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);