1414
1515namespace ccls {
1616namespace {
17+ struct Command {
18+ std::string title;
19+ std::string command;
20+ std::vector<std::string> arguments;
21+ };
1722struct 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
2550template <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+
2966void MessageHandler::textDocument_codeAction (CodeActionParam ¶m,
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- };
74137struct CodeLens {
75138 lsRange range;
76139 std::optional<Command> command;
77140};
78141REFLECT_STRUCT (Cmd_xref, usr, kind, field);
79- REFLECT_STRUCT (Command, title, command, arguments);
80142REFLECT_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-
90144struct 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