forked from qt-creator/qt-creator
LanguageClient: manually track document version
Using the document revision causes issues for some servers. Task-number: QTCREATORBUG-25766 Change-Id: Ic858e19c6fe39e57c9d3124913887aafee0a3cd0 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -222,7 +222,7 @@ void JLSClient::executeCommand(const LanguageServerProtocol::Command &command)
|
|||||||
continue;
|
continue;
|
||||||
LanguageServerProtocol::WorkspaceEdit edit(argument.toObject());
|
LanguageServerProtocol::WorkspaceEdit edit(argument.toObject());
|
||||||
if (edit.isValid())
|
if (edit.isValid())
|
||||||
LanguageClient::applyWorkspaceEdit(edit);
|
LanguageClient::applyWorkspaceEdit(this, edit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Client::executeCommand(command);
|
Client::executeCommand(command);
|
||||||
|
@@ -385,7 +385,9 @@ void Client::openDocument(TextEditor::TextDocument *document)
|
|||||||
item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType()));
|
item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType()));
|
||||||
item.setUri(DocumentUri::fromFilePath(filePath));
|
item.setUri(DocumentUri::fromFilePath(filePath));
|
||||||
item.setText(document->plainText());
|
item.setText(document->plainText());
|
||||||
item.setVersion(document->document()->revision());
|
if (!m_documentVersions.contains(filePath))
|
||||||
|
m_documentVersions[filePath] = 0;
|
||||||
|
item.setVersion(m_documentVersions[filePath]);
|
||||||
sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
|
sendContent(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)));
|
||||||
|
|
||||||
const Client *currentClient = LanguageClientManager::clientForDocument(document);
|
const Client *currentClient = LanguageClientManager::clientForDocument(document);
|
||||||
@@ -547,8 +549,9 @@ void Client::requestDocumentHighlights(TextEditor::TextEditorWidget *widget)
|
|||||||
|
|
||||||
void Client::activateDocument(TextEditor::TextDocument *document)
|
void Client::activateDocument(TextEditor::TextDocument *document)
|
||||||
{
|
{
|
||||||
auto uri = DocumentUri::fromFilePath(document->filePath());
|
const FilePath &filePath = document->filePath();
|
||||||
m_diagnosticManager.showDiagnostics(uri);
|
auto uri = DocumentUri::fromFilePath(filePath);
|
||||||
|
m_diagnosticManager.showDiagnostics(uri, m_documentVersions.value(filePath));
|
||||||
SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities());
|
SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities());
|
||||||
m_tokentSupport.updateSemanticTokens(document);
|
m_tokentSupport.updateSemanticTokens(document);
|
||||||
// only replace the assist provider if the language server support it
|
// only replace the assist provider if the language server support it
|
||||||
@@ -1020,6 +1023,7 @@ bool Client::reset()
|
|||||||
qDeleteAll(m_documentHighlightsTimer);
|
qDeleteAll(m_documentHighlightsTimer);
|
||||||
m_documentHighlightsTimer.clear();
|
m_documentHighlightsTimer.clear();
|
||||||
m_progressManager.reset();
|
m_progressManager.reset();
|
||||||
|
m_documentVersions.clear();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1143,10 +1147,11 @@ void Client::sendPostponedDocumentUpdates()
|
|||||||
|
|
||||||
const QList<TextEditor::TextDocument *> documents = m_documentsToUpdate.keys();
|
const QList<TextEditor::TextDocument *> documents = m_documentsToUpdate.keys();
|
||||||
for (auto document : documents) {
|
for (auto document : documents) {
|
||||||
const auto uri = DocumentUri::fromFilePath(document->filePath());
|
const FilePath &filePath = document->filePath();
|
||||||
|
const auto uri = DocumentUri::fromFilePath(filePath);
|
||||||
m_highlights[uri].clear();
|
m_highlights[uri].clear();
|
||||||
VersionedTextDocumentIdentifier docId(uri);
|
VersionedTextDocumentIdentifier docId(uri);
|
||||||
docId.setVersion(document->document()->revision());
|
docId.setVersion(++m_documentVersions[filePath]);
|
||||||
DidChangeTextDocumentParams params;
|
DidChangeTextDocumentParams params;
|
||||||
params.setTextDocument(docId);
|
params.setTextDocument(docId);
|
||||||
params.setContentChanges(m_documentsToUpdate.take(document));
|
params.setContentChanges(m_documentsToUpdate.take(document));
|
||||||
@@ -1233,7 +1238,7 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
|
|||||||
} else if (method == ApplyWorkspaceEditRequest::methodName) {
|
} else if (method == ApplyWorkspaceEditRequest::methodName) {
|
||||||
auto params = dynamic_cast<const ApplyWorkspaceEditRequest *>(content)->params().value_or(ApplyWorkspaceEditParams());
|
auto params = dynamic_cast<const ApplyWorkspaceEditRequest *>(content)->params().value_or(ApplyWorkspaceEditParams());
|
||||||
if (params.isValid())
|
if (params.isValid())
|
||||||
applyWorkspaceEdit(params.edit());
|
applyWorkspaceEdit(this, params.edit());
|
||||||
else
|
else
|
||||||
logError(params);
|
logError(params);
|
||||||
} else if (method == WorkSpaceFolderRequest::methodName) {
|
} else if (method == WorkSpaceFolderRequest::methodName) {
|
||||||
@@ -1280,7 +1285,7 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms)
|
|||||||
const QList<Diagnostic> &diagnostics = params.diagnostics();
|
const QList<Diagnostic> &diagnostics = params.diagnostics();
|
||||||
m_diagnosticManager.setDiagnostics(uri, diagnostics, params.version());
|
m_diagnosticManager.setDiagnostics(uri, diagnostics, params.version());
|
||||||
if (LanguageClientManager::clientForUri(uri) == this) {
|
if (LanguageClientManager::clientForUri(uri) == this) {
|
||||||
m_diagnosticManager.showDiagnostics(uri);
|
m_diagnosticManager.showDiagnostics(uri, m_documentVersions.value(uri.toFilePath()));
|
||||||
requestCodeActions(uri, diagnostics);
|
requestCodeActions(uri, diagnostics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1303,7 +1308,7 @@ void Client::handleSemanticHighlight(const SemanticHighlightingParams ¶ms)
|
|||||||
uri.toFilePath());
|
uri.toFilePath());
|
||||||
|
|
||||||
if (!doc || LanguageClientManager::clientForDocument(doc) != this
|
if (!doc || LanguageClientManager::clientForDocument(doc) != this
|
||||||
|| (!version.isNull() && doc->document()->revision() != version.value())) {
|
|| (!version.isNull() && m_documentVersions.value(uri.toFilePath()) != version.value())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1333,6 +1338,11 @@ bool Client::documentUpdatePostponed(const Utils::FilePath &fileName) const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Client::documentVersion(const Utils::FilePath &filePath) const
|
||||||
|
{
|
||||||
|
return m_documentVersions.value(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::initializeCallback(const InitializeRequest::Response &initResponse)
|
void Client::initializeCallback(const InitializeRequest::Response &initResponse)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_state == InitializeRequested, return);
|
QTC_ASSERT(m_state == InitializeRequested, return);
|
||||||
|
@@ -145,6 +145,7 @@ public:
|
|||||||
int charsAdded);
|
int charsAdded);
|
||||||
void cursorPositionChanged(TextEditor::TextEditorWidget *widget);
|
void cursorPositionChanged(TextEditor::TextEditorWidget *widget);
|
||||||
bool documentUpdatePostponed(const Utils::FilePath &fileName) const;
|
bool documentUpdatePostponed(const Utils::FilePath &fileName) const;
|
||||||
|
int documentVersion(const Utils::FilePath &filePath) const;
|
||||||
|
|
||||||
// workspace control
|
// workspace control
|
||||||
virtual void setCurrentProject(ProjectExplorer::Project *project);
|
virtual void setCurrentProject(ProjectExplorer::Project *project);
|
||||||
@@ -231,6 +232,7 @@ private:
|
|||||||
LanguageFilter m_languagFilter;
|
LanguageFilter m_languagFilter;
|
||||||
QJsonObject m_initializationOptions;
|
QJsonObject m_initializationOptions;
|
||||||
QMap<TextEditor::TextDocument *, QString> m_openedDocument;
|
QMap<TextEditor::TextDocument *, QString> m_openedDocument;
|
||||||
|
QMap<Utils::FilePath, int> m_documentVersions;
|
||||||
QMap<TextEditor::TextDocument *,
|
QMap<TextEditor::TextDocument *,
|
||||||
QList<LanguageServerProtocol::DidChangeTextDocumentParams::TextDocumentContentChangeEvent>>
|
QList<LanguageServerProtocol::DidChangeTextDocumentParams::TextDocumentContentChangeEvent>>
|
||||||
m_documentsToUpdate;
|
m_documentsToUpdate;
|
||||||
|
@@ -117,14 +117,13 @@ static QTextEdit::ExtraSelection toDiagnosticsSelections(const Diagnostic &diagn
|
|||||||
return QTextEdit::ExtraSelection{cursor, fontSettings.toTextCharFormat(style)};
|
return QTextEdit::ExtraSelection{cursor, fontSettings.toTextCharFormat(style)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticManager::showDiagnostics(const DocumentUri &uri)
|
void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version)
|
||||||
{
|
{
|
||||||
const FilePath &filePath = uri.toFilePath();
|
const FilePath &filePath = uri.toFilePath();
|
||||||
if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) {
|
if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) {
|
||||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||||
const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri);
|
const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri);
|
||||||
const int docRevision = doc->document()->revision();
|
if (versionedDiagnostics.version.value_or(version) == version) {
|
||||||
if (versionedDiagnostics.version.value_or(docRevision) == docRevision) {
|
|
||||||
const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
||||||
const QString tooltip = tr("Copy to Clipboard");
|
const QString tooltip = tr("Copy to Clipboard");
|
||||||
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
||||||
|
@@ -47,7 +47,7 @@ public:
|
|||||||
const Utils::optional<int> &version);
|
const Utils::optional<int> &version);
|
||||||
void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
|
void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
|
||||||
|
|
||||||
void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
|
void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri, int version);
|
||||||
void hideDiagnostics(TextEditor::TextDocument *doc);
|
void hideDiagnostics(TextEditor::TextDocument *doc);
|
||||||
|
|
||||||
void clearDiagnostics();
|
void clearDiagnostics();
|
||||||
|
@@ -50,7 +50,7 @@ public:
|
|||||||
void perform() override
|
void perform() override
|
||||||
{
|
{
|
||||||
if (Utils::optional<WorkspaceEdit> edit = m_action.edit()) {
|
if (Utils::optional<WorkspaceEdit> edit = m_action.edit()) {
|
||||||
applyWorkspaceEdit(*edit);
|
applyWorkspaceEdit(m_client, *edit);
|
||||||
} else if (Utils::optional<Command> command = m_action.command()) {
|
} else if (Utils::optional<Command> command = m_action.command()) {
|
||||||
if (m_client)
|
if (m_client)
|
||||||
m_client->executeCommand(*command);
|
m_client->executeCommand(*command);
|
||||||
|
@@ -78,15 +78,16 @@ ChangeSet editsToChangeSet(const QList<TextEdit> &edits, const QTextDocument *do
|
|||||||
return changeSet;
|
return changeSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool applyTextDocumentEdit(const TextDocumentEdit &edit)
|
bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit)
|
||||||
{
|
{
|
||||||
const QList<TextEdit> &edits = edit.edits();
|
const QList<TextEdit> &edits = edit.edits();
|
||||||
if (edits.isEmpty())
|
if (edits.isEmpty())
|
||||||
return true;
|
return true;
|
||||||
const DocumentUri &uri = edit.textDocument().uri();
|
const DocumentUri &uri = edit.textDocument().uri();
|
||||||
if (TextDocument* doc = TextDocument::textDocumentForFilePath(uri.toFilePath())) {
|
const FilePath &filePath = uri.toFilePath();
|
||||||
|
if (TextDocument* doc = TextDocument::textDocumentForFilePath(filePath)) {
|
||||||
LanguageClientValue<int> version = edit.textDocument().version();
|
LanguageClientValue<int> version = edit.textDocument().version();
|
||||||
if (!version.isNull() && version.value(0) < doc->document()->revision())
|
if (!version.isNull() && version.value(0) < client->documentVersion(filePath))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return applyTextEdits(uri, edits);
|
return applyTextEdits(uri, edits);
|
||||||
@@ -120,14 +121,14 @@ void applyTextEdit(TextDocumentManipulatorInterface &manipulator,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool applyWorkspaceEdit(const WorkspaceEdit &edit)
|
bool applyWorkspaceEdit(const Client *client, const WorkspaceEdit &edit)
|
||||||
{
|
{
|
||||||
bool result = true;
|
bool result = true;
|
||||||
const QList<TextDocumentEdit> &documentChanges
|
const QList<TextDocumentEdit> &documentChanges
|
||||||
= edit.documentChanges().value_or(QList<TextDocumentEdit>());
|
= edit.documentChanges().value_or(QList<TextDocumentEdit>());
|
||||||
if (!documentChanges.isEmpty()) {
|
if (!documentChanges.isEmpty()) {
|
||||||
for (const TextDocumentEdit &documentChange : documentChanges)
|
for (const TextDocumentEdit &documentChange : documentChanges)
|
||||||
result |= applyTextDocumentEdit(documentChange);
|
result |= applyTextDocumentEdit(client, documentChange);
|
||||||
} else {
|
} else {
|
||||||
const WorkspaceEdit::Changes &changes = edit.changes().value_or(WorkspaceEdit::Changes());
|
const WorkspaceEdit::Changes &changes = edit.changes().value_or(WorkspaceEdit::Changes());
|
||||||
for (auto it = changes.cbegin(); it != changes.cend(); ++it)
|
for (auto it = changes.cbegin(); it != changes.cend(); ++it)
|
||||||
@@ -164,8 +165,8 @@ void updateCodeActionRefactoringMarker(Client *client,
|
|||||||
marker.tooltip = action.title();
|
marker.tooltip = action.title();
|
||||||
if (action.edit().has_value()) {
|
if (action.edit().has_value()) {
|
||||||
WorkspaceEdit edit = action.edit().value();
|
WorkspaceEdit edit = action.edit().value();
|
||||||
marker.callback = [edit](const TextEditorWidget *) {
|
marker.callback = [client, edit](const TextEditorWidget *) {
|
||||||
applyWorkspaceEdit(edit);
|
applyWorkspaceEdit(client, edit);
|
||||||
};
|
};
|
||||||
if (diagnostics.isEmpty()) {
|
if (diagnostics.isEmpty()) {
|
||||||
QList<TextEdit> edits;
|
QList<TextEdit> edits;
|
||||||
|
@@ -46,9 +46,9 @@ class Client;
|
|||||||
|
|
||||||
Utils::ChangeSet editsToChangeSet(const QList<LanguageServerProtocol::TextEdit> &edits,
|
Utils::ChangeSet editsToChangeSet(const QList<LanguageServerProtocol::TextEdit> &edits,
|
||||||
const QTextDocument *doc);
|
const QTextDocument *doc);
|
||||||
bool LANGUAGECLIENT_EXPORT applyWorkspaceEdit(const LanguageServerProtocol::WorkspaceEdit &edit);
|
bool LANGUAGECLIENT_EXPORT applyWorkspaceEdit(const Client *client, const LanguageServerProtocol::WorkspaceEdit &edit);
|
||||||
bool LANGUAGECLIENT_EXPORT
|
bool LANGUAGECLIENT_EXPORT
|
||||||
applyTextDocumentEdit(const LanguageServerProtocol::TextDocumentEdit &edit);
|
applyTextDocumentEdit(const Client *client, const LanguageServerProtocol::TextDocumentEdit &edit);
|
||||||
bool LANGUAGECLIENT_EXPORT applyTextEdits(const LanguageServerProtocol::DocumentUri &uri,
|
bool LANGUAGECLIENT_EXPORT applyTextEdits(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
const QList<LanguageServerProtocol::TextEdit> &edits);
|
const QList<LanguageServerProtocol::TextEdit> &edits);
|
||||||
void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator,
|
void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator,
|
||||||
|
Reference in New Issue
Block a user