ccls/src/main.cc

157 lines
4.6 KiB
C++
Raw Normal View History

2018-08-21 05:27:52 +00:00
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
2018-05-27 19:24:56 +00:00
#include "log.hh"
#include "pipeline.hh"
2018-10-29 04:21:21 +00:00
#include "platform.hh"
#include "serializer.hh"
2018-10-29 04:21:21 +00:00
#include "test.hh"
#include "working_files.hh"
2018-11-04 04:48:38 +00:00
#include <clang/Basic/Version.h>
#include <llvm/Support/CommandLine.h>
2018-07-16 05:49:32 +00:00
#include <llvm/Support/CrashRecoveryContext.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Process.h>
2018-07-01 17:19:35 +00:00
#include <llvm/Support/Program.h>
2018-05-27 19:24:56 +00:00
#include <llvm/Support/Signals.h>
#include <rapidjson/document.h>
#include <rapidjson/error/en.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <unordered_map>
#include <vector>
using namespace ccls;
using namespace llvm;
using namespace llvm::cl;
namespace ccls {
std::vector<std::string> g_init_options;
}
namespace {
OptionCategory C("ccls options");
opt<bool> opt_help("h", desc("Alias for -help"), cat(C));
opt<int> opt_verbose("v", desc("verbosity, from -3 (fatal) to 2 (verbose)"),
init(0), cat(C));
2018-08-09 17:08:14 +00:00
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"),
desc("run index tests"), cat(C));
opt<std::string> opt_index("index",
desc("standalone mode: index a project and exit"),
value_desc("root"), cat(C));
list<std::string> opt_init("init", desc("extra initialization options in JSON"),
cat(C));
opt<std::string> opt_log_file("log-file", desc("stderr or log file"),
value_desc("file"), init("stderr"), cat(C));
opt<bool> opt_log_file_append("log-file-append", desc("append to log file"),
cat(C));
2018-08-09 17:08:14 +00:00
void CloseLog() { fclose(ccls::log::file); }
2018-05-27 19:24:56 +00:00
2018-08-09 17:08:14 +00:00
} // namespace
2018-08-09 17:08:14 +00:00
int main(int argc, char **argv) {
TraceMe();
2018-05-27 19:24:56 +00:00
sys::PrintStackTraceOnErrorSignal(argv[0]);
2018-11-04 04:48:38 +00:00
cl::SetVersionPrinter([](raw_ostream &OS) {
OS << clang::getClangToolFullVersion("ccls version " CCLS_VERSION "\nclang")
<< "\n";
2018-11-04 04:48:38 +00:00
});
for (auto &I : TopLevelSubCommand->OptionsMap)
#if LLVM_VERSION_MAJOR >= 9 // rL360179
if (I.second->Categories[0] != &C)
#else
if (I.second->Category != &C)
#endif
I.second->setHiddenFlag(ReallyHidden);
ParseCommandLineOptions(argc, argv,
"C/C++/Objective-C language server\n\n"
"See more on https://github.com/MaskRay/ccls/wiki");
if (opt_help) {
PrintHelpMessage();
2018-07-09 00:13:41 +00:00
return 0;
}
ccls::log::verbosity = ccls::log::Verbosity(opt_verbose.getValue());
2018-05-28 00:50:02 +00:00
pipeline::Init();
2018-07-16 05:49:32 +00:00
const char *env = getenv("CCLS_CRASH_RECOVERY");
if (!env || strcmp(env, "0") != 0)
CrashRecoveryContext::Enable();
bool language_server = true;
if (opt_log_file.size()) {
ccls::log::file =
opt_log_file == "stderr"
? stderr
: fopen(opt_log_file.c_str(), opt_log_file_append ? "ab" : "wb");
2018-05-27 19:24:56 +00:00
if (!ccls::log::file) {
fprintf(stderr, "failed to open %s\n", opt_log_file.c_str());
2018-05-27 19:24:56 +00:00
return 2;
}
setbuf(ccls::log::file, NULL);
atexit(CloseLog);
}
if (opt_test_index != "!") {
language_server = false;
if (!ccls::RunIndexTests(opt_test_index, sys::Process::StandardInIsUserInput()))
return 1;
}
if (language_server) {
if (!opt_init.empty()) {
// We check syntax error here but override client-side
// initializationOptions in messages/initialize.cc
g_init_options = opt_init;
rapidjson::Document reader;
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<JsonReader &>(json_reader).GetPath().c_str(),
e.what());
return 1;
}
}
}
2018-07-01 17:19:35 +00:00
sys::ChangeStdinToBinary();
sys::ChangeStdoutToBinary();
if (opt_index.size()) {
SmallString<256> Root(opt_index);
sys::fs::make_absolute(Root);
pipeline::Standalone(Root.str());
} else {
// The thread that reads from stdin and dispatchs commands to the main
// thread.
pipeline::LaunchStdin();
// The thread that writes responses from the main thread to stdout.
pipeline::LaunchStdout();
// Main thread which also spawns indexer threads upon the "initialize"
// request.
pipeline::MainLoop();
}
}
return 0;
}