From 1f0ee887708637336ed5b712deb2df5471c5f237 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Fri, 24 Nov 2017 19:56:25 +0800 Subject: [PATCH] refactor edit operations - Ctrl+B/I/K/D/M: Revert if content between the markers is empty. - Ctrl+7: delete title mark. --- src/resources/docs/shortcuts_en.md | 4 ++ src/resources/docs/shortcuts_zh.md | 4 ++ src/utils/veditutils.cpp | 15 ++++- src/utils/veditutils.h | 1 + src/vmdeditoperations.cpp | 102 +++++++++++++++++++++++------ src/vmdeditoperations.h | 1 + 6 files changed, 105 insertions(+), 22 deletions(-) diff --git a/src/resources/docs/shortcuts_en.md b/src/resources/docs/shortcuts_en.md index 6c82edfb..040f1fc6 100644 --- a/src/resources/docs/shortcuts_en.md +++ b/src/resources/docs/shortcuts_en.md @@ -17,6 +17,8 @@ VNote supports `Ctrl+J` and `Ctrl+K` for navigation in the notebooks list, direc Scroll in all directions. - `Ctrl+Shift+T` Recover last closed file. +- `Ctrl+Alt+L` +Open Flash Page. ### Read Mode - `Ctrl+W` @@ -70,6 +72,8 @@ Delete all the characters from current cursor to the first space backward. Delete all the characters from current cursor to the beginning of current line. - `Ctrl+` Insert title at level ``. `` should be 1 to 6. Current selected text will be changed to title if exists. +- `Ctrl+7` +Delete the title mark of current line or selected text. - `Tab`/`Shift+Tab` Increase or decrease the indentation. If any text is selected, the indentation will operate on all these selected lines. - `Shift+Enter` diff --git a/src/resources/docs/shortcuts_zh.md b/src/resources/docs/shortcuts_zh.md index 31efa6cf..a97e1492 100644 --- a/src/resources/docs/shortcuts_zh.md +++ b/src/resources/docs/shortcuts_zh.md @@ -17,6 +17,8 @@ 任意滚动。 - `Ctrl+Shift+T` 恢复上一个关闭的文件。 +- `Ctrl+Alt+L` +打开灵犀页。 ### 阅读模式 - `Ctrl+W` @@ -70,6 +72,8 @@ 删除光标位置到行首的所有字符。 - `Ctrl+` 插入级别为``的标题。``应该是1到6的一个数字。如果已经选择文本,则将当前选择文本改为标题。 +- `Ctrl+7` +删除当前行或所选择文本的标题标记。 - `Tab`/`Shift+Tab` 增加或减小缩进。如果已经选择文本,则对所有选择的行进行缩进操作。 - `Shift+Enter` diff --git a/src/utils/veditutils.cpp b/src/utils/veditutils.cpp index 50c87e34..5cb04f97 100644 --- a/src/utils/veditutils.cpp +++ b/src/utils/veditutils.cpp @@ -785,7 +785,7 @@ void VEditUtils::insertTitleMark(QTextCursor &p_cursor, return; } - Q_ASSERT(p_level >= 1 && p_level <= 6); + Q_ASSERT(p_level >= 0 && p_level <= 6); bool needInsert = true; @@ -801,15 +801,24 @@ void VEditUtils::insertTitleMark(QTextCursor &p_cursor, needInsert = false; } else { // Remove the title mark. + int length = level; + if (p_level == 0) { + // Remove all the prefix. + QRegExp prefixReg(VUtils::c_headerPrefixRegExp); + bool preMatched = prefixReg.exactMatch(text); + Q_ASSERT(preMatched); + length = prefixReg.cap(1).length(); + } + p_cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, - level); + length); p_cursor.removeSelectedText(); } } // Insert titleMark + " " at the front of the block. - if (needInsert) { + if (p_level > 0 && needInsert) { // Remove the spaces at front. // insertText() will remove the selection. moveCursorFirstNonSpaceCharacter(p_cursor, QTextCursor::KeepAnchor); diff --git a/src/utils/veditutils.h b/src/utils/veditutils.h index ce4eebd6..47ae97ac 100644 --- a/src/utils/veditutils.h +++ b/src/utils/veditutils.h @@ -151,6 +151,7 @@ public: // Insert title Mark at level @p_level in front of block @p_block // If there already exists title marks, remove it first. // Move cursor at the end of the block after insertion. + // If @p_level is 0, remove the title mark. static void insertTitleMark(QTextCursor &p_cursor, const QTextBlock &p_block, int p_level); diff --git a/src/vmdeditoperations.cpp b/src/vmdeditoperations.cpp index b75b9f2c..4018a596 100644 --- a/src/vmdeditoperations.cpp +++ b/src/vmdeditoperations.cpp @@ -219,10 +219,11 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event) case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: + case Qt::Key_7: { if (modifiers == Qt::ControlModifier) { // Ctrl + : insert title at level . - if (insertTitle(key - Qt::Key_0)) { + if (insertTitle(key == Qt::Key_7 ? 0 : key - Qt::Key_0)) { p_event->accept(); ret = true; goto exit; @@ -728,18 +729,32 @@ void VMdEditOperations::decorateBold() cursor.insertText("**"); } else { // Insert **** and place cursor in the middle. - // Or if there are two * after current cursor, just skip them. + // Or if there are two * after current cursor, just skip them or delete + // them if four * appear. int pos = cursor.positionInBlock(); bool hasStars = false; + bool emptyMarkers = false; QString text = cursor.block().text(); if (pos <= text.size() - 2) { if (text[pos] == '*' && text[pos + 1] == '*') { hasStars = true; + + if (pos >= 2 + && text[pos - 1] == '*' + && text[pos - 2] == '*') { + emptyMarkers = true; + } } } if (hasStars) { - cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); + if (emptyMarkers) { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, 2); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 4); + cursor.removeSelectedText(); + } else { + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); + } } else { cursor.insertText("****"); cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2); @@ -765,18 +780,31 @@ void VMdEditOperations::decorateItalic() cursor.insertText("*"); } else { // Insert ** and place cursor in the middle. - // Or if there are one * after current cursor, just skip it. + // Or if there are one * after current cursor, just skip them or delete + // them if two * appear. int pos = cursor.positionInBlock(); bool hasStar = false; + bool emptyMarkers = false; QString text = cursor.block().text(); if (pos <= text.size() - 1) { - if (text[pos] == '*') { + if (text[pos] == '*' + && (pos == text.size() - 1 || text[pos + 1] != '*')) { hasStar = true; + + if (pos >= 1 && text[pos - 1] == '*') { + emptyMarkers = true; + } } } if (hasStar) { - cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1); + if (emptyMarkers) { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, 1); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); + cursor.removeSelectedText(); + } else { + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1); + } } else { cursor.insertText("**"); cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1); @@ -802,18 +830,30 @@ void VMdEditOperations::decorateInlineCode() cursor.insertText("`"); } else { // Insert `` and place cursor in the middle. - // Or if there are one ` after current cursor, just skip it. + // Or if there are one ` after current cursor, just skip them or delete + // them if two ` appear. int pos = cursor.positionInBlock(); bool hasBackquote = false; + bool emptyMarkers = false; QString text = cursor.block().text(); if (pos <= text.size() - 1) { if (text[pos] == '`') { hasBackquote = true; + + if (pos >= 1 && text[pos - 1] == '`') { + emptyMarkers = true; + } } } if (hasBackquote) { - cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1); + if (emptyMarkers) { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, 1); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 2); + cursor.removeSelectedText(); + } else { + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 1); + } } else { cursor.insertText("``"); cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 1); @@ -857,22 +897,32 @@ void VMdEditOperations::decorateCodeBlock() || state == HighlightBlockState::CodeBlockStart || state == HighlightBlockState::CodeBlockEnd) { // Find the block end. - while (block.isValid()) { - if (block.userState() == HighlightBlockState::CodeBlockEnd) { + QTextBlock endBlock = block; + while (endBlock.isValid()) { + if (endBlock.userState() == HighlightBlockState::CodeBlockEnd) { break; } - block = block.next(); + endBlock = endBlock.next(); } - if (block.isValid()) { + if (endBlock.isValid()) { // It is CodeBlockEnd. - cursor.setPosition(block.position()); - if (block.next().isValid()) { - cursor.movePosition(QTextCursor::NextBlock); - cursor.movePosition(QTextCursor::StartOfBlock); + if (endBlock.previous().isValid() + && endBlock.previous().userState() == HighlightBlockState::CodeBlockStart) { + // Delete empty code blocks. + cursor.setPosition(endBlock.previous().position()); + cursor.movePosition(QTextCursor::NextBlock, QTextCursor::KeepAnchor); + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + cursor.removeSelectedText(); } else { - cursor.movePosition(QTextCursor::EndOfBlock); + cursor.setPosition(endBlock.position()); + if (endBlock.next().isValid()) { + cursor.movePosition(QTextCursor::NextBlock); + cursor.movePosition(QTextCursor::StartOfBlock); + } else { + cursor.movePosition(QTextCursor::EndOfBlock); + } } } else { // Reach the end of the document. @@ -919,18 +969,32 @@ void VMdEditOperations::decorateStrikethrough() cursor.insertText("~~"); } else { // Insert ~~~~ and place cursor in the middle. - // Or if there are one ~~ after current cursor, just skip it. + // Or if there are one ~~ after current cursor, just skip it or delete + // it if for ~ appear. int pos = cursor.positionInBlock(); bool hasStrikethrough = false; + bool emptyMarkers = false; QString text = cursor.block().text(); if (pos <= text.size() - 2) { if (text[pos] == '~' && text[pos + 1] == '~') { hasStrikethrough = true; + + if (pos >= 2 + && text[pos - 1] == '~' + && text[pos - 2] == '~') { + emptyMarkers = true; + } } } if (hasStrikethrough) { - cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); + if (emptyMarkers) { + cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::MoveAnchor, 2); + cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, 4); + cursor.removeSelectedText(); + } else { + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, 2); + } } else { cursor.insertText("~~~~"); cursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2); diff --git a/src/vmdeditoperations.h b/src/vmdeditoperations.h index ae88c360..b9f9a515 100644 --- a/src/vmdeditoperations.h +++ b/src/vmdeditoperations.h @@ -58,6 +58,7 @@ private: // Insert title of level @p_level. // Will detect if current block already has some leading #s. If yes, // will delete it and insert the correct #s. + // @p_level: 0 to cancel title. bool insertTitle(int p_level); // Change the sequence number of a list block.