mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-22 07:35:08 +00:00
Add $ccls/navigate and improve textDocument/definition
This commit is contained in:
parent
d22e6402d9
commit
d864f969ad
@ -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
|
||||||
|
103
src/messages/ccls_navigate.cc
Normal file
103
src/messages/ccls_navigate.cc
Normal 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 ¶ms = 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
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user