diff --git a/src/config.hh b/src/config.hh index 751a712c..87bf71a4 100644 --- a/src/config.hh +++ b/src/config.hh @@ -121,6 +121,11 @@ struct Config { // If false, disable snippets and complete just the identifier part. // TextDocumentClientCapabilities.completion.completionItem.snippetSupport bool snippetSupport = true; + + // List of supported CodeActionKinds. If empty, client does not + // have CodeActionLiteralSupport. + // TextDocumentClientCapabilities.codeAction.codeActionLiteralSupport.codeActionKind.valueSet + std::vector codeActionKind; } client; struct CodeLens { diff --git a/src/message_handler.cc b/src/message_handler.cc index 498a72de..890a9088 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -19,7 +19,7 @@ using namespace clang; MAKE_HASHABLE(ccls::SymbolIdx, t.usr, t.kind); namespace ccls { -REFLECT_STRUCT(CodeActionParam::Context, diagnostics); +REFLECT_STRUCT(CodeActionParam::Context, diagnostics, only); REFLECT_STRUCT(CodeActionParam, textDocument, range, context); void reflect(JsonReader &, EmptyParam &) {} REFLECT_STRUCT(TextDocumentParam, textDocument); diff --git a/src/message_handler.hh b/src/message_handler.hh index 038b5bdd..9c487d26 100644 --- a/src/message_handler.hh +++ b/src/message_handler.hh @@ -30,6 +30,7 @@ struct CodeActionParam { lsRange range; struct Context { std::vector diagnostics; + std::vector only; } context; }; struct EmptyParam {}; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 9b9e2bb5..17a0d56a 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -162,6 +162,15 @@ struct TextDocumentClientCap { bool hierarchicalDocumentSymbolSupport = false; } documentSymbol; + struct CodeAction { + bool dynamicRegistration = false; + struct CodeActionLiteralSupport { + struct CodeActionKind { + std::vector valueSet; + } codeActionKind; + } codeActionLiteralSupport; + } codeAction; + struct PublishDiagnostics { bool relatedInformation = false; } publishDiagnostics; @@ -173,9 +182,14 @@ REFLECT_STRUCT(TextDocumentClientCap::Completion, completionItem); REFLECT_STRUCT(TextDocumentClientCap::DocumentSymbol, hierarchicalDocumentSymbolSupport); REFLECT_STRUCT(TextDocumentClientCap::LinkSupport, linkSupport); +REFLECT_STRUCT(TextDocumentClientCap::CodeAction::CodeActionLiteralSupport::CodeActionKind, + valueSet); +REFLECT_STRUCT(TextDocumentClientCap::CodeAction::CodeActionLiteralSupport, codeActionKind); +REFLECT_STRUCT(TextDocumentClientCap::CodeAction, + dynamicRegistration, codeActionLiteralSupport); REFLECT_STRUCT(TextDocumentClientCap::PublishDiagnostics, relatedInformation); REFLECT_STRUCT(TextDocumentClientCap, completion, definition, documentSymbol, - publishDiagnostics); + codeAction, publishDiagnostics); struct ClientCap { WorkspaceClientCap workspace; @@ -322,6 +336,10 @@ void do_initialize(MessageHandler *m, InitializeParam ¶m, if (!g_config->client.snippetSupport) g_config->completion.duplicateOptional = false; + g_config->client.codeActionKind = + capabilities.textDocument + .codeAction.codeActionLiteralSupport.codeActionKind.valueSet; + // Ensure there is a resource directory. if (g_config->clang.resourceDir.empty()) g_config->clang.resourceDir = getDefaultResourceDirectory(); diff --git a/src/messages/textDocument_code.cc b/src/messages/textDocument_code.cc index c7b249b1..a205f05d 100644 --- a/src/messages/textDocument_code.cc +++ b/src/messages/textDocument_code.cc @@ -21,12 +21,27 @@ struct CodeAction { }; REFLECT_STRUCT(CodeAction, title, kind, edit); } // 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); +} + 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; std::vector result; + if (!only.empty() && !vec_has(only, std::string("quickfix"))) { + reply(result); + return; + } + 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)