diff --git a/src/main.cc b/src/main.cc index 7bd17552..74fd89c0 100644 --- a/src/main.cc +++ b/src/main.cc @@ -23,6 +23,7 @@ limitations under the License. #include #include +#include #include #include #include @@ -49,6 +50,9 @@ opt opt_verbose("v", desc("verbosity"), init(0), cat(C)); opt opt_test_index("test-index", ValueOptional, init("!"), desc("run index tests"), cat(C)); +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)); opt opt_log_file("log-file", desc("log"), value_desc("filename"), @@ -130,14 +134,20 @@ int main(int argc, char **argv) { sys::ChangeStdinToBinary(); sys::ChangeStdoutToBinary(); - // 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(); + 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; diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index 810ffb85..402a635b 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -322,25 +322,13 @@ struct lsClientCapabilities { MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument); struct lsInitializeParams { - // The process Id of the parent process that started - // the server. Is null if the process has not been started by another process. - // If the parent process is not alive then the server should exit (see exit - // notification) its process. - std::optional processId; - - // The rootPath of the workspace. Is null - // if no folder is open. - // - // @deprecated in favour of rootUri. - std::optional rootPath; - // The rootUri of the workspace. Is null if no // folder is open. If both `rootPath` and `rootUri` are set // `rootUri` wins. std::optional rootUri; // User provided initialization options. - std::optional initializationOptions; + Config initializationOptions; // The capabilities provided by the client (editor or tool) lsClientCapabilities capabilities; @@ -372,33 +360,8 @@ void Reflect(Reader &reader, lsInitializeParams::lsTrace &value) { value = lsInitializeParams::lsTrace::Verbose; } -#if 0 // unused -void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) { - switch (value) { - case lsInitializeParams::lsTrace::Off: - writer.String("off"); - break; - case lsInitializeParams::lsTrace::Messages: - writer.String("messages"); - break; - case lsInitializeParams::lsTrace::Verbose: - writer.String("verbose"); - break; - } -} -#endif - -MAKE_REFLECT_STRUCT(lsInitializeParams, processId, rootPath, rootUri, - initializationOptions, capabilities, trace, - workspaceFolders); - -struct lsInitializeError { - // Indicates whether the client should retry to send the - // initilize request after showing the message provided - // in the ResponseError. - bool retry; -}; -MAKE_REFLECT_STRUCT(lsInitializeError, retry); +MAKE_REFLECT_STRUCT(lsInitializeParams, rootUri, initializationOptions, + capabilities, trace, workspaceFolders); struct In_InitializeRequest : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } @@ -438,10 +401,7 @@ struct Handler_Initialize : BaseMessageHandler { << params.rootUri->raw_uri; { - if (params.initializationOptions) - g_config = new Config(*params.initializationOptions); - else - g_config = new Config; + g_config = new Config(params.initializationOptions); rapidjson::Document reader; reader.Parse(g_init_options.c_str()); if (!reader.HasParseError()) { @@ -531,3 +491,17 @@ struct Handler_Initialize : BaseMessageHandler { }; REGISTER_MESSAGE_HANDLER(Handler_Initialize); } // namespace + +void StandaloneInitialize(const std::string &root, Project &project, + WorkingFiles &wfiles, VFS &vfs, + IncludeComplete &complete) { + Handler_Initialize handler; + handler.project = &project; + handler.working_files = &wfiles; + handler.vfs = &vfs; + handler.include_complete = &complete; + + In_InitializeRequest request; + request.params.rootUri = lsDocumentUri::FromPath(root); + handler.Run(&request); +} diff --git a/src/pipeline.cc b/src/pipeline.cc index 62fd4d21..ed674646 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -30,6 +30,7 @@ limitations under the License. #include +#include #include #include using namespace llvm; @@ -42,6 +43,9 @@ using namespace llvm; #include #endif +void StandaloneInitialize(const std::string &, Project &, WorkingFiles &, VFS &, + IncludeComplete &); + void VFS::Clear() { std::lock_guard lock(mutex); state.clear(); @@ -535,6 +539,35 @@ void MainLoop() { } } +void Standalone(const std::string &root) { + Project project; + WorkingFiles wfiles; + VFS vfs; + IncludeComplete complete(&project); + StandaloneInitialize(root, project, wfiles, vfs, complete); + bool tty = sys::Process::StandardOutIsDisplayed(); + + if (tty) { + int entries = 0; + for (auto &[_, folder] : project.root2folder) + entries += folder.entries.size(); + printf("entries: %5d\n", entries); + } + while (1) { + (void)on_indexed->DequeueAll(); + int pending = pending_index_requests; + if (tty) { + printf("\rpending: %5d", pending); + fflush(stdout); + } + if (!pending) + break; + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (tty) + puts(""); +} + void Index(const std::string &path, const std::vector &args, IndexMode mode, lsRequestId id) { pending_index_requests++; diff --git a/src/pipeline.hh b/src/pipeline.hh index e0adc969..112e8bb9 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -45,6 +45,7 @@ void LaunchStdout(); void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project, WorkingFiles *wfiles); void MainLoop(); +void Standalone(const std::string &root); void Index(const std::string &path, const std::vector &args, IndexMode mode, lsRequestId id = {});