mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 13:59:52 +08:00
support Insert Code Block tool bar button
Ctrl+M to insert a code block.
This commit is contained in:
parent
e66b70b6ff
commit
30dfc24a28
@ -49,13 +49,17 @@ Save current changes and exit edit mode.
|
||||
|
||||
#### Text Editing
|
||||
- `Ctrl+B`
|
||||
Insert bold. Press `Ctrl+B` again to exit. Current selected text will be changed to bold if exist.
|
||||
Insert bold. Press `Ctrl+B` again to exit. Current selected text will be changed to bold if exists.
|
||||
- `Ctrl+I`
|
||||
Insert italic. Press `Ctrl+I` again to exit. Current selected text will be changed to italic if exist.
|
||||
Insert italic. Press `Ctrl+I` again to exit. Current selected text will be changed to italic if exists.
|
||||
- `Ctrl+D`
|
||||
Insert strikethrought. Press `Ctrl+D` again to exit. Current selected text will be changed to strikethrough if exist.
|
||||
Insert strikethrought. Press `Ctrl+D` again to exit. Current selected text will be changed to strikethrough if exists.
|
||||
- `Ctrl+O`
|
||||
Insert inline code. Press `Ctrl+O` again to exit. Current selected text will be changed to inline code if exist.
|
||||
Insert inline code. Press `Ctrl+O` again to exit. Current selected text will be changed to inline code if exists.
|
||||
- `Ctrl+M`
|
||||
Insert fenced code block. Press `Ctrl+M` again to exit. Current selected text will be wrapped into a code block if exists.
|
||||
- `Ctrl+L`
|
||||
Insert link.
|
||||
- `Ctrl+H`
|
||||
Backspace. Delete a character backward.
|
||||
- `Ctrl+W`
|
||||
@ -63,7 +67,7 @@ Delete all the characters from current cursor to the first space backward.
|
||||
- `Ctrl+U`
|
||||
Delete all the characters from current cursor to the beginning of current line.
|
||||
- `Ctrl+<Num>`
|
||||
Insert title at level `<Num>`. `<Num>` should be 1 to 6. Current selected text will be changed to title if exist.
|
||||
Insert title at level `<Num>`. `<Num>` should be 1 to 6. Current selected text will be changed to title if exists.
|
||||
- `Tab`/`Shift+Tab`
|
||||
Increase or decrease the indentation. If any text is selected, the indentation will operate on all these selected lines.
|
||||
- `Shift+Enter`
|
||||
|
@ -56,6 +56,10 @@
|
||||
插入删除线;再次按`Ctrl+D`退出。如果已经选择文本,则将当前选择文本改为删除线。
|
||||
- `Ctrl+O`
|
||||
插入行内代码;再次按`Ctrl+O`退出。如果已经选择文本,则将当前选择文本改为行内代码。
|
||||
- `Ctrl+M`
|
||||
插入代码块;再次按`Ctrl+M`退出。如果已经选择文本,则将当前选择文本嵌入到代码块中。
|
||||
- `Ctrl+L`
|
||||
插入链接。
|
||||
- `Ctrl+H`
|
||||
退格键,向前删除一个字符。
|
||||
- `Ctrl+W`
|
||||
|
6
src/resources/icons/code_block.svg
Normal file
6
src/resources/icons/code_block.svg
Normal file
@ -0,0 +1,6 @@
|
||||
<svg width="512" height="512" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<title>Layer 1</title>
|
||||
<text style="cursor: move;" fill="#000000" stroke-width="0" x="-146.75684" y="248.49038" id="svg_4" font-size="24" font-family="serif" text-anchor="middle" xml:space="preserve" font-weight="bold" transform="matrix(16.72881317138672,0,0,16.72881317138672,2707.567729830742,-3759.186347961426) " stroke="#000000">#</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 470 B |
@ -48,7 +48,7 @@ bool VEditUtils::insertBlockWithIndent(QTextCursor &p_cursor)
|
||||
{
|
||||
V_ASSERT(!p_cursor.hasSelection());
|
||||
p_cursor.insertBlock();
|
||||
return indentBlockAsPreviousBlock(p_cursor);
|
||||
return indentBlockAsBlock(p_cursor, false);
|
||||
}
|
||||
|
||||
bool VEditUtils::insertListMarkAsPreviousBlock(QTextCursor &p_cursor)
|
||||
@ -85,21 +85,16 @@ bool VEditUtils::insertListMarkAsPreviousBlock(QTextCursor &p_cursor)
|
||||
|
||||
}
|
||||
|
||||
bool VEditUtils::indentBlockAsPreviousBlock(QTextCursor &p_cursor)
|
||||
bool VEditUtils::indentBlockAsBlock(QTextCursor &p_cursor, bool p_next)
|
||||
{
|
||||
bool changed = false;
|
||||
QTextBlock block = p_cursor.block();
|
||||
if (block.blockNumber() == 0) {
|
||||
// The first block.
|
||||
QTextBlock refBlock = p_next ? block.next() : block.previous();
|
||||
if (!refBlock.isValid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextBlock preBlock = block.previous();
|
||||
QString text = preBlock.text();
|
||||
QRegExp regExp("(^\\s*)");
|
||||
regExp.indexIn(text);
|
||||
V_ASSERT(regExp.captureCount() == 1);
|
||||
QString leadingSpaces = regExp.capturedTexts()[1];
|
||||
QString leadingSpaces = fetchIndentSpaces(refBlock);
|
||||
|
||||
moveCursorFirstNonSpaceCharacter(p_cursor, QTextCursor::MoveAnchor);
|
||||
if (!p_cursor.atBlockStart()) {
|
||||
@ -789,3 +784,30 @@ void VEditUtils::findCurrentWORD(const QTextCursor &p_cursor,
|
||||
p_end += block.position();
|
||||
}
|
||||
|
||||
QString VEditUtils::fetchIndentSpaces(const QTextBlock &p_block)
|
||||
{
|
||||
QString text = p_block.text();
|
||||
QRegExp regExp("(^\\s*)");
|
||||
regExp.indexIn(text);
|
||||
Q_ASSERT(regExp.captureCount() == 1);
|
||||
return regExp.capturedTexts()[1];
|
||||
}
|
||||
|
||||
void VEditUtils::insertBlock(QTextCursor &p_cursor,
|
||||
bool p_above)
|
||||
{
|
||||
p_cursor.movePosition(p_above ? QTextCursor::StartOfBlock
|
||||
: QTextCursor::EndOfBlock,
|
||||
QTextCursor::MoveAnchor,
|
||||
1);
|
||||
|
||||
p_cursor.insertBlock();
|
||||
|
||||
if (p_above) {
|
||||
p_cursor.movePosition(QTextCursor::PreviousBlock,
|
||||
QTextCursor::MoveAnchor,
|
||||
1);
|
||||
}
|
||||
|
||||
p_cursor.movePosition(QTextCursor::EndOfBlock);
|
||||
}
|
||||
|
@ -24,10 +24,11 @@ public:
|
||||
// Need to call setTextCursor() to make it take effect.
|
||||
static void moveCursorFirstNonSpaceCharacter(QTextCursor &p_cursor,
|
||||
QTextCursor::MoveMode p_mode);
|
||||
// Indent current block as previous block.
|
||||
// Indent current block as next/previous block.
|
||||
// Return true if some changes have been made.
|
||||
// @p_cursor will be placed at the position after inserting leading spaces.
|
||||
static bool indentBlockAsPreviousBlock(QTextCursor &p_cursor);
|
||||
// @p_next: indent as next block or previous block.
|
||||
static bool indentBlockAsBlock(QTextCursor &p_cursor, bool p_next);
|
||||
|
||||
// Returns true if two blocks has the same indent.
|
||||
static bool hasSameIndent(const QTextBlock &p_blocka, const QTextBlock &p_blockb);
|
||||
@ -157,6 +158,14 @@ public:
|
||||
int &p_start,
|
||||
int &p_end);
|
||||
|
||||
// Return the leading spaces of @p_block.
|
||||
static QString fetchIndentSpaces(const QTextBlock &p_block);
|
||||
|
||||
// Insert a block above/below current block. Move the cursor to the start of
|
||||
// the new block after insertion.
|
||||
static void insertBlock(QTextCursor &p_cursor,
|
||||
bool p_above);
|
||||
|
||||
private:
|
||||
VEditUtils() {}
|
||||
};
|
||||
|
@ -296,7 +296,7 @@ static void insertChangeBlockAfterDeletion(QTextCursor &p_cursor, int p_deletion
|
||||
}
|
||||
|
||||
if (g_config->getAutoIndent()) {
|
||||
VEditUtils::indentBlockAsPreviousBlock(p_cursor);
|
||||
VEditUtils::indentBlockAsBlock(p_cursor, false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -911,7 +911,7 @@ bool VVim::handleKeyPressEvent(int key, int modifiers, int *p_autoIndentPos)
|
||||
|
||||
bool textInserted = false;
|
||||
if (g_config->getAutoIndent()) {
|
||||
textInserted = VEditUtils::indentBlockAsPreviousBlock(cursor);
|
||||
textInserted = VEditUtils::indentBlockAsBlock(cursor, false);
|
||||
if (g_config->getAutoList()) {
|
||||
textInserted = VEditUtils::insertListMarkAsPreviousBlock(cursor)
|
||||
|| textInserted;
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
class QKeyEvent;
|
||||
class VNavigationMode;
|
||||
class QShortcut;
|
||||
|
||||
// void func(void *p_target, void *p_data);
|
||||
typedef std::function<void(void *, void *)> CaptainFunc;
|
||||
|
@ -52,12 +52,16 @@ namespace DirConfig
|
||||
|
||||
static const QString c_emptyHeaderName = "[EMPTY]";
|
||||
|
||||
enum class TextDecoration { None,
|
||||
Bold,
|
||||
Italic,
|
||||
Underline,
|
||||
Strikethrough,
|
||||
InlineCode };
|
||||
enum class TextDecoration
|
||||
{
|
||||
None,
|
||||
Bold,
|
||||
Italic,
|
||||
Underline,
|
||||
Strikethrough,
|
||||
InlineCode,
|
||||
CodeBlock
|
||||
};
|
||||
|
||||
enum FindOption
|
||||
{
|
||||
|
@ -463,6 +463,21 @@ void VMainWindow::initEditToolBar(QSize p_iconSize)
|
||||
|
||||
m_editToolBar->addAction(inlineCodeAct);
|
||||
|
||||
QAction *codeBlockAct = new QAction(QIcon(":/resources/icons/code_block.svg"),
|
||||
tr("Code Block (Ctrl+M)"),
|
||||
this);
|
||||
codeBlockAct->setStatusTip(tr("Insert fenced code block text or wrap selected text into a fenced code block"));
|
||||
connect(codeBlockAct, &QAction::triggered,
|
||||
this, [this](){
|
||||
if (m_curTab) {
|
||||
m_curTab->decorateText(TextDecoration::CodeBlock);
|
||||
}
|
||||
});
|
||||
|
||||
m_editToolBar->addAction(codeBlockAct);
|
||||
|
||||
m_editToolBar->addSeparator();
|
||||
|
||||
// Insert link.
|
||||
QAction *insetLinkAct = new QAction(QIcon(":/resources/icons/link.svg"),
|
||||
tr("Insert Link (Ctrl+L)"), this);
|
||||
|
@ -289,6 +289,17 @@ bool VMdEditOperations::handleKeyPressEvent(QKeyEvent *p_event)
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_M:
|
||||
{
|
||||
if (modifiers == Qt::ControlModifier) {
|
||||
decorateCodeBlock();
|
||||
p_event->accept();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::Key_O:
|
||||
{
|
||||
if (modifiers == Qt::ControlModifier) {
|
||||
@ -684,6 +695,10 @@ void VMdEditOperations::decorateText(TextDecoration p_decoration)
|
||||
decorateInlineCode();
|
||||
break;
|
||||
|
||||
case TextDecoration::CodeBlock:
|
||||
decorateCodeBlock();
|
||||
break;
|
||||
|
||||
default:
|
||||
validDecoration = false;
|
||||
qDebug() << "decoration" << (int)p_decoration << "is not implemented yet";
|
||||
@ -807,6 +822,86 @@ void VMdEditOperations::decorateInlineCode()
|
||||
m_editor->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void VMdEditOperations::decorateCodeBlock()
|
||||
{
|
||||
const QString marker("```");
|
||||
|
||||
QTextCursor cursor = m_editor->textCursor();
|
||||
cursor.beginEditBlock();
|
||||
if (cursor.hasSelection()) {
|
||||
// Insert ``` around the selected text.
|
||||
int start = cursor.selectionStart();
|
||||
int end = cursor.selectionEnd();
|
||||
|
||||
QString indentation = VEditUtils::fetchIndentSpaces(cursor.block());
|
||||
|
||||
// Insert the end marker first.
|
||||
cursor.setPosition(end, QTextCursor::MoveAnchor);
|
||||
VEditUtils::insertBlock(cursor, false);
|
||||
VEditUtils::indentBlock(cursor, indentation);
|
||||
cursor.insertText(marker);
|
||||
|
||||
// Insert the start marker.
|
||||
cursor.setPosition(start, QTextCursor::MoveAnchor);
|
||||
VEditUtils::insertBlock(cursor, true);
|
||||
VEditUtils::indentBlock(cursor, indentation);
|
||||
cursor.insertText(marker);
|
||||
} else {
|
||||
// Insert ``` ``` and place cursor after the first marker.
|
||||
// Or if current block or next block is ```, we will skip it.
|
||||
QTextBlock block = cursor.block();
|
||||
int state = block.userState();
|
||||
if (state == HighlightBlockState::CodeBlock
|
||||
|| state == HighlightBlockState::CodeBlockStart
|
||||
|| state == HighlightBlockState::CodeBlockEnd) {
|
||||
// Find the block end.
|
||||
while (block.isValid()) {
|
||||
if (block.userState() == HighlightBlockState::CodeBlockEnd) {
|
||||
break;
|
||||
}
|
||||
|
||||
block = block.next();
|
||||
}
|
||||
|
||||
if (block.isValid()) {
|
||||
// It is CodeBlockEnd.
|
||||
cursor.setPosition(block.position());
|
||||
if (block.next().isValid()) {
|
||||
cursor.movePosition(QTextCursor::NextBlock);
|
||||
cursor.movePosition(QTextCursor::StartOfBlock);
|
||||
} else {
|
||||
cursor.movePosition(QTextCursor::EndOfBlock);
|
||||
}
|
||||
} else {
|
||||
// Reach the end of the document.
|
||||
cursor.movePosition(QTextCursor::End);
|
||||
}
|
||||
} else {
|
||||
bool insertInline = false;
|
||||
if (!cursor.atBlockEnd()) {
|
||||
cursor.insertBlock();
|
||||
cursor.movePosition(QTextCursor::PreviousBlock);
|
||||
} else if (cursor.atBlockStart()) {
|
||||
insertInline = true;
|
||||
}
|
||||
|
||||
if (!insertInline) {
|
||||
VEditUtils::insertBlock(cursor, false);
|
||||
VEditUtils::indentBlockAsBlock(cursor, false);
|
||||
}
|
||||
|
||||
cursor.insertText(marker);
|
||||
|
||||
VEditUtils::insertBlock(cursor, true);
|
||||
VEditUtils::indentBlockAsBlock(cursor, true);
|
||||
cursor.insertText(marker);
|
||||
}
|
||||
}
|
||||
|
||||
cursor.endEditBlock();
|
||||
m_editor->setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void VMdEditOperations::decorateStrikethrough()
|
||||
{
|
||||
QTextCursor cursor = m_editor->textCursor();
|
||||
|
@ -72,6 +72,9 @@ private:
|
||||
// Insert inline-code marker or set selected text inline-coded.
|
||||
void decorateInlineCode();
|
||||
|
||||
// Insert inline-code marker or set selected text inline-coded.
|
||||
void decorateCodeBlock();
|
||||
|
||||
// Insert strikethrough marker or set selected text strikethrough.
|
||||
void decorateStrikethrough();
|
||||
|
||||
|
@ -133,5 +133,6 @@
|
||||
<file>resources/icons/compact_mode.svg</file>
|
||||
<file>resources/icons/heading_sequence.svg</file>
|
||||
<file>resources/icons/link.svg</file>
|
||||
<file>resources/icons/code_block.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
x
Reference in New Issue
Block a user