mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-26 09:31:59 +00:00
Support the 'reference' codeActionKind
https://github.com/joaotavora/eglot/issues/302#issuecomment-550225329
This commit is contained in:
parent
8b4d0fc055
commit
17b769851f
@ -70,7 +70,7 @@ struct ServerCap {
|
|||||||
bool documentSymbolProvider = true;
|
bool documentSymbolProvider = true;
|
||||||
bool workspaceSymbolProvider = true;
|
bool workspaceSymbolProvider = true;
|
||||||
struct CodeActionOptions {
|
struct CodeActionOptions {
|
||||||
std::vector<const char *> codeActionKinds = {"quickfix"};
|
std::vector<const char *> codeActionKinds = {"quickfix", "reference"};
|
||||||
} codeActionProvider;
|
} codeActionProvider;
|
||||||
struct CodeLensOptions {
|
struct CodeLensOptions {
|
||||||
bool resolveProvider = false;
|
bool resolveProvider = false;
|
||||||
|
@ -14,49 +14,117 @@
|
|||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
namespace {
|
namespace {
|
||||||
|
struct Command {
|
||||||
|
std::string title;
|
||||||
|
std::string command;
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
};
|
||||||
struct CodeAction {
|
struct CodeAction {
|
||||||
std::string title;
|
std::string title;
|
||||||
const char *kind = "quickfix";
|
std::string kind;
|
||||||
WorkspaceEdit edit;
|
WorkspaceEdit edit;
|
||||||
|
Command command;
|
||||||
};
|
};
|
||||||
REFLECT_STRUCT(CodeAction, title, kind, edit);
|
struct ReferenceCommand {
|
||||||
|
TextDocumentIdentifier textDocument;
|
||||||
|
Position position;
|
||||||
|
bool callee;
|
||||||
|
std::string direction;
|
||||||
|
bool derived;
|
||||||
|
int kind;
|
||||||
|
};
|
||||||
|
REFLECT_STRUCT(Command, title, command, arguments);
|
||||||
|
REFLECT_STRUCT(CodeAction, title, kind, edit, command);
|
||||||
|
REFLECT_STRUCT(ReferenceCommand, textDocument, position,
|
||||||
|
callee, direction, derived, kind);
|
||||||
|
|
||||||
|
template <typename T> std::string toString(T &v) {
|
||||||
|
rapidjson::StringBuffer output;
|
||||||
|
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
|
||||||
|
JsonWriter json_writer(&writer);
|
||||||
|
reflect(json_writer, v);
|
||||||
|
return output.GetString();
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
template <typename T> bool vec_has(const std::vector<T> &vec, const T &key) {
|
template <typename T> bool vec_has(const std::vector<T> &vec, const T &key) {
|
||||||
return std::find(std::begin(vec), std::end(vec), key) != std::end(vec);
|
return std::find(std::begin(vec), std::end(vec), key) != std::end(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool should_send_action(std::vector<std::string> available_kinds,
|
||||||
|
std::vector<std::string> requested_kinds,
|
||||||
|
std::string kind) {
|
||||||
|
if (!requested_kinds.empty() && !vec_has(requested_kinds, kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!available_kinds.empty() && !vec_has(available_kinds, kind)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void MessageHandler::textDocument_codeAction(CodeActionParam ¶m,
|
void MessageHandler::textDocument_codeAction(CodeActionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
WorkingFile *wf = findOrFail(param.textDocument.uri.getPath(), reply).second;
|
WorkingFile *wf = findOrFail(param.textDocument.uri.getPath(), reply).second;
|
||||||
if (!wf)
|
if (!wf)
|
||||||
return;
|
return;
|
||||||
std::vector<std::string> only = param.context.only;
|
auto available_kinds = g_config->client.codeActionKind;
|
||||||
|
std::vector<std::string> requested_kinds = param.context.only;
|
||||||
std::vector<CodeAction> result;
|
std::vector<CodeAction> result;
|
||||||
if (!only.empty() && !vec_has(only, std::string("quickfix"))) {
|
|
||||||
reply(result);
|
if (should_send_action(available_kinds, requested_kinds, "quickfix")) {
|
||||||
return;
|
std::vector<Diagnostic> diagnostics;
|
||||||
|
wfiles->withLock([&]() { diagnostics = wf->diagnostics; });
|
||||||
|
for (Diagnostic &diag : diagnostics)
|
||||||
|
if (diag.fixits_.size() &&
|
||||||
|
(param.range.intersects(diag.range) ||
|
||||||
|
llvm::any_of(diag.fixits_, [&](const TextEdit &edit) {
|
||||||
|
return param.range.intersects(edit.range);
|
||||||
|
}))) {
|
||||||
|
CodeAction &cmd = result.emplace_back();
|
||||||
|
cmd.title = "FixIt: " + diag.message;
|
||||||
|
cmd.kind = "quickfix";
|
||||||
|
auto &edit = cmd.edit.documentChanges.emplace_back();
|
||||||
|
edit.textDocument.uri = param.textDocument.uri;
|
||||||
|
edit.textDocument.version = wf->version;
|
||||||
|
edit.edits = diag.fixits_;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
auto kinds = g_config->client.codeActionKind;
|
|
||||||
if (!kinds.empty() && !vec_has(kinds, std::string("quickfix"))) {
|
if (should_send_action(available_kinds, requested_kinds, "reference")) {
|
||||||
reply(result);
|
auto add = [&, param = param] (
|
||||||
return;
|
const char *title, const char *command_name,
|
||||||
}
|
const bool callee=false, const char *dir="",
|
||||||
std::vector<Diagnostic> diagnostics;
|
const bool derived=false, int kind=0) {
|
||||||
wfiles->withLock([&]() { diagnostics = wf->diagnostics; });
|
|
||||||
for (Diagnostic &diag : diagnostics)
|
|
||||||
if (diag.fixits_.size() &&
|
|
||||||
(param.range.intersects(diag.range) ||
|
|
||||||
llvm::any_of(diag.fixits_, [&](const TextEdit &edit) {
|
|
||||||
return param.range.intersects(edit.range);
|
|
||||||
}))) {
|
|
||||||
CodeAction &cmd = result.emplace_back();
|
CodeAction &cmd = result.emplace_back();
|
||||||
cmd.title = "FixIt: " + diag.message;
|
ReferenceCommand rcmd;
|
||||||
auto &edit = cmd.edit.documentChanges.emplace_back();
|
rcmd.textDocument = param.textDocument;
|
||||||
edit.textDocument.uri = param.textDocument.uri;
|
rcmd.position = param.range.start;
|
||||||
edit.textDocument.version = wf->version;
|
rcmd.callee = callee;
|
||||||
edit.edits = diag.fixits_;
|
rcmd.direction = dir;
|
||||||
}
|
rcmd.derived = derived;
|
||||||
|
rcmd.kind = kind;
|
||||||
|
cmd.title = title;
|
||||||
|
cmd.kind = "reference";
|
||||||
|
cmd.command.title = title;
|
||||||
|
cmd.command.command = command_name;
|
||||||
|
cmd.command.arguments.push_back(toString(rcmd));
|
||||||
|
};
|
||||||
|
|
||||||
|
add("call", "$ccls/call");
|
||||||
|
add("callee", "$ccls/call", true);
|
||||||
|
add("navigate-up", "$ccls/navigate", false, "U");
|
||||||
|
add("navigate-down", "$ccls/navigate", false, "D");
|
||||||
|
add("navigate-right", "$ccls/navigate", false, "R");
|
||||||
|
add("navigate-left", "$ccls/navigate", false, "L");
|
||||||
|
add("inheritance", "$ccls/inheritance");
|
||||||
|
add("inheritance-derived", "$ccls/inheritance", false, "", true);
|
||||||
|
add("member-var", "$ccls/member", false, "", 4);
|
||||||
|
add("member-fun", "$ccls/member", false, "", 3);
|
||||||
|
add("member-type", "$ccls/member", false, "", 2);
|
||||||
|
add("vars", "$ccls/vars");
|
||||||
|
}
|
||||||
|
|
||||||
reply(result);
|
reply(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,27 +134,13 @@ struct Cmd_xref {
|
|||||||
Kind kind;
|
Kind kind;
|
||||||
std::string field;
|
std::string field;
|
||||||
};
|
};
|
||||||
struct Command {
|
|
||||||
std::string title;
|
|
||||||
std::string command;
|
|
||||||
std::vector<std::string> arguments;
|
|
||||||
};
|
|
||||||
struct CodeLens {
|
struct CodeLens {
|
||||||
lsRange range;
|
lsRange range;
|
||||||
std::optional<Command> command;
|
std::optional<Command> command;
|
||||||
};
|
};
|
||||||
REFLECT_STRUCT(Cmd_xref, usr, kind, field);
|
REFLECT_STRUCT(Cmd_xref, usr, kind, field);
|
||||||
REFLECT_STRUCT(Command, title, command, arguments);
|
|
||||||
REFLECT_STRUCT(CodeLens, range, command);
|
REFLECT_STRUCT(CodeLens, range, command);
|
||||||
|
|
||||||
template <typename T> std::string toString(T &v) {
|
|
||||||
rapidjson::StringBuffer output;
|
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
|
|
||||||
JsonWriter json_writer(&writer);
|
|
||||||
reflect(json_writer, v);
|
|
||||||
return output.GetString();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CommonCodeLensParams {
|
struct CommonCodeLensParams {
|
||||||
std::vector<CodeLens> *result;
|
std::vector<CodeLens> *result;
|
||||||
DB *db;
|
DB *db;
|
||||||
@ -230,6 +284,16 @@ void MessageHandler::workspace_executeCommand(JsonReader &reader,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
reply(result);
|
reply(result);
|
||||||
|
} else if (param.command == "$ccls/call") {
|
||||||
|
ccls_call(json_reader, reply);
|
||||||
|
} else if (param.command == "$ccls/navigate") {
|
||||||
|
ccls_navigate(json_reader, reply);
|
||||||
|
} else if (param.command == "$ccls/inheritance") {
|
||||||
|
ccls_inheritance(json_reader, reply);
|
||||||
|
} else if (param.command == "$ccls/member") {
|
||||||
|
ccls_member(json_reader, reply);
|
||||||
|
} else if (param.command == "$ccls/vars") {
|
||||||
|
ccls_vars(json_reader, reply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace ccls
|
} // namespace ccls
|
||||||
|
Loading…
Reference in New Issue
Block a user