From 1d7674bdfc02cb32cb50e44f3306ca4f8ae39c1b Mon Sep 17 00:00:00 2001 From: Fangrui Song Date: Sun, 9 Dec 2018 13:50:58 -0800 Subject: [PATCH] Support multiple -init= Initialization options are applied (deserialized to the same object) in the following order: * "initializationOptions" from client * first -init= * second -init= * ... Scalar options will be overridden but arrays will get concatenated, e.g. ccls -log-file=/dev/stderr -index . -init='{"clang":{"extraArgs":["-DA"]}}' -init='{"clang":{"extraArgs":["-DB"]}}' results in clang.extraArgs: ["-DA", "-DB"] --- src/main.cc | 40 ++++++++++++++++++++------------------ src/messages/initialize.cc | 21 ++++++++++---------- 2 files changed, 32 insertions(+), 29 deletions(-) diff --git a/src/main.cc b/src/main.cc index 6250bff0..536c5df8 100644 --- a/src/main.cc +++ b/src/main.cc @@ -30,7 +30,7 @@ using namespace llvm; using namespace llvm::cl; namespace ccls { -std::string g_init_options; +std::vector g_init_options; } namespace { @@ -44,8 +44,8 @@ opt opt_test_index("test-index", ValueOptional, init("!"), opt opt_index("index", desc("standalone mode: index a project and exit"), value_desc("root"), cat(C)); -opt opt_init("init", desc("extra initialization options in JSON"), - cat(C)); +list opt_init("init", desc("extra initialization options in JSON"), + cat(C)); opt opt_log_file("log-file", desc("log"), value_desc("filename"), cat(C)); opt opt_log_file_append("log-file-append", desc("log"), @@ -106,23 +106,25 @@ int main(int argc, char **argv) { if (!opt_init.empty()) { // We check syntax error here but override client-side // initializationOptions in messages/initialize.cc - g_init_options = opt_init.getValue(); + g_init_options = opt_init; rapidjson::Document reader; - rapidjson::ParseResult ok = reader.Parse(g_init_options.c_str()); - if (!ok) { - fprintf(stderr, "Failed to parse --init as JSON: %s (%zd)\n", - rapidjson::GetParseError_En(ok.Code()), ok.Offset()); - return 1; - } - JsonReader json_reader{&reader}; - try { - Config config; - Reflect(json_reader, config); - } catch (std::invalid_argument &e) { - fprintf(stderr, "Failed to parse --init %s, expected %s\n", - static_cast(json_reader).GetPath().c_str(), - e.what()); - return 1; + for (const std::string &str : g_init_options) { + rapidjson::ParseResult ok = reader.Parse(str.c_str()); + if (!ok) { + fprintf(stderr, "Failed to parse --init as JSON: %s (%zd)\n", + rapidjson::GetParseError_En(ok.Code()), ok.Offset()); + return 1; + } + JsonReader json_reader{&reader}; + try { + Config config; + Reflect(json_reader, config); + } catch (std::invalid_argument &e) { + fprintf(stderr, "Failed to parse --init %s, expected %s\n", + static_cast(json_reader).GetPath().c_str(), + e.what()); + return 1; + } } } diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 8ada5de0..2b51be38 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -24,8 +24,7 @@ namespace ccls { using namespace llvm; -// TODO Cleanup global variables -extern std::string g_init_options; +extern std::vector g_init_options; namespace { enum class TextDocumentSyncKind { None = 0, Full = 1, Incremental = 2 }; @@ -243,14 +242,16 @@ void Initialize(MessageHandler *m, InitializeParam ¶m, ReplyOnce &reply) { { g_config = new Config(param.initializationOptions); rapidjson::Document reader; - reader.Parse(g_init_options.c_str()); - if (!reader.HasParseError()) { - JsonReader json_reader{&reader}; - try { - Reflect(json_reader, *g_config); - } catch (std::invalid_argument &) { - // This will not trigger because parse error is handled in - // MessageRegistry::Parse in lsp.cc + for (const std::string &str : g_init_options) { + reader.Parse(str.c_str()); + if (!reader.HasParseError()) { + JsonReader json_reader{&reader}; + try { + Reflect(json_reader, *g_config); + } catch (std::invalid_argument &) { + // This will not trigger because parse error is handled in + // MessageRegistry::Parse in lsp.cc + } } }