2018-08-21 05:27:52 +00:00
|
|
|
/* 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.
|
|
|
|
==============================================================================*/
|
|
|
|
|
2018-05-27 19:24:56 +00:00
|
|
|
#include "log.hh"
|
|
|
|
#include "pipeline.hh"
|
2018-05-13 16:52:19 +00:00
|
|
|
#include "platform.h"
|
2018-10-28 17:49:31 +00:00
|
|
|
#include "serializer.hh"
|
2018-05-13 16:52:19 +00:00
|
|
|
#include "serializers/json.h"
|
|
|
|
#include "test.h"
|
|
|
|
#include "working_files.h"
|
|
|
|
|
|
|
|
#include <llvm/Support/CommandLine.h>
|
2018-07-16 05:49:32 +00:00
|
|
|
#include <llvm/Support/CrashRecoveryContext.h>
|
2018-10-23 05:01:10 +00:00
|
|
|
#include <llvm/Support/FileSystem.h>
|
2018-05-13 16:52:19 +00:00
|
|
|
#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>
|
2018-05-13 16:52:19 +00:00
|
|
|
|
|
|
|
#include <rapidjson/error/en.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include <vector>
|
|
|
|
|
2018-09-23 19:10:40 +00:00
|
|
|
using namespace ccls;
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::cl;
|
|
|
|
|
2018-10-28 17:49:31 +00:00
|
|
|
namespace ccls {
|
2018-05-13 16:52:19 +00:00
|
|
|
std::string g_init_options;
|
2018-10-28 17:49:31 +00:00
|
|
|
}
|
2018-05-13 16:52:19 +00:00
|
|
|
|
|
|
|
namespace {
|
2018-10-14 06:22:29 +00:00
|
|
|
OptionCategory C("ccls options");
|
|
|
|
|
|
|
|
opt<bool> opt_help("h", desc("Alias for -help"), cat(C));
|
|
|
|
opt<int> opt_verbose("v", desc("verbosity"), init(0), cat(C));
|
2018-08-09 17:08:14 +00:00
|
|
|
opt<std::string> opt_test_index("test-index", ValueOptional, init("!"),
|
2018-10-14 06:22:29 +00:00
|
|
|
desc("run index tests"), cat(C));
|
2018-05-13 16:52:19 +00:00
|
|
|
|
2018-10-23 05:01:10 +00:00
|
|
|
opt<std::string> opt_index("index",
|
|
|
|
desc("standalone mode: index a project and exit"),
|
|
|
|
value_desc("root"), cat(C));
|
2018-10-14 06:22:29 +00:00
|
|
|
opt<std::string> opt_init("init", desc("extra initialization options in JSON"),
|
|
|
|
cat(C));
|
|
|
|
opt<std::string> opt_log_file("log-file", desc("log"), value_desc("filename"),
|
|
|
|
cat(C));
|
2018-08-09 17:08:14 +00:00
|
|
|
opt<std::string> opt_log_file_append("log-file-append", desc("log"),
|
2018-10-14 06:22:29 +00:00
|
|
|
value_desc("filename"), cat(C));
|
2018-05-13 16:52:19 +00:00
|
|
|
|
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-05-13 16:52:19 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
int main(int argc, char **argv) {
|
2018-05-13 16:52:19 +00:00
|
|
|
TraceMe();
|
2018-05-27 19:24:56 +00:00
|
|
|
sys::PrintStackTraceOnErrorSignal(argv[0]);
|
2018-05-13 16:52:19 +00:00
|
|
|
|
2018-10-14 06:22:29 +00:00
|
|
|
for (auto &I : TopLevelSubCommand->OptionsMap)
|
|
|
|
if (I.second->Category != &C)
|
|
|
|
I.second->setHiddenFlag(ReallyHidden);
|
|
|
|
|
2018-05-13 16:52:19 +00:00
|
|
|
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;
|
2018-05-13 16:52:19 +00:00
|
|
|
}
|
|
|
|
|
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();
|
2018-05-13 16:52:19 +00:00
|
|
|
|
|
|
|
bool language_server = true;
|
|
|
|
|
2018-05-27 19:24:56 +00:00
|
|
|
if (opt_log_file.size() || opt_log_file_append.size()) {
|
|
|
|
ccls::log::file = opt_log_file.size()
|
|
|
|
? fopen(opt_log_file.c_str(), "wb")
|
|
|
|
: fopen(opt_log_file_append.c_str(), "ab");
|
|
|
|
if (!ccls::log::file) {
|
|
|
|
fprintf(
|
|
|
|
stderr, "failed to open %s\n",
|
|
|
|
(opt_log_file.size() ? opt_log_file : opt_log_file_append).c_str());
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
setbuf(ccls::log::file, NULL);
|
|
|
|
atexit(CloseLog);
|
|
|
|
}
|
2018-05-13 16:52:19 +00:00
|
|
|
|
2018-07-06 00:53:33 +00:00
|
|
|
if (opt_test_index != "!") {
|
2018-05-13 16:52:19 +00:00
|
|
|
language_server = false;
|
2018-10-28 17:49:31 +00:00
|
|
|
if (!ccls::RunIndexTests(opt_test_index, sys::Process::StandardInIsUserInput()))
|
2018-05-13 16:52:19 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (language_server) {
|
|
|
|
if (!opt_init.empty()) {
|
|
|
|
// We check syntax error here but override client-side
|
|
|
|
// initializationOptions in messages/initialize.cc
|
2018-10-01 07:39:44 +00:00
|
|
|
g_init_options = opt_init.getValue();
|
2018-05-13 16:52:19 +00:00
|
|
|
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);
|
2018-08-09 17:08:14 +00:00
|
|
|
} catch (std::invalid_argument &e) {
|
2018-05-13 16:52:19 +00:00
|
|
|
fprintf(stderr, "Failed to parse --init %s, expected %s\n",
|
2018-08-09 17:08:14 +00:00
|
|
|
static_cast<JsonReader &>(json_reader).GetPath().c_str(),
|
2018-05-13 16:52:19 +00:00
|
|
|
e.what());
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-01 17:19:35 +00:00
|
|
|
sys::ChangeStdinToBinary();
|
|
|
|
sys::ChangeStdoutToBinary();
|
2018-10-23 05:01:10 +00:00
|
|
|
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();
|
|
|
|
}
|
2018-05-13 16:52:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|