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:
Le Tan 2017-11-24 19:56:58 +08:00
parent cb6338ecf6
commit d943e58f13
4 changed files with 75 additions and 13 deletions

View File

@ -209,6 +209,10 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
{
const HighlightingStyle &style = highlightingStyles[i];
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)
{
// elem_cursor->pos and elem_cursor->end is the start
@ -217,6 +221,14 @@ void HGMarkdownHighlighter::initBlockHighlightFromResult(int nrBlocks)
elem_cursor = elem_cursor->next;
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);
elem_cursor = elem_cursor->next;
}
@ -304,7 +316,8 @@ void HGMarkdownHighlighter::initHeaderRegionsFromResult()
for (int i = 0; i < 6; ++i) {
pmh_element *elem = result[hx[i]];
while (elem != NULL) {
if (elem->end <= elem->pos) {
if (elem->end <= elem->pos
|| !isValidHeader(elem->pos, elem->end)) {
elem = elem->next;
continue;
}
@ -336,10 +349,20 @@ void HGMarkdownHighlighter::initHeaderRegionsFromResult()
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 endBlockNum = document->findBlock(end).blockNumber();
for (int i = startBlockNum; i <= endBlockNum; ++i)
{
QTextBlock block = document->findBlockByNumber(i);
@ -688,3 +711,18 @@ void HGMarkdownHighlighter::highlightChanged()
m_completeTimer->stop();
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;
}

View File

@ -206,8 +206,13 @@ private:
void parse();
void parseInternal();
// Init highlight elements for all the blocks from parse results.
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);
// 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.
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

View File

@ -437,7 +437,9 @@ void VMdEditor::updateHeaders(const QVector<VElementRegion> &p_headerRegions)
}
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)

View File

@ -38,20 +38,34 @@ static bool parseTocLi(QXmlStreamReader &p_xml,
if (p_xml.name() == "a") {
QString anchor = p_xml.attributes().value("href").toString().mid(1);
QString name;
if (p_xml.readNext()) {
// Read till </a>.
int nrStart = 1;
while (p_xml.readNext()) {
if (p_xml.tokenString() == "Characters") {
name = p_xml.text().toString();
} else if (!p_xml.isEndElement()) {
qWarning() << "TOC HTML <a> should be ended by </a>" << p_xml.name();
return false;
}
name += p_xml.text().toString();
} else if (p_xml.isEndElement()) {
--nrStart;
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());
p_table.append(header);
} else {
if (p_xml.name() == "a") {
break;
}
} else if (p_xml.isStartElement()) {
++nrStart;
}
}
if (p_xml.hasError()) {
// Error
qWarning() << "fail to parse an entire <a> element" << anchor << name;
return false;
}
VTableOfContentItem header(name, p_level, anchor, p_table.size());
p_table.append(header);
} else if (p_xml.name() == "ul") {
// Such as header 3 under header 1 directly
VTableOfContentItem header(c_emptyHeaderName, p_level, "", p_table.size());