diff options
author | David Schulz <david.schulz@qt.io> | 2022-12-15 07:23:55 +0100 |
---|---|---|
committer | David Schulz <david.schulz@qt.io> | 2022-12-15 09:49:48 +0000 |
commit | 2d0456f08509092b2bd882a723b8b26b2143945a (patch) | |
tree | 8e23b8bc61939755f497793cb823073ac95a42ad /src/plugins/languageclient | |
parent | 0b33a08af1e088670e561fad316f4dfe7fcd265e (diff) | |
download | qt-creator-2d0456f08509092b2bd882a723b8b26b2143945a.tar.gz |
LSP: Support remote LSP file paths
Change-Id: If3cf1b8d675ef091427dbcd703c7d14b384a1b3a
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Diffstat (limited to 'src/plugins/languageclient')
22 files changed, 252 insertions, 166 deletions
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 5c99329675..91fe7a2d80 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -139,6 +139,7 @@ public: , m_hoverHandler(q) , m_symbolSupport(q) , m_tokenSupport(q) + , m_serverDeviceTemplate(clientInterface->serverDeviceTemplate()) { using namespace ProjectExplorer; @@ -329,6 +330,7 @@ public: LanguageServerProtocol::ClientInfo m_clientInfo; QJsonValue m_configuration; int m_completionResultsLimit = -1; + const Utils::FilePath m_serverDeviceTemplate; }; Client::Client(BaseClientInterface *clientInterface) @@ -500,11 +502,11 @@ void Client::initialize() params.setCapabilities(d->m_clientCapabilities); params.setInitializationOptions(d->m_initializationOptions); if (d->m_project) - params.setRootUri(DocumentUri::fromFilePath(d->m_project->projectDirectory())); + params.setRootUri(hostPathToServerUri(d->m_project->projectDirectory())); const QList<WorkSpaceFolder> workspaces - = Utils::transform(SessionManager::projects(), [](Project *pro) { - return WorkSpaceFolder(DocumentUri::fromFilePath(pro->projectDirectory()), + = Utils::transform(SessionManager::projects(), [this](Project *pro) { + return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()), pro->displayName()); }); if (workspaces.isEmpty()) @@ -746,7 +748,6 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg { QTimer *timer = m_documentHighlightsTimer[widget]; if (!timer) { - const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); if (m_highlightRequests.contains(widget)) q->cancelRequest(m_highlightRequests.take(widget)); timer = new QTimer; @@ -771,7 +772,7 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *widget) { QTC_ASSERT(q->reachable(), return); - const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath()); + const auto uri = q->hostPathToServerUri(widget->textDocument()->filePath()); if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) { TextDocumentRegistrationOptions option( m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName)); @@ -833,9 +834,8 @@ void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *w void Client::activateDocument(TextEditor::TextDocument *document) { const FilePath &filePath = document->filePath(); - auto uri = DocumentUri::fromFilePath(filePath); if (d->m_diagnosticManager) - d->m_diagnosticManager->showDiagnostics(uri, d->m_documentVersions.value(filePath)); + d->m_diagnosticManager->showDiagnostics(filePath, d->m_documentVersions.value(filePath)); d->m_tokenSupport.updateSemanticTokens(document); // only replace the assist provider if the language server support it d->updateCompletionProvider(document); @@ -897,7 +897,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString { TextDocumentItem item; item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(mimeType)); - item.setUri(DocumentUri::fromFilePath(filePath)); + item.setUri(q->hostPathToServerUri(filePath)); item.setText(content); item.setVersion(version); q->sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)), @@ -907,7 +907,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString void ClientPrivate::sendCloseNotification(const FilePath &filePath) { q->sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams( - TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})), + TextDocumentIdentifier{q->hostPathToServerUri(filePath)})), Client::SendDocUpdates::Ignore); } @@ -950,7 +950,7 @@ void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &c } else { shadowIt.value().first = content; if (!shadowIt.value().second.isEmpty()) { - VersionedTextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + VersionedTextDocumentIdentifier docId(hostPathToServerUri(filePath)); docId.setVersion(++d->m_documentVersions[filePath]); const DidChangeTextDocumentParams params(docId, content); sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore); @@ -981,7 +981,6 @@ void ClientPrivate::openShadowDocument(const TextEditor::TextDocument *requringD shadowIt.value().second << requringDoc; if (shadowIt.value().second.size() > 1) return; - const auto uri = DocumentUri::fromFilePath(shadowIt.key()); const QString mimeType = mimeTypeForFile(shadowIt.key(), MimeMatchMode::MatchExtension).name(); sendOpenNotification(shadowIt.key(), mimeType, shadowIt.value().first, ++m_documentVersions[shadowIt.key()]); @@ -1021,7 +1020,7 @@ void Client::documentContentsSaved(TextEditor::TextDocument *document) if (!send) return; DidSaveTextDocumentParams params( - TextDocumentIdentifier(DocumentUri::fromFilePath(document->filePath()))); + TextDocumentIdentifier(hostPathToServerUri(document->filePath()))); d->openRequiredShadowDocuments(document); if (includeText) params.setText(document->plainText()); @@ -1053,7 +1052,7 @@ void Client::documentWillSave(Core::IDocument *document) if (!send) return; const WillSaveTextDocumentParams params( - TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); + TextDocumentIdentifier(hostPathToServerUri(filePath))); sendMessage(WillSaveTextDocumentNotification(params)); } @@ -1241,7 +1240,7 @@ void ClientPrivate::requestCodeActions(const DocumentUri &uri, const Range &range, const QList<Diagnostic> &diagnostics) { - const Utils::FilePath fileName = uri.toFilePath(); + const Utils::FilePath fileName = q->serverUriToHostPath(uri); TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(fileName); if (!doc) return; @@ -1273,8 +1272,11 @@ void Client::requestCodeActions(const CodeActionRequest &request) if (!request.isValid(nullptr)) return; - const Utils::FilePath fileName - = request.params().value_or(CodeActionParams()).textDocument().uri().toFilePath(); + const Utils::FilePath fileName = request.params() + .value_or(CodeActionParams()) + .textDocument() + .uri() + .toFilePath(hostPathMapper()); const QString method(CodeActionRequest::methodName); if (std::optional<bool> registered = d->m_dynamicCapabilities.isRegistered(method)) { @@ -1349,7 +1351,7 @@ void Client::projectOpened(ProjectExplorer::Project *project) if (!d->sendWorkspceFolderChanges()) return; WorkspaceFoldersChangeEvent event; - event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + event.setAdded({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), project->displayName())}); DidChangeWorkspaceFoldersParams params; params.setEvent(event); @@ -1361,7 +1363,7 @@ void Client::projectClosed(ProjectExplorer::Project *project) { if (d->sendWorkspceFolderChanges()) { WorkspaceFoldersChangeEvent event; - event.setRemoved({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + event.setRemoved({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()), project->displayName())}); DidChangeWorkspaceFoldersParams params; params.setEvent(event); @@ -1420,7 +1422,7 @@ bool Client::isSupportedFile(const Utils::FilePath &filePath, const QString &mim bool Client::isSupportedUri(const DocumentUri &uri) const { - const FilePath &filePath = uri.toFilePath(); + const FilePath &filePath = serverUriToHostPath(uri); return d->m_languagFilter.isSupported(filePath, Utils::mimeTypeForFile(filePath).name()); } @@ -1434,18 +1436,18 @@ void Client::removeAssistProcessor(TextEditor::IAssistProcessor *processor) d->m_runningAssistProcessors.remove(processor); } -QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const QTextCursor &cursor) const +QList<Diagnostic> Client::diagnosticsAt(const FilePath &filePath, const QTextCursor &cursor) const { if (d->m_diagnosticManager) - return d->m_diagnosticManager->diagnosticsAt(uri, cursor); + return d->m_diagnosticManager->diagnosticsAt(filePath, cursor); return {}; } -bool Client::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, +bool Client::hasDiagnostic(const FilePath &filePath, const LanguageServerProtocol::Diagnostic &diag) const { if (d->m_diagnosticManager) - return d->m_diagnosticManager->hasDiagnostic(uri, documentForFilePath(uri.toFilePath()), diag); + return d->m_diagnosticManager->hasDiagnostic(filePath, documentForFilePath(filePath), diag); return false; } @@ -1708,7 +1710,7 @@ void ClientPrivate::sendPostponedDocumentUpdates(Schedule semanticTokensSchedule [this](const auto &elem) { TextEditor::TextDocument * const document = elem.first; const FilePath &filePath = document->filePath(); - const auto uri = DocumentUri::fromFilePath(filePath); + const LanguageServerProtocol::DocumentUri uri = q->hostPathToServerUri(filePath); VersionedTextDocumentIdentifier docId(uri); docId.setVersion(m_documentVersions[filePath]); DidChangeTextDocumentParams params; @@ -1867,8 +1869,8 @@ void ClientPrivate::handleMethod(const QString &method, const MessageId &id, con } else { response.setResult(Utils::transform( projects, - [](ProjectExplorer::Project *project) { - return WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), + [this](ProjectExplorer::Project *project) { + return WorkSpaceFolder(q->hostPathToServerUri(project->projectDirectory()), project->displayName()); })); } @@ -1906,9 +1908,10 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms) const QList<Diagnostic> &diagnostics = params.diagnostics(); if (!d->m_diagnosticManager) d->m_diagnosticManager = createDiagnosticManager(); - d->m_diagnosticManager->setDiagnostics(uri, diagnostics, params.version()); - if (LanguageClientManager::clientForUri(uri) == this) { - d->m_diagnosticManager->showDiagnostics(uri, d->m_documentVersions.value(uri.toFilePath())); + const FilePath &path = serverUriToHostPath(uri); + d->m_diagnosticManager->setDiagnostics(path, diagnostics, params.version()); + if (LanguageClientManager::clientForFilePath(path) == this) { + d->m_diagnosticManager->showDiagnostics(path, d->m_documentVersions.value(path)); if (d->m_autoRequestCodeActions) requestCodeActions(uri, diagnostics); } @@ -1932,6 +1935,11 @@ int Client::documentVersion(const Utils::FilePath &filePath) const return d->m_documentVersions.value(filePath); } +int Client::documentVersion(const LanguageServerProtocol::DocumentUri &uri) const +{ + return documentVersion(serverUriToHostPath(uri)); +} + void Client::setDocumentChangeUpdateThreshold(int msecs) { d->m_documentUpdateTimer.setInterval(msecs); @@ -2071,6 +2079,25 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const return project() && project()->isKnownFile(filePath); } +DocumentUri::PathMapper Client::hostPathMapper() const +{ + return [serverDeviceTemplate = d->m_serverDeviceTemplate](const Utils::FilePath &serverPath) { + return serverDeviceTemplate.withNewPath(serverPath.path()); + }; +} + +FilePath Client::serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const +{ + return uri.toFilePath(hostPathMapper()); +} + +DocumentUri Client::hostPathToServerUri(const Utils::FilePath &path) const +{ + return DocumentUri::fromFilePath(path, [&](const Utils::FilePath &clientPath){ + return clientPath.onDevice(d->m_serverDeviceTemplate); + }); +} + } // namespace LanguageClient #include <client.moc> diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 7061b9514e..1921e01fe7 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -126,6 +126,7 @@ public: void cursorPositionChanged(TextEditor::TextEditorWidget *widget); bool documentUpdatePostponed(const Utils::FilePath &fileName) const; int documentVersion(const Utils::FilePath &filePath) const; + int documentVersion(const LanguageServerProtocol::DocumentUri &uri) const; void setDocumentChangeUpdateThreshold(int msecs); // workspace control @@ -151,10 +152,9 @@ public: SymbolSupport &symbolSupport(); DocumentSymbolCache *documentSymbolCache(); HoverHandler *hoverHandler(); - QList<LanguageServerProtocol::Diagnostic> diagnosticsAt( - const LanguageServerProtocol::DocumentUri &uri, - const QTextCursor &cursor) const; - bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, + QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(const Utils::FilePath &filePath, + const QTextCursor &cursor) const; + bool hasDiagnostic(const Utils::FilePath &filePath, const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const; void setSemanticTokensHandler(const SemanticTokensHandler &handler); @@ -166,6 +166,10 @@ public: virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool fileBelongsToProject(const Utils::FilePath &filePath) const; + LanguageServerProtocol::DocumentUri::PathMapper hostPathMapper() const; + Utils::FilePath serverUriToHostPath(const LanguageServerProtocol::DocumentUri &uri) const; + LanguageServerProtocol::DocumentUri hostPathToServerUri(const Utils::FilePath &path) const; + // logging enum class LogTarget { Console, Ui }; void setLogTarget(LogTarget target); diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index cb199538e9..a1c23f858c 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -56,12 +56,12 @@ DiagnosticManager::~DiagnosticManager() clearDiagnostics(); } -void DiagnosticManager::setDiagnostics(const DocumentUri &uri, +void DiagnosticManager::setDiagnostics(const FilePath &filePath, const QList<Diagnostic> &diagnostics, const std::optional<int> &version) { - hideDiagnostics(uri.toFilePath()); - m_diagnostics[uri] = {version, filteredDiagnostics(diagnostics)}; + hideDiagnostics(filePath); + m_diagnostics[filePath] = {version, filteredDiagnostics(diagnostics)}; } void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath) @@ -89,12 +89,11 @@ void DiagnosticManager::disableDiagnostics(TextEditor::TextDocument *document) marks.enabled = false; } -void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version) +void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version) { - const FilePath &filePath = uri.toFilePath(); if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) { QList<QTextEdit::ExtraSelection> extraSelections; - const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(uri); + const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(filePath); if (versionedDiagnostics.version.value_or(version) == version && !versionedDiagnostics.diagnostics.isEmpty()) { Marks &marks = m_marks[filePath]; @@ -167,17 +166,17 @@ void DiagnosticManager::forAllMarks(std::function<void (TextEditor::TextMark *)> void DiagnosticManager::clearDiagnostics() { - for (const DocumentUri &uri : m_diagnostics.keys()) - hideDiagnostics(uri.toFilePath()); + for (const Utils::FilePath &path : m_diagnostics.keys()) + hideDiagnostics(path); m_diagnostics.clear(); QTC_ASSERT(m_marks.isEmpty(), m_marks.clear()); } -QList<Diagnostic> DiagnosticManager::diagnosticsAt(const DocumentUri &uri, +QList<Diagnostic> DiagnosticManager::diagnosticsAt(const FilePath &filePath, const QTextCursor &cursor) const { - const int documentRevision = m_client->documentVersion(uri.toFilePath()); - auto it = m_diagnostics.find(uri); + const int documentRevision = m_client->documentVersion(filePath); + auto it = m_diagnostics.find(filePath); if (it == m_diagnostics.end()) return {}; if (documentRevision != it->version.value_or(documentRevision)) @@ -187,16 +186,16 @@ QList<Diagnostic> DiagnosticManager::diagnosticsAt(const DocumentUri &uri, }); } -bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, +bool DiagnosticManager::hasDiagnostic(const FilePath &filePath, const TextDocument *doc, const LanguageServerProtocol::Diagnostic &diag) const { if (!doc) return false; - const auto it = m_diagnostics.find(uri); + const auto it = m_diagnostics.find(filePath); if (it == m_diagnostics.end()) return {}; - const int revision = m_client->documentVersion(uri.toFilePath()); + const int revision = m_client->documentVersion(filePath); if (revision != it->version.value_or(revision)) return false; return it->diagnostics.contains(diag); @@ -205,7 +204,7 @@ bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const { const FilePath docPath = doc->filePath(); - const auto it = m_diagnostics.find(DocumentUri::fromFilePath(docPath)); + const auto it = m_diagnostics.find(docPath); if (it == m_diagnostics.end()) return {}; const int revision = m_client->documentVersion(docPath); diff --git a/src/plugins/languageclient/diagnosticmanager.h b/src/plugins/languageclient/diagnosticmanager.h index 3898327619..121dc66c8c 100644 --- a/src/plugins/languageclient/diagnosticmanager.h +++ b/src/plugins/languageclient/diagnosticmanager.h @@ -30,11 +30,11 @@ public: explicit DiagnosticManager(Client *client); ~DiagnosticManager() override; - virtual void setDiagnostics(const LanguageServerProtocol::DocumentUri &uri, + virtual void setDiagnostics(const Utils::FilePath &filePath, const QList<LanguageServerProtocol::Diagnostic> &diagnostics, const std::optional<int> &version); - virtual void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri, int version); + virtual void showDiagnostics(const Utils::FilePath &filePath, int version); virtual void hideDiagnostics(const Utils::FilePath &filePath); virtual QList<LanguageServerProtocol::Diagnostic> filteredDiagnostics( const QList<LanguageServerProtocol::Diagnostic> &diagnostics) const; @@ -43,9 +43,9 @@ public: void clearDiagnostics(); QList<LanguageServerProtocol::Diagnostic> diagnosticsAt( - const LanguageServerProtocol::DocumentUri &uri, + const Utils::FilePath &filePath, const QTextCursor &cursor) const; - bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, + bool hasDiagnostic(const Utils::FilePath &filePath, const TextEditor::TextDocument *doc, const LanguageServerProtocol::Diagnostic &diag) const; bool hasDiagnostics(const TextEditor::TextDocument *doc) const; @@ -71,7 +71,7 @@ private: std::optional<int> version; QList<LanguageServerProtocol::Diagnostic> diagnostics; }; - QMap<LanguageServerProtocol::DocumentUri, VersionedDiagnostics> m_diagnostics; + QMap<Utils::FilePath, VersionedDiagnostics> m_diagnostics; class Marks { public: diff --git a/src/plugins/languageclient/documentsymbolcache.cpp b/src/plugins/languageclient/documentsymbolcache.cpp index 465c3c4f69..40485b7c62 100644 --- a/src/plugins/languageclient/documentsymbolcache.cpp +++ b/src/plugins/languageclient/documentsymbolcache.cpp @@ -18,8 +18,8 @@ DocumentSymbolCache::DocumentSymbolCache(Client *client) { auto connectDocument = [this](Core::IDocument *document) { connect(document, &Core::IDocument::contentsChanged, this, [document, this]() { - const auto uri = DocumentUri::fromFilePath(document->filePath()); - m_cache.remove(DocumentUri::fromFilePath(document->filePath())); + const auto uri = m_client->hostPathToServerUri(document->filePath()); + m_cache.remove(uri); auto requestIdIt = m_runningRequests.find(uri); if (requestIdIt != m_runningRequests.end()) { m_client->cancelRequest(requestIdIt.value()); @@ -54,7 +54,8 @@ void DocumentSymbolCache::requestSymbols(const DocumentUri &uri, Schedule schedu bool clientSupportsDocumentSymbols(const Client *client, const DocumentUri &uri) { QTC_ASSERT(client, return false); - const auto doc = TextEditor::TextDocument::textDocumentForFilePath(uri.toFilePath()); + const auto doc = TextEditor::TextDocument::textDocumentForFilePath( + uri.toFilePath(client->hostPathMapper())); return client->supportsDocumentSymbols(doc); } diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index 23d6b3e3b2..30ed1c0d54 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -446,7 +446,7 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform() params.setPosition({line, column}); params.setContext(context); params.setTextDocument( - TextDocumentIdentifier(DocumentUri::fromFilePath(interface()->filePath()))); + TextDocumentIdentifier(m_client->hostPathToServerUri(interface()->filePath()))); if (const int limit = m_client->completionResultsLimit(); limit >= 0) params.setLimit(limit); CompletionRequest completionRequest(params); diff --git a/src/plugins/languageclient/languageclientformatter.cpp b/src/plugins/languageclient/languageclientformatter.cpp index f67302aa0e..ab5fbe70ae 100644 --- a/src/plugins/languageclient/languageclientformatter.cpp +++ b/src/plugins/languageclient/languageclientformatter.cpp @@ -73,7 +73,7 @@ QFutureWatcher<ChangeSet> *LanguageClientFormatter::format( return nullptr; } DocumentRangeFormattingParams params; - const DocumentUri uri = DocumentUri::fromFilePath(filePath); + const DocumentUri uri = m_client->hostPathToServerUri(filePath); params.setTextDocument(TextDocumentIdentifier(uri)); params.setOptions(formattingOptions(tabSettings)); if (!cursor.hasSelection()) { diff --git a/src/plugins/languageclient/languageclientfunctionhint.cpp b/src/plugins/languageclient/languageclientfunctionhint.cpp index ba877dd7c0..7863750041 100644 --- a/src/plugins/languageclient/languageclientfunctionhint.cpp +++ b/src/plugins/languageclient/languageclientfunctionhint.cpp @@ -72,7 +72,7 @@ IAssistProposal *FunctionHintProcessor::perform() m_pos = interface()->position(); QTextCursor cursor(interface()->textDocument()); cursor.setPosition(m_pos); - auto uri = DocumentUri::fromFilePath(interface()->filePath()); + auto uri = m_client->hostPathToServerUri(interface()->filePath()); SignatureHelpRequest request((TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(cursor)))); request.setResponseCallback([this](auto response) { this->handleSignatureResponse(response); }); m_client->addAssistProcessor(this); diff --git a/src/plugins/languageclient/languageclienthoverhandler.cpp b/src/plugins/languageclient/languageclienthoverhandler.cpp index 9204a1ec04..75d2edc61a 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.cpp +++ b/src/plugins/languageclient/languageclienthoverhandler.cpp @@ -55,7 +55,7 @@ void HoverHandler::setHelpItem(const LanguageServerProtocol::MessageId &msgId, bool HoverHandler::reportDiagnostics(const QTextCursor &cursor) { - const QList<Diagnostic> &diagnostics = m_client->diagnosticsAt(m_uri, cursor); + const QList<Diagnostic> &diagnostics = m_client->diagnosticsAt(m_filePath, cursor); if (diagnostics.isEmpty()) return false; @@ -76,7 +76,7 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, report(Priority_None); return; } - m_uri = DocumentUri::fromFilePath(editorWidget->textDocument()->filePath()); + m_filePath = editorWidget->textDocument()->filePath(); m_response = {}; m_report = report; @@ -108,8 +108,9 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget, return; } - HoverRequest request{TextDocumentPositionParams(TextDocumentIdentifier(m_uri), - Position(cursor))}; + HoverRequest request{ + TextDocumentPositionParams(TextDocumentIdentifier(m_client->hostPathToServerUri(m_filePath)), + Position(cursor))}; m_currentRequest = request.id(); request.setResponseCallback( [this, cursor](const HoverRequest::Response &response) { handleResponse(response, cursor); }); @@ -127,7 +128,7 @@ void HoverHandler::handleResponse(const HoverRequest::Response &response, const if (auto hover = std::get_if<Hover>(&(*result))) { if (m_helpItemProvider) { m_response = response; - m_helpItemProvider(response, m_uri); + m_helpItemProvider(response, m_filePath); return; } setContent(hover->content()); diff --git a/src/plugins/languageclient/languageclienthoverhandler.h b/src/plugins/languageclient/languageclienthoverhandler.h index 08840d406f..4aa8099a59 100644 --- a/src/plugins/languageclient/languageclienthoverhandler.h +++ b/src/plugins/languageclient/languageclienthoverhandler.h @@ -15,7 +15,7 @@ namespace LanguageClient { class Client; using HelpItemProvider = std::function<void(const LanguageServerProtocol::HoverRequest::Response &, - const LanguageServerProtocol::DocumentUri &uri)>; + const Utils::FilePath &path)>; class LANGUAGECLIENT_EXPORT HoverHandler final : public TextEditor::BaseHoverHandler { @@ -49,7 +49,7 @@ private: QPointer<Client> m_client; std::optional<LanguageServerProtocol::MessageId> m_currentRequest; - LanguageServerProtocol::DocumentUri m_uri; + Utils::FilePath m_filePath; LanguageServerProtocol::HoverRequest::Response m_response; TextEditor::BaseHoverHandler::ReportPriority m_report; HelpItemProvider m_helpItemProvider; diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 38d9db03ec..4dbcf93f4a 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -131,6 +131,11 @@ void StdIOClientInterface::setEnvironment(const Utils::Environment &environment) m_env = environment; } +Utils::FilePath StdIOClientInterface::serverDeviceTemplate() const +{ + return m_cmd.executable(); +} + void StdIOClientInterface::sendData(const QByteArray &data) { if (!m_process || m_process->state() != QProcess::Running) { diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 7e90c99c23..b8b8c55805 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -28,6 +28,8 @@ public: void sendMessage(const LanguageServerProtocol::JsonRpcMessage message); void start() { startImpl(); } + virtual Utils::FilePath serverDeviceTemplate() const = 0; + void resetBuffer(); signals: @@ -66,6 +68,8 @@ public: void setWorkingDirectory(const Utils::FilePath &workingDirectory); void setEnvironment(const Utils::Environment &environment); + Utils::FilePath serverDeviceTemplate() const override; + protected: void sendData(const QByteArray &data) final; Utils::CommandLine m_cmd; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 7f50391ea1..f3e32813d9 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -391,11 +391,6 @@ Client *LanguageClientManager::clientForFilePath(const Utils::FilePath &filePath return clientForDocument(TextEditor::TextDocument::textDocumentForFilePath(filePath)); } -Client *LanguageClientManager::clientForUri(const DocumentUri &uri) -{ - return clientForFilePath(uri.toFilePath()); -} - const QList<Client *> LanguageClientManager::clientsForProject( const ProjectExplorer::Project *project) { diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index 7ce055f1fb..09815f29df 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -64,7 +64,6 @@ public: static const BaseSettings *settingForClient(Client *setting); static Client *clientForDocument(TextEditor::TextDocument *document); static Client *clientForFilePath(const Utils::FilePath &filePath); - static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri); static const QList<Client *> clientsForProject(const ProjectExplorer::Project *project); template<typename T> static bool hasClients(); diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 0387ebdd21..5ed70ae0e0 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -195,14 +195,14 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client, : m_client(client) , m_editor(editor) , m_view(this) - , m_uri(DocumentUri::fromFilePath(editor->textDocument()->filePath())) + , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath())) { connect(client->documentSymbolCache(), &DocumentSymbolCache::gotSymbols, this, &LanguageClientOutlineWidget::handleResponse); connect(client, &Client::documentUpdated, this, [this](TextEditor::TextDocument *document) { - if (m_client && m_uri == DocumentUri::fromFilePath(document->filePath())) + if (m_client && m_uri == m_client->hostPathToServerUri(document->filePath())) m_client->documentSymbolCache()->requestSymbols(m_uri, Schedule::Delayed); }); @@ -375,7 +375,7 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox( OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) : m_client(client) , m_editorWidget(editor->editorWidget()) - , m_uri(DocumentUri::fromFilePath(editor->document()->filePath())) + , m_uri(m_client->hostPathToServerUri(editor->document()->filePath())) { m_model.setSymbolStringifier(client->symbolStringifier()); m_proxyModel.setSourceModel(&m_model); diff --git a/src/plugins/languageclient/languageclientquickfix.cpp b/src/plugins/languageclient/languageclientquickfix.cpp index e04e7306c7..6093b50405 100644 --- a/src/plugins/languageclient/languageclientquickfix.cpp +++ b/src/plugins/languageclient/languageclientquickfix.cpp @@ -60,10 +60,11 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform() cursor.select(QTextCursor::LineUnderCursor); Range range(cursor); params.setRange(range); - auto uri = DocumentUri::fromFilePath(interface()->filePath()); + const Utils::FilePath filePath = interface()->filePath(); + const DocumentUri &uri = m_client->hostPathToServerUri(filePath); params.setTextDocument(TextDocumentIdentifier(uri)); CodeActionParams::CodeActionContext context; - context.setDiagnostics(m_client->diagnosticsAt(uri, cursor)); + context.setDiagnostics(m_client->diagnosticsAt(filePath, cursor)); params.setContext(context); CodeActionRequest request(params); diff --git a/src/plugins/languageclient/languageclientsymbolsupport.cpp b/src/plugins/languageclient/languageclientsymbolsupport.cpp index 163162d8b0..3014431332 100644 --- a/src/plugins/languageclient/languageclientsymbolsupport.cpp +++ b/src/plugins/languageclient/languageclientsymbolsupport.cpp @@ -56,7 +56,9 @@ public: } m_renameFilesCheckBox.setText(tr("Re&name %n files", nullptr, filesToRename.size())); const auto filesForUser = Utils::transform<QStringList>(filesToRename, - [](const Utils::FilePath &fp) { return fp.toUserOutput(); }); + [](const Utils::FilePath &fp) { + return fp.toUserOutput(); + }); m_renameFilesCheckBox.setToolTip(tr("Files:\n%1").arg(filesForUser.join('\n'))); m_renameFilesCheckBox.setVisible(true); } @@ -69,7 +71,8 @@ private: }; } // anonymous namespace -SymbolSupport::SymbolSupport(Client *client) : m_client(client) +SymbolSupport::SymbolSupport(Client *client) + : m_client(client) {} template<typename Request> @@ -104,16 +107,17 @@ static void sendTextDocumentPositionParamsRequest(Client *client, static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response, Utils::LinkHandler callback, - std::optional<Utils::Link> linkUnderCursor) + std::optional<Utils::Link> linkUnderCursor, + const Client *client) { if (std::optional<GotoResult> result = response.result()) { if (std::holds_alternative<std::nullptr_t>(*result)) { callback({}); } else if (auto ploc = std::get_if<Location>(&*result)) { - callback(linkUnderCursor.value_or(ploc->toLink())); + callback(linkUnderCursor.value_or(ploc->toLink(client->hostPathMapper()))); } else if (auto plloc = std::get_if<QList<Location>>(&*result)) { if (!plloc->isEmpty()) - callback(linkUnderCursor.value_or(plloc->value(0).toLink())); + callback(linkUnderCursor.value_or(plloc->value(0).toLink(client->hostPathMapper()))); else callback({}); } @@ -123,9 +127,10 @@ static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response & } static TextDocumentPositionParams generateDocPosParams(TextEditor::TextDocument *document, - const QTextCursor &cursor) + const QTextCursor &cursor, + const Client *client) { - const DocumentUri uri = DocumentUri::fromFilePath(document->filePath()); + const DocumentUri uri = client->hostPathToServerUri(document->filePath()); const TextDocumentIdentifier documentId(uri); const Position pos(cursor); return TextDocumentPositionParams(documentId, pos); @@ -138,7 +143,7 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document, { if (!m_client->reachable()) return; - GotoDefinitionRequest request(generateDocPosParams(document, cursor)); + GotoDefinitionRequest request(generateDocPosParams(document, cursor, m_client)); std::optional<Utils::Link> linkUnderCursor; if (!resolveTarget) { QTextCursor linkCursor = cursor; @@ -150,16 +155,15 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document, link.linkTextEnd = linkCursor.selectionEnd(); linkUnderCursor = link; } - request.setResponseCallback( - [callback, linkUnderCursor](const GotoDefinitionRequest::Response &response) { - handleGotoDefinitionResponse(response, callback, linkUnderCursor); - }); + request.setResponseCallback([callback, linkUnderCursor, client = m_client]( + const GotoDefinitionRequest::Response &response) { + handleGotoDefinitionResponse(response, callback, linkUnderCursor, client); + }); sendTextDocumentPositionParamsRequest(m_client, request, m_client->dynamicCapabilities(), m_client->capabilities()); - } bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const @@ -212,9 +216,9 @@ QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath) } QList<Core::SearchResultItem> generateSearchResultItems( - const QMap<Utils::FilePath, QList<ItemData>> &rangesInDocument, - Core::SearchResult *search = nullptr, - bool limitToProjects = false) + const QMap<Utils::FilePath, QList<ItemData>> &rangesInDocument, + Core::SearchResult *search = nullptr, + bool limitToProjects = false) { QList<Core::SearchResultItem> result; const bool renaming = search && search->supportsReplace(); @@ -232,11 +236,11 @@ QList<Core::SearchResultItem> generateSearchResultItems( item.setFilePath(filePath); item.setUseTextEditorFont(true); if (renaming && limitToProjects) { - const bool fileBelongsToProject - = ProjectExplorer::SessionManager::projectForFile(filePath); + const bool fileBelongsToProject = ProjectExplorer::SessionManager::projectForFile( + filePath); item.setSelectForReplacement(fileBelongsToProject); - if (fileBelongsToProject && filePath.baseName().compare(oldSymbolName, - Qt::CaseInsensitive) == 0) { + if (fileBelongsToProject + && filePath.baseName().compare(oldSymbolName, Qt::CaseInsensitive) == 0) { fileRenameCandidates << filePath; } } @@ -260,13 +264,13 @@ QList<Core::SearchResultItem> generateSearchResultItems( } QList<Core::SearchResultItem> generateSearchResultItems( - const LanguageClientArray<Location> &locations) + const LanguageClientArray<Location> &locations, const DocumentUri::PathMapper &pathMapper) { if (locations.isNull()) return {}; QMap<Utils::FilePath, QList<ItemData>> rangesInDocument; for (const Location &location : locations.toList()) - rangesInDocument[location.uri().toFilePath()] + rangesInDocument[location.uri().toFilePath(pathMapper)] << ItemData{SymbolSupport::convertRange(location.range()), {}}; return generateSearchResultItems(rangesInDocument); } @@ -284,7 +288,8 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re if (result) { Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor); - search->addResults(generateSearchResultItems(*result), Core::SearchResult::AddOrdered); + search->addResults(generateSearchResultItems(*result, m_client->hostPathMapper()), + Core::SearchResult::AddOrdered); connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) { Core::EditorManager::openEditorAtSearchResult(item); }); @@ -293,18 +298,19 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re } } -std::optional<MessageId> SymbolSupport::findUsages( - TextEditor::TextDocument *document, const QTextCursor &cursor, const ResultHandler &handler) +std::optional<MessageId> SymbolSupport::findUsages(TextEditor::TextDocument *document, + const QTextCursor &cursor, + const ResultHandler &handler) { if (!supportsFindUsages(document)) return {}; - ReferenceParams params(generateDocPosParams(document, cursor)); + ReferenceParams params(generateDocPosParams(document, cursor, m_client)); params.setContext(ReferenceParams::ReferenceContext(true)); FindReferencesRequest request(params); QTextCursor termCursor(cursor); termCursor.select(QTextCursor::WordUnderCursor); request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText(), handler]( - const FindReferencesRequest::Response &response) { + const FindReferencesRequest::Response &response) { handleFindReferencesResponse(response, wordUnderCursor, handler); }); @@ -355,10 +361,12 @@ bool SymbolSupport::supportsRename(TextEditor::TextDocument *document) return LanguageClient::supportsRename(m_client, document, prepareSupported); } -void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QTextCursor &cursor, - const QString &newSymbolName, bool preferLowerCaseFileNames) +void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, + const QTextCursor &cursor, + const QString &newSymbolName, + bool preferLowerCaseFileNames) { - const TextDocumentPositionParams params = generateDocPosParams(document, cursor); + const TextDocumentPositionParams params = generateDocPosParams(document, cursor, m_client); QTextCursor tc = cursor; tc.select(QTextCursor::WordUnderCursor); const QString oldSymbolName = tc.selectedText(); @@ -370,26 +378,25 @@ void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QText if (!LanguageClient::supportsRename(m_client, document, prepareSupported)) { const QString error = tr("Renaming is not supported with %1").arg(m_client->name()); createSearch(params, placeholder, {}, {})->finishSearch(true, error); - } else if (prepareSupported) { + } else if (prepareSupported) { requestPrepareRename(document, - generateDocPosParams(document, cursor), + generateDocPosParams(document, cursor, m_client), placeholder, oldSymbolName, preferLowerCaseFileNames); } else { - startRenameSymbol(generateDocPosParams(document, cursor), + startRenameSymbol(generateDocPosParams(document, cursor, m_client), placeholder, oldSymbolName, preferLowerCaseFileNames); } } -void SymbolSupport::requestPrepareRename( - TextEditor::TextDocument *document, - const TextDocumentPositionParams ¶ms, - const QString &placeholder, - const QString &oldSymbolName, - bool preferLowerCaseFileNames) +void SymbolSupport::requestPrepareRename(TextEditor::TextDocument *document, + const TextDocumentPositionParams ¶ms, + const QString &placeholder, + const QString &oldSymbolName, + bool preferLowerCaseFileNames) { PrepareRenameRequest request(params); request.setResponseCallback([this, @@ -409,7 +416,9 @@ void SymbolSupport::requestPrepareRename( if (result.has_value()) { if (std::holds_alternative<PlaceHolderResult>(*result)) { auto placeHolderResult = std::get<PlaceHolderResult>(*result); - startRenameSymbol(params, placeHolderResult.placeHolder(), oldSymbolName, + startRenameSymbol(params, + placeHolderResult.placeHolder(), + oldSymbolName, preferLowerCaseFileNames); } else if (std::holds_alternative<Range>(*result)) { auto range = std::get<Range>(*result); @@ -425,10 +434,7 @@ void SymbolSupport::requestPrepareRename( reportedSymbolName, preferLowerCaseFileNames); } else { - startRenameSymbol(params, - placeholder, - oldSymbolName, - preferLowerCaseFileNames); + startRenameSymbol(params, placeholder, oldSymbolName, preferLowerCaseFileNames); } } } @@ -453,7 +459,8 @@ void SymbolSupport::requestRename(const TextDocumentPositionParams &positionPara QList<Core::SearchResultItem> generateReplaceItems(const WorkspaceEdit &edits, Core::SearchResult *search, - bool limitToProjects) + bool limitToProjects, + const DocumentUri::PathMapper &pathMapper) { auto convertEdits = [](const QList<TextEdit> &edits) { return Utils::transform(edits, [](const TextEdit &edit) { @@ -464,22 +471,21 @@ QList<Core::SearchResultItem> generateReplaceItems(const WorkspaceEdit &edits, auto documentChanges = edits.documentChanges().value_or(QList<TextDocumentEdit>()); if (!documentChanges.isEmpty()) { for (const TextDocumentEdit &documentChange : std::as_const(documentChanges)) { - rangesInDocument[documentChange.textDocument().uri().toFilePath()] = convertEdits( - documentChange.edits()); + rangesInDocument[documentChange.textDocument().uri().toFilePath(pathMapper)] + = convertEdits(documentChange.edits()); } } else { auto changes = edits.changes().value_or(WorkspaceEdit::Changes()); for (auto it = changes.begin(), end = changes.end(); it != end; ++it) - rangesInDocument[it.key().toFilePath()] = convertEdits(it.value()); + rangesInDocument[it.key().toFilePath(pathMapper)] = convertEdits(it.value()); } return generateSearchResultItems(rangesInDocument, search, limitToProjects); } -Core::SearchResult *SymbolSupport::createSearch( - const TextDocumentPositionParams &positionParams, - const QString &placeholder, - const QString &oldSymbolName, - bool preferLowerCaseFileNames) +Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams &positionParams, + const QString &placeholder, + const QString &oldSymbolName, + bool preferLowerCaseFileNames) { Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( tr("Find References with %1 for:").arg(m_client->name()), @@ -500,18 +506,22 @@ Core::SearchResult *SymbolSupport::createSearch( search->setSearchAgainEnabled(true); search->setReplaceEnabled(false); }); - connect(search, &Core::SearchResult::searchAgainRequested, this, + connect(search, + &Core::SearchResult::searchAgainRequested, + this, [this, positionParams, search]() { search->restart(); requestRename(positionParams, search->textToReplace(), search); }); - connect(search, &Core::SearchResult::replaceButtonClicked, this, + connect(search, + &Core::SearchResult::replaceButtonClicked, + this, [this, positionParams, search](const QString & /*replaceText*/, const QList<Core::SearchResultItem> &checkedItems) { applyRename(checkedItems, search); }); - connect(this, &QObject::destroyed, search, [search, clientName = m_client->name()](){ + connect(this, &QObject::destroyed, search, [search, clientName = m_client->name()]() { search->restart(); // clears potential current results search->finishSearch(true, tr("%1 is not reachable anymore.").arg(clientName)); }); @@ -520,11 +530,13 @@ Core::SearchResult *SymbolSupport::createSearch( } void SymbolSupport::startRenameSymbol(const TextDocumentPositionParams &positionParams, - const QString &placeholder, const QString &oldSymbolName, + const QString &placeholder, + const QString &oldSymbolName, bool preferLowerCaseFileNames) { - requestRename(positionParams, placeholder, createSearch( - positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames)); + requestRename(positionParams, + placeholder, + createSearch(positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames)); } void SymbolSupport::handleRenameResponse(Core::SearchResult *search, @@ -539,7 +551,10 @@ void SymbolSupport::handleRenameResponse(Core::SearchResult *search, const std::optional<WorkspaceEdit> &edits = response.result(); if (edits.has_value()) { - search->addResults(generateReplaceItems(*edits, search, m_limitRenamingToProjects), + search->addResults(generateReplaceItems(*edits, + search, + m_limitRenamingToProjects, + m_client->hostPathMapper()), Core::SearchResult::AddOrdered); qobject_cast<ReplaceWidget *>(search->additionalReplaceWidget())->showLabel(false); search->setReplaceEnabled(true); @@ -554,22 +569,21 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem Core::SearchResult *search) { QSet<Utils::FilePath> affectedNonOpenFilePaths; - QMap<DocumentUri, QList<TextEdit>> editsForDocuments; + QMap<Utils::FilePath, QList<TextEdit>> editsForDocuments; for (const Core::SearchResultItem &item : checkedItems) { const auto filePath = Utils::FilePath::fromString(item.path().value(0)); if (!m_client->documentForFilePath(filePath)) affectedNonOpenFilePaths << filePath; TextEdit edit(item.userData().toJsonObject()); if (edit.isValid()) - editsForDocuments[DocumentUri::fromFilePath(filePath)] << edit; + editsForDocuments[filePath] << edit; } for (auto it = editsForDocuments.begin(), end = editsForDocuments.end(); it != end; ++it) applyTextEdits(m_client, it.key(), it.value()); if (!affectedNonOpenFilePaths.isEmpty()) { - Core::DocumentManager::notifyFilesChangedInternally( - Utils::toList(affectedNonOpenFilePaths)); + Core::DocumentManager::notifyFilesChangedInternally(Utils::toList(affectedNonOpenFilePaths)); } const auto extraWidget = qobject_cast<ReplaceWidget *>(search->additionalReplaceWidget()); @@ -579,10 +593,14 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem const QVariantList userData = search->userData().toList(); QTC_ASSERT(userData.size() == 3, return); const Utils::FilePaths filesToRename = Utils::transform(userData.at(2).toStringList(), - [](const QString &f) { return Utils::FilePath::fromString(f); }); - ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol( - userData.at(0).toString(), search->textToReplace(), - filesToRename, userData.at(1).toBool()); + [](const QString &f) { + return Utils::FilePath::fromString( + f); + }); + ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol(userData.at(0).toString(), + search->textToReplace(), + filesToRename, + userData.at(1).toBool()); } Core::Search::TextRange SymbolSupport::convertRange(const Range &range) diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index f85d62a4c2..8803a12289 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -62,7 +62,7 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit) if (edits.isEmpty()) return true; const DocumentUri &uri = edit.textDocument().uri(); - const FilePath &filePath = uri.toFilePath(); + const FilePath &filePath = client->serverUriToHostPath(uri); LanguageClientValue<int> version = edit.textDocument().version(); if (!version.isNull() && version.value(0) < client->documentVersion(filePath)) return false; @@ -71,12 +71,19 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit) bool applyTextEdits(const Client *client, const DocumentUri &uri, const QList<TextEdit> &edits) { + return applyTextEdits(client, client->serverUriToHostPath(uri), edits); +} + +bool applyTextEdits(const Client *client, + const Utils::FilePath &filePath, + const QList<LanguageServerProtocol::TextEdit> &edits) +{ if (edits.isEmpty()) return true; RefactoringChangesData * const backend = client->createRefactoringChangesBackend(); RefactoringChanges changes(backend); RefactoringFilePtr file; - file = changes.file(uri.toFilePath()); + file = changes.file(filePath); file->setChangeSet(editsToChangeSet(edits, file->document())); if (backend) { for (const TextEdit &edit : edits) @@ -130,7 +137,7 @@ void updateCodeActionRefactoringMarker(Client *client, const QList<CodeAction> &actions, const DocumentUri &uri) { - TextDocument* doc = TextDocument::textDocumentForFilePath(uri.toFilePath()); + TextDocument* doc = TextDocument::textDocumentForFilePath(client->serverUriToHostPath(uri)); if (!doc) return; const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc); diff --git a/src/plugins/languageclient/languageclientutils.h b/src/plugins/languageclient/languageclientutils.h index bccfdd533f..6438f09f67 100644 --- a/src/plugins/languageclient/languageclientutils.h +++ b/src/plugins/languageclient/languageclientutils.h @@ -32,6 +32,9 @@ applyTextDocumentEdit(const Client *client, const LanguageServerProtocol::TextDo bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client, const LanguageServerProtocol::DocumentUri &uri, const QList<LanguageServerProtocol::TextEdit> &edits); +bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client, + const Utils::FilePath &filePath, + const QList<LanguageServerProtocol::TextEdit> &edits); void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator, const LanguageServerProtocol::TextEdit &edit, bool newTextIsSnippet = false); diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index f297a359db..bee8bc0500 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -9,9 +9,13 @@ #include "languageclientutils.h" #include <coreplugin/editormanager/editormanager.h> + +#include <languageserverprotocol/lsptypes.h> #include <languageserverprotocol/servercapabilities.h> + #include <texteditor/textdocument.h> #include <texteditor/texteditor.h> + #include <utils/fuzzymatcher.h> #include <utils/linecolumn.h> @@ -43,6 +47,7 @@ void DocumentLocatorFilter::updateCurrentClient() TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument(); if (Client *client = LanguageClientManager::clientForDocument(document); client && (client->locatorsEnabled() || m_forced)) { + setEnabled(!m_forced); if (m_symbolCache != client->documentSymbolCache()) { disconnect(m_updateSymbolsConnection); @@ -52,12 +57,14 @@ void DocumentLocatorFilter::updateCurrentClient() } m_resetSymbolsConnection = connect(document, &Core::IDocument::contentsChanged, this, &DocumentLocatorFilter::resetSymbols); - m_currentUri = DocumentUri::fromFilePath(document->filePath()); + m_currentUri = client->hostPathToServerUri(document->filePath()); + m_pathMapper = client->hostPathMapper(); } else { disconnect(m_updateSymbolsConnection); m_symbolCache.clear(); m_currentUri.clear(); setEnabled(false); + m_pathMapper = DocumentUri::PathMapper(); } } @@ -78,7 +85,8 @@ void DocumentLocatorFilter::resetSymbols() } static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, - Core::ILocatorFilter *filter) + Core::ILocatorFilter *filter, + DocumentUri::PathMapper pathMapper) { Core::LocatorFilterEntry entry; entry.filter = filter; @@ -86,14 +94,14 @@ static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &in if (std::optional<QString> container = info.containerName()) entry.extraInfo = container.value_or(QString()); entry.displayIcon = symbolIcon(info.kind()); - entry.internalData = QVariant::fromValue(info.location().toLink()); + entry.internalData = QVariant::fromValue(info.location().toLink(pathMapper)); return entry; - } Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) { - return LanguageClient::generateLocatorEntry(info, this); + QTC_ASSERT(m_pathMapper, return {}); + return LanguageClient::generateLocatorEntry(info, this, m_pathMapper); } QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries( @@ -203,8 +211,11 @@ void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection, int * /*selectionLength*/) const { if (selection.internalData.canConvert<Utils::LineColumn>()) { + QTC_ASSERT(m_pathMapper, return); auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData); - const Utils::Link link(m_currentUri.toFilePath(), lineColumn.line + 1, lineColumn.column); + const Utils::Link link(m_currentUri.toFilePath(m_pathMapper), + lineColumn.line + 1, + lineColumn.column); Core::EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor); } else if (selection.internalData.canConvert<Utils::Link>()) { Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData), @@ -293,15 +304,14 @@ QList<Core::LocatorFilterEntry> WorkspaceLocatorFilter::matchesFor( if (!m_filterKinds.isEmpty()) { - m_results = Utils::filtered(m_results, [&](const SymbolInformation &info) { - return m_filterKinds.contains(SymbolKind(info.kind())); + m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) { + return m_filterKinds.contains(SymbolKind(info.symbol.kind())); }); } - return Utils::transform(m_results, - [this](const SymbolInformation &info) { - return generateLocatorEntry(info, this); - }) - .toList(); + auto generateEntry = [this](const SymbolInfoWithPathMapper &info) { + return generateLocatorEntry(info.symbol, this, info.mapper); + }; + return Utils::transform(m_results, generateEntry).toList(); } void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, @@ -322,7 +332,10 @@ void WorkspaceLocatorFilter::handleResponse(Client *client, m_pendingRequests.remove(client); auto result = response.result().value_or(LanguageClientArray<SymbolInformation>()); if (!result.isNull()) - m_results.append(result.toList().toVector()); + m_results.append( + Utils::transform(result.toList().toVector(), [client](const SymbolInformation &info) { + return SymbolInfoWithPathMapper{info, client->hostPathMapper()}; + })); if (m_pendingRequests.isEmpty()) emit allRequestsFinished(QPrivateSignal()); } diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index afb8630795..11a664380d 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -7,8 +7,9 @@ #include "languageclient_global.h" #include <coreplugin/locator/ilocatorfilter.h> -#include <languageserverprotocol/lsptypes.h> + #include <languageserverprotocol/languagefeatures.h> +#include <languageserverprotocol/lsptypes.h> #include <languageserverprotocol/workspace.h> #include <QPointer> @@ -67,6 +68,7 @@ private: QMetaObject::Connection m_updateSymbolsConnection; QMetaObject::Connection m_resetSymbolsConnection; std::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols; + LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; bool m_forced = false; }; @@ -101,8 +103,15 @@ private: const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); QMutex m_mutex; + + struct SymbolInfoWithPathMapper + { + LanguageServerProtocol::SymbolInformation symbol; + LanguageServerProtocol::DocumentUri::PathMapper mapper; + }; + QMap<Client *, LanguageServerProtocol::MessageId> m_pendingRequests; - QVector<LanguageServerProtocol::SymbolInformation> m_results; + QVector<SymbolInfoWithPathMapper> m_results; QVector<LanguageServerProtocol::SymbolKind> m_filterKinds; qint64 m_maxResultCount = 0; }; diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index bf54ee91e0..1f1ddb832a 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -60,7 +60,7 @@ void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument, if (supportedRequests.testFlag(SemanticRequestType::None)) return; const Utils::FilePath filePath = textDocument->filePath(); - const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); + const TextDocumentIdentifier docId(m_client->hostPathToServerUri(filePath)); auto responseCallback = [this, remainingRerequests, filePath, @@ -128,7 +128,7 @@ void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument, if (documentVersion == versionedToken.version) return; SemanticTokensDeltaParams params; - params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); + params.setTextDocument(TextDocumentIdentifier(m_client->hostPathToServerUri(filePath))); params.setPreviousResultId(previousResultId); SemanticTokensFullDeltaRequest request(params); request.setResponseCallback( |