From 17b769851ffc3722090d34b20e01e88510eec55f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felici=C3=A1n=20N=C3=A9meth?= Date: Mon, 18 Nov 2019 16:24:06 +0100 Subject: [PATCH] Support the 'reference' codeActionKind https://github.com/joaotavora/eglot/issues/302#issuecomment-550225329 --- src/messages/initialize.cc | 2 +- src/messages/textDocument_code.cc | 142 ++++++++++++++++++++++-------- 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 17a0d56a..8f511014 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -70,7 +70,7 @@ struct ServerCap { bool documentSymbolProvider = true; bool workspaceSymbolProvider = true; struct CodeActionOptions { - std::vector codeActionKinds = {"quickfix"}; + std::vector codeActionKinds = {"quickfix", "reference"}; } codeActionProvider; struct CodeLensOptions { bool resolveProvider = false; diff --git a/src/messages/textDocument_code.cc b/src/messages/textDocument_code.cc index a205f05d..e3b41851 100644 --- a/src/messages/textDocument_code.cc +++ b/src/messages/textDocument_code.cc @@ -14,49 +14,117 @@ namespace ccls { namespace { +struct Command { + std::string title; + std::string command; + std::vector arguments; +}; struct CodeAction { std::string title; - const char *kind = "quickfix"; + std::string kind; 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 std::string toString(T &v) { + rapidjson::StringBuffer output; + rapidjson::Writer writer(output); + JsonWriter json_writer(&writer); + reflect(json_writer, v); + return output.GetString(); +} } // namespace template bool vec_has(const std::vector &vec, const T &key) { return std::find(std::begin(vec), std::end(vec), key) != std::end(vec); } +bool should_send_action(std::vector available_kinds, + std::vector 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, ReplyOnce &reply) { WorkingFile *wf = findOrFail(param.textDocument.uri.getPath(), reply).second; if (!wf) return; - std::vector only = param.context.only; + auto available_kinds = g_config->client.codeActionKind; + std::vector requested_kinds = param.context.only; std::vector result; - if (!only.empty() && !vec_has(only, std::string("quickfix"))) { - reply(result); - return; + + if (should_send_action(available_kinds, requested_kinds, "quickfix")) { + std::vector 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"))) { - reply(result); - return; - } - std::vector 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); - }))) { + + if (should_send_action(available_kinds, requested_kinds, "reference")) { + auto add = [&, param = param] ( + const char *title, const char *command_name, + const bool callee=false, const char *dir="", + const bool derived=false, int kind=0) { CodeAction &cmd = result.emplace_back(); - cmd.title = "FixIt: " + diag.message; - auto &edit = cmd.edit.documentChanges.emplace_back(); - edit.textDocument.uri = param.textDocument.uri; - edit.textDocument.version = wf->version; - edit.edits = diag.fixits_; - } + ReferenceCommand rcmd; + rcmd.textDocument = param.textDocument; + rcmd.position = param.range.start; + rcmd.callee = callee; + 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); } @@ -66,27 +134,13 @@ struct Cmd_xref { Kind kind; std::string field; }; -struct Command { - std::string title; - std::string command; - std::vector arguments; -}; struct CodeLens { lsRange range; std::optional command; }; REFLECT_STRUCT(Cmd_xref, usr, kind, field); -REFLECT_STRUCT(Command, title, command, arguments); REFLECT_STRUCT(CodeLens, range, command); -template std::string toString(T &v) { - rapidjson::StringBuffer output; - rapidjson::Writer writer(output); - JsonWriter json_writer(&writer); - reflect(json_writer, v); - return output.GetString(); -} - struct CommonCodeLensParams { std::vector *result; DB *db; @@ -230,6 +284,16 @@ void MessageHandler::workspace_executeCommand(JsonReader &reader, break; } 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