forked from qt-creator/qt-creator
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>
This commit is contained in:
@@ -30,25 +30,52 @@
|
|||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
#include <QTextDocument>
|
|
||||||
#include <QTextBlock>
|
#include <QTextBlock>
|
||||||
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace TextEditor;
|
using namespace TextEditor;
|
||||||
using namespace TextEditor::SemanticHighlighter;
|
using namespace TextEditor::SemanticHighlighter;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
QTextLayout::FormatRange rangeForResult(const HighlightingResult &result,
|
class Range {
|
||||||
const QHash<int, QTextCharFormat> &kindToFormat)
|
public:
|
||||||
{
|
|
||||||
QTextLayout::FormatRange formatRange;
|
QTextLayout::FormatRange formatRange;
|
||||||
|
QTextBlock block;
|
||||||
|
};
|
||||||
|
using Ranges = QVector<Range>;
|
||||||
|
|
||||||
formatRange.start = int(result.column) - 1;
|
Ranges rangesForResult(const HighlightingResult &result,
|
||||||
formatRange.length = int(result.length);
|
QTextDocument *doc,
|
||||||
formatRange.format = result.useTextSyles
|
const QHash<int, QTextCharFormat> &kindToFormat)
|
||||||
|
{
|
||||||
|
const QTextCharFormat format = result.useTextSyles
|
||||||
? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles)
|
? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles)
|
||||||
: kindToFormat.value(result.kind);
|
: 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();
|
QTextDocument *doc = highlighter->document();
|
||||||
QTC_ASSERT(currentBlockNumber < doc->blockCount(), return);
|
QTC_ASSERT(currentBlockNumber < doc->blockCount(), return);
|
||||||
QTextBlock b = doc->findBlockByNumber(currentBlockNumber);
|
QTextBlock currentBlock = doc->findBlockByNumber(currentBlockNumber);
|
||||||
|
|
||||||
HighlightingResult result = future.resultAt(from);
|
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
||||||
for (int i = from; i < to && b.isValid(); ) {
|
for (int i = from; i < to; ++i) {
|
||||||
const int blockNumber = int(result.line) - 1;
|
const Ranges ranges = rangesForResult(future.resultAt(i), doc, kindToFormat);
|
||||||
QTC_ASSERT(blockNumber < doc->blockCount(), return);
|
for (const Range &range : ranges)
|
||||||
|
formatRanges[range.block].append(range.formatRange);
|
||||||
|
}
|
||||||
|
|
||||||
// clear formats of blocks until blockNumber
|
for (auto &[block, ranges] : formatRanges) {
|
||||||
while (currentBlockNumber < blockNumber) {
|
while (currentBlock < block) {
|
||||||
highlighter->clearExtraFormats(b);
|
highlighter->clearExtraFormats(currentBlock);
|
||||||
b = b.next();
|
currentBlock = currentBlock.next();
|
||||||
++currentBlockNumber;
|
|
||||||
}
|
}
|
||||||
|
highlighter->setExtraFormats(block, std::move(ranges));
|
||||||
// collect all the formats for the current line
|
currentBlock = block.next();
|
||||||
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;
|
|
||||||
}
|
|
||||||
highlighter->setExtraFormats(b, std::move(formats));
|
|
||||||
b = b.next();
|
|
||||||
++currentBlockNumber;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,21 +138,16 @@ void SemanticHighlighter::setExtraAdditionalFormats(SyntaxHighlighter *highlight
|
|||||||
QTextDocument *doc = highlighter->document();
|
QTextDocument *doc = highlighter->document();
|
||||||
QTC_ASSERT(doc, return );
|
QTC_ASSERT(doc, return );
|
||||||
|
|
||||||
QVector<QVector<QTextLayout::FormatRange>> ranges(doc->blockCount());
|
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
||||||
|
|
||||||
for (auto result : results) {
|
for (auto result : results) {
|
||||||
const QTextLayout::FormatRange formatRange = rangeForResult(result, kindToFormat);
|
const Ranges ranges = rangesForResult(result, doc, kindToFormat);
|
||||||
if (formatRange.format.isValid())
|
for (const Range &range : ranges)
|
||||||
ranges[int(result.line) - 1].append(formatRange);
|
formatRanges[range.block].append(range.formatRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int blockNumber = 0; blockNumber < ranges.count(); ++blockNumber) {
|
for (auto &[block, ranges] : formatRanges)
|
||||||
if (!ranges[blockNumber].isEmpty()) {
|
highlighter->setExtraFormats(block, std::move(ranges));
|
||||||
QTextBlock b = doc->findBlockByNumber(blockNumber);
|
|
||||||
QTC_ASSERT(b.isValid(), return );
|
|
||||||
highlighter->setExtraFormats(b, std::move(ranges[blockNumber]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
|
void SemanticHighlighter::clearExtraAdditionalFormatsUntilEnd(
|
||||||
|
Reference in New Issue
Block a user