mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
refine auto indent and auto list
1. Enter will cancel the auto indent and auto list; 2. Tab/Shift+Tab will increase or descrease the indentation of auto list;
This commit is contained in:
parent
177e5495d8
commit
f1c101b1d8
@ -27,7 +27,7 @@ extern VConfigManager vconfig;
|
|||||||
const QString VMdEditOperations::c_defaultImageTitle = "image";
|
const QString VMdEditOperations::c_defaultImageTitle = "image";
|
||||||
|
|
||||||
VMdEditOperations::VMdEditOperations(VEdit *p_editor, VFile *p_file)
|
VMdEditOperations::VMdEditOperations(VEdit *p_editor, VFile *p_file)
|
||||||
: VEditOperations(p_editor, p_file)
|
: VEditOperations(p_editor, p_file), m_autoIndentPos(-1)
|
||||||
{
|
{
|
||||||
m_pendingTimer = new QTimer(this);
|
m_pendingTimer = new QTimer(this);
|
||||||
m_pendingTimer->setSingleShot(true);
|
m_pendingTimer->setSingleShot(true);
|
||||||
@ -176,13 +176,17 @@ bool VMdEditOperations::shouldTriggerVimMode(QKeyEvent *p_event)
|
|||||||
|
|
||||||
bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
|
int key = p_event->key();
|
||||||
|
int modifiers = p_event->modifiers();
|
||||||
|
|
||||||
if (shouldTriggerVimMode(p_event)) {
|
if (shouldTriggerVimMode(p_event)) {
|
||||||
if (handleKeyPressVim(p_event)) {
|
if (handleKeyPressVim(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int modifiers = p_event->modifiers();
|
switch (key) {
|
||||||
switch (p_event->key()) {
|
|
||||||
case Qt::Key_1:
|
case Qt::Key_1:
|
||||||
case Qt::Key_2:
|
case Qt::Key_2:
|
||||||
case Qt::Key_3:
|
case Qt::Key_3:
|
||||||
@ -192,9 +196,10 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
{
|
{
|
||||||
if (modifiers == (Qt::ControlModifier | Qt::AltModifier)) {
|
if (modifiers == (Qt::ControlModifier | Qt::AltModifier)) {
|
||||||
// Ctrl + Alt + <N>: insert title at level <N>.
|
// Ctrl + Alt + <N>: insert title at level <N>.
|
||||||
if (insertTitle(p_event->key() - Qt::Key_0)) {
|
if (insertTitle(key - Qt::Key_0)) {
|
||||||
p_event->accept();
|
p_event->accept();
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -203,7 +208,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_Tab:
|
case Qt::Key_Tab:
|
||||||
{
|
{
|
||||||
if (handleKeyTab(p_event)) {
|
if (handleKeyTab(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -211,7 +217,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_Backtab:
|
case Qt::Key_Backtab:
|
||||||
{
|
{
|
||||||
if (handleKeyBackTab(p_event)) {
|
if (handleKeyBackTab(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -219,7 +226,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_B:
|
case Qt::Key_B:
|
||||||
{
|
{
|
||||||
if (handleKeyB(p_event)) {
|
if (handleKeyB(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -227,7 +235,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_D:
|
case Qt::Key_D:
|
||||||
{
|
{
|
||||||
if (handleKeyD(p_event)) {
|
if (handleKeyD(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -235,7 +244,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_H:
|
case Qt::Key_H:
|
||||||
{
|
{
|
||||||
if (handleKeyH(p_event)) {
|
if (handleKeyH(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -243,7 +253,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_I:
|
case Qt::Key_I:
|
||||||
{
|
{
|
||||||
if (handleKeyI(p_event)) {
|
if (handleKeyI(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -251,7 +262,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_O:
|
case Qt::Key_O:
|
||||||
{
|
{
|
||||||
if (handleKeyO(p_event)) {
|
if (handleKeyO(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -259,7 +271,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_U:
|
case Qt::Key_U:
|
||||||
{
|
{
|
||||||
if (handleKeyU(p_event)) {
|
if (handleKeyU(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -267,7 +280,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_W:
|
case Qt::Key_W:
|
||||||
{
|
{
|
||||||
if (handleKeyW(p_event)) {
|
if (handleKeyW(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -275,7 +289,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_BracketLeft:
|
case Qt::Key_BracketLeft:
|
||||||
{
|
{
|
||||||
if (handleKeyBracketLeft(p_event)) {
|
if (handleKeyBracketLeft(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -283,7 +298,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_Escape:
|
case Qt::Key_Escape:
|
||||||
{
|
{
|
||||||
if (handleKeyEsc(p_event)) {
|
if (handleKeyEsc(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -291,7 +307,8 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
case Qt::Key_Return:
|
case Qt::Key_Return:
|
||||||
{
|
{
|
||||||
if (handleKeyReturn(p_event)) {
|
if (handleKeyReturn(p_event)) {
|
||||||
return true;
|
ret = true;
|
||||||
|
goto exit;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -301,7 +318,13 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
exit:
|
||||||
|
// Qt::Key_Return, Qt::Key_Tab and Qt::Key_Backtab will handle m_autoIndentPos.
|
||||||
|
if (key != Qt::Key_Return && key != Qt::Key_Tab && key != Qt::Key_Backtab &&
|
||||||
|
key != Qt::Key_Shift) {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let Ctrl+[ behave exactly like ESC.
|
// Let Ctrl+[ behave exactly like ESC.
|
||||||
@ -342,8 +365,9 @@ bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event)
|
|||||||
|
|
||||||
if (p_event->modifiers() == Qt::NoModifier) {
|
if (p_event->modifiers() == Qt::NoModifier) {
|
||||||
QTextCursor cursor = m_editor->textCursor();
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
cursor.beginEditBlock();
|
|
||||||
if (cursor.hasSelection()) {
|
if (cursor.hasSelection()) {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
|
cursor.beginEditBlock();
|
||||||
// Indent each selected line.
|
// Indent each selected line.
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
||||||
QTextBlock endBlock = doc->findBlock(cursor.selectionEnd());
|
QTextBlock endBlock = doc->findBlock(cursor.selectionEnd());
|
||||||
@ -358,12 +382,23 @@ bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event)
|
|||||||
}
|
}
|
||||||
block = block.next();
|
block = block.next();
|
||||||
}
|
}
|
||||||
|
cursor.endEditBlock();
|
||||||
} else {
|
} else {
|
||||||
// Just insert "tab".
|
// If it is a Tab key following auto list, increase the indent level.
|
||||||
insertTextAtCurPos(text);
|
QTextBlock block = cursor.block();
|
||||||
|
if (m_autoIndentPos == cursor.position() && isListBlock(block)) {
|
||||||
|
QTextCursor blockCursor(block);
|
||||||
|
blockCursor.insertText(text);
|
||||||
|
// Change m_autoIndentPos to let it can be repeated.
|
||||||
|
m_autoIndentPos = m_editor->textCursor().position();
|
||||||
|
} else {
|
||||||
|
// Just insert "tab".
|
||||||
|
insertTextAtCurPos(text);
|
||||||
|
m_autoIndentPos = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cursor.endEditBlock();
|
|
||||||
} else {
|
} else {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
p_event->accept();
|
p_event->accept();
|
||||||
@ -373,12 +408,19 @@ bool VMdEditOperations::handleKeyTab(QKeyEvent *p_event)
|
|||||||
bool VMdEditOperations::handleKeyBackTab(QKeyEvent *p_event)
|
bool VMdEditOperations::handleKeyBackTab(QKeyEvent *p_event)
|
||||||
{
|
{
|
||||||
if (p_event->modifiers() != Qt::ShiftModifier) {
|
if (p_event->modifiers() != Qt::ShiftModifier) {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QTextDocument *doc = m_editor->document();
|
QTextDocument *doc = m_editor->document();
|
||||||
QTextCursor cursor = m_editor->textCursor();
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
QTextBlock block = doc->findBlock(cursor.selectionStart());
|
||||||
QTextBlock endBlock = doc->findBlock(cursor.selectionEnd());
|
QTextBlock endBlock = doc->findBlock(cursor.selectionEnd());
|
||||||
|
|
||||||
|
bool continueAutoIndent = false;
|
||||||
|
if (cursor.position() == m_autoIndentPos && isListBlock(block) &&
|
||||||
|
!cursor.hasSelection()) {
|
||||||
|
continueAutoIndent = true;
|
||||||
|
}
|
||||||
int endBlockNum = endBlock.blockNumber();
|
int endBlockNum = endBlock.blockNumber();
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
for (; block.isValid() && block.blockNumber() <= endBlockNum;
|
for (; block.isValid() && block.blockNumber() <= endBlockNum;
|
||||||
@ -411,6 +453,12 @@ bool VMdEditOperations::handleKeyBackTab(QKeyEvent *p_event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
|
|
||||||
|
if (continueAutoIndent) {
|
||||||
|
m_autoIndentPos = m_editor->textCursor().position();
|
||||||
|
} else {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
|
}
|
||||||
p_event->accept();
|
p_event->accept();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -644,26 +692,57 @@ bool VMdEditOperations::handleKeyEsc(QKeyEvent *p_event)
|
|||||||
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
bool VMdEditOperations::handleKeyReturn(QKeyEvent *p_event)
|
||||||
{
|
{
|
||||||
if (p_event->modifiers() & Qt::ControlModifier) {
|
if (p_event->modifiers() & Qt::ControlModifier) {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ret = false;
|
// See if we need to cancel auto indent.
|
||||||
|
if (m_autoIndentPos > -1) {
|
||||||
|
// Cancel the auto indent/list if the pos is the same and cursor is at
|
||||||
|
// the end of a block.
|
||||||
|
bool cancelAutoIndent = false;
|
||||||
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
|
QTextBlock block = cursor.block();
|
||||||
|
if (cursor.position() == m_autoIndentPos && !cursor.hasSelection()) {
|
||||||
|
if (isListBlock(block)) {
|
||||||
|
if (cursor.atBlockEnd()) {
|
||||||
|
cancelAutoIndent = true;
|
||||||
|
}
|
||||||
|
} else if (isSpaceToBlockStart(block, cursor.positionInBlock())) {
|
||||||
|
cancelAutoIndent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancelAutoIndent) {
|
||||||
|
m_autoIndentPos = -1;
|
||||||
|
deleteIndentAndListMark();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handled = false;
|
||||||
|
m_autoIndentPos = -1;
|
||||||
if (vconfig.getAutoIndent()) {
|
if (vconfig.getAutoIndent()) {
|
||||||
ret = true;
|
handled = true;
|
||||||
|
|
||||||
|
bool textInserted = false;
|
||||||
// Indent the new line as previous line.
|
// Indent the new line as previous line.
|
||||||
insertNewBlockWithIndent();
|
textInserted = insertNewBlockWithIndent();
|
||||||
|
|
||||||
// Continue the list from previous line.
|
// Continue the list from previous line.
|
||||||
if (vconfig.getAutoList()) {
|
if (vconfig.getAutoList()) {
|
||||||
insertListMarkAsPreviousLine();
|
textInserted = insertListMarkAsPreviousLine() || textInserted;
|
||||||
|
}
|
||||||
|
if (textInserted) {
|
||||||
|
m_autoIndentPos = m_editor->textCursor().position();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMdEditOperations::insertNewBlockWithIndent()
|
bool VMdEditOperations::insertNewBlockWithIndent()
|
||||||
{
|
{
|
||||||
QTextCursor cursor = m_editor->textCursor();
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
cursor.removeSelectedText();
|
cursor.removeSelectedText();
|
||||||
@ -674,13 +753,18 @@ void VMdEditOperations::insertNewBlockWithIndent()
|
|||||||
V_ASSERT(regExp.captureCount() == 1);
|
V_ASSERT(regExp.captureCount() == 1);
|
||||||
QString leadingSpaces = regExp.capturedTexts()[1];
|
QString leadingSpaces = regExp.capturedTexts()[1];
|
||||||
cursor.insertBlock();
|
cursor.insertBlock();
|
||||||
cursor.insertText(leadingSpaces);
|
if (!leadingSpaces.isEmpty()) {
|
||||||
|
cursor.insertText(leadingSpaces);
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
m_editor->setTextCursor(cursor);
|
m_editor->setTextCursor(cursor);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VMdEditOperations::insertListMarkAsPreviousLine()
|
bool VMdEditOperations::insertListMarkAsPreviousLine()
|
||||||
{
|
{
|
||||||
|
bool ret = false;
|
||||||
QTextCursor cursor = m_editor->textCursor();
|
QTextCursor cursor = m_editor->textCursor();
|
||||||
QTextBlock block = cursor.block();
|
QTextBlock block = cursor.block();
|
||||||
QTextBlock preBlock = block.previous();
|
QTextBlock preBlock = block.previous();
|
||||||
@ -688,6 +772,7 @@ void VMdEditOperations::insertListMarkAsPreviousLine()
|
|||||||
QRegExp regExp("^\\s*(-|\\d+\\.)\\s");
|
QRegExp regExp("^\\s*(-|\\d+\\.)\\s");
|
||||||
int regIdx = regExp.indexIn(text);
|
int regIdx = regExp.indexIn(text);
|
||||||
if (regIdx != -1) {
|
if (regIdx != -1) {
|
||||||
|
ret = true;
|
||||||
V_ASSERT(regExp.captureCount() == 1);
|
V_ASSERT(regExp.captureCount() == 1);
|
||||||
cursor.beginEditBlock();
|
cursor.beginEditBlock();
|
||||||
QString markText = regExp.capturedTexts()[1];
|
QString markText = regExp.capturedTexts()[1];
|
||||||
@ -706,6 +791,34 @@ void VMdEditOperations::insertListMarkAsPreviousLine()
|
|||||||
cursor.endEditBlock();
|
cursor.endEditBlock();
|
||||||
m_editor->setTextCursor(cursor);
|
m_editor->setTextCursor(cursor);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VMdEditOperations::isListBlock(const QTextBlock &p_block)
|
||||||
|
{
|
||||||
|
QString text = p_block.text();
|
||||||
|
QRegExp regExp("^\\s*(-|\\d+\\.)\\s");
|
||||||
|
int regIdx = regExp.indexIn(text);
|
||||||
|
return regIdx != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::handleKeyPressVim(QKeyEvent *p_event)
|
bool VMdEditOperations::handleKeyPressVim(QKeyEvent *p_event)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QTextBlock>
|
||||||
#include "veditoperations.h"
|
#include "veditoperations.h"
|
||||||
|
|
||||||
class QTimer;
|
class QTimer;
|
||||||
@ -46,10 +47,17 @@ private:
|
|||||||
int keySeqToNumber(const QList<QString> &p_seq);
|
int keySeqToNumber(const QList<QString> &p_seq);
|
||||||
bool suffixNumAllowed(const QList<QString> &p_seq);
|
bool suffixNumAllowed(const QList<QString> &p_seq);
|
||||||
bool insertTitle(int p_level);
|
bool insertTitle(int p_level);
|
||||||
void insertNewBlockWithIndent();
|
bool insertNewBlockWithIndent();
|
||||||
void insertListMarkAsPreviousLine();
|
bool insertListMarkAsPreviousLine();
|
||||||
|
void deleteIndentAndListMark();
|
||||||
|
bool isListBlock(const QTextBlock &p_block);
|
||||||
|
// If the start of @p_block to postition @p_posInBlock are spaces.
|
||||||
|
bool isSpaceToBlockStart(const QTextBlock &p_block, int p_posInBlock);
|
||||||
|
|
||||||
QTimer *m_pendingTimer;
|
QTimer *m_pendingTimer;
|
||||||
|
// The cursor position after auto indent or auto list.
|
||||||
|
// It will be -1 if last key press do not trigger the auto indent or auto list.
|
||||||
|
int m_autoIndentPos;
|
||||||
|
|
||||||
static const QString c_defaultImageTitle;
|
static const QString c_defaultImageTitle;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user