From 526579b09d1be00ef2f0e371e0c57064777e6538 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 19 Oct 2020 14:49:06 +0200 Subject: TextEditor: Support highlighter results that cross block boundaries This is needed to properly highlight raw string literals. Task-number: QTCREATORBUG-16183 Change-Id: I00c59a26891bd339b58cc515041d237e496d6068 Reviewed-by: Christian Kandeler Reviewed-by: David Schulz --- src/plugins/texteditor/semantichighlighter.cpp | 103 +++++++++++++------------ 1 file changed, 54 insertions(+), 49 deletions(-) (limited to 'src/plugins/texteditor/semantichighlighter.cpp') diff --git a/src/plugins/texteditor/semantichighlighter.cpp b/src/plugins/texteditor/semantichighlighter.cpp index 858f8bb8cd..22a5ecf3c9 100644 --- a/src/plugins/texteditor/semantichighlighter.cpp +++ b/src/plugins/texteditor/semantichighlighter.cpp @@ -30,25 +30,52 @@ #include -#include #include +#include + +#include using namespace TextEditor; using namespace TextEditor::SemanticHighlighter; namespace { -QTextLayout::FormatRange rangeForResult(const HighlightingResult &result, - const QHash &kindToFormat) -{ +class Range { +public: QTextLayout::FormatRange formatRange; + QTextBlock block; +}; +using Ranges = QVector; - formatRange.start = int(result.column) - 1; - formatRange.length = int(result.length); - formatRange.format = result.useTextSyles +Ranges rangesForResult(const HighlightingResult &result, + QTextDocument *doc, + const QHash &kindToFormat) +{ + const QTextCharFormat format = result.useTextSyles ? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles) : kindToFormat.value(result.kind); - return formatRange; + if (!format.isValid()) + return {}; + + HighlightingResult curResult = result; + QTextBlock curBlock = doc->findBlockByNumber(curResult.line - 1); + Ranges ranges; + while (curBlock.isValid()) { + Range range; + range.block = curBlock; + range.formatRange.format = format; + range.formatRange.start = curResult.column - 1; + range.formatRange.length = std::min(curResult.length, + curBlock.length() - range.formatRange.start); + ranges << range; + if (range.formatRange.length == curResult.length) + break; + curBlock = curBlock.next(); + curResult.column = 1; + curResult.length -= range.formatRange.length; + } + + return ranges; } } @@ -81,39 +108,22 @@ void SemanticHighlighter::incrementalApplyExtraAdditionalFormats( QTextDocument *doc = highlighter->document(); QTC_ASSERT(currentBlockNumber < doc->blockCount(), return); - QTextBlock b = doc->findBlockByNumber(currentBlockNumber); + QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber); - HighlightingResult result = future.resultAt(from); - for (int i = from; i < to && b.isValid(); ) { - const int blockNumber = int(result.line) - 1; - QTC_ASSERT(blockNumber < doc->blockCount(), return); - - // clear formats of blocks until blockNumber - while (currentBlockNumber < blockNumber) { - highlighter->clearExtraFormats(b); - b = b.next(); - ++currentBlockNumber; - } + std::map> formatRanges; + for (int i = from; i < to; ++i) { + const Ranges ranges = rangesForResult(future.resultAt(i), doc, kindToFormat); + for (const Range &range : ranges) + formatRanges[range.block].append(range.formatRange); + } - // collect all the formats for the current line - QVector formats; - formats.reserve(to - from); - forever { - const QTextLayout::FormatRange formatRange = rangeForResult(result, kindToFormat); - if (formatRange.format.isValid()) - formats.append(formatRange); - - ++i; - if (i >= to) - break; - result = future.resultAt(i); - const int nextBlockNumber = int(result.line) - 1; - if (nextBlockNumber != blockNumber) - break; + for (auto &[block, ranges] : formatRanges) { + while (currentBlock < block) { + highlighter->clearExtraFormats(currentBlock); + currentBlock = currentBlock.next(); } - highlighter->setExtraFormats(b, std::move(formats)); - b = b.next(); - ++currentBlockNumber; + highlighter->setExtraFormats(block, std::move(ranges)); + currentBlock = block.next(); } } @@ -128,21 +138,16 @@ void SemanticHighlighter::setExtraAdditionalFormats(SyntaxHighlighter *highlight QTextDocument *doc = highlighter->document(); QTC_ASSERT(doc, return ); - QVector> ranges(doc->blockCount()); + std::map> formatRanges; for (auto result : results) { - const QTextLayout::FormatRange formatRange = rangeForResult(result, kindToFormat); - if (formatRange.format.isValid()) - ranges[int(result.line) - 1].append(formatRange); + const Ranges ranges = rangesForResult(result, doc, kindToFormat); + for (const Range &range : ranges) + formatRanges[range.block].append(range.formatRange); } - for (int blockNumber = 0; blockNumber < ranges.count(); ++blockNumber) { - if (!ranges[blockNumber].isEmpty()) { - QTextBlock b = doc->findBlockByNumber(blockNumber); - QTC_ASSERT(b.isValid(), return ); - highlighter->setExtraFormats(b, std::move(ranges[blockNumber])); - } - } + for (auto &[block, ranges] : formatRanges) + highlighter->setExtraFormats(block, std::move(ranges)); } void SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd( -- cgit v1.2.3