From 1508ac85d8cace7bdf9fdf456753a6024959008b Mon Sep 17 00:00:00 2001 From: Jacob Dufault Date: Thu, 9 Mar 2017 23:06:01 -0800 Subject: [PATCH] fixes --- command_line.cc | 162 ++- indexer.cpp | 12 +- language_server_api.h | 2654 +++++++++++++++++++------------------- serializer.h | 1 - test.cc | 9 +- test.h | 3 + tests/outline/outline.cc | 19 + 7 files changed, 1433 insertions(+), 1427 deletions(-) create mode 100644 test.h create mode 100644 tests/outline/outline.cc diff --git a/command_line.cc b/command_line.cc index 45a209be..1b1cce5a 100644 --- a/command_line.cc +++ b/command_line.cc @@ -1,4 +1,3 @@ -#if false #include #include #include @@ -10,6 +9,7 @@ #include "ipc.h" #include "query.h" #include "language_server_api.h" +#include "test.h" #include "third_party/tiny-process-library/process.hpp" @@ -21,7 +21,6 @@ #include #endif - std::unordered_map ParseOptions(int argc, char** argv) { std::unordered_map output; @@ -54,7 +53,7 @@ bool HasOption(const std::unordered_map& options, cons -std::unique_ptr ParseMessage() { +std::unique_ptr ParseMessage() { int content_length = -1; int iteration = 0; while (true) { @@ -93,7 +92,7 @@ std::unique_ptr ParseMessage() { document.Parse(content.c_str(), content_length); assert(!document.HasParseError()); - return language_server_api::MessageRegistry::instance()->Parse(document); + return MessageRegistry::instance()->Parse(document); } @@ -176,51 +175,49 @@ IpcMessageId IpcMessage_OpenProject::kId = "OpenProject"; struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage { - language_server_api::RequestId id; + RequestId id; std::string document; // BaseIpcMessage: static IpcMessageId kId; - void Serialize(Writer& writer) override { - using namespace language_server_api; + void Serialize(Writer& visitor) override { + // TODO: dedup auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(id); - SERIALIZE_MEMBER(document); - writer.EndObject(); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(document); + REFLECT_MEMBER_END(); } - void Deserialize(Reader& reader) override { - using namespace language_server_api; + void Deserialize(Reader& visitor) override { + // TODO: dedup auto& value = *this; - - DESERIALIZE_MEMBER(id); - DESERIALIZE_MEMBER(document); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(document); + REFLECT_MEMBER_END(); } }; IpcMessageId IpcMessage_DocumentSymbolsRequest::kId = "IpcMessage_DocumentSymbolsRequest"; struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage { - language_server_api::RequestId id; - std::vector symbols; + RequestId id; + std::vector symbols; // BaseIpcMessage: static IpcMessageId kId; - void Serialize(Writer& writer) override { - using namespace language_server_api; + void Serialize(Writer& visitor) override { auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(id); - SERIALIZE_MEMBER(symbols); - writer.EndObject(); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(symbols); + REFLECT_MEMBER_END(); } - void Deserialize(Reader& reader) override { - using namespace language_server_api; + void Deserialize(Reader& visitor) override { auto& value = *this; - - DESERIALIZE_MEMBER(id); - DESERIALIZE_MEMBER(symbols); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(symbols); + REFLECT_MEMBER_END(); } }; IpcMessageId IpcMessage_DocumentSymbolsResponse::kId = "IpcMessage_DocumentSymbolsResponse"; @@ -231,51 +228,47 @@ IpcMessageId IpcMessage_DocumentSymbolsResponse::kId = "IpcMessage_DocumentSymbo struct IpcMessage_WorkspaceSymbolsRequest : public BaseIpcMessage { - language_server_api::RequestId id; + RequestId id; std::string query; // BaseIpcMessage: static IpcMessageId kId; - void Serialize(Writer& writer) override { - using namespace language_server_api; + void Serialize(Writer& visitor) override { auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(id); - SERIALIZE_MEMBER(query); - writer.EndObject(); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(query); + REFLECT_MEMBER_END(); } - void Deserialize(Reader& reader) override { - using namespace language_server_api; + void Deserialize(Reader& visitor) override { auto& value = *this; - - DESERIALIZE_MEMBER(id); - DESERIALIZE_MEMBER(query); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(query); + REFLECT_MEMBER_END(); } }; IpcMessageId IpcMessage_WorkspaceSymbolsRequest::kId = "IpcMessage_WorkspaceSymbolsRequest"; struct IpcMessage_WorkspaceSymbolsResponse : public BaseIpcMessage { - language_server_api::RequestId id; - std::vector symbols; + RequestId id; + std::vector symbols; // BaseIpcMessage: static IpcMessageId kId; - void Serialize(Writer& writer) override { - using namespace language_server_api; + void Serialize(Writer& visitor) override { auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(id); - SERIALIZE_MEMBER(symbols); - writer.EndObject(); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(symbols); + REFLECT_MEMBER_END(); } - void Deserialize(Reader& reader) override { - using namespace language_server_api; + void Deserialize(Reader& visitor) override { auto& value = *this; - - DESERIALIZE_MEMBER(id); - DESERIALIZE_MEMBER(symbols); + REFLECT_MEMBER_START(); + REFLECT_MEMBER(id); + REFLECT_MEMBER(symbols); + REFLECT_MEMBER_END(); } }; IpcMessageId IpcMessage_WorkspaceSymbolsResponse::kId = "IpcMessage_WorkspaceSymbolsResponse"; @@ -308,8 +301,6 @@ IpcMessageId IpcMessage_WorkspaceSymbolsResponse::kId = "IpcMessage_WorkspaceSym void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { - using namespace language_server_api; - std::vector> messages = ipc->TakeMessages(); for (auto& message : messages) { @@ -361,7 +352,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { for (UsrRef ref : file.outline) { SymbolIdx symbol = db->usr_to_symbol[ref.usr]; - SymbolInformation info; + lsSymbolInformation info; info.location.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1. info.location.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1. // TODO: store range information. @@ -374,20 +365,20 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { { QueryableTypeDef& def = db->types[symbol.idx]; info.name = def.def.qualified_name; - info.kind = language_server_api::SymbolKind::Class; + info.kind = lsSymbolKind::Class; break; } - case ::SymbolKind::Func: + case SymbolKind::Func: { QueryableFuncDef& def = db->funcs[symbol.idx]; info.name = def.def.qualified_name; if (def.def.declaring_type.has_value()) { - info.kind = language_server_api::SymbolKind::Method; + info.kind = lsSymbolKind::Method; Usr declaring = def.def.declaring_type.value(); info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; } else { - info.kind = language_server_api::SymbolKind::Function; + info.kind = lsSymbolKind::Function; } break; } @@ -395,7 +386,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { { QueryableVarDef& def = db->vars[symbol.idx]; info.name = def.def.qualified_name; - info.kind = language_server_api::SymbolKind::Variable; + info.kind = lsSymbolKind::Variable; break; } }; @@ -430,7 +421,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { if (name.find(msg->query) != std::string::npos) { - SymbolInformation info; + lsSymbolInformation info; info.name = name; SymbolIdx symbol = db->symbols[i]; @@ -442,7 +433,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { { QueryableTypeDef& def = db->types[symbol.idx]; info.name = def.def.qualified_name; - info.kind = language_server_api::SymbolKind::Class; + info.kind = lsSymbolKind::Class; if (def.def.definition.has_value()) { info.location.range.start.line = def.def.definition->line - 1; @@ -455,12 +446,12 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { QueryableFuncDef& def = db->funcs[symbol.idx]; info.name = def.def.qualified_name; if (def.def.declaring_type.has_value()) { - info.kind = language_server_api::SymbolKind::Method; + info.kind = lsSymbolKind::Method; Usr declaring = def.def.declaring_type.value(); info.containerName = db->types[db->usr_to_symbol[declaring].idx].def.qualified_name; } else { - info.kind = language_server_api::SymbolKind::Function; + info.kind = lsSymbolKind::Function; } if (def.def.definition.has_value()) { @@ -473,7 +464,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { { QueryableVarDef& def = db->vars[symbol.idx]; info.name = def.def.qualified_name; - info.kind = language_server_api::SymbolKind::Variable; + info.kind = lsSymbolKind::Variable; if (def.def.definition.has_value()) { info.location.range.start.line = def.def.definition->line - 1; @@ -546,8 +537,6 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) { // // |ipc| is connected to a server. void LanguageServerStdinLoop(IpcClient* ipc) { - using namespace language_server_api; - while (true) { std::unique_ptr message = ParseMessage(); @@ -557,7 +546,7 @@ void LanguageServerStdinLoop(IpcClient* ipc) { std::cerr << "[info]: Got message of type " << MethodIdToString(message->method_id) << std::endl; switch (message->method_id) { - case MethodId::Initialize: + case lsMethodId::Initialize: { auto request = static_cast(message.get()); if (request->params.rootUri) { @@ -576,7 +565,7 @@ void LanguageServerStdinLoop(IpcClient* ipc) { break; } - case MethodId::TextDocumentDocumentSymbol: + case lsMethodId::TextDocumentDocumentSymbol: { // TODO: response should take id as input. // TODO: message should not have top-level id. @@ -590,7 +579,7 @@ void LanguageServerStdinLoop(IpcClient* ipc) { break; } - case MethodId::WorkspaceSymbol: + case lsMethodId::WorkspaceSymbol: { auto request = static_cast(message.get()); IpcMessage_WorkspaceSymbolsRequest ipc_request; @@ -605,8 +594,6 @@ void LanguageServerStdinLoop(IpcClient* ipc) { } void LanguageServerMainLoop(IpcClient* ipc) { - using namespace language_server_api; - std::vector> messages = ipc->TakeMessages(); for (auto& message : messages) { if (IpcMessage_Quit::kId == message->runtime_id()) { @@ -763,7 +750,12 @@ void LanguageServerMain(std::string process_name) { -int mai2525252n(int argc, char** argv) { +int main(int argc, char** argv) { + if (argc == 1) { + RunTests(); + return 0; + } + // We need to write to stdout in binary mode because in Windows, writing // \n will implicitly write \r\n. Language server API will ignore a // \r\r\n split request. @@ -783,11 +775,11 @@ int mai2525252n(int argc, char** argv) { IpcRegistry::instance()->Register(); IpcRegistry::instance()->Register(); - language_server_api::MessageRegistry::instance()->Register(); - language_server_api::MessageRegistry::instance()->Register(); - language_server_api::MessageRegistry::instance()->Register(); - language_server_api::MessageRegistry::instance()->Register(); - language_server_api::MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); + MessageRegistry::instance()->Register(); @@ -820,5 +812,3 @@ int mai2525252n(int argc, char** argv) { return 1; } - -#endif \ No newline at end of file diff --git a/indexer.cpp b/indexer.cpp index 6354d35c..9e540466 100644 --- a/indexer.cpp +++ b/indexer.cpp @@ -284,7 +284,7 @@ struct NamespaceHelper { // Anonymous namespaces are not processed by indexDeclaration. If we // encounter one insert it into map. if (container->cursor.kind == CXCursor_Namespace) { - assert(clang::Cursor(container->cursor).get_spelling() == ""); + //assert(clang::Cursor(container->cursor).get_spelling() == ""); container_usr_to_qualified_name[container_usr] = "::"; return "::" + unqualified_name; } @@ -940,11 +940,11 @@ void indexEntityReference(CXClientData client_data, const CXIdxEntityRefInfo* re IndexedFuncDef* called_def = db->Resolve(called_id); // I suspect it is possible for the declaring type to be null // when the class is invalid. - //if (called_def->def.declaring_type) { - assert(called_def->def.declaring_type.has_value()); - IndexedTypeDef* type_def = db->Resolve(called_def->def.declaring_type.value()); - type_def->AddUsage(our_loc); - //} + if (called_def->def.declaring_type) { + //assert(called_def->def.declaring_type.has_value()); + IndexedTypeDef* type_def = db->Resolve(called_def->def.declaring_type.value()); + type_def->AddUsage(our_loc); + } } } break; diff --git a/language_server_api.h b/language_server_api.h index 82afdce8..dbe62e07 100644 --- a/language_server_api.h +++ b/language_server_api.h @@ -11,23 +11,20 @@ using std::experimental::optional; using std::experimental::nullopt; -namespace language_server_api { +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////// OUTGOING MESSAGES ///////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////// OUTGOING MESSAGES ///////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// +struct RequestId { + optional id0; + optional id1; +}; - struct RequestId { - optional id0; - optional id1; - }; -} - -void Reflect(Writer& visitor, language_server_api::RequestId& value) { +void Reflect(Writer& visitor, RequestId& value) { if (value.id0) { Reflect(visitor, value.id0.value()); } @@ -37,7 +34,7 @@ void Reflect(Writer& visitor, language_server_api::RequestId& value) { } } -void Reflect(Reader& visitor, language_server_api::RequestId& id) { +void Reflect(Reader& visitor, RequestId& id) { if (visitor.IsInt()) Reflect(visitor, id.id0); else if (visitor.IsString()) @@ -46,1352 +43,1349 @@ void Reflect(Reader& visitor, language_server_api::RequestId& id) { std::cerr << "Unable to deserialize id" << std::endl; } -namespace language_server_api { - - struct OutMessage { - // Write out the body of the message. The writer expects object key/value - // pairs. - virtual void WriteMessageBody(Writer& writer) = 0; - - // Send the message to the language client by writing it to stdout. - void Send() { - rapidjson::StringBuffer output; - Writer writer(output); - writer.StartObject(); - writer.Key("jsonrpc"); - writer.String("2.0"); - WriteMessageBody(writer); - writer.EndObject(); - - std::cout << "Content-Length: " << output.GetSize(); - std::cout << (char)13 << char(10) << char(13) << char(10); - std::cout << output.GetString(); - std::cout.flush(); - } - }; - - struct OutRequestMessage : OutMessage { - RequestId id; - - virtual std::string Method() = 0; - virtual void SerializeParams(Writer& visitor) = 0; - - // Message: - void WriteMessageBody(Writer& visitor) override { - auto& value = *this; - auto method = Method(); - - REFLECT_MEMBER(id); - REFLECT_MEMBER2("method", method); - - visitor.Key("params"); - SerializeParams(visitor); - } - }; - - - struct ResponseError { - struct Data { - virtual void Write(Writer& writer) = 0; - }; - - enum class ErrorCodes : int { - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - serverErrorStart = -32099, - serverErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001 - }; - - ErrorCodes code; - // Short description. - 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(); - } - }; - - struct OutResponseMessage : OutMessage { - RequestId id; - - virtual optional Error() { - return nullopt; - } - virtual void WriteResult(Writer& visitor) = 0; - - // Message: - void WriteMessageBody(Writer& visitor) override { - auto& value = *this; - - REFLECT_MEMBER(id); - - optional error = Error(); - if (error) { - visitor.Key("error"); - error->Write(visitor); - } - else { - visitor.Key("result"); - WriteResult(visitor); - } - } - }; - - struct OutNotificationMessage : OutMessage { - virtual std::string Method() = 0; - virtual void SerializeParams(Writer& writer) = 0; - - // Message: - void WriteMessageBody(Writer& visitor) override { - visitor.Key("method"); - std::string method = Method(); - Reflect(visitor, method); - - visitor.Key("params"); - SerializeParams(visitor); - } - }; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////// INCOMING MESSAGES ///////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - - enum class MethodId { - CancelRequest, - Initialize, - Initialized, - TextDocumentDocumentSymbol, - WorkspaceSymbol, - }; - - const char* MethodIdToString(MethodId id) { - switch (id) { - case MethodId::CancelRequest: - return "$/cancelRequest"; - case MethodId::Initialize: - return "initialize"; - case MethodId::Initialized: - return "initialized"; - case MethodId::TextDocumentDocumentSymbol: - return "textDocument/documentSymbol"; - case MethodId::WorkspaceSymbol: - return "workspace/symbol"; - default: - exit(1); - } - } - - struct InMessage; - - struct MessageRegistry { - static MessageRegistry* instance_; - static MessageRegistry* instance(); - - using Allocator = std::function(optional id, const Reader& params)>; - std::unordered_map allocators; - - template - void Register() { - std::string method_name = MethodIdToString(T::kMethod); - allocators[method_name] = [](optional id, const Reader& params) { - return MakeUnique(id, params); - }; - } - - std::unique_ptr Parse(const Reader& visitor) { - std::string jsonrpc = visitor["jsonrpc"].GetString(); - if (jsonrpc != "2.0") - exit(1); - - optional id; - if (visitor.FindMember("id") != visitor.MemberEnd()) - ::Deserialize(visitor["id"], id); - - std::string method; - ::Deserialize(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]; - - - // We run the allocator with actual params object or a null - // params object if there are no params. Unifying the two ifs is - // tricky because the second allocator param is a reference. - if (visitor.FindMember("params") != visitor.MemberEnd()) { - const Reader& params = visitor["params"]; - return allocator(id, params); - } - else { - Reader params; - params.SetNull(); - return allocator(id, params); - } - } - }; - - MessageRegistry* MessageRegistry::instance_ = nullptr; - MessageRegistry* MessageRegistry::instance() { - if (!instance_) - instance_ = new MessageRegistry(); - - return instance_; - } - - - struct InMessage { - const MethodId method_id; - optional id; - - InMessage(MethodId method_id, optional id, const Reader& reader) - // We verify there are no duplicate hashes inside of MessageRegistry. - : method_id(method_id), id(id) {} - }; - - struct InRequestMessage : public InMessage { - InRequestMessage(MethodId method, optional id, const Reader& reader) - : InMessage(method, id, reader) {} - }; - - struct InNotificationMessage : public InMessage { - InNotificationMessage(MethodId method, optional id, const Reader& reader) - : InMessage(method, id, reader) {} - }; - - - - - - - - - - - - - - - struct In_CancelRequest : public InNotificationMessage { - static const MethodId kMethod = MethodId::CancelRequest; - - In_CancelRequest(optional id, const Reader& reader) - : InNotificationMessage(kMethod, id, reader) {} - }; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ////////////////////////////// PRIMITIVE TYPES ////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - - // Keep all types in the language_server_api namespace in sync with language server spec. - // TODO - struct DocumentUri { - std::string raw_uri; - - 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; - } - }; - - template - void Reflect(TVisitor& visitor, DocumentUri& value) { - Reflect(visitor, value.raw_uri); - } - - - struct Position { - // Note: these are 0-based. - int line = 0; - int character = 0; - }; - - template - void Reflect(TVisitor& visitor, Position& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(line); - REFLECT_MEMBER(character); - REFLECT_MEMBER_END(); - } - - - struct Range { - Position start; - Position end; - }; - - template - void Reflect(TVisitor& visitor, Range& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(start); - REFLECT_MEMBER(end); - REFLECT_MEMBER_END(); - } - - - struct Location { - DocumentUri uri; - Range range; - }; - - template - void Reflect(TVisitor& visitor, Location& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(uri); - REFLECT_MEMBER(range); - REFLECT_MEMBER_END(); - } - - - enum class SymbolKind : int { - File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18 - }; - - void Reflect(Writer& writer, SymbolKind& value) { - writer.Int(static_cast(value)); - } - - void Reflect(Reader& reader, SymbolKind& value) { - value = static_cast(reader.GetInt()); - } - - - struct SymbolInformation { - std::string name; - SymbolKind kind; - Location location; - std::string containerName; - }; - - template - void Reflect(TVisitor& visitor, SymbolInformation& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(name); - REFLECT_MEMBER(kind); - REFLECT_MEMBER(location); - REFLECT_MEMBER(containerName); - REFLECT_MEMBER_END(); - } - - - struct Command { - // Title of the command (ie, 'save') - std::string title; - // Actual command identifier. - std::string command; - // Arguments to run the command with. Could be JSON objects. - std::vector arguments; - }; - - template - void Reflect(TVisitor& visitor, Command& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(title); - REFLECT_MEMBER(command); - REFLECT_MEMBER(arguments); - REFLECT_MEMBER_END(); - } - - - // TODO: TextDocumentEdit - // TODO: WorkspaceEdit - - struct TextDocumentIdentifier { - DocumentUri uri; - }; - - void Serialize(Writer& writer, const TextDocumentIdentifier& value) { +struct OutMessage { + // Write out the body of the message. The writer expects object key/value + // pairs. + virtual void WriteMessageBody(Writer& writer) = 0; + + // Send the message to the language client by writing it to stdout. + void Send() { + rapidjson::StringBuffer output; + Writer writer(output); writer.StartObject(); - SERIALIZE_MEMBER(uri); + writer.Key("jsonrpc"); + writer.String("2.0"); + WriteMessageBody(writer); writer.EndObject(); + + std::cout << "Content-Length: " << output.GetSize(); + std::cout << (char)13 << char(10) << char(13) << char(10); + std::cout << output.GetString(); + std::cout.flush(); } +}; - void Deserialize(const Reader& reader, TextDocumentIdentifier& value) { - DESERIALIZE_MEMBER(uri); +struct OutRequestMessage : public OutMessage { + RequestId id; + + virtual std::string Method() = 0; + virtual void SerializeParams(Writer& visitor) = 0; + + // Message: + void WriteMessageBody(Writer& visitor) override { + auto& value = *this; + auto method = Method(); + + REFLECT_MEMBER(id); + REFLECT_MEMBER2("method", method); + + visitor.Key("params"); + SerializeParams(visitor); } +}; - // TODO: TextDocumentItem - // TODO: VersionedTextDocumentIdentifier - // TODO: TextDocumentPositionParams - // TODO: DocumentFilter - // TODO: DocumentSelector - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ////////////////////////////// INITIALIZATION /////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - - // Workspace specific client capabilities. - struct WorkspaceClientCapabilites { - // The client supports applying batch edits to the workspace. - optional applyEdit; - - struct WorkspaceEdit { - // The client supports versioned document changes in `WorkspaceEdit`s - optional documentChanges; - }; - - // Capabilities specific to `WorkspaceEdit`s - optional workspaceEdit; - - - struct GenericDynamicReg { - // Did foo notification supports dynamic registration. - optional dynamicRegistration; - }; - - - // Capabilities specific to the `workspace/didChangeConfiguration` notification. - optional didChangeConfiguration; - - // Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - optional didChangeWatchedFiles; - - // Capabilities specific to the `workspace/symbol` request. - optional symbol; - - // Capabilities specific to the `workspace/executeCommand` request. - optional executeCommand; +struct lsResponseError { + struct Data { + virtual void Write(Writer& writer) = 0; }; - template - void Reflect(TVisitor& visitor, WorkspaceClientCapabilites::WorkspaceEdit& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(documentChanges); - REFLECT_MEMBER_END(); + enum class lsErrorCodes : int { + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + serverErrorStart = -32099, + serverErrorEnd = -32000, + ServerNotInitialized = -32002, + UnknownErrorCode = -32001 + }; + + lsErrorCodes code; + // Short description. + 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(); + } +}; + +struct OutResponseMessage : public OutMessage { + RequestId id; + + virtual optional Error() { + return nullopt; + } + virtual void WriteResult(Writer& visitor) = 0; + + // Message: + void WriteMessageBody(Writer& visitor) override { + auto& value = *this; + + REFLECT_MEMBER(id); + + optional error = Error(); + if (error) { + visitor.Key("error"); + error->Write(visitor); + } + else { + visitor.Key("result"); + WriteResult(visitor); + } + } +}; + +struct OutNotificationMessage : public OutMessage { + virtual std::string Method() = 0; + virtual void SerializeParams(Writer& writer) = 0; + + // Message: + void WriteMessageBody(Writer& visitor) override { + visitor.Key("method"); + std::string method = Method(); + ::Reflect(visitor, method); + + visitor.Key("params"); + SerializeParams(visitor); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////// INCOMING MESSAGES ///////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +enum class lsMethodId { + CancelRequest, + Initialize, + Initialized, + TextDocumentDocumentSymbol, + WorkspaceSymbol, +}; + +const char* MethodIdToString(lsMethodId id) { + switch (id) { + case lsMethodId::CancelRequest: + return "$/cancelRequest"; + case lsMethodId::Initialize: + return "initialize"; + case lsMethodId::Initialized: + return "initialized"; + case lsMethodId::TextDocumentDocumentSymbol: + return "textDocument/documentSymbol"; + case lsMethodId::WorkspaceSymbol: + return "workspace/symbol"; + default: + exit(1); + } +} + +struct InMessage; + +struct MessageRegistry { + static MessageRegistry* instance_; + static MessageRegistry* instance(); + + using Allocator = std::function(optional id, Reader& params)>; + std::unordered_map allocators; + + template + void Register() { + std::string method_name = MethodIdToString(T::kMethod); + allocators[method_name] = [](optional id, Reader& params) { + return MakeUnique(id, params); + }; } - template - void Reflect(TVisitor& visitor, WorkspaceClientCapabilites::GenericDynamicReg& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(dynamicRegistration); - REFLECT_MEMBER_END(); - } + std::unique_ptr Parse(Reader& visitor) { + std::string jsonrpc = visitor["jsonrpc"].GetString(); + if (jsonrpc != "2.0") + exit(1); - template - void Reflect(TVisitor& visitor, WorkspaceClientCapabilites& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(applyEdit); - REFLECT_MEMBER(workspaceEdit); - REFLECT_MEMBER(didChangeConfiguration); - REFLECT_MEMBER(didChangeWatchedFiles); - REFLECT_MEMBER(symbol); - REFLECT_MEMBER(executeCommand); - REFLECT_MEMBER_END(); - } + optional id; + ReflectMember(visitor, "id", id); + 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]; + + + // We run the allocator with actual params object or a null + // params object if there are no params. Unifying the two ifs is + // tricky because the second allocator param is a reference. + if (visitor.FindMember("params") != visitor.MemberEnd()) { + Reader& params = visitor["params"]; + return allocator(id, params); + } + else { + Reader params; + params.SetNull(); + return allocator(id, params); + } + } +}; + +MessageRegistry* MessageRegistry::instance_ = nullptr; +MessageRegistry* MessageRegistry::instance() { + if (!instance_) + instance_ = new MessageRegistry(); + + return instance_; +} + + +struct InMessage { + const lsMethodId method_id; + optional id; + + InMessage(lsMethodId method_id, optional id, Reader& reader) + // We verify there are no duplicate hashes inside of MessageRegistry. + : method_id(method_id), id(id) {} +}; + +struct InRequestMessage : public InMessage { + InRequestMessage(lsMethodId method, optional id, Reader& reader) + : InMessage(method, id, reader) {} +}; + +struct InNotificationMessage : public InMessage { + InNotificationMessage(lsMethodId method, optional id, Reader& reader) + : InMessage(method, id, reader) {} +}; + + + + + + + + + + + + + + +struct In_CancelRequest : public InNotificationMessage { + static const lsMethodId kMethod = lsMethodId::CancelRequest; + + In_CancelRequest(optional id, Reader& reader) + : InNotificationMessage(kMethod, id, reader) {} +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +////////////////////////////// PRIMITIVE TYPES ////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +struct lsDocumentUri { + std::string raw_uri; + + 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; + } +}; + +template +void Reflect(TVisitor& visitor, lsDocumentUri& value) { + Reflect(visitor, value.raw_uri); +} + + +struct lsPosition { + // Note: these are 0-based. + int line = 0; + int character = 0; +}; + +template +void Reflect(TVisitor& visitor, lsPosition& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(line); + REFLECT_MEMBER(character); + REFLECT_MEMBER_END(); +} + + +struct lsRange { + lsPosition start; + lsPosition end; +}; + +template +void Reflect(TVisitor& visitor, lsRange& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(start); + REFLECT_MEMBER(end); + REFLECT_MEMBER_END(); +} + + +struct lsLocation { + lsDocumentUri uri; + lsRange range; +}; + +template +void Reflect(TVisitor& visitor, lsLocation& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(uri); + REFLECT_MEMBER(range); + REFLECT_MEMBER_END(); +} + + +enum class lsSymbolKind : int { + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + 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()); +} + + +struct lsSymbolInformation { + std::string name; + lsSymbolKind kind; + lsLocation location; + std::string containerName; +}; + +template +void Reflect(TVisitor& visitor, lsSymbolInformation& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(name); + REFLECT_MEMBER(kind); + REFLECT_MEMBER(location); + REFLECT_MEMBER(containerName); + REFLECT_MEMBER_END(); +} + + +struct lsCommand { + // Title of the command (ie, 'save') + std::string title; + // Actual command identifier. + std::string command; + // Arguments to run the command with. Could be JSON objects. + std::vector arguments; +}; + +template +void Reflect(TVisitor& visitor, lsCommand& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(title); + REFLECT_MEMBER(command); + REFLECT_MEMBER(arguments); + REFLECT_MEMBER_END(); +} + + +// TODO: TextDocumentEdit +// TODO: WorkspaceEdit + +struct lsTextDocumentIdentifier { + lsDocumentUri uri; +}; + +template +void Reflect(TVisitor& visitor, lsTextDocumentIdentifier& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(uri); + REFLECT_MEMBER_END(); +} + +// TODO: TextDocumentItem +// TODO: VersionedTextDocumentIdentifier +// TODO: TextDocumentPositionParams +// TODO: DocumentFilter +// TODO: DocumentSelector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +////////////////////////////// INITIALIZATION /////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// + +// Workspace specific client capabilities. +struct lsWorkspaceClientCapabilites { + // The client supports applying batch edits to the workspace. + optional applyEdit; + + struct lsWorkspaceEdit { + // The client supports versioned document changes in `WorkspaceEdit`s + optional documentChanges; + }; + + // Capabilities specific to `WorkspaceEdit`s + optional workspaceEdit; + + + struct lsGenericDynamicReg { + // Did foo notification supports dynamic registration. + optional dynamicRegistration; + }; + + + // Capabilities specific to the `workspace/didChangeConfiguration` notification. + optional didChangeConfiguration; + + // Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + optional didChangeWatchedFiles; + + // Capabilities specific to the `workspace/symbol` request. + optional symbol; + + // Capabilities specific to the `workspace/executeCommand` request. + optional executeCommand; +}; + +template +void Reflect(TVisitor& visitor, lsWorkspaceClientCapabilites::lsWorkspaceEdit& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(documentChanges); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsWorkspaceClientCapabilites::lsGenericDynamicReg& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(dynamicRegistration); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsWorkspaceClientCapabilites& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(applyEdit); + REFLECT_MEMBER(workspaceEdit); + REFLECT_MEMBER(didChangeConfiguration); + REFLECT_MEMBER(didChangeWatchedFiles); + REFLECT_MEMBER(symbol); + REFLECT_MEMBER(executeCommand); + REFLECT_MEMBER_END(); +} + + +// Text document specific client capabilities. +struct lsTextDocumentClientCapabilities { + struct lsSynchronization { + // Whether text document synchronization supports dynamic registration. + optional dynamicRegistration; + + // The client supports sending will save notifications. + optional willSave; + + // The client supports sending a will save request and + // waits for a response providing text edits which will + // be applied to the document before it is saved. + optional willSaveWaitUntil; + + // The client supports did save notifications. + optional didSave; + }; + + lsSynchronization synchronization; + + struct lsCompletion { + // Whether completion supports dynamic registration. + optional dynamicRegistration; + + struct lsCompletionItem { + // Client supports snippets as insert text. + // + // A snippet can define tab stops and placeholders with `$1`, `$2` + // and `${3:foo}`. `$0` defines the final tab stop, it defaults to + // the end of the snippet. Placeholders with equal identifiers are linked, + // that is typing in one will update others too. + optional snippetSupport; + }; + + // The client supports the following `CompletionItem` specific + // capabilities. + optional completionItem; + }; + // Capabilities specific to the `textDocument/completion` + optional completion; + + struct lsGenericDynamicReg { + // Whether foo supports dynamic registration. + optional dynamicRegistration; + }; + + // Capabilities specific to the `textDocument/hover` + optional hover; + + // Capabilities specific to the `textDocument/signatureHelp` + optional signatureHelp; + + // Capabilities specific to the `textDocument/references` + optional references; + + // Capabilities specific to the `textDocument/documentHighlight` + optional documentHighlight; + + // Capabilities specific to the `textDocument/documentSymbol` + optional documentSymbol; + + // Capabilities specific to the `textDocument/formatting` + optional formatting; + + // Capabilities specific to the `textDocument/rangeFormatting` + optional rangeFormatting; + + // Capabilities specific to the `textDocument/onTypeFormatting` + optional onTypeFormatting; + + // Capabilities specific to the `textDocument/definition` + optional definition; + + // Capabilities specific to the `textDocument/codeAction` + optional codeAction; + + // Capabilities specific to the `textDocument/codeLens` + optional codeLens; + + // Capabilities specific to the `textDocument/documentLink` + optional documentLink; + + // Capabilities specific to the `textDocument/rename` + optional rename; +}; + +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::lsSynchronization& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(dynamicRegistration); + REFLECT_MEMBER(willSave); + REFLECT_MEMBER(willSaveWaitUntil); + REFLECT_MEMBER(didSave); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::lsCompletion& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(dynamicRegistration); + REFLECT_MEMBER(completionItem); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::lsCompletion::lsCompletionItem& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(snippetSupport); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities::lsGenericDynamicReg& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(dynamicRegistration); + REFLECT_MEMBER_END(); +} + +template +void Reflect(TVisitor& visitor, lsTextDocumentClientCapabilities& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(synchronization); + REFLECT_MEMBER(completion); + REFLECT_MEMBER(hover); + REFLECT_MEMBER(signatureHelp); + REFLECT_MEMBER(references); + REFLECT_MEMBER(documentHighlight); + REFLECT_MEMBER(documentSymbol); + REFLECT_MEMBER(formatting); + REFLECT_MEMBER(rangeFormatting); + REFLECT_MEMBER(onTypeFormatting); + REFLECT_MEMBER(definition); + REFLECT_MEMBER(codeAction); + REFLECT_MEMBER(codeLens); + REFLECT_MEMBER(documentLink); + REFLECT_MEMBER(rename); + REFLECT_MEMBER_END(); +} + +struct lsClientCapabilities { + // Workspace specific client capabilities. + optional workspace; // Text document specific client capabilities. - struct TextDocumentClientCapabilities { - struct Synchronization { - // Whether text document synchronization supports dynamic registration. - optional dynamicRegistration; + optional textDocument; - // The client supports sending will save notifications. - optional willSave; + /** + * Experimental client capabilities. + */ + // experimental?: any; // TODO +}; - // The client supports sending a will save request and - // waits for a response providing text edits which will - // be applied to the document before it is saved. - optional willSaveWaitUntil; +template +void Reflect(TVisitor& visitor, lsClientCapabilities& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(workspace); + REFLECT_MEMBER(textDocument); + REFLECT_MEMBER_END(); +} - // The client supports did save notifications. - optional didSave; - }; +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. + optional processId; - Synchronization synchronization; + // The rootPath of the workspace. Is null + // if no folder is open. + // + // @deprecated in favour of rootUri. + optional rootPath; - struct Completion { - // Whether completion supports dynamic registration. - optional dynamicRegistration; + // The rootUri of the workspace. Is null if no + // folder is open. If both `rootPath` and `rootUri` are set + // `rootUri` wins. + optional rootUri; - struct CompletionItem { - // Client supports snippets as insert text. - // - // A snippet can define tab stops and placeholders with `$1`, `$2` - // and `${3:foo}`. `$0` defines the final tab stop, it defaults to - // the end of the snippet. Placeholders with equal identifiers are linked, - // that is typing in one will update others too. - optional snippetSupport; - }; + // User provided initialization options. + // initializationOptions?: any; // TODO - // The client supports the following `CompletionItem` specific - // capabilities. - optional completionItem; - }; - // Capabilities specific to the `textDocument/completion` - optional completion; + // The capabilities provided by the client (editor or tool) + lsClientCapabilities capabilities; - struct GenericDynamicReg { - // Whether foo supports dynamic registration. - optional dynamicRegistration; - }; - - // Capabilities specific to the `textDocument/hover` - optional hover; - - // Capabilities specific to the `textDocument/signatureHelp` - optional signatureHelp; - - // Capabilities specific to the `textDocument/references` - optional references; - - // Capabilities specific to the `textDocument/documentHighlight` - optional documentHighlight; - - // Capabilities specific to the `textDocument/documentSymbol` - optional documentSymbol; - - // Capabilities specific to the `textDocument/formatting` - optional formatting; - - // Capabilities specific to the `textDocument/rangeFormatting` - optional rangeFormatting; - - // Capabilities specific to the `textDocument/onTypeFormatting` - optional onTypeFormatting; - - // Capabilities specific to the `textDocument/definition` - optional definition; - - // Capabilities specific to the `textDocument/codeAction` - optional codeAction; - - // Capabilities specific to the `textDocument/codeLens` - optional codeLens; - - // Capabilities specific to the `textDocument/documentLink` - optional documentLink; - - // Capabilities specific to the `textDocument/rename` - optional rename; + enum class lsTrace { + // NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose'; + Off, // off + Messages, // messages + Verbose // verbose }; - template - void Reflect(TVisitor& visitor, TextDocumentClientCapabilities::Synchronization& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(dynamicRegistration); - REFLECT_MEMBER(willSave); - REFLECT_MEMBER(willSaveWaitUntil); - REFLECT_MEMBER(didSave); - REFLECT_MEMBER_END(); - } + // The initial trace setting. If omitted trace is disabled ('off'). + lsTrace trace = lsTrace::Off; +}; - template - void Reflect(TVisitor& visitor, TextDocumentClientCapabilities::Completion& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(dynamicRegistration); - REFLECT_MEMBER(completionItem); - REFLECT_MEMBER_END(); - } +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; +} - template - void Reflect(TVisitor& visitor, TextDocumentClientCapabilities::Completion::CompletionItem& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(snippetSupport); - REFLECT_MEMBER_END(); - } - - template - void Reflect(TVisitor& visitor, TextDocumentClientCapabilities::GenericDynamicReg& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(dynamicRegistration); - REFLECT_MEMBER_END(); - } - - template - void Reflect(TVisitor& visitor, TextDocumentClientCapabilities& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(synchronization); - REFLECT_MEMBER(completion); - REFLECT_MEMBER(hover); - REFLECT_MEMBER(signatureHelp); - REFLECT_MEMBER(references); - REFLECT_MEMBER(documentHighlight); - REFLECT_MEMBER(documentSymbol); - REFLECT_MEMBER(formatting); - REFLECT_MEMBER(rangeFormatting); - REFLECT_MEMBER(onTypeFormatting); - REFLECT_MEMBER(definition); - REFLECT_MEMBER(codeAction); - REFLECT_MEMBER(codeLens); - REFLECT_MEMBER(documentLink); - REFLECT_MEMBER(rename); - REFLECT_MEMBER_END(); - } - - struct ClientCapabilities { - // Workspace specific client capabilities. - optional workspace; - - // Text document specific client capabilities. - optional textDocument; - - /** - * Experimental client capabilities. - */ - // experimental?: any; // TODO - }; - - template - void Deserialize(TVisitor& visitor, ClientCapabilities& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(workspace); - REFLECT_MEMBER(textDocument); - REFLECT_MEMBER_END(); - } - - struct InitializeParams { - // 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. - optional processId; - - // The rootPath of the workspace. Is null - // if no folder is open. - // - // @deprecated in favour of rootUri. - optional rootPath; - - // The rootUri of the workspace. Is null if no - // folder is open. If both `rootPath` and `rootUri` are set - // `rootUri` wins. - optional rootUri; - - // User provided initialization options. - // initializationOptions?: any; // TODO - - // The capabilities provided by the client (editor or tool) - ClientCapabilities capabilities; - - enum class Trace { - // NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose'; - Off, // off - Messages, // messages - Verbose // verbose - }; - - // The initial trace setting. If omitted trace is disabled ('off'). - Trace trace = Trace::Off; - }; - - void Deserialize(const Reader& reader, InitializeParams::Trace& value) { - std::string v = reader.GetString(); - if (v == "off") - value = InitializeParams::Trace::Off; - else if (v == "messages") - value = InitializeParams::Trace::Messages; - else if (v == "verbose") - value = InitializeParams::Trace::Verbose; - } - - template - void Reflect(TVisitor& visitor, InitializeParams& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(processId); - REFLECT_MEMBER(rootPath); - REFLECT_MEMBER(rootUri); - REFLECT_MEMBER(capabilities); - REFLECT_MEMBER(trace); - REFLECT_MEMBER_END(); - } +template +void Reflect(TVisitor& visitor, lsInitializeParams& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(processId); + REFLECT_MEMBER(rootPath); + REFLECT_MEMBER(rootUri); + REFLECT_MEMBER(capabilities); + REFLECT_MEMBER(trace); + REFLECT_MEMBER_END(); +} #if false +/** + * Known error codes for an `InitializeError`; + */ +export namespace lsInitializeError { /** - * Known error codes for an `InitializeError`; + * If the protocol version provided by the client can't be handled by the server. + * @deprecated This initialize error got replaced by client capabilities. There is + * no version handshake in version 3.0x */ - export namespace InitializeError { - /** - * If the protocol version provided by the client can't be handled by the server. - * @deprecated This initialize error got replaced by client capabilities. There is - * no version handshake in version 3.0x - */ - export const unknownProtocolVersion : number = 1; - } + export const unknownProtocolVersion : number = 1; +} #endif - struct InitializeError { - // Indicates whether the client should retry to send the - // initilize request after showing the message provided - // in the ResponseError. - bool retry; - }; - - template - void Reflect(TVisitor& visitor, InitializeError& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(retry); - REFLECT_MEMBER_END(); - } - - // Defines how the host (editor) should sync document changes to the language server. - enum class TextDocumentSyncKind { - // Documents should not be synced at all. - None = 0, - - // Documents are synced by always sending the full content - // of the document. - Full = 1, - - // Documents are synced by sending the full content on open. - // After that only incremental updates to the document are - // send. - Incremental = 2 - }; - - void Reflect(Writer& writer, TextDocumentSyncKind& value) { - writer.Int(static_cast(value)); - } - - // Completion options. - struct CompletionOptions { - // The server provides support to resolve additional - // information for a completion item. - bool resolveProvider = false; - - // The characters that trigger completion automatically. - std::vector triggerCharacters; - }; - - template - void Reflect(TVisitor& visitor, CompletionOptions& value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(resolveProvider); - REFLECT_MEMBER(triggerCharacters); - REFLECT_MEMBER_END(); - } - - // Signature help options. - struct SignatureHelpOptions { - // The characters that trigger signature help automatically. - std::vector triggerCharacters; - }; - - template - void Serialize(TVisitor& visitor, SignatureHelpOptions& value) { - REFLECT_MEMBER_START(); - writer.StartObject(); - SERIALIZE_MEMBER(triggerCharacters); - writer.EndObject(); - } - - // Code Lens options. - struct CodeLensOptions { - // Code lens has a resolve provider as well. - bool resolveProvider = false; - }; - - void Serialize(Writer& writer, const CodeLensOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(resolveProvider); - writer.EndObject(); - } - - // Format document on type options - struct DocumentOnTypeFormattingOptions { - // A character on which formatting should be triggered, like `}`. - std::string firstTriggerCharacter; - - // More trigger characters. - std::vector moreTriggerCharacter; - }; - - void Serialize(Writer& writer, const DocumentOnTypeFormattingOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(firstTriggerCharacter); - SERIALIZE_MEMBER(moreTriggerCharacter); - writer.EndObject(); - } - - // Document link options - struct DocumentLinkOptions { - // Document links have a resolve provider as well. - bool resolveProvider = false; - }; - - void Serialize(Writer& writer, const DocumentLinkOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(resolveProvider); - writer.EndObject(); - } - - // Execute command options. - struct ExecuteCommandOptions { - // The commands to be executed on the server - std::vector commands; - }; - - void Serialize(Writer& writer, const ExecuteCommandOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(commands); - writer.EndObject(); - } - - // Save options. - struct SaveOptions { - // The client is supposed to include the content on save. - bool includeText = false; - }; - - void Serialize(Writer& writer, const SaveOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(includeText); - writer.EndObject(); - } - - struct TextDocumentSyncOptions { - // Open and close notifications are sent to the server. - bool openClose = false; - // Change notificatins are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full - // and TextDocumentSyncKindIncremental. - optional change; - // Will save notifications are sent to the server. - bool willSave = false; - // Will save wait until requests are sent to the server. - bool willSaveWaitUntil = false; - // Save notifications are sent to the server. - optional save; - }; - - void Serialize(Writer& writer, const TextDocumentSyncOptions& value) { - writer.StartObject(); - SERIALIZE_MEMBER(openClose); - SERIALIZE_MEMBER(change); - SERIALIZE_MEMBER(willSave); - SERIALIZE_MEMBER(willSaveWaitUntil); - SERIALIZE_MEMBER(save); - writer.EndObject(); - } - - struct ServerCapabilities { - // Defines how text documents are synced. Is either a detailed structure defining each notification or - // for backwards compatibility the TextDocumentSyncKind number. - optional textDocumentSync; - // The server provides hover support. - bool hoverProvider = false; - // The server provides completion support. - optional completionProvider; - // The server provides signature help support. - optional signatureHelpProvider; - // The server provides goto definition support. - bool definitionProvider = false; - // The server provides find references support. - bool referencesProvider = false; - // The server provides document highlight support. - bool documentHighlightProvider = false; - // The server provides document symbol support. - bool documentSymbolProvider = false; - // The server provides workspace symbol support. - bool workspaceSymbolProvider = false; - // The server provides code actions. - bool codeActionProvider = false; - // The server provides code lens. - optional codeLensProvider; - // The server provides document formatting. - bool documentFormattingProvider = false; - // The server provides document range formatting. - bool documentRangeFormattingProvider = false; - // The server provides document formatting on typing. - optional documentOnTypeFormattingProvider; - // The server provides rename support. - bool renameProvider = false; - // The server provides document link support. - optional documentLinkProvider; - // The server provides execute command support. - optional executeCommandProvider; - }; - - void Serialize(Writer& writer, const ServerCapabilities& value) { - writer.StartObject(); - SERIALIZE_MEMBER(textDocumentSync); - SERIALIZE_MEMBER(hoverProvider); - SERIALIZE_MEMBER(completionProvider); - SERIALIZE_MEMBER(signatureHelpProvider); - SERIALIZE_MEMBER(definitionProvider); - SERIALIZE_MEMBER(referencesProvider); - SERIALIZE_MEMBER(documentHighlightProvider); - SERIALIZE_MEMBER(documentSymbolProvider); - SERIALIZE_MEMBER(workspaceSymbolProvider); - SERIALIZE_MEMBER(codeActionProvider); - SERIALIZE_MEMBER(codeLensProvider); - SERIALIZE_MEMBER(documentFormattingProvider); - SERIALIZE_MEMBER(documentRangeFormattingProvider); - SERIALIZE_MEMBER(documentOnTypeFormattingProvider); - SERIALIZE_MEMBER(renameProvider); - SERIALIZE_MEMBER(documentLinkProvider); - SERIALIZE_MEMBER(executeCommandProvider); - writer.EndObject(); - } - - struct InitializeResult { - // The capabilities the language server provides. - ServerCapabilities capabilities; - }; - - void Serialize(Writer& writer, const InitializeResult& value) { - writer.StartObject(); - SERIALIZE_MEMBER(capabilities); - writer.EndObject(); - } - - - struct In_InitializeRequest : public InRequestMessage { - const static MethodId kMethod = MethodId::Initialize; - InitializeParams params; - - In_InitializeRequest(optional id, const Reader& reader) - : InRequestMessage(kMethod, id, reader) { - auto type = reader.GetType(); - Deserialize(reader, params); - std::cerr << "done" << std::endl; - } - }; - - struct Out_InitializeResponse : public OutResponseMessage { - InitializeResult result; - - // OutResponseMessage: - void WriteResult(Writer& writer) override { - Serialize(writer, result); - } - }; - - struct In_InitializedNotification : public InNotificationMessage { - const static MethodId kMethod = MethodId::Initialized; - - In_InitializedNotification(optional id, const Reader& reader) - : InNotificationMessage(kMethod, id, reader) {} - }; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - struct DocumentSymbolParams { - TextDocumentIdentifier textDocument; - }; - - void Deserialize(const Reader& reader, DocumentSymbolParams& value) { - DESERIALIZE_MEMBER(textDocument); - } - - struct In_DocumentSymbolRequest : public InRequestMessage { - const static MethodId kMethod = MethodId::TextDocumentDocumentSymbol; - - DocumentSymbolParams params; - - In_DocumentSymbolRequest(optional id, const Reader& reader) - : InRequestMessage(kMethod, id, reader) { - Deserialize(reader, params); - } - }; - - - struct Out_DocumentSymbolResponse : public OutResponseMessage { - std::vector result; - - // OutResponseMessage: - void WriteResult(Writer& writer) override { - ::Serialize(writer, result); - } - }; - - - - - - - - - - struct WorkspaceSymbolParams { - std::string query; - }; - - void Deserialize(const Reader& reader, WorkspaceSymbolParams& value) { - DESERIALIZE_MEMBER(query); - } - - struct In_WorkspaceSymbolRequest : public InRequestMessage { - const static MethodId kMethod = MethodId::WorkspaceSymbol; - - WorkspaceSymbolParams params; - - In_WorkspaceSymbolRequest(optional id, const Reader& reader) - : InRequestMessage(kMethod, id, reader) { - Deserialize(reader, params); - } - }; - - - struct Out_WorkspaceSymbolResponse : public OutResponseMessage { - std::vector result; - - // OutResponseMessage: - void WriteResult(Writer& writer) override { - ::Serialize(writer, result); - } - }; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enum class MessageType { - Error = 1, - Warning = 2, - Info = 3, - Log = 4 - }; - - void Serialize(Writer& writer, MessageType value) { - writer.Int(static_cast(value)); - } - - struct ShowMessageOutNotification : public OutNotificationMessage { - MessageType type = MessageType::Error; - std::string message; - - // OutNotificationMessage: - std::string Method() override { - return "window/showMessage"; - } - void SerializeParams(Writer& writer) override { - auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(type); - SERIALIZE_MEMBER(message); - writer.EndObject(); - } - }; - - struct LogMessageOutNotification : public OutNotificationMessage { - MessageType type = MessageType::Error; - std::string message; - - // OutNotificationMessage: - std::string Method() override { - return "window/logMessage"; - } - void SerializeParams(Writer& writer) override { - auto& value = *this; - - writer.StartObject(); - SERIALIZE_MEMBER(type); - SERIALIZE_MEMBER(message); - writer.EndObject(); - } - }; - - -//#undef SERIALIZE_MEMBER -//#undef SERIALIZE_MEMBER2 -//#undef DESERIALIZE_MEMBER - - - +struct lsInitializeError { + // Indicates whether the client should retry to send the + // initilize request after showing the message provided + // in the ResponseError. + bool retry; +}; + +template +void Reflect(TVisitor& visitor, lsInitializeError& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(retry); + REFLECT_MEMBER_END(); } + +// Defines how the host (editor) should sync document changes to the language server. +enum class lsTextDocumentSyncKind { + // Documents should not be synced at all. + None = 0, + + // Documents are synced by always sending the full content + // of the document. + Full = 1, + + // Documents are synced by sending the full content on open. + // After that only incremental updates to the document are + // send. + Incremental = 2 +}; + +void Reflect(Writer& writer, lsTextDocumentSyncKind& value) { + writer.Int(static_cast(value)); +} + +// Completion options. +struct lsCompletionOptions { + // The server provides support to resolve additional + // information for a completion item. + bool resolveProvider = false; + + // The characters that trigger completion automatically. + std::vector triggerCharacters; +}; + +template +void Reflect(TVisitor& visitor, lsCompletionOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(resolveProvider); + REFLECT_MEMBER(triggerCharacters); + REFLECT_MEMBER_END(); +} + +// Signature help options. +struct lsSignatureHelpOptions { + // The characters that trigger signature help automatically. + std::vector triggerCharacters; +}; + +template +void Reflect(TVisitor& visitor, lsSignatureHelpOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(triggerCharacters); + REFLECT_MEMBER_END(); +} + +// Code Lens options. +struct lsCodeLensOptions { + // Code lens has a resolve provider as well. + bool resolveProvider = false; +}; + +template +void Reflect(TVisitor& visitor, lsCodeLensOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(resolveProvider); + REFLECT_MEMBER_END(); +} + +// Format document on type options +struct lsDocumentOnTypeFormattingOptions { + // A character on which formatting should be triggered, like `}`. + std::string firstTriggerCharacter; + + // More trigger characters. + std::vector moreTriggerCharacter; +}; + +template +void Reflect(TVisitor& visitor, lsDocumentOnTypeFormattingOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(firstTriggerCharacter); + REFLECT_MEMBER(moreTriggerCharacter); + REFLECT_MEMBER_END(); +} + +// Document link options +struct lsDocumentLinkOptions { + // Document links have a resolve provider as well. + bool resolveProvider = false; +}; + +template +void Reflect(TVisitor& visitor, lsDocumentLinkOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(resolveProvider); + REFLECT_MEMBER_END(); +} + +// Execute command options. +struct lsExecuteCommandOptions { + // The commands to be executed on the server + std::vector commands; +}; + +template +void Reflect(TVisitor& visitor, lsExecuteCommandOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(commands); + REFLECT_MEMBER_END(); +} + +// Save options. +struct lsSaveOptions { + // The client is supposed to include the content on save. + bool includeText = false; +}; + +template +void Reflect(TVisitor& visitor, lsSaveOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(includeText); + REFLECT_MEMBER_END(); +} + +struct lsTextDocumentSyncOptions { + // Open and close notifications are sent to the server. + bool openClose = false; + // Change notificatins are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + // and TextDocumentSyncKindIncremental. + optional change; + // Will save notifications are sent to the server. + bool willSave = false; + // Will save wait until requests are sent to the server. + bool willSaveWaitUntil = false; + // Save notifications are sent to the server. + optional save; +}; + +template +void Reflect(TVisitor& visitor, lsTextDocumentSyncOptions& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(openClose); + REFLECT_MEMBER(change); + REFLECT_MEMBER(willSave); + REFLECT_MEMBER(willSaveWaitUntil); + REFLECT_MEMBER(save); + REFLECT_MEMBER_END(); +} + +struct lsServerCapabilities { + // Defines how text documents are synced. Is either a detailed structure defining each notification or + // for backwards compatibility the TextDocumentSyncKind number. + optional textDocumentSync; + // The server provides hover support. + bool hoverProvider = false; + // The server provides completion support. + optional completionProvider; + // The server provides signature help support. + optional signatureHelpProvider; + // The server provides goto definition support. + bool definitionProvider = false; + // The server provides find references support. + bool referencesProvider = false; + // The server provides document highlight support. + bool documentHighlightProvider = false; + // The server provides document symbol support. + bool documentSymbolProvider = false; + // The server provides workspace symbol support. + bool workspaceSymbolProvider = false; + // The server provides code actions. + bool codeActionProvider = false; + // The server provides code lens. + optional codeLensProvider; + // The server provides document formatting. + bool documentFormattingProvider = false; + // The server provides document range formatting. + bool documentRangeFormattingProvider = false; + // The server provides document formatting on typing. + optional documentOnTypeFormattingProvider; + // The server provides rename support. + bool renameProvider = false; + // The server provides document link support. + optional documentLinkProvider; + // The server provides execute command support. + optional executeCommandProvider; +}; + +template +void Reflect(TVisitor& visitor, lsServerCapabilities& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(textDocumentSync); + REFLECT_MEMBER(hoverProvider); + REFLECT_MEMBER(completionProvider); + REFLECT_MEMBER(signatureHelpProvider); + REFLECT_MEMBER(definitionProvider); + REFLECT_MEMBER(referencesProvider); + REFLECT_MEMBER(documentHighlightProvider); + REFLECT_MEMBER(documentSymbolProvider); + REFLECT_MEMBER(workspaceSymbolProvider); + REFLECT_MEMBER(codeActionProvider); + REFLECT_MEMBER(codeLensProvider); + REFLECT_MEMBER(documentFormattingProvider); + REFLECT_MEMBER(documentRangeFormattingProvider); + REFLECT_MEMBER(documentOnTypeFormattingProvider); + REFLECT_MEMBER(renameProvider); + REFLECT_MEMBER(documentLinkProvider); + REFLECT_MEMBER(executeCommandProvider); + REFLECT_MEMBER_END(); +} + +struct lsInitializeResult { + // The capabilities the language server provides. + lsServerCapabilities capabilities; +}; + +template +void Reflect(TVisitor& visitor, lsInitializeResult& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(capabilities); + REFLECT_MEMBER_END(); +} + + +struct In_InitializeRequest : public InRequestMessage { + const static lsMethodId kMethod = lsMethodId::Initialize; + lsInitializeParams params; + + In_InitializeRequest(optional id, Reader& reader) + : InRequestMessage(kMethod, id, reader) { + auto type = reader.GetType(); + Reflect(reader, params); + std::cerr << "done" << std::endl; + } +}; + +struct Out_InitializeResponse : public OutResponseMessage { + lsInitializeResult result; + + // OutResponseMessage: + void WriteResult(Writer& writer) override { + Reflect(writer, result); + } +}; + +struct In_InitializedNotification : public InNotificationMessage { + const static lsMethodId kMethod = lsMethodId::Initialized; + + In_InitializedNotification(optional id, Reader& reader) + : InNotificationMessage(kMethod, id, reader) {} +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +struct lsDocumentSymbolParams { + lsTextDocumentIdentifier textDocument; +}; + +template +void Reflect(TVisitor& visitor, lsDocumentSymbolParams& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(textDocument); + REFLECT_MEMBER_END(); +} + +struct In_DocumentSymbolRequest : public InRequestMessage { + const static lsMethodId kMethod = lsMethodId::TextDocumentDocumentSymbol; + + lsDocumentSymbolParams params; + + In_DocumentSymbolRequest(optional id, Reader& reader) + : InRequestMessage(kMethod, id, reader) { + Reflect(reader, params); + } +}; + + +struct Out_DocumentSymbolResponse : public OutResponseMessage { + std::vector result; + + // OutResponseMessage: + void WriteResult(Writer& writer) override { + ::Reflect(writer, result); + } +}; + + + + + + + + + +struct lsWorkspaceSymbolParams { + std::string query; +}; + +template +void Reflect(TVisitor& visitor, lsWorkspaceSymbolParams& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(query); + REFLECT_MEMBER_END(); +} + +struct In_WorkspaceSymbolRequest : public InRequestMessage { + const static lsMethodId kMethod = lsMethodId::WorkspaceSymbol; + + lsWorkspaceSymbolParams params; + + In_WorkspaceSymbolRequest(optional id, Reader& reader) + : InRequestMessage(kMethod, id, reader) { + Reflect(reader, params); + } +}; + + +struct Out_WorkspaceSymbolResponse : public OutResponseMessage { + std::vector result; + + // OutResponseMessage: + void WriteResult(Writer& writer) override { + ::Reflect(writer, result); + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +enum class lsMessageType : int { + Error = 1, + Warning = 2, + Info = 3, + Log = 4 +}; + +template +void Reflect(TWriter& writer, lsMessageType& value) { + int value0 = static_cast(value); + Reflect(writer, value0); + value = static_cast(value0); +} + +struct ShowMessageOutNotification : public OutNotificationMessage { + lsMessageType type = lsMessageType::Error; + std::string message; + + // OutNotificationMessage: + std::string Method() override { + return "window/showMessage"; + } + void SerializeParams(Writer& visitor) override { + auto& value = *this; + REFLECT_MEMBER_START(); + REFLECT_MEMBER(type); + REFLECT_MEMBER(message); + REFLECT_MEMBER_END(); + } +}; + +struct LogMessageOutNotification : public OutNotificationMessage { + lsMessageType type = lsMessageType::Error; + std::string message; + + // OutNotificationMessage: + std::string Method() override { + return "window/logMessage"; + } + void SerializeParams(Writer& visitor) override { + auto& value = *this; + REFLECT_MEMBER_START(); + REFLECT_MEMBER(type); + REFLECT_MEMBER(message); + REFLECT_MEMBER_END(); + } +}; diff --git a/serializer.h b/serializer.h index d679a24d..baf22f73 100644 --- a/serializer.h +++ b/serializer.h @@ -156,7 +156,6 @@ void ReflectMember(Reader& visitor, const char* name, T& value) { - #if false void Serialize(Writer& writer, int value); diff --git a/test.cc b/test.cc index e63f134b..0fcb31c4 100644 --- a/test.cc +++ b/test.cc @@ -1,3 +1,5 @@ +#include "test.h" + #include "indexer.h" #include "serializer.h" #include "utils.h" @@ -82,7 +84,7 @@ void VerifySerializeToFrom(IndexedFile& file) { } } -int main(int argc, char** argv) { +void RunTests() { // TODO: Assert that we need to be on clang >= 3.9.1 /* @@ -95,7 +97,7 @@ int main(int argc, char** argv) { for (std::string path : GetFilesInFolder("tests", true /*add_folder_to_path*/)) { //if (path != "tests/templates/specialized_func_definition.cc") continue; - //if (path != "tests/constructors/invalid_reference.cc") continue; + if (path != "tests/outline/outline.cc") continue; //if (path == "tests/inheritance/class_inherit_templated_parent.cc") continue; //if (path != "tests/namespaces/namespace_reference.cc") continue; //if (path != "tests/stl.cc") continue; @@ -111,7 +113,7 @@ int main(int argc, char** argv) { // Run test. std::cout << "[START] " << path << std::endl; - IndexedFile db = Parse(path, {}, false /*dump_ast*/); + IndexedFile db = Parse(path, {}, true /*dump_ast*/); VerifySerializeToFrom(db); std::string actual_output = db.ToString(); @@ -135,7 +137,6 @@ int main(int argc, char** argv) { } std::cin.get(); - return 0; } // TODO: ctor/dtor, copy ctor diff --git a/test.h b/test.h new file mode 100644 index 00000000..43a0ead1 --- /dev/null +++ b/test.h @@ -0,0 +1,3 @@ +#pragma once + +void RunTests(); \ No newline at end of file diff --git a/tests/outline/outline.cc b/tests/outline/outline.cc new file mode 100644 index 00000000..3eb6dd6c --- /dev/null +++ b/tests/outline/outline.cc @@ -0,0 +1,19 @@ +#include + +struct MergeableUpdate { + std::vector to_add; +}; + +/* +OUTPUT: +{ + "types": [{ + "id": 0, + "usr": "c:@S@MergeableUpdate", + "short_name": "MergeableUpdate", + "qualified_name": "MergeableUpdate", + "definition": "1:1:8", + "uses": ["*1:1:8"] + }] +} +*/