Revamp codeLens & codeAction

b.ref: references of bases
d.ref: references of derived
when b.ref > 0, don't display 0 ref or x bases
This commit is contained in:
Fangrui Song 2018-09-29 01:10:56 -07:00
parent d4871207ed
commit da704521b5
6 changed files with 199 additions and 321 deletions

View File

@ -91,6 +91,8 @@ struct lsResponseError {
void Write(Writer &visitor); void Write(Writer &visitor);
}; };
constexpr std::string_view ccls_xref("ccls.xref");
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -205,43 +207,6 @@ struct lsLocationEx : lsLocation {
}; };
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role); MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
template <typename T> struct lsCommand {
// Title of the command (ie, 'save')
std::string title;
// Actual command identifier.
std::string command;
// Arguments to run the command with.
// **NOTE** This must be serialized as an array. Use
// MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
T arguments;
};
template <typename TVisitor, typename T>
void Reflect(TVisitor &visitor, lsCommand<T> &value) {
REFLECT_MEMBER_START();
REFLECT_MEMBER(title);
REFLECT_MEMBER(command);
REFLECT_MEMBER(arguments);
REFLECT_MEMBER_END();
}
template <typename TData, typename TCommandArguments> struct lsCodeLens {
// The range in which this code lens is valid. Should only span a single line.
lsRange range;
// The command this code lens represents.
std::optional<lsCommand<TCommandArguments>> command;
// A data entry field that is preserved on a code lens item between
// a code lens and a code lens resolve request.
TData data;
};
template <typename TVisitor, typename TData, typename TCommandArguments>
void Reflect(TVisitor &visitor, lsCodeLens<TData, TCommandArguments> &value) {
REFLECT_MEMBER_START();
REFLECT_MEMBER(range);
REFLECT_MEMBER(command);
REFLECT_MEMBER(data);
REFLECT_MEMBER_END();
}
struct lsTextDocumentIdentifier { struct lsTextDocumentIdentifier {
lsDocumentUri uri; lsDocumentUri uri;
}; };

View File

@ -1,36 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#pragma once
#include "lsp.h"
// codeAction
struct CommandArgs {
lsDocumentUri textDocumentUri;
std::vector<lsTextEdit> edits;
};
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(CommandArgs, textDocumentUri, edits);
// codeLens
struct lsCodeLensUserData {};
MAKE_REFLECT_EMPTY_STRUCT(lsCodeLensUserData);
struct lsCodeLensCommandArguments {
lsDocumentUri uri;
lsPosition position;
std::vector<lsLocation> locations;
};
MAKE_REFLECT_STRUCT(lsCodeLensCommandArguments, uri, position, locations)

View File

@ -81,13 +81,6 @@ struct lsDocumentLinkOptions {
}; };
MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, resolveProvider); MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, resolveProvider);
// Execute command options.
struct lsExecuteCommandOptions {
// The commands to be executed on the server
std::vector<std::string> commands;
};
MAKE_REFLECT_STRUCT(lsExecuteCommandOptions, commands);
// Save options. // Save options.
struct lsSaveOptions { struct lsSaveOptions {
// The client is supposed to include the content on save. // The client is supposed to include the content on save.
@ -180,8 +173,11 @@ struct lsServerCapabilities {
// The server provides document link support. // The server provides document link support.
lsDocumentLinkOptions documentLinkProvider; lsDocumentLinkOptions documentLinkProvider;
// The server provides execute command support. // The server provides execute command support.
lsExecuteCommandOptions executeCommandProvider; struct ExecuteCommandOptions {
std::vector<std::string> commands{std::string(ccls_xref)};
} executeCommandProvider;
}; };
MAKE_REFLECT_STRUCT(lsServerCapabilities::ExecuteCommandOptions, commands);
MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider, MAKE_REFLECT_STRUCT(lsServerCapabilities, textDocumentSync, hoverProvider,
completionProvider, signatureHelpProvider, completionProvider, signatureHelpProvider,
definitionProvider, implementationProvider, definitionProvider, implementationProvider,

View File

@ -18,12 +18,6 @@ limitations under the License.
#include "working_files.h" #include "working_files.h"
using namespace ccls; using namespace ccls;
struct CommandArgs {
lsDocumentUri textDocumentUri;
std::vector<lsTextEdit> edits;
};
MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(CommandArgs, textDocumentUri, edits);
namespace { namespace {
MethodType kMethodType = "textDocument/codeAction"; MethodType kMethodType = "textDocument/codeAction";
@ -53,10 +47,17 @@ MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction::lsCodeActionParams, textDocument,
MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentCodeAction, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentCodeAction); REGISTER_IN_MESSAGE(In_TextDocumentCodeAction);
struct lsCodeAction {
std::string title;
const char *kind = "quickfix";
lsWorkspaceEdit edit;
};
MAKE_REFLECT_STRUCT(lsCodeAction, title, kind, edit);
struct Out_TextDocumentCodeAction struct Out_TextDocumentCodeAction
: public lsOutMessage<Out_TextDocumentCodeAction> { : public lsOutMessage<Out_TextDocumentCodeAction> {
lsRequestId id; lsRequestId id;
std::vector<lsCommand<CommandArgs>> result; std::vector<lsCodeAction> result;
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
@ -76,12 +77,12 @@ struct Handler_TextDocumentCodeAction
working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; }); working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; });
for (lsDiagnostic &diag : diagnostics) for (lsDiagnostic &diag : diagnostics)
if (diag.fixits_.size()) { if (diag.fixits_.size()) {
lsCommand<CommandArgs> command; lsCodeAction &cmd = out.result.emplace_back();
command.title = "FixIt: " + diag.message; cmd.title = "FixIt: " + diag.message;
command.command = "ccls._applyFixIt"; auto &edit = cmd.edit.documentChanges.emplace_back();
command.arguments.textDocumentUri = params.textDocument.uri; edit.textDocument.uri = params.textDocument.uri;
command.arguments.edits = diag.fixits_; edit.textDocument.version = wfile->version;
out.result.push_back(command); edit.edits = diag.fixits_;
} }
pipeline::WriteStdout(kMethodType, out); pipeline::WriteStdout(kMethodType, out);
} }

View File

@ -13,21 +13,64 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
==============================================================================*/ ==============================================================================*/
#include "clang_complete.hh"
#include "lsp_code_action.h"
#include "message_handler.h" #include "message_handler.h"
#include "pipeline.hh" #include "pipeline.hh"
#include "query_utils.h" #include "query_utils.h"
using namespace ccls; #include "serializers/json.h"
#include <llvm/Support/FormatVariadic.h>
#include <unordered_set> #include <unordered_set>
namespace { using namespace ccls;
MethodType kMethodType = "textDocument/codeLens";
namespace {
const MethodType codeLens = "textDocument/codeLens",
executeCommand = "workspace/executeCommand";
struct lsCommand {
std::string title;
std::string command;
std::vector<std::string> arguments;
};
MAKE_REFLECT_STRUCT(lsCommand, title, command, arguments);
struct lsCodeLens {
lsRange range;
std::optional<lsCommand> command;
};
MAKE_REFLECT_STRUCT(lsCodeLens, range, command);
struct Cmd_xref {
Usr usr;
SymbolKind kind;
std::string field;
};
MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field);
struct Out_xref : public lsOutMessage<Out_xref> {
lsRequestId id;
std::vector<lsLocation> result;
};
MAKE_REFLECT_STRUCT(Out_xref, jsonrpc, id, result);
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 {
std::vector<lsCodeLens> *result;
DB *db;
WorkingFile *wfile;
};
using TCodeLens = lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>;
struct In_TextDocumentCodeLens : public RequestInMessage { struct In_TextDocumentCodeLens : public RequestInMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return codeLens; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
} params; } params;
@ -39,179 +82,85 @@ REGISTER_IN_MESSAGE(In_TextDocumentCodeLens);
struct Out_TextDocumentCodeLens struct Out_TextDocumentCodeLens
: public lsOutMessage<Out_TextDocumentCodeLens> { : public lsOutMessage<Out_TextDocumentCodeLens> {
lsRequestId id; lsRequestId id;
std::vector<lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>> std::vector<lsCodeLens> result;
result;
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
struct CommonCodeLensParams {
std::vector<TCodeLens> *result;
DB *db;
WorkingFiles *working_files;
WorkingFile *working_file;
};
Use OffsetStartColumn(Use use, int16_t offset) {
use.range.start.column += offset;
return use;
}
void AddCodeLens(const char *singular, const char *plural,
CommonCodeLensParams *common, Use use,
const std::vector<Use> &uses, bool force_display) {
TCodeLens code_lens;
std::optional<lsRange> range = GetLsRange(common->working_file, use.range);
if (!range)
return;
if (use.file_id < 0)
return;
code_lens.range = *range;
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
code_lens.command->command = "ccls.showReferences";
code_lens.command->arguments.uri = GetLsDocumentUri(common->db, use.file_id);
code_lens.command->arguments.position = code_lens.range.start;
// Add unique uses.
std::vector<lsLocation> unique_uses;
for (Use use1 : uses) {
if (auto ls_loc = GetLsLocation(common->db, common->working_files, use1))
unique_uses.push_back(*ls_loc);
}
code_lens.command->arguments.locations.assign(unique_uses.begin(),
unique_uses.end());
// User visible label
size_t num_usages = unique_uses.size();
code_lens.command->title = std::to_string(num_usages) + " ";
if (num_usages == 1)
code_lens.command->title += singular;
else
code_lens.command->title += plural;
if (force_display || unique_uses.size() > 0)
common->result->push_back(code_lens);
}
struct Handler_TextDocumentCodeLens struct Handler_TextDocumentCodeLens
: BaseMessageHandler<In_TextDocumentCodeLens> { : BaseMessageHandler<In_TextDocumentCodeLens> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return codeLens; }
void Run(In_TextDocumentCodeLens *request) override { void Run(In_TextDocumentCodeLens *request) override {
auto &params = request->params; auto &params = request->params;
Out_TextDocumentCodeLens out; Out_TextDocumentCodeLens out;
out.id = request->id; out.id = request->id;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
clang_complete->NotifyView(path);
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id, path, &file))
params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
CommonCodeLensParams common; auto Add = [&](const char *singular, Cmd_xref show, Use use, int num,
common.result = &out.result; bool force_display = false) {
common.db = db; if (!num && !force_display)
common.working_files = working_files; return;
common.working_file = working_files->GetFileByFilename(file->def->path); std::optional<lsRange> range = GetLsRange(wfile, use.range);
if (!range)
return;
lsCodeLens &code_lens = out.result.emplace_back();
code_lens.range = *range;
code_lens.command = lsCommand();
code_lens.command->command = std::string(ccls_xref);
bool plural = num > 1 && singular[strlen(singular) - 1] != 'd';
code_lens.command->title =
llvm::formatv("{0} {1}{2}", num, singular, plural ? "s" : "").str();
code_lens.command->arguments.push_back(ToString(show));
};
auto ToSpell = [&](Use use) {
Maybe<Use> def = GetDefinitionSpell(db, use);
if (def && def->file_id == use.file_id &&
def->range.start.line == use.range.start.line)
return *def;
return use;
};
std::unordered_set<Range> seen; std::unordered_set<Range> seen;
for (auto [sym, refcnt] : file->outline2refcnt) { for (auto [sym, refcnt] : file->outline2refcnt) {
if (refcnt <= 0 || !seen.insert(sym.range).second) if (refcnt <= 0 || !seen.insert(sym.range).second)
continue; continue;
// NOTE: We OffsetColumn so that the code lens always show up in a Use use = ToSpell({{sym.range, sym.usr, sym.kind, sym.role}, file->id});
// predictable order. Otherwise, the client may randomize it.
Use use{{sym.range, sym.usr, sym.kind, sym.role}, file->id};
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Type: {
QueryType &type = db->GetType(sym);
const QueryType::Def *def = type.AnyDef();
if (!def || def->kind == lsSymbolKind::Namespace)
continue;
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0),
type.uses, true /*force_display*/);
AddCodeLens("derived", "derived", &common, OffsetStartColumn(use, 1),
GetTypeDeclarations(db, type.derived),
false /*force_display*/);
AddCodeLens("var", "vars", &common, OffsetStartColumn(use, 2),
GetVarDeclarations(db, type.instances, true),
false /*force_display*/);
break;
}
case SymbolKind::Func: { case SymbolKind::Func: {
QueryFunc &func = db->GetFunc(sym); QueryFunc &func = db->GetFunc(sym);
const QueryFunc::Def *def = func.AnyDef(); const QueryFunc::Def *def = func.AnyDef();
if (!def) if (!def)
continue; continue;
std::vector<Use> base_uses = GetUsesForAllBases(db, func);
int16_t offset = 0; std::vector<Use> derived_uses = GetUsesForAllDerived(db, func);
Add("ref", {sym.usr, SymbolKind::Func, "uses"}, use, func.uses.size(),
// For functions, the outline will report a location that is using the base_uses.empty());
// extent since that is better for outline. This tries to convert the if (base_uses.size())
// extent location to the spelling location. Add("b.ref", {sym.usr, SymbolKind::Func, "bases uses"}, use,
auto try_ensure_spelling = [&](Use use) { base_uses.size());
Maybe<Use> def = GetDefinitionSpell(db, use); if (derived_uses.size())
if (!def || def->range.start.line != use.range.start.line) { Add("d.ref", {sym.usr, SymbolKind::Func, "derived uses"}, use,
return use; derived_uses.size());
if (base_uses.empty())
Add("base", {sym.usr, SymbolKind::Func, "bases"}, use,
def->bases.size());
Add("derived", {sym.usr, SymbolKind::Func, "derived"}, use,
func.derived.size());
break;
} }
return *def; case SymbolKind::Type: {
}; QueryType &type = db->GetType(sym);
Add("ref", {sym.usr, SymbolKind::Type, "uses"}, use, type.uses.size(),
std::vector<Use> base_callers = GetUsesForAllBases(db, func); true);
std::vector<Use> derived_callers = GetUsesForAllDerived(db, func); Add("derived", {sym.usr, SymbolKind::Type, "derived"}, use,
if (base_callers.empty() && derived_callers.empty()) { type.derived.size());
Use loc = try_ensure_spelling(use); Add("var", {sym.usr, SymbolKind::Type, "instances"}, use,
AddCodeLens("call", "calls", &common, type.instances.size());
OffsetStartColumn(loc, offset++), func.uses,
true /*force_display*/);
} else {
Use loc = try_ensure_spelling(use);
AddCodeLens("direct call", "direct calls", &common,
OffsetStartColumn(loc, offset++), func.uses,
false /*force_display*/);
if (!base_callers.empty())
AddCodeLens("base call", "base calls", &common,
OffsetStartColumn(loc, offset++), base_callers,
false /*force_display*/);
if (!derived_callers.empty())
AddCodeLens("derived call", "derived calls", &common,
OffsetStartColumn(loc, offset++), derived_callers,
false /*force_display*/);
}
AddCodeLens(
"derived", "derived", &common, OffsetStartColumn(use, offset++),
GetFuncDeclarations(db, func.derived), false /*force_display*/);
// "Base"
if (def->bases.size() == 1) {
Maybe<Use> base_loc = GetDefinitionSpell(
db, SymbolIdx{def->bases[0], SymbolKind::Func});
if (base_loc) {
std::optional<lsLocation> ls_base =
GetLsLocation(db, working_files, *base_loc);
if (ls_base) {
std::optional<lsRange> range =
GetLsRange(common.working_file, sym.range);
if (range) {
TCodeLens code_lens;
code_lens.range = *range;
code_lens.range.start.character += offset++;
code_lens.command = lsCommand<lsCodeLensCommandArguments>();
code_lens.command->title = "Base";
code_lens.command->command = "ccls.goto";
code_lens.command->arguments.uri = ls_base->uri;
code_lens.command->arguments.position = ls_base->range.start;
out.result.push_back(code_lens);
}
}
}
} else {
AddCodeLens("base", "base", &common, OffsetStartColumn(use, 1),
GetTypeDeclarations(db, def->bases),
false /*force_display*/);
}
break; break;
} }
case SymbolKind::Var: { case SymbolKind::Var: {
@ -219,27 +168,88 @@ struct Handler_TextDocumentCodeLens
const QueryVar::Def *def = var.AnyDef(); const QueryVar::Def *def = var.AnyDef();
if (!def || (def->is_local() && !g_config->codeLens.localVariables)) if (!def || (def->is_local() && !g_config->codeLens.localVariables))
continue; continue;
Add("ref", {sym.usr, SymbolKind::Var, "uses"}, use, var.uses.size(),
bool force_display = true; def->kind != lsSymbolKind::Macro);
// Do not show 0 refs on macro with no uses, as it is most likely
// a header guard.
if (def->kind == lsSymbolKind::Macro)
force_display = false;
AddCodeLens("ref", "refs", &common, OffsetStartColumn(use, 0), var.uses,
force_display);
break; break;
} }
case SymbolKind::File: case SymbolKind::File:
case SymbolKind::Invalid: { case SymbolKind::Invalid:
assert(false && "unexpected"); llvm_unreachable("");
break;
}
}; };
} }
pipeline::WriteStdout(kMethodType, out); pipeline::WriteStdout(codeLens, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
struct In_WorkspaceExecuteCommand : public RequestInMessage {
MethodType GetMethodType() const override { return executeCommand; }
lsCommand params;
};
MAKE_REFLECT_STRUCT(In_WorkspaceExecuteCommand, id, params);
REGISTER_IN_MESSAGE(In_WorkspaceExecuteCommand);
struct Handler_WorkspaceExecuteCommand
: BaseMessageHandler<In_WorkspaceExecuteCommand> {
MethodType GetMethodType() const override { return executeCommand; }
void Run(In_WorkspaceExecuteCommand *request) override {
const auto &params = request->params;
if (params.arguments.empty())
return;
rapidjson::Document reader;
reader.Parse(params.arguments[0].c_str());
JsonReader json_reader{&reader};
if (params.command == ccls_xref) {
Cmd_xref cmd;
Reflect(json_reader, cmd);
Out_xref out;
out.id = request->id;
auto Map = [&](auto &&uses) {
for (auto &use : uses)
if (auto loc = GetLsLocation(db, working_files, use))
out.result.push_back(std::move(*loc));
};
switch (cmd.kind) {
case SymbolKind::Func: {
QueryFunc &func = db->Func(cmd.usr);
if (cmd.field == "bases") {
if (auto *def = func.AnyDef())
Map(GetFuncDeclarations(db, def->bases));
} else if (cmd.field == "bases uses") {
Map(GetUsesForAllBases(db, func));
} else if (cmd.field == "derived") {
Map(GetFuncDeclarations(db, func.derived));
} else if (cmd.field == "derived uses") {
Map(GetUsesForAllDerived(db, func));
} else if (cmd.field == "uses") {
Map(func.uses);
}
break;
}
case SymbolKind::Type: {
QueryType &type = db->Type(cmd.usr);
if (cmd.field == "derived") {
Map(GetTypeDeclarations(db, type.derived));
} else if (cmd.field == "instances") {
Map(GetVarDeclarations(db, type.instances, 7));
} else if (cmd.field == "uses") {
Map(type.uses);
}
break;
}
case SymbolKind::Var: {
QueryVar &var = db->Var(cmd.usr);
if (cmd.field == "uses")
Map(var.uses);
break;
}
default:
break;
}
pipeline::WriteStdout(executeCommand, out);
}
}
};
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
} // namespace } // namespace

View File

@ -1,58 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "lsp_code_action.h"
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"
using namespace ccls;
namespace {
MethodType kMethodType = "workspace/executeCommand";
struct In_WorkspaceExecuteCommand : public RequestInMessage {
MethodType GetMethodType() const override { return kMethodType; }
lsCommand<lsCodeLensCommandArguments> params;
};
MAKE_REFLECT_STRUCT(In_WorkspaceExecuteCommand, id, params);
REGISTER_IN_MESSAGE(In_WorkspaceExecuteCommand);
struct Out_WorkspaceExecuteCommand
: public lsOutMessage<Out_WorkspaceExecuteCommand> {
lsRequestId id;
std::variant<std::vector<lsLocation>, CommandArgs> result;
};
MAKE_REFLECT_STRUCT(Out_WorkspaceExecuteCommand, jsonrpc, id, result);
struct Handler_WorkspaceExecuteCommand
: BaseMessageHandler<In_WorkspaceExecuteCommand> {
MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceExecuteCommand *request) override {
const auto &params = request->params;
Out_WorkspaceExecuteCommand out;
out.id = request->id;
if (params.command == "ccls._applyFixIt") {
} else if (params.command == "ccls._autoImplement") {
} else if (params.command == "ccls._insertInclude") {
} else if (params.command == "ccls.showReferences") {
out.result = params.arguments.locations;
}
pipeline::WriteStdout(kMethodType, out);
}
};
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceExecuteCommand);
} // namespace