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)
{
reloadSemanticTokensImpl(textDocument);
}
void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument,
int remainingRerequests)
{
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
if (supportedRequests.testFlag(SemanticRequestType::None))
return;
const Utils::FilePath filePath = textDocument->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) {
if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT)
<< "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)) {
const int start = widget->firstVisibleBlockNumber();
@@ -107,6 +121,12 @@ void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument)
}
void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
{
updateSemanticTokensImpl(textDocument);
}
void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument,
int remainingRerequests)
{
const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument);
if (supportedRequests.testFlag(SemanticRequestType::FullDelta)) {
@@ -122,15 +142,22 @@ void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument)
params.setPreviousResultId(previousResultId);
SemanticTokensFullDeltaRequest request(params);
request.setResponseCallback(
[this, filePath, documentVersion](
[this, filePath, documentVersion, remainingRerequests](
const SemanticTokensFullDeltaRequest::Response &response) {
if (const auto error = response.error()) {
qCDebug(LOGLSPHIGHLIGHT) << "received error" << error->code()
<< 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,
response.result().value_or(nullptr),
documentVersion);
}
handleSemanticTokensDelta(filePath,
response.result().value_or(nullptr),
documentVersion);
});
qCDebug(LOGLSPHIGHLIGHT)
<< "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)) {
m_tokens[filePath] = {*tokens, documentVersion};
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;
tokens.setData(newData);
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);
}

View File

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