diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index 431d84279df..cb199950947 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -36,6 +36,29 @@ SemanticTokenSupport::SemanticTokenSupport(Client *client) &Core::EditorManager::currentEditorChanged, this, &SemanticTokenSupport::onCurrentEditorChanged); + m_textStyleForTokenType = [](int tokenType) -> std::optional { + switch (tokenType) { + case namespaceToken: return C_NAMESPACE; + case typeToken: return C_TYPE; + case classToken: return C_TYPE; + case structToken: return C_TYPE; + case enumMemberToken: return C_ENUMERATION; + case typeParameterToken: return C_FIELD; + case parameterToken: return C_PARAMETER; + case variableToken: return C_LOCAL; + case functionToken: return C_FUNCTION; + case methodToken: return C_FUNCTION; + case macroToken: return C_MACRO; + case keywordToken: return C_KEYWORD; + case commentToken: return C_COMMENT; + case stringToken: return C_STRING; + case numberToken: return C_NUMBER; + case operatorToken: return C_OPERATOR; + default: + break; + } + return std::nullopt; + }; } void SemanticTokenSupport::refresh() @@ -239,31 +262,13 @@ void SemanticTokenSupport::updateFormatHash() for (int tokenType : std::as_const(m_tokenTypes)) { if (tokenType < 0) continue; - TextStyle style; - switch (tokenType) { - case namespaceToken: style = C_NAMESPACE; break; - case typeToken: style = C_TYPE; break; - case classToken: style = C_TYPE; break; - case structToken: style = C_TYPE; break; - case enumMemberToken: style = C_ENUMERATION; break; - case typeParameterToken: style = C_FIELD; break; - case parameterToken: style = C_PARAMETER; break; - case variableToken: style = C_LOCAL; break; - case functionToken: style = C_FUNCTION; break; - case methodToken: style = C_FUNCTION; break; - case macroToken: style = C_MACRO; break; - case keywordToken: style = C_KEYWORD; break; - case commentToken: style = C_COMMENT; break; - case stringToken: style = C_STRING; break; - case numberToken: style = C_NUMBER; break; - case operatorToken: style = C_OPERATOR; break; - default: + const std::optional style = m_textStyleForTokenType(tokenType); + if (!style) continue; - } int mainHashPart = tokenType << tokenTypeBitOffset; - m_formatHash[mainHashPart] = fontSettings.toTextCharFormat(style); + m_formatHash[mainHashPart] = fontSettings.toTextCharFormat(*style); TextStyles styles; - styles.mainStyle = style; + styles.mainStyle = *style; styles.mixinStyles.initializeElements(); addModifiers(mainHashPart, &m_formatHash, styles, m_tokenModifiers, fontSettings); } diff --git a/src/plugins/languageclient/semantichighlightsupport.h b/src/plugins/languageclient/semantichighlightsupport.h index 25248ab1e93..4af5f35080d 100644 --- a/src/plugins/languageclient/semantichighlightsupport.h +++ b/src/plugins/languageclient/semantichighlightsupport.h @@ -42,6 +42,7 @@ using SemanticTokensHandler = std::function (*)(int); explicit SemanticTokenSupport(Client *client); void refresh(); @@ -61,6 +62,7 @@ public: // void setAdditionalTokenModifierStyles(const QHash &modifierStyles); void setTokensHandler(const SemanticTokensHandler &handler) { m_tokensHandler = handler; } + void setTextStyleForTokenType(TokenToTextStyle callback){ m_textStyleForTokenType = callback; } private: void reloadSemanticTokensImpl(TextEditor::TextDocument *doc, int remainingRerequests = 3); @@ -99,6 +101,7 @@ private: QStringList m_tokenModifierStrings; QSet m_docReloadQueue; QHash m_runningRequests; + TokenToTextStyle m_textStyleForTokenType; }; } // namespace LanguageClient diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index ab239da5053..8dbf7082679 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -13,12 +13,15 @@ #include #include +#include #include #include #include +#include +#include using namespace LanguageClient; using namespace Utils; @@ -66,6 +69,19 @@ QmllsClient *QmllsClient::clientForQmlls(const FilePath &qmlls) return client; } +QMap QmllsClient::semanticTokenTypesMap() +{ + QMap result; + QMetaEnum metaEnum = QMetaEnum::fromType(); + for (auto i = 0; i < metaEnum.keyCount(); ++i) { + auto &&enumName = QString::fromUtf8(metaEnum.key(i)); + enumName.front() = enumName.front().toLower(); + result.insert(std::move(enumName), metaEnum.value(i)); + } + + return result; +} + QmllsClient::QmllsClient(StdIOClientInterface *interface) : Client(interface) { @@ -80,6 +96,63 @@ QmllsClient::QmllsClient(StdIOClientInterface *interface) {"qtCreatorHighlighting", true} }; setInitializationOptions(initializationOptions); + semanticTokenSupport()->setTokenTypesMap(QmllsClient::semanticTokenTypesMap()); + semanticTokenSupport()->setTextStyleForTokenType( + [](int tokenType) -> std::optional { + using namespace TextEditor; + switch (tokenType) { + // customized lsp token types + case QmlSemanticTokens::Namespace: + return C_NAMESPACE; + case QmlSemanticTokens::Type: + return C_QML_TYPE_ID; + case QmlSemanticTokens::Enum: + return C_ENUMERATION; + case QmlSemanticTokens::Parameter: + return C_PARAMETER; + case QmlSemanticTokens::Variable: + return C_JS_SCOPE_VAR; + case QmlSemanticTokens::Property: + return C_BINDING; + case QmlSemanticTokens::EnumMember: + return C_FIELD; + case QmlSemanticTokens::Method: + return C_FUNCTION; + case QmlSemanticTokens::Keyword: + return C_KEYWORD; + case QmlSemanticTokens::Comment: + return C_COMMENT; + case QmlSemanticTokens::String: + return C_STRING; + case QmlSemanticTokens::Number: + return C_NUMBER; + case QmlSemanticTokens::Regexp: + return C_STRING; + case QmlSemanticTokens::Operator: + return C_OPERATOR; + case QmlSemanticTokens::QmlLocalId: + return C_QML_LOCAL_ID; + case QmlSemanticTokens::QmlExternalId: + return C_QML_EXTERNAL_ID; + case QmlSemanticTokens::QmlRootObjectProperty: + return C_QML_ROOT_OBJECT_PROPERTY; + case QmlSemanticTokens::QmlScopeObjectProperty: + return C_QML_SCOPE_OBJECT_PROPERTY; + case QmlSemanticTokens::QmlExternalObjectProperty: + return C_QML_EXTERNAL_OBJECT_PROPERTY; + case QmlSemanticTokens::JsScopeVar: + return C_JS_SCOPE_VAR; + case QmlSemanticTokens::JsImportVar: + return C_JS_IMPORT_VAR; + case QmlSemanticTokens::JsGlobalVar: + return C_JS_GLOBAL_VAR; + case QmlSemanticTokens::QmlStateName: + return C_QML_STATE_NAME; + default: + break; + } + return std::nullopt; + }); } QmllsClient::~QmllsClient() diff --git a/src/plugins/qmljseditor/qmllsclient.h b/src/plugins/qmljseditor/qmllsclient.h index feea95a6683..049e78311b1 100644 --- a/src/plugins/qmljseditor/qmllsclient.h +++ b/src/plugins/qmljseditor/qmllsclient.h @@ -16,11 +16,47 @@ class QMLJSEDITOR_EXPORT QmllsClient : public LanguageClient::Client { Q_OBJECT public: + // Only token types that overlap with the token types registered in the language + // server are highlighted. + // Therefore, this should be matched with the server's token types + enum QmlSemanticTokens { + // Subset of the QLspSpefication::SemanticTokenTypes enum + // We register only the token types used in the qml semantic highlighting + Namespace, + Type, + Enum, + Parameter, + Variable, + Property, + EnumMember, + Method, + Keyword, + Comment, + String, + Number, + Regexp, + Operator, + Decorator, + + // Additional token types for the extended semantic highlighting + QmlLocalId, // object id within the same file + QmlExternalId, // object id defined in another file + QmlRootObjectProperty, // qml property defined in the parent scopes + QmlScopeObjectProperty, // qml property defined in the current scope + QmlExternalObjectProperty, // qml property defined in the root object of another file + JsScopeVar, // js variable defined in the current file + JsImportVar, // js import name that is imported in the qml file + JsGlobalVar, // js global variables + QmlStateName // name of a qml state + }; + Q_ENUM(QmlSemanticTokens); explicit QmllsClient(LanguageClient::StdIOClientInterface *interface); ~QmllsClient(); void startImpl() override; static QmllsClient *clientForQmlls(const Utils::FilePath &qmlls); +private: + static QMap semanticTokenTypesMap(); }; } // namespace QmlJSEditor