LanguageClient: keep semantic tokens after receiving error

A usual error we receive for semantic request is that the request got
canceled. This can be due to external changes. But a server might still
be able to calculate a diff against a previous token set. So just keep
the previously reported tokens and rerequest a new highlight. If the
server is not able to calculate a diff it also might send a full
token set as a result for the delta request according to the protocol.

Fixes: QTCREATORBUG-26624
Change-Id: Ia91e599706519dbbf4cd22050484e4f36cecdab8
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2022-01-14 06:54:41 +01:00
parent dc4b9e48dc
commit 9fea2af1e9
2 changed files with 35 additions and 17 deletions

View File

@@ -67,19 +67,33 @@ void SemanticTokenSupport::refresh()
} }
void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument) void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
{
reloadSemanticTokensImpl(textDocument);
}
void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument,
int remainingRerequests)
{ {
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument); const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
if (supportedRequests.testFlag(SemanticRequestType::None)) if (supportedRequests.testFlag(SemanticRequestType::None))
return; return;
const Utils::FilePath filePath = textDocument->filePath(); const Utils::FilePath filePath = textDocument->filePath();
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath));
auto responseCallback = [this, filePath, documentVersion = m_client->documentVersion(filePath)]( auto responseCallback = [this,
remainingRerequests,
filePath,
documentVersion = m_client->documentVersion(filePath)](
const SemanticTokensFullRequest::Response &response) { const SemanticTokensFullRequest::Response &response) {
if (const auto error = response.error()) { if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT) qCDebug(LOGLSPHIGHLIGHT)
<< "received error" << error->code() << error->message() << "for" << filePath; << "received error" << error->code() << error->message() << "for" << filePath;
if (remainingRerequests > 0) {
if (auto document = TextDocument::textDocumentForFilePath(filePath))
reloadSemanticTokensImpl(document, remainingRerequests - 1);
} }
} else {
handleSemanticTokens(filePath, response.result().value_or(nullptr), documentVersion); handleSemanticTokens(filePath, response.result().value_or(nullptr), documentVersion);
}
}; };
/*if (supportedRequests.testFlag(SemanticRequestType::Range)) { /*if (supportedRequests.testFlag(SemanticRequestType::Range)) {
const int start = widget->firstVisibleBlockNumber(); const int start = widget->firstVisibleBlockNumber();
@@ -107,6 +121,12 @@ void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
} }
void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument) void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
{
updateSemanticTokensImpl(textDocument);
}
void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument,
int remainingRerequests)
{ {
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument); const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) { if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
@@ -122,15 +142,22 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
params.setPreviousResultId(previousResultId); params.setPreviousResultId(previousResultId);
SemanticTokensFullDeltaRequest request(params); SemanticTokensFullDeltaRequest request(params);
request.setResponseCallback( request.setResponseCallback(
[this, filePath, documentVersion]( [this, filePath, documentVersion, remainingRerequests](
const SemanticTokensFullDeltaRequest::Response &response) { const SemanticTokensFullDeltaRequest::Response &response) {
if (const auto error = response.error()) { if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT) << "received error" << error->code() qCDebug(LOGLSPHIGHLIGHT) << "received error" << error->code()
<< error->message() << "for" << filePath; << error->message() << "for" << filePath;
if (auto document = TextDocument::textDocumentForFilePath(filePath)) {
if (remainingRerequests > 0)
updateSemanticTokensImpl(document, remainingRerequests - 1);
else
reloadSemanticTokensImpl(document, 1); // try a full reload once
} }
} else {
handleSemanticTokensDelta(filePath, handleSemanticTokensDelta(filePath,
response.result().value_or(nullptr), response.result().value_or(nullptr),
documentVersion); documentVersion);
}
}); });
qCDebug(LOGLSPHIGHLIGHT) qCDebug(LOGLSPHIGHLIGHT)
<< "Requesting delta for" << filePath << "with version" << documentVersion; << "Requesting delta for" << filePath << "with version" << documentVersion;
@@ -292,11 +319,6 @@ void SemanticTokenSupport::handleSemanticTokens(const Utils::FilePath &filePath,
if (auto tokens = Utils::get_if<SemanticTokens>(&result)) { if (auto tokens = Utils::get_if<SemanticTokens>(&result)) {
m_tokens[filePath] = {*tokens, documentVersion}; m_tokens[filePath] = {*tokens, documentVersion};
highlight(filePath); highlight(filePath);
} else {
qCDebug(LOGLSPHIGHLIGHT)
<< "no data in reply to full semantic tokens request, clearing tokens"
<< m_client->name() << filePath;
m_tokens.remove(filePath);
} }
} }
@@ -363,12 +385,6 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
qCDebug(LOGLSPHIGHLIGHT) << "New Data " << newData; qCDebug(LOGLSPHIGHLIGHT) << "New Data " << newData;
tokens.setData(newData); tokens.setData(newData);
tokens.setResultId(tokensDelta->resultId()); tokens.setResultId(tokensDelta->resultId());
} else {
qCDebug(LOGLSPHIGHLIGHT)
<< "no data in reply to semantic tokens delta request, clearing tokens"
<< m_client->name() << filePath;
m_tokens.remove(filePath);
return;
} }
highlight(filePath); highlight(filePath);
} }

View File

@@ -83,6 +83,8 @@ public:
void setTokensHandler(const SemanticTokensHandler &handler) { m_tokensHandler = handler; } void setTokensHandler(const SemanticTokensHandler &handler) { m_tokensHandler = handler; }
private: private:
void reloadSemanticTokensImpl(TextEditor::TextDocument *doc, int remainingRerequests = 3);
void updateSemanticTokensImpl(TextEditor::TextDocument *doc, int remainingRerequests = 3);
LanguageServerProtocol::SemanticRequestTypes supportedSemanticRequests( LanguageServerProtocol::SemanticRequestTypes supportedSemanticRequests(
TextEditor::TextDocument *document) const; TextEditor::TextDocument *document) const;
void handleSemanticTokens(const Utils::FilePath &filePath, void handleSemanticTokens(const Utils::FilePath &filePath,