From a6b2cb67db47ce46ec5a1d94ecd961069c3d9b11 Mon Sep 17 00:00:00 2001 From: Semih Yavuz Date: Mon, 28 Oct 2024 16:51:52 +0100 Subject: [PATCH] Make qmlls semantic highlighting optional Qmlls semantic highlighting in QtC occasionally flickers on editing the document. Since this might be disturbing to some users, we should be able to toggle its switch so that they can enable/disable it. By default, it is disabled. Add an option in the qml language server preferences to switch highlighter module. Add a check in highlighter() to test if there is actually semantic highlighting request. Otherwise, it is invoked on the initialization of the language client unconditionally which wouldn't respect the settings. Task-number: QTCREATORBUG-31215 Change-Id: I1d7df44071053993839860087fb0ab6ede61e145 Reviewed-by: Fabian Kosmale --- .../semantichighlightsupport.cpp | 2 ++ .../qmljseditor/qmljseditordocument.cpp | 11 ++++++-- .../qmljseditor/qmljseditorsettings.cpp | 9 +++++++ src/plugins/qmljseditor/qmljseditorsettings.h | 2 ++ src/plugins/qmljseditor/qmllsclient.cpp | 26 +++++++++++++++++++ src/plugins/qmljseditor/qmllsclient.h | 1 + 6 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index cb199950947..03d62cb61f8 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -418,6 +418,8 @@ void SemanticTokenSupport::highlight(const Utils::FilePath &filePath, bool force TextDocument *doc = TextDocument::textDocumentForFilePath(filePath); if (!doc || LanguageClientManager::clientForDocument(doc) != m_client) return; + if (supportedSemanticRequests(doc).testFlag(SemanticRequestType::None)) + return; SyntaxHighlighter *highlighter = doc->syntaxHighlighter(); if (!highlighter) return; diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index 444a5407304..1bec169fe1e 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -734,7 +734,7 @@ void QmlJSEditorDocumentPrivate::setSourcesWithCapabilities( setSemanticWarningSource(QmllsStatus::Source::Qmlls); else setSemanticWarningSource(QmllsStatus::Source::EmbeddedCodeModel); - if (cap.semanticTokensProvider()) + if (cap.semanticTokensProvider() && settings().enableQmllsSemanticHighlighting()) setSemanticHighlightSource(QmllsStatus::Source::Qmlls); else setSemanticHighlightSource(QmllsStatus::Source::EmbeddedCodeModel); @@ -765,8 +765,14 @@ void QmlJSEditorDocumentPrivate::settingsChanged() return; FilePath newQmlls = qmllsForFile(q->filePath(), ModelManagerInterface::instance()); - if (m_qmllsStatus.qmllsPath == newQmlls) + if (m_qmllsStatus.qmllsPath == newQmlls) { + if (QmllsClient *client = QmllsClient::clientForQmlls(newQmlls)) { + client->updateQmllsSemanticHighlightingCapability(); + setSourcesWithCapabilities(client->capabilities()); + client->activateDocument(q); + } return; + } using namespace LanguageClient; m_qmllsStatus.qmllsPath = newQmlls; @@ -788,6 +794,7 @@ void QmlJSEditorDocumentPrivate::settingsChanged() if (client == oldClient) shouldActivate = true; } + client->updateQmllsSemanticHighlightingCapability(); switch (client->state()) { case Client::State::Uninitialized: case Client::State::InitializeRequested: diff --git a/src/plugins/qmljseditor/qmljseditorsettings.cpp b/src/plugins/qmljseditor/qmljseditorsettings.cpp index 84cdfed95f4..f731e27a0f9 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.cpp +++ b/src/plugins/qmljseditor/qmljseditorsettings.cpp @@ -61,6 +61,7 @@ const char USE_GLOBAL_SETTINGS[] = "QmlJSEditor.UseGlobalSettings"; const char USE_QMLLS[] = "QmlJSEditor.UseQmlls"; const char USE_LATEST_QMLLS[] = "QmlJSEditor.UseLatestQmlls"; const char IGNORE_MINIMUM_QMLLS_VERSION[] = "QmlJSEditor.IgnoreMinimumQmllsVersion"; +const char USE_QMLLS_SEMANTIC_HIGHLIGHTING[] = "QmlJSEditor.EnableQmllsSemanticHighlighting"; const char DISABLE_BUILTIN_CODEMODEL[] = "QmlJSEditor.DisableBuiltinCodemodel"; const char GENERATE_QMLLS_INI_FILES[] = "QmlJSEditor.GenerateQmllsIniFiles"; const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode"; @@ -150,6 +151,7 @@ void QmllsSettingsManager::checkForChanges() && m_useLatestQmlls == newSettings.useLatestQmlls() && m_disableBuiltinCodemodel == newSettings.disableBuiltinCodemodel() && m_generateQmllsIniFiles == newSettings.generateQmllsIniFiles() + && m_enableQmllsSemanticHighlighting == newSettings.enableQmllsSemanticHighlighting() && newLatest == m_latestQmlls) return; qCDebug(qmllsLog) << "qmlls settings changed:" << newSettings.useQmlls() @@ -160,6 +162,7 @@ void QmllsSettingsManager::checkForChanges() m_useQmlls = newSettings.useQmlls(); m_useLatestQmlls = newSettings.useLatestQmlls(); m_disableBuiltinCodemodel = newSettings.disableBuiltinCodemodel(); + m_enableQmllsSemanticHighlighting = newSettings.enableQmllsSemanticHighlighting(); m_generateQmllsIniFiles = newSettings.generateQmllsIniFiles(); } emit settingsChanged(); @@ -263,6 +266,10 @@ QmlJsEditingSettings::QmlJsEditingSettings() Tr::tr("Allow versions below Qt %1") .arg(QmlJsEditingSettings::mininumQmllsVersion.toString())); + enableQmllsSemanticHighlighting.setSettingsKey(group, USE_QMLLS_SEMANTIC_HIGHLIGHTING); + enableQmllsSemanticHighlighting.setLabelText( + Tr::tr("Enable semantic highlighting (experimental)")); + useCustomFormatCommand.setSettingsKey(group, CUSTOM_COMMAND); useCustomFormatCommand.setLabelText( Tr::tr("Use custom command instead of built-in formatter")); @@ -296,6 +303,7 @@ QmlJsEditingSettings::QmlJsEditingSettings() disableBuiltinCodemodel.setEnabler(&useQmlls); generateQmllsIniFiles.setEnabler(&useQmlls); ignoreMinimumQmllsVersion.setEnabler(&useQmlls); + enableQmllsSemanticHighlighting.setEnabler(&useQmlls); formatCommand.setEnabler(&useCustomFormatCommand); formatCommandOptions.setEnabler(&useCustomFormatCommand); } @@ -422,6 +430,7 @@ public: s.useQmlls, s.ignoreMinimumQmllsVersion, s.disableBuiltinCodemodel, + s.enableQmllsSemanticHighlighting, s.useLatestQmlls, s.generateQmllsIniFiles }, diff --git a/src/plugins/qmljseditor/qmljseditorsettings.h b/src/plugins/qmljseditor/qmljseditorsettings.h index a58c755b89e..4aa1608d7c3 100644 --- a/src/plugins/qmljseditor/qmljseditorsettings.h +++ b/src/plugins/qmljseditor/qmljseditorsettings.h @@ -34,6 +34,7 @@ public: Utils::BoolAspect useQmlls{this}; Utils::BoolAspect useLatestQmlls{this}; Utils::BoolAspect ignoreMinimumQmllsVersion{this}; + Utils::BoolAspect enableQmllsSemanticHighlighting{this}; Utils::BoolAspect disableBuiltinCodemodel{this}; Utils::BoolAspect generateQmllsIniFiles{this}; Utils::SelectionAspect uiQmlOpenMode{this}; @@ -67,6 +68,7 @@ private: bool m_useLatestQmlls = false; bool m_disableBuiltinCodemodel = false; bool m_generateQmllsIniFiles = false; + bool m_enableQmllsSemanticHighlighting = false; Utils::FilePath m_latestQmlls; }; diff --git a/src/plugins/qmljseditor/qmllsclient.cpp b/src/plugins/qmljseditor/qmllsclient.cpp index 8dbf7082679..f551b0b109f 100644 --- a/src/plugins/qmljseditor/qmllsclient.cpp +++ b/src/plugins/qmljseditor/qmllsclient.cpp @@ -5,6 +5,7 @@ #include "qmljseditorconstants.h" #include "qmljseditortr.h" +#include "qmljseditorsettings.h" #include #include @@ -82,6 +83,30 @@ QMap QmllsClient::semanticTokenTypesMap() return result; } +void QmllsClient::updateQmllsSemanticHighlightingCapability() +{ + const QString methodName = QStringLiteral("textDocument/semanticTokens"); + if (!QmlJSEditor::Internal::settings().enableQmllsSemanticHighlighting()) { + LanguageServerProtocol::Unregistration unregister; + unregister.setMethod(methodName); + unregister.setId({}); + this->unregisterCapabilities({unregister}); + } else { + const LanguageServerProtocol::ServerCapabilities &caps = this->capabilities(); + const std::optional &options + = caps.semanticTokensProvider(); + if (options) { + LanguageServerProtocol::Registration registeration; + registeration.setMethod(methodName); + registeration.setId({}); + registeration.setRegisterOptions({*options}); + this->registerCapabilities({registeration}); + } else { + qCWarning(qmllsLog) << "qmlls does not support semantic highlighting"; + } + } +} + QmllsClient::QmllsClient(StdIOClientInterface *interface) : Client(interface) { @@ -162,6 +187,7 @@ QmllsClient::~QmllsClient() void QmllsClient::startImpl() { + updateQmllsSemanticHighlightingCapability(); Client::startImpl(); } diff --git a/src/plugins/qmljseditor/qmllsclient.h b/src/plugins/qmljseditor/qmllsclient.h index 049e78311b1..a174d0f0e2d 100644 --- a/src/plugins/qmljseditor/qmllsclient.h +++ b/src/plugins/qmljseditor/qmllsclient.h @@ -55,6 +55,7 @@ public: void startImpl() override; static QmllsClient *clientForQmlls(const Utils::FilePath &qmlls); + void updateQmllsSemanticHighlightingCapability(); private: static QMap semanticTokenTypesMap(); };