From baf25e4cdbfb7f58809f72aea5165c14a50eafde Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 19 Oct 2020 18:03:31 +0200 Subject: 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 --- .../clanghighlightingresultreporter.cpp | 7 +-- src/plugins/cpptools/semantichighlighter.cpp | 66 +++++++++++++++++++++- src/plugins/texteditor/semantichighlighter.cpp | 35 ++++++++---- src/plugins/texteditor/semantichighlighter.h | 13 ++++- 4 files changed, 102 insertions(+), 19 deletions(-) diff --git a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp index 46bdbc33ea..7f1e6dc181 100644 --- a/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp +++ b/src/plugins/clangcodemodel/clanghighlightingresultreporter.cpp @@ -197,13 +197,8 @@ void HighlightingResultReporter::run_internal() using ClangBackEnd::HighlightingType; - for (const auto &tokenInfo : m_tokenInfos) { - const HighlightingType mainType = tokenInfo.types.mainHighlightingType; - if (mainType == HighlightingType::StringLiteral) - continue; - + for (const auto &tokenInfo : qAsConst(m_tokenInfos)) reportChunkWise(toHighlightingResult(tokenInfo)); - } if (isCanceled()) return; diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp index 2fdce4c743..a0c21c3b97 100644 --- a/src/plugins/cpptools/semantichighlighter.cpp +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -44,6 +44,69 @@ static Q_LOGGING_CATEGORY(log, "qtc.cpptools.semantichighlighter", QtWarningMsg) namespace CppTools { +static const QList> +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) : QObject(baseTextDocument) , m_baseTextDocument(baseTextDocument) @@ -94,7 +157,8 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) SyntaxHighlighter *highlighter = m_baseTextDocument->syntaxHighlighter(); 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() diff --git a/src/plugins/texteditor/semantichighlighter.cpp b/src/plugins/texteditor/semantichighlighter.cpp index 22a5ecf3c9..8572295b9f 100644 --- a/src/plugins/texteditor/semantichighlighter.cpp +++ b/src/plugins/texteditor/semantichighlighter.cpp @@ -47,9 +47,8 @@ public: }; using Ranges = QVector; -Ranges rangesForResult(const HighlightingResult &result, - QTextDocument *doc, - const QHash &kindToFormat) +const Ranges rangesForResult(const HighlightingResult &result, const QTextBlock &startBlock, + const QHash &kindToFormat) { const QTextCharFormat format = result.useTextSyles ? TextEditorSettings::fontSettings().toTextCharFormat(result.textStyles) @@ -58,7 +57,7 @@ Ranges rangesForResult(const HighlightingResult &result, return {}; HighlightingResult curResult = result; - QTextBlock curBlock = doc->findBlockByNumber(curResult.line - 1); + QTextBlock curBlock = startBlock; Ranges ranges; while (curBlock.isValid()) { Range range; @@ -78,13 +77,29 @@ Ranges rangesForResult(const HighlightingResult &result, return ranges; } +const Ranges rangesForResult( + const HighlightingResult &result, + QTextDocument *doc, + const QHash &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 &future, int from, int to, - const QHash &kindToFormat) + const QHash &kindToFormat, + const Splitter &splitter) { if (to <= from) return; @@ -112,8 +127,7 @@ void SemanticHighlighter::incrementalApplyExtraAdditionalFormats( std::map> formatRanges; for (int i = from; i < to; ++i) { - const Ranges ranges = rangesForResult(future.resultAt(i), doc, kindToFormat); - for (const Range &range : ranges) + for (const Range &range : rangesForResult(future.resultAt(i), doc, kindToFormat, splitter)) formatRanges[range.block].append(range.formatRange); } @@ -141,8 +155,7 @@ void SemanticHighlighter::setExtraAdditionalFormats(SyntaxHighlighter *highlight std::map> formatRanges; for (auto result : results) { - const Ranges ranges = rangesForResult(result, doc, kindToFormat); - for (const Range &range : ranges) + for (const Range &range : rangesForResult(result, doc, kindToFormat)) formatRanges[range.block].append(range.formatRange); } diff --git a/src/plugins/texteditor/semantichighlighter.h b/src/plugins/texteditor/semantichighlighter.h index 330f9c8f05..35573261c2 100644 --- a/src/plugins/texteditor/semantichighlighter.h +++ b/src/plugins/texteditor/semantichighlighter.h @@ -33,6 +33,13 @@ #include #include +#include +#include + +QT_BEGIN_NAMESPACE +class QTextBlock; +QT_END_NAMESPACE + namespace TextEditor { class SyntaxHighlighter; @@ -76,6 +83,9 @@ using HighlightingResults = QList; namespace SemanticHighlighter { +using Splitter = std::function> + (const HighlightingResult &, const QTextBlock &)>; + // Applies the future results [from, to) and applies the extra formats // indicated by Result::kind and kindToFormat to the correct location using // SyntaxHighlighter::setExtraAdditionalFormats. @@ -87,7 +97,8 @@ void TEXTEDITOR_EXPORT incrementalApplyExtraAdditionalFormats( SyntaxHighlighter *highlighter, const QFuture &future, int from, int to, - const QHash &kindToFormat); + const QHash &kindToFormat, + const Splitter &splitter = {}); // Clears all extra highlights and applies the extra formats // indicated by Result::kind and kindToFormat to the correct location using -- cgit v1.2.3