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); }
|
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
|
class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceClientCapabilities : public JsonObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -601,6 +619,12 @@ public:
|
|||||||
Utils::optional<bool> configuration() const { return optionalValue<bool>(configurationKey); }
|
Utils::optional<bool> configuration() const { return optionalValue<bool>(configurationKey); }
|
||||||
void setConfiguration(bool configuration) { insert(configurationKey, configuration); }
|
void setConfiguration(bool configuration) { insert(configurationKey, configuration); }
|
||||||
void clearConfiguration() { remove(configurationKey); }
|
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
|
class WindowClientClientCapabilities : public JsonObject
|
||||||
|
|||||||
@@ -171,6 +171,7 @@ constexpr char reasonKey[] = "reason";
|
|||||||
constexpr char redKey[] = "red";
|
constexpr char redKey[] = "red";
|
||||||
constexpr char referencesKey[] = "references";
|
constexpr char referencesKey[] = "references";
|
||||||
constexpr char referencesProviderKey[] = "referencesProvider";
|
constexpr char referencesProviderKey[] = "referencesProvider";
|
||||||
|
constexpr char refreshSupportKey[] = "refreshSupport";
|
||||||
constexpr char registerOptionsKey[] = "registerOptions";
|
constexpr char registerOptionsKey[] = "registerOptions";
|
||||||
constexpr char registrationsKey[] = "registrations";
|
constexpr char registrationsKey[] = "registrations";
|
||||||
constexpr char removedKey[] = "removed";
|
constexpr char removedKey[] = "removed";
|
||||||
|
|||||||
@@ -156,4 +156,8 @@ SemanticTokensDeltaResult::SemanticTokensDeltaResult(const QJsonValue &value)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SemanticTokensRefreshRequest::SemanticTokensRefreshRequest()
|
||||||
|
: Request(methodName, nullptr)
|
||||||
|
{}
|
||||||
|
|
||||||
} // namespace LanguageServerProtocol
|
} // namespace LanguageServerProtocol
|
||||||
|
|||||||
@@ -240,4 +240,13 @@ public:
|
|||||||
constexpr static const char methodName[] = "textDocument/semanticTokens/range";
|
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
|
} // namespace LanguageServerProtocol
|
||||||
|
|||||||
@@ -674,7 +674,7 @@ void ClangdTestHighlighting::initTestCase()
|
|||||||
m_results = results;
|
m_results = results;
|
||||||
loop.quit();
|
loop.quit();
|
||||||
};
|
};
|
||||||
connect(client(), &ClangdClient::highlightingResultsReady, handler);
|
connect(client(), &ClangdClient::highlightingResultsReady, &loop, handler);
|
||||||
timer.start(10000);
|
timer.start(10000);
|
||||||
loop.exec();
|
loop.exec();
|
||||||
QVERIFY(timer.isActive());
|
QVERIFY(timer.isActive());
|
||||||
|
|||||||
@@ -170,6 +170,9 @@ static ClientCapabilities generateClientCapabilities()
|
|||||||
workspaceCapabilities.setDidChangeConfiguration(allowDynamicRegistration);
|
workspaceCapabilities.setDidChangeConfiguration(allowDynamicRegistration);
|
||||||
workspaceCapabilities.setExecuteCommand(allowDynamicRegistration);
|
workspaceCapabilities.setExecuteCommand(allowDynamicRegistration);
|
||||||
workspaceCapabilities.setConfiguration(true);
|
workspaceCapabilities.setConfiguration(true);
|
||||||
|
SemanticTokensWorkspaceClientCapabilities semanticTokensWorkspaceClientCapabilities;
|
||||||
|
semanticTokensWorkspaceClientCapabilities.setRefreshSupport(true);
|
||||||
|
workspaceCapabilities.setSemanticTokens(semanticTokensWorkspaceClientCapabilities);
|
||||||
capabilities.setWorkspace(workspaceCapabilities);
|
capabilities.setWorkspace(workspaceCapabilities);
|
||||||
|
|
||||||
TextDocumentClientCapabilities documentCapabilities;
|
TextDocumentClientCapabilities documentCapabilities;
|
||||||
@@ -1363,6 +1366,11 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
|
|||||||
dynamic_cast<const WorkDoneProgressCreateRequest *>(content)->id());
|
dynamic_cast<const WorkDoneProgressCreateRequest *>(content)->id());
|
||||||
response.setResult(nullptr);
|
response.setResult(nullptr);
|
||||||
sendContent(response);
|
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) {
|
} else if (method == ProgressNotification::methodName) {
|
||||||
if (Utils::optional<ProgressParams> params
|
if (Utils::optional<ProgressParams> params
|
||||||
= dynamic_cast<const ProgressNotification *>(content)->params()) {
|
= dynamic_cast<const ProgressNotification *>(content)->params()) {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ LanguageClientManager::LanguageClientManager(QObject *parent)
|
|||||||
JsonRpcMessageHandler::registerMessageProvider<UnregisterCapabilityRequest>();
|
JsonRpcMessageHandler::registerMessageProvider<UnregisterCapabilityRequest>();
|
||||||
JsonRpcMessageHandler::registerMessageProvider<WorkDoneProgressCreateRequest>();
|
JsonRpcMessageHandler::registerMessageProvider<WorkDoneProgressCreateRequest>();
|
||||||
JsonRpcMessageHandler::registerMessageProvider<ProgressNotification>();
|
JsonRpcMessageHandler::registerMessageProvider<ProgressNotification>();
|
||||||
|
JsonRpcMessageHandler::registerMessageProvider<SemanticTokensRefreshRequest>();
|
||||||
connect(EditorManager::instance(), &EditorManager::editorOpened,
|
connect(EditorManager::instance(), &EditorManager::editorOpened,
|
||||||
this, &LanguageClientManager::editorOpened);
|
this, &LanguageClientManager::editorOpened);
|
||||||
connect(EditorManager::instance(), &EditorManager::documentOpened,
|
connect(EditorManager::instance(), &EditorManager::documentOpened,
|
||||||
|
|||||||
@@ -183,6 +183,17 @@ SemanticTokenSupport::SemanticTokenSupport(Client *client)
|
|||||||
&TextEditorSettings::fontSettingsChanged,
|
&TextEditorSettings::fontSettingsChanged,
|
||||||
client,
|
client,
|
||||||
[this]() { updateFormatHash(); });
|
[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)
|
void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
|
||||||
@@ -224,8 +235,11 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
|
|||||||
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
|
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
|
||||||
if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
|
if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
|
||||||
const Utils::FilePath filePath = textDocument->filePath();
|
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 (!previousResultId.isEmpty()) {
|
||||||
|
if (m_client->documentVersion(filePath) == versionedToken.version)
|
||||||
|
return;
|
||||||
SemanticTokensDeltaParams params;
|
SemanticTokensDeltaParams params;
|
||||||
params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)));
|
params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)));
|
||||||
params.setPreviousResultId(previousResultId);
|
params.setPreviousResultId(previousResultId);
|
||||||
@@ -325,6 +339,12 @@ void SemanticTokenSupport::updateFormatHash()
|
|||||||
rehighlight();
|
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)
|
void SemanticTokenSupport::setTokenTypesMap(const QMap<QString, int> &tokenTypesMap)
|
||||||
{
|
{
|
||||||
m_tokenTypesMap = tokenTypesMap;
|
m_tokenTypesMap = tokenTypesMap;
|
||||||
|
|||||||
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
namespace Core { class IEditor; }
|
||||||
|
|
||||||
namespace LanguageClient {
|
namespace LanguageClient {
|
||||||
class Client;
|
class Client;
|
||||||
|
|
||||||
@@ -62,11 +64,12 @@ void applyHighlight(TextEditor::TextDocument *doc,
|
|||||||
|
|
||||||
} // namespace SemanticHighligtingSupport
|
} // namespace SemanticHighligtingSupport
|
||||||
|
|
||||||
class SemanticTokenSupport
|
class SemanticTokenSupport : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit SemanticTokenSupport(Client *client);
|
explicit SemanticTokenSupport(Client *client);
|
||||||
|
|
||||||
|
void refresh();
|
||||||
void reloadSemanticTokens(TextEditor::TextDocument *doc);
|
void reloadSemanticTokens(TextEditor::TextDocument *doc);
|
||||||
void updateSemanticTokens(TextEditor::TextDocument *doc);
|
void updateSemanticTokens(TextEditor::TextDocument *doc);
|
||||||
void rehighlight();
|
void rehighlight();
|
||||||
@@ -94,6 +97,7 @@ private:
|
|||||||
void highlight(const Utils::FilePath &filePath);
|
void highlight(const Utils::FilePath &filePath);
|
||||||
void updateFormatHash();
|
void updateFormatHash();
|
||||||
void currentEditorChanged();
|
void currentEditorChanged();
|
||||||
|
void onCurrentEditorChanged(Core::IEditor *editor);
|
||||||
|
|
||||||
Client *m_client = nullptr;
|
Client *m_client = nullptr;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user