mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-06 14:29:54 +08:00
bug-fix: headings
- Missing headings with special characters; - Display only the starting block of headers across multiple blocks; - HGMarkdownHighlighter: - Skip headers without spaces after #s; - Fix last-block-header issue;
This commit is contained in:
parent
cb6338ecf6
commit
d943e58f13
@ -209,6 +209,10 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
|
|||||||
{
|
{
|
||||||
const HighlightingStyle &style = highlightingStyles[i];
|
const HighlightingStyle &style = highlightingStyles[i];
|
||||||
pmh_element *elem_cursor = result[style.type];
|
pmh_element *elem_cursor = result[style.type];
|
||||||
|
|
||||||
|
// pmh_H1 to pmh_H6 is continuous.
|
||||||
|
bool isHeader = style.type >= pmh_H1 && style.type <= pmh_H6;
|
||||||
|
|
||||||
while (elem_cursor != NULL)
|
while (elem_cursor != NULL)
|
||||||
{
|
{
|
||||||
// elem_cursor->pos and elem_cursor->end is the start
|
// elem_cursor->pos and elem_cursor->end is the start
|
||||||
@ -217,6 +221,14 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
|
|||||||
elem_cursor = elem_cursor->next;
|
elem_cursor = elem_cursor->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check header. Skip those headers with no spaces after #s.
|
||||||
|
if (isHeader
|
||||||
|
&& !isValidHeader(elem_cursor->pos, elem_cursor->end)) {
|
||||||
|
elem_cursor = elem_cursor->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
initBlockHighlihgtOne(elem_cursor->pos, elem_cursor->end, i);
|
initBlockHighlihgtOne(elem_cursor->pos, elem_cursor->end, i);
|
||||||
elem_cursor = elem_cursor->next;
|
elem_cursor = elem_cursor->next;
|
||||||
}
|
}
|
||||||
@ -304,7 +316,8 @@ void HGMarkdownHighlighter::initHeaderRegionsFromResult()
|
|||||||
for (int i = 0; i < 6; ++i) {
|
for (int i = 0; i < 6; ++i) {
|
||||||
pmh_element *elem = result[hx[i]];
|
pmh_element *elem = result[hx[i]];
|
||||||
while (elem != NULL) {
|
while (elem != NULL) {
|
||||||
if (elem->end <= elem->pos) {
|
if (elem->end <= elem->pos
|
||||||
|
|| !isValidHeader(elem->pos, elem->end)) {
|
||||||
elem = elem->next;
|
elem = elem->next;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -336,10 +349,20 @@ void HGMarkdownHighlighter::initHeaderRegionsFromResult()
|
|||||||
emit headersUpdated(m_headerRegions);
|
emit headersUpdated(m_headerRegions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HGMarkdownHighlighter::initBlockHighlihgtOne(unsigned long pos, unsigned long end, int styleIndex)
|
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 startBlockNum = document->findBlock(pos).blockNumber();
|
||||||
int endBlockNum = document->findBlock(end).blockNumber();
|
int endBlockNum = document->findBlock(end).blockNumber();
|
||||||
|
|
||||||
for (int i = startBlockNum; i <= endBlockNum; ++i)
|
for (int i = startBlockNum; i <= endBlockNum; ++i)
|
||||||
{
|
{
|
||||||
QTextBlock block = document->findBlockByNumber(i);
|
QTextBlock block = document->findBlockByNumber(i);
|
||||||
@ -688,3 +711,18 @@ void HGMarkdownHighlighter::highlightChanged()
|
|||||||
m_completeTimer->stop();
|
m_completeTimer->stop();
|
||||||
m_completeTimer->start();
|
m_completeTimer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HGMarkdownHighlighter::isValidHeader(unsigned long p_pos, unsigned long p_end)
|
||||||
|
{
|
||||||
|
// There must exist spaces after #s.
|
||||||
|
for (unsigned long i = p_pos; i < p_end; ++i) {
|
||||||
|
QChar ch = document->characterAt(i);
|
||||||
|
if (ch.isSpace()) {
|
||||||
|
return true;
|
||||||
|
} else if (ch != QChar('#')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -206,8 +206,13 @@ private:
|
|||||||
|
|
||||||
void parse();
|
void parse();
|
||||||
void parseInternal();
|
void parseInternal();
|
||||||
|
|
||||||
|
// Init highlight elements for all the blocks from parse results.
|
||||||
void initBlockHighlightFromResult(int nrBlocks);
|
void initBlockHighlightFromResult(int nrBlocks);
|
||||||
void initBlockHighlihgtOne(unsigned long pos, unsigned long end,
|
|
||||||
|
// Init highlight elements for blocks from one parse result.
|
||||||
|
void initBlockHighlihgtOne(unsigned long pos,
|
||||||
|
unsigned long end,
|
||||||
int styleIndex);
|
int styleIndex);
|
||||||
|
|
||||||
// Return true if there are fenced code blocks and it will call rehighlight() later.
|
// Return true if there are fenced code blocks and it will call rehighlight() later.
|
||||||
@ -234,6 +239,9 @@ private:
|
|||||||
|
|
||||||
// Highlight color column in code block.
|
// Highlight color column in code block.
|
||||||
void highlightCodeBlockColorColumn(const QString &p_text);
|
void highlightCodeBlockColorColumn(const QString &p_text);
|
||||||
|
|
||||||
|
// Check if [p_pos, p_end) is a valid header.
|
||||||
|
bool isValidHeader(unsigned long p_pos, unsigned long p_end);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline const QMap<int, bool> &HGMarkdownHighlighter::getPotentialPreviewBlocks() const
|
inline const QMap<int, bool> &HGMarkdownHighlighter::getPotentialPreviewBlocks() const
|
||||||
|
@ -437,7 +437,9 @@ void VMdEditor::updateHeaders(const QVector<VElementRegion> &p_headerRegions)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!block.contains(reg.m_endPos - 1)) {
|
if (!block.contains(reg.m_endPos - 1)) {
|
||||||
continue;
|
qWarning() << "header accross multiple blocks, starting from block"
|
||||||
|
<< block.blockNumber()
|
||||||
|
<< block.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((block.userState() == HighlightBlockState::Normal)
|
if ((block.userState() == HighlightBlockState::Normal)
|
||||||
|
@ -38,20 +38,34 @@ static bool parseTocLi(QXmlStreamReader &p_xml,
|
|||||||
if (p_xml.name() == "a") {
|
if (p_xml.name() == "a") {
|
||||||
QString anchor = p_xml.attributes().value("href").toString().mid(1);
|
QString anchor = p_xml.attributes().value("href").toString().mid(1);
|
||||||
QString name;
|
QString name;
|
||||||
if (p_xml.readNext()) {
|
// Read till </a>.
|
||||||
|
int nrStart = 1;
|
||||||
|
while (p_xml.readNext()) {
|
||||||
if (p_xml.tokenString() == "Characters") {
|
if (p_xml.tokenString() == "Characters") {
|
||||||
name = p_xml.text().toString();
|
name += p_xml.text().toString();
|
||||||
} else if (!p_xml.isEndElement()) {
|
} else if (p_xml.isEndElement()) {
|
||||||
qWarning() << "TOC HTML <a> should be ended by </a>" << p_xml.name();
|
--nrStart;
|
||||||
return false;
|
if (nrStart < 0) {
|
||||||
}
|
qWarning() << "end elements more than start elements in <a>" << anchor << p_xml.name();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
VTableOfContentItem header(name, p_level, anchor, p_table.size());
|
if (p_xml.name() == "a") {
|
||||||
p_table.append(header);
|
break;
|
||||||
} else {
|
}
|
||||||
|
} else if (p_xml.isStartElement()) {
|
||||||
|
++nrStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_xml.hasError()) {
|
||||||
// Error
|
// Error
|
||||||
|
qWarning() << "fail to parse an entire <a> element" << anchor << name;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VTableOfContentItem header(name, p_level, anchor, p_table.size());
|
||||||
|
p_table.append(header);
|
||||||
} else if (p_xml.name() == "ul") {
|
} else if (p_xml.name() == "ul") {
|
||||||
// Such as header 3 under header 1 directly
|
// Such as header 3 under header 1 directly
|
||||||
VTableOfContentItem header(c_emptyHeaderName, p_level, "", p_table.size());
|
VTableOfContentItem header(c_emptyHeaderName, p_level, "", p_table.size());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user