Skip to content

Commit adc3940

Browse files
committed
Support the 'reference' codeActionKind
joaotavora/eglot#302 (comment)
1 parent 9256b3d commit adc3940

File tree

2 files changed

+104
-40
lines changed

2 files changed

+104
-40
lines changed

src/messages/initialize.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ struct ServerCap {
6969
bool documentSymbolProvider = true;
7070
bool workspaceSymbolProvider = true;
7171
struct CodeActionOptions {
72-
std::vector<const char *> codeActionKinds = {"quickfix"};
72+
std::vector<const char *> codeActionKinds = {"quickfix", "reference"};
7373
} codeActionProvider;
7474
struct CodeLensOptions {
7575
bool resolveProvider = false;

src/messages/textDocument_code.cc

Lines changed: 103 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,49 +14,117 @@
1414

1515
namespace ccls {
1616
namespace {
17+
struct Command {
18+
std::string title;
19+
std::string command;
20+
std::vector<std::string> arguments;
21+
};
1722
struct CodeAction {
1823
std::string title;
19-
const char *kind = "quickfix";
24+
std::string kind;
2025
WorkspaceEdit edit;
26+
Command command;
27+
};
28+
struct ReferenceCommand {
29+
TextDocumentIdentifier textDocument;
30+
Position position;
31+
bool callee;
32+
std::string direction;
33+
bool derived;
34+
int kind;
2135
};
22-
REFLECT_STRUCT(CodeAction, title, kind, edit);
36+
REFLECT_STRUCT(Command, title, command, arguments);
37+
REFLECT_STRUCT(CodeAction, title, kind, edit, command);
38+
REFLECT_STRUCT(ReferenceCommand, textDocument, position,
39+
callee, direction, derived, kind);
40+
41+
template <typename T> std::string toString(T &v) {
42+
rapidjson::StringBuffer output;
43+
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
44+
JsonWriter json_writer(&writer);
45+
reflect(json_writer, v);
46+
return output.GetString();
47+
}
2348
} // namespace
2449

2550
template <typename T> bool vec_has(const std::vector<T> &vec, const T &key) {
2651
return std::find(std::begin(vec), std::end(vec), key) != std::end(vec);
2752
}
2853

54+
bool should_send_action(std::vector<std::string> available_kinds,
55+
std::vector<std::string> requested_kinds,
56+
std::string kind) {
57+
if (!requested_kinds.empty() && !vec_has(requested_kinds, kind)) {
58+
return false;
59+
}
60+
if (!available_kinds.empty() && !vec_has(available_kinds, kind)) {
61+
return false;
62+
}
63+
return true;
64+
}
65+
2966
void MessageHandler::textDocument_codeAction(CodeActionParam &param,
3067
ReplyOnce &reply) {
3168
WorkingFile *wf = findOrFail(param.textDocument.uri.getPath(), reply).second;
3269
if (!wf)
3370
return;
34-
std::vector<std::string> only = param.context.only;
71+
auto available_kinds = g_config->client.codeActionKind;
72+
std::vector<std::string> requested_kinds = param.context.only;
3573
std::vector<CodeAction> result;
36-
if (!only.empty() && !vec_has(only, std::string("quickfix"))) {
37-
reply(result);
38-
return;
39-
}
40-
auto kinds = g_config->client.codeActionKind;
41-
if (!kinds.empty() && !vec_has(kinds, std::string("quickfix"))) {
42-
reply(result);
43-
return;
74+
75+
if (should_send_action(available_kinds, requested_kinds, "quickfix")) {
76+
std::vector<Diagnostic> diagnostics;
77+
wfiles->withLock([&]() { diagnostics = wf->diagnostics; });
78+
for (Diagnostic &diag : diagnostics)
79+
if (diag.fixits_.size() &&
80+
(param.range.intersects(diag.range) ||
81+
llvm::any_of(diag.fixits_, [&](const TextEdit &edit) {
82+
return param.range.intersects(edit.range);
83+
}))) {
84+
CodeAction &cmd = result.emplace_back();
85+
cmd.title = "FixIt: " + diag.message;
86+
cmd.kind = "quickfix";
87+
auto &edit = cmd.edit.documentChanges.emplace_back();
88+
edit.textDocument.uri = param.textDocument.uri;
89+
edit.textDocument.version = wf->version;
90+
edit.edits = diag.fixits_;
91+
}
4492
}
45-
std::vector<Diagnostic> diagnostics;
46-
wfiles->withLock([&]() { diagnostics = wf->diagnostics; });
47-
for (Diagnostic &diag : diagnostics)
48-
if (diag.fixits_.size() &&
49-
(param.range.intersects(diag.range) ||
50-
llvm::any_of(diag.fixits_, [&](const TextEdit &edit) {
51-
return param.range.intersects(edit.range);
52-
}))) {
93+
94+
if (should_send_action(available_kinds, requested_kinds, "reference")) {
95+
auto add = [&, param = param] (
96+
const char *title, const char *command_name,
97+
const bool callee=false, const char *dir="",
98+
const bool derived=false, int kind=0) {
5399
CodeAction &cmd = result.emplace_back();
54-
cmd.title = "FixIt: " + diag.message;
55-
auto &edit = cmd.edit.documentChanges.emplace_back();
56-
edit.textDocument.uri = param.textDocument.uri;
57-
edit.textDocument.version = wf->version;
58-
edit.edits = diag.fixits_;
59-
}
100+
ReferenceCommand rcmd;
101+
rcmd.textDocument = param.textDocument;
102+
rcmd.position = param.range.start;
103+
rcmd.callee = callee;
104+
rcmd.direction = dir;
105+
rcmd.derived = derived;
106+
rcmd.kind = kind;
107+
cmd.title = title;
108+
cmd.kind = "reference";
109+
cmd.command.title = title;
110+
cmd.command.command = command_name;
111+
cmd.command.arguments.push_back(toString(rcmd));
112+
};
113+
114+
add("call", "$ccls/call");
115+
add("callee", "$ccls/call", true);
116+
add("navigate-up", "$ccls/navigate", false, "U");
117+
add("navigate-down", "$ccls/navigate", false, "D");
118+
add("navigate-right", "$ccls/navigate", false, "R");
119+
add("navigate-left", "$ccls/navigate", false, "L");
120+
add("inheritance", "$ccls/inheritance");
121+
add("inheritance-derived", "$ccls/inheritance", false, "", true);
122+
add("member-var", "$ccls/member", false, "", 4);
123+
add("member-fun", "$ccls/member", false, "", 3);
124+
add("member-type", "$ccls/member", false, "", 2);
125+
add("vars", "$ccls/vars");
126+
}
127+
60128
reply(result);
61129
}
62130

@@ -66,27 +134,13 @@ struct Cmd_xref {
66134
Kind kind;
67135
std::string field;
68136
};
69-
struct Command {
70-
std::string title;
71-
std::string command;
72-
std::vector<std::string> arguments;
73-
};
74137
struct CodeLens {
75138
lsRange range;
76139
std::optional<Command> command;
77140
};
78141
REFLECT_STRUCT(Cmd_xref, usr, kind, field);
79-
REFLECT_STRUCT(Command, title, command, arguments);
80142
REFLECT_STRUCT(CodeLens, range, command);
81143

82-
template <typename T> std::string toString(T &v) {
83-
rapidjson::StringBuffer output;
84-
rapidjson::Writer<rapidjson::StringBuffer> writer(output);
85-
JsonWriter json_writer(&writer);
86-
reflect(json_writer, v);
87-
return output.GetString();
88-
}
89-
90144
struct CommonCodeLensParams {
91145
std::vector<CodeLens> *result;
92146
DB *db;
@@ -230,6 +284,16 @@ void MessageHandler::workspace_executeCommand(JsonReader &reader,
230284
break;
231285
}
232286
reply(result);
287+
} else if (param.command == "$ccls/call") {
288+
ccls_call(json_reader, reply);
289+
} else if (param.command == "$ccls/navigate") {
290+
ccls_navigate(json_reader, reply);
291+
} else if (param.command == "$ccls/inheritance") {
292+
ccls_inheritance(json_reader, reply);
293+
} else if (param.command == "$ccls/member") {
294+
ccls_member(json_reader, reply);
295+
} else if (param.command == "$ccls/vars") {
296+
ccls_vars(json_reader, reply);
233297
}
234298
}
235299
} // namespace ccls

0 commit comments

Comments
 (0)