Add $ccls/navigate and improve textDocument/definition

This commit is contained in:
Fangrui Song 2018-09-03 15:08:34 -07:00
parent d22e6402d9
commit d864f969ad
4 changed files with 112 additions and 4 deletions

View File

@ -216,6 +216,7 @@ target_sources(ccls PRIVATE
src/messages/ccls_freshenIndex.cc src/messages/ccls_freshenIndex.cc
src/messages/ccls_inheritanceHierarchy.cc src/messages/ccls_inheritanceHierarchy.cc
src/messages/ccls_memberHierarchy.cc src/messages/ccls_memberHierarchy.cc
src/messages/ccls_navigate.cc
src/messages/ccls_vars.cc src/messages/ccls_vars.cc
src/messages/exit.cc src/messages/exit.cc
src/messages/initialize.cc src/messages/initialize.cc

View File

@ -0,0 +1,103 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"
using namespace ccls;
namespace {
MethodType kMethodType = "$ccls/navigate";
struct In_CclsNavigate : public RequestInMessage {
MethodType GetMethodType() const override { return kMethodType; }
struct Params {
lsTextDocumentIdentifier textDocument;
lsPosition position;
std::string direction;
} params;
};
MAKE_REFLECT_STRUCT(In_CclsNavigate::Params, textDocument, position, direction);
MAKE_REFLECT_STRUCT(In_CclsNavigate, id, params);
REGISTER_IN_MESSAGE(In_CclsNavigate);
struct Handler_CclsNavigate : BaseMessageHandler<In_CclsNavigate> {
MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsNavigate *request) override {
auto &params = request->params;
QueryFile *file;
if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file))
return;
WorkingFile *wfile =
working_files->GetFileByFilename(file->def->path);
lsPosition ls_pos = request->params.position;
if (wfile && wfile->index_lines.size())
if (auto line = wfile->GetIndexPosFromBufferPos(
ls_pos.line, &ls_pos.character, false))
ls_pos.line = *line;
Position pos{(int16_t)ls_pos.line, (int16_t)ls_pos.character};
Maybe<Range> res;
switch (params.direction[0]) {
case 'D': {
Maybe<Range> parent;
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && sym.range.start <= pos && pos < sym.range.end &&
(!parent || parent->start < sym.range.start))
parent = sym.range;
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && pos < sym.range.start &&
(!parent || sym.range.end <= parent->end) &&
(!res || sym.range.start < res->start))
res = sym.range;
break;
}
case 'L':
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && sym.range.end <= pos &&
(!res || (res->end == sym.range.end ? sym.range.start < res->start
: res->end < sym.range.end)))
res = sym.range;
break;
case 'R': {
Maybe<Range> parent;
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && sym.range.start <= pos && pos < sym.range.end &&
(!parent || parent->start < sym.range.start))
parent = sym.range;
if (parent && parent->start.line == pos.line && pos < parent->end) {
pos = parent->end;
if (pos.column)
pos.column--;
}
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && pos < sym.range.start &&
(!res ||
(sym.range.start == res->start ? res->end < sym.range.end
: sym.range.start < res->start)))
res = sym.range;
break;
}
case 'U':
default:
for (auto [sym, refcnt] : file->outline2refcnt)
if (refcnt > 0 && sym.range.start < pos && pos < sym.range.end &&
(!res || res->start < sym.range.start))
res = sym.range;
break;
}
Out_LocationList out;
out.id = request->id;
if (res)
if (auto ls_range = GetLsRange(wfile, *res)) {
lsLocationEx &ls_loc = out.result.emplace_back();
ls_loc.uri = params.textDocument.uri;
ls_loc.range = *ls_range;
}
pipeline::WriteStdout(kMethodType, out);
}
};
REGISTER_MESSAGE_HANDLER(Handler_CclsNavigate);
} // namespace

View File

@ -63,14 +63,17 @@ struct Handler_TextDocumentDefinition
Out_TextDocumentDefinition out; Out_TextDocumentDefinition out;
out.id = request->id; out.id = request->id;
Maybe<Range> range;
Maybe<Use> on_def; Maybe<Use> on_def;
bool has_symbol = false;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
lsPosition &ls_pos = params.position; lsPosition &ls_pos = params.position;
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) { for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, ls_pos)) {
if (!range)
range = sym.range;
else if (!(*range == sym.range))
break;
// Found symbol. Return definition. // Found symbol. Return definition.
has_symbol = true;
// Special cases which are handled: // Special cases which are handled:
// - symbol has declaration but no definition (ie, pure virtual) // - symbol has declaration but no definition (ie, pure virtual)
@ -118,12 +121,12 @@ struct Handler_TextDocumentDefinition
lsLocationEx result; lsLocationEx result;
result.uri = lsDocumentUri::FromPath(include.resolved_path); result.uri = lsDocumentUri::FromPath(include.resolved_path);
out.result.push_back(result); out.result.push_back(result);
has_symbol = true; range = {{0, 0}, {0, 0}};
break; break;
} }
} }
// Find the best match of the identifier at point. // Find the best match of the identifier at point.
if (!has_symbol) { if (!range) {
lsPosition position = request->params.position; lsPosition position = request->params.position;
const std::string &buffer = wfile->buffer_content; const std::string &buffer = wfile->buffer_content;
std::string_view query = LexIdentifierAroundPos(position, buffer); std::string_view query = LexIdentifierAroundPos(position, buffer);

View File

@ -28,6 +28,7 @@ struct Position {
return line < o.line; return line < o.line;
return column < o.column; return column < o.column;
} }
bool operator<=(const Position &o) const { return !(o < *this); }
}; };
MAKE_HASHABLE(Position, t.line, t.column); MAKE_HASHABLE(Position, t.line, t.column);