From 8219a39a3220b38b60de8282c976b0a96713f064 Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Sat, 25 Mar 2017 15:13:19 -0700 Subject: [PATCH] move some things into language_server_api.cc --- src/command_line.cc | 2 +- src/language_server_api.cc | 240 +++++++++++++++++++++++++- src/language_server_api.h | 334 +++++++------------------------------ src/serializer.h | 9 + 4 files changed, 305 insertions(+), 280 deletions(-) diff --git a/src/command_line.cc b/src/command_line.cc index a747907e..25ce4846 100644 --- a/src/command_line.cc +++ b/src/command_line.cc @@ -640,7 +640,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) { continue; std::cerr << "[info]: Got message of type " - << MethodIdToString(message->method_id) << std::endl; + << IpcIdToString(message->method_id) << std::endl; 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. diff --git a/src/language_server_api.cc b/src/language_server_api.cc index acf78bd4..80346d1a 100644 --- a/src/language_server_api.cc +++ b/src/language_server_api.cc @@ -1 +1,239 @@ -//#include "language_server_api.h" \ No newline at end of file +#include "language_server_api.h" + +const char* IpcIdToString(IpcId id) { + switch (id) { + case IpcId::CancelRequest: + return "$/cancelRequest"; + case IpcId::Initialize: + return "initialize"; + case IpcId::Initialized: + return "initialized"; + case IpcId::TextDocumentDocumentSymbol: + return "textDocument/documentSymbol"; + case IpcId::TextDocumentCodeLens: + return "textDocument/codeLens"; + case IpcId::CodeLensResolve: + return "codeLens/resolve"; + case IpcId::WorkspaceSymbol: + return "workspace/symbol"; + default: + assert(false); + exit(1); + } +} + +void Reflect(Writer& visitor, lsRequestId& value) { + assert(value.id0.has_value() || value.id1.has_value()); + + if (value.id0) { + Reflect(visitor, value.id0.value()); + } + else { + Reflect(visitor, value.id1.value()); + } +} + +void Reflect(Reader& visitor, lsRequestId& id) { + if (visitor.IsInt()) + Reflect(visitor, id.id0); + else if (visitor.IsString()) + Reflect(visitor, id.id1); + else + std::cerr << "Unable to deserialize id" << std::endl; +} + +MessageRegistry* MessageRegistry::instance_ = nullptr; + +std::unique_ptr MessageRegistry::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 MessageRegistry::Parse(Reader& visitor) { + std::string jsonrpc = visitor["jsonrpc"].GetString(); + if (jsonrpc != "2.0") + exit(1); + + std::string method; + ReflectMember(visitor, "method", method); + + if (allocators.find(method) == allocators.end()) { + std::cerr << "Unable to find registered handler for method \"" << method << "\"" << std::endl; + return nullptr; + } + + Allocator& allocator = allocators[method]; + return allocator(visitor); +} + +MessageRegistry* MessageRegistry::instance() { + if (!instance_) + instance_ = new MessageRegistry(); + + return instance_; +} + +BaseIpcMessage::BaseIpcMessage(IpcId method_id) + : method_id(method_id) {} + +void lsResponseError::Write(Writer& visitor) { + auto& value = *this; + int code = static_cast(this->code); + + visitor.StartObject(); + REFLECT_MEMBER2("code", code); + REFLECT_MEMBER(message); + if (data) { + visitor.Key("data"); + data->Write(visitor); + } + visitor.EndObject(); +} + +lsDocumentUri lsDocumentUri::FromPath(const std::string& path) { + lsDocumentUri result; + result.SetPath(path); + return result; +} + +lsDocumentUri::lsDocumentUri() {} + +bool lsDocumentUri::operator==(const lsDocumentUri& other) const { + return raw_uri == other.raw_uri; +} + +void lsDocumentUri::SetPath(const std::string& path) { + // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests + raw_uri = path; + + size_t index = raw_uri.find(":"); + if (index != -1) { + raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1, "%3A"); + } + + raw_uri = "file:///" + raw_uri; + //std::cerr << "Set uri to " << raw_uri << " from " << path; +} + +std::string lsDocumentUri::GetPath() { + // TODO: make this not a hack. + std::string result = raw_uri; + + size_t index = result.find("%3A"); + if (index != -1) { + result.replace(result.begin() + index, result.begin() + index + 3, ":"); + } + + index = result.find("file://"); + if (index != -1) { + result.replace(result.begin() + index, result.begin() + index + 8, ""); + } + + std::replace(result.begin(), result.end(), '\\', '/'); + return result; +} + +lsPosition::lsPosition() {} +lsPosition::lsPosition(int line, int character) : line(line), character(character) {} + +bool lsPosition::operator==(const lsPosition& other) const { + return line == other.line && character == other.character; +} + +lsRange::lsRange() {} +lsRange::lsRange(lsPosition position) : start(position), end(position) {} + +bool lsRange::operator==(const lsRange& other) const { + return start == other.start && end == other.end; +} + +lsLocation::lsLocation() {} +lsLocation::lsLocation(lsDocumentUri uri, lsRange range) : uri(uri), range(range) {} + +bool lsLocation::operator==(const lsLocation& other) const { + return uri == other.uri && range == other.range; +} + +void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) { + std::string v = reader.GetString(); + if (v == "off") + value = lsInitializeParams::lsTrace::Off; + else if (v == "messages") + value = lsInitializeParams::lsTrace::Messages; + else if (v == "verbose") + value = lsInitializeParams::lsTrace::Verbose; +} + +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; + } +} + +void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) { + visitor.StartArray(); + Reflect(visitor, value.uri); + Reflect(visitor, value.position); + Reflect(visitor, value.locations); + visitor.EndArray(); +} +void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) { + auto it = visitor.Begin(); + Reflect(*it, value.uri); + ++it; + Reflect(*it, value.position); + ++it; + Reflect(*it, value.locations); +} + +std::string Out_ShowLogMessage::method() { + if (display_type == DisplayType::Log) + return "window/logMessage"; + return "window/showMessage"; +} \ No newline at end of file diff --git a/src/language_server_api.h b/src/language_server_api.h index 60fb9340..0e0be07c 100644 --- a/src/language_server_api.h +++ b/src/language_server_api.h @@ -38,39 +38,16 @@ enum class IpcId : int { OpenProject, Cout }; -MAKE_ENUM_HASHABLE(IpcId); +MAKE_ENUM_HASHABLE(IpcId) +MAKE_REFLECT_TYPE_PROXY(IpcId, int) +const char* IpcIdToString(IpcId id); -template -void Reflect(TVisitor& visitor, IpcId& value) { - int value0 = static_cast(value); - Reflect(visitor, value0); - value = static_cast(value0); -} - -struct RequestId { +struct lsRequestId { optional id0; optional id1; }; - -void Reflect(Writer& visitor, RequestId& value) { - assert(value.id0.has_value() || value.id1.has_value()); - - if (value.id0) { - Reflect(visitor, value.id0.value()); - } - else { - Reflect(visitor, value.id1.value()); - } -} - -void Reflect(Reader& visitor, RequestId& id) { - if (visitor.IsInt()) - Reflect(visitor, id.id0); - else if (visitor.IsString()) - Reflect(visitor, id.id1); - else - std::cerr << "Unable to deserialize id" << std::endl; -} +void Reflect(Writer& visitor, lsRequestId& value); +void Reflect(Reader& visitor, lsRequestId& id); @@ -122,28 +99,6 @@ void Reflect(Reader& visitor, RequestId& id) { ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// -const char* MethodIdToString(IpcId id) { - switch (id) { - case IpcId::CancelRequest: - return "$/cancelRequest"; - case IpcId::Initialize: - return "initialize"; - case IpcId::Initialized: - return "initialized"; - case IpcId::TextDocumentDocumentSymbol: - return "textDocument/documentSymbol"; - case IpcId::TextDocumentCodeLens: - return "textDocument/codeLens"; - case IpcId::CodeLensResolve: - return "codeLens/resolve"; - case IpcId::WorkspaceSymbol: - return "workspace/symbol"; - default: - assert(false); - exit(1); - } -} - struct BaseIpcMessage; struct MessageRegistry { @@ -155,7 +110,7 @@ struct MessageRegistry { template void Register() { - std::string method_name = MethodIdToString(T::kIpcId); + std::string method_name = IpcIdToString(T::kIpcId); allocators[method_name] = [](Reader& visitor) { auto result = MakeUnique(); Reflect(visitor, *result); @@ -163,78 +118,14 @@ 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") - exit(1); - - std::string method; - ReflectMember(visitor, "method", method); - - if (allocators.find(method) == allocators.end()) { - std::cerr << "Unable to find registered handler for method \"" << method << "\"" << std::endl; - return nullptr; - } - - Allocator& allocator = allocators[method]; - return allocator(visitor); - } + std::unique_ptr ReadMessageFromStdin(); + std::unique_ptr Parse(Reader& visitor); }; -MessageRegistry* MessageRegistry::instance_ = nullptr; -MessageRegistry* MessageRegistry::instance() { - if (!instance_) - instance_ = new MessageRegistry(); - - return instance_; -} struct BaseIpcMessage { const IpcId method_id; - BaseIpcMessage(IpcId method_id) : method_id(method_id) {} + BaseIpcMessage(IpcId method_id); }; template @@ -285,19 +176,7 @@ struct lsResponseError { std::string message; std::unique_ptr data; - void Write(Writer& visitor) { - auto& value = *this; - int code = static_cast(this->code); - - visitor.StartObject(); - REFLECT_MEMBER2("code", code); - REFLECT_MEMBER(message); - if (data) { - visitor.Key("data"); - data->Write(visitor); - } - visitor.EndObject(); - } + void Write(Writer& visitor); }; @@ -358,50 +237,15 @@ struct lsResponseError { ///////////////////////////////////////////////////////////////////////////// struct lsDocumentUri { + static lsDocumentUri FromPath(const std::string& path); + + lsDocumentUri(); + bool operator==(const lsDocumentUri& other) const; + + void SetPath(const std::string& path); + std::string GetPath(); + std::string raw_uri; - - lsDocumentUri() {} - - static lsDocumentUri FromPath(const std::string& path) { - lsDocumentUri result; - result.SetPath(path); - return result; - } - - bool operator==(const lsDocumentUri& other) const { - return raw_uri == other.raw_uri; - } - - void SetPath(const std::string& path) { - // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests - raw_uri = path; - - size_t index = raw_uri.find(":"); - if (index != -1) { - raw_uri.replace(raw_uri.begin() + index, raw_uri.begin() + index + 1, "%3A"); - } - - raw_uri = "file:///" + raw_uri; - //std::cerr << "Set uri to " << raw_uri << " from " << path; - } - - std::string GetPath() { - // TODO: make this not a hack. - std::string result = raw_uri; - - size_t index = result.find("%3A"); - if (index != -1) { - result.replace(result.begin() + index, result.begin() + index + 3, ":"); - } - - index = result.find("file://"); - if (index != -1) { - result.replace(result.begin() + index, result.begin() + index + 8, ""); - } - - std::replace(result.begin(), result.end(), '\\', '/'); - return result; - } }; MAKE_HASHABLE(lsDocumentUri, t.raw_uri); @@ -412,19 +256,16 @@ void Reflect(TVisitor& visitor, lsDocumentUri& value) { struct lsPosition { + lsPosition(); + lsPosition(int line, int character); + + bool operator==(const lsPosition& other) const; + // Note: these are 0-based. int line = 0; int character = 0; - - lsPosition() {} - lsPosition(int line, int character) : line(line), character(character) {} - - bool operator==(const lsPosition& other) const { - return line == other.line && character == other.character; - } }; MAKE_HASHABLE(lsPosition, t.line, t.character); - template void Reflect(TVisitor& visitor, lsPosition& value) { REFLECT_MEMBER_START(); @@ -435,15 +276,13 @@ void Reflect(TVisitor& visitor, lsPosition& value) { struct lsRange { + lsRange(); + lsRange(lsPosition position); + + bool operator==(const lsRange& other) const; + lsPosition start; lsPosition end; - - lsRange() {} - lsRange(lsPosition position) : start(position), end(position) {} - - bool operator==(const lsRange& other) const { - return start == other.start && end == other.end; - } }; MAKE_HASHABLE(lsRange, t.start, t.end); @@ -457,18 +296,15 @@ void Reflect(TVisitor& visitor, lsRange& value) { struct lsLocation { + lsLocation(); + lsLocation(lsDocumentUri uri, lsRange range); + + bool operator==(const lsLocation& other) const; + lsDocumentUri uri; lsRange range; - - lsLocation() {} - lsLocation(lsDocumentUri uri, lsRange range) : uri(uri), range(range) {} - - bool operator==(const lsLocation& other) const { - return uri == other.uri && range == other.range; - } }; -MAKE_HASHABLE(lsLocation, t.uri, t.range); - +MAKE_HASHABLE(lsLocation, t.uri, t.range) template void Reflect(TVisitor& visitor, lsLocation& value) { REFLECT_MEMBER_START(); @@ -498,15 +334,7 @@ enum class lsSymbolKind : int { Boolean = 17, Array = 18 }; - -void Reflect(Writer& writer, lsSymbolKind& value) { - writer.Int(static_cast(value)); -} - -void Reflect(Reader& reader, lsSymbolKind& value) { - value = static_cast(reader.GetInt()); -} - +MAKE_REFLECT_TYPE_PROXY(lsSymbolKind, int) struct lsSymbolInformation { std::string name; @@ -955,30 +783,8 @@ struct lsInitializeParams { // The initial trace setting. If omitted trace is disabled ('off'). lsTrace trace = lsTrace::Off; }; - -void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) { - std::string v = reader.GetString(); - if (v == "off") - value = lsInitializeParams::lsTrace::Off; - else if (v == "messages") - value = lsInitializeParams::lsTrace::Messages; - else if (v == "verbose") - value = lsInitializeParams::lsTrace::Verbose; -} - -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; - } -} +void Reflect(Reader& reader, lsInitializeParams::lsTrace& value); +void Reflect(Writer& writer, lsInitializeParams::lsTrace& value); template void Reflect(TVisitor& visitor, lsInitializeParams& value) { @@ -1020,13 +826,7 @@ enum class lsTextDocumentSyncKind { // send. Incremental = 2 }; - -template -void Reflect(TVisitor& visitor, lsTextDocumentSyncKind& value) { - int value0 = static_cast(value); - Reflect(visitor, value0); - value = static_cast(value0); -} +MAKE_REFLECT_TYPE_PROXY(lsTextDocumentSyncKind, int) // Completion options. struct lsCompletionOptions { @@ -1230,7 +1030,7 @@ void Reflect(TVisitor& visitor, lsInitializeResult& value) { struct Ipc_InitializeRequest : public IpcMessage { const static IpcId kIpcId = IpcId::Initialize; - RequestId id; + lsRequestId id; lsInitializeParams params; }; template @@ -1242,7 +1042,7 @@ void Reflect(TVisitor& visitor, Ipc_InitializeRequest& value) { } struct Out_InitializeResponse : public lsOutMessage { - RequestId id; + lsRequestId id; lsInitializeResult result; }; template @@ -1257,7 +1057,7 @@ void Reflect(TVisitor& visitor, Out_InitializeResponse& value) { struct Ipc_InitializedNotification : public IpcMessage { const static IpcId kIpcId = IpcId::Initialized; - RequestId id; + lsRequestId id; }; template void Reflect(TVisitor& visitor, Ipc_InitializedNotification& value) { @@ -1310,7 +1110,7 @@ void Reflect(TVisitor& visitor, Ipc_InitializedNotification& value) { // Cancel an existing request. struct Ipc_CancelRequest : public IpcMessage { static const IpcId kIpcId = IpcId::CancelRequest; - RequestId id; + lsRequestId id; }; template void Reflect(TVisitor& visitor, Ipc_CancelRequest& value) { @@ -1332,7 +1132,7 @@ void Reflect(TVisitor& visitor, lsDocumentSymbolParams& value) { struct Ipc_TextDocumentDocumentSymbol : public IpcMessage { const static IpcId kIpcId = IpcId::TextDocumentDocumentSymbol; - RequestId id; + lsRequestId id; lsDocumentSymbolParams params; }; template @@ -1343,7 +1143,7 @@ void Reflect(TVisitor& visitor, Ipc_TextDocumentDocumentSymbol& value) { REFLECT_MEMBER_END(); } struct Out_TextDocumentDocumentSymbol : public lsOutMessage { - RequestId id; + lsRequestId id; std::vector result; }; template @@ -1376,25 +1176,12 @@ struct lsCodeLensCommandArguments { lsPosition position; std::vector locations; }; -void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) { - visitor.StartArray(); - Reflect(visitor, value.uri); - Reflect(visitor, value.position); - Reflect(visitor, value.locations); - visitor.EndArray(); -} -void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) { - auto it = visitor.Begin(); - Reflect(*it, value.uri); - ++it; - Reflect(*it, value.position); - ++it; - Reflect(*it, value.locations); -} +void Reflect(Writer& visitor, lsCodeLensCommandArguments& value); +void Reflect(Reader& visitor, lsCodeLensCommandArguments& value); using TCodeLens = lsCodeLens; struct Ipc_TextDocumentCodeLens : public IpcMessage { const static IpcId kIpcId = IpcId::TextDocumentCodeLens; - RequestId id; + lsRequestId id; lsDocumentCodeLensParams params; }; template @@ -1405,7 +1192,7 @@ void Reflect(TVisitor& visitor, Ipc_TextDocumentCodeLens& value) { REFLECT_MEMBER_END(); } struct Out_TextDocumentCodeLens : public lsOutMessage { - RequestId id; + lsRequestId id; std::vector> result; }; template @@ -1419,7 +1206,7 @@ void Reflect(TVisitor& visitor, Out_TextDocumentCodeLens& value) { struct Ipc_CodeLensResolve : public IpcMessage { const static IpcId kIpcId = IpcId::CodeLensResolve; - RequestId id; + lsRequestId id; TCodeLens params; }; template @@ -1430,7 +1217,7 @@ void Reflect(TVisitor& visitor, Ipc_CodeLensResolve& value) { REFLECT_MEMBER_END(); } struct Out_CodeLensResolve : public lsOutMessage { - RequestId id; + lsRequestId id; TCodeLens result; }; template @@ -1454,7 +1241,7 @@ void Reflect(TVisitor& visitor, lsWorkspaceSymbolParams& value) { } struct Ipc_WorkspaceSymbol : public IpcMessage { const static IpcId kIpcId = IpcId::WorkspaceSymbol; - RequestId id; + lsRequestId id; lsWorkspaceSymbolParams params; }; template @@ -1465,7 +1252,7 @@ void Reflect(TVisitor& visitor, Ipc_WorkspaceSymbol& value) { REFLECT_MEMBER_END(); } struct Out_WorkspaceSymbol : public lsOutMessage { - RequestId id; + lsRequestId id; std::vector result; }; template @@ -1484,12 +1271,7 @@ enum class lsMessageType : int { Info = 3, Log = 4 }; -template -void Reflect(TWriter& writer, lsMessageType& value) { - int value0 = static_cast(value); - Reflect(writer, value0); - value = static_cast(value0); -} +MAKE_REFLECT_TYPE_PROXY(lsMessageType, int) struct Out_ShowLogMessageParams { lsMessageType type = lsMessageType::Error; std::string message; @@ -1506,12 +1288,8 @@ struct Out_ShowLogMessage : public lsOutMessage { Show, Log }; DisplayType display_type = DisplayType::Show; - std::string method() { - if (display_type == DisplayType::Log) - return "window/logMessage"; - return "window/showMessage"; - } - + + std::string method(); Out_ShowLogMessageParams params; }; template diff --git a/src/serializer.h b/src/serializer.h index ca6dd59e..3abcb3ea 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -30,6 +30,15 @@ struct IndexedFile; ReflectMember(visitor, name, value) +#define MAKE_REFLECT_TYPE_PROXY(type, as_type) \ + template \ + void Reflect(TVisitor& visitor, type& value) { \ + auto value0 = static_cast(value); \ + Reflect(visitor, value0); \ + value = static_cast(value0); \ + } + + // API: /* template