From f5bbc1ccd70cbb8005673f198158ce6d8da77fc6 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Fri, 13 Jul 2018 20:32:22 +0800 Subject: [PATCH] PegHighlighter: support math --- src/hgmarkdownhighlighter.cpp | 1317 ----------------- src/hgmarkdownhighlighter.h | 324 ---- src/markdownhighlighterdata.h | 22 +- src/peghighlighterresult.cpp | 86 ++ src/peghighlighterresult.h | 7 + src/pegmarkdownhighlighter.cpp | 11 +- src/pegmarkdownhighlighter.h | 7 + src/pegparser.cpp | 100 +- src/pegparser.h | 23 + src/resources/markdown-it.js | 4 +- src/resources/themes/v_detorte/v_detorte.mdhl | 10 +- .../themes/v_moonlight/v_moonlight.mdhl | 10 +- src/resources/themes/v_native/v_native.mdhl | 10 +- src/resources/themes/v_pure/v_pure.mdhl | 10 +- src/src.pro | 2 - src/utils/vutils.cpp | 46 +- src/utils/vutils.h | 10 +- src/vconfigmanager.cpp | 6 - src/vconfigmanager.h | 12 +- src/vconstants.h | 18 +- src/vlivepreviewhelper.h | 2 +- src/vmathjaxinplacepreviewhelper.h | 2 +- src/vmdedit.cpp | 5 +- src/vmdedit.h | 4 +- src/vstyleparser.h | 2 +- src/vtextblockdata.h | 97 -- 26 files changed, 284 insertions(+), 1863 deletions(-) delete mode 100644 src/hgmarkdownhighlighter.cpp delete mode 100644 src/hgmarkdownhighlighter.h diff --git a/src/hgmarkdownhighlighter.cpp b/src/hgmarkdownhighlighter.cpp deleted file mode 100644 index bbd8c65c..00000000 --- a/src/hgmarkdownhighlighter.cpp +++ /dev/null @@ -1,1317 +0,0 @@ -#include -#include -#include -#include -#include "hgmarkdownhighlighter.h" -#include "vconfigmanager.h" -#include "utils/vutils.h" - -extern VConfigManager *g_config; - -const int HGMarkdownHighlighter::initCapacity = 1024; - -void HGMarkdownHighlighter::resizeBuffer(int newCap) -{ - if (newCap == capacity) { - return; - } - if (capacity > 0) { - Q_ASSERT(content); - delete [] content; - } - capacity = newCap; - content = new char [capacity]; -} - -// Will be freeed by parent automatically -HGMarkdownHighlighter::HGMarkdownHighlighter(const QVector &styles, - const QHash &codeBlockStyles, - int waitInterval, - QTextDocument *parent) - : QSyntaxHighlighter(parent), - m_timeStamp(0), - highlightingStyles(styles), - m_codeBlockStyles(codeBlockStyles), - m_numOfCodeBlockHighlightsToRecv(0), - parsing(0), - m_blockHLResultReady(false), - waitInterval(waitInterval), - m_enableMathjax(false), - m_signalOut(false), - content(NULL), - capacity(0), - result(NULL) -{ - codeBlockStartExp = QRegExp(VUtils::c_fencedCodeBlockStartRegExp); - codeBlockEndExp = QRegExp(VUtils::c_fencedCodeBlockEndRegExp); - - m_mathjaxInlineExp = QRegExp(VUtils::c_mathjaxInlineRegExp); - m_mathjaxBlockExp = QRegExp(VUtils::c_mathjaxBlockRegExp); - - m_codeBlockFormat.setForeground(QBrush(Qt::darkYellow)); - for (int index = 0; index < styles.size(); ++index) { - switch (styles[index].type) { - case pmh_VERBATIM: - m_codeBlockFormat = styles[index].format; - break; - - case pmh_LINK: - m_linkFormat = styles[index].format; - break; - - case pmh_IMAGE: - m_imageFormat = styles[index].format; - break; - - case pmh_CODE: - // Use inline code font family for MathJax format. - m_mathjaxFormat.setFontFamily(styles[index].format.fontFamily()); - break; - - default: - break; - } - } - - m_colorColumnFormat = m_codeBlockFormat; - m_colorColumnFormat.setForeground(QColor(g_config->getEditorColorColumnFg())); - m_colorColumnFormat.setBackground(QColor(g_config->getEditorColorColumnBg())); - - m_mathjaxFormat.setForeground(QColor(g_config->getEditorMathjaxFg())); - - m_headerStyles.resize(6); - for (auto const & it : highlightingStyles) { - if (it.type >= pmh_H1 && it.type <= pmh_H6) { - m_headerStyles[it.type - pmh_H1] = it.format; - } - } - - resizeBuffer(initCapacity); - document = parent; - - timer = new QTimer(this); - timer->setSingleShot(true); - timer->setInterval(this->waitInterval); - connect(timer, &QTimer::timeout, - this, [this]() { - startParseAndHighlight(false); - }); - - const int completeWaitTime = 400; - m_completeTimer = new QTimer(this); - m_completeTimer->setSingleShot(true); - m_completeTimer->setInterval(completeWaitTime); - connect(m_completeTimer, &QTimer::timeout, - this, &HGMarkdownHighlighter::completeHighlight); - - connect(document, &QTextDocument::contentsChange, - this, &HGMarkdownHighlighter::handleContentChange); -} - -HGMarkdownHighlighter::~HGMarkdownHighlighter() -{ - if (result) { - pmh_free_elements(result); - result = NULL; - } - if (content) { - delete [] content; - capacity = 0; - content = NULL; - } -} - -void HGMarkdownHighlighter::updateBlockUserData(int p_blockNum, const QString &p_text) -{ - Q_UNUSED(p_text); - - VTextBlockData *blockData = currentBlockData(); - if (!blockData) { - blockData = new VTextBlockData(); - setCurrentBlockUserData(blockData); - } else { - blockData->setCodeBlockIndentation(-1); - blockData->clearMathjax(); - } - - if (blockData->getPreviews().isEmpty()) { - m_possiblePreviewBlocks.remove(p_blockNum); - } else { - m_possiblePreviewBlocks.insert(p_blockNum); - } -} - -void HGMarkdownHighlighter::highlightBlock(const QString &text) -{ - QTextBlock curBlock = currentBlock(); - int blockNum = curBlock.blockNumber(); - if (m_blockHLResultReady && m_blockHighlights.size() > blockNum) { - // units are sorted by start position and length. - const QVector &units = m_blockHighlights[blockNum]; - if (!units.isEmpty()) { - for (int i = 0; i < units.size(); ++i) { - const HLUnit &unit = units[i]; - if (i == 0) { - // No need to merge format. - setFormat(unit.start, - unit.length, - highlightingStyles[unit.styleIndex].format); - } else { - QTextCharFormat newFormat = highlightingStyles[unit.styleIndex].format; - for (int j = i - 1; j >= 0; --j) { - if (units[j].start + units[j].length <= unit.start) { - // It won't affect current unit. - continue; - } else { - // Merge the format. - QTextCharFormat tmpFormat(newFormat); - newFormat = highlightingStyles[units[j].styleIndex].format; - // tmpFormat takes precedence. - newFormat.merge(tmpFormat); - } - } - - setFormat(unit.start, unit.length, newFormat); - } - } - } - } - - // We use PEG Markdown Highlight as the main highlighter. - // We can use other highlighting methods to complement it. - - // Set current block's user data. - updateBlockUserData(blockNum, text); - - int preState = previousBlockState(); - bool inCodeblock = preState == HighlightBlockState::CodeBlock - || preState == HighlightBlockState::CodeBlockStart; - - // If it is a block inside HTML comment, just skip it. - // Pay attention to distinguish the HTML comments inside a fenced code block. - if (!inCodeblock && isBlockInsideCommentRegion(curBlock)) { - setCurrentBlockState(HighlightBlockState::Comment); - goto exit; - } - - setCurrentBlockState(HighlightBlockState::Normal); - - highlightCodeBlock(blockNum, text); - - if (currentBlockState() == HighlightBlockState::Normal) { - if (isVerbatimBlock(curBlock)) { - setCurrentBlockState(HighlightBlockState::Verbatim); - goto exit; - } - - highlightHeaderFast(blockNum, text); - - if (m_enableMathjax - && currentBlockState() == HighlightBlockState::Normal) { - highlightMathJax(curBlock, text); - } - } - - if (currentBlockState() != HighlightBlockState::CodeBlock) { - goto exit; - } - - // Highlight CodeBlock using VCodeBlockHighlightHelper. - if (m_codeBlockHighlights.size() > blockNum) { - const QVector &units = m_codeBlockHighlights[blockNum]; - if (!units.isEmpty()) { - QVector formats(units.size(), NULL); - for (int i = 0; i < units.size(); ++i) { - const HLUnitStyle &unit = units[i]; - auto it = m_codeBlockStyles.find(unit.style); - if (it == m_codeBlockStyles.end()) { - continue; - } - - formats[i] = &(*it); - - QTextCharFormat newFormat = m_codeBlockFormat; - newFormat.merge(*it); - for (int j = i - 1; j >= 0; --j) { - if (units[j].start + units[j].length <= unit.start) { - // It won't affect current unit. - continue; - } else { - // Merge the format. - if (formats[j]) { - QTextCharFormat tmpFormat(newFormat); - newFormat = *(formats[j]); - // tmpFormat takes precedence. - newFormat.merge(tmpFormat); - } - } - } - - setFormat(unit.start, unit.length, newFormat); - } - } - } - - highlightCodeBlockColorColumn(text); - -exit: - highlightChanged(); -} - -static bool compHLUnit(const HLUnit &p_a, const HLUnit &p_b) -{ - if (p_a.start < p_b.start) { - return true; - } else if (p_a.start == p_b.start) { - return p_a.length > p_b.length; - } else { - return false; - } -} - -void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks) -{ - m_blockHighlights.resize(nrBlocks); - for (int i = 0; i < m_blockHighlights.size(); ++i) { - m_blockHighlights[i].clear(); - } - - if (!result) { - return; - } - - for (int i = 0; i < highlightingStyles.size(); i++) - { - const HighlightingStyle &style = highlightingStyles[i]; - pmh_element *elem_cursor = result[style.type]; - - while (elem_cursor != NULL) - { - // elem_cursor->pos and elem_cursor->end is the start - // and end position of the element in document. - if (elem_cursor->end <= elem_cursor->pos) { - elem_cursor = elem_cursor->next; - continue; - } - - initBlockHighlihgtOne(elem_cursor->pos, elem_cursor->end, i); - elem_cursor = elem_cursor->next; - } - } - - // Sort m_blockHighlights. - for (int i = 0; i < m_blockHighlights.size(); ++i) { - if (m_blockHighlights[i].size() > 1) { - std::sort(m_blockHighlights[i].begin(), m_blockHighlights[i].end(), compHLUnit); - } - } -} - -void HGMarkdownHighlighter::initHtmlCommentRegionsFromResult() -{ - m_commentRegions.clear(); - - if (!result) { - return; - } - - pmh_element *elem = result[pmh_COMMENT]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - initBlockElementRegionOne(m_commentRegions, elem->pos, elem->end); - elem = elem->next; - } -} - -void HGMarkdownHighlighter::initImageRegionsFromResult() -{ - // From Qt5.7, the capacity is preserved. - m_imageRegions.clear(); - - if (!result) { - return; - } - - pmh_element *elem = result[pmh_IMAGE]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - m_imageRegions.push_back(VElementRegion(elem->pos, elem->end)); - elem = elem->next; - } -} - -void HGMarkdownHighlighter::initVerbatimBlocksFromResult() -{ - m_verbatimBlocks.clear(); - if (!result) { - return; - } - - pmh_element *elem = result[pmh_VERBATIM]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - // [firstBlock, lastBlock]. - int firstBlock = document->findBlock(elem->pos).blockNumber(); - int lastBlock = document->findBlock(elem->end - 1).blockNumber(); - for (int i = firstBlock; i <= lastBlock; ++i) { - m_verbatimBlocks.insert(i); - } - - elem = elem->next; - } -} - -void HGMarkdownHighlighter::initFencedCodeBlocksFromResult() -{ - m_codeBlocks.clear(); - m_codeBlocksState.clear(); - if (!result) { - return; - } - - // Ordered by start position in ascending order. - QMap regs; - - pmh_element *elem = result[pmh_FENCEDCODEBLOCK]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - if (!regs.contains(elem->pos)) { - regs.insert(elem->pos, VElementRegion(elem->pos, elem->end)); - } - - elem = elem->next; - } - - VCodeBlock item; - bool inBlock = false; - for (auto it = regs.begin(); it != regs.end(); ++it) { - // [firstBlock, lastBlock]. - int firstBlock = document->findBlock(it.value().m_startPos).blockNumber(); - int lastBlock = document->findBlock(it.value().m_endPos - 1).blockNumber(); - - QTextBlock block = document->findBlockByNumber(firstBlock); - while (block.isValid()) { - int blockNumber = block.blockNumber(); - if (blockNumber > lastBlock) { - break; - } - - HighlightBlockState state = HighlightBlockState::Normal; - QString text = block.text(); - if (inBlock) { - item.m_text = item.m_text + "\n" + text; - int idx = codeBlockEndExp.indexIn(text); - if (idx >= 0) { - // End block. - inBlock = false; - state = HighlightBlockState::CodeBlockEnd; - item.m_endBlock = blockNumber; - m_codeBlocks.append(item); - } else { - // Within code block. - state = HighlightBlockState::CodeBlock; - } - } else { - int idx = codeBlockStartExp.indexIn(text); - if (idx >= 0) { - // Start block. - inBlock = true; - state = HighlightBlockState::CodeBlockStart; - item.m_startBlock = blockNumber; - item.m_startPos = block.position(); - item.m_text = text; - if (codeBlockStartExp.captureCount() == 2) { - item.m_lang = codeBlockStartExp.capturedTexts()[2]; - } - } - } - - if (state != HighlightBlockState::Normal) { - m_codeBlocksState.insert(blockNumber, state); - } - - block = block.next(); - } - } -} - -void HGMarkdownHighlighter::initHeaderRegionsFromResult() -{ - // From Qt5.7, the capacity is preserved. - m_headerBlocks.clear(); - m_headerRegions.clear(); - - if (!result) { - return; - } - - pmh_element_type hx[6] = {pmh_H1, pmh_H2, pmh_H3, pmh_H4, pmh_H5, pmh_H6}; - for (int i = 0; i < 6; ++i) { - pmh_element *elem = result[hx[i]]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - m_headerRegions.push_back(VElementRegion(elem->pos, elem->end)); - - QTextBlock block = document->findBlock(elem->pos); - if (block.isValid()) { - // Header element will contain the new line character. - m_headerBlocks.insert(block.blockNumber(), HeaderBlockInfo(i, elem->end - elem->pos - 1)); - } - - elem = elem->next; - } - } - - std::sort(m_headerRegions.begin(), m_headerRegions.end()); -} - -void HGMarkdownHighlighter::initBlockHighlihgtOne(unsigned long pos, - unsigned long end, - int styleIndex) -{ - // When the the highlight element is at the end of document, @end will equals - // to the characterCount. - unsigned int nrChar = (unsigned int)document->characterCount(); - if (end >= nrChar && nrChar > 0) { - end = nrChar - 1; - } - - int startBlockNum = document->findBlock(pos).blockNumber(); - int endBlockNum = document->findBlock(end).blockNumber(); - - for (int i = startBlockNum; i <= endBlockNum; ++i) - { - QTextBlock block = document->findBlockByNumber(i); - int blockStartPos = block.position(); - HLUnit unit; - if (i == startBlockNum) { - unit.start = pos - blockStartPos; - unit.length = (startBlockNum == endBlockNum) ? - (end - pos) : (block.length() - unit.start); - } else if (i == endBlockNum) { - unit.start = 0; - unit.length = end - blockStartPos; - } else { - unit.start = 0; - unit.length = block.length(); - } - unit.styleIndex = styleIndex; - - m_blockHighlights[i].append(unit); - } -} - -void HGMarkdownHighlighter::highlightCodeBlock(int p_blockNumber, const QString &p_text) -{ - auto it = m_codeBlocksState.find(p_blockNumber); - if (it != m_codeBlocksState.end()) { - VTextBlockData *blockData = currentBlockData(); - Q_ASSERT(blockData); - - HighlightBlockState state = it.value(); - // Set code block indentation. - switch (state) { - case HighlightBlockState::CodeBlockStart: - { - int index = codeBlockStartExp.indexIn(p_text); - Q_ASSERT(index >= 0); - blockData->setCodeBlockIndentation(codeBlockStartExp.capturedTexts()[1].size()); - break; - } - - case HighlightBlockState::CodeBlock: - V_FALLTHROUGH; - case HighlightBlockState::CodeBlockEnd: - { - int startLeadingSpaces = 0; - VTextBlockData *preBlockData = previousBlockData(); - if (preBlockData) { - startLeadingSpaces = preBlockData->getCodeBlockIndentation(); - } - - blockData->setCodeBlockIndentation(startLeadingSpaces); - break; - } - - default: - Q_ASSERT(false); - break; - } - - // Set code block state. - setCurrentBlockState(state); - } -} - -static bool intersect(const QList> &p_indices, int &p_start, int &p_end) -{ - for (auto const & range : p_indices) { - if (p_end <= range.first) { - return false; - } else if (p_start < range.second) { - return true; - } - } - - return false; -} - -void HGMarkdownHighlighter::highlightMathJax(const QTextBlock &p_block, const QString &p_text) -{ - const int blockMarkLength = 2; - const int inlineMarkLength = 1; - - VTextBlockData *blockData = currentBlockData(); - Q_ASSERT(blockData); - - int blockNumber = p_block.blockNumber(); - - int startIdx = 0; - // Next position to search. - int pos = 0; - HighlightBlockState state = (HighlightBlockState)previousBlockState(); - - QList> blockIdices; - - bool fromPreBlock = true; - // Mathjax block formula. - if (state != HighlightBlockState::MathjaxBlock) { - fromPreBlock = false; - startIdx = findMathjaxMarker(blockNumber, p_text, pos, m_mathjaxBlockExp, blockMarkLength); - pos = startIdx + blockMarkLength; - } - - while (startIdx >= 0) { - int endIdx = findMathjaxMarker(blockNumber, p_text, pos, m_mathjaxBlockExp, blockMarkLength); - int mathLength = 0; - MathjaxInfo info; - bool valid = false; - if (endIdx == -1) { - mathLength = p_text.length() - startIdx; - pos = p_text.length(); - - if (isValidMathjaxRegion(blockNumber, startIdx, pos)) { - valid = true; - setCurrentBlockState(HighlightBlockState::MathjaxBlock); - info.m_previewedAsBlock = false; - info.m_index = startIdx, - info.m_length = mathLength; - if (fromPreBlock) { - VTextBlockData *preBlockData = previousBlockData(); - Q_ASSERT(preBlockData); - const MathjaxInfo &preInfo = preBlockData->getPendingMathjax(); - info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength); - } else { - info.m_text = p_text.mid(startIdx, mathLength); - } - - blockData->setPendingMathjax(info); - } - } else { - // Found end marker of a formula. - pos = endIdx + blockMarkLength; - mathLength = pos - startIdx; - - if (isValidMathjaxRegion(blockNumber, startIdx, pos)) { - valid = true; - info.m_previewedAsBlock = false; - info.m_index = startIdx; - info.m_length = mathLength; - if (fromPreBlock) { - // A cross-block formula. - if (pos >= p_text.length()) { - info.m_previewedAsBlock = true; - } - - VTextBlockData *preBlockData = previousBlockData(); - Q_ASSERT(preBlockData); - const MathjaxInfo &preInfo = preBlockData->getPendingMathjax(); - info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength); - } else { - // A formula within one block. - if (pos >= p_text.length() && startIdx == 0) { - info.m_previewedAsBlock = true; - } - - info.m_text = p_text.mid(startIdx, mathLength); - } - - blockData->addMathjax(info); - } - } - - fromPreBlock = false; - - if (valid) { - blockIdices.append(QPair(startIdx, pos)); - setFormat(startIdx, mathLength, m_mathjaxFormat); - startIdx = findMathjaxMarker(blockNumber, p_text, pos, m_mathjaxBlockExp, blockMarkLength); - pos = startIdx + blockMarkLength; - } else { - // Make the second mark as the first one and try again. - if (endIdx == -1) { - break; - } - - startIdx = pos - blockMarkLength; - } - } - - // Mathjax inline formula. - startIdx = 0; - pos = 0; - fromPreBlock = true; - if (state != HighlightBlockState::MathjaxInline) { - fromPreBlock = false; - startIdx = findMathjaxMarker(blockNumber, p_text, pos, m_mathjaxInlineExp, inlineMarkLength); - pos = startIdx + inlineMarkLength; - } - - while (startIdx >= 0) { - int endIdx = findMathjaxMarker(blockNumber, p_text, pos, m_mathjaxInlineExp, inlineMarkLength); - int mathLength = 0; - bool valid = false; - if (endIdx == -1) { - mathLength = p_text.length() - startIdx; - pos = p_text.length(); - } else { - pos = endIdx + inlineMarkLength; - mathLength = pos - startIdx; - } - - valid = isValidMathjaxRegion(blockNumber, startIdx, pos); - // Check if it intersect with blocks. - if (valid && !intersect(blockIdices, startIdx, pos)) { - // A valid inline mathjax. - MathjaxInfo info; - if (endIdx == -1) { - setCurrentBlockState(HighlightBlockState::MathjaxInline); - - info.m_previewedAsBlock = false; - info.m_index = startIdx, - info.m_length = mathLength; - if (fromPreBlock) { - VTextBlockData *preBlockData = previousBlockData(); - Q_ASSERT(preBlockData); - const MathjaxInfo &preInfo = preBlockData->getPendingMathjax(); - info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength); - } else { - info.m_text = p_text.mid(startIdx, mathLength); - } - - blockData->setPendingMathjax(info); - } else { - info.m_previewedAsBlock = false; - info.m_index = startIdx; - info.m_length = mathLength; - if (fromPreBlock) { - // A cross-block formula. - if (pos >= p_text.length()) { - info.m_previewedAsBlock = true; - } - - VTextBlockData *preBlockData = previousBlockData(); - Q_ASSERT(preBlockData); - const MathjaxInfo &preInfo = preBlockData->getPendingMathjax(); - info.m_text = preInfo.text() + "\n" + p_text.mid(startIdx, mathLength); - } else { - // A formula within one block. - if (pos >= p_text.length() && startIdx == 0) { - info.m_previewedAsBlock = true; - } - - info.m_text = p_text.mid(startIdx, mathLength); - } - - blockData->addMathjax(info); - } - - setFormat(startIdx, mathLength, m_mathjaxFormat); - - startIdx = m_mathjaxInlineExp.indexIn(p_text, pos); - pos = startIdx + m_mathjaxInlineExp.matchedLength(); - startIdx = pos - inlineMarkLength; - } else { - // Make the second mark as the first one and try again. - if (endIdx == -1) { - break; - } - - startIdx = pos - inlineMarkLength; - } - - fromPreBlock = false; - } -} - -void HGMarkdownHighlighter::highlightCodeBlockColorColumn(const QString &p_text) -{ - int cc = g_config->getColorColumn(); - if (cc <= 0 || currentBlockState() != HighlightBlockState::CodeBlock) { - return; - } - - VTextBlockData *blockData = currentBlockData(); - Q_ASSERT(blockData); - int indent = blockData->getCodeBlockIndentation(); - if (indent == -1) { - return; - } - - cc += indent; - if (p_text.size() < cc) { - return; - } - - setFormat(cc - 1, 1, m_colorColumnFormat); -} - -void HGMarkdownHighlighter::parse() -{ - if (!parsing.testAndSetRelaxed(0, 1)) { - return; - } - - if (highlightingStyles.isEmpty()) { - goto exit; - } - - { - m_blockHLResultReady = false; - - int nrBlocks = document->blockCount(); - parseInternal(); - - initBlockHighlightFromResult(nrBlocks); - - m_blockHLResultReady = true; - - initHtmlCommentRegionsFromResult(); - - initImageRegionsFromResult(); - - initHeaderRegionsFromResult(); - - initVerbatimBlocksFromResult(); - - initFencedCodeBlocksFromResult(); - - initInlineCodeRegionsFromResult(); - - initBoldItalicRegionsFromResult(); - - initLinkRegionsFromResult(); - - if (result) { - pmh_free_elements(result); - result = NULL; - } - } - -exit: - parsing.store(0); -} - -void HGMarkdownHighlighter::parseInternal() -{ - QString text = document->toPlainText(); - QByteArray ba = text.toUtf8(); - const char *data = (const char *)ba.data(); - int len = ba.size(); - - if (result) { - pmh_free_elements(result); - result = NULL; - } - - if (len == 0) { - return; - } else if (len >= capacity) { - resizeBuffer(qMax(2 * capacity, len * 2)); - } else if (len < (capacity >> 2)) { - resizeBuffer(qMax(capacity >> 1, len * 2)); - } - - memcpy(content, data, len); - content[len] = '\0'; - - int exts = pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER; - pmh_markdown_to_elements(content, exts, &result); -} - -void HGMarkdownHighlighter::handleContentChange(int /* position */, int charsRemoved, int charsAdded) -{ - if (charsRemoved == 0 && charsAdded == 0) { - return; - } - - ++m_timeStamp; - - m_signalOut = false; - timer->start(); -} - -void HGMarkdownHighlighter::startParseAndHighlight(bool p_fast) -{ - qDebug() << "HGMarkdownHighlighter start a new parse (fast" << p_fast << ")"; - parse(); - - m_signalOut = !p_fast; - - if (!p_fast) { - updateCodeBlocks(); - } - - rehighlight(); -} - -void HGMarkdownHighlighter::updateHighlight() -{ - timer->stop(); - startParseAndHighlight(false); -} - -void HGMarkdownHighlighter::updateHighlightFast() -{ - timer->stop(); - startParseAndHighlight(true); -} - -bool HGMarkdownHighlighter::updateCodeBlocks() -{ - if (!g_config->getEnableCodeBlockHighlight()) { - m_codeBlockHighlights.clear(); - return false; - } - - m_codeBlockHighlights.resize(document->blockCount()); - for (int i = 0; i < m_codeBlockHighlights.size(); ++i) { - m_codeBlockHighlights[i].clear(); - } - - m_numOfCodeBlockHighlightsToRecv = m_codeBlocks.size(); - emit codeBlocksUpdated(m_codeBlocks); - return m_numOfCodeBlockHighlightsToRecv > 0; -} - -static bool compHLUnitStyle(const HLUnitStyle &a, const HLUnitStyle &b) -{ - if (a.start < b.start) { - return true; - } else if (a.start == b.start) { - return a.length > b.length; - } else { - return false; - } -} - -void HGMarkdownHighlighter::setCodeBlockHighlights(const QVector &p_units) -{ - if (p_units.isEmpty()) { - goto exit; - } - - { - QVector> highlights(m_codeBlockHighlights.size()); - - for (auto const &unit : p_units) { - int pos = unit.m_position; - int end = unit.m_position + unit.m_length; - int startBlockNum = document->findBlock(pos).blockNumber(); - int endBlockNum = document->findBlock(end).blockNumber(); - - // Text has been changed. Abandon the obsolete parsed result. - if (startBlockNum == -1 || endBlockNum >= highlights.size()) { - goto exit; - } - - for (int i = startBlockNum; i <= endBlockNum; ++i) - { - QTextBlock block = document->findBlockByNumber(i); - int blockStartPos = block.position(); - HLUnitStyle hl; - hl.style = unit.m_style; - if (i == startBlockNum) { - hl.start = pos - blockStartPos; - hl.length = (startBlockNum == endBlockNum) ? - (end - pos) : (block.length() - hl.start); - } else if (i == endBlockNum) { - hl.start = 0; - hl.length = end - blockStartPos; - } else { - hl.start = 0; - hl.length = block.length(); - } - - highlights[i].append(hl); - } - } - - // Need to highlight in order. - for (int i = 0; i < highlights.size(); ++i) { - QVector &units = highlights[i]; - if (!units.isEmpty()) { - if (units.size() > 1) { - std::sort(units.begin(), units.end(), compHLUnitStyle); - } - - m_codeBlockHighlights[i].append(units); - } - } - } - -exit: - --m_numOfCodeBlockHighlightsToRecv; - if (m_numOfCodeBlockHighlightsToRecv <= 0) { - rehighlight(); - } -} - -bool HGMarkdownHighlighter::isBlockInsideCommentRegion(const QTextBlock &p_block) const -{ - if (!p_block.isValid()) { - return false; - } - - auto it = m_commentRegions.find(p_block.blockNumber()); - if (it != m_commentRegions.end()) { - const QVector ®s = it.value(); - if (regs.size() == 1 - && regs[0].m_startPos == 0 - && regs[0].m_endPos == p_block.length()) { - return true; - } - } - - return false; -} - -void HGMarkdownHighlighter::highlightChanged() -{ - m_completeTimer->stop(); - m_completeTimer->start(); -} - -bool HGMarkdownHighlighter::isValidHeader(const QString &p_text) -{ - // There must exist spaces after #s. - // No more than 6 #s. - int nrNumberSign = 0; - for (int i = 0; i < p_text.size(); ++i) { - QChar ch = p_text[i]; - if (ch.isSpace()) { - return nrNumberSign > 0; - } else if (ch == QChar('#')) { - if (++nrNumberSign > 6) { - return false; - } - } else { - return false; - } - } - - return false; -} - -void HGMarkdownHighlighter::highlightHeaderFast(int p_blockNumber, const QString &p_text) -{ - auto it = m_headerBlocks.find(p_blockNumber); - if (it != m_headerBlocks.end()) { - const HeaderBlockInfo &info = it.value(); - if (!isValidHeader(p_text)) { - // Set an empty format to clear formats. It seems to work. - setFormat(0, p_text.size(), QTextCharFormat()); - } else { - if (info.m_length < p_text.size()) { - setFormat(info.m_length, - p_text.size() - info.m_length, - m_headerStyles[info.m_level]); - } - - setCurrentBlockState(HighlightBlockState::Header); - } - } -} - -void HGMarkdownHighlighter::updateMathjaxBlocks() -{ - if (!m_enableMathjax) { - return; - } - - QVector blocks; - QTextBlock bl = document->firstBlock(); - while (bl.isValid()) { - VTextBlockData *data = static_cast(bl.userData()); - if (!data) { - bl = bl.next(); - continue; - } - - const QVector &info = data->getMathjax(); - for (auto const & it : info) { - blocks.append(VMathjaxBlock(bl.blockNumber(), it)); - } - - bl = bl.next(); - } - - emit mathjaxBlocksUpdated(blocks); -} - -void HGMarkdownHighlighter::initInlineCodeRegionsFromResult() -{ - m_inlineCodeRegions.clear(); - - if (!result) { - return; - } - - pmh_element *elem = result[pmh_CODE]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - initBlockElementRegionOne(m_inlineCodeRegions, elem->pos, elem->end); - elem = elem->next; - } -} - -void HGMarkdownHighlighter::initBoldItalicRegionsFromResult() -{ - m_boldItalicRegions.clear(); - - if (!result) { - return; - } - - pmh_element_type types[2] = {pmh_EMPH, pmh_STRONG}; - - for (int i = 0; i < 2; ++i) { - pmh_element *elem = result[types[i]]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - initBlockElementRegionOne(m_boldItalicRegions, elem->pos, elem->end); - elem = elem->next; - } - } -} - -void HGMarkdownHighlighter::initLinkRegionsFromResult() -{ - m_linkRegions.clear(); - - if (!result) { - return; - } - - pmh_element_type types[2] = {pmh_LINK, pmh_IMAGE}; - - for (int i = 0; i < 2; ++i) { - pmh_element *elem = result[types[i]]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - initBlockElementRegionOne(m_linkRegions, elem->pos, elem->end); - elem = elem->next; - } - } -} - -void HGMarkdownHighlighter::initBlockElementRegionOne(QHash> &p_regs, - unsigned long p_pos, - unsigned long p_end) -{ - // When the the highlight element is at the end of document, @p_end will equals - // to the characterCount. - unsigned int nrChar = (unsigned int)document->characterCount(); - if (p_end >= nrChar && nrChar > 0) { - p_end = nrChar - 1; - } - - int startBlockNum = document->findBlock(p_pos).blockNumber(); - int endBlockNum = document->findBlock(p_end).blockNumber(); - - for (int i = startBlockNum; i <= endBlockNum; ++i) - { - QTextBlock block = document->findBlockByNumber(i); - int blockStartPos = block.position(); - - QVector ®s = p_regs[i]; - int start, end; - if (i == startBlockNum) { - start = p_pos - blockStartPos; - end = (startBlockNum == endBlockNum) ? (p_end - blockStartPos) - : block.length(); - } else if (i == endBlockNum) { - start = 0; - end = p_end - blockStartPos; - } else { - start = 0; - end = block.length(); - } - - regs.append(VElementRegion(start, end)); - } -} - -static bool indexInsideRegion(const QVector &p_regions, int p_idx) -{ - for (auto const & reg : p_regions) { - if (reg.contains(p_idx)) { - return true; - } - } - - return false; -} - -int HGMarkdownHighlighter::findMathjaxMarker(int p_blockNumber, - const QString &p_text, - int p_pos, - QRegExp &p_reg, - int p_markerLength) -{ - if (p_pos >= p_text.size()) { - return -1; - } - - int idx = -1; - auto inlineCodeIt = m_inlineCodeRegions.find(p_blockNumber); - auto commentIt = m_commentRegions.find(p_blockNumber); - auto boldItalicIt = m_boldItalicRegions.find(p_blockNumber); - auto linkIt = m_linkRegions.find(p_blockNumber); - - while (p_pos < p_text.size()) { - idx = p_reg.indexIn(p_text, p_pos); - if (idx == -1) { - return idx; - } - - p_pos = idx + p_reg.matchedLength(); - idx = p_pos - p_markerLength; - - // Check if this idx is legal. - // Check inline code. - if (inlineCodeIt != m_inlineCodeRegions.end()) { - if (indexInsideRegion(inlineCodeIt.value(), idx)) { - idx = -1; - continue; - } - } - - if (commentIt != m_commentRegions.end()) { - if (indexInsideRegion(commentIt.value(), idx)) { - idx = -1; - continue; - } - } - - if (boldItalicIt != m_boldItalicRegions.end()) { - if (indexInsideRegion(boldItalicIt.value(), idx)) { - idx = -1; - continue; - } - } - - if (linkIt != m_linkRegions.end()) { - if (indexInsideRegion(linkIt.value(), idx)) { - idx = -1; - continue; - } - } - - break; - } - - return idx; -} - -static bool intersectRegion(const QVector &p_regions, - int p_start, - int p_end) -{ - for (auto const & reg : p_regions) { - if (reg.intersect(p_start, p_end)) { - return true; - } - } - - return false; -} - -bool HGMarkdownHighlighter::isValidMathjaxRegion(int p_blockNumber, - int p_start, - int p_end) -{ - auto inlineCodeIt = m_inlineCodeRegions.find(p_blockNumber); - if (inlineCodeIt != m_inlineCodeRegions.end()) { - if (intersectRegion(inlineCodeIt.value(), p_start, p_end)) { - return false; - } - } - - auto commentIt = m_commentRegions.find(p_blockNumber); - if (commentIt != m_commentRegions.end()) { - if (intersectRegion(commentIt.value(), p_start, p_end)) { - return false; - } - } - - auto boldItalicIt = m_boldItalicRegions.find(p_blockNumber); - if (boldItalicIt != m_boldItalicRegions.end()) { - if (intersectRegion(boldItalicIt.value(), p_start, p_end)) { - return false; - } - } - - auto linkIt = m_linkRegions.find(p_blockNumber); - if (linkIt != m_linkRegions.end()) { - if (intersectRegion(linkIt.value(), p_start, p_end)) { - return false; - } - } - - return true; -} - -void HGMarkdownHighlighter::completeHighlight() -{ - if (m_signalOut) { - m_signalOut = false; - updateMathjaxBlocks(); - emit imageLinksUpdated(m_imageRegions); - emit headersUpdated(m_headerRegions); - } - - emit highlightCompleted(); -} diff --git a/src/hgmarkdownhighlighter.h b/src/hgmarkdownhighlighter.h deleted file mode 100644 index 215b58d6..00000000 --- a/src/hgmarkdownhighlighter.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef HGMARKDOWNHIGHLIGHTER_H -#define HGMARKDOWNHIGHLIGHTER_H - -#include -#include -#include -#include -#include - -#include "vtextblockdata.h" -#include "markdownhighlighterdata.h" - -class QTextDocument; - - -class HGMarkdownHighlighter : public QSyntaxHighlighter -{ - Q_OBJECT - -public: - HGMarkdownHighlighter(const QVector &styles, - const QHash &codeBlockStyles, - int waitInterval, - QTextDocument *parent = 0); - ~HGMarkdownHighlighter(); - - // Request to update highlihgt (re-parse and re-highlight) - void setCodeBlockHighlights(const QVector &p_units); - - const QVector &getHeaderRegions() const; - - const QSet &getPossiblePreviewBlocks() const; - - void clearPossiblePreviewBlocks(const QVector &p_blocksToClear); - - void addPossiblePreviewBlock(int p_blockNumber); - - // Parse and only update the highlight results for rehighlight(). - void updateHighlightFast(); - - QHash &getCodeBlockStyles(); - - QVector &getHighlightingStyles(); - - void setMathjaxEnabled(bool p_enabled); - -signals: - void highlightCompleted(); - - // QVector is implicitly shared. - void codeBlocksUpdated(const QVector &p_codeBlocks); - - // Emitted when image regions have been fetched from a new parsing result. - void imageLinksUpdated(const QVector &p_imageRegions); - - // Emitted when header regions have been fetched from a new parsing result. - void headersUpdated(const QVector &p_headerRegions); - - // Emitted when Mathjax blocks updated. - void mathjaxBlocksUpdated(const QVector &p_mathjaxBlocks); - -protected: - void highlightBlock(const QString &text) Q_DECL_OVERRIDE; - -public slots: - // Parse and rehighlight immediately. - void updateHighlight(); - -private slots: - void handleContentChange(int position, int charsRemoved, int charsAdded); - - // @p_fast: if true, just parse and update styles. - void startParseAndHighlight(bool p_fast = false); - - void completeHighlight(); - -private: - struct HeaderBlockInfo - { - HeaderBlockInfo(int p_level = -1, int p_length = 0) - : m_level(p_level), m_length(p_length) - { - } - - // Header level based on 0. - int m_level; - - // Block length; - int m_length; - }; - - TimeStamp m_timeStamp; - - QRegExp codeBlockStartExp; - QRegExp codeBlockEndExp; - - QRegExp m_mathjaxInlineExp; - QRegExp m_mathjaxBlockExp; - - QTextCharFormat m_codeBlockFormat; - QTextCharFormat m_linkFormat; - QTextCharFormat m_imageFormat; - QTextCharFormat m_colorColumnFormat; - QTextCharFormat m_mathjaxFormat; - - QTextDocument *document; - - QVector highlightingStyles; - - QHash m_codeBlockStyles; - - QVector > m_blockHighlights; - - // Used for cache, [0, 6]. - QVector m_headerStyles; - - // Use another member to store the codeblocks highlights, because the highlight - // sequence is blockHighlights, regular-expression-based highlihgts, and then - // codeBlockHighlights. - // Support fenced code block only. - QVector > m_codeBlockHighlights; - - int m_numOfCodeBlockHighlightsToRecv; - - // All image link regions. - QVector m_imageRegions; - - // All header regions. - // May contains illegal elements. - // Sorted by start position. - QVector m_headerRegions; - - // All verbatim blocks (by parser) number. - QSet m_verbatimBlocks; - - // All fenced code blocks. - QVector m_codeBlocks; - - // Indexed by block number. - QHash m_codeBlocksState; - - // Indexed by block number. - QHash m_headerBlocks; - - // Timer to signal highlightCompleted(). - QTimer *m_completeTimer; - - QAtomicInt parsing; - - // Whether highlight results for blocks are ready. - bool m_blockHLResultReady; - - QTimer *timer; - int waitInterval; - - // Block number of those blocks which possible contains previewed image. - QSet m_possiblePreviewBlocks; - - bool m_enableMathjax; - - // Inline code regions for each block. - // VElementRegion's position is relative position within a block. - QHash> m_inlineCodeRegions; - - QHash> m_boldItalicRegions; - - // Including links and images. - QHash> m_linkRegions; - - // Comment regions for each block. - QHash> m_commentRegions; - - // Whether need to signal out changes when highlight completes. - bool m_signalOut; - - char *content; - int capacity; - pmh_element **result; - - static const int initCapacity; - - void resizeBuffer(int newCap); - - void highlightCodeBlock(int p_blockNumber, const QString &p_text); - - void highlightMathJax(const QTextBlock &p_block, const QString &p_text); - - void parse(); - - void parseInternal(); - - // Init highlight elements for all the blocks from parse results. - void initBlockHighlightFromResult(int nrBlocks); - - // Init highlight elements for blocks from one parse result. - void initBlockHighlihgtOne(unsigned long pos, - unsigned long end, - int styleIndex); - - // Return true if there are fenced code blocks and it will call rehighlight() later. - // Return false if there is none. - bool updateCodeBlocks(); - - void updateMathjaxBlocks(); - - // Fetch all the HTML comment regions from parsing result. - void initHtmlCommentRegionsFromResult(); - - // Fetch all the image link regions from parsing result. - void initImageRegionsFromResult(); - - // Fetch all the header regions from parsing result. - void initHeaderRegionsFromResult(); - - // Fetch all the verbatim blocks from parsing result. - void initVerbatimBlocksFromResult(); - - // Fetch all the fenced code blocks from parsing result. - void initFencedCodeBlocksFromResult(); - - // Fetch all the inlnie code regions from parsing result. - void initInlineCodeRegionsFromResult(); - - // Fetch all bold/italic regions from parsing result. - void initBoldItalicRegionsFromResult(); - - // Fetch all bold/italic regions from parsing result. - void initLinkRegionsFromResult(); - - void initBlockElementRegionOne(QHash> &p_regs, - unsigned long p_pos, - unsigned long p_end); - - // Whether @p_block is totally inside a HTML comment. - bool isBlockInsideCommentRegion(const QTextBlock &p_block) const; - - // Whether @p_block is a Verbatim block. - bool isVerbatimBlock(const QTextBlock &p_block) const; - - // Highlights have been changed. Try to signal highlightCompleted(). - void highlightChanged(); - - // Set the user data of currentBlock(). - void updateBlockUserData(int p_blockNum, const QString &p_text); - - // Highlight color column in code block. - void highlightCodeBlockColorColumn(const QString &p_text); - - bool isValidHeader(const QString &p_text); - - VTextBlockData *currentBlockData() const; - - VTextBlockData *previousBlockData() const; - - // Highlight headers using regular expression first instead of waiting for - // another parse. - void highlightHeaderFast(int p_blockNumber, const QString &p_text); - - int findMathjaxMarker(int p_blockNumber, - const QString &p_text, - int p_pos, - QRegExp &p_reg, - int p_markerLength); - - bool isValidMathjaxRegion(int p_blockNumber, int p_start, int p_end); -}; - -inline const QVector &HGMarkdownHighlighter::getHeaderRegions() const -{ - return m_headerRegions; -} - -inline const QSet &HGMarkdownHighlighter::getPossiblePreviewBlocks() const -{ - return m_possiblePreviewBlocks; -} - -inline void HGMarkdownHighlighter::clearPossiblePreviewBlocks(const QVector &p_blocksToClear) -{ - for (auto i : p_blocksToClear) { - m_possiblePreviewBlocks.remove(i); - } -} - -inline void HGMarkdownHighlighter::addPossiblePreviewBlock(int p_blockNumber) -{ - m_possiblePreviewBlocks.insert(p_blockNumber); -} - -inline VTextBlockData *HGMarkdownHighlighter::currentBlockData() const -{ - return static_cast(currentBlockUserData()); -} - -inline VTextBlockData *HGMarkdownHighlighter::previousBlockData() const -{ - QTextBlock block = currentBlock().previous(); - if (!block.isValid()) { - return NULL; - } - - return static_cast(block.userData()); -} - -inline QHash &HGMarkdownHighlighter::getCodeBlockStyles() -{ - return m_codeBlockStyles; -} - -inline QVector &HGMarkdownHighlighter::getHighlightingStyles() -{ - return highlightingStyles; -} - -inline bool HGMarkdownHighlighter::isVerbatimBlock(const QTextBlock &p_block) const -{ - return m_verbatimBlocks.contains(p_block.blockNumber()); -} - -inline void HGMarkdownHighlighter::setMathjaxEnabled(bool p_enabled) -{ - m_enableMathjax = p_enabled; -} -#endif diff --git a/src/markdownhighlighterdata.h b/src/markdownhighlighterdata.h index cdf64bf8..cac2e2d8 100644 --- a/src/markdownhighlighterdata.h +++ b/src/markdownhighlighterdata.h @@ -72,15 +72,6 @@ struct VMathjaxBlock { } - VMathjaxBlock(int p_blockNumber, const MathjaxInfo &p_info) - : m_blockNumber(p_blockNumber), - m_previewedAsBlock(p_info.m_previewedAsBlock), - m_index(p_info.m_index), - m_length(p_info.m_length), - m_text(p_info.m_text) - { - } - bool equalContent(const VMathjaxBlock &p_block) const { return m_text == p_block.m_text; @@ -94,13 +85,16 @@ struct VMathjaxBlock m_length = p_block.m_length; } + // Block number for in-place preview. int m_blockNumber; + // Whether it should be previewed as block or not. bool m_previewedAsBlock; - // Start index within the block. + // Start index wihtin block with number m_blockNumber, including the start mark. int m_index; + // Length of this mathjax in block with number m_blockNumber, including the end mark. int m_length; QString m_text; @@ -171,12 +165,4 @@ struct VElementRegion return QString("[%1,%2)").arg(m_startPos).arg(m_endPos); } }; - -struct PegHighlightResult -{ - TimeStamp m_timeStamp; - - QVector > m_blockHighlights; -}; - #endif // MARKDOWNHIGHLIGHTERDATA_H diff --git a/src/peghighlighterresult.cpp b/src/peghighlighterresult.cpp index 5936e166..d79db4c9 100644 --- a/src/peghighlighterresult.cpp +++ b/src/peghighlighterresult.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "pegmarkdownhighlighter.h" #include "utils/vutils.h" @@ -31,6 +32,8 @@ PegHighlighterResult::PegHighlighterResult(const PegMarkdownHighlighter *p_peg, m_headerRegions = p_result->m_headerRegions; parseFencedCodeBlocks(p_peg, p_result); + + parseMathjaxBlocks(p_peg, p_result); } static bool compHLUnit(const HLUnit &p_a, const HLUnit &p_b) @@ -221,3 +224,86 @@ void PegHighlighterResult::parseFencedCodeBlocks(const PegMarkdownHighlighter *p } } } + +void PegHighlighterResult::parseMathjaxBlocks(const PegMarkdownHighlighter *p_peg, + const QSharedPointer &p_result) +{ + const QTextDocument *doc = p_peg->getDocument(); + + // Inline equations. + const QVector inlineRegs = p_result->m_inlineEquationRegions; + + for (auto it = inlineRegs.begin(); it != inlineRegs.end(); ++it) { + const VElementRegion &r = *it; + QTextBlock block = doc->findBlock(r.m_startPos); + // Inline equation MUST in one block. + Q_ASSERT(block.blockNumber() == doc->findBlock(r.m_endPos - 1).blockNumber()); + + if (!block.isValid()) { + continue; + } + + if (r.m_endPos - block.position() > block.length()) { + continue; + } + + VMathjaxBlock item; + item.m_blockNumber = block.blockNumber(); + item.m_previewedAsBlock = false; + item.m_index = r.m_startPos - block.position(); + item.m_length = r.m_endPos - r.m_startPos; + item.m_text = block.text().mid(item.m_index, item.m_length); + m_mathjaxBlocks.append(item); + } + + // Display formulas. + // One block may be split into several regions due to list indentation. + const QVector formulaRegs = p_result->m_displayFormulaRegions; + VMathjaxBlock item; + bool inBlock = false; + QString marker("$$"); + for (auto it = formulaRegs.begin(); it != formulaRegs.end(); ++it) { + const VElementRegion &r = *it; + QTextBlock block = doc->findBlock(r.m_startPos); + int lastBlock = doc->findBlock(r.m_endPos - 1).blockNumber(); + + while (block.isValid()) { + int blockNum = block.blockNumber(); + if (blockNum > lastBlock) { + break; + } + + int pib = r.m_startPos - block.position(); + int length = r.m_endPos - r.m_startPos; + QString text = block.text().mid(pib, length); + if (inBlock) { + item.m_text = item.m_text + "\n" + text; + if (text.endsWith(marker)) { + // End of block. + inBlock = false; + item.m_blockNumber = blockNum; + item.m_index = pib; + item.m_length = length; + m_mathjaxBlocks.append(item); + } + } else { + Q_ASSERT(text.startsWith(marker)); + if (text.size() > 2 && text.endsWith(marker)) { + // Within one block. + item.m_blockNumber = blockNum; + item.m_previewedAsBlock = true; + item.m_index = pib; + item.m_length = length; + item.m_text = text; + m_mathjaxBlocks.append(item); + } else { + inBlock = true; + item.m_previewedAsBlock = true; + item.m_text = text; + } + } + + block = block.next(); + } + } +} diff --git a/src/peghighlighterresult.h b/src/peghighlighterresult.h index 8c471b47..63a8490f 100644 --- a/src/peghighlighterresult.h +++ b/src/peghighlighterresult.h @@ -44,6 +44,9 @@ public: int m_numOfCodeBlockHighlightsToRecv; + // All MathJax blocks. + QVector m_mathjaxBlocks; + private: // Parse highlight elements for all the blocks from parse results. void parseBlocksHighlights(const PegMarkdownHighlighter *p_peg, @@ -59,6 +62,10 @@ private: void parseFencedCodeBlocks(const PegMarkdownHighlighter *p_peg, const QSharedPointer &p_result); + // Parse fenced code blocks from parse results. + void parseMathjaxBlocks(const PegMarkdownHighlighter *p_peg, + const QSharedPointer &p_result); + void parseBlocksElementRegionOne(QHash> &p_regs, const QTextDocument *p_doc, unsigned long p_pos, diff --git a/src/pegmarkdownhighlighter.cpp b/src/pegmarkdownhighlighter.cpp index d5927abd..1923a26c 100644 --- a/src/pegmarkdownhighlighter.cpp +++ b/src/pegmarkdownhighlighter.cpp @@ -15,7 +15,7 @@ PegMarkdownHighlighter::PegMarkdownHighlighter(QTextDocument *p_doc) m_doc(p_doc), m_timeStamp(0), m_parser(NULL), - m_parserExts(pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER) + m_parserExts(pmh_EXT_NOTES | pmh_EXT_STRIKE | pmh_EXT_FRONTMATTER) { } @@ -27,6 +27,10 @@ void PegMarkdownHighlighter::init(const QVector &p_styles, m_styles = p_styles; m_codeBlockStyles = p_codeBlockStyles; + if (p_mathjaxEnabled) { + m_parserExts |= pmh_EXT_MATH; + } + m_codeBlockFormat.setForeground(QBrush(Qt::darkYellow)); for (int index = 0; index < m_styles.size(); ++index) { switch (m_styles[index].type) { @@ -272,7 +276,6 @@ void PegMarkdownHighlighter::updateBlockUserData(int p_blockNum, const QString & setCurrentBlockUserData(blockData); } else { blockData->setCodeBlockIndentation(-1); - blockData->clearMathjax(); } if (blockData->getPreviews().isEmpty()) { @@ -402,6 +405,10 @@ void PegMarkdownHighlighter::completeHighlight(QSharedPointerm_mathjaxBlocks); + } + emit imageLinksUpdated(p_result->m_imageRegions); emit headersUpdated(p_result->m_headerRegions); diff --git a/src/pegmarkdownhighlighter.h b/src/pegmarkdownhighlighter.h index 31f1a747..a73b5863 100644 --- a/src/pegmarkdownhighlighter.h +++ b/src/pegmarkdownhighlighter.h @@ -96,6 +96,8 @@ private: void completeHighlight(QSharedPointer p_result); + bool isMathJaxEnabled() const; + QTextDocument *m_doc; TimeStamp m_timeStamp; @@ -176,4 +178,9 @@ inline VTextBlockData *PegMarkdownHighlighter::previousBlockData() const return static_cast(block.userData()); } + +inline bool PegMarkdownHighlighter::isMathJaxEnabled() const +{ + return m_parserExts & pmh_EXT_MATH; +} #endif // PEGMARKDOWNHIGHLIGHTER_H diff --git a/src/pegparser.cpp b/src/pegparser.cpp index 7784aef4..00498321 100644 --- a/src/pegparser.cpp +++ b/src/pegparser.cpp @@ -15,6 +15,10 @@ void PegParseResult::parse(QAtomicInt &p_stop) parseHeaderRegions(p_stop); parseFencedCodeBlockRegions(p_stop); + + parseInlineEquationRegions(p_stop); + + parseDisplayFormulaRegions(p_stop); } void PegParseResult::parseImageRegions(QAtomicInt &p_stop) @@ -100,6 +104,58 @@ void PegParseResult::parseFencedCodeBlockRegions(QAtomicInt &p_stop) } } +void PegParseResult::parseInlineEquationRegions(QAtomicInt &p_stop) +{ + m_inlineEquationRegions.clear(); + if (isEmpty()) { + return; + } + + pmh_element *elem = m_pmhElements[pmh_INLINEEQUATION]; + while (elem != NULL) { + if (elem->end <= elem->pos) { + elem = elem->next; + continue; + } + + if (p_stop.load() == 1) { + return; + } + + m_inlineEquationRegions.push_back(VElementRegion(elem->pos, elem->end)); + elem = elem->next; + } +} + +void PegParseResult::parseDisplayFormulaRegions(QAtomicInt &p_stop) +{ + m_displayFormulaRegions.clear(); + if (isEmpty()) { + return; + } + + pmh_element *elem = m_pmhElements[pmh_DISPLAYFORMULA]; + while (elem != NULL) { + if (elem->end <= elem->pos) { + elem = elem->next; + continue; + } + + if (p_stop.load() == 1) { + return; + } + + m_displayFormulaRegions.push_back(VElementRegion(elem->pos, elem->end)); + elem = elem->next; + } + + if (p_stop.load() == 1) { + return; + } + + std::sort(m_displayFormulaRegions.begin(), m_displayFormulaRegions.end()); +} + PegParserWorker::PegParserWorker(QObject *p_parent) : QThread(p_parent), @@ -152,13 +208,7 @@ QSharedPointer PegParserWorker::parseMarkdown(const QSharedPoint return result; } - pmh_element **pmhResult = NULL; - - char *data = p_config->m_data.data(); - - pmh_markdown_to_elements(data, p_config->m_extensions, &pmhResult); - - result->m_pmhElements = pmhResult; + result->m_pmhElements = PegParser::parseMarkdownToElements(p_config); if (p_stop.load() == 1) { return result; @@ -274,3 +324,39 @@ void PegParser::scheduleWork(PegParserWorker *p_worker, p_worker->prepareParse(p_config); p_worker->start(); } + +QVector PegParser::parseImageRegions(const QSharedPointer &p_config) +{ + QVector regs; + pmh_element **res = PegParser::parseMarkdownToElements(p_config); + if (!res) { + return regs; + } + + pmh_element *elem = res[pmh_IMAGE]; + while (elem != NULL) { + if (elem->end <= elem->pos) { + elem = elem->next; + continue; + } + + regs.push_back(VElementRegion(elem->pos, elem->end)); + elem = elem->next; + } + + pmh_free_elements(res); + + return regs; +} + +pmh_element **PegParser::parseMarkdownToElements(const QSharedPointer &p_config) +{ + if (p_config->m_data.isEmpty()) { + return NULL; + } + + pmh_element **pmhResult = NULL; + char *data = p_config->m_data.data(); + pmh_markdown_to_elements(data, p_config->m_extensions, &pmhResult); + return pmhResult; +} diff --git a/src/pegparser.h b/src/pegparser.h index 40f308d5..b36257bd 100644 --- a/src/pegparser.h +++ b/src/pegparser.h @@ -13,6 +13,13 @@ struct PegParseConfig { + PegParseConfig() + : m_timeStamp(0), + m_numOfBlocks(0), + m_extensions(pmh_EXT_NONE) + { + } + TimeStamp m_timeStamp; QByteArray m_data; @@ -86,12 +93,23 @@ struct PegParseResult // Ordered by start position in ascending order. QMap m_codeBlockRegions; + // All $ $ inline equation regions. + QVector m_inlineEquationRegions; + + // All $$ $$ display formula regions. + // Sorted by start position. + QVector m_displayFormulaRegions; + private: void parseImageRegions(QAtomicInt &p_stop); void parseHeaderRegions(QAtomicInt &p_stop); void parseFencedCodeBlockRegions(QAtomicInt &p_stop); + + void parseInlineEquationRegions(QAtomicInt &p_stop); + + void parseDisplayFormulaRegions(QAtomicInt &p_stop); }; class PegParserWorker : public QThread @@ -162,6 +180,11 @@ public: void parseAsync(const QSharedPointer &p_config); + static QVector parseImageRegions(const QSharedPointer &p_config); + + // MUST pmh_free_elements() the result. + static pmh_element **parseMarkdownToElements(const QSharedPointer &p_config); + signals: void parseResultReady(const QSharedPointer &p_result); diff --git a/src/resources/markdown-it.js b/src/resources/markdown-it.js index b0d0f964..e0e87e4d 100644 --- a/src/resources/markdown-it.js +++ b/src/resources/markdown-it.js @@ -108,7 +108,9 @@ mdit = mdit.use(window.markdownitFootnote); mdit = mdit.use(window["markdown-it-imsize.js"]); -mdit = mdit.use(texmath, { delimiters: 'dollars' }); +if (typeof texmath != 'undefined') { + mdit = mdit.use(texmath, { delimiters: 'dollars' }); +} var mdHasTocSection = function(markdown) { var n = markdown.search(/(\n|^)\[toc\]/i); diff --git a/src/resources/themes/v_detorte/v_detorte.mdhl b/src/resources/themes/v_detorte/v_detorte.mdhl index 2f875a38..12a0e80f 100644 --- a/src/resources/themes/v_detorte/v_detorte.mdhl +++ b/src/resources/themes/v_detorte/v_detorte.mdhl @@ -39,8 +39,6 @@ color-column-foreground: eeeeee preview-image-line-foreground: 6f5799 # [VNote] Style for preview image (useful for SVG in dark theme) preview-image-background: 949494 -# [VNote] Style for MathJax -mathjax-foreground: 93d3cc editor-selection foreground: dadada @@ -184,3 +182,11 @@ font-style: strikeout FRONTMATTER foreground: af8787 + +INLINEEQUATION +foreground: 93d3cc +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New + +DISPLAYFORMULA +foreground: 93d3cc +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New diff --git a/src/resources/themes/v_moonlight/v_moonlight.mdhl b/src/resources/themes/v_moonlight/v_moonlight.mdhl index 8ab8f914..5ce3408b 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.mdhl +++ b/src/resources/themes/v_moonlight/v_moonlight.mdhl @@ -39,8 +39,6 @@ color-column-foreground: eeeeee preview-image-line-foreground: 6f5799 # [VNote] Style for preview image (useful for SVG in dark theme) preview-image-background: b0bec5 -# [VNote] Style for MathJax -mathjax-foreground: 4db6ac editor-selection foreground: bcbcbc @@ -183,3 +181,11 @@ font-style: strikeout FRONTMATTER foreground: 6e7686 + +INLINEEQUATION +foreground: 4db6ac +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New + +DISPLAYFORMULA +foreground: 4db6ac +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New diff --git a/src/resources/themes/v_native/v_native.mdhl b/src/resources/themes/v_native/v_native.mdhl index 38c415e1..2746930e 100644 --- a/src/resources/themes/v_native/v_native.mdhl +++ b/src/resources/themes/v_native/v_native.mdhl @@ -36,8 +36,6 @@ color-column-background: dd0000 color-column-foreground: ffff00 # [VNote] Style for preview image line preview-image-line-foreground: 9575cd -# [VNote] Style for MathJax -mathjax-foreground: 00897b editor-selection foreground: ffffff @@ -179,3 +177,11 @@ font-style: strikeout FRONTMATTER foreground: 6c6c6c + +INLINEEQUATION +foreground: 00897b +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New + +DISPLAYFORMULA +foreground: 00897b +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New diff --git a/src/resources/themes/v_pure/v_pure.mdhl b/src/resources/themes/v_pure/v_pure.mdhl index 0f6734be..d6f0f13b 100644 --- a/src/resources/themes/v_pure/v_pure.mdhl +++ b/src/resources/themes/v_pure/v_pure.mdhl @@ -37,8 +37,6 @@ color-column-background: dd0000 color-column-foreground: ffff00 # [VNote] Style for preview image line preview-image-line-foreground: 9575cd -# [VNote] Style for MathJax -mathjax-foreground: 00897b editor-selection foreground: f5f5f5 @@ -180,3 +178,11 @@ font-style: strikeout FRONTMATTER foreground: 6c6c6c + +INLINEEQUATION +foreground: 00897b +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New + +DISPLAYFORMULA +foreground: 00897b +font-family: Consolas, Monaco, Andale Mono, Monospace, Courier New diff --git a/src/src.pro b/src/src.pro index 8b11b4f6..16291498 100644 --- a/src/src.pro +++ b/src/src.pro @@ -29,7 +29,6 @@ SOURCES += main.cpp\ vdocument.cpp \ utils/vutils.cpp \ vpreviewpage.cpp \ - hgmarkdownhighlighter.cpp \ vstyleparser.cpp \ dialog/vnewnotebookdialog.cpp \ vmarkdownconverter.cpp \ @@ -158,7 +157,6 @@ HEADERS += vmainwindow.h \ vdocument.h \ utils/vutils.h \ vpreviewpage.h \ - hgmarkdownhighlighter.h \ vstyleparser.h \ dialog/vnewnotebookdialog.h \ vmarkdownconverter.h \ diff --git a/src/utils/vutils.cpp b/src/utils/vutils.cpp index 04a896c0..eb76757d 100644 --- a/src/utils/vutils.cpp +++ b/src/utils/vutils.cpp @@ -32,8 +32,8 @@ #include "vorphanfile.h" #include "vnote.h" #include "vnotebook.h" -#include "hgmarkdownhighlighter.h" #include "vpreviewpage.h" +#include "pegparser.h" extern VConfigManager *g_config; @@ -52,10 +52,6 @@ const QString VUtils::c_fencedCodeBlockStartRegExp = QString("^(\\s*)```([^`\\s] const QString VUtils::c_fencedCodeBlockEndRegExp = QString("^(\\s*)```$"); -const QString VUtils::c_mathjaxInlineRegExp = QString("(?:^|[^\\$\\\\]|(?:^|[^\\\\])(?:\\\\\\\\)+)\\$(?!\\$)"); - -const QString VUtils::c_mathjaxBlockRegExp = QString("(?:^|[^\\$\\\\]|(?:^|[^\\\\])(?:\\\\\\\\)+)\\$\\$(?!\\$)"); - const QString VUtils::c_previewImageBlockRegExp = QString("[\\n|^][ |\\t]*\\xfffc[ |\\t]*(?=\\n)"); const QString VUtils::c_headerRegExp = QString("^(#{1,6})\\s+(((\\d+\\.)+(?=\\s))?\\s*(\\S.*)?)$"); @@ -661,8 +657,11 @@ QString VUtils::generateHtmlTemplate(const QString &p_template, "\n" + "\n" + "\n" + - "\n" + - "\n"; + "\n"; + + if (g_config->getEnableMathjax()) { + extraFile += "\n"; + } const MarkdownitOption &opt = g_config->getMarkdownitOption(); @@ -1201,38 +1200,11 @@ bool VUtils::deleteFile(const QString &p_recycleBinFolderPath, QVector VUtils::fetchImageRegionsUsingParser(const QString &p_content) { Q_ASSERT(!p_content.isEmpty()); - QVector regs; - QByteArray ba = p_content.toUtf8(); - const char *data = (const char *)ba.data(); - int len = ba.size(); + const QSharedPointer parserConfig(new PegParseConfig()); + parserConfig->m_data = p_content.toUtf8(); - pmh_element **result = NULL; - char *content = new char[len + 1]; - memcpy(content, data, len); - content[len] = '\0'; - - pmh_markdown_to_elements(content, pmh_EXT_NONE, &result); - - if (!result) { - return regs; - } - - pmh_element *elem = result[pmh_IMAGE]; - while (elem != NULL) { - if (elem->end <= elem->pos) { - elem = elem->next; - continue; - } - - regs.push_back(VElementRegion(elem->pos, elem->end)); - - elem = elem->next; - } - - pmh_free_elements(result); - - return regs; + return PegParser::parseImageRegions(parserConfig); } QString VUtils::displayDateTime(const QDateTime &p_dateTime, diff --git a/src/utils/vutils.h b/src/utils/vutils.h index 4b9f5be6..84f6bb9c 100644 --- a/src/utils/vutils.h +++ b/src/utils/vutils.h @@ -374,14 +374,6 @@ public: static const QString c_fencedCodeBlockStartRegExp; static const QString c_fencedCodeBlockEndRegExp; - // Regular expression for inline mathjax formula. - // $..$ - static const QString c_mathjaxInlineRegExp; - - // Regular expression for block mathjax formula. - // $$..$$ - static const QString c_mathjaxBlockRegExp; - // Regular expression for preview image block. static const QString c_previewImageBlockRegExp; @@ -403,7 +395,7 @@ private: static void initAvailableLanguage(); - // Use HGMarkdownParser to parse @p_content to get all image link regions. + // Use PegParser to parse @p_content to get all image link regions. static QVector fetchImageRegionsUsingParser(const QString &p_content); // Delete file/directory specified by @p_path by moving it to the recycle bin diff --git a/src/vconfigmanager.cpp b/src/vconfigmanager.cpp index d16688fa..99bf63a8 100644 --- a/src/vconfigmanager.cpp +++ b/src/vconfigmanager.cpp @@ -620,7 +620,6 @@ void VConfigManager::updateMarkdownEditStyle() m_editorColorColumnFg = defaultColor; m_editorPreviewImageLineFg = defaultColor; m_editorPreviewImageBg.clear(); - m_editorMathjaxFg = defaultColor; auto editorIt = styles.find("editor"); if (editorIt != styles.end()) { @@ -698,11 +697,6 @@ void VConfigManager::updateMarkdownEditStyle() if (it != editorIt->end()) { m_editorPreviewImageBg = "#" + *it; } - - it = editorIt->find("mathjax-foreground"); - if (it != editorIt->end()) { - m_editorMathjaxFg = "#" + *it; - } } } diff --git a/src/vconfigmanager.h b/src/vconfigmanager.h index 3bba53dc..fe2d5418 100644 --- a/src/vconfigmanager.h +++ b/src/vconfigmanager.h @@ -333,8 +333,6 @@ public: const QString &getEditorPreviewImageBg() const; - const QString &getEditorMathjaxFg() const; - bool getEnableCodeBlockLineNumber() const; void setEnableCodeBlockLineNumber(bool p_enabled); @@ -789,7 +787,7 @@ private: // [DocType] -> { Suffixes }. QHash> m_docSuffixes; - // Interval for HGMarkdownHighlighter highlight timer (milliseconds). + // Interval for PegMarkdownHighlighter highlight timer (milliseconds). int m_markdownHighlightInterval; // Line distance height in pixel. @@ -825,9 +823,6 @@ private: // The forced background color of the preview image. Can be empty. QString m_editorPreviewImageBg; - // The foreground color of the MathJax. - QString m_editorMathjaxFg; - // Icon size of tool bar in pixels. int m_toolBarIconSize; @@ -1927,11 +1922,6 @@ inline const QString &VConfigManager::getEditorPreviewImageBg() const return m_editorPreviewImageBg; } -inline const QString &VConfigManager::getEditorMathjaxFg() const -{ - return m_editorMathjaxFg; -} - inline bool VConfigManager::getEnableCodeBlockLineNumber() const { return m_enableCodeBlockLineNumber; diff --git a/src/vconstants.h b/src/vconstants.h index 5079b180..54c02f23 100644 --- a/src/vconstants.h +++ b/src/vconstants.h @@ -119,23 +119,7 @@ enum HighlightBlockState // A fenced code block. CodeBlockStart, CodeBlock, - CodeBlockEnd, - - // This block is inside a HTML comment region. - // Obsolete. - Comment, - - // Verbatim code block. - // Obsolete. - Verbatim, - - // Mathjax. It means the pending state of the block. - MathjaxBlock, - MathjaxInline, - - // Header. - // Obsolete. - Header + CodeBlockEnd }; // Pages to open on start up. diff --git a/src/vlivepreviewhelper.h b/src/vlivepreviewhelper.h index d2edb2c4..f9662204 100644 --- a/src/vlivepreviewhelper.h +++ b/src/vlivepreviewhelper.h @@ -4,7 +4,7 @@ #include #include -#include "hgmarkdownhighlighter.h" +#include "pegmarkdownhighlighter.h" #include "vpreviewmanager.h" #include "vconstants.h" diff --git a/src/vmathjaxinplacepreviewhelper.h b/src/vmathjaxinplacepreviewhelper.h index 53b08cbf..a8efac16 100644 --- a/src/vmathjaxinplacepreviewhelper.h +++ b/src/vmathjaxinplacepreviewhelper.h @@ -3,7 +3,7 @@ #include -#include "hgmarkdownhighlighter.h" +#include "pegmarkdownhighlighter.h" #include "vpreviewmanager.h" #include "vconstants.h" diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index cd064c15..459c4bde 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -1,6 +1,6 @@ #include #include "vmdedit.h" -#include "hgmarkdownhighlighter.h" +#include "pegmarkdownhighlighter.h" #include "vmdeditoperations.h" #include "vnote.h" #include "vconfigmanager.h" @@ -30,6 +30,7 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type, setAcceptRichText(false); + /* m_mdHighlighter = new HGMarkdownHighlighter(g_config->getMdHighlightingStyles(), g_config->getCodeBlockStyles(), g_config->getMarkdownHighlightInterval(), @@ -37,13 +38,13 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type, connect(m_mdHighlighter, &HGMarkdownHighlighter::headersUpdated, this, &VMdEdit::updateHeaders); - // After highlight, the cursor may trun into non-visible. We should make it visible // in this case. connect(m_mdHighlighter, &HGMarkdownHighlighter::highlightCompleted, this, [this]() { makeBlockVisible(textCursor().block()); }); + */ /* m_imagePreviewer = new VImagePreviewer(this, m_mdHighlighter); diff --git a/src/vmdedit.h b/src/vmdedit.h index c7b73767..81207bfb 100644 --- a/src/vmdedit.h +++ b/src/vmdedit.h @@ -12,8 +12,8 @@ #include "vconfigmanager.h" #include "utils/vutils.h" -class HGMarkdownHighlighter; class VDocument; +class PegMarkdownHighlighter; class VMdEdit : public VEdit { @@ -108,7 +108,7 @@ private: // Index in m_headers of current header which contains the cursor. int indexOfCurrentHeader() const; - HGMarkdownHighlighter *m_mdHighlighter; + PegMarkdownHighlighter *m_mdHighlighter; // VImagePreviewer *m_imagePreviewer; // Image links inserted while editing. diff --git a/src/vstyleparser.h b/src/vstyleparser.h index 5eff16fb..ef41fca7 100644 --- a/src/vstyleparser.h +++ b/src/vstyleparser.h @@ -5,7 +5,7 @@ #include #include #include -#include "hgmarkdownhighlighter.h" +#include "pegmarkdownhighlighter.h" extern "C" { #include diff --git a/src/vtextblockdata.h b/src/vtextblockdata.h index 09ad2a5b..ecbf5e9d 100644 --- a/src/vtextblockdata.h +++ b/src/vtextblockdata.h @@ -139,60 +139,6 @@ struct VPreviewInfo }; -struct MathjaxInfo -{ -public: - MathjaxInfo() - : m_previewedAsBlock(false), - m_index(-1), - m_length(0) - { - } - - - bool isValid() const - { - return m_index >= 0 && m_length > 0; - } - - bool previewedAsBlock() const - { - return m_previewedAsBlock; - } - - void clear() - { - m_previewedAsBlock = false; - m_index = -1; - m_length = 0; - } - - const QString &text() const - { - return m_text; - } - - QString toString() const - { - return QString("MathjaxInfo %1 (%2,%3) %4").arg(m_previewedAsBlock) - .arg(m_index) - .arg(m_length) - .arg(m_text); - } - - // Whether it should be previewed as block or not. - bool m_previewedAsBlock; - - // Start index wihtin block, including the start mark. - int m_index; - - // Length of this mathjax, including the end mark. - int m_length; - - QString m_text; -}; - - // User data for each block. class VTextBlockData : public QTextBlockUserData { @@ -217,16 +163,6 @@ public: void setCodeBlockIndentation(int p_indent); - void clearMathjax(); - - const MathjaxInfo &getPendingMathjax() const; - - void setPendingMathjax(const MathjaxInfo &p_info); - - const QVector &getMathjax() const; - - void addMathjax(const MathjaxInfo &p_info); - private: // Check the order of elements. bool checkOrder() const; @@ -236,12 +172,6 @@ private: // Indentation of the this code block if this block is a fenced code block. int m_codeBlockIndentation; - - // Pending Mathjax info, such as this block is the start of a Mathjax formula. - MathjaxInfo m_pendingMathjax; - - // Mathjax info ends in this block. - QVector m_mathjax; }; inline const QVector &VTextBlockData::getPreviews() const @@ -258,31 +188,4 @@ inline void VTextBlockData::setCodeBlockIndentation(int p_indent) { m_codeBlockIndentation = p_indent; } - -inline void VTextBlockData::clearMathjax() -{ - m_pendingMathjax.clear(); - m_mathjax.clear(); -} - -inline const MathjaxInfo &VTextBlockData::getPendingMathjax() const -{ - return m_pendingMathjax; -} - -inline void VTextBlockData::setPendingMathjax(const MathjaxInfo &p_info) -{ - m_pendingMathjax = p_info; -} - -inline const QVector &VTextBlockData::getMathjax() const -{ - return m_mathjax; -} - -inline void VTextBlockData::addMathjax(const MathjaxInfo &p_info) -{ - m_mathjax.append(p_info); -} - #endif // VTEXTBLOCKDATA_H