LSP: Support remote LSP file paths

Change-Id: If3cf1b8d675ef091427dbcd703c7d14b384a1b3a
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2022-12-15 07:23:55 +01:00
parent 0b33a08af1
commit 2d0456f085
36 changed files with 424 additions and 310 deletions

View File

@@ -62,7 +62,7 @@ void WorkspaceEdit::setChanges(const Changes &changes)
QJsonArray edits; QJsonArray edits;
for (const TextEdit &edit : it.value()) for (const TextEdit &edit : it.value())
edits.append(QJsonValue(edit)); edits.append(QJsonValue(edit));
changesObject.insert(it.key().toFilePath().toString(), edits); changesObject.insert(QJsonValue(it.key()).toString(), edits);
} }
insert(changesKey, changesObject); insert(changesKey, changesObject);
} }
@@ -345,36 +345,46 @@ bool DocumentFilter::applies(const Utils::FilePath &fileName, const Utils::MimeT
return !contains(schemeKey) && !contains(languageKey) && !contains(patternKey); return !contains(schemeKey) && !contains(languageKey) && !contains(patternKey);
} }
Utils::Link Location::toLink() const Utils::Link Location::toLink(const DocumentUri::PathMapper &mapToHostPath) const
{ {
if (!isValid()) if (!isValid())
return Utils::Link(); return Utils::Link();
// Ensure %xx like %20 are really decoded using fromPercentEncoding return Utils::Link(uri().toFilePath(mapToHostPath),
// Else, a path with spaces would keep its %20 which would cause failure
// to open the file by the text editor. This is the cases with compilers in
// C:\Programs Files on Windows.
auto file = uri().toString(QUrl::PrettyDecoded | QUrl::PreferLocalFile);
// fromPercentEncoding convert %xx encoding to raw values and then interpret
// the result as utf-8, so toUtf8() must be used here.
file = QUrl::fromPercentEncoding(file.toUtf8());
return Utils::Link(Utils::FilePath::fromString(file),
range().start().line() + 1, range().start().line() + 1,
range().start().character()); range().start().character());
} }
// Ensure %xx like %20 are really decoded using fromPercentEncoding
// Else, a path with spaces would keep its %20 which would cause failure
// to open the file by the text editor. This is the cases with compilers in
// C:\Programs Files on Windows.
DocumentUri::DocumentUri(const QString &other) DocumentUri::DocumentUri(const QString &other)
: QUrl(QUrl::fromPercentEncoding(other.toUtf8())) : QUrl(QUrl::fromPercentEncoding(other.toUtf8()))
{ } { }
DocumentUri::DocumentUri(const Utils::FilePath &other) DocumentUri::DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath)
: QUrl(QUrl::fromLocalFile(other.toString())) : QUrl(QUrl::fromLocalFile(mapToServerPath(other).path()))
{ } { }
Utils::FilePath DocumentUri::toFilePath() const Utils::FilePath DocumentUri::toFilePath(const PathMapper &mapToHostPath) const
{ {
return isLocalFile() ? Utils::FilePath::fromUserInput(QUrl(*this).toLocalFile()) if (isLocalFile()) {
: Utils::FilePath(); const Utils::FilePath serverPath = Utils::FilePath::fromUserInput(toLocalFile());
QTC_ASSERT(mapToHostPath, return serverPath);
return mapToHostPath(serverPath);
}
return Utils::FilePath();
}
DocumentUri DocumentUri::fromProtocol(const QString &uri)
{
return DocumentUri(uri);
}
DocumentUri DocumentUri::fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath)
{
return DocumentUri(file, mapToServerPath);
} }
MarkupKind::MarkupKind(const QJsonValue &value) MarkupKind::MarkupKind(const QJsonValue &value)

View File

@@ -27,16 +27,17 @@ class LANGUAGESERVERPROTOCOL_EXPORT DocumentUri : public QUrl
{ {
public: public:
DocumentUri() = default; DocumentUri() = default;
Utils::FilePath toFilePath() const; using PathMapper = std::function<Utils::FilePath(const Utils::FilePath &)>;
Utils::FilePath toFilePath(const PathMapper &mapToHostPath) const;
static DocumentUri fromProtocol(const QString &uri) { return DocumentUri(uri); } static DocumentUri fromProtocol(const QString &uri);
static DocumentUri fromFilePath(const Utils::FilePath &file) { return DocumentUri(file); } static DocumentUri fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath);
operator QJsonValue() const { return QJsonValue(toString()); } operator QJsonValue() const { return QJsonValue(toString()); }
private: private:
DocumentUri(const QString &other); DocumentUri(const QString &other);
DocumentUri(const Utils::FilePath &other); DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath);
friend class LanguageClientValue<QString>; friend class LanguageClientValue<QString>;
}; };
@@ -137,7 +138,7 @@ public:
Range range() const { return typedValue<Range>(rangeKey); } Range range() const { return typedValue<Range>(rangeKey); }
void setRange(const Range &range) { insert(rangeKey, range); } void setRange(const Range &range) { insert(rangeKey, range); }
Utils::Link toLink() const; Utils::Link toLink(const DocumentUri::PathMapper &mapToHostPath) const;
bool isValid() const override { return contains(uriKey) && contains(rangeKey); } bool isValid() const override { return contains(uriKey) && contains(rangeKey); }
}; };

View File

@@ -387,7 +387,7 @@ MessageId requestAst(Client *client, const FilePath &filePath, const Range range
explicit AstRequest(const AstParams &params) : Request("textDocument/ast", params) {} explicit AstRequest(const AstParams &params) : Request("textDocument/ast", params) {}
}; };
AstRequest request(AstParams(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath)), AstRequest request(AstParams(TextDocumentIdentifier(client->hostPathToServerUri(filePath)),
range)); range));
request.setResponseCallback([handler, reqId = request.id()](AstRequest::Response response) { request.setResponseCallback([handler, reqId = request.id()](AstRequest::Response response) {
const auto result = response.result(); const auto result = response.result();

View File

@@ -274,7 +274,7 @@ public:
QTextCursor adjustedCursor(const QTextCursor &cursor, const TextDocument *doc); QTextCursor adjustedCursor(const QTextCursor &cursor, const TextDocument *doc);
void setHelpItemForTooltip(const MessageId &token, void setHelpItemForTooltip(const MessageId &token,
const DocumentUri &uri, const Utils::FilePath &filePath,
const QString &fqn = {}, const QString &fqn = {},
HelpItem::Category category = HelpItem::Unknown, HelpItem::Category category = HelpItem::Unknown,
const QString &type = {}); const QString &type = {});
@@ -409,8 +409,8 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
d->handleSemanticTokens(doc, tokens, version, force); d->handleSemanticTokens(doc, tokens, version, force);
}); });
hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response, hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response,
const DocumentUri &uri) { const Utils::FilePath &filePath) {
gatherHelpItemForTooltip(response, uri); gatherHelpItemForTooltip(response, filePath);
}); });
connect(this, &Client::workDone, this, connect(this, &Client::workDone, this,
@@ -462,7 +462,7 @@ void ClangdClient::openExtraFile(const Utils::FilePath &filePath, const QString
return; return;
TextDocumentItem item; TextDocumentItem item;
item.setLanguageId("cpp"); item.setLanguageId("cpp");
item.setUri(DocumentUri::fromFilePath(filePath)); item.setUri(hostPathToServerUri(filePath));
item.setText(!content.isEmpty() ? content : QString::fromUtf8(cxxFile.readAll())); item.setText(!content.isEmpty() ? content : QString::fromUtf8(cxxFile.readAll()));
item.setVersion(0); item.setVersion(0);
sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)), sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)),
@@ -480,7 +480,7 @@ void ClangdClient::closeExtraFile(const Utils::FilePath &filePath)
return; return;
d->openedExtraFiles.erase(it); d->openedExtraFiles.erase(it);
sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams( sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams(
TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})), TextDocumentIdentifier{hostPathToServerUri(filePath)})),
SendDocUpdates::Ignore); SendDocUpdates::Ignore);
} }
@@ -533,7 +533,7 @@ void ClangdClient::handleDiagnostics(const PublishDiagnosticsParams &params)
{ {
const DocumentUri &uri = params.uri(); const DocumentUri &uri = params.uri();
Client::handleDiagnostics(params); Client::handleDiagnostics(params);
const int docVersion = documentVersion(uri.toFilePath()); const int docVersion = documentVersion(uri);
if (params.version().value_or(docVersion) != docVersion) if (params.version().value_or(docVersion) != docVersion)
return; return;
for (const Diagnostic &diagnostic : params.diagnostics()) { for (const Diagnostic &diagnostic : params.diagnostics()) {
@@ -593,11 +593,10 @@ class ClangdDiagnosticManager : public LanguageClient::DiagnosticManager
return doc && doc->filePath() == filePath; return doc && doc->filePath() == filePath;
} }
void showDiagnostics(const DocumentUri &uri, int version) override void showDiagnostics(const Utils::FilePath &filePath, int version) override
{ {
const Utils::FilePath filePath = uri.toFilePath();
getClient()->clearTasks(filePath); getClient()->clearTasks(filePath);
DiagnosticManager::showDiagnostics(uri, version); DiagnosticManager::showDiagnostics(filePath, version);
if (isCurrentDocument(filePath)) if (isCurrentDocument(filePath))
getClient()->switchIssuePaneEntries(filePath); getClient()->switchIssuePaneEntries(filePath);
} }
@@ -851,7 +850,7 @@ MessageId ClangdClient::getAndHandleAst(const TextDocOrFile &doc, const AstHandl
MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const Position &position, MessageId ClangdClient::requestSymbolInfo(const Utils::FilePath &filePath, const Position &position,
const SymbolInfoHandler &handler) const SymbolInfoHandler &handler)
{ {
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); const TextDocumentIdentifier docId(hostPathToServerUri(filePath));
const TextDocumentPositionParams params(docId, position); const TextDocumentPositionParams params(docId, position);
SymbolInfoRequest symReq(params); SymbolInfoRequest symReq(params);
symReq.setResponseCallback([handler, reqId = symReq.id()] symReq.setResponseCallback([handler, reqId = symReq.id()]
@@ -932,15 +931,16 @@ void ClangdClient::switchHeaderSource(const Utils::FilePath &filePath, bool inNe
{ {
public: public:
using Request::Request; using Request::Request;
explicit SwitchSourceHeaderRequest(const Utils::FilePath &filePath) explicit SwitchSourceHeaderRequest(const DocumentUri &uri)
: Request("textDocument/switchSourceHeader", : Request("textDocument/switchSourceHeader", TextDocumentIdentifier(uri))
TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))) {} {}
}; };
SwitchSourceHeaderRequest req(filePath); SwitchSourceHeaderRequest req(hostPathToServerUri(filePath));
req.setResponseCallback([inNextSplit](const SwitchSourceHeaderRequest::Response &response) { req.setResponseCallback([inNextSplit, pathMapper = hostPathMapper()](
const SwitchSourceHeaderRequest::Response &response) {
if (const std::optional<QJsonValue> result = response.result()) { if (const std::optional<QJsonValue> result = response.result()) {
const DocumentUri uri = DocumentUri::fromProtocol(result->toString()); const DocumentUri uri = DocumentUri::fromProtocol(result->toString());
const Utils::FilePath filePath = uri.toFilePath(); const Utils::FilePath filePath = uri.toFilePath(pathMapper);
if (!filePath.isEmpty()) if (!filePath.isEmpty())
CppEditor::openEditor(filePath, inNextSplit); CppEditor::openEditor(filePath, inNextSplit);
} }
@@ -976,7 +976,7 @@ void ClangdClient::findLocalUsages(TextDocument *document, const QTextCursor &cu
} }
void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverResponse, void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverResponse,
const DocumentUri &uri) const Utils::FilePath &filePath)
{ {
if (const std::optional<HoverResult> result = hoverResponse.result()) { if (const std::optional<HoverResult> result = hoverResponse.result()) {
if (auto hover = std::get_if<Hover>(&(*result))) { if (auto hover = std::get_if<Hover>(&(*result))) {
@@ -994,7 +994,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
const QString macroName = markupString.mid(nameStart, const QString macroName = markupString.mid(nameStart,
closingQuoteIndex - nameStart); closingQuoteIndex - nameStart);
d->setHelpItemForTooltip(hoverResponse.id(), d->setHelpItemForTooltip(hoverResponse.id(),
uri, filePath,
macroName, macroName,
HelpItem::Macro); HelpItem::Macro);
return; return;
@@ -1006,11 +1006,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
cleanString.remove('`'); cleanString.remove('`');
const QStringList lines = cleanString.trimmed().split('\n'); const QStringList lines = cleanString.trimmed().split('\n');
if (!lines.isEmpty()) { if (!lines.isEmpty()) {
const auto filePath = Utils::FilePath::fromUserInput(lines.last().simplified()); const auto markupFilePath = Utils::FilePath::fromUserInput(
if (filePath.exists()) { lines.last().simplified());
if (markupFilePath.exists()) {
d->setHelpItemForTooltip(hoverResponse.id(), d->setHelpItemForTooltip(hoverResponse.id(),
uri, filePath,
filePath.fileName(), markupFilePath.fileName(),
HelpItem::Brief); HelpItem::Brief);
return; return;
} }
@@ -1019,9 +1020,10 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
} }
} }
const TextDocument * const doc = documentForFilePath(uri.toFilePath()); const TextDocument * const doc = documentForFilePath(filePath);
QTC_ASSERT(doc, return); QTC_ASSERT(doc, return);
const auto astHandler = [this, uri, hoverResponse](const ClangdAstNode &ast, const MessageId &) { const auto astHandler = [this, filePath, hoverResponse](const ClangdAstNode &ast,
const MessageId &) {
const MessageId id = hoverResponse.id(); const MessageId id = hoverResponse.id();
Range range; Range range;
if (const std::optional<HoverResult> result = hoverResponse.result()) { if (const std::optional<HoverResult> result = hoverResponse.result()) {
@@ -1030,7 +1032,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
} }
const ClangdAstPath path = getAstPath(ast, range); const ClangdAstPath path = getAstPath(ast, range);
if (path.isEmpty()) { if (path.isEmpty()) {
d->setHelpItemForTooltip(id, uri); d->setHelpItemForTooltip(id, filePath);
return; return;
} }
ClangdAstNode node = path.last(); ClangdAstNode node = path.last();
@@ -1054,7 +1056,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
type = type.left(angleBracketIndex); type = type.left(angleBracketIndex);
}; };
if (gatherMemberFunctionOverrideHelpItemForTooltip(id, uri, path)) if (gatherMemberFunctionOverrideHelpItemForTooltip(id, filePath, path))
return; return;
const bool isMemberFunction = node.role() == "expression" && node.kind() == "Member" const bool isMemberFunction = node.role() == "expression" && node.kind() == "Member"
@@ -1062,9 +1064,8 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
const bool isFunction = node.role() == "expression" && node.kind() == "DeclRef" const bool isFunction = node.role() == "expression" && node.kind() == "DeclRef"
&& type.contains('('); && type.contains('(');
if (isMemberFunction || isFunction) { if (isMemberFunction || isFunction) {
const auto symbolInfoHandler = [this, id, uri, type, isFunction](const QString &name, const auto symbolInfoHandler = [this, id, filePath, type, isFunction]
const QString &prefix, (const QString &name, const QString &prefix, const MessageId &) {
const MessageId &) {
qCDebug(clangdLog) << "handling symbol info reply"; qCDebug(clangdLog) << "handling symbol info reply";
const QString fqn = prefix + name; const QString fqn = prefix + name;
@@ -1074,12 +1075,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
// with mainOverload = true, such information would get ignored anyway. // with mainOverload = true, such information would get ignored anyway.
if (!fqn.isEmpty()) if (!fqn.isEmpty())
d->setHelpItemForTooltip(id, d->setHelpItemForTooltip(id,
uri, filePath,
fqn, fqn,
HelpItem::Function, HelpItem::Function,
isFunction ? type : "()"); isFunction ? type : "()");
}; };
requestSymbolInfo(uri.toFilePath(), range.start(), symbolInfoHandler); requestSymbolInfo(filePath, range.start(), symbolInfoHandler);
return; return;
} }
if ((node.role() == "expression" && node.kind() == "DeclRef") if ((node.role() == "expression" && node.kind() == "DeclRef")
@@ -1088,7 +1089,7 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
|| node.kind() == "Field"))) { || node.kind() == "Field"))) {
if (node.arcanaContains("EnumConstant")) { if (node.arcanaContains("EnumConstant")) {
d->setHelpItemForTooltip(id, d->setHelpItemForTooltip(id,
uri, filePath,
node.detail().value_or(QString()), node.detail().value_or(QString()),
HelpItem::Enum, HelpItem::Enum,
type); type);
@@ -1103,12 +1104,12 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
&& type != "double" && !type.contains(" double") && type != "double" && !type.contains(" double")
&& type != "float" && type != "bool") { && type != "float" && type != "bool") {
d->setHelpItemForTooltip(id, d->setHelpItemForTooltip(id,
uri, filePath,
type, type,
node.qdocCategoryForDeclaration( node.qdocCategoryForDeclaration(
HelpItem::ClassOrNamespace)); HelpItem::ClassOrNamespace));
} else { } else {
d->setHelpItemForTooltip(id, uri); d->setHelpItemForTooltip(id, filePath);
} }
return; return;
} }
@@ -1121,19 +1122,22 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
ns.prepend("::").prepend(name); ns.prepend("::").prepend(name);
} }
} }
d->setHelpItemForTooltip(id, uri, ns, HelpItem::ClassOrNamespace); d->setHelpItemForTooltip(id, filePath, ns, HelpItem::ClassOrNamespace);
return; return;
} }
if (node.role() == "type") { if (node.role() == "type") {
if (node.kind() == "Enum") { if (node.kind() == "Enum") {
d->setHelpItemForTooltip(id, uri, node.detail().value_or(QString()), HelpItem::Enum); d->setHelpItemForTooltip(id,
filePath,
node.detail().value_or(QString()),
HelpItem::Enum);
} else if (node.kind() == "Record" || node.kind() == "TemplateSpecialization") { } else if (node.kind() == "Record" || node.kind() == "TemplateSpecialization") {
stripTemplatePartOffType(); stripTemplatePartOffType();
d->setHelpItemForTooltip(id, uri, type, HelpItem::ClassOrNamespace); d->setHelpItemForTooltip(id, filePath, type, HelpItem::ClassOrNamespace);
} else if (node.kind() == "Typedef") { } else if (node.kind() == "Typedef") {
d->setHelpItemForTooltip(id, uri, type, HelpItem::Typedef); d->setHelpItemForTooltip(id, filePath, type, HelpItem::Typedef);
} else { } else {
d->setHelpItemForTooltip(id, uri); d->setHelpItemForTooltip(id, filePath);
} }
return; return;
} }
@@ -1141,23 +1145,23 @@ void ClangdClient::gatherHelpItemForTooltip(const HoverRequest::Response &hoverR
const QString name = node.detail().value_or(QString()); const QString name = node.detail().value_or(QString());
if (!name.isEmpty()) if (!name.isEmpty())
type = name; type = name;
d->setHelpItemForTooltip(id, uri, type, HelpItem::ClassOrNamespace); d->setHelpItemForTooltip(id, filePath, type, HelpItem::ClassOrNamespace);
} }
if (node.role() == "specifier" && node.kind() == "NamespaceAlias") { if (node.role() == "specifier" && node.kind() == "NamespaceAlias") {
d->setHelpItemForTooltip(id, d->setHelpItemForTooltip(id,
uri, filePath,
node.detail().value_or(QString()).chopped(2), node.detail().value_or(QString()).chopped(2),
HelpItem::ClassOrNamespace); HelpItem::ClassOrNamespace);
return; return;
} }
d->setHelpItemForTooltip(id, uri); d->setHelpItemForTooltip(id, filePath);
}; };
d->getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible); d->getAndHandleAst(doc, astHandler, AstCallbackMode::SyncIfPossible);
} }
bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip( bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip(
const LanguageServerProtocol::MessageId &token, const LanguageServerProtocol::MessageId &token,
const DocumentUri &uri, const Utils::FilePath &filePath,
const QList<ClangdAstNode> &path) const QList<ClangdAstNode> &path)
{ {
// Heuristic: If we encounter a member function re-declaration, continue under the // Heuristic: If we encounter a member function re-declaration, continue under the
@@ -1196,7 +1200,7 @@ bool ClangdClient::gatherMemberFunctionOverrideHelpItemForTooltip(
if (!baseClassNode.detail()) if (!baseClassNode.detail())
return false; return false;
d->setHelpItemForTooltip(token, d->setHelpItemForTooltip(token,
uri, filePath,
*baseClassNode.detail() + "::" + *methodNode.detail(), *baseClassNode.detail() + "::" + *methodNode.detail(),
HelpItem::Function, HelpItem::Function,
"()"); "()");
@@ -1320,7 +1324,7 @@ QTextCursor ClangdClient::Private::adjustedCursor(const QTextCursor &cursor,
} }
void ClangdClient::Private::setHelpItemForTooltip(const MessageId &token, void ClangdClient::Private::setHelpItemForTooltip(const MessageId &token,
const DocumentUri &uri, const Utils::FilePath &filePath,
const QString &fqn, const QString &fqn,
HelpItem::Category category, HelpItem::Category category,
const QString &type) const QString &type)
@@ -1344,7 +1348,7 @@ void ClangdClient::Private::setHelpItemForTooltip(const MessageId &token,
if (category == HelpItem::Enum && !type.isEmpty()) if (category == HelpItem::Enum && !type.isEmpty())
mark = type; mark = type;
const HelpItem helpItem(helpIds, uri.toFilePath(), mark, category); const HelpItem helpItem(helpIds, filePath, mark, category);
if (isTesting) if (isTesting)
emit q->helpItemGathered(helpItem); emit q->helpItemGathered(helpItem);
else else

View File

@@ -74,10 +74,9 @@ public:
void gatherHelpItemForTooltip( void gatherHelpItemForTooltip(
const LanguageServerProtocol::HoverRequest::Response &hoverResponse, const LanguageServerProtocol::HoverRequest::Response &hoverResponse,
const LanguageServerProtocol::DocumentUri &uri); const Utils::FilePath &filePath);
bool gatherMemberFunctionOverrideHelpItemForTooltip( bool gatherMemberFunctionOverrideHelpItemForTooltip(const LanguageServerProtocol::MessageId &token,
const LanguageServerProtocol::MessageId &token, const Utils::FilePath &uri,
const LanguageServerProtocol::DocumentUri &uri,
const QList<ClangdAstNode> &path); const QList<ClangdAstNode> &path);
void setVirtualRanges(const Utils::FilePath &filePath, void setVirtualRanges(const Utils::FilePath &filePath,

View File

@@ -193,7 +193,7 @@ ClangdFindReferences::ClangdFindReferences(ClangdClient *client, const Link &lin
client->openExtraFile(link.targetFilePath, contents); client->openExtraFile(link.targetFilePath, contents);
d->checkUnusedData->openedExtraFileForLink = true; d->checkUnusedData->openedExtraFileForLink = true;
} }
const TextDocumentIdentifier documentId(DocumentUri::fromFilePath(link.targetFilePath)); const TextDocumentIdentifier documentId(client->hostPathToServerUri(link.targetFilePath));
const Position pos(link.targetLine - 1, link.targetColumn); const Position pos(link.targetLine - 1, link.targetColumn);
ReferenceParams params(TextDocumentPositionParams(documentId, pos)); ReferenceParams params(TextDocumentPositionParams(documentId, pos));
params.setContext(ReferenceParams::ReferenceContext(true)); params.setContext(ReferenceParams::ReferenceContext(true));
@@ -280,7 +280,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList<Location>
for (const Location &loc : locations) for (const Location &loc : locations)
fileData[loc.uri()].rangesAndLineText.push_back({loc.range(), {}}); fileData[loc.uri()].rangesAndLineText.push_back({loc.range(), {}});
for (auto it = fileData.begin(); it != fileData.end();) { for (auto it = fileData.begin(); it != fileData.end();) {
const Utils::FilePath filePath = it.key().toFilePath(); const Utils::FilePath filePath = client()->serverUriToHostPath(it.key());
if (!filePath.exists()) { // https://github.com/clangd/clangd/issues/935 if (!filePath.exists()) { // https://github.com/clangd/clangd/issues/935
it = fileData.erase(it); it = fileData.erase(it);
continue; continue;
@@ -303,19 +303,19 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList<Location>
} }
for (auto it = fileData.begin(); it != fileData.end(); ++it) { for (auto it = fileData.begin(); it != fileData.end(); ++it) {
const FilePath filePath = it.key().toFilePath(); const FilePath filePath = client()->serverUriToHostPath(it.key());
const TextDocument * const doc = client()->documentForFilePath(filePath); const TextDocument * const doc = client()->documentForFilePath(filePath);
const bool openExtraFile = !doc && (!checkUnusedData const bool openExtraFile = !doc && (!checkUnusedData
|| !checkUnusedData->openedExtraFileForLink || !checkUnusedData->openedExtraFileForLink
|| checkUnusedData->link.targetFilePath != filePath); || checkUnusedData->link.targetFilePath != filePath);
if (openExtraFile) if (openExtraFile)
client()->openExtraFile(it.key().toFilePath(), it->fileContent); client()->openExtraFile(filePath, it->fileContent);
it->fileContent.clear(); it->fileContent.clear();
const auto docVariant = doc ? ClangdClient::TextDocOrFile(doc) const auto docVariant = doc ? ClangdClient::TextDocOrFile(doc)
: ClangdClient::TextDocOrFile(it.key().toFilePath()); : ClangdClient::TextDocOrFile(filePath);
const auto astHandler = [sentinel = QPointer(q), this, loc = it.key()]( const auto astHandler = [sentinel = QPointer(q), this, loc = it.key(), filePath](
const ClangdAstNode &ast, const MessageId &reqId) { const ClangdAstNode &ast, const MessageId &reqId) {
qCDebug(clangdLog) << "AST for" << loc.toFilePath(); qCDebug(clangdLog) << "AST for" << filePath;
if (!sentinel) if (!sentinel)
return; return;
if (!search || canceled) if (!search || canceled)
@@ -324,7 +324,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList<Location>
data.ast = ast; data.ast = ast;
pendingAstRequests.removeOne(reqId); pendingAstRequests.removeOne(reqId);
qCDebug(clangdLog) << pendingAstRequests.size() << "AST requests still pending"; qCDebug(clangdLog) << pendingAstRequests.size() << "AST requests still pending";
addSearchResultsForFile(loc.toFilePath(), data); addSearchResultsForFile(filePath, data);
fileData.remove(loc); fileData.remove(loc);
if (pendingAstRequests.isEmpty() && !canceled) { if (pendingAstRequests.isEmpty() && !canceled) {
qCDebug(clangdLog) << "retrieved all ASTs"; qCDebug(clangdLog) << "retrieved all ASTs";
@@ -335,7 +335,7 @@ void ClangdFindReferences::Private::handleFindUsagesResult(const QList<Location>
docVariant, astHandler, ClangdClient::AstCallbackMode::AlwaysAsync, {}); docVariant, astHandler, ClangdClient::AstCallbackMode::AlwaysAsync, {});
pendingAstRequests << reqId; pendingAstRequests << reqId;
if (openExtraFile) if (openExtraFile)
client()->closeExtraFile(it.key().toFilePath()); client()->closeExtraFile(filePath);
} }
} }
@@ -370,7 +370,7 @@ void ClangdFindReferences::Private::reportAllSearchResultsAndFinish()
{ {
if (!checkUnusedData) { if (!checkUnusedData) {
for (auto it = fileData.begin(); it != fileData.end(); ++it) for (auto it = fileData.begin(); it != fileData.end(); ++it)
addSearchResultsForFile(it.key().toFilePath(), it.value()); addSearchResultsForFile(client()->serverUriToHostPath(it.key()), it.value());
} }
finishSearch(); finishSearch();
} }
@@ -647,7 +647,7 @@ public:
Private(ClangdFindLocalReferences *q, TextDocument *document, const QTextCursor &cursor, Private(ClangdFindLocalReferences *q, TextDocument *document, const QTextCursor &cursor,
const RenameCallback &callback) const RenameCallback &callback)
: q(q), document(document), cursor(cursor), callback(callback), : q(q), document(document), cursor(cursor), callback(callback),
uri(DocumentUri::fromFilePath(document->filePath())), uri(client()->hostPathToServerUri(document->filePath())),
revision(document->document()->revision()) revision(document->document()->revision())
{} {}
@@ -749,7 +749,12 @@ void ClangdFindLocalReferences::Private::checkDefinitionAst(const ClangdAstNode
void ClangdFindLocalReferences::Private::handleReferences(const QList<Location> &references) void ClangdFindLocalReferences::Private::handleReferences(const QList<Location> &references)
{ {
qCDebug(clangdLog) << "found" << references.size() << "local references"; qCDebug(clangdLog) << "found" << references.size() << "local references";
const Utils::Links links = Utils::transform(references, &Location::toLink);
const auto transformLocation = [mapper = client()->hostPathMapper()](const Location &loc) {
return loc.toLink(mapper);
};
const Utils::Links links = Utils::transform(references, transformLocation);
// The callback only uses the symbol length, so we just create a dummy. // The callback only uses the symbol length, so we just create a dummy.
// Note that the calculation will be wrong for identifiers with // Note that the calculation will be wrong for identifiers with

View File

@@ -72,7 +72,7 @@ public:
CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback, CppEditorWidget *editorWidget, const FilePath &filePath, const LinkHandler &callback,
bool openInSplit) bool openInSplit)
: q(q), client(client), cursor(cursor), editorWidget(editorWidget), : q(q), client(client), cursor(cursor), editorWidget(editorWidget),
uri(DocumentUri::fromFilePath(filePath)), callback(callback), uri(client->hostPathToServerUri(filePath)), callback(callback),
virtualFuncAssistProvider(q), virtualFuncAssistProvider(q),
docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1), docRevision(editorWidget ? editorWidget->textDocument()->document()->revision() : -1),
openInSplit(openInSplit) {} openInSplit(openInSplit) {}
@@ -246,7 +246,7 @@ void ClangdFollowSymbol::Private::sendGotoImplementationRequest(const Link &link
if (!client->documentForFilePath(link.targetFilePath) && addOpenFile(link.targetFilePath)) if (!client->documentForFilePath(link.targetFilePath) && addOpenFile(link.targetFilePath))
client->openExtraFile(link.targetFilePath); client->openExtraFile(link.targetFilePath);
const Position position(link.targetLine - 1, link.targetColumn); const Position position(link.targetLine - 1, link.targetColumn);
const TextDocumentIdentifier documentId(DocumentUri::fromFilePath(link.targetFilePath)); const TextDocumentIdentifier documentId(client->hostPathToServerUri(link.targetFilePath));
GotoImplementationRequest req(TextDocumentPositionParams(documentId, position)); GotoImplementationRequest req(TextDocumentPositionParams(documentId, position));
req.setResponseCallback([sentinel = QPointer(q), this, reqId = req.id()] req.setResponseCallback([sentinel = QPointer(q), this, reqId = req.id()]
(const GotoImplementationRequest::Response &response) { (const GotoImplementationRequest::Response &response) {
@@ -363,12 +363,13 @@ void ClangdFollowSymbol::Private::goToTypeDefinition()
if (!sentinel) if (!sentinel)
return; return;
Link link; Link link;
if (const std::optional<GotoResult> &result = response.result()) { if (const std::optional<GotoResult> &result = response.result()) {
if (const auto ploc = std::get_if<Location>(&*result)) { if (const auto ploc = std::get_if<Location>(&*result)) {
link = {ploc->toLink()}; link = {ploc->toLink(client->hostPathMapper())};
} else if (const auto plloc = std::get_if<QList<Location>>(&*result)) { } else if (const auto plloc = std::get_if<QList<Location>>(&*result)) {
if (!plloc->empty()) if (!plloc->empty())
link = plloc->first().toLink(); link = plloc->first().toLink(client->hostPathMapper());
} }
} }
q->emitDone(link); q->emitDone(link);
@@ -399,12 +400,15 @@ void ClangdFollowSymbol::Private::handleGotoDefinitionResult()
void ClangdFollowSymbol::Private::handleGotoImplementationResult( void ClangdFollowSymbol::Private::handleGotoImplementationResult(
const GotoImplementationRequest::Response &response) const GotoImplementationRequest::Response &response)
{ {
auto transformLink = [mapper = client->hostPathMapper()](const Location &loc) {
return loc.toLink(mapper);
};
if (const std::optional<GotoResult> &result = response.result()) { if (const std::optional<GotoResult> &result = response.result()) {
QList<Link> newLinks; QList<Link> newLinks;
if (const auto ploc = std::get_if<Location>(&*result)) if (const auto ploc = std::get_if<Location>(&*result))
newLinks = {ploc->toLink()}; newLinks = {transformLink(*ploc)};
if (const auto plloc = std::get_if<QList<Location>>(&*result)) if (const auto plloc = std::get_if<QList<Location>>(&*result))
newLinks = transform(*plloc, &Location::toLink); newLinks = transform(*plloc, transformLink);
for (const Link &link : std::as_const(newLinks)) { for (const Link &link : std::as_const(newLinks)) {
if (!allLinks.contains(link)) { if (!allLinks.contains(link)) {
allLinks << link; allLinks << link;
@@ -465,33 +469,34 @@ void ClangdFollowSymbol::Private::handleGotoImplementationResult(
if (link == defLink) if (link == defLink)
continue; continue;
const TextDocumentIdentifier doc(DocumentUri::fromFilePath(link.targetFilePath)); const TextDocumentIdentifier doc(client->hostPathToServerUri(link.targetFilePath));
const TextDocumentPositionParams params(doc, pos); const TextDocumentPositionParams params(doc, pos);
GotoDefinitionRequest defReq(params); GotoDefinitionRequest defReq(params);
defReq.setResponseCallback([this, link, sentinel = QPointer(q), reqId = defReq.id()] defReq.setResponseCallback(
(const GotoDefinitionRequest::Response &response) { [this, link, transformLink, sentinel = QPointer(q), reqId = defReq.id()](
qCDebug(clangdLog) << "handling additional go to definition reply for" const GotoDefinitionRequest::Response &response) {
<< link.targetFilePath << link.targetLine; qCDebug(clangdLog) << "handling additional go to definition reply for"
if (!sentinel) << link.targetFilePath << link.targetLine;
return; if (!sentinel)
Link newLink; return;
if (std::optional<GotoResult> _result = response.result()) { Link newLink;
const GotoResult result = _result.value(); if (std::optional<GotoResult> _result = response.result()) {
if (const auto ploc = std::get_if<Location>(&result)) { const GotoResult result = _result.value();
newLink = ploc->toLink(); if (const auto ploc = std::get_if<Location>(&result)) {
} else if (const auto plloc = std::get_if<QList<Location>>(&result)) { newLink = transformLink(*ploc);
if (!plloc->isEmpty()) } else if (const auto plloc = std::get_if<QList<Location>>(&result)) {
newLink = plloc->value(0).toLink(); if (!plloc->isEmpty())
newLink = transformLink(plloc->value(0));
}
} }
} qCDebug(clangdLog) << "def link is" << newLink.targetFilePath << newLink.targetLine;
qCDebug(clangdLog) << "def link is" << newLink.targetFilePath << newLink.targetLine; declDefMap.insert(link, newLink);
declDefMap.insert(link, newLink); pendingGotoDefRequests.removeOne(reqId);
pendingGotoDefRequests.removeOne(reqId); if (pendingSymbolInfoRequests.isEmpty() && pendingGotoDefRequests.isEmpty()
if (pendingSymbolInfoRequests.isEmpty() && pendingGotoDefRequests.isEmpty()
&& defLinkNode.isValid()) { && defLinkNode.isValid()) {
handleDocumentInfoResults(); handleDocumentInfoResults();
} }
}); });
pendingGotoDefRequests << defReq.id(); pendingGotoDefRequests << defReq.id();
qCDebug(clangdLog) << "sending additional go to definition request" qCDebug(clangdLog) << "sending additional go to definition request"
<< link.targetFilePath << link.targetLine; << link.targetFilePath << link.targetLine;

View File

@@ -24,11 +24,10 @@ void ClangdQuickFixFactory::match(const CppEditor::Internal::CppQuickFixInterfac
if (!client) if (!client)
return; return;
const auto uri = DocumentUri::fromFilePath(interface.filePath());
QTextCursor cursor(interface.textDocument()); QTextCursor cursor(interface.textDocument());
cursor.setPosition(interface.position()); cursor.setPosition(interface.position());
cursor.select(QTextCursor::LineUnderCursor); cursor.select(QTextCursor::LineUnderCursor);
const QList<Diagnostic> &diagnostics = client->diagnosticsAt(uri, cursor); const QList<Diagnostic> &diagnostics = client->diagnosticsAt(interface.filePath(), cursor);
for (const Diagnostic &diagnostic : diagnostics) { for (const Diagnostic &diagnostic : diagnostics) {
ClangdDiagnostic clangdDiagnostic(diagnostic); ClangdDiagnostic clangdDiagnostic(diagnostic);
if (const auto actions = clangdDiagnostic.codeActions()) { if (const auto actions = clangdDiagnostic.codeActions()) {

View File

@@ -31,7 +31,7 @@ class ClangdSwitchDeclDef::Private
public: public:
Private(ClangdSwitchDeclDef * q, ClangdClient *client, TextDocument *doc, Private(ClangdSwitchDeclDef * q, ClangdClient *client, TextDocument *doc,
const QTextCursor &cursor, CppEditorWidget *editorWidget, const LinkHandler &callback) const QTextCursor &cursor, CppEditorWidget *editorWidget, const LinkHandler &callback)
: q(q), client(client), document(doc), uri(DocumentUri::fromFilePath(doc->filePath())), : q(q), client(client), document(doc), uri(client->hostPathToServerUri(doc->filePath())),
cursor(cursor), editorWidget(editorWidget), callback(callback) cursor(cursor), editorWidget(editorWidget), callback(callback)
{} {}

View File

@@ -163,7 +163,9 @@ ClangSourceRange convertRange(const FilePath &filePath, const Range &src)
return ClangSourceRange(start, end); return ClangSourceRange(start, end);
} }
ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src, const FilePath &filePath) ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src,
const FilePath &filePath,
const DocumentUri::PathMapper &mapper)
{ {
ClangDiagnostic target; ClangDiagnostic target;
target.location = convertRange(filePath, src.range()).start; target.location = convertRange(filePath, src.range()).start;
@@ -226,7 +228,8 @@ ClangDiagnostic convertDiagnostic(const ClangdDiagnostic &src, const FilePath &f
for (auto it = changes->cbegin(); it != changes->cend(); ++it) { for (auto it = changes->cbegin(); it != changes->cend(); ++it) {
for (const TextEdit &textEdit : it.value()) { for (const TextEdit &textEdit : it.value()) {
fixItDiag.fixIts << ClangFixIt(textEdit.newText(), fixItDiag.fixIts << ClangFixIt(textEdit.newText(),
convertRange(it.key().toFilePath(), textEdit.range())); convertRange(it.key().toFilePath(mapper),
textEdit.range()));
} }
} }
target.children << fixItDiag; target.children << fixItDiag;
@@ -270,7 +273,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath,
ClangdClient *client) ClangdClient *client)
: TextEditor::TextMark(filePath, int(diagnostic.range().start().line() + 1), client->id()) : TextEditor::TextMark(filePath, int(diagnostic.range().start().line() + 1), client->id())
, m_lspDiagnostic(diagnostic) , m_lspDiagnostic(diagnostic)
, m_diagnostic(convertDiagnostic(ClangdDiagnostic(diagnostic), filePath)) , m_diagnostic(convertDiagnostic(ClangdDiagnostic(diagnostic), filePath, client->hostPathMapper()))
, m_client(client) , m_client(client)
{ {
setSettingsPage(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); setSettingsPage(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID);
@@ -319,8 +322,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath,
bool ClangdTextMark::addToolTipContent(QLayout *target) const bool ClangdTextMark::addToolTipContent(QLayout *target) const
{ {
const auto canApplyFixIt = [c = m_client, diag = m_lspDiagnostic, fp = fileName()] { const auto canApplyFixIt = [c = m_client, diag = m_lspDiagnostic, fp = fileName()] {
return QTC_GUARD(c) && c->reachable() return QTC_GUARD(c) && c->reachable() && c->hasDiagnostic(fp, diag);
&& c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag);
}; };
const QString clientName = QTC_GUARD(m_client) ? m_client->name() : "clangd [unknown]"; const QString clientName = QTC_GUARD(m_client) ? m_client->name() : "clangd [unknown]";
target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic}, target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic},

View File

@@ -209,12 +209,12 @@ private:
return {}; return {};
} }
void setDiagnostics(const DocumentUri &uri, void setDiagnostics(const FilePath &filePath,
const QList<Diagnostic> &diagnostics, const QList<Diagnostic> &diagnostics,
const std::optional<int> &version) override const std::optional<int> &version) override
{ {
DiagnosticManager::setDiagnostics(uri, diagnostics, version); DiagnosticManager::setDiagnostics(filePath, diagnostics, version);
showDiagnostics(uri, client()->documentVersion(uri.toFilePath())); showDiagnostics(filePath, client()->documentVersion(filePath));
} }
}; };
@@ -227,7 +227,7 @@ void CocoLanguageClient::handleDiagnostics(const PublishDiagnosticsParams &param
{ {
using namespace TextEditor; using namespace TextEditor;
Client::handleDiagnostics(params); Client::handleDiagnostics(params);
TextDocument *document = documentForFilePath(params.uri().toFilePath()); TextDocument *document = documentForFilePath(serverUriToHostPath(params.uri()));
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(document)) for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(document))
editor->editorWidget()->addHoverHandler(hoverHandler()); editor->editorWidget()->addHoverHandler(hoverHandler());
} }

View File

@@ -5,8 +5,8 @@
#include "cppsourceprocessor.h" #include "cppsourceprocessor.h"
#include <projectexplorer/projectmacro.h>
#include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmacro.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -23,9 +23,12 @@ static QByteArray overwrittenToolchainDefines(const ProjectPart &projectPart)
// MSVC's predefined macros like __FUNCSIG__ expand to itself. // MSVC's predefined macros like __FUNCSIG__ expand to itself.
// We can't parse this, so redefine to the empty string literal. // We can't parse this, so redefine to the empty string literal.
if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) {
defines += "#define __FUNCSIG__ \"void __cdecl someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"\n" defines += "#define __FUNCSIG__ \"void __cdecl "
"#define __FUNCDNAME__ \"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"\n" "someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580(void)\"\n"
"#define __FUNCTION__ \"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"\n"; "#define __FUNCDNAME__ "
"\"?someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580@@YAXXZ\"\n"
"#define __FUNCTION__ "
"\"someLegalAndLongishFunctionNameThatWorksAroundQTCREATORBUG-24580\"\n";
} }
return defines; return defines;
@@ -63,11 +66,11 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
LanguageFeatures features = LanguageFeatures::defaultFeatures(); LanguageFeatures features = LanguageFeatures::defaultFeatures();
baseState.projectPartInfo = determineProjectPart(filePath().toString(), baseState.projectPartInfo = determineProjectPart(filePath().toString(),
baseConfig.preferredProjectPartId, baseConfig.preferredProjectPartId,
baseState.projectPartInfo, baseState.projectPartInfo,
updateParams.activeProject, updateParams.activeProject,
updateParams.languagePreference, updateParams.languagePreference,
updateParams.projectsUpdated); updateParams.projectsUpdated);
emit projectPartInfoUpdated(baseState.projectPartInfo); emit projectPartInfoUpdated(baseState.projectPartInfo);
if (state.forceSnapshotInvalidation) { if (state.forceSnapshotInvalidation) {
@@ -131,8 +134,8 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
if (invalidateSnapshot) { if (invalidateSnapshot) {
state.snapshot = Snapshot(); state.snapshot = Snapshot();
if (!baseState.editorDefines.isEmpty()) { if (!baseState.editorDefines.isEmpty()) {
workingCopy.insert(CppModelManager::editorConfigurationFileName(), workingCopy.insert(CppModelManager::editorConfigurationFileName(),
baseState.editorDefines); baseState.editorDefines);
} }
} else { } else {
// Remove changed files from the snapshot // Remove changed files from the snapshot
@@ -177,9 +180,7 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
doc->releaseSourceAndAST(); doc->releaseSourceAndAST();
}); });
sourceProcessor.setFileSizeLimitInMb(m_fileSizeLimitInMb); sourceProcessor.setFileSizeLimitInMb(m_fileSizeLimitInMb);
sourceProcessor.setCancelChecker([future]() { sourceProcessor.setCancelChecker([future]() { return future.isCanceled(); });
return future.isCanceled();
});
Snapshot globalSnapshot = modelManager->snapshot(); Snapshot globalSnapshot = modelManager->snapshot();
globalSnapshot.remove(filePath()); globalSnapshot.remove(filePath());
@@ -201,7 +202,9 @@ void BuiltinEditorDocumentParser::updateImpl(const QFutureInterface<void> &futur
sourceProcessor.run(filePath(), transform(includedFiles, &FilePath::fromString)); sourceProcessor.run(filePath(), transform(includedFiles, &FilePath::fromString));
state.snapshot = sourceProcessor.snapshot(); state.snapshot = sourceProcessor.snapshot();
Snapshot newSnapshot = state.snapshot.simplified(state.snapshot.document(filePath())); Snapshot newSnapshot = state.snapshot.simplified(state.snapshot.document(filePath()));
for (Snapshot::const_iterator i = state.snapshot.begin(), ei = state.snapshot.end(); i != ei; ++i) { for (Snapshot::const_iterator i = state.snapshot.begin(), ei = state.snapshot.end();
i != ei;
++i) {
if (Client::isInjectedFile(i.key().toString())) if (Client::isInjectedFile(i.key().toString()))
newSnapshot.insert(i.value()); newSnapshot.insert(i.value());
} }

View File

@@ -139,6 +139,7 @@ public:
, m_hoverHandler(q) , m_hoverHandler(q)
, m_symbolSupport(q) , m_symbolSupport(q)
, m_tokenSupport(q) , m_tokenSupport(q)
, m_serverDeviceTemplate(clientInterface->serverDeviceTemplate())
{ {
using namespace ProjectExplorer; using namespace ProjectExplorer;
@@ -329,6 +330,7 @@ public:
LanguageServerProtocol::ClientInfo m_clientInfo; LanguageServerProtocol::ClientInfo m_clientInfo;
QJsonValue m_configuration; QJsonValue m_configuration;
int m_completionResultsLimit = -1; int m_completionResultsLimit = -1;
const Utils::FilePath m_serverDeviceTemplate;
}; };
Client::Client(BaseClientInterface *clientInterface) Client::Client(BaseClientInterface *clientInterface)
@@ -500,11 +502,11 @@ void Client::initialize()
params.setCapabilities(d->m_clientCapabilities); params.setCapabilities(d->m_clientCapabilities);
params.setInitializationOptions(d->m_initializationOptions); params.setInitializationOptions(d->m_initializationOptions);
if (d->m_project) if (d->m_project)
params.setRootUri(DocumentUri::fromFilePath(d->m_project->projectDirectory())); params.setRootUri(hostPathToServerUri(d->m_project->projectDirectory()));
const QList<WorkSpaceFolder> workspaces const QList<WorkSpaceFolder> workspaces
= Utils::transform(SessionManager::projects(), [](Project *pro) { = Utils::transform(SessionManager::projects(), [this](Project *pro) {
return WorkSpaceFolder(DocumentUri::fromFilePath(pro->projectDirectory()), return WorkSpaceFolder(hostPathToServerUri(pro->projectDirectory()),
pro->displayName()); pro->displayName());
}); });
if (workspaces.isEmpty()) if (workspaces.isEmpty())
@@ -746,7 +748,6 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg
{ {
QTimer *timer = m_documentHighlightsTimer[widget]; QTimer *timer = m_documentHighlightsTimer[widget];
if (!timer) { if (!timer) {
const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath());
if (m_highlightRequests.contains(widget)) if (m_highlightRequests.contains(widget))
q->cancelRequest(m_highlightRequests.take(widget)); q->cancelRequest(m_highlightRequests.take(widget));
timer = new QTimer; timer = new QTimer;
@@ -771,7 +772,7 @@ void ClientPrivate::requestDocumentHighlights(TextEditor::TextEditorWidget *widg
void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *widget) void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *widget)
{ {
QTC_ASSERT(q->reachable(), return); 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)) { if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) {
TextDocumentRegistrationOptions option( TextDocumentRegistrationOptions option(
m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName)); m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName));
@@ -833,9 +834,8 @@ void ClientPrivate::requestDocumentHighlightsNow(TextEditor::TextEditorWidget *w
void Client::activateDocument(TextEditor::TextDocument *document) void Client::activateDocument(TextEditor::TextDocument *document)
{ {
const FilePath &filePath = document->filePath(); const FilePath &filePath = document->filePath();
auto uri = DocumentUri::fromFilePath(filePath);
if (d->m_diagnosticManager) 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); d->m_tokenSupport.updateSemanticTokens(document);
// only replace the assist provider if the language server support it // only replace the assist provider if the language server support it
d->updateCompletionProvider(document); d->updateCompletionProvider(document);
@@ -897,7 +897,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString
{ {
TextDocumentItem item; TextDocumentItem item;
item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(mimeType)); item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(mimeType));
item.setUri(DocumentUri::fromFilePath(filePath)); item.setUri(q->hostPathToServerUri(filePath));
item.setText(content); item.setText(content);
item.setVersion(version); item.setVersion(version);
q->sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)), q->sendMessage(DidOpenTextDocumentNotification(DidOpenTextDocumentParams(item)),
@@ -907,7 +907,7 @@ void ClientPrivate::sendOpenNotification(const FilePath &filePath, const QString
void ClientPrivate::sendCloseNotification(const FilePath &filePath) void ClientPrivate::sendCloseNotification(const FilePath &filePath)
{ {
q->sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams( q->sendMessage(DidCloseTextDocumentNotification(DidCloseTextDocumentParams(
TextDocumentIdentifier{DocumentUri::fromFilePath(filePath)})), TextDocumentIdentifier{q->hostPathToServerUri(filePath)})),
Client::SendDocUpdates::Ignore); Client::SendDocUpdates::Ignore);
} }
@@ -950,7 +950,7 @@ void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &c
} else { } else {
shadowIt.value().first = content; shadowIt.value().first = content;
if (!shadowIt.value().second.isEmpty()) { if (!shadowIt.value().second.isEmpty()) {
VersionedTextDocumentIdentifier docId(DocumentUri::fromFilePath(filePath)); VersionedTextDocumentIdentifier docId(hostPathToServerUri(filePath));
docId.setVersion(++d->m_documentVersions[filePath]); docId.setVersion(++d->m_documentVersions[filePath]);
const DidChangeTextDocumentParams params(docId, content); const DidChangeTextDocumentParams params(docId, content);
sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore); sendMessage(DidChangeTextDocumentNotification(params), SendDocUpdates::Ignore);
@@ -981,7 +981,6 @@ void ClientPrivate::openShadowDocument(const TextEditor::TextDocument *requringD
shadowIt.value().second << requringDoc; shadowIt.value().second << requringDoc;
if (shadowIt.value().second.size() > 1) if (shadowIt.value().second.size() > 1)
return; return;
const auto uri = DocumentUri::fromFilePath(shadowIt.key());
const QString mimeType = mimeTypeForFile(shadowIt.key(), MimeMatchMode::MatchExtension).name(); const QString mimeType = mimeTypeForFile(shadowIt.key(), MimeMatchMode::MatchExtension).name();
sendOpenNotification(shadowIt.key(), mimeType, shadowIt.value().first, sendOpenNotification(shadowIt.key(), mimeType, shadowIt.value().first,
++m_documentVersions[shadowIt.key()]); ++m_documentVersions[shadowIt.key()]);
@@ -1021,7 +1020,7 @@ void Client::documentContentsSaved(TextEditor::TextDocument *document)
if (!send) if (!send)
return; return;
DidSaveTextDocumentParams params( DidSaveTextDocumentParams params(
TextDocumentIdentifier(DocumentUri::fromFilePath(document->filePath()))); TextDocumentIdentifier(hostPathToServerUri(document->filePath())));
d->openRequiredShadowDocuments(document); d->openRequiredShadowDocuments(document);
if (includeText) if (includeText)
params.setText(document->plainText()); params.setText(document->plainText());
@@ -1053,7 +1052,7 @@ void Client::documentWillSave(Core::IDocument *document)
if (!send) if (!send)
return; return;
const WillSaveTextDocumentParams params( const WillSaveTextDocumentParams params(
TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); TextDocumentIdentifier(hostPathToServerUri(filePath)));
sendMessage(WillSaveTextDocumentNotification(params)); sendMessage(WillSaveTextDocumentNotification(params));
} }
@@ -1241,7 +1240,7 @@ void ClientPrivate::requestCodeActions(const DocumentUri &uri,
const Range &range, const Range &range,
const QList<Diagnostic> &diagnostics) const QList<Diagnostic> &diagnostics)
{ {
const Utils::FilePath fileName = uri.toFilePath(); const Utils::FilePath fileName = q->serverUriToHostPath(uri);
TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(fileName); TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath(fileName);
if (!doc) if (!doc)
return; return;
@@ -1273,8 +1272,11 @@ void Client::requestCodeActions(const CodeActionRequest &request)
if (!request.isValid(nullptr)) if (!request.isValid(nullptr))
return; return;
const Utils::FilePath fileName const Utils::FilePath fileName = request.params()
= request.params().value_or(CodeActionParams()).textDocument().uri().toFilePath(); .value_or(CodeActionParams())
.textDocument()
.uri()
.toFilePath(hostPathMapper());
const QString method(CodeActionRequest::methodName); const QString method(CodeActionRequest::methodName);
if (std::optional<bool> registered = d->m_dynamicCapabilities.isRegistered(method)) { if (std::optional<bool> registered = d->m_dynamicCapabilities.isRegistered(method)) {
@@ -1349,7 +1351,7 @@ void Client::projectOpened(ProjectExplorer::Project *project)
if (!d->sendWorkspceFolderChanges()) if (!d->sendWorkspceFolderChanges())
return; return;
WorkspaceFoldersChangeEvent event; WorkspaceFoldersChangeEvent event;
event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), event.setAdded({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()),
project->displayName())}); project->displayName())});
DidChangeWorkspaceFoldersParams params; DidChangeWorkspaceFoldersParams params;
params.setEvent(event); params.setEvent(event);
@@ -1361,7 +1363,7 @@ void Client::projectClosed(ProjectExplorer::Project *project)
{ {
if (d->sendWorkspceFolderChanges()) { if (d->sendWorkspceFolderChanges()) {
WorkspaceFoldersChangeEvent event; WorkspaceFoldersChangeEvent event;
event.setRemoved({WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), event.setRemoved({WorkSpaceFolder(hostPathToServerUri(project->projectDirectory()),
project->displayName())}); project->displayName())});
DidChangeWorkspaceFoldersParams params; DidChangeWorkspaceFoldersParams params;
params.setEvent(event); params.setEvent(event);
@@ -1420,7 +1422,7 @@ bool Client::isSupportedFile(const Utils::FilePath &filePath, const QString &mim
bool Client::isSupportedUri(const DocumentUri &uri) const 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()); 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); 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) if (d->m_diagnosticManager)
return d->m_diagnosticManager->diagnosticsAt(uri, cursor); return d->m_diagnosticManager->diagnosticsAt(filePath, cursor);
return {}; return {};
} }
bool Client::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, bool Client::hasDiagnostic(const FilePath &filePath,
const LanguageServerProtocol::Diagnostic &diag) const const LanguageServerProtocol::Diagnostic &diag) const
{ {
if (d->m_diagnosticManager) 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; return false;
} }
@@ -1708,7 +1710,7 @@ void ClientPrivate::sendPostponedDocumentUpdates(Schedule semanticTokensSchedule
[this](const auto &elem) { [this](const auto &elem) {
TextEditor::TextDocument * const document = elem.first; TextEditor::TextDocument * const document = elem.first;
const FilePath &filePath = document->filePath(); const FilePath &filePath = document->filePath();
const auto uri = DocumentUri::fromFilePath(filePath); const LanguageServerProtocol::DocumentUri uri = q->hostPathToServerUri(filePath);
VersionedTextDocumentIdentifier docId(uri); VersionedTextDocumentIdentifier docId(uri);
docId.setVersion(m_documentVersions[filePath]); docId.setVersion(m_documentVersions[filePath]);
DidChangeTextDocumentParams params; DidChangeTextDocumentParams params;
@@ -1867,8 +1869,8 @@ void ClientPrivate::handleMethod(const QString &method, const MessageId &id, con
} else { } else {
response.setResult(Utils::transform( response.setResult(Utils::transform(
projects, projects,
[](ProjectExplorer::Project *project) { [this](ProjectExplorer::Project *project) {
return WorkSpaceFolder(DocumentUri::fromFilePath(project->projectDirectory()), return WorkSpaceFolder(q->hostPathToServerUri(project->projectDirectory()),
project->displayName()); project->displayName());
})); }));
} }
@@ -1906,9 +1908,10 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams &params)
const QList<Diagnostic> &diagnostics = params.diagnostics(); const QList<Diagnostic> &diagnostics = params.diagnostics();
if (!d->m_diagnosticManager) if (!d->m_diagnosticManager)
d->m_diagnosticManager = createDiagnosticManager(); d->m_diagnosticManager = createDiagnosticManager();
d->m_diagnosticManager->setDiagnostics(uri, diagnostics, params.version()); const FilePath &path = serverUriToHostPath(uri);
if (LanguageClientManager::clientForUri(uri) == this) { d->m_diagnosticManager->setDiagnostics(path, diagnostics, params.version());
d->m_diagnosticManager->showDiagnostics(uri, d->m_documentVersions.value(uri.toFilePath())); if (LanguageClientManager::clientForFilePath(path) == this) {
d->m_diagnosticManager->showDiagnostics(path, d->m_documentVersions.value(path));
if (d->m_autoRequestCodeActions) if (d->m_autoRequestCodeActions)
requestCodeActions(uri, diagnostics); requestCodeActions(uri, diagnostics);
} }
@@ -1932,6 +1935,11 @@ int Client::documentVersion(const Utils::FilePath &filePath) const
return d->m_documentVersions.value(filePath); return d->m_documentVersions.value(filePath);
} }
int Client::documentVersion(const LanguageServerProtocol::DocumentUri &uri) const
{
return documentVersion(serverUriToHostPath(uri));
}
void Client::setDocumentChangeUpdateThreshold(int msecs) void Client::setDocumentChangeUpdateThreshold(int msecs)
{ {
d->m_documentUpdateTimer.setInterval(msecs); d->m_documentUpdateTimer.setInterval(msecs);
@@ -2071,6 +2079,25 @@ bool Client::fileBelongsToProject(const Utils::FilePath &filePath) const
return project() && project()->isKnownFile(filePath); 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 } // namespace LanguageClient
#include <client.moc> #include <client.moc>

View File

@@ -126,6 +126,7 @@ public:
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; int documentVersion(const Utils::FilePath &filePath) const;
int documentVersion(const LanguageServerProtocol::DocumentUri &uri) const;
void setDocumentChangeUpdateThreshold(int msecs); void setDocumentChangeUpdateThreshold(int msecs);
// workspace control // workspace control
@@ -151,10 +152,9 @@ public:
SymbolSupport &symbolSupport(); SymbolSupport &symbolSupport();
DocumentSymbolCache *documentSymbolCache(); DocumentSymbolCache *documentSymbolCache();
HoverHandler *hoverHandler(); HoverHandler *hoverHandler();
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt( QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(const Utils::FilePath &filePath,
const LanguageServerProtocol::DocumentUri &uri, const QTextCursor &cursor) const;
const QTextCursor &cursor) const; bool hasDiagnostic(const Utils::FilePath &filePath,
bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
const LanguageServerProtocol::Diagnostic &diag) const; const LanguageServerProtocol::Diagnostic &diag) const;
bool hasDiagnostics(const TextEditor::TextDocument *document) const; bool hasDiagnostics(const TextEditor::TextDocument *document) const;
void setSemanticTokensHandler(const SemanticTokensHandler &handler); void setSemanticTokensHandler(const SemanticTokensHandler &handler);
@@ -166,6 +166,10 @@ public:
virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const; virtual bool supportsDocumentSymbols(const TextEditor::TextDocument *doc) const;
virtual bool fileBelongsToProject(const Utils::FilePath &filePath) 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 // logging
enum class LogTarget { Console, Ui }; enum class LogTarget { Console, Ui };
void setLogTarget(LogTarget target); void setLogTarget(LogTarget target);

View File

@@ -56,12 +56,12 @@ DiagnosticManager::~DiagnosticManager()
clearDiagnostics(); clearDiagnostics();
} }
void DiagnosticManager::setDiagnostics(const DocumentUri &uri, void DiagnosticManager::setDiagnostics(const FilePath &filePath,
const QList<Diagnostic> &diagnostics, const QList<Diagnostic> &diagnostics,
const std::optional<int> &version) const std::optional<int> &version)
{ {
hideDiagnostics(uri.toFilePath()); hideDiagnostics(filePath);
m_diagnostics[uri] = {version, filteredDiagnostics(diagnostics)}; m_diagnostics[filePath] = {version, filteredDiagnostics(diagnostics)};
} }
void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath) void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath)
@@ -89,12 +89,11 @@ void DiagnosticManager::disableDiagnostics(TextEditor::TextDocument *document)
marks.enabled = false; 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)) { 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(filePath);
if (versionedDiagnostics.version.value_or(version) == version if (versionedDiagnostics.version.value_or(version) == version
&& !versionedDiagnostics.diagnostics.isEmpty()) { && !versionedDiagnostics.diagnostics.isEmpty()) {
Marks &marks = m_marks[filePath]; Marks &marks = m_marks[filePath];
@@ -167,17 +166,17 @@ void DiagnosticManager::forAllMarks(std::function<void (TextEditor::TextMark *)>
void DiagnosticManager::clearDiagnostics() void DiagnosticManager::clearDiagnostics()
{ {
for (const DocumentUri &uri : m_diagnostics.keys()) for (const Utils::FilePath &path : m_diagnostics.keys())
hideDiagnostics(uri.toFilePath()); hideDiagnostics(path);
m_diagnostics.clear(); m_diagnostics.clear();
QTC_ASSERT(m_marks.isEmpty(), m_marks.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 QTextCursor &cursor) const
{ {
const int documentRevision = m_client->documentVersion(uri.toFilePath()); const int documentRevision = m_client->documentVersion(filePath);
auto it = m_diagnostics.find(uri); auto it = m_diagnostics.find(filePath);
if (it == m_diagnostics.end()) if (it == m_diagnostics.end())
return {}; return {};
if (documentRevision != it->version.value_or(documentRevision)) 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 TextDocument *doc,
const LanguageServerProtocol::Diagnostic &diag) const const LanguageServerProtocol::Diagnostic &diag) const
{ {
if (!doc) if (!doc)
return false; return false;
const auto it = m_diagnostics.find(uri); const auto it = m_diagnostics.find(filePath);
if (it == m_diagnostics.end()) if (it == m_diagnostics.end())
return {}; return {};
const int revision = m_client->documentVersion(uri.toFilePath()); const int revision = m_client->documentVersion(filePath);
if (revision != it->version.value_or(revision)) if (revision != it->version.value_or(revision))
return false; return false;
return it->diagnostics.contains(diag); return it->diagnostics.contains(diag);
@@ -205,7 +204,7 @@ bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri
bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const
{ {
const FilePath docPath = doc->filePath(); 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()) if (it == m_diagnostics.end())
return {}; return {};
const int revision = m_client->documentVersion(docPath); const int revision = m_client->documentVersion(docPath);

View File

@@ -30,11 +30,11 @@ public:
explicit DiagnosticManager(Client *client); explicit DiagnosticManager(Client *client);
~DiagnosticManager() override; ~DiagnosticManager() override;
virtual void setDiagnostics(const LanguageServerProtocol::DocumentUri &uri, virtual void setDiagnostics(const Utils::FilePath &filePath,
const QList<LanguageServerProtocol::Diagnostic> &diagnostics, const QList<LanguageServerProtocol::Diagnostic> &diagnostics,
const std::optional<int> &version); 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 void hideDiagnostics(const Utils::FilePath &filePath);
virtual QList<LanguageServerProtocol::Diagnostic> filteredDiagnostics( virtual QList<LanguageServerProtocol::Diagnostic> filteredDiagnostics(
const QList<LanguageServerProtocol::Diagnostic> &diagnostics) const; const QList<LanguageServerProtocol::Diagnostic> &diagnostics) const;
@@ -43,9 +43,9 @@ public:
void clearDiagnostics(); void clearDiagnostics();
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt( QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
const LanguageServerProtocol::DocumentUri &uri, const Utils::FilePath &filePath,
const QTextCursor &cursor) const; const QTextCursor &cursor) const;
bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri, bool hasDiagnostic(const Utils::FilePath &filePath,
const TextEditor::TextDocument *doc, const TextEditor::TextDocument *doc,
const LanguageServerProtocol::Diagnostic &diag) const; const LanguageServerProtocol::Diagnostic &diag) const;
bool hasDiagnostics(const TextEditor::TextDocument *doc) const; bool hasDiagnostics(const TextEditor::TextDocument *doc) const;
@@ -71,7 +71,7 @@ private:
std::optional<int> version; std::optional<int> version;
QList<LanguageServerProtocol::Diagnostic> diagnostics; QList<LanguageServerProtocol::Diagnostic> diagnostics;
}; };
QMap<LanguageServerProtocol::DocumentUri, VersionedDiagnostics> m_diagnostics; QMap<Utils::FilePath, VersionedDiagnostics> m_diagnostics;
class Marks class Marks
{ {
public: public:

View File

@@ -18,8 +18,8 @@ DocumentSymbolCache::DocumentSymbolCache(Client *client)
{ {
auto connectDocument = [this](Core::IDocument *document) { auto connectDocument = [this](Core::IDocument *document) {
connect(document, &Core::IDocument::contentsChanged, this, [document, this]() { connect(document, &Core::IDocument::contentsChanged, this, [document, this]() {
const auto uri = DocumentUri::fromFilePath(document->filePath()); const auto uri = m_client->hostPathToServerUri(document->filePath());
m_cache.remove(DocumentUri::fromFilePath(document->filePath())); m_cache.remove(uri);
auto requestIdIt = m_runningRequests.find(uri); auto requestIdIt = m_runningRequests.find(uri);
if (requestIdIt != m_runningRequests.end()) { if (requestIdIt != m_runningRequests.end()) {
m_client->cancelRequest(requestIdIt.value()); 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) bool clientSupportsDocumentSymbols(const Client *client, const DocumentUri &uri)
{ {
QTC_ASSERT(client, return false); 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); return client->supportsDocumentSymbols(doc);
} }

View File

@@ -446,7 +446,7 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform()
params.setPosition({line, column}); params.setPosition({line, column});
params.setContext(context); params.setContext(context);
params.setTextDocument( params.setTextDocument(
TextDocumentIdentifier(DocumentUri::fromFilePath(interface()->filePath()))); TextDocumentIdentifier(m_client->hostPathToServerUri(interface()->filePath())));
if (const int limit = m_client->completionResultsLimit(); limit >= 0) if (const int limit = m_client->completionResultsLimit(); limit >= 0)
params.setLimit(limit); params.setLimit(limit);
CompletionRequest completionRequest(params); CompletionRequest completionRequest(params);

View File

@@ -73,7 +73,7 @@ QFutureWatcher<ChangeSet> *LanguageClientFormatter::format(
return nullptr; return nullptr;
} }
DocumentRangeFormattingParams params; DocumentRangeFormattingParams params;
const DocumentUri uri = DocumentUri::fromFilePath(filePath); const DocumentUri uri = m_client->hostPathToServerUri(filePath);
params.setTextDocument(TextDocumentIdentifier(uri)); params.setTextDocument(TextDocumentIdentifier(uri));
params.setOptions(formattingOptions(tabSettings)); params.setOptions(formattingOptions(tabSettings));
if (!cursor.hasSelection()) { if (!cursor.hasSelection()) {

View File

@@ -72,7 +72,7 @@ IAssistProposal *FunctionHintProcessor::perform()
m_pos = interface()->position(); m_pos = interface()->position();
QTextCursor cursor(interface()->textDocument()); QTextCursor cursor(interface()->textDocument());
cursor.setPosition(m_pos); cursor.setPosition(m_pos);
auto uri = DocumentUri::fromFilePath(interface()->filePath()); auto uri = m_client->hostPathToServerUri(interface()->filePath());
SignatureHelpRequest request((TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(cursor)))); SignatureHelpRequest request((TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(cursor))));
request.setResponseCallback([this](auto response) { this->handleSignatureResponse(response); }); request.setResponseCallback([this](auto response) { this->handleSignatureResponse(response); });
m_client->addAssistProcessor(this); m_client->addAssistProcessor(this);

View File

@@ -55,7 +55,7 @@ void HoverHandler::setHelpItem(const LanguageServerProtocol::MessageId &msgId,
bool HoverHandler::reportDiagnostics(const QTextCursor &cursor) 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()) if (diagnostics.isEmpty())
return false; return false;
@@ -76,7 +76,7 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget,
report(Priority_None); report(Priority_None);
return; return;
} }
m_uri = DocumentUri::fromFilePath(editorWidget->textDocument()->filePath()); m_filePath = editorWidget->textDocument()->filePath();
m_response = {}; m_response = {};
m_report = report; m_report = report;
@@ -108,8 +108,9 @@ void HoverHandler::identifyMatch(TextEditor::TextEditorWidget *editorWidget,
return; return;
} }
HoverRequest request{TextDocumentPositionParams(TextDocumentIdentifier(m_uri), HoverRequest request{
Position(cursor))}; TextDocumentPositionParams(TextDocumentIdentifier(m_client->hostPathToServerUri(m_filePath)),
Position(cursor))};
m_currentRequest = request.id(); m_currentRequest = request.id();
request.setResponseCallback( request.setResponseCallback(
[this, cursor](const HoverRequest::Response &response) { handleResponse(response, cursor); }); [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 (auto hover = std::get_if<Hover>(&(*result))) {
if (m_helpItemProvider) { if (m_helpItemProvider) {
m_response = response; m_response = response;
m_helpItemProvider(response, m_uri); m_helpItemProvider(response, m_filePath);
return; return;
} }
setContent(hover->content()); setContent(hover->content());

View File

@@ -15,7 +15,7 @@ namespace LanguageClient {
class Client; class Client;
using HelpItemProvider = std::function<void(const LanguageServerProtocol::HoverRequest::Response &, 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 class LANGUAGECLIENT_EXPORT HoverHandler final : public TextEditor::BaseHoverHandler
{ {
@@ -49,7 +49,7 @@ private:
QPointer<Client> m_client; QPointer<Client> m_client;
std::optional<LanguageServerProtocol::MessageId> m_currentRequest; std::optional<LanguageServerProtocol::MessageId> m_currentRequest;
LanguageServerProtocol::DocumentUri m_uri; Utils::FilePath m_filePath;
LanguageServerProtocol::HoverRequest::Response m_response; LanguageServerProtocol::HoverRequest::Response m_response;
TextEditor::BaseHoverHandler::ReportPriority m_report; TextEditor::BaseHoverHandler::ReportPriority m_report;
HelpItemProvider m_helpItemProvider; HelpItemProvider m_helpItemProvider;

View File

@@ -131,6 +131,11 @@ void StdIOClientInterface::setEnvironment(const Utils::Environment &environment)
m_env = environment; m_env = environment;
} }
Utils::FilePath StdIOClientInterface::serverDeviceTemplate() const
{
return m_cmd.executable();
}
void StdIOClientInterface::sendData(const QByteArray &data) void StdIOClientInterface::sendData(const QByteArray &data)
{ {
if (!m_process || m_process->state() != QProcess::Running) { if (!m_process || m_process->state() != QProcess::Running) {

View File

@@ -28,6 +28,8 @@ public:
void sendMessage(const LanguageServerProtocol::JsonRpcMessage message); void sendMessage(const LanguageServerProtocol::JsonRpcMessage message);
void start() { startImpl(); } void start() { startImpl(); }
virtual Utils::FilePath serverDeviceTemplate() const = 0;
void resetBuffer(); void resetBuffer();
signals: signals:
@@ -66,6 +68,8 @@ public:
void setWorkingDirectory(const Utils::FilePath &workingDirectory); void setWorkingDirectory(const Utils::FilePath &workingDirectory);
void setEnvironment(const Utils::Environment &environment); void setEnvironment(const Utils::Environment &environment);
Utils::FilePath serverDeviceTemplate() const override;
protected: protected:
void sendData(const QByteArray &data) final; void sendData(const QByteArray &data) final;
Utils::CommandLine m_cmd; Utils::CommandLine m_cmd;

View File

@@ -391,11 +391,6 @@ Client *LanguageClientManager::clientForFilePath(const Utils::FilePath &filePath
return clientForDocument(TextEditor::TextDocument::textDocumentForFilePath(filePath)); return clientForDocument(TextEditor::TextDocument::textDocumentForFilePath(filePath));
} }
Client *LanguageClientManager::clientForUri(const DocumentUri &uri)
{
return clientForFilePath(uri.toFilePath());
}
const QList<Client *> LanguageClientManager::clientsForProject( const QList<Client *> LanguageClientManager::clientsForProject(
const ProjectExplorer::Project *project) const ProjectExplorer::Project *project)
{ {

View File

@@ -64,7 +64,6 @@ public:
static const BaseSettings *settingForClient(Client *setting); static const BaseSettings *settingForClient(Client *setting);
static Client *clientForDocument(TextEditor::TextDocument *document); static Client *clientForDocument(TextEditor::TextDocument *document);
static Client *clientForFilePath(const Utils::FilePath &filePath); static Client *clientForFilePath(const Utils::FilePath &filePath);
static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri);
static const QList<Client *> clientsForProject(const ProjectExplorer::Project *project); static const QList<Client *> clientsForProject(const ProjectExplorer::Project *project);
template<typename T> static bool hasClients(); template<typename T> static bool hasClients();

View File

@@ -195,14 +195,14 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client,
: m_client(client) : m_client(client)
, m_editor(editor) , m_editor(editor)
, m_view(this) , m_view(this)
, m_uri(DocumentUri::fromFilePath(editor->textDocument()->filePath())) , m_uri(m_client->hostPathToServerUri(editor->textDocument()->filePath()))
{ {
connect(client->documentSymbolCache(), connect(client->documentSymbolCache(),
&DocumentSymbolCache::gotSymbols, &DocumentSymbolCache::gotSymbols,
this, this,
&LanguageClientOutlineWidget::handleResponse); &LanguageClientOutlineWidget::handleResponse);
connect(client, &Client::documentUpdated, this, [this](TextEditor::TextDocument *document) { 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); m_client->documentSymbolCache()->requestSymbols(m_uri, Schedule::Delayed);
}); });
@@ -375,7 +375,7 @@ Utils::TreeViewComboBox *LanguageClientOutlineWidgetFactory::createComboBox(
OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor) OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *editor)
: m_client(client) : m_client(client)
, m_editorWidget(editor->editorWidget()) , 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_model.setSymbolStringifier(client->symbolStringifier());
m_proxyModel.setSourceModel(&m_model); m_proxyModel.setSourceModel(&m_model);

View File

@@ -60,10 +60,11 @@ IAssistProposal *LanguageClientQuickFixAssistProcessor::perform()
cursor.select(QTextCursor::LineUnderCursor); cursor.select(QTextCursor::LineUnderCursor);
Range range(cursor); Range range(cursor);
params.setRange(range); 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)); params.setTextDocument(TextDocumentIdentifier(uri));
CodeActionParams::CodeActionContext context; CodeActionParams::CodeActionContext context;
context.setDiagnostics(m_client->diagnosticsAt(uri, cursor)); context.setDiagnostics(m_client->diagnosticsAt(filePath, cursor));
params.setContext(context); params.setContext(context);
CodeActionRequest request(params); CodeActionRequest request(params);

View File

@@ -56,7 +56,9 @@ public:
} }
m_renameFilesCheckBox.setText(tr("Re&name %n files", nullptr, filesToRename.size())); m_renameFilesCheckBox.setText(tr("Re&name %n files", nullptr, filesToRename.size()));
const auto filesForUser = Utils::transform<QStringList>(filesToRename, 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.setToolTip(tr("Files:\n%1").arg(filesForUser.join('\n')));
m_renameFilesCheckBox.setVisible(true); m_renameFilesCheckBox.setVisible(true);
} }
@@ -69,7 +71,8 @@ private:
}; };
} // anonymous namespace } // anonymous namespace
SymbolSupport::SymbolSupport(Client *client) : m_client(client) SymbolSupport::SymbolSupport(Client *client)
: m_client(client)
{} {}
template<typename Request> template<typename Request>
@@ -104,16 +107,17 @@ static void sendTextDocumentPositionParamsRequest(Client *client,
static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response, static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &response,
Utils::LinkHandler callback, 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::optional<GotoResult> result = response.result()) {
if (std::holds_alternative<std::nullptr_t>(*result)) { if (std::holds_alternative<std::nullptr_t>(*result)) {
callback({}); callback({});
} else if (auto ploc = std::get_if<Location>(&*result)) { } 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)) { } else if (auto plloc = std::get_if<QList<Location>>(&*result)) {
if (!plloc->isEmpty()) if (!plloc->isEmpty())
callback(linkUnderCursor.value_or(plloc->value(0).toLink())); callback(linkUnderCursor.value_or(plloc->value(0).toLink(client->hostPathMapper())));
else else
callback({}); callback({});
} }
@@ -123,9 +127,10 @@ static void handleGotoDefinitionResponse(const GotoDefinitionRequest::Response &
} }
static TextDocumentPositionParams generateDocPosParams(TextEditor::TextDocument *document, 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 TextDocumentIdentifier documentId(uri);
const Position pos(cursor); const Position pos(cursor);
return TextDocumentPositionParams(documentId, pos); return TextDocumentPositionParams(documentId, pos);
@@ -138,7 +143,7 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
{ {
if (!m_client->reachable()) if (!m_client->reachable())
return; return;
GotoDefinitionRequest request(generateDocPosParams(document, cursor)); GotoDefinitionRequest request(generateDocPosParams(document, cursor, m_client));
std::optional<Utils::Link> linkUnderCursor; std::optional<Utils::Link> linkUnderCursor;
if (!resolveTarget) { if (!resolveTarget) {
QTextCursor linkCursor = cursor; QTextCursor linkCursor = cursor;
@@ -150,16 +155,15 @@ void SymbolSupport::findLinkAt(TextEditor::TextDocument *document,
link.linkTextEnd = linkCursor.selectionEnd(); link.linkTextEnd = linkCursor.selectionEnd();
linkUnderCursor = link; linkUnderCursor = link;
} }
request.setResponseCallback( request.setResponseCallback([callback, linkUnderCursor, client = m_client](
[callback, linkUnderCursor](const GotoDefinitionRequest::Response &response) { const GotoDefinitionRequest::Response &response) {
handleGotoDefinitionResponse(response, callback, linkUnderCursor); handleGotoDefinitionResponse(response, callback, linkUnderCursor, client);
}); });
sendTextDocumentPositionParamsRequest(m_client, sendTextDocumentPositionParamsRequest(m_client,
request, request,
m_client->dynamicCapabilities(), m_client->dynamicCapabilities(),
m_client->capabilities()); m_client->capabilities());
} }
bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const bool SymbolSupport::supportsFindUsages(TextEditor::TextDocument *document) const
@@ -212,9 +216,9 @@ QStringList SymbolSupport::getFileContents(const Utils::FilePath &filePath)
} }
QList<Core::SearchResultItem> generateSearchResultItems( QList<Core::SearchResultItem> generateSearchResultItems(
const QMap<Utils::FilePath, QList<ItemData>> &rangesInDocument, const QMap<Utils::FilePath, QList<ItemData>> &rangesInDocument,
Core::SearchResult *search = nullptr, Core::SearchResult *search = nullptr,
bool limitToProjects = false) bool limitToProjects = false)
{ {
QList<Core::SearchResultItem> result; QList<Core::SearchResultItem> result;
const bool renaming = search && search->supportsReplace(); const bool renaming = search && search->supportsReplace();
@@ -232,11 +236,11 @@ QList<Core::SearchResultItem> generateSearchResultItems(
item.setFilePath(filePath); item.setFilePath(filePath);
item.setUseTextEditorFont(true); item.setUseTextEditorFont(true);
if (renaming && limitToProjects) { if (renaming && limitToProjects) {
const bool fileBelongsToProject const bool fileBelongsToProject = ProjectExplorer::SessionManager::projectForFile(
= ProjectExplorer::SessionManager::projectForFile(filePath); filePath);
item.setSelectForReplacement(fileBelongsToProject); item.setSelectForReplacement(fileBelongsToProject);
if (fileBelongsToProject && filePath.baseName().compare(oldSymbolName, if (fileBelongsToProject
Qt::CaseInsensitive) == 0) { && filePath.baseName().compare(oldSymbolName, Qt::CaseInsensitive) == 0) {
fileRenameCandidates << filePath; fileRenameCandidates << filePath;
} }
} }
@@ -260,13 +264,13 @@ QList<Core::SearchResultItem> generateSearchResultItems(
} }
QList<Core::SearchResultItem> generateSearchResultItems( QList<Core::SearchResultItem> generateSearchResultItems(
const LanguageClientArray<Location> &locations) const LanguageClientArray<Location> &locations, const DocumentUri::PathMapper &pathMapper)
{ {
if (locations.isNull()) if (locations.isNull())
return {}; return {};
QMap<Utils::FilePath, QList<ItemData>> rangesInDocument; QMap<Utils::FilePath, QList<ItemData>> rangesInDocument;
for (const Location &location : locations.toList()) for (const Location &location : locations.toList())
rangesInDocument[location.uri().toFilePath()] rangesInDocument[location.uri().toFilePath(pathMapper)]
<< ItemData{SymbolSupport::convertRange(location.range()), {}}; << ItemData{SymbolSupport::convertRange(location.range()), {}};
return generateSearchResultItems(rangesInDocument); return generateSearchResultItems(rangesInDocument);
} }
@@ -284,7 +288,8 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re
if (result) { if (result) {
Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch(
tr("Find References with %1 for:").arg(m_client->name()), "", wordUnderCursor); 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) { connect(search, &Core::SearchResult::activated, [](const Core::SearchResultItem &item) {
Core::EditorManager::openEditorAtSearchResult(item); Core::EditorManager::openEditorAtSearchResult(item);
}); });
@@ -293,18 +298,19 @@ void SymbolSupport::handleFindReferencesResponse(const FindReferencesRequest::Re
} }
} }
std::optional<MessageId> SymbolSupport::findUsages( std::optional<MessageId> SymbolSupport::findUsages(TextEditor::TextDocument *document,
TextEditor::TextDocument *document, const QTextCursor &cursor, const ResultHandler &handler) const QTextCursor &cursor,
const ResultHandler &handler)
{ {
if (!supportsFindUsages(document)) if (!supportsFindUsages(document))
return {}; return {};
ReferenceParams params(generateDocPosParams(document, cursor)); ReferenceParams params(generateDocPosParams(document, cursor, m_client));
params.setContext(ReferenceParams::ReferenceContext(true)); params.setContext(ReferenceParams::ReferenceContext(true));
FindReferencesRequest request(params); FindReferencesRequest request(params);
QTextCursor termCursor(cursor); QTextCursor termCursor(cursor);
termCursor.select(QTextCursor::WordUnderCursor); termCursor.select(QTextCursor::WordUnderCursor);
request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText(), handler]( request.setResponseCallback([this, wordUnderCursor = termCursor.selectedText(), handler](
const FindReferencesRequest::Response &response) { const FindReferencesRequest::Response &response) {
handleFindReferencesResponse(response, wordUnderCursor, handler); handleFindReferencesResponse(response, wordUnderCursor, handler);
}); });
@@ -355,10 +361,12 @@ bool SymbolSupport::supportsRename(TextEditor::TextDocument *document)
return LanguageClient::supportsRename(m_client, document, prepareSupported); return LanguageClient::supportsRename(m_client, document, prepareSupported);
} }
void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QTextCursor &cursor, void SymbolSupport::renameSymbol(TextEditor::TextDocument *document,
const QString &newSymbolName, bool preferLowerCaseFileNames) 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; QTextCursor tc = cursor;
tc.select(QTextCursor::WordUnderCursor); tc.select(QTextCursor::WordUnderCursor);
const QString oldSymbolName = tc.selectedText(); const QString oldSymbolName = tc.selectedText();
@@ -370,26 +378,25 @@ void SymbolSupport::renameSymbol(TextEditor::TextDocument *document, const QText
if (!LanguageClient::supportsRename(m_client, document, prepareSupported)) { if (!LanguageClient::supportsRename(m_client, document, prepareSupported)) {
const QString error = tr("Renaming is not supported with %1").arg(m_client->name()); const QString error = tr("Renaming is not supported with %1").arg(m_client->name());
createSearch(params, placeholder, {}, {})->finishSearch(true, error); createSearch(params, placeholder, {}, {})->finishSearch(true, error);
} else if (prepareSupported) { } else if (prepareSupported) {
requestPrepareRename(document, requestPrepareRename(document,
generateDocPosParams(document, cursor), generateDocPosParams(document, cursor, m_client),
placeholder, placeholder,
oldSymbolName, oldSymbolName,
preferLowerCaseFileNames); preferLowerCaseFileNames);
} else { } else {
startRenameSymbol(generateDocPosParams(document, cursor), startRenameSymbol(generateDocPosParams(document, cursor, m_client),
placeholder, placeholder,
oldSymbolName, oldSymbolName,
preferLowerCaseFileNames); preferLowerCaseFileNames);
} }
} }
void SymbolSupport::requestPrepareRename( void SymbolSupport::requestPrepareRename(TextEditor::TextDocument *document,
TextEditor::TextDocument *document, const TextDocumentPositionParams &params,
const TextDocumentPositionParams &params, const QString &placeholder,
const QString &placeholder, const QString &oldSymbolName,
const QString &oldSymbolName, bool preferLowerCaseFileNames)
bool preferLowerCaseFileNames)
{ {
PrepareRenameRequest request(params); PrepareRenameRequest request(params);
request.setResponseCallback([this, request.setResponseCallback([this,
@@ -409,7 +416,9 @@ void SymbolSupport::requestPrepareRename(
if (result.has_value()) { if (result.has_value()) {
if (std::holds_alternative<PlaceHolderResult>(*result)) { if (std::holds_alternative<PlaceHolderResult>(*result)) {
auto placeHolderResult = std::get<PlaceHolderResult>(*result); auto placeHolderResult = std::get<PlaceHolderResult>(*result);
startRenameSymbol(params, placeHolderResult.placeHolder(), oldSymbolName, startRenameSymbol(params,
placeHolderResult.placeHolder(),
oldSymbolName,
preferLowerCaseFileNames); preferLowerCaseFileNames);
} else if (std::holds_alternative<Range>(*result)) { } else if (std::holds_alternative<Range>(*result)) {
auto range = std::get<Range>(*result); auto range = std::get<Range>(*result);
@@ -425,10 +434,7 @@ void SymbolSupport::requestPrepareRename(
reportedSymbolName, reportedSymbolName,
preferLowerCaseFileNames); preferLowerCaseFileNames);
} else { } else {
startRenameSymbol(params, startRenameSymbol(params, placeholder, oldSymbolName, preferLowerCaseFileNames);
placeholder,
oldSymbolName,
preferLowerCaseFileNames);
} }
} }
} }
@@ -453,7 +459,8 @@ void SymbolSupport::requestRename(const TextDocumentPositionParams &positionPara
QList<Core::SearchResultItem> generateReplaceItems(const WorkspaceEdit &edits, QList<Core::SearchResultItem> generateReplaceItems(const WorkspaceEdit &edits,
Core::SearchResult *search, Core::SearchResult *search,
bool limitToProjects) bool limitToProjects,
const DocumentUri::PathMapper &pathMapper)
{ {
auto convertEdits = [](const QList<TextEdit> &edits) { auto convertEdits = [](const QList<TextEdit> &edits) {
return Utils::transform(edits, [](const TextEdit &edit) { 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>()); auto documentChanges = edits.documentChanges().value_or(QList<TextDocumentEdit>());
if (!documentChanges.isEmpty()) { if (!documentChanges.isEmpty()) {
for (const TextDocumentEdit &documentChange : std::as_const(documentChanges)) { for (const TextDocumentEdit &documentChange : std::as_const(documentChanges)) {
rangesInDocument[documentChange.textDocument().uri().toFilePath()] = convertEdits( rangesInDocument[documentChange.textDocument().uri().toFilePath(pathMapper)]
documentChange.edits()); = convertEdits(documentChange.edits());
} }
} else { } else {
auto changes = edits.changes().value_or(WorkspaceEdit::Changes()); auto changes = edits.changes().value_or(WorkspaceEdit::Changes());
for (auto it = changes.begin(), end = changes.end(); it != end; ++it) 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); return generateSearchResultItems(rangesInDocument, search, limitToProjects);
} }
Core::SearchResult *SymbolSupport::createSearch( Core::SearchResult *SymbolSupport::createSearch(const TextDocumentPositionParams &positionParams,
const TextDocumentPositionParams &positionParams, const QString &placeholder,
const QString &placeholder, const QString &oldSymbolName,
const QString &oldSymbolName, bool preferLowerCaseFileNames)
bool preferLowerCaseFileNames)
{ {
Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch( Core::SearchResult *search = Core::SearchResultWindow::instance()->startNewSearch(
tr("Find References with %1 for:").arg(m_client->name()), tr("Find References with %1 for:").arg(m_client->name()),
@@ -500,18 +506,22 @@ Core::SearchResult *SymbolSupport::createSearch(
search->setSearchAgainEnabled(true); search->setSearchAgainEnabled(true);
search->setReplaceEnabled(false); search->setReplaceEnabled(false);
}); });
connect(search, &Core::SearchResult::searchAgainRequested, this, connect(search,
&Core::SearchResult::searchAgainRequested,
this,
[this, positionParams, search]() { [this, positionParams, search]() {
search->restart(); search->restart();
requestRename(positionParams, search->textToReplace(), search); requestRename(positionParams, search->textToReplace(), search);
}); });
connect(search, &Core::SearchResult::replaceButtonClicked, this, connect(search,
&Core::SearchResult::replaceButtonClicked,
this,
[this, positionParams, search](const QString & /*replaceText*/, [this, positionParams, search](const QString & /*replaceText*/,
const QList<Core::SearchResultItem> &checkedItems) { const QList<Core::SearchResultItem> &checkedItems) {
applyRename(checkedItems, search); 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->restart(); // clears potential current results
search->finishSearch(true, tr("%1 is not reachable anymore.").arg(clientName)); 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, void SymbolSupport::startRenameSymbol(const TextDocumentPositionParams &positionParams,
const QString &placeholder, const QString &oldSymbolName, const QString &placeholder,
const QString &oldSymbolName,
bool preferLowerCaseFileNames) bool preferLowerCaseFileNames)
{ {
requestRename(positionParams, placeholder, createSearch( requestRename(positionParams,
positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames)); placeholder,
createSearch(positionParams, placeholder, oldSymbolName, preferLowerCaseFileNames));
} }
void SymbolSupport::handleRenameResponse(Core::SearchResult *search, void SymbolSupport::handleRenameResponse(Core::SearchResult *search,
@@ -539,7 +551,10 @@ void SymbolSupport::handleRenameResponse(Core::SearchResult *search,
const std::optional<WorkspaceEdit> &edits = response.result(); const std::optional<WorkspaceEdit> &edits = response.result();
if (edits.has_value()) { if (edits.has_value()) {
search->addResults(generateReplaceItems(*edits, search, m_limitRenamingToProjects), search->addResults(generateReplaceItems(*edits,
search,
m_limitRenamingToProjects,
m_client->hostPathMapper()),
Core::SearchResult::AddOrdered); Core::SearchResult::AddOrdered);
qobject_cast<ReplaceWidget *>(search->additionalReplaceWidget())->showLabel(false); qobject_cast<ReplaceWidget *>(search->additionalReplaceWidget())->showLabel(false);
search->setReplaceEnabled(true); search->setReplaceEnabled(true);
@@ -554,22 +569,21 @@ void SymbolSupport::applyRename(const QList<Core::SearchResultItem> &checkedItem
Core::SearchResult *search) Core::SearchResult *search)
{ {
QSet<Utils::FilePath> affectedNonOpenFilePaths; QSet<Utils::FilePath> affectedNonOpenFilePaths;
QMap<DocumentUri, QList<TextEdit>> editsForDocuments; QMap<Utils::FilePath, QList<TextEdit>> editsForDocuments;
for (const Core::SearchResultItem &item : checkedItems) { for (const Core::SearchResultItem &item : checkedItems) {
const auto filePath = Utils::FilePath::fromString(item.path().value(0)); const auto filePath = Utils::FilePath::fromString(item.path().value(0));
if (!m_client->documentForFilePath(filePath)) if (!m_client->documentForFilePath(filePath))
affectedNonOpenFilePaths << filePath; affectedNonOpenFilePaths << filePath;
TextEdit edit(item.userData().toJsonObject()); TextEdit edit(item.userData().toJsonObject());
if (edit.isValid()) if (edit.isValid())
editsForDocuments[DocumentUri::fromFilePath(filePath)] << edit; editsForDocuments[filePath] << edit;
} }
for (auto it = editsForDocuments.begin(), end = editsForDocuments.end(); it != end; ++it) for (auto it = editsForDocuments.begin(), end = editsForDocuments.end(); it != end; ++it)
applyTextEdits(m_client, it.key(), it.value()); applyTextEdits(m_client, it.key(), it.value());
if (!affectedNonOpenFilePaths.isEmpty()) { if (!affectedNonOpenFilePaths.isEmpty()) {
Core::DocumentManager::notifyFilesChangedInternally( Core::DocumentManager::notifyFilesChangedInternally(Utils::toList(affectedNonOpenFilePaths));
Utils::toList(affectedNonOpenFilePaths));
} }
const auto extraWidget = qobject_cast<ReplaceWidget *>(search->additionalReplaceWidget()); 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(); const QVariantList userData = search->userData().toList();
QTC_ASSERT(userData.size() == 3, return); QTC_ASSERT(userData.size() == 3, return);
const Utils::FilePaths filesToRename = Utils::transform(userData.at(2).toStringList(), const Utils::FilePaths filesToRename = Utils::transform(userData.at(2).toStringList(),
[](const QString &f) { return Utils::FilePath::fromString(f); }); [](const QString &f) {
ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol( return Utils::FilePath::fromString(
userData.at(0).toString(), search->textToReplace(), f);
filesToRename, userData.at(1).toBool()); });
ProjectExplorer::ProjectExplorerPlugin::renameFilesForSymbol(userData.at(0).toString(),
search->textToReplace(),
filesToRename,
userData.at(1).toBool());
} }
Core::Search::TextRange SymbolSupport::convertRange(const Range &range) Core::Search::TextRange SymbolSupport::convertRange(const Range &range)

View File

@@ -62,7 +62,7 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit)
if (edits.isEmpty()) if (edits.isEmpty())
return true; return true;
const DocumentUri &uri = edit.textDocument().uri(); const DocumentUri &uri = edit.textDocument().uri();
const FilePath &filePath = uri.toFilePath(); const FilePath &filePath = client->serverUriToHostPath(uri);
LanguageClientValue<int> version = edit.textDocument().version(); LanguageClientValue<int> version = edit.textDocument().version();
if (!version.isNull() && version.value(0) < client->documentVersion(filePath)) if (!version.isNull() && version.value(0) < client->documentVersion(filePath))
return false; return false;
@@ -70,13 +70,20 @@ bool applyTextDocumentEdit(const Client *client, const TextDocumentEdit &edit)
} }
bool applyTextEdits(const Client *client, const DocumentUri &uri, const QList<TextEdit> &edits) 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()) if (edits.isEmpty())
return true; return true;
RefactoringChangesData * const backend = client->createRefactoringChangesBackend(); RefactoringChangesData * const backend = client->createRefactoringChangesBackend();
RefactoringChanges changes(backend); RefactoringChanges changes(backend);
RefactoringFilePtr file; RefactoringFilePtr file;
file = changes.file(uri.toFilePath()); file = changes.file(filePath);
file->setChangeSet(editsToChangeSet(edits, file->document())); file->setChangeSet(editsToChangeSet(edits, file->document()));
if (backend) { if (backend) {
for (const TextEdit &edit : edits) for (const TextEdit &edit : edits)
@@ -130,7 +137,7 @@ void updateCodeActionRefactoringMarker(Client *client,
const QList<CodeAction> &actions, const QList<CodeAction> &actions,
const DocumentUri &uri) const DocumentUri &uri)
{ {
TextDocument* doc = TextDocument::textDocumentForFilePath(uri.toFilePath()); TextDocument* doc = TextDocument::textDocumentForFilePath(client->serverUriToHostPath(uri));
if (!doc) if (!doc)
return; return;
const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc); const QVector<BaseTextEditor *> editors = BaseTextEditor::textEditorsForDocument(doc);

View File

@@ -32,6 +32,9 @@ applyTextDocumentEdit(const Client *client, const LanguageServerProtocol::TextDo
bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client, bool LANGUAGECLIENT_EXPORT applyTextEdits(const Client *client,
const LanguageServerProtocol::DocumentUri &uri, const LanguageServerProtocol::DocumentUri &uri,
const QList<LanguageServerProtocol::TextEdit> &edits); 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, void LANGUAGECLIENT_EXPORT applyTextEdit(TextEditor::TextDocumentManipulatorInterface &manipulator,
const LanguageServerProtocol::TextEdit &edit, const LanguageServerProtocol::TextEdit &edit,
bool newTextIsSnippet = false); bool newTextIsSnippet = false);

View File

@@ -9,9 +9,13 @@
#include "languageclientutils.h" #include "languageclientutils.h"
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <languageserverprotocol/lsptypes.h>
#include <languageserverprotocol/servercapabilities.h> #include <languageserverprotocol/servercapabilities.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <utils/fuzzymatcher.h> #include <utils/fuzzymatcher.h>
#include <utils/linecolumn.h> #include <utils/linecolumn.h>
@@ -43,6 +47,7 @@ void DocumentLocatorFilter::updateCurrentClient()
TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument(); TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument();
if (Client *client = LanguageClientManager::clientForDocument(document); if (Client *client = LanguageClientManager::clientForDocument(document);
client && (client->locatorsEnabled() || m_forced)) { client && (client->locatorsEnabled() || m_forced)) {
setEnabled(!m_forced); setEnabled(!m_forced);
if (m_symbolCache != client->documentSymbolCache()) { if (m_symbolCache != client->documentSymbolCache()) {
disconnect(m_updateSymbolsConnection); disconnect(m_updateSymbolsConnection);
@@ -52,12 +57,14 @@ void DocumentLocatorFilter::updateCurrentClient()
} }
m_resetSymbolsConnection = connect(document, &Core::IDocument::contentsChanged, m_resetSymbolsConnection = connect(document, &Core::IDocument::contentsChanged,
this, &DocumentLocatorFilter::resetSymbols); this, &DocumentLocatorFilter::resetSymbols);
m_currentUri = DocumentUri::fromFilePath(document->filePath()); m_currentUri = client->hostPathToServerUri(document->filePath());
m_pathMapper = client->hostPathMapper();
} else { } else {
disconnect(m_updateSymbolsConnection); disconnect(m_updateSymbolsConnection);
m_symbolCache.clear(); m_symbolCache.clear();
m_currentUri.clear(); m_currentUri.clear();
setEnabled(false); setEnabled(false);
m_pathMapper = DocumentUri::PathMapper();
} }
} }
@@ -78,7 +85,8 @@ void DocumentLocatorFilter::resetSymbols()
} }
static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
Core::ILocatorFilter *filter) Core::ILocatorFilter *filter,
DocumentUri::PathMapper pathMapper)
{ {
Core::LocatorFilterEntry entry; Core::LocatorFilterEntry entry;
entry.filter = filter; entry.filter = filter;
@@ -86,14 +94,14 @@ static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &in
if (std::optional<QString> container = info.containerName()) if (std::optional<QString> container = info.containerName())
entry.extraInfo = container.value_or(QString()); entry.extraInfo = container.value_or(QString());
entry.displayIcon = symbolIcon(info.kind()); entry.displayIcon = symbolIcon(info.kind());
entry.internalData = QVariant::fromValue(info.location().toLink()); entry.internalData = QVariant::fromValue(info.location().toLink(pathMapper));
return entry; return entry;
} }
Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info) 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( QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries(
@@ -203,8 +211,11 @@ void DocumentLocatorFilter::accept(const Core::LocatorFilterEntry &selection,
int * /*selectionLength*/) const int * /*selectionLength*/) const
{ {
if (selection.internalData.canConvert<Utils::LineColumn>()) { if (selection.internalData.canConvert<Utils::LineColumn>()) {
QTC_ASSERT(m_pathMapper, return);
auto lineColumn = qvariant_cast<Utils::LineColumn>(selection.internalData); 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); Core::EditorManager::openEditorAt(link, {}, Core::EditorManager::AllowExternalEditor);
} else if (selection.internalData.canConvert<Utils::Link>()) { } else if (selection.internalData.canConvert<Utils::Link>()) {
Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData), Core::EditorManager::openEditorAt(qvariant_cast<Utils::Link>(selection.internalData),
@@ -293,15 +304,14 @@ QList<Core::LocatorFilterEntry> WorkspaceLocatorFilter::matchesFor(
if (!m_filterKinds.isEmpty()) { if (!m_filterKinds.isEmpty()) {
m_results = Utils::filtered(m_results, [&](const SymbolInformation &info) { m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) {
return m_filterKinds.contains(SymbolKind(info.kind())); return m_filterKinds.contains(SymbolKind(info.symbol.kind()));
}); });
} }
return Utils::transform(m_results, auto generateEntry = [this](const SymbolInfoWithPathMapper &info) {
[this](const SymbolInformation &info) { return generateLocatorEntry(info.symbol, this, info.mapper);
return generateLocatorEntry(info, this); };
}) return Utils::transform(m_results, generateEntry).toList();
.toList();
} }
void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection, void WorkspaceLocatorFilter::accept(const Core::LocatorFilterEntry &selection,
@@ -322,7 +332,10 @@ void WorkspaceLocatorFilter::handleResponse(Client *client,
m_pendingRequests.remove(client); m_pendingRequests.remove(client);
auto result = response.result().value_or(LanguageClientArray<SymbolInformation>()); auto result = response.result().value_or(LanguageClientArray<SymbolInformation>());
if (!result.isNull()) 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()) if (m_pendingRequests.isEmpty())
emit allRequestsFinished(QPrivateSignal()); emit allRequestsFinished(QPrivateSignal());
} }

View File

@@ -7,8 +7,9 @@
#include "languageclient_global.h" #include "languageclient_global.h"
#include <coreplugin/locator/ilocatorfilter.h> #include <coreplugin/locator/ilocatorfilter.h>
#include <languageserverprotocol/lsptypes.h>
#include <languageserverprotocol/languagefeatures.h> #include <languageserverprotocol/languagefeatures.h>
#include <languageserverprotocol/lsptypes.h>
#include <languageserverprotocol/workspace.h> #include <languageserverprotocol/workspace.h>
#include <QPointer> #include <QPointer>
@@ -67,6 +68,7 @@ private:
QMetaObject::Connection m_updateSymbolsConnection; QMetaObject::Connection m_updateSymbolsConnection;
QMetaObject::Connection m_resetSymbolsConnection; QMetaObject::Connection m_resetSymbolsConnection;
std::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols; std::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper;
bool m_forced = false; bool m_forced = false;
}; };
@@ -101,8 +103,15 @@ private:
const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response);
QMutex m_mutex; QMutex m_mutex;
struct SymbolInfoWithPathMapper
{
LanguageServerProtocol::SymbolInformation symbol;
LanguageServerProtocol::DocumentUri::PathMapper mapper;
};
QMap<Client *, LanguageServerProtocol::MessageId> m_pendingRequests; QMap<Client *, LanguageServerProtocol::MessageId> m_pendingRequests;
QVector<LanguageServerProtocol::SymbolInformation> m_results; QVector<SymbolInfoWithPathMapper> m_results;
QVector<LanguageServerProtocol::SymbolKind> m_filterKinds; QVector<LanguageServerProtocol::SymbolKind> m_filterKinds;
qint64 m_maxResultCount = 0; qint64 m_maxResultCount = 0;
}; };

View File

@@ -60,7 +60,7 @@ void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *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(m_client->hostPathToServerUri(filePath));
auto responseCallback = [this, auto responseCallback = [this,
remainingRerequests, remainingRerequests,
filePath, filePath,
@@ -128,7 +128,7 @@ void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument,
if (documentVersion == versionedToken.version) if (documentVersion == versionedToken.version)
return; return;
SemanticTokensDeltaParams params; SemanticTokensDeltaParams params;
params.setTextDocument(TextDocumentIdentifier(DocumentUri::fromFilePath(filePath))); params.setTextDocument(TextDocumentIdentifier(m_client->hostPathToServerUri(filePath)));
params.setPreviousResultId(previousResultId); params.setPreviousResultId(previousResultId);
SemanticTokensFullDeltaRequest request(params); SemanticTokensFullDeltaRequest request(params);
request.setResponseCallback( request.setResponseCallback(

View File

@@ -213,7 +213,7 @@ void PyLSClient::openDocument(TextEditor::TextDocument *document)
const FilePath workspacePath = documentPath.parentDir(); const FilePath workspacePath = documentPath.parentDir();
if (!m_extraWorkspaceDirs.contains(workspacePath)) { if (!m_extraWorkspaceDirs.contains(workspacePath)) {
WorkspaceFoldersChangeEvent event; WorkspaceFoldersChangeEvent event;
event.setAdded({WorkSpaceFolder(DocumentUri::fromFilePath(workspacePath), event.setAdded({WorkSpaceFolder(hostPathToServerUri(workspacePath),
workspacePath.fileName())}); workspacePath.fileName())});
DidChangeWorkspaceFoldersParams params; DidChangeWorkspaceFoldersParams params;
params.setEvent(event); params.setEvent(event);

View File

@@ -476,7 +476,7 @@ void tst_LanguageServerProtocol::documentUri_data()
QTest::newRow("home dir") QTest::newRow("home dir")
<< DocumentUri::fromFilePath(Utils::FilePath::fromString(QDir::homePath())) << DocumentUri::fromFilePath(Utils::FilePath::fromString(QDir::homePath()), [](auto in){ return in;})
<< true << true
<< Utils::FilePath::fromUserInput(QDir::homePath()) << Utils::FilePath::fromUserInput(QDir::homePath())
<< QString(filePrefix + QDir::homePath()); << QString(filePrefix + QDir::homePath());
@@ -484,7 +484,7 @@ void tst_LanguageServerProtocol::documentUri_data()
const QString argv0 = QFileInfo(qApp->arguments().first()).absoluteFilePath(); const QString argv0 = QFileInfo(qApp->arguments().first()).absoluteFilePath();
const auto argv0FileName = Utils::FilePath::fromUserInput(argv0); const auto argv0FileName = Utils::FilePath::fromUserInput(argv0);
QTest::newRow("argv0 file name") QTest::newRow("argv0 file name")
<< DocumentUri::fromFilePath(argv0FileName) << DocumentUri::fromFilePath(argv0FileName, [](auto in){ return in;})
<< true << true
<< argv0FileName << argv0FileName
<< QString(filePrefix + QDir::fromNativeSeparators(argv0)); << QString(filePrefix + QDir::fromNativeSeparators(argv0));
@@ -514,7 +514,7 @@ void tst_LanguageServerProtocol::documentUri()
QFETCH(QString, string); QFETCH(QString, string);
QCOMPARE(uri.isValid(), isValid); QCOMPARE(uri.isValid(), isValid);
QCOMPARE(uri.toFilePath(), fileName); QCOMPARE(uri.toFilePath([](auto in){ return in;}), fileName);
QCOMPARE(uri.toString(), string); QCOMPARE(uri.toString(), string);
} }