PegParser: support ~~~ as fenced code block

This commit is contained in:
Le Tan 2018-11-22 20:31:47 +08:00
parent 026f3a6535
commit 28eb48cc2e
10 changed files with 727 additions and 626 deletions

File diff suppressed because it is too large Load Diff

View File

@ -25,8 +25,8 @@ PegHighlighterResult::PegHighlighterResult()
m_codeBlockTimeStamp(0), m_codeBlockTimeStamp(0),
m_numOfCodeBlockHighlightsToRecv(0) m_numOfCodeBlockHighlightsToRecv(0)
{ {
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp); m_codeBlockStartExp = QRegularExpression(VUtils::c_fencedCodeBlockStartRegExp);
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp); m_codeBlockEndExp = QRegularExpression(VUtils::c_fencedCodeBlockEndRegExp);
} }
PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg, PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
@ -37,8 +37,8 @@ PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg,
m_codeBlockTimeStamp(0), m_codeBlockTimeStamp(0),
m_numOfCodeBlockHighlightsToRecv(0) m_numOfCodeBlockHighlightsToRecv(0)
{ {
m_codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp); m_codeBlockStartExp = QRegularExpression(VUtils::c_fencedCodeBlockStartRegExp);
m_codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp); m_codeBlockEndExp = QRegularExpression(VUtils::c_fencedCodeBlockEndRegExp);
parseBlocksHighlights(m_blocksHighlights, p_peg, p_result); parseBlocksHighlights(m_blocksHighlights, p_peg, p_result);
@ -215,6 +215,7 @@ void PegHighlighterResult::parseFencedCodeBlocks(const PegMarkdownHighlighter *p
const QTextDocument *doc = p_peg->getDocument(); const QTextDocument *doc = p_peg->getDocument();
VCodeBlock item; VCodeBlock item;
bool inBlock = false; bool inBlock = false;
QString marker;
for (auto it = regs.begin(); it != regs.end(); ++it) { for (auto it = regs.begin(); it != regs.end(); ++it) {
QTextBlock block = doc->findBlock(it.value().m_startPos); QTextBlock block = doc->findBlock(it.value().m_startPos);
int lastBlock = doc->findBlock(it.value().m_endPos - 1).blockNumber(); int lastBlock = doc->findBlock(it.value().m_endPos - 1).blockNumber();
@ -232,10 +233,12 @@ void PegHighlighterResult::parseFencedCodeBlocks(const PegMarkdownHighlighter *p
QString text = block.text(); QString text = block.text();
if (inBlock) { if (inBlock) {
item.m_text = item.m_text + "\n" + text; item.m_text = item.m_text + "\n" + text;
int idx = m_codeBlockEndExp.indexIn(text); auto match = m_codeBlockEndExp.match(text);
if (idx >= 0) { if (match.hasMatch() && marker == match.captured(2)) {
// End block. // End block.
inBlock = false; inBlock = false;
marker.clear();
state = HighlightBlockState::CodeBlockEnd; state = HighlightBlockState::CodeBlockEnd;
item.m_endBlock = blockNumber; item.m_endBlock = blockNumber;
m_codeBlocks.append(item); m_codeBlocks.append(item);
@ -244,17 +247,17 @@ void PegHighlighterResult::parseFencedCodeBlocks(const PegMarkdownHighlighter *p
state = HighlightBlockState::CodeBlock; state = HighlightBlockState::CodeBlock;
} }
} else { } else {
int idx = m_codeBlockStartExp.indexIn(text); auto match = m_codeBlockStartExp.match(text);
if (idx >= 0) { if (match.hasMatch()) {
// Start block. // Start block.
inBlock = true; inBlock = true;
marker = match.captured(2);
state = HighlightBlockState::CodeBlockStart; state = HighlightBlockState::CodeBlockStart;
item.m_startBlock = blockNumber; item.m_startBlock = blockNumber;
item.m_startPos = block.position(); item.m_startPos = block.position();
item.m_text = text; item.m_text = text;
if (m_codeBlockStartExp.captureCount() == 2) { item.m_lang = match.captured(3).trimmed();
item.m_lang = m_codeBlockStartExp.capturedTexts()[2];
}
} }
} }

View File

@ -2,6 +2,7 @@
#define PEGHIGHLIGHTERRESULT_H #define PEGHIGHLIGHTERRESULT_H
#include <QSet> #include <QSet>
#include <QRegularExpression>
#include "vconstants.h" #include "vconstants.h"
#include "pegparser.h" #include "pegparser.h"
@ -114,8 +115,8 @@ private:
unsigned long p_end); unsigned long p_end);
#endif #endif
QRegExp m_codeBlockStartExp; QRegularExpression m_codeBlockStartExp;
QRegExp m_codeBlockEndExp; QRegularExpression m_codeBlockEndExp;
}; };
inline bool PegHighlighterResult::matched(TimeStamp p_timeStamp) const inline bool PegHighlighterResult::matched(TimeStamp p_timeStamp) const

View File

@ -607,10 +607,10 @@ void PegMarkdownHighlighter::updateAllBlocksUserState(const QSharedPointer<PegHi
case HighlightBlockState::CodeBlockStart: case HighlightBlockState::CodeBlockStart:
{ {
int startLeadingSpaces = 0; int startLeadingSpaces = 0;
QRegExp reg(VUtils::c_fencedCodeBlockStartRegExp); QRegularExpression reg(VUtils::c_fencedCodeBlockStartRegExp);
int idx = reg.indexIn(block.text()); auto match = reg.match(block.text());
if (idx >= 0) { if (match.hasMatch()) {
startLeadingSpaces = reg.capturedTexts()[1].size(); startLeadingSpaces = match.captured(1).size();
} }
blockData->setCodeBlockIndentation(startLeadingSpaces); blockData->setCodeBlockIndentation(startLeadingSpaces);

View File

@ -112,9 +112,13 @@ As VNote suggests:
This is a fenced code block. This is a fenced code block.
``` ```
~~~
This is another fenced code block.
~~~
**Notes**: **Notes**:
- `lang` is optional to specify the language of the code; - `lang` is optional to specify the language of the code; if not specified, VNote won't highlight the code;
### Diagrams ### Diagrams

View File

@ -113,9 +113,13 @@ As VNote suggests:
This is a fenced code block. This is a fenced code block.
``` ```
~~~
This is another fenced code block.
~~~
**注意** **注意**
- `lang`用于指定代码块的代码语言,可选; - `lang`用于指定代码块的代码语言,可选;如果不指定VNote不会尝试高亮代码
### 图表 ### 图表

View File

@ -258,7 +258,7 @@ smart_live_preview=3
insert_new_note_in_front=false insert_new_note_in_front=false
; Whether highlight matches in page when activating a search result item ; Whether highlight matches in page when activating a search result item
highlight_matches_in_page=true highlight_matches_in_page=false
; Incremental search in page ; Incremental search in page
find_incremental_search=true find_incremental_search=true

View File

@ -1130,9 +1130,16 @@ bool VEditUtils::isWordSeparator(QChar p_char)
QString VEditUtils::removeCodeBlockFence(const QString &p_text) QString VEditUtils::removeCodeBlockFence(const QString &p_text)
{ {
QString text = VCodeBlockHighlightHelper::unindentCodeBlock(p_text); QString text = VCodeBlockHighlightHelper::unindentCodeBlock(p_text);
Q_ASSERT(text.startsWith("```") && text.endsWith("```")); Q_ASSERT(text.startsWith("```") || text.startsWith("~~~"));
int idx = text.indexOf('\n') + 1; int idx = text.indexOf('\n') + 1;
return text.mid(idx, text.size() - idx - 3); int lidx = text.size() - 1;
// Trim spaces at the end.
while (lidx >= 0 && text[lidx].isSpace()) {
--lidx;
}
Q_ASSERT(text[lidx] == '`' || text[lidx] == '~');
return text.mid(idx, lidx + 1 - idx - 3);
} }
bool VEditUtils::isSpaceOrWordSeparator(QChar p_char) bool VEditUtils::isSpaceOrWordSeparator(QChar p_char)

View File

@ -61,9 +61,9 @@ const QString VUtils::c_linkRegExp = QString("\\[([^\\]]*)\\]"
const QString VUtils::c_fileNameRegExp = QString("(?:[^\\\\/:\\*\\?\"<>\\|\\s]| )*"); const QString VUtils::c_fileNameRegExp = QString("(?:[^\\\\/:\\*\\?\"<>\\|\\s]| )*");
const QString VUtils::c_fencedCodeBlockStartRegExp = QString("^(\\s*)```([^`\\s]*)\\s*[^`]*$"); const QString VUtils::c_fencedCodeBlockStartRegExp = QString("^(\\s*)([`~])\\2{2}((?:(?!\\2)[^\\r\\n])*)$");
const QString VUtils::c_fencedCodeBlockEndRegExp = QString("^(\\s*)```$"); const QString VUtils::c_fencedCodeBlockEndRegExp = QString("^(\\s*)([`~])\\2{2}\\s*$");
const QString VUtils::c_previewImageBlockRegExp = QString("[\\n|^][ |\\t]*\\xfffc[ |\\t]*(?=\\n)"); const QString VUtils::c_previewImageBlockRegExp = QString("[\\n|^][ |\\t]*\\xfffc[ |\\t]*(?=\\n)");

View File

@ -33,8 +33,8 @@ QString VCodeBlockHighlightHelper::unindentCodeBlock(const QString &p_text)
} }
QStringList lines = p_text.split('\n'); QStringList lines = p_text.split('\n');
V_ASSERT(lines[0].trimmed().startsWith("```")); Q_ASSERT(lines[0].trimmed().startsWith("```") || lines[0].trimmed().startsWith("~~~"));
V_ASSERT(lines.size() > 1); Q_ASSERT(lines.size() > 1);
QRegExp regExp("(^\\s*)"); QRegExp regExp("(^\\s*)");
regExp.indexIn(lines[0]); regExp.indexIn(lines[0]);