diff --git a/src/command_line.cc b/src/command_line.cc index 7ac5a107..a747907e 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -37,13 +37,13 @@ struct IndexTranslationUnitResponse { }; // TODO: Rename TypedBidiMessageQueue to IpcTransport? -using IpcMessageQueue = TypedBidiMessageQueue; +using IpcMessageQueue = TypedBidiMessageQueue; using IndexRequestQueue = ThreadedQueue; using IndexResponseQueue = ThreadedQueue; template void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) { - t.SendMessage(destination, TMessage::kMethod, message); + t.SendMessage(destination, TMessage::kIpcId, message); } std::unordered_map ParseOptions(int argc, @@ -79,48 +79,6 @@ bool HasOption(const std::unordered_map& options, return options.find(option) != options.end(); } -std::unique_ptr ParseMessage() { - int content_length = -1; - int iteration = 0; - while (true) { - if (++iteration > 10) { - assert(false && "bad parser state"); - exit(1); - } - - std::string line; - std::getline(std::cin, line); - // std::cin >> line; - - if (line.compare(0, 14, "Content-Length") == 0) { - content_length = atoi(line.c_str() + 16); - } - - if (line == "\r") - break; - } - - // bad input that is not a message. - if (content_length < 0) { - std::cerr << "parsing command failed (no Content-Length header)" - << std::endl; - return nullptr; - } - - std::string content; - content.reserve(content_length); - for (int i = 0; i < content_length; ++i) { - char c; - std::cin >> c; - content += c; - } - - rapidjson::Document document; - document.Parse(content.c_str(), content_length); - assert(!document.HasParseError()); - - return MessageRegistry::instance()->Parse(document); -} std::string Join(const std::vector& elements, std::string sep) { bool first = true; @@ -135,19 +93,19 @@ std::string Join(const std::vector& elements, std::string sep) { } struct Ipc_Quit : public IpcMessage { - static constexpr lsMethodId kMethod = lsMethodId::Quit; + static constexpr IpcId kIpcId = IpcId::Quit; }; template void Reflect(TVisitor& visitor, Ipc_Quit& value) {} struct Ipc_IsAlive : public IpcMessage { - static constexpr lsMethodId kMethod = lsMethodId::IsAlive; + static constexpr IpcId kIpcId = IpcId::IsAlive; }; template void Reflect(TVisitor& visitor, Ipc_IsAlive& value) {} struct Ipc_OpenProject : public IpcMessage { - static constexpr lsMethodId kMethod = lsMethodId::OpenProject; + static constexpr IpcId kIpcId = IpcId::OpenProject; std::string project_path; }; template @@ -156,7 +114,7 @@ void Reflect(TVisitor& visitor, Ipc_OpenProject& value) { } struct Ipc_Cout : public IpcMessage { - static constexpr lsMethodId kMethod = lsMethodId::Cout; + static constexpr IpcId kIpcId = IpcId::Cout; std::string content; }; template @@ -171,14 +129,14 @@ void SendOutMessageToClient(IpcMessageQueue* queue, T& response) { Ipc_Cout out; out.content = sstream.str(); - queue->SendMessage(&queue->for_client, Ipc_Cout::kMethod, out); + queue->SendMessage(&queue->for_client, Ipc_Cout::kIpcId, out); } template void RegisterId(IpcMessageQueue* t) { - t->RegisterId(T::kMethod, + t->RegisterId(T::kIpcId, [](Writer& visitor, BaseIpcMessage& message) { T& m = static_cast(message); Reflect(visitor, m); @@ -374,19 +332,19 @@ void QueryDbMainLoop( // << std::endl; switch (message->method_id) { - case lsMethodId::Quit: { + case IpcId::Quit: { std::cerr << "Got quit message (exiting)" << std::endl; exit(0); break; } - case lsMethodId::IsAlive: { + case IpcId::IsAlive: { Ipc_IsAlive response; language_client->SendMessage(&language_client->for_client, response.method_id, response); break; } - case lsMethodId::OpenProject: { + case IpcId::OpenProject: { Ipc_OpenProject* msg = static_cast(message.get()); std::string path = msg->project_path; @@ -408,7 +366,7 @@ void QueryDbMainLoop( break; } - case lsMethodId::TextDocumentDocumentSymbol: { + case IpcId::TextDocumentDocumentSymbol: { auto msg = static_cast(message.get()); Out_TextDocumentDocumentSymbol response; @@ -473,7 +431,7 @@ void QueryDbMainLoop( break; } - case lsMethodId::TextDocumentCodeLens: { + case IpcId::TextDocumentCodeLens: { auto msg = static_cast(message.get()); Out_TextDocumentCodeLens response; @@ -528,7 +486,7 @@ void QueryDbMainLoop( break; } - case lsMethodId::WorkspaceSymbol: { + case IpcId::WorkspaceSymbol: { auto msg = static_cast(message.get()); Out_WorkspaceSymbol response; @@ -675,7 +633,7 @@ void QueryDbMain() { // |ipc| is connected to a server. void LanguageServerStdinLoop(IpcMessageQueue* ipc) { while (true) { - std::unique_ptr message = ParseMessage(); + std::unique_ptr message = MessageRegistry::instance()->ReadMessageFromStdin(); // Message parsing can fail if we don't recognize the method. if (!message) @@ -686,7 +644,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { switch (message->method_id) { // TODO: For simplicitly lets just proxy the initialize request like // all other requests so that stdin loop thread becomes super simple. - case lsMethodId::Initialize: { + case IpcId::Initialize: { auto request = static_cast(message.get()); if (request->params.rootUri) { std::string project_path = request->params.rootUri->GetPath(); @@ -695,7 +653,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { << std::endl; Ipc_OpenProject open_project; open_project.project_path = project_path; - ipc->SendMessage(&ipc->for_server, Ipc_OpenProject::kMethod, open_project); + ipc->SendMessage(&ipc->for_server, Ipc_OpenProject::kIpcId, open_project); } auto response = Out_InitializeResponse(); @@ -709,9 +667,9 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { break; } - case lsMethodId::TextDocumentDocumentSymbol: - case lsMethodId::TextDocumentCodeLens: - case lsMethodId::WorkspaceSymbol: { + case IpcId::TextDocumentDocumentSymbol: + case IpcId::TextDocumentCodeLens: + case IpcId::WorkspaceSymbol: { ipc->SendMessage(&ipc->for_server, message->method_id, *message.get()); break; } @@ -723,13 +681,13 @@ void LanguageServerMainLoop(IpcMessageQueue* ipc) { std::vector> messages = ipc->GetMessages(&ipc->for_client); for (auto& message : messages) { switch (message->method_id) { - case lsMethodId::Quit: { + case IpcId::Quit: { std::cerr << "Got quit message (exiting)" << std::endl; exit(0); break; } - case lsMethodId::Cout: { + case IpcId::Cout: { auto msg = static_cast(message.get()); std::cout << msg->content; std::cout.flush(); @@ -756,7 +714,7 @@ bool IsQueryDbProcessRunning(IpcMessageQueue* ipc) { // Check if we got an IsAlive message back. std::vector> messages = ipc->GetMessages(&ipc->for_client); for (auto& message : messages) { - if (lsMethodId::IsAlive == message->method_id) + if (IpcId::IsAlive == message->method_id) return true; } diff --git a/src/language_server_api.cc b/src/language_server_api.cc new file mode 100644 index 00000000..acf78bd4 --- /dev/null +++ b/src/language_server_api.cc @@ -0,0 +1 @@ +//#include "language_server_api.h" \ No newline at end of file diff --git a/src/language_server_api.h b/src/language_server_api.h index 68edbc49..60fb9340 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -21,7 +22,7 @@ using std::experimental::nullopt; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -enum class lsMethodId : int { +enum class IpcId : int { // Language server specific requests. CancelRequest = 0, Initialize, @@ -37,13 +38,13 @@ enum class lsMethodId : int { OpenProject, Cout }; -MAKE_ENUM_HASHABLE(lsMethodId); +MAKE_ENUM_HASHABLE(IpcId); template -void Reflect(TVisitor& visitor, lsMethodId& value) { +void Reflect(TVisitor& visitor, IpcId& value) { int value0 = static_cast(value); Reflect(visitor, value0); - value = static_cast(value0); + value = static_cast(value0); } struct RequestId { @@ -121,23 +122,24 @@ void Reflect(Reader& visitor, RequestId& id) { ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -const char* MethodIdToString(lsMethodId id) { +const char* MethodIdToString(IpcId id) { switch (id) { - case lsMethodId::CancelRequest: + case IpcId::CancelRequest: return "$/cancelRequest"; - case lsMethodId::Initialize: + case IpcId::Initialize: return "initialize"; - case lsMethodId::Initialized: + case IpcId::Initialized: return "initialized"; - case lsMethodId::TextDocumentDocumentSymbol: + case IpcId::TextDocumentDocumentSymbol: return "textDocument/documentSymbol"; - case lsMethodId::TextDocumentCodeLens: + case IpcId::TextDocumentCodeLens: return "textDocument/codeLens"; - case lsMethodId::CodeLensResolve: + case IpcId::CodeLensResolve: return "codeLens/resolve"; - case lsMethodId::WorkspaceSymbol: + case IpcId::WorkspaceSymbol: return "workspace/symbol"; default: + assert(false); exit(1); } } @@ -153,7 +155,7 @@ struct MessageRegistry { template void Register() { - std::string method_name = MethodIdToString(T::kMethod); + std::string method_name = MethodIdToString(T::kIpcId); allocators[method_name] = [](Reader& visitor) { auto result = MakeUnique(); Reflect(visitor, *result); @@ -161,6 +163,49 @@ struct MessageRegistry { }; } + std::unique_ptr ReadMessageFromStdin() { + int content_length = -1; + int iteration = 0; + while (true) { + if (++iteration > 10) { + assert(false && "bad parser state"); + exit(1); + } + + std::string line; + std::getline(std::cin, line); + // std::cin >> line; + + if (line.compare(0, 14, "Content-Length") == 0) { + content_length = atoi(line.c_str() + 16); + } + + if (line == "\r") + break; + } + + // bad input that is not a message. + if (content_length < 0) { + std::cerr << "parsing command failed (no Content-Length header)" + << std::endl; + return nullptr; + } + + std::string content; + content.reserve(content_length); + for (int i = 0; i < content_length; ++i) { + char c; + std::cin >> c; + content += c; + } + + rapidjson::Document document; + document.Parse(content.c_str(), content_length); + assert(!document.HasParseError()); + + return Parse(document); + } + std::unique_ptr Parse(Reader& visitor) { std::string jsonrpc = visitor["jsonrpc"].GetString(); if (jsonrpc != "2.0") @@ -188,13 +233,13 @@ MessageRegistry* MessageRegistry::instance() { } struct BaseIpcMessage { - const lsMethodId method_id; - BaseIpcMessage(lsMethodId method_id) : method_id(method_id) {} + const IpcId method_id; + BaseIpcMessage(IpcId method_id) : method_id(method_id) {} }; template struct IpcMessage : public BaseIpcMessage { - IpcMessage() : BaseIpcMessage(T::kMethod) {} + IpcMessage() : BaseIpcMessage(T::kIpcId) {} }; template @@ -1182,8 +1227,8 @@ void Reflect(TVisitor& visitor, lsInitializeResult& value) { } -struct Ipc_InitializeRequest : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::Initialize; +struct Ipc_InitializeRequest : public IpcMessage { + const static IpcId kIpcId = IpcId::Initialize; RequestId id; lsInitializeParams params; @@ -1209,8 +1254,8 @@ void Reflect(TVisitor& visitor, Out_InitializeResponse& value) { REFLECT_MEMBER_END(); } -struct Ipc_InitializedNotification : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::Initialized; +struct Ipc_InitializedNotification : public IpcMessage { + const static IpcId kIpcId = IpcId::Initialized; RequestId id; }; @@ -1264,7 +1309,7 @@ void Reflect(TVisitor& visitor, Ipc_InitializedNotification& value) { // Cancel an existing request. struct Ipc_CancelRequest : public IpcMessage { - static const lsMethodId kMethod = lsMethodId::CancelRequest; + static const IpcId kIpcId = IpcId::CancelRequest; RequestId id; }; template @@ -1284,8 +1329,8 @@ void Reflect(TVisitor& visitor, lsDocumentSymbolParams& value) { REFLECT_MEMBER(textDocument); REFLECT_MEMBER_END(); } -struct Ipc_TextDocumentDocumentSymbol : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::TextDocumentDocumentSymbol; +struct Ipc_TextDocumentDocumentSymbol : public IpcMessage { + const static IpcId kIpcId = IpcId::TextDocumentDocumentSymbol; RequestId id; lsDocumentSymbolParams params; @@ -1297,7 +1342,7 @@ void Reflect(TVisitor& visitor, Ipc_TextDocumentDocumentSymbol& value) { REFLECT_MEMBER(params); REFLECT_MEMBER_END(); } -struct Out_TextDocumentDocumentSymbol : public lsOutMessage{ +struct Out_TextDocumentDocumentSymbol : public lsOutMessage { RequestId id; std::vector result; }; @@ -1347,9 +1392,8 @@ void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) { Reflect(*it, value.locations); } using TCodeLens = lsCodeLens; -struct Ipc_TextDocumentCodeLens : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::TextDocumentCodeLens; - +struct Ipc_TextDocumentCodeLens : public IpcMessage { + const static IpcId kIpcId = IpcId::TextDocumentCodeLens; RequestId id; lsDocumentCodeLensParams params; }; @@ -1372,8 +1416,8 @@ void Reflect(TVisitor& visitor, Out_TextDocumentCodeLens& value) { REFLECT_MEMBER(result); REFLECT_MEMBER_END(); } -struct Ipc_CodeLensResolve : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::CodeLensResolve; +struct Ipc_CodeLensResolve : public IpcMessage { + const static IpcId kIpcId = IpcId::CodeLensResolve; RequestId id; TCodeLens params; @@ -1408,8 +1452,8 @@ void Reflect(TVisitor& visitor, lsWorkspaceSymbolParams& value) { REFLECT_MEMBER(query); REFLECT_MEMBER_END(); } -struct Ipc_WorkspaceSymbol : public IpcMessage{ - const static lsMethodId kMethod = lsMethodId::WorkspaceSymbol; +struct Ipc_WorkspaceSymbol : public IpcMessage { + const static IpcId kIpcId = IpcId::WorkspaceSymbol; RequestId id; lsWorkspaceSymbolParams params; }; @@ -1461,20 +1505,11 @@ struct Out_ShowLogMessage : public lsOutMessage { enum class DisplayType { Show, Log }; - DisplayType display_type = DisplayType::Show; - std::string method() { - switch (display_type) { - case Out_ShowLogMessage::DisplayType::Show: - return "window/showMessage"; - break; - case Out_ShowLogMessage::DisplayType::Log: + if (display_type == DisplayType::Log) return "window/logMessage"; - break; - } - assert(false); - return "window/logMessage"; + return "window/showMessage"; } Out_ShowLogMessageParams params;