aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2020-10-19 14:49:06 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2020-10-20 13:08:08 +0000
commit526579b09d1be00ef2f0e371e0c57064777e6538 (patch)
tree41bcbb3e9df8fbd169bc2239defe0832bbcc2f01
parent80951d3e59f8b6ff270333692adfe2d65adf6c9c (diff)
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 <christian.kandeler@qt.io> Reviewed-by: David Schulz <david.schulz@qt.io>
-rw-r--r--src/plugins/texteditor/semantichighlighter.cpp103
1 files changed, 54 insertions, 49 deletions
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 <utils/qtcassert.h>
-#include <QTextDocument>
#include <QTextBlock>
+#include <QTextDocument>
+
+#include <algorithm>
using namespace TextEditor;
using namespace TextEditor::SemanticHighlighter;
namespace {
-QTextLayout::FormatRange rangeForResult(const HighlightingResult &result,
- const QHash<int, QTextCharFormat> &kindToFormat)
-{
+class Range {
+public:
QTextLayout::FormatRange formatRange;
+ QTextBlock block;
+};
+using Ranges = QVector<Range>;
- formatRange.start = int(result.column) - 1;
- formatRange.length = int(result.length);
- formatRange.format = result.useTextSyles
+Ranges rangesForResult(const HighlightingResult &result,
+ QTextDocument *doc,
+ const QHash<int, QTextCharFormat> &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<QTextBlock, QVector<QTextLayout::FormatRange>> 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<QTextLayout::FormatRange> 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<QVector<QTextLayout::FormatRange>> ranges(doc->blockCount());
+ std::map<QTextBlock, QVector<QTextLayout::FormatRange>> 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(