forked from qt-creator/qt-creator
ClangCodeModel: Do not ignore highlighting for raw string literals
Also add the special handling for prefix and suffix like in CppHighlighter, as not to re-introduce QTCREATORBUG-19119. Fixes: QTCREATORBUG-16183 Change-Id: Ie264946782220a8e5a862c1d4550bcd49bc2349f Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -197,13 +197,8 @@ void HighlightingResultReporter::run_internal()
|
|||||||
|
|
||||||
using ClangBackEnd::HighlightingType;
|
using ClangBackEnd::HighlightingType;
|
||||||
|
|
||||||
for (const auto &tokenInfo : m_tokenInfos) {
|
for (const auto &tokenInfo : qAsConst(m_tokenInfos))
|
||||||
const HighlightingType mainType = tokenInfo.types.mainHighlightingType;
|
|
||||||
if (mainType == HighlightingType::StringLiteral)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
reportChunkWise(toHighlightingResult(tokenInfo));
|
reportChunkWise(toHighlightingResult(tokenInfo));
|
||||||
}
|
|
||||||
|
|
||||||
if (isCanceled())
|
if (isCanceled())
|
||||||
return;
|
return;
|
||||||
|
@@ -44,6 +44,69 @@ static Q_LOGGING_CATEGORY(log, "qtc.cpptools.semantichighlighter", QtWarningMsg)
|
|||||||
|
|
||||||
namespace CppTools {
|
namespace CppTools {
|
||||||
|
|
||||||
|
static const QList<std::pair<HighlightingResult, QTextBlock>>
|
||||||
|
splitRawStringLiteral(const HighlightingResult &result, const QTextBlock &startBlock)
|
||||||
|
{
|
||||||
|
if (result.textStyles.mainStyle != C_STRING)
|
||||||
|
return {{result, startBlock}};
|
||||||
|
|
||||||
|
QTextCursor cursor(startBlock);
|
||||||
|
cursor.setPosition(cursor.position() + result.column - 1);
|
||||||
|
cursor.setPosition(cursor.position() + result.length, QTextCursor::KeepAnchor);
|
||||||
|
const QString theString = cursor.selectedText();
|
||||||
|
|
||||||
|
// Find all the components of a raw string literal. If we don't succeed, then it's
|
||||||
|
// something else.
|
||||||
|
if (!theString.endsWith('"'))
|
||||||
|
return {{result, startBlock}};
|
||||||
|
int rOffset = -1;
|
||||||
|
if (theString.startsWith("R\"")) {
|
||||||
|
rOffset = 0;
|
||||||
|
} else if (theString.startsWith("LR\"")
|
||||||
|
|| theString.startsWith("uR\"")
|
||||||
|
|| theString.startsWith("UR\"")) {
|
||||||
|
rOffset = 1;
|
||||||
|
} else if (theString.startsWith("u8R\"")) {
|
||||||
|
rOffset = 2;
|
||||||
|
}
|
||||||
|
if (rOffset == -1)
|
||||||
|
return {{result, startBlock}};
|
||||||
|
const int delimiterOffset = rOffset + 2;
|
||||||
|
const int openParenOffset = theString.indexOf('(', delimiterOffset);
|
||||||
|
if (openParenOffset == -1)
|
||||||
|
return {{result, startBlock}};
|
||||||
|
const QStringView delimiter = theString.mid(delimiterOffset, openParenOffset - delimiterOffset);
|
||||||
|
const int endDelimiterOffset = theString.length() - 1 - delimiter.length();
|
||||||
|
if (theString.mid(endDelimiterOffset, delimiter.length()) != delimiter)
|
||||||
|
return {{result, startBlock}};
|
||||||
|
if (theString.at(endDelimiterOffset - 1) != ')')
|
||||||
|
return {{result, startBlock}};
|
||||||
|
|
||||||
|
// Now split the result. For clarity, we display only the actual content as a string,
|
||||||
|
// and the rest (including the delimiter) as a keyword.
|
||||||
|
HighlightingResult prefix = result;
|
||||||
|
prefix.textStyles.mainStyle = C_KEYWORD;
|
||||||
|
prefix.textStyles.mixinStyles = {};
|
||||||
|
prefix.length = delimiterOffset + delimiter.length() + 1;
|
||||||
|
cursor.setPosition(startBlock.position() + result.column - 1 + prefix.length);
|
||||||
|
QTextBlock stringBlock = cursor.block();
|
||||||
|
HighlightingResult actualString = result;
|
||||||
|
actualString.line = stringBlock.blockNumber() + 1;
|
||||||
|
actualString.column = cursor.positionInBlock() + 1;
|
||||||
|
actualString.length = endDelimiterOffset - openParenOffset - 2;
|
||||||
|
cursor.setPosition(cursor.position() + actualString.length);
|
||||||
|
QTextBlock suffixBlock = cursor.block();
|
||||||
|
HighlightingResult suffix = result;
|
||||||
|
suffix.textStyles.mainStyle = C_KEYWORD;
|
||||||
|
suffix.textStyles.mixinStyles = {};
|
||||||
|
suffix.line = suffixBlock.blockNumber() + 1;
|
||||||
|
suffix.column = cursor.positionInBlock() + 1;
|
||||||
|
suffix.length = delimiter.length() + 2;
|
||||||
|
QTC_CHECK(prefix.length + actualString.length + suffix.length == result.length);
|
||||||
|
|
||||||
|
return {{prefix, startBlock}, {actualString, stringBlock}, {suffix, suffixBlock}};
|
||||||
|
}
|
||||||
|
|
||||||
SemanticHighlighter::SemanticHighlighter(TextDocument *baseTextDocument)
|
SemanticHighlighter::SemanticHighlighter(TextDocument *baseTextDocument)
|
||||||
: QObject(baseTextDocument)
|
: QObject(baseTextDocument)
|
||||||
, m_baseTextDocument(baseTextDocument)
|
, m_baseTextDocument(baseTextDocument)
|
||||||
@@ -94,7 +157,8 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to)
|
|||||||
|
|
||||||
SyntaxHighlighter *highlighter = m_baseTextDocument->syntaxHighlighter();
|
SyntaxHighlighter *highlighter = m_baseTextDocument->syntaxHighlighter();
|
||||||
QTC_ASSERT(highlighter, return);
|
QTC_ASSERT(highlighter, return);
|
||||||
incrementalApplyExtraAdditionalFormats(highlighter, m_watcher->future(), from, to, m_formatMap);
|
incrementalApplyExtraAdditionalFormats(highlighter, m_watcher->future(), from, to, m_formatMap,
|
||||||
|
&splitRawStringLiteral);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SemanticHighlighter::onHighlighterFinished()
|
void SemanticHighlighter::onHighlighterFinished()
|
||||||
|
@@ -47,9 +47,8 @@ public:
|
|||||||
};
|
};
|
||||||
using Ranges = QVector<Range>;
|
using Ranges = QVector<Range>;
|
||||||
|
|
||||||
Ranges rangesForResult(const HighlightingResult &result,
|
const Ranges rangesForResult(const HighlightingResult &result, const QTextBlock &startBlock,
|
||||||
QTextDocument *doc,
|
const QHash<int, QTextCharFormat> &kindToFormat)
|
||||||
const QHash<int, QTextCharFormat> &kindToFormat)
|
|
||||||
{
|
{
|
||||||
const QTextCharFormat format = result.useTextSyles
|
const QTextCharFormat format = result.useTextSyles
|
||||||
? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles)
|
? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles)
|
||||||
@@ -58,7 +57,7 @@ Ranges rangesForResult(const HighlightingResult &result,
|
|||||||
return {};
|
return {};
|
||||||
|
|
||||||
HighlightingResult curResult = result;
|
HighlightingResult curResult = result;
|
||||||
QTextBlock curBlock = doc->findBlockByNumber(curResult.line - 1);
|
QTextBlock curBlock = startBlock;
|
||||||
Ranges ranges;
|
Ranges ranges;
|
||||||
while (curBlock.isValid()) {
|
while (curBlock.isValid()) {
|
||||||
Range range;
|
Range range;
|
||||||
@@ -78,13 +77,29 @@ Ranges rangesForResult(const HighlightingResult &result,
|
|||||||
return ranges;
|
return ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Ranges rangesForResult(
|
||||||
|
const HighlightingResult &result,
|
||||||
|
QTextDocument *doc,
|
||||||
|
const QHash<int, QTextCharFormat> &kindToFormat,
|
||||||
|
const Splitter &splitter = {})
|
||||||
|
{
|
||||||
|
const QTextBlock startBlock = doc->findBlockByNumber(result.line - 1);
|
||||||
|
if (splitter) {
|
||||||
|
Ranges ranges;
|
||||||
|
for (const auto &[newResult, newBlock] : splitter(result, startBlock))
|
||||||
|
ranges << rangesForResult(newResult, newBlock, kindToFormat);
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
|
return rangesForResult(result, startBlock, kindToFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
|
}
|
||||||
SyntaxHighlighter *highlighter,
|
|
||||||
|
void SemanticHighlighter::incrementalApplyExtraAdditionalFormats(SyntaxHighlighter *highlighter,
|
||||||
const QFuture<HighlightingResult> &future,
|
const QFuture<HighlightingResult> &future,
|
||||||
int from, int to,
|
int from, int to,
|
||||||
const QHash<int, QTextCharFormat> &kindToFormat)
|
const QHash<int, QTextCharFormat> &kindToFormat,
|
||||||
|
const Splitter &splitter)
|
||||||
{
|
{
|
||||||
if (to <= from)
|
if (to <= from)
|
||||||
return;
|
return;
|
||||||
@@ -112,8 +127,7 @@ void SemanticHighlighter::incrementalApplyExtraAdditionalFormats(
|
|||||||
|
|
||||||
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
||||||
for (int i = from; i < to; ++i) {
|
for (int i = from; i < to; ++i) {
|
||||||
const Ranges ranges = rangesForResult(future.resultAt(i), doc, kindToFormat);
|
for (const Range &range : rangesForResult(future.resultAt(i), doc, kindToFormat, splitter))
|
||||||
for (const Range &range : ranges)
|
|
||||||
formatRanges[range.block].append(range.formatRange);
|
formatRanges[range.block].append(range.formatRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,8 +155,7 @@ void SemanticHighlighter::setExtraAdditionalFormats(SyntaxHighlighter *highlight
|
|||||||
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
std::map<QTextBlock, QVector<QTextLayout::FormatRange>> formatRanges;
|
||||||
|
|
||||||
for (auto result : results) {
|
for (auto result : results) {
|
||||||
const Ranges ranges = rangesForResult(result, doc, kindToFormat);
|
for (const Range &range : rangesForResult(result, doc, kindToFormat))
|
||||||
for (const Range &range : ranges)
|
|
||||||
formatRanges[range.block].append(range.formatRange);
|
formatRanges[range.block].append(range.formatRange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,6 +33,13 @@
|
|||||||
#include <QFuture>
|
#include <QFuture>
|
||||||
#include <QTextCharFormat>
|
#include <QTextCharFormat>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
class QTextBlock;
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
namespace TextEditor {
|
namespace TextEditor {
|
||||||
|
|
||||||
class SyntaxHighlighter;
|
class SyntaxHighlighter;
|
||||||
@@ -76,6 +83,9 @@ using HighlightingResults = QList<HighlightingResult>;
|
|||||||
|
|
||||||
namespace SemanticHighlighter {
|
namespace SemanticHighlighter {
|
||||||
|
|
||||||
|
using Splitter = std::function<const QList<std::pair<HighlightingResult, QTextBlock>>
|
||||||
|
(const HighlightingResult &, const QTextBlock &)>;
|
||||||
|
|
||||||
// Applies the future results [from, to) and applies the extra formats
|
// Applies the future results [from, to) and applies the extra formats
|
||||||
// indicated by Result::kind and kindToFormat to the correct location using
|
// indicated by Result::kind and kindToFormat to the correct location using
|
||||||
// SyntaxHighlighter::setExtraAdditionalFormats.
|
// SyntaxHighlighter::setExtraAdditionalFormats.
|
||||||
@@ -87,7 +97,8 @@ void TEXTEDITOR_EXPORT incrementalApplyExtraAdditionalFormats(
|
|||||||
SyntaxHighlighter *highlighter,
|
SyntaxHighlighter *highlighter,
|
||||||
const QFuture<HighlightingResult> &future,
|
const QFuture<HighlightingResult> &future,
|
||||||
int from, int to,
|
int from, int to,
|
||||||
const QHash<int, QTextCharFormat> &kindToFormat);
|
const QHash<int, QTextCharFormat> &kindToFormat,
|
||||||
|
const Splitter &splitter = {});
|
||||||
|
|
||||||
// Clears all extra highlights and applies the extra formats
|
// Clears all extra highlights and applies the extra formats
|
||||||
// indicated by Result::kind and kindToFormat to the correct location using
|
// indicated by Result::kind and kindToFormat to the correct location using
|
||||||
|
Reference in New Issue
Block a user