forked from qt-creator/qt-creator
LanguageClient: support semanticTokens/refresh
Fixes: QTCREATORBUG-26499 Change-Id: Icd5879609bb856797fa223394357a1f15554d2cf Reviewed-by: Christian Kandeler <christian.kandeler@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -529,6 +529,24 @@ public:
|
||||
void clearSemanticTokens() { remove(semanticTokensKey); }
|
||||
};
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensWorkspaceClientCapabilities : public JsonObject
|
||||
{
|
||||
public:
|
||||
using JsonObject::JsonObject;
|
||||
/**
|
||||
* Whether the client implementation supports a refresh request sent from
|
||||
* the server to the client.
|
||||
*
|
||||
* Note that this event is global and will force the client to refresh all
|
||||
* semantic tokens currently shown. It should be used with absolute care
|
||||
* and is useful for situation where a server for example detect a project
|
||||
* wide change that requires such a calculation.
|
||||
*/
|
||||
Utils::optional<bool> refreshSupport() const { return optionalValue<bool>(refreshSupportKey); }
|
||||
void setRefreshSupport(bool refreshSupport) { insert(refreshSupportKey, refreshSupport); }
|
||||
void clearRefreshSupport() { remove(refreshSupportKey); }
|
||||
};
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceClientCapabilities : public JsonObject
|
||||
{
|
||||
public:
|
||||
@@ -601,6 +619,12 @@ public:
|
||||
Utils::optional<bool> configuration() const { return optionalValue<bool>(configurationKey); }
|
||||
void setConfiguration(bool configuration) { insert(configurationKey, configuration); }
|
||||
void clearConfiguration() { remove(configurationKey); }
|
||||
|
||||
Utils::optional<SemanticTokensWorkspaceClientCapabilities> semanticTokens() const
|
||||
{ return optionalValue<SemanticTokensWorkspaceClientCapabilities>(semanticTokensKey); }
|
||||
void setSemanticTokens(const SemanticTokensWorkspaceClientCapabilities &semanticTokens)
|
||||
{ insert(semanticTokensKey, semanticTokens); }
|
||||
void clearSemanticTokens() { remove(semanticTokensKey); }
|
||||
};
|
||||
|
||||
class WindowClientClientCapabilities : public JsonObject
|
||||
|
||||
@@ -171,6 +171,7 @@ constexpr char reasonKey[] = "reason";
|
||||
constexpr char redKey[] = "red";
|
||||
constexpr char referencesKey[] = "references";
|
||||
constexpr char referencesProviderKey[] = "referencesProvider";
|
||||
constexpr char refreshSupportKey[] = "refreshSupport";
|
||||
constexpr char registerOptionsKey[] = "registerOptions";
|
||||
constexpr char registrationsKey[] = "registrations";
|
||||
constexpr char removedKey[] = "removed";
|
||||
|
||||
@@ -156,4 +156,8 @@ SemanticTokensDeltaResult::SemanticTokensDeltaResult(const QJsonValue &value)
|
||||
}
|
||||
}
|
||||
|
||||
SemanticTokensRefreshRequest::SemanticTokensRefreshRequest()
|
||||
: Request(methodName, nullptr)
|
||||
{}
|
||||
|
||||
} // namespace LanguageServerProtocol
|
||||
|
||||
@@ -240,4 +240,13 @@ public:
|
||||
constexpr static const char methodName[] = "textDocument/semanticTokens/range";
|
||||
};
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT SemanticTokensRefreshRequest
|
||||
: public Request<std::nullptr_t, std::nullptr_t, std::nullptr_t>
|
||||
{
|
||||
public:
|
||||
explicit SemanticTokensRefreshRequest();
|
||||
using Request::Request;
|
||||
constexpr static const char methodName[] = "workspace/semanticTokens/refresh";
|
||||
};
|
||||
|
||||
} // namespace LanguageServerProtocol
|
||||
|
||||
@@ -674,7 +674,7 @@ void ClangdTestHighlighting::initTestCase()
|
||||
m_results = results;
|
||||
loop.quit();
|
||||
};
|
||||
connect(client(), &ClangdClient::highlightingResultsReady, handler);
|
||||
connect(client(), &ClangdClient::highlightingResultsReady, &loop, handler);
|
||||
timer.start(10000);
|
||||
loop.exec();
|
||||
QVERIFY(timer.isActive());
|
||||
|
||||
@@ -170,6 +170,9 @@ static ClientCapabilities generateClientCapabilities()
|
||||
workspaceCapabilities.setDidChangeConfiguration(allowDynamicRegistration);
|
||||
workspaceCapabilities.setExecuteCommand(allowDynamicRegistration);
|
||||
workspaceCapabilities.setConfiguration(true);
|
||||
SemanticTokensWorkspaceClientCapabilities semanticTokensWorkspaceClientCapabilities;
|
||||
semanticTokensWorkspaceClientCapabilities.setRefreshSupport(true);
|
||||
workspaceCapabilities.setSemanticTokens(semanticTokensWorkspaceClientCapabilities);
|
||||
capabilities.setWorkspace(workspaceCapabilities);
|
||||
|
||||
TextDocumentClientCapabilities documentCapabilities;
|
||||
@@ -1363,6 +1366,11 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
|
||||
dynamic_cast<const WorkDoneProgressCreateRequest *>(content)->id());
|
||||
response.setResult(nullptr);
|
||||
sendContent(response);
|
||||
} else if (method == SemanticTokensRefreshRequest::methodName) {
|
||||
m_tokenSupport.refresh();
|
||||
Response<std::nullptr_t, JsonObject> response(id);
|
||||
response.setResult(nullptr);
|
||||
sendContent(response);
|
||||
} else if (method == ProgressNotification::methodName) {
|
||||
if (Utils::optional<ProgressParams> params
|
||||
= dynamic_cast<const ProgressNotification *>(content)->params()) {
|
||||
|
||||
@@ -71,6 +71,7 @@ LanguageClientManager::LanguageClientManager(QObject *parent)
|
||||
JsonRpcMessageHandler::registerMessageProvider<UnregisterCapabilityRequest>();
|
||||
JsonRpcMessageHandler::registerMessageProvider<WorkDoneProgressCreateRequest>();
|
||||
JsonRpcMessageHandler::registerMessageProvider<ProgressNotification>();
|
||||
JsonRpcMessageHandler::registerMessageProvider<SemanticTokensRefreshRequest>();
|
||||
connect(EditorManager::instance(), &EditorManager::editorOpened,
|
||||
this, &LanguageClientManager::editorOpened);
|
||||
connect(EditorManager::instance(), &EditorManager::documentOpened,
|
||||
|
||||
@@ -183,6 +183,17 @@ SemanticTokenSupport::SemanticTokenSupport(Client *client)
|
||||
&TextEditorSettings::fontSettingsChanged,
|
||||
client,
|
||||
[this]() { updateFormatHash(); });
|
||||
QObject::connect(Core::EditorManager::instance(),
|
||||
&Core::EditorManager::currentEditorChanged,
|
||||
this,
|
||||
&SemanticTokenSupport::onCurrentEditorChanged);
|
||||
}
|
||||
|
||||
void SemanticTokenSupport::refresh()
|
||||
{
|
||||
m_tokens.clear();
|
||||
for (Core::IEditor *editor : Core::EditorManager::visibleEditors())
|
||||
onCurrentEditorChanged(editor);
|
||||
}
|
||||
|
||||
void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
|
||||
@@ -224,8 +235,11 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
|
||||
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
|
||||
if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
|
||||
const Utils::FilePath filePath = textDocument->filePath();
|
||||
const QString &previousResultId = m_tokens.value(filePath).tokens.resultId().value_or(QString());
|
||||
const VersionedTokens versionedToken = m_tokens.value(filePath);
|
||||
const QString &previousResultId = versionedToken.tokens.resultId().value_or(QString());
|
||||
if (!previousResultId.isEmpty()) {
|
||||
if (m_client->documentVersion(filePath) == versionedToken.version)
|
||||
return;
|
||||
SemanticTokensDeltaParams params;
|
||||
params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)));
|
||||
params.setPreviousResultId(previousResultId);
|
||||
@@ -325,6 +339,12 @@ void SemanticTokenSupport::updateFormatHash()
|
||||
rehighlight();
|
||||
}
|
||||
|
||||
void SemanticTokenSupport::onCurrentEditorChanged(Core::IEditor *editor)
|
||||
{
|
||||
if (auto textEditor = qobject_cast<BaseTextEditor *>(editor))
|
||||
updateSemanticTokens(textEditor->textDocument());
|
||||
}
|
||||
|
||||
void SemanticTokenSupport::setTokenTypesMap(const QMap<QString, int> &tokenTypesMap)
|
||||
{
|
||||
m_tokenTypesMap = tokenTypesMap;
|
||||
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace Core { class IEditor; }
|
||||
|
||||
namespace LanguageClient {
|
||||
class Client;
|
||||
|
||||
@@ -62,11 +64,12 @@ void applyHighlight(TextEditor::TextDocument *doc,
|
||||
|
||||
} // namespace SemanticHighligtingSupport
|
||||
|
||||
class SemanticTokenSupport
|
||||
class SemanticTokenSupport : public QObject
|
||||
{
|
||||
public:
|
||||
explicit SemanticTokenSupport(Client *client);
|
||||
|
||||
void refresh();
|
||||
void reloadSemanticTokens(TextEditor::TextDocument *doc);
|
||||
void updateSemanticTokens(TextEditor::TextDocument *doc);
|
||||
void rehighlight();
|
||||
@@ -94,6 +97,7 @@ private:
|
||||
void highlight(const Utils::FilePath &filePath);
|
||||
void updateFormatHash();
|
||||
void currentEditorChanged();
|
||||
void onCurrentEditorChanged(Core::IEditor *editor);
|
||||
|
||||
Client *m_client = nullptr;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user