Implement textDocument/documentLink

This commit is contained in:
Fangrui Song 2018-10-24 18:03:57 -07:00
parent 1d67a40ce8
commit 6e19a5964e
4 changed files with 119 additions and 127 deletions

View File

@ -222,8 +222,7 @@ target_sources(ccls PRIVATE
src/messages/textDocument_did.cc
src/messages/textDocument_foldingRange.cc
src/messages/textDocument_formatting.cc
src/messages/textDocument_documentHighlight.cc
src/messages/textDocument_documentSymbol.cc
src/messages/textDocument_document.cc
src/messages/textDocument_hover.cc
src/messages/textDocument_references.cc
src/messages/textDocument_rename.cc

View File

@ -74,12 +74,6 @@ struct lsDocumentOnTypeFormattingOptions {
MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, firstTriggerCharacter,
moreTriggerCharacter);
// Document link options
struct lsDocumentLinkOptions {
// Document links have a resolve provider as well.
bool resolveProvider = false;
};
MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, resolveProvider);
// Save options.
struct lsSaveOptions {
@ -144,34 +138,22 @@ struct lsServerCapabilities {
lsCompletionOptions completionProvider;
// The server provides signature help support.
lsSignatureHelpOptions signatureHelpProvider;
// The server provides goto definition support.
bool definitionProvider = true;
// The server provides Goto Type Definition support.
bool typeDefinitionProvider = true;
// The server provides Goto Implementation support.
bool implementationProvider = true;
// The server provides find references support.
bool referencesProvider = true;
// The server provides document highlight support.
bool documentHighlightProvider = true;
// The server provides document symbol support.
bool documentSymbolProvider = true;
// The server provides workspace symbol support.
bool workspaceSymbolProvider = true;
// The server provides code actions.
bool codeActionProvider = true;
// The server provides code lens.
lsCodeLensOptions codeLensProvider;
// The server provides document formatting.
bool documentFormattingProvider = true;
// The server provides document range formatting.
bool documentRangeFormattingProvider = true;
// The server provides document formatting on typing.
lsDocumentOnTypeFormattingOptions documentOnTypeFormattingProvider;
// The server provides rename support.
bool renameProvider = true;
// The server provides document link support.
lsDocumentLinkOptions documentLinkProvider;
struct DocumentLinkOptions {
bool resolveProvider = true;
} documentLinkProvider;
bool foldingRangeProvider = true;
// The server provides execute command support.
struct ExecuteCommandOptions {
@ -184,6 +166,7 @@ struct lsServerCapabilities {
} workspaceFolders;
} workspace;
};
MAKE_REFLECT_STRUCT(lsServerCapabilities::DocumentLinkOptions, resolveProvider);
MAKE_REFLECT_STRUCT(lsServerCapabilities::ExecuteCommandOptions, commands);
MAKE_REFLECT_STRUCT(lsServerCapabilities::Workspace::WorkspaceFolders,
supported, changeNotifications);

View File

@ -16,16 +16,116 @@ limitations under the License.
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"
using namespace ccls;
using namespace clang;
#include <algorithm>
MAKE_HASHABLE(SymbolIdx, t.usr, t.kind);
namespace ccls {
namespace {
MethodType kMethodType = "textDocument/documentSymbol";
MethodType documentHighlight = "textDocument/documentHighlight",
documentLink = "textDocument/documentLink",
documentSymbol = "textDocument/documentSymbol";
struct In_TextDocumentDocumentSymbol : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; }
struct lsDocumentHighlight {
enum Kind { Text = 1, Read = 2, Write = 3 };
lsRange range;
int kind = 1;
// ccls extension
Role role = Role::None;
bool operator<(const lsDocumentHighlight &o) const {
return !(range == o.range) ? range < o.range : kind < o.kind;
}
};
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role);
struct In_TextDocumentDocumentHighlight : public RequestMessage {
MethodType GetMethodType() const override { return documentHighlight; }
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentHighlight, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentDocumentHighlight);
struct Handler_TextDocumentDocumentHighlight
: BaseMessageHandler<In_TextDocumentDocumentHighlight> {
MethodType GetMethodType() const override { return documentHighlight; }
void Run(In_TextDocumentDocumentHighlight *request) override {
int file_id;
QueryFile *file;
if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file,
&file_id))
return;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
std::vector<lsDocumentHighlight> result;
std::vector<SymbolRef> syms =
FindSymbolsAtLocation(wfile, file, request->params.position, true);
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0)
continue;
Usr usr = sym.usr;
SymbolKind kind = sym.kind;
if (std::none_of(syms.begin(), syms.end(), [&](auto &sym1) {
return usr == sym1.usr && kind == sym1.kind;
}))
continue;
if (auto loc = GetLsLocation(db, working_files, sym, file_id)) {
lsDocumentHighlight highlight;
highlight.range = loc->range;
if (sym.role & Role::Write)
highlight.kind = lsDocumentHighlight::Write;
else if (sym.role & Role::Read)
highlight.kind = lsDocumentHighlight::Read;
else
highlight.kind = lsDocumentHighlight::Text;
highlight.role = sym.role;
result.push_back(highlight);
}
}
std::sort(result.begin(), result.end());
pipeline::Reply(request->id, result);
}
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
struct In_textDocumentDocumentLink : public RequestMessage {
MethodType GetMethodType() const override { return documentLink; }
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(In_textDocumentDocumentLink, id, params);
REGISTER_IN_MESSAGE(In_textDocumentDocumentLink);
struct lsDocumentLink {
lsRange range;
lsDocumentUri target;
};
MAKE_REFLECT_STRUCT(lsDocumentLink, range, target);
struct Handler_textDocumentDocumentLink
: BaseMessageHandler<In_textDocumentDocumentLink> {
MethodType GetMethodType() const override { return documentLink; }
void Run(In_textDocumentDocumentLink *request) override {
QueryFile *file;
if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file))
return;
std::vector<lsDocumentLink> result;
for (const IndexInclude &include : file->def->includes)
result.push_back({lsRange{{include.line, 0}, {include.line + 1, 0}},
lsDocumentUri::FromPath(include.resolved_path)});
pipeline::Reply(request->id, result);
}
};
REGISTER_MESSAGE_HANDLER(Handler_textDocumentDocumentLink);
struct In_textDocumentDocumentSymbol : public RequestMessage {
MethodType GetMethodType() const override { return documentSymbol; }
struct Params {
lsTextDocumentIdentifier textDocument;
// false: outline; true: all symbols
@ -35,10 +135,10 @@ struct In_TextDocumentDocumentSymbol : public RequestMessage {
int endLine = -1;
} params;
};
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol::Params, textDocument, all,
MAKE_REFLECT_STRUCT(In_textDocumentDocumentSymbol::Params, textDocument, all,
startLine, endLine);
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentDocumentSymbol);
MAKE_REFLECT_STRUCT(In_textDocumentDocumentSymbol, id, params);
REGISTER_IN_MESSAGE(In_textDocumentDocumentSymbol);
struct lsDocumentSymbol {
std::string name;
@ -68,10 +168,10 @@ bool Ignore(const QueryVar::Def *def) {
return !def || def->is_local();
}
struct Handler_TextDocumentDocumentSymbol
: BaseMessageHandler<In_TextDocumentDocumentSymbol> {
MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDocumentSymbol *request) override {
struct Handler_textDocumentDocumentSymbol
: BaseMessageHandler<In_textDocumentDocumentSymbol> {
MethodType GetMethodType() const override { return documentSymbol; }
void Run(In_textDocumentDocumentSymbol *request) override {
auto &params = request->params;
QueryFile *file;
@ -192,5 +292,6 @@ struct Handler_TextDocumentDocumentSymbol
}
}
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentSymbol);
REGISTER_MESSAGE_HANDLER(Handler_textDocumentDocumentSymbol);
} // namespace
} // namespace ccls

View File

@ -1,91 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"
#include <algorithm>
using namespace ccls;
namespace {
MethodType kMethodType = "textDocument/documentHighlight";
struct lsDocumentHighlight {
enum Kind { Text = 1, Read = 2, Write = 3 };
lsRange range;
int kind = 1;
// ccls extension
Role role = Role::None;
bool operator<(const lsDocumentHighlight &o) const {
return !(range == o.range) ? range < o.range : kind < o.kind;
}
};
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role);
struct In_TextDocumentDocumentHighlight : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentHighlight, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentDocumentHighlight);
struct Handler_TextDocumentDocumentHighlight
: BaseMessageHandler<In_TextDocumentDocumentHighlight> {
MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentDocumentHighlight *request) override {
int file_id;
QueryFile *file;
if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file,
&file_id))
return;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
std::vector<lsDocumentHighlight> result;
std::vector<SymbolRef> syms =
FindSymbolsAtLocation(wfile, file, request->params.position, true);
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0)
continue;
Usr usr = sym.usr;
SymbolKind kind = sym.kind;
if (std::none_of(syms.begin(), syms.end(), [&](auto &sym1) {
return usr == sym1.usr && kind == sym1.kind;
}))
continue;
if (auto loc = GetLsLocation(db, working_files, sym, file_id)) {
lsDocumentHighlight highlight;
highlight.range = loc->range;
if (sym.role & Role::Write)
highlight.kind = lsDocumentHighlight::Write;
else if (sym.role & Role::Read)
highlight.kind = lsDocumentHighlight::Read;
else
highlight.kind = lsDocumentHighlight::Text;
highlight.role = sym.role;
result.push_back(highlight);
}
}
std::sort(result.begin(), result.end());
pipeline::Reply(request->id, result);
}
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);
} // namespace