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

This commit is contained in:
Le Tan 2017-06-28 22:04:54 +08:00
parent eeaeb0b567
commit 4b1e256308
6 changed files with 112 additions and 82 deletions

View File

@ -352,3 +352,51 @@ void VEditUtils::scrollBlockInPage(QTextEdit *p_edit,
p_edit->ensureCursorVisible(); 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();
}

View File

@ -84,6 +84,18 @@ public:
int p_blockNum, int p_blockNum,
int p_dest); 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: private:
VEditUtils() {} VEditUtils() {}
}; };

View File

@ -351,9 +351,9 @@ static bool isControlModifier(int p_modifiers)
#endif #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) { if (ret) {
p_event->accept(); p_event->accept();
} }
@ -361,23 +361,47 @@ bool VVim::handleKeyPressEvent(QKeyEvent *p_event, bool *p_autoIndented)
return ret; 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 ret = false;
bool resetPositionInBlock = true; bool resetPositionInBlock = true;
Key keyInfo(key, modifiers); Key keyInfo(key, modifiers);
bool unindent = false; bool unindent = false;
int autoIndentPos = -1;
if (p_autoIndented) {
*p_autoIndented = false;
}
// Handle Insert mode key press. // Handle Insert mode key press.
if (VimMode::Insert == m_mode) { if (VimMode::Insert == m_mode) {
if (key == Qt::Key_Escape if (key == Qt::Key_Escape
|| (key == Qt::Key_BracketLeft && isControlModifier(modifiers))) { || (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. // Clear selection and enter Normal mode.
if (!cancelAutoIndent) {
clearSelection(); clearSelection();
}
setMode(VimMode::Normal); setMode(VimMode::Normal);
goto clear_accept; goto clear_accept;
@ -766,8 +790,8 @@ bool VVim::handleKeyPressEvent(int key, int modifiers, bool *p_autoIndented)
cursor.endEditBlock(); cursor.endEditBlock();
m_editor->setTextCursor(cursor); m_editor->setTextCursor(cursor);
if (p_autoIndented && textInserted) { if (textInserted) {
*p_autoIndented = true; autoIndentPos = cursor.position();
} }
setMode(VimMode::Insert); setMode(VimMode::Insert);
@ -1679,6 +1703,11 @@ clear_accept:
accept: accept:
ret = true; ret = true;
// Only alter the autoIndentPos when the key is handled by Vim.
if (p_autoIndentPos) {
*p_autoIndentPos = autoIndentPos;
}
exit: exit:
m_resetPositionInBlock = resetPositionInBlock; m_resetPositionInBlock = resetPositionInBlock;
emit vimStatusUpdated(this); emit vimStatusUpdated(this);

View File

@ -147,8 +147,9 @@ public:
}; };
// Handle key press event. // 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. // 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. // Return current mode.
VimMode getMode() const; VimMode getMode() const;
@ -449,7 +450,7 @@ private:
}; };
// Returns true if the event is consumed and need no more handling. // 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. // Reset all key state info.
void resetState(); void resetState();

View File

@ -193,15 +193,8 @@ bool VMdEditOperations::insertImage()
bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event) bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
{ {
bool autoIndentedVim = false;
if (m_editConfig->m_enableVimMode if (m_editConfig->m_enableVimMode
&& m_vim->handleKeyPressEvent(p_event, &autoIndentedVim)) { && m_vim->handleKeyPressEvent(p_event, &m_autoIndentPos)) {
if (autoIndentedVim) {
m_autoIndentPos = m_editor->textCursor().position();
} else {
m_autoIndentPos = -1;
}
return true; 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. // If it is a Tab key following auto list, increase the indent level.
QTextBlock block = cursor.block(); QTextBlock block = cursor.block();
int seq = -1; int seq = -1;
if (m_autoIndentPos == cursor.position() && isListBlock(block, &seq)) { if (m_autoIndentPos == cursor.position()
&& VEditUtils::isListBlock(block, &seq)) {
QTextCursor blockCursor(block); QTextCursor blockCursor(block);
blockCursor.beginEditBlock(); blockCursor.beginEditBlock();
blockCursor.insertText(text); blockCursor.insertText(text);
@ -418,7 +412,8 @@ bool VMdEditOperations::handleKeyBackTab(QKeyEvent *p_event)
QTextBlock block = doc->findBlock(cursor.selectionStart()); QTextBlock block = doc->findBlock(cursor.selectionStart());
bool continueAutoIndent = false; bool continueAutoIndent = false;
int seq = -1; int seq = -1;
if (cursor.position() == m_autoIndentPos && isListBlock(block, &seq) && if (cursor.position() == m_autoIndentPos
&& VEditUtils::isListBlock(block, &seq) &&
!cursor.hasSelection()) { !cursor.hasSelection()) {
continueAutoIndent = true; continueAutoIndent = true;
} }
@ -668,17 +663,19 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
QTextCursor cursor = m_editor->textCursor(); QTextCursor cursor = m_editor->textCursor();
QTextBlock block = cursor.block(); QTextBlock block = cursor.block();
if (cursor.position() == m_autoIndentPos && !cursor.hasSelection()) { if (cursor.position() == m_autoIndentPos && !cursor.hasSelection()) {
if (isListBlock(block)) { if (VEditUtils::isListBlock(block)) {
if (cursor.atBlockEnd()) { if (cursor.atBlockEnd()) {
cancelAutoIndent = true; cancelAutoIndent = true;
} }
} else if (isSpaceToBlockStart(block, cursor.positionInBlock())) { } else if (VEditUtils::isSpaceToBlockStart(block,
cursor.positionInBlock())) {
cancelAutoIndent = true; cancelAutoIndent = true;
} }
} }
if (cancelAutoIndent) { if (cancelAutoIndent) {
m_autoIndentPos = -1; m_autoIndentPos = -1;
deleteIndentAndListMark(); VEditUtils::deleteIndentAndListMark(cursor);
m_editor->setTextCursor(cursor);
return true; return true;
} }
} }
@ -711,35 +708,6 @@ bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
return handled; 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) void VMdEditOperations::changeListBlockSeqNumber(QTextBlock &p_block, int p_seq)
{ {
QString text = p_block.text(); QString text = p_block.text();
@ -774,25 +742,6 @@ void VMdEditOperations::changeListBlockSeqNumber(QTextBlock &p_block, int p_seq)
cursor.insertText(QString::number(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) bool VMdEditOperations::insertTitle(int p_level)
{ {
Q_ASSERT(p_level > 0 && p_level < 7); Q_ASSERT(p_level > 0 && p_level < 7);

View File

@ -42,15 +42,6 @@ private:
bool handleKeyReturn(QKeyEvent *p_event); bool handleKeyReturn(QKeyEvent *p_event);
bool handleKeyBracketLeft(QKeyEvent *p_event); bool handleKeyBracketLeft(QKeyEvent *p_event);
bool insertTitle(int p_level); 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. // Change the sequence number of a list block.
void changeListBlockSeqNumber(QTextBlock &p_block, int p_seq); void changeListBlockSeqNumber(QTextBlock &p_block, int p_seq);