CppEditor: Add syntax highlighting for C++ attributes

Fixes: QTCREATORBUG-31241
Change-Id: I7583c3cd08c2ec58ca7702e7758aad6c0e142574
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2024-08-05 14:58:21 +02:00
parent 42925652f1
commit 5e3da690e2
16 changed files with 113 additions and 0 deletions

View File

@@ -29,6 +29,7 @@
<style name="Function"/> <style name="Function"/>
<style name="Macro"/> <style name="Macro"/>
<style name="Keyword" foreground="#45c6d6" italic="true"/> <style name="Keyword" foreground="#45c6d6" italic="true"/>
<style name="Attribute" foreground="#45c6d6" italic="true"/>
<style name="PrimitiveType" foreground="#d69aa7"/> <style name="PrimitiveType" foreground="#d69aa7"/>
<style name="Punctuation"/> <style name="Punctuation"/>
<style name="Operator" foreground="#d6bb9a"/> <style name="Operator" foreground="#d6bb9a"/>

View File

@@ -19,6 +19,7 @@
<style name="Macro"/> <style name="Macro"/>
<style name="Global"/> <style name="Global"/>
<style name="Keyword" foreground="#ffff55"/> <style name="Keyword" foreground="#ffff55"/>
<style name="Attribute" foreground="#ffff55"/>
<style name="PrimitiveType" foreground="#ffff55"/> <style name="PrimitiveType" foreground="#ffff55"/>
<style name="Label" foreground="#ffff55"/> <style name="Label" foreground="#ffff55"/>
<style name="LineNumber" foreground="#888888" background="#232323"/> <style name="LineNumber" foreground="#888888" background="#232323"/>

View File

@@ -25,6 +25,7 @@
<style name="Function" background="#ffffff"/> <style name="Function" background="#ffffff"/>
<style name="Macro" background="#ffffff"/> <style name="Macro" background="#ffffff"/>
<style name="Keyword" foreground="#808000"/> <style name="Keyword" foreground="#808000"/>
<style name="Attribute" foreground="#808000"/>
<style name="PrimitiveType" foreground="#808000"/> <style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/> <style name="Punctuation"/>
<style name="Operator"/> <style name="Operator"/>

View File

@@ -17,6 +17,7 @@
<style name="Function"/> <style name="Function"/>
<style name="Macro"/> <style name="Macro"/>
<style name="Keyword" bold="true"/> <style name="Keyword" bold="true"/>
<style name="Attribute" bold="true"/>
<style name="PrimitiveType" bold="true"/> <style name="PrimitiveType" bold="true"/>
<style name="Label"/> <style name="Label"/>
<style name="LineNumber" foreground="#c7c4c1" background="#efebe7"/> <style name="LineNumber" foreground="#c7c4c1" background="#efebe7"/>

View File

@@ -23,6 +23,7 @@
<style name="Macro"/> <style name="Macro"/>
<style name="Global"/> <style name="Global"/>
<style name="Keyword" foreground="#808bed"/> <style name="Keyword" foreground="#808bed"/>
<style name="Attribute" foreground="#808bed"/>
<style name="PrimitiveType" foreground="#808bed"/> <style name="PrimitiveType" foreground="#808bed"/>
<style name="Label" foreground="#e76000"/> <style name="Label" foreground="#e76000"/>
<style name="LineNumber" foreground="#8b8bcd" background="#2e2e2e"/> <style name="LineNumber" foreground="#8b8bcd" background="#2e2e2e"/>

View File

@@ -11,6 +11,7 @@
<style name="Function" foreground="#000000"/> <style name="Function" foreground="#000000"/>
<style name="Macro" foreground="#000000"/> <style name="Macro" foreground="#000000"/>
<style name="Keyword" foreground="#000080" bold="true"/> <style name="Keyword" foreground="#000080" bold="true"/>
<style name="Attribute" foreground="#000080" bold="true"/>
<style name="PrimitiveType" foreground="#000080" bold="true"/> <style name="PrimitiveType" foreground="#000080" bold="true"/>
<style name="Label" foreground="#800000" bold="true"/> <style name="Label" foreground="#800000" bold="true"/>
<style name="Local" foreground="#000000"/> <style name="Local" foreground="#000000"/>

View File

@@ -35,6 +35,7 @@
<style name="Function"/> <style name="Function"/>
<style name="Macro"/> <style name="Macro"/>
<style name="Keyword" foreground="#78d7ec" italic="true"/> <style name="Keyword" foreground="#78d7ec" italic="true"/>
<style name="Attribute" foreground="#78d7ec" italic="true"/>
<style name="PrimitiveType" foreground="#ff8080"/> <style name="PrimitiveType" foreground="#ff8080"/>
<style name="Punctuation"/> <style name="Punctuation"/>
<style name="Operator" foreground="#a6e22e"/> <style name="Operator" foreground="#a6e22e"/>

View File

@@ -35,6 +35,7 @@
<style name="Function" foreground="#839496"/> <style name="Function" foreground="#839496"/>
<style name="Macro" foreground="#839496"/> <style name="Macro" foreground="#839496"/>
<style name="Keyword" foreground="#709d06"/> <style name="Keyword" foreground="#709d06"/>
<style name="Attribute" foreground="#709d06"/>
<style name="PrimitiveType" foreground="#808000"/> <style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/> <style name="Punctuation"/>
<style name="Operator" foreground="#839496"/> <style name="Operator" foreground="#839496"/>

View File

@@ -35,6 +35,7 @@
<style name="Function" foreground="#657b83"/> <style name="Function" foreground="#657b83"/>
<style name="Macro" foreground="#657b83"/> <style name="Macro" foreground="#657b83"/>
<style name="Keyword" foreground="#709d06"/> <style name="Keyword" foreground="#709d06"/>
<style name="Attribute" foreground="#709d06"/>
<style name="PrimitiveType" foreground="#808000"/> <style name="PrimitiveType" foreground="#808000"/>
<style name="Punctuation"/> <style name="Punctuation"/>
<style name="Operator" foreground="#657b83"/> <style name="Operator" foreground="#657b83"/>

View File

@@ -33,6 +33,15 @@ using namespace CPlusPlus;
namespace CppEditor { namespace CppEditor {
using namespace Internal; using namespace Internal;
union AttributeState {
struct {
quint8 lbrackets: 1;
quint8 rbrackets: 1;
quint8 opened: 6;
};
quint8 state;
};
CppHighlighter::CppHighlighter(QTextDocument *document) : CppHighlighter::CppHighlighter(QTextDocument *document) :
SyntaxHighlighter(document) SyntaxHighlighter(document)
{ {
@@ -79,6 +88,8 @@ void CppHighlighter::highlightBlock(const QString &text)
userData->setFoldingStartIncluded(false); userData->setFoldingStartIncluded(false);
userData->setFoldingEndIncluded(false); userData->setFoldingEndIncluded(false);
} }
AttributeState attrState;
attrState.state = TextDocumentLayout::attributeState(prevBlock);
if (tokens.isEmpty()) { if (tokens.isEmpty()) {
setCurrentBlockState((braceDepth << 8) | lexerState); setCurrentBlockState((braceDepth << 8) | lexerState);
@@ -93,6 +104,7 @@ void CppHighlighter::highlightBlock(const QString &text)
} }
TextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent); TextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
TextDocumentLayout::setExpectedRawStringSuffix(currentBlock(), inheritedRawStringSuffix); TextDocumentLayout::setExpectedRawStringSuffix(currentBlock(), inheritedRawStringSuffix);
TextDocumentLayout::setAttributeState(currentBlock(), attrState.state);
qCDebug(highlighterLog) << "no tokens, storing brace depth" << braceDepth << "and foldingIndent" qCDebug(highlighterLog) << "no tokens, storing brace depth" << braceDepth << "and foldingIndent"
<< foldingIndent; << foldingIndent;
return; return;
@@ -185,6 +197,25 @@ void CppHighlighter::highlightBlock(const QString &text)
if (onlyHighlightComments && !tk.isComment()) if (onlyHighlightComments && !tk.isComment())
continue; continue;
// Handle attributes, i.e. identifiers in pairs of "[[" and "]]".
if (tk.is(T_LBRACKET) && !tk.isOperator()) {
attrState.lbrackets = !attrState.lbrackets;
if (attrState.lbrackets == 0)
++attrState.opened;
continue;
}
if (tk.is(T_RBRACKET) && !tk.isOperator()) {
attrState.rbrackets = !attrState.rbrackets;
if (attrState.rbrackets == 0 && attrState.opened > 0)
--attrState.opened;
continue;
}
attrState.lbrackets = attrState.rbrackets = 0;
if (attrState.opened && (tk.is(T_IDENTIFIER) || (tk.isKeyword() && !tk.is(T_USING)))) {
setFormat(tk.utf16charsBegin(), tk.utf16chars(), formatForCategory(C_ATTRIBUTE));
continue;
}
if (i == 0 && tk.is(T_POUND)) { if (i == 0 && tk.is(T_POUND)) {
setFormatWithSpaces(text, tk.utf16charsBegin(), tk.utf16chars(), setFormatWithSpaces(text, tk.utf16charsBegin(), tk.utf16chars(),
formatForCategory(C_PREPROCESSOR)); formatForCategory(C_PREPROCESSOR));
@@ -297,6 +328,7 @@ void CppHighlighter::highlightBlock(const QString &text)
} }
TextDocumentLayout::setParentheses(currentBlock(), parentheses); TextDocumentLayout::setParentheses(currentBlock(), parentheses);
TextDocumentLayout::setAttributeState(currentBlock(), attrState.state);
TextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent); TextDocumentLayout::setFoldingIndent(currentBlock(), foldingIndent);
setCurrentBlockState(rehighlightNextBlock | (braceDepth << 8) | tokenize.state()); setCurrentBlockState(rehighlightNextBlock | (braceDepth << 8) | tokenize.state());
@@ -655,6 +687,46 @@ private slots:
<< 73 << 17 << 73 << 18 << C_STRING; << 73 << 17 << 73 << 18 << C_STRING;
QTest::newRow("wide char literal with user-defined suffix (suffix)") QTest::newRow("wide char literal with user-defined suffix (suffix)")
<< 73 << 20 << 73 << 22 << C_OVERLOADED_OPERATOR; << 73 << 20 << 73 << 22 << C_OVERLOADED_OPERATOR;
QTest::newRow("separate attributes specs, 1/4, namespace")
<< 75 << 3 << 72 << 5 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 1/4, attr")
<< 75 << 8 << 72 << 20 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 2/4, namespace")
<< 75 << 26 << 72 << 28 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 2/4, attr")
<< 75 << 31 << 72 << 33 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 3/4, namespace")
<< 75 << 39 << 72 << 41 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 3/4, attr")
<< 75 << 44 << 72 << 48 << C_ATTRIBUTE;
QTest::newRow("separate attributes specs, 4/4, attr")
<< 75 << 54 << 72 << 62 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 1/4, namespace")
<< 76 << 3 << 73 << 5 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 1/4, attr")
<< 76 << 8 << 73 << 20 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 2/4, namespace")
<< 76 << 23 << 73 << 25 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 2/4, attr")
<< 76 << 28 << 73 << 32 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 3/4, namespace")
<< 76 << 35 << 73 << 37 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 3/4, attr")
<< 76 << 40 << 73 << 42 << C_ATTRIBUTE;
QTest::newRow("single attributes spec, 4/4, attr")
<< 76 << 45 << 73 << 53 << C_ATTRIBUTE;
QTest::newRow("attributes with using, namespace")
<< 77 << 9 << 74 << 11 << C_ATTRIBUTE;
QTest::newRow("attributes with using, attr 1/3")
<< 77 << 15 << 74 << 19 << C_ATTRIBUTE;
QTest::newRow("attributes with using, attr 2/3")
<< 77 << 22 << 74 << 34 << C_ATTRIBUTE;
QTest::newRow("attributes with using, attr 3/3")
<< 77 << 37 << 74 << 39 << C_ATTRIBUTE;
QTest::newRow("attribute with line split, namespace")
<< 79 << 9 << 76 << 11 << C_ATTRIBUTE;
QTest::newRow("attribute with line split, attr")
<< 79 << 14 << 76 << 26 << C_ATTRIBUTE;
} }
void test() void test()

View File

@@ -71,3 +71,10 @@ static void parenTest2()
wchar_t operator ""_wc(const wchar_t c) { return c; } wchar_t operator ""_wc(const wchar_t c) { return c; }
const auto c = L'c'_wc; const auto c = L'c'_wc;
[[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]] int attr1();
[[gnu::always_inline, gnu::const, gnu::hot, nodiscard]] int attr2();
[[using gnu : const, always_inline, hot]] int attr3[
[
gnu::always_inline]
]();

View File

@@ -543,6 +543,21 @@ TextSuggestion *TextDocumentLayout::suggestion(const QTextBlock &block)
return nullptr; return nullptr;
} }
void TextDocumentLayout::setAttributeState(const QTextBlock &block, quint8 attrState)
{
if (TextBlockUserData * const data = textUserData(block))
data->setAttrState(attrState);
else if (attrState)
userData(block)->setAttrState(attrState);
}
quint8 TextDocumentLayout::attributeState(const QTextBlock &block)
{
if (TextBlockUserData *userData = textUserData(block))
return userData->attrState();
return 0;
}
void TextDocumentLayout::updateSuggestionFormats(const QTextBlock &block, void TextDocumentLayout::updateSuggestionFormats(const QTextBlock &block,
const FontSettings &fontSettings) const FontSettings &fontSettings)
{ {

View File

@@ -153,6 +153,9 @@ public:
TextSuggestion *suggestion() const; TextSuggestion *suggestion() const;
void clearSuggestion(); void clearSuggestion();
void setAttrState(quint8 state) { m_attrState = state; }
quint8 attrState() const { return m_attrState; }
private: private:
TextMarks m_marks; TextMarks m_marks;
int m_foldingIndent : 16; int m_foldingIndent : 16;
@@ -168,6 +171,7 @@ private:
QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic. QByteArray m_expectedRawStringSuffix; // A bit C++-specific, but let's be pragmatic.
std::unique_ptr<QTextDocument> m_replacement; std::unique_ptr<QTextDocument> m_replacement;
std::unique_ptr<TextSuggestion> m_suggestion; std::unique_ptr<TextSuggestion> m_suggestion;
quint8 m_attrState = 0;
}; };
class TEXTEDITOR_EXPORT TextDocumentLayout : public QPlainTextDocumentLayout class TEXTEDITOR_EXPORT TextDocumentLayout : public QPlainTextDocumentLayout
@@ -201,6 +205,8 @@ public:
static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix); static void setExpectedRawStringSuffix(const QTextBlock &block, const QByteArray &suffix);
static QByteArray expectedRawStringSuffix(const QTextBlock &block); static QByteArray expectedRawStringSuffix(const QTextBlock &block);
static TextSuggestion *suggestion(const QTextBlock &block); static TextSuggestion *suggestion(const QTextBlock &block);
static void setAttributeState(const QTextBlock &block, quint8 attrState);
static quint8 attributeState(const QTextBlock &block);
static void updateSuggestionFormats(const QTextBlock &block, static void updateSuggestionFormats(const QTextBlock &block,
const FontSettings &fontSettings); const FontSettings &fontSettings);
static bool updateSuggestion(const QTextBlock &block, static bool updateSuggestion(const QTextBlock &block,

View File

@@ -52,6 +52,7 @@ const char *nameForStyle(TextStyle style)
case C_PREPROCESSOR: return "Preprocessor"; case C_PREPROCESSOR: return "Preprocessor";
case C_MACRO: return "Macro"; case C_MACRO: return "Macro";
case C_LABEL: return "Label"; case C_LABEL: return "Label";
case C_ATTRIBUTE: return "Attribute";
case C_COMMENT: return "Comment"; case C_COMMENT: return "Comment";
case C_DOXYGEN_COMMENT: return "Doxygen.Comment"; case C_DOXYGEN_COMMENT: return "Doxygen.Comment";
case C_DOXYGEN_TAG: return "Doxygen.Tag"; case C_DOXYGEN_TAG: return "Doxygen.Tag";

View File

@@ -50,6 +50,7 @@ enum TextStyle : quint8 {
C_PREPROCESSOR, C_PREPROCESSOR,
C_MACRO, C_MACRO,
C_LABEL, C_LABEL,
C_ATTRIBUTE,
C_COMMENT, C_COMMENT,
C_DOXYGEN_COMMENT, C_DOXYGEN_COMMENT,
C_DOXYGEN_TAG, C_DOXYGEN_TAG,

View File

@@ -251,6 +251,8 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats()
Tr::tr("Macros."), functionFormat); Tr::tr("Macros."), functionFormat);
formatDescr.emplace_back(C_LABEL, Tr::tr("Label"), Tr::tr("Labels for goto statements."), formatDescr.emplace_back(C_LABEL, Tr::tr("Label"), Tr::tr("Labels for goto statements."),
Qt::darkRed); Qt::darkRed);
formatDescr.emplace_back(C_ATTRIBUTE, Tr::tr("Attribute"), Tr::tr("Attributes."),
Qt::darkYellow);
formatDescr.emplace_back(C_COMMENT, Tr::tr("Comment"), formatDescr.emplace_back(C_COMMENT, Tr::tr("Comment"),
Tr::tr("All style of comments except Doxygen comments."), Tr::tr("All style of comments except Doxygen comments."),
Qt::darkGreen); Qt::darkGreen);