diff --git a/CMakeLists.txt b/CMakeLists.txt index 7af3eb16..7c526d72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,7 +187,6 @@ target_sources(ccls PRIVATE src/main.cc src/include_complete.cc src/indexer.cc - src/method.cc src/log.cc src/lsp.cc src/match.cc @@ -225,12 +224,10 @@ target_sources(ccls PRIVATE src/messages/textDocument_documentHighlight.cc src/messages/textDocument_documentSymbol.cc src/messages/textDocument_hover.cc - src/messages/textDocument_implementation.cc src/messages/textDocument_references.cc src/messages/textDocument_rename.cc src/messages/textDocument_signatureHelp.cc src/messages/textDocument_typeDefinition.cc src/messages/workspace_did.cc - src/messages/workspace_didChangeWatchedFiles.cc src/messages/workspace_symbol.cc ) diff --git a/src/clang_complete.hh b/src/clang_complete.hh index eae3897a..0d50a7f8 100644 --- a/src/clang_complete.hh +++ b/src/clang_complete.hh @@ -5,8 +5,8 @@ #include "clang_tu.hh" #include "lru_cache.h" +#include "lsp.h" #include "lsp_completion.h" -#include "lsp_diagnostic.h" #include "project.h" #include "threaded_queue.h" #include "working_files.h" diff --git a/src/hierarchy.hh b/src/hierarchy.hh index 5a78c949..3fd7d341 100644 --- a/src/hierarchy.hh +++ b/src/hierarchy.hh @@ -9,19 +9,22 @@ #include template -void FlattenHierarchy(const Node &root, Out_LocationList &out) { +std::vector FlattenHierarchy(const std::optional &root) { + if (!root) + return {}; + std::vector ret; std::queue q; - for (auto &entry : root.children) + for (auto &entry : root->children) q.push(&entry); while (q.size()) { auto *entry = q.front(); q.pop(); if (entry->location.uri.raw_uri.size()) - out.result.push_back({entry->location}); + ret.push_back({entry->location}); for (auto &entry1 : entry->children) q.push(&entry1); } - std::sort(out.result.begin(), out.result.end()); - out.result.erase(std::unique(out.result.begin(), out.result.end()), - out.result.end()); + std::sort(ret.begin(), ret.end()); + ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); + return ret; } diff --git a/src/indexer.h b/src/indexer.h index c49f74e6..2d263866 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -4,7 +4,6 @@ #pragma once #include "lsp.h" -#include "lsp_diagnostic.h" #include "maybe.h" #include "position.h" #include "serializer.h" diff --git a/src/lsp.cc b/src/lsp.cc index b134f477..6a6e70f0 100644 --- a/src/lsp.cc +++ b/src/lsp.cc @@ -6,11 +6,46 @@ #include "log.hh" #include "serializers/json.h" -#include +#include #include #include +MethodType kMethodType_Exit = "exit"; + +void Reflect(Reader &visitor, lsRequestId &value) { + if (visitor.IsInt64()) { + value.type = lsRequestId::kInt; + value.value = int(visitor.GetInt64()); + } else if (visitor.IsInt()) { + value.type = lsRequestId::kInt; + value.value = visitor.GetInt(); + } else if (visitor.IsString()) { + value.type = lsRequestId::kString; + value.value = atoll(visitor.GetString()); + } else { + value.type = lsRequestId::kNone; + value.value = -1; + } +} + +void Reflect(Writer &visitor, lsRequestId &value) { + switch (value.type) { + case lsRequestId::kNone: + visitor.Null(); + break; + case lsRequestId::kInt: + visitor.Int(value.value); + break; + case lsRequestId::kString: + auto s = std::to_string(value.value); + visitor.String(s.c_str(), s.length()); + break; + } +} + +InMessage::~InMessage() {} + MessageRegistry *MessageRegistry::instance_ = nullptr; lsTextDocumentIdentifier @@ -134,29 +169,6 @@ MessageRegistry *MessageRegistry::instance() { return instance_; } -lsBaseOutMessage::~lsBaseOutMessage() = default; - -void lsBaseOutMessage::Write(std::ostream &out) { - rapidjson::StringBuffer output; - rapidjson::Writer writer(output); - JsonWriter json_writer{&writer}; - ReflectWriter(json_writer); - - out << "Content-Length: " << output.GetSize() << "\r\n\r\n" - << output.GetString(); - out.flush(); -} - -void lsResponseError::Write(Writer &visitor) { - auto &value = *this; - int code2 = static_cast(this->code); - - visitor.StartObject(); - REFLECT_MEMBER2("code", code2); - REFLECT_MEMBER(message); - visitor.EndObject(); -} - lsDocumentUri lsDocumentUri::FromPath(const std::string &path) { lsDocumentUri result; result.SetPath(path); @@ -261,9 +273,3 @@ void Reflect(Writer &visitor, lsMarkedString &value) { Reflect(visitor, value.value); } } - -std::string Out_ShowLogMessage::method() { - if (display_type == DisplayType::Log) - return "window/logMessage"; - return "window/showMessage"; -} diff --git a/src/lsp.h b/src/lsp.h index be2d767a..4aad7f94 100644 --- a/src/lsp.h +++ b/src/lsp.h @@ -4,13 +4,42 @@ #pragma once #include "config.h" -#include "method.h" #include "serializer.h" #include "utils.h" #include #include +using MethodType = const char *; +extern MethodType kMethodType_Exit; + +struct lsRequestId { + // The client can send the request id as an int or a string. We should output + // the same format we received. + enum Type { kNone, kInt, kString }; + Type type = kNone; + + int value = -1; + + bool Valid() const { return type != kNone; } +}; +void Reflect(Reader &visitor, lsRequestId &value); +void Reflect(Writer &visitor, lsRequestId &value); + +struct InMessage { + virtual ~InMessage(); + + virtual MethodType GetMethodType() const = 0; + virtual lsRequestId GetRequestId() const { return {}; } +}; + +struct NotificationMessage : InMessage {}; + +struct RequestMessage : public InMessage { + lsRequestId id; + lsRequestId GetRequestId() const override { return id; } +}; + #define REGISTER_IN_MESSAGE(type) \ static MessageRegistryRegister type##message_handler_instance_; @@ -41,45 +70,38 @@ template struct MessageRegistryRegister { } }; -struct lsBaseOutMessage { - virtual ~lsBaseOutMessage(); - virtual void ReflectWriter(Writer &) = 0; +enum class lsErrorCodes { + // Defined by JSON RPC + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + serverErrorStart = -32099, + serverErrorEnd = -32000, + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, - // Send the message to the language client by writing it to stdout. - void Write(std::ostream &out); -}; - -template struct lsOutMessage : lsBaseOutMessage { - // All derived types need to reflect on the |jsonrpc| member. - std::string jsonrpc = "2.0"; - - void ReflectWriter(Writer &writer) override { - Reflect(writer, static_cast(*this)); - } + // Defined by the protocol. + RequestCancelled = -32800, }; +MAKE_REFLECT_TYPE_PROXY(lsErrorCodes); struct lsResponseError { - enum class lsErrorCodes : int { - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - serverErrorStart = -32099, - serverErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - RequestCancelled = -32800, - }; - + // A number indicating the error type that occurred. lsErrorCodes code; - // Short description. + + // A string providing a short description of the error. std::string message; - void Write(Writer &visitor); + // A Primitive or Structured value that contains additional + // information about the error. Can be omitted. + // std::optional data; }; +MAKE_REFLECT_STRUCT(lsResponseError, code, message); -constexpr std::string_view ccls_xref("ccls.xref"); +constexpr char ccls_xref[] = "ccls.xref"; +constexpr char window_showMessage[] = "window/showMessage"; ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// @@ -305,35 +327,55 @@ MAKE_REFLECT_STRUCT(lsWorkspaceFolder, uri, name); enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; MAKE_REFLECT_TYPE_PROXY(lsMessageType) -struct Out_ShowLogMessageParams { +enum class lsDiagnosticSeverity { + // Reports an error. + Error = 1, + // Reports a warning. + Warning = 2, + // Reports an information. + Information = 3, + // Reports a hint. + Hint = 4 +}; +MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity); + +struct lsDiagnostic { + // The range at which the message applies. + lsRange range; + + // The diagnostic's severity. Can be omitted. If omitted it is up to the + // client to interpret diagnostics as error, warning, info or hint. + std::optional severity; + + // The diagnostic's code. Can be omitted. + int code = 0; + + // A human-readable string describing the source of this + // diagnostic, e.g. 'typescript' or 'super lint'. + std::string source = "ccls"; + + // The diagnostic's message. + std::string message; + + // Non-serialized set of fixits. + std::vector fixits_; +}; +MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message); + +struct lsPublishDiagnosticsParams { + // The URI for which diagnostic information is reported. + lsDocumentUri uri; + + // An array of diagnostic information items. + std::vector diagnostics; +}; +MAKE_REFLECT_STRUCT(lsPublishDiagnosticsParams, uri, diagnostics); + +struct lsShowMessageParams { lsMessageType type = lsMessageType::Error; std::string message; }; -MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message); - -struct Out_ShowLogMessage : public lsOutMessage { - enum class DisplayType { Show, Log }; - DisplayType display_type = DisplayType::Show; - - std::string method(); - Out_ShowLogMessageParams params; -}; - -template -void Reflect(TVisitor &visitor, Out_ShowLogMessage &value) { - REFLECT_MEMBER_START(); - REFLECT_MEMBER(jsonrpc); - std::string method = value.method(); - REFLECT_MEMBER2("method", method); - REFLECT_MEMBER(params); - REFLECT_MEMBER_END(); -} - -struct Out_LocationList : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result); +MAKE_REFLECT_STRUCT(lsShowMessageParams, type, message); // Used to identify the language at a file level. The ordering is important, as // a file previously identified as `C`, will be changed to `Cpp` if it diff --git a/src/lsp_diagnostic.h b/src/lsp_diagnostic.h deleted file mode 100644 index 501b83b8..00000000 --- a/src/lsp_diagnostic.h +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "lsp.h" - -enum class lsDiagnosticSeverity { - // Reports an error. - Error = 1, - // Reports a warning. - Warning = 2, - // Reports an information. - Information = 3, - // Reports a hint. - Hint = 4 -}; -MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity); - -struct lsDiagnostic { - // The range at which the message applies. - lsRange range; - - // The diagnostic's severity. Can be omitted. If omitted it is up to the - // client to interpret diagnostics as error, warning, info or hint. - std::optional severity; - - // The diagnostic's code. Can be omitted. - int code = 0; - - // A human-readable string describing the source of this - // diagnostic, e.g. 'typescript' or 'super lint'. - std::string source = "ccls"; - - // The diagnostic's message. - std::string message; - - // Non-serialized set of fixits. - std::vector fixits_; -}; -MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message); - -enum class lsErrorCodes { - // Defined by JSON RPC - ParseError = -32700, - InvalidRequest = -32600, - MethodNotFound = -32601, - InvalidParams = -32602, - InternalError = -32603, - serverErrorStart = -32099, - serverErrorEnd = -32000, - ServerNotInitialized = -32002, - UnknownErrorCode = -32001, - - // Defined by the protocol. - RequestCancelled = -32800, -}; -MAKE_REFLECT_TYPE_PROXY(lsErrorCodes); -struct Out_Error : public lsOutMessage { - struct lsResponseError { - // A number indicating the error type that occurred. - lsErrorCodes code; - - // A string providing a short description of the error. - std::string message; - - // A Primitive or Structured value that contains additional - // information about the error. Can be omitted. - // std::optional data; - }; - - lsRequestId id; - - // The error object in case a request fails. - lsResponseError error; -}; -MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message); -MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error); - -// Diagnostics -struct Out_TextDocumentPublishDiagnostics - : public lsOutMessage { - struct Params { - // The URI for which diagnostic information is reported. - lsDocumentUri uri; - - // An array of diagnostic information items. - std::vector diagnostics; - }; - - Params params; -}; -template -void Reflect(TVisitor &visitor, Out_TextDocumentPublishDiagnostics &value) { - std::string method = "textDocument/publishDiagnostics"; - REFLECT_MEMBER_START(); - REFLECT_MEMBER(jsonrpc); - REFLECT_MEMBER2("method", method); - REFLECT_MEMBER(params); - REFLECT_MEMBER_END(); -} -MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri, - diagnostics); diff --git a/src/match.cc b/src/match.cc index 83003e50..ce614b35 100644 --- a/src/match.cc +++ b/src/match.cc @@ -18,12 +18,11 @@ std::optional Matcher::Create(const std::string &search) { ); return m; } catch (const std::exception &e) { - Out_ShowLogMessage out; - out.display_type = Out_ShowLogMessage::DisplayType::Show; - out.params.type = lsMessageType::Error; - out.params.message = - "ccls: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what(); - pipeline::WriteStdout(kMethodType_Unknown, out); + lsShowMessageParams params; + params.type = lsMessageType::Error; + params.message = + "failed to parse EMCAScript regex " + search + " : " + e.what(); + pipeline::Notify(window_showMessage, params); return std::nullopt; } } diff --git a/src/message_handler.cc b/src/message_handler.cc index b1fb6fad..7540c990 100644 --- a/src/message_handler.cc +++ b/src/message_handler.cc @@ -18,23 +18,36 @@ MAKE_HASHABLE(SymbolIdx, t.usr, t.kind); namespace { -struct Out_CclsSetSkippedRanges - : public lsOutMessage { - struct Params { - lsDocumentUri uri; - std::vector skippedRanges; - }; - std::string method = "$ccls/setSkippedRanges"; - Params params; +struct CclsSemanticHighlightSymbol { + int id = 0; + lsSymbolKind parentKind; + lsSymbolKind kind; + uint8_t storage; + std::vector> ranges; + + // `lsRanges` is used to compute `ranges`. + std::vector lsRanges; }; -MAKE_REFLECT_STRUCT(Out_CclsSetSkippedRanges::Params, uri, skippedRanges); -MAKE_REFLECT_STRUCT(Out_CclsSetSkippedRanges, jsonrpc, method, params); + +struct CclsSemanticHighlightParams { + lsDocumentUri uri; + std::vector symbols; +}; +MAKE_REFLECT_STRUCT(CclsSemanticHighlightSymbol, id, parentKind, kind, storage, + ranges, lsRanges); +MAKE_REFLECT_STRUCT(CclsSemanticHighlightParams, uri, symbols); + +struct CclsSetSkippedRangesParams { + lsDocumentUri uri; + std::vector skippedRanges; +}; +MAKE_REFLECT_STRUCT(CclsSetSkippedRangesParams, uri, skippedRanges); struct ScanLineEvent { lsPosition pos; lsPosition end_pos; // Second key when there is a tie for insertion events. int id; - Out_CclsPublishSemanticHighlighting::Symbol *symbol; + CclsSemanticHighlightSymbol *symbol; bool operator<(const ScanLineEvent &other) const { // See the comments below when insertion/deletion events are inserted. if (!(pos == other.pos)) @@ -56,7 +69,6 @@ MessageHandler::MessageHandler() { message_handlers->push_back(this); } -// static std::vector *MessageHandler::message_handlers = nullptr; bool FindFileOrFail(DB *db, Project *project, std::optional id, @@ -86,46 +98,40 @@ bool FindFileOrFail(DB *db, Project *project, std::optional id, } if (id) { - Out_Error out; - out.id = *id; + lsResponseError err; if (has_entry) { - out.error.code = lsErrorCodes::ServerNotInitialized; - out.error.message = absolute_path + " is being indexed"; + err.code = lsErrorCodes::ServerNotInitialized; + err.message = absolute_path + " is being indexed"; } else { - out.error.code = lsErrorCodes::InternalError; - out.error.message = "Unable to find file " + absolute_path; + err.code = lsErrorCodes::InternalError; + err.message = "unable to find " + absolute_path; } - LOG_S(INFO) << out.error.message; - pipeline::WriteStdout(kMethodType_Unknown, out); + pipeline::ReplyError(*id, err); } return false; } -void EmitSkippedRanges(WorkingFile *working_file, - const std::vector &skipped_ranges) { - Out_CclsSetSkippedRanges out; - out.params.uri = lsDocumentUri::FromPath(working_file->filename); - for (Range skipped : skipped_ranges) { - std::optional ls_skipped = GetLsRange(working_file, skipped); - if (ls_skipped) - out.params.skippedRanges.push_back(*ls_skipped); - } - pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out); +void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) { + CclsSetSkippedRangesParams params; + params.uri = lsDocumentUri::FromPath(wfile->filename); + for (Range skipped : file.def->skipped_ranges) + if (auto ls_skipped = GetLsRange(wfile, skipped)) + params.skippedRanges.push_back(*ls_skipped); + pipeline::Notify("$ccls/publishSkippedRanges", params); } -void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { +void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) { static GroupMatch match(g_config->highlight.whitelist, g_config->highlight.blacklist); - assert(file->def); + assert(file.def); if (wfile->buffer_content.size() > g_config->highlight.largeFileSize || - !match.IsMatch(file->def->path)) + !match.IsMatch(file.def->path)) return; // Group symbols together. - std::unordered_map - grouped_symbols; - for (auto [sym, refcnt] : file->symbol2refcnt) { + std::unordered_map grouped_symbols; + for (auto [sym, refcnt] : file.symbol2refcnt) { if (refcnt <= 0) continue; std::string_view detailed_name; lsSymbolKind parent_kind = lsSymbolKind::Unknown; @@ -205,8 +211,8 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { if (it != grouped_symbols.end()) { it->second.lsRanges.push_back(*loc); } else { - Out_CclsPublishSemanticHighlighting::Symbol symbol; - symbol.stableId = idx; + CclsSemanticHighlightSymbol symbol; + symbol.id = idx; symbol.parentKind = parent_kind; symbol.kind = kind; symbol.storage = storage; @@ -220,7 +226,7 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { std::vector events; int id = 0; for (auto &entry : grouped_symbols) { - Out_CclsPublishSemanticHighlighting::Symbol &symbol = entry.second; + CclsSemanticHighlightSymbol &symbol = entry.second; for (auto &loc : symbol.lsRanges) { // For ranges sharing the same start point, the one with leftmost end // point comes first. @@ -255,13 +261,11 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { deleted[~events[i].id] = 1; } - Out_CclsPublishSemanticHighlighting out; - out.params.uri = lsDocumentUri::FromPath(wfile->filename); + CclsSemanticHighlightParams params; + params.uri = lsDocumentUri::FromPath(wfile->filename); // Transform lsRange into pair (offset pairs) if (!g_config->highlight.lsRanges) { - std::vector< - std::pair> - scratch; + std::vector> scratch; for (auto &entry : grouped_symbols) { for (auto &range : entry.second.lsRanges) scratch.emplace_back(range, &entry.second); @@ -303,6 +307,6 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { for (auto &entry : grouped_symbols) if (entry.second.ranges.size() || entry.second.lsRanges.size()) - out.params.symbols.push_back(std::move(entry.second)); - pipeline::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out); + params.symbols.push_back(std::move(entry.second)); + pipeline::Notify("$ccls/publishSemanticHighlight", params); } diff --git a/src/message_handler.h b/src/message_handler.h index 31c2eabe..dd882597 100644 --- a/src/message_handler.h +++ b/src/message_handler.h @@ -4,7 +4,6 @@ #pragma once #include "lsp.h" -#include "method.h" #include "query.h" #include @@ -23,30 +22,6 @@ struct DB; struct WorkingFile; struct WorkingFiles; -struct Out_CclsPublishSemanticHighlighting - : public lsOutMessage { - struct Symbol { - int stableId = 0; - lsSymbolKind parentKind; - lsSymbolKind kind; - uint8_t storage; - std::vector> ranges; - - // `lsRanges` is used to compute `ranges`. - std::vector lsRanges; - }; - struct Params { - lsDocumentUri uri; - std::vector symbols; - }; - std::string method = "$ccls/publishSemanticHighlighting"; - Params params; -}; -MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Symbol, stableId, - parentKind, kind, storage, ranges, lsRanges); -MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting::Params, uri, symbols); -MAKE_REFLECT_STRUCT(Out_CclsPublishSemanticHighlighting, jsonrpc, method, - params); // Usage: // @@ -91,8 +66,6 @@ bool FindFileOrFail(DB *db, Project *project, std::optional id, const std::string &absolute_path, QueryFile **out_query_file, int *out_file_id = nullptr); -void EmitSkippedRanges(WorkingFile *working_file, - const std::vector &skipped_ranges); +void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file); -void EmitSemanticHighlighting(DB *db, WorkingFile *working_file, - QueryFile *file); +void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file); diff --git a/src/messages/ccls_call.cc b/src/messages/ccls_call.cc index 56efbcdd..54de411f 100644 --- a/src/messages/ccls_call.cc +++ b/src/messages/ccls_call.cc @@ -26,7 +26,7 @@ bool operator&(CallType lhs, CallType rhs) { return uint8_t(lhs) & uint8_t(rhs); } -struct In_CclsCall : public RequestInMessage { +struct In_cclsCall : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { @@ -50,34 +50,29 @@ struct In_CclsCall : public RequestInMessage { }; Params params; }; -MAKE_REFLECT_STRUCT(In_CclsCall::Params, textDocument, position, id, - callee, callType, qualified, levels, hierarchy); -MAKE_REFLECT_STRUCT(In_CclsCall, id, params); -REGISTER_IN_MESSAGE(In_CclsCall); +MAKE_REFLECT_STRUCT(In_cclsCall::Params, textDocument, position, id, callee, + callType, qualified, levels, hierarchy); +MAKE_REFLECT_STRUCT(In_cclsCall, id, params); +REGISTER_IN_MESSAGE(In_cclsCall); -struct Out_CclsCall : public lsOutMessage { - struct Entry { - Usr usr; - std::string id; - std::string_view name; - lsLocation location; - CallType callType = CallType::Direct; - int numChildren; - // Empty if the |levels| limit is reached. - std::vector children; - bool operator==(const Entry &o) const { return location == o.location; } - bool operator<(const Entry &o) const { return location < o.location; } - }; - - lsRequestId id; - std::optional result; +struct Out_cclsCall { + Usr usr; + std::string id; + std::string_view name; + lsLocation location; + CallType callType = CallType::Direct; + int numChildren; + // Empty if the |levels| limit is reached. + std::vector children; + bool operator==(const Out_cclsCall &o) const { + return location == o.location; + } + bool operator<(const Out_cclsCall &o) const { return location < o.location; } }; -MAKE_REFLECT_STRUCT(Out_CclsCall::Entry, id, name, location, callType, - numChildren, children); -MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCall, jsonrpc, id, - result); +MAKE_REFLECT_STRUCT(Out_cclsCall, id, name, location, callType, numChildren, + children); -bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee, +bool Expand(MessageHandler *m, Out_cclsCall *entry, bool callee, CallType call_type, bool qualified, int levels) { const QueryFunc &func = m->db->Func(entry->usr); const QueryFunc::Def *def = func.AnyDef(); @@ -87,7 +82,7 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee, auto handle = [&](SymbolRef sym, int file_id, CallType call_type1) { entry->numChildren++; if (levels > 0) { - Out_CclsCall::Entry entry1; + Out_cclsCall entry1; entry1.id = std::to_string(sym.usr); entry1.usr = sym.usr; if (auto loc = GetLsLocation(m->db, m->working_files, @@ -167,17 +162,17 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee, return true; } -struct Handler_CclsCall : BaseMessageHandler { +struct Handler_cclsCall : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - std::optional - BuildInitial(Usr root_usr, bool callee, CallType call_type, bool qualified, - int levels) { + std::optional BuildInitial(Usr root_usr, bool callee, + CallType call_type, bool qualified, + int levels) { const auto *def = db->Func(root_usr).AnyDef(); if (!def) return {}; - Out_CclsCall::Entry entry; + Out_cclsCall entry; entry.id = std::to_string(root_usr); entry.usr = root_usr; entry.callType = CallType::Direct; @@ -190,25 +185,22 @@ struct Handler_CclsCall : BaseMessageHandler { return entry; } - void Run(In_CclsCall *request) override { + void Run(In_cclsCall *request) override { auto ¶ms = request->params; - Out_CclsCall out; - out.id = request->id; - + std::optional result; if (params.id.size()) { try { params.usr = std::stoull(params.id); } catch (...) { return; } - Out_CclsCall::Entry entry; - entry.id = std::to_string(params.usr); - entry.usr = params.usr; - entry.callType = CallType::Direct; + result.emplace(); + result->id = std::to_string(params.usr); + result->usr = params.usr; + result->callType = CallType::Direct; if (db->HasFunc(params.usr)) - Expand(this, &entry, params.callee, params.callType, params.qualified, + Expand(this, &*result, params.callee, params.callType, params.qualified, params.levels); - out.result = std::move(entry); } else { QueryFile *file; if (!FindFileOrFail(db, project, request->id, @@ -219,24 +211,21 @@ struct Handler_CclsCall : BaseMessageHandler { for (SymbolRef sym : FindSymbolsAtLocation(working_file, file, params.position)) { if (sym.kind == SymbolKind::Func) { - out.result = BuildInitial(sym.usr, params.callee, params.callType, - params.qualified, params.levels); + result = BuildInitial(sym.usr, params.callee, params.callType, + params.qualified, params.levels); break; } } } - if (params.hierarchy) { - pipeline::WriteStdout(kMethodType, out); - return; + if (params.hierarchy) + pipeline::Reply(request->id, result); + else { + auto out = FlattenHierarchy(result); + pipeline::Reply(request->id, out); } - Out_LocationList out1; - out1.id = request->id; - if (out.result) - FlattenHierarchy(*out.result, out1); - pipeline::WriteStdout(kMethodType, out1); } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsCall); +REGISTER_MESSAGE_HANDLER(Handler_cclsCall); } // namespace diff --git a/src/messages/ccls_info.cc b/src/messages/ccls_info.cc index 15ba8bea..b8b3e2bf 100644 --- a/src/messages/ccls_info.cc +++ b/src/messages/ccls_info.cc @@ -13,51 +13,46 @@ MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges, namespace { MethodType cclsInfo = "$ccls/info", fileInfo = "$ccls/fileInfo"; -struct In_cclsInfo : public RequestInMessage { +struct In_cclsInfo : public RequestMessage { MethodType GetMethodType() const override { return cclsInfo; } }; MAKE_REFLECT_STRUCT(In_cclsInfo, id); REGISTER_IN_MESSAGE(In_cclsInfo); -struct Out_cclsInfo : public lsOutMessage { - lsRequestId id; - struct Result { - struct DB { - int files, funcs, types, vars; - } db; - struct Pipeline { - int pendingIndexRequests; - } pipeline; - struct Project { - int entries; - } project; - } result; +struct Out_cclsInfo { + struct DB { + int files, funcs, types, vars; + } db; + struct Pipeline { + int pendingIndexRequests; + } pipeline; + struct Project { + int entries; + } project; }; -MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::DB, files, funcs, types, vars); -MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::Pipeline, pendingIndexRequests); -MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::Project, entries); -MAKE_REFLECT_STRUCT(Out_cclsInfo::Result, db, pipeline, project); -MAKE_REFLECT_STRUCT(Out_cclsInfo, jsonrpc, id, result); +MAKE_REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars); +MAKE_REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests); +MAKE_REFLECT_STRUCT(Out_cclsInfo::Project, entries); +MAKE_REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project); struct Handler_cclsInfo : BaseMessageHandler { MethodType GetMethodType() const override { return cclsInfo; } void Run(In_cclsInfo *request) override { - Out_cclsInfo out; - out.id = request->id; - out.result.db.files = db->files.size(); - out.result.db.funcs = db->funcs.size(); - out.result.db.types = db->types.size(); - out.result.db.vars = db->vars.size(); - out.result.pipeline.pendingIndexRequests = pipeline::pending_index_requests; - out.result.project.entries = 0; + Out_cclsInfo result; + result.db.files = db->files.size(); + result.db.funcs = db->funcs.size(); + result.db.types = db->types.size(); + result.db.vars = db->vars.size(); + result.pipeline.pendingIndexRequests = pipeline::pending_index_requests; + result.project.entries = 0; for (auto &[_, folder] : project->root2folder) - out.result.project.entries += folder.entries.size(); - pipeline::WriteStdout(cclsInfo, out); + result.project.entries += folder.entries.size(); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_cclsInfo); -struct In_cclsFileInfo : public RequestInMessage { +struct In_cclsFileInfo : public RequestMessage { MethodType GetMethodType() const override { return fileInfo; } struct Params { lsTextDocumentIdentifier textDocument; @@ -67,12 +62,6 @@ MAKE_REFLECT_STRUCT(In_cclsFileInfo::Params, textDocument); MAKE_REFLECT_STRUCT(In_cclsFileInfo, id, params); REGISTER_IN_MESSAGE(In_cclsFileInfo); -struct Out_cclsFileInfo : public lsOutMessage { - lsRequestId id; - QueryFile::Def result; -}; -MAKE_REFLECT_STRUCT(Out_cclsFileInfo, jsonrpc, id, result); - struct Handler_cclsFileInfo : BaseMessageHandler { MethodType GetMethodType() const override { return fileInfo; } void Run(In_cclsFileInfo *request) override { @@ -81,15 +70,14 @@ struct Handler_cclsFileInfo : BaseMessageHandler { request->params.textDocument.uri.GetPath(), &file)) return; - Out_cclsFileInfo out; - out.id = request->id; + QueryFile::Def result; // Expose some fields of |QueryFile::Def|. - out.result.path = file->def->path; - out.result.args = file->def->args; - out.result.language = file->def->language; - out.result.includes = file->def->includes; - out.result.skipped_ranges = file->def->skipped_ranges; - pipeline::WriteStdout(fileInfo, out); + result.path = file->def->path; + result.args = file->def->args; + result.language = file->def->language; + result.includes = file->def->includes; + result.skipped_ranges = file->def->skipped_ranges; + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_cclsFileInfo); diff --git a/src/messages/ccls_inheritance.cc b/src/messages/ccls_inheritance.cc index ebbe5d02..747001e7 100644 --- a/src/messages/ccls_inheritance.cc +++ b/src/messages/ccls_inheritance.cc @@ -10,9 +10,10 @@ using namespace ccls; #include namespace { -MethodType kMethodType = "$ccls/inheritance"; +MethodType kMethodType = "$ccls/inheritance", + implementation = "textDocument/implementation"; -struct In_CclsInheritance : public RequestInMessage { +struct In_cclsInheritance : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { // If id+kind are specified, expand a node; otherwise textDocument+position @@ -32,39 +33,32 @@ struct In_CclsInheritance : public RequestInMessage { } params; }; -MAKE_REFLECT_STRUCT(In_CclsInheritance::Params, textDocument, position, - id, kind, derived, qualified, levels, hierarchy); -MAKE_REFLECT_STRUCT(In_CclsInheritance, id, params); -REGISTER_IN_MESSAGE(In_CclsInheritance); +MAKE_REFLECT_STRUCT(In_cclsInheritance::Params, textDocument, position, id, + kind, derived, qualified, levels, hierarchy); +MAKE_REFLECT_STRUCT(In_cclsInheritance, id, params); +REGISTER_IN_MESSAGE(In_cclsInheritance); -struct Out_CclsInheritance - : public lsOutMessage { - struct Entry { - Usr usr; - std::string id; - SymbolKind kind; - std::string_view name; - lsLocation location; - // For unexpanded nodes, this is an upper bound because some entities may be - // undefined. If it is 0, there are no members. - int numChildren; - // Empty if the |levels| limit is reached. - std::vector children; - }; - lsRequestId id; - std::optional result; +struct Out_cclsInheritance { + Usr usr; + std::string id; + SymbolKind kind; + std::string_view name; + lsLocation location; + // For unexpanded nodes, this is an upper bound because some entities may be + // undefined. If it is 0, there are no members. + int numChildren; + // Empty if the |levels| limit is reached. + std::vector children; }; -MAKE_REFLECT_STRUCT(Out_CclsInheritance::Entry, id, kind, name, - location, numChildren, children); -MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritance, jsonrpc, - id, result); +MAKE_REFLECT_STRUCT(Out_cclsInheritance, id, kind, name, location, numChildren, + children); -bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry, - bool derived, bool qualified, int levels); +bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived, + bool qualified, int levels); template -bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry, - bool derived, bool qualified, int levels, Q &entity) { +bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived, + bool qualified, int levels, Q &entity) { const auto *def = entity.AnyDef(); if (def) { entry->name = def->Name(qualified); @@ -85,7 +79,7 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry, for (auto usr : entity.derived) { if (!seen.insert(usr).second) continue; - Out_CclsInheritance::Entry entry1; + Out_cclsInheritance entry1; entry1.id = std::to_string(usr); entry1.usr = usr; entry1.kind = entry->kind; @@ -100,7 +94,7 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry, for (auto usr : def->bases) { if (!seen.insert(usr).second) continue; - Out_CclsInheritance::Entry entry1; + Out_cclsInheritance entry1; entry1.id = std::to_string(usr); entry1.usr = usr; entry1.kind = entry->kind; @@ -114,8 +108,8 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry, return true; } -bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry, - bool derived, bool qualified, int levels) { +bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived, + bool qualified, int levels) { if (entry->kind == SymbolKind::Func) return ExpandHelper(m, entry, derived, qualified, levels, m->db->Func(entry->usr)); @@ -124,13 +118,12 @@ bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry, m->db->Type(entry->usr)); } -struct Handler_CclsInheritance - : BaseMessageHandler { +struct Handler_cclsInheritance : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - std::optional - BuildInitial(SymbolRef sym, bool derived, bool qualified, int levels) { - Out_CclsInheritance::Entry entry; + std::optional BuildInitial(SymbolRef sym, bool derived, + bool qualified, int levels) { + Out_cclsInheritance entry; entry.id = std::to_string(sym.usr); entry.usr = sym.usr; entry.kind = sym.kind; @@ -138,25 +131,24 @@ struct Handler_CclsInheritance return entry; } - void Run(In_CclsInheritance *request) override { + void Run(In_cclsInheritance *request) override { auto ¶ms = request->params; - Out_CclsInheritance out; - out.id = request->id; - + std::optional result; if (params.id.size()) { try { params.usr = std::stoull(params.id); } catch (...) { return; } - Out_CclsInheritance::Entry entry; - entry.id = std::to_string(params.usr); - entry.usr = params.usr; - entry.kind = params.kind; - if (((entry.kind == SymbolKind::Func && db->HasFunc(entry.usr)) || - (entry.kind == SymbolKind::Type && db->HasType(entry.usr))) && - Expand(this, &entry, params.derived, params.qualified, params.levels)) - out.result = std::move(entry); + result.emplace(); + result->id = std::to_string(params.usr); + result->usr = params.usr; + result->kind = params.kind; + if (!(((params.kind == SymbolKind::Func && db->HasFunc(params.usr)) || + (params.kind == SymbolKind::Type && db->HasType(params.usr))) && + Expand(this, &*result, params.derived, params.qualified, + params.levels))) + result.reset(); } else { QueryFile *file; if (!FindFileOrFail(db, project, request->id, @@ -166,23 +158,38 @@ struct Handler_CclsInheritance for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) { - out.result = BuildInitial(sym, params.derived, params.qualified, - params.levels); + result = BuildInitial(sym, params.derived, params.qualified, + params.levels); break; } } - if (params.hierarchy) { - pipeline::WriteStdout(kMethodType, out); - return; + if (params.hierarchy) + pipeline::Reply(request->id, result); + else { + auto out = FlattenHierarchy(result); + pipeline::Reply(request->id, out); } - Out_LocationList out1; - out1.id = request->id; - if (out.result) - FlattenHierarchy(*out.result, out1); - pipeline::WriteStdout(kMethodType, out1); } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsInheritance); +REGISTER_MESSAGE_HANDLER(Handler_cclsInheritance); +struct In_textDocumentImplementation : public RequestMessage { + MethodType GetMethodType() const override { return implementation; } + lsTextDocumentPositionParams params; +}; +MAKE_REFLECT_STRUCT(In_textDocumentImplementation, id, params); +REGISTER_IN_MESSAGE(In_textDocumentImplementation); + +struct Handler_textDocumentImplementation + : BaseMessageHandler { + MethodType GetMethodType() const override { return implementation; } + void Run(In_textDocumentImplementation *request) override { + In_cclsInheritance request1; + request1.params.textDocument = request->params.textDocument; + request1.params.position = request->params.position; + Handler_cclsInheritance().Run(&request1); + } +}; +REGISTER_MESSAGE_HANDLER(Handler_textDocumentImplementation); } // namespace diff --git a/src/messages/ccls_member.cc b/src/messages/ccls_member.cc index 395667d5..e7714724 100644 --- a/src/messages/ccls_member.cc +++ b/src/messages/ccls_member.cc @@ -18,7 +18,7 @@ using namespace clang; namespace { MethodType kMethodType = "$ccls/member"; -struct In_CclsMember : public RequestInMessage { +struct In_cclsMember : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { @@ -40,42 +40,36 @@ struct In_CclsMember : public RequestInMessage { } params; }; -MAKE_REFLECT_STRUCT(In_CclsMember::Params, textDocument, position, id, +MAKE_REFLECT_STRUCT(In_cclsMember::Params, textDocument, position, id, qualified, levels, kind, hierarchy); -MAKE_REFLECT_STRUCT(In_CclsMember, id, params); -REGISTER_IN_MESSAGE(In_CclsMember); +MAKE_REFLECT_STRUCT(In_cclsMember, id, params); +REGISTER_IN_MESSAGE(In_cclsMember); -struct Out_CclsMember : public lsOutMessage { - struct Entry { - Usr usr; - std::string id; - std::string_view name; - std::string fieldName; - lsLocation location; - // For unexpanded nodes, this is an upper bound because some entities may be - // undefined. If it is 0, there are no members. - int numChildren = 0; - // Empty if the |levels| limit is reached. - std::vector children; - }; - lsRequestId id; - std::optional result; +struct Out_cclsMember { + Usr usr; + std::string id; + std::string_view name; + std::string fieldName; + lsLocation location; + // For unexpanded nodes, this is an upper bound because some entities may be + // undefined. If it is 0, there are no members. + int numChildren = 0; + // Empty if the |levels| limit is reached. + std::vector children; }; -MAKE_REFLECT_STRUCT(Out_CclsMember::Entry, id, name, fieldName, - location, numChildren, children); -MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMember, jsonrpc, id, - result); +MAKE_REFLECT_STRUCT(Out_cclsMember, id, name, fieldName, location, numChildren, + children); -bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, - bool qualified, int levels, SymbolKind memberKind); +bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified, + int levels, SymbolKind memberKind); // Add a field to |entry| which is a Func/Type. -void DoField(MessageHandler *m, Out_CclsMember::Entry *entry, - const QueryVar &var, int64_t offset, bool qualified, int levels) { +void DoField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var, + int64_t offset, bool qualified, int levels) { const QueryVar::Def *def1 = var.AnyDef(); if (!def1) return; - Out_CclsMember::Entry entry1; + Out_cclsMember entry1; // With multiple inheritance, the offset is incorrect. if (offset >= 0) { if (offset / 8 < 10) @@ -112,8 +106,8 @@ void DoField(MessageHandler *m, Out_CclsMember::Entry *entry, } // Expand a type node by adding members recursively to it. -bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, - bool qualified, int levels, SymbolKind memberKind) { +bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified, + int levels, SymbolKind memberKind) { if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) { entry->name = ClangBuiltinTypeName(int(entry->usr)); return true; @@ -145,7 +139,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, } if (def->alias_of) { const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef(); - Out_CclsMember::Entry entry1; + Out_cclsMember entry1; entry1.id = std::to_string(def->alias_of); entry1.usr = def->alias_of; if (def1 && def1->spell) { @@ -175,7 +169,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, if (seen1.insert(usr).second) { QueryFunc &func1 = m->db->Func(usr); if (const QueryFunc::Def *def1 = func1.AnyDef()) { - Out_CclsMember::Entry entry1; + Out_cclsMember entry1; entry1.fieldName = def1->Name(false); if (def1->spell) { if (auto loc = @@ -196,7 +190,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, if (seen1.insert(usr).second) { QueryType &type1 = m->db->Type(usr); if (const QueryType::Def *def1 = type1.AnyDef()) { - Out_CclsMember::Entry entry1; + Out_cclsMember entry1; entry1.fieldName = def1->Name(false); if (def1->spell) { if (auto loc = @@ -227,12 +221,12 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, return true; } -struct Handler_CclsMember - : BaseMessageHandler { +struct Handler_cclsMember : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - std::optional - BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels, SymbolKind memberKind) { + std::optional BuildInitial(SymbolKind kind, Usr root_usr, + bool qualified, int levels, + SymbolKind memberKind) { switch (kind) { default: return {}; @@ -241,7 +235,7 @@ struct Handler_CclsMember if (!def) return {}; - Out_CclsMember::Entry entry; + Out_cclsMember entry; // Not type, |id| is invalid. entry.name = def->Name(qualified); if (def->spell) { @@ -261,7 +255,7 @@ struct Handler_CclsMember if (!def) return {}; - Out_CclsMember::Entry entry; + Out_cclsMember entry; entry.id = std::to_string(root_usr); entry.usr = root_usr; if (def->spell) { @@ -275,24 +269,22 @@ struct Handler_CclsMember } } - void Run(In_CclsMember *request) override { + void Run(In_cclsMember *request) override { auto ¶ms = request->params; - Out_CclsMember out; - out.id = request->id; - + std::optional result; if (params.id.size()) { try { params.usr = std::stoull(params.id); } catch (...) { return; } - Out_CclsMember::Entry entry; - entry.id = std::to_string(params.usr); - entry.usr = params.usr; + result.emplace(); + result->id = std::to_string(params.usr); + result->usr = params.usr; // entry.name is empty as it is known by the client. - if (db->HasType(entry.usr) && - Expand(this, &entry, params.qualified, params.levels, params.kind)) - out.result = std::move(entry); + if (!(db->HasType(params.usr) && Expand(this, &*result, params.qualified, + params.levels, params.kind))) + result.reset(); } else { QueryFile *file; if (!FindFileOrFail(db, project, request->id, @@ -304,14 +296,14 @@ struct Handler_CclsMember switch (sym.kind) { case SymbolKind::Func: case SymbolKind::Type: - out.result = BuildInitial(sym.kind, sym.usr, params.qualified, - params.levels, params.kind); + result = BuildInitial(sym.kind, sym.usr, params.qualified, + params.levels, params.kind); break; case SymbolKind::Var: { const QueryVar::Def *def = db->GetVar(sym).AnyDef(); if (def && def->type) - out.result = BuildInitial(SymbolKind::Type, def->type, - params.qualified, params.levels, params.kind); + result = BuildInitial(SymbolKind::Type, def->type, params.qualified, + params.levels, params.kind); break; } default: @@ -321,17 +313,14 @@ struct Handler_CclsMember } } - if (params.hierarchy) { - pipeline::WriteStdout(kMethodType, out); - return; + if (params.hierarchy) + pipeline::Reply(request->id, result); + else { + auto out = FlattenHierarchy(result); + pipeline::Reply(request->id, out); } - Out_LocationList out1; - out1.id = request->id; - if (out.result) - FlattenHierarchy(*out.result, out1); - pipeline::WriteStdout(kMethodType, out1); } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsMember); +REGISTER_MESSAGE_HANDLER(Handler_cclsMember); } // namespace diff --git a/src/messages/ccls_navigate.cc b/src/messages/ccls_navigate.cc index d0b9bcaf..9ab73178 100644 --- a/src/messages/ccls_navigate.cc +++ b/src/messages/ccls_navigate.cc @@ -9,7 +9,7 @@ using namespace ccls; namespace { MethodType kMethodType = "$ccls/navigate"; -struct In_CclsNavigate : public RequestInMessage { +struct In_CclsNavigate : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { lsTextDocumentIdentifier textDocument; @@ -88,15 +88,14 @@ struct Handler_CclsNavigate : BaseMessageHandler { res = sym.range; break; } - Out_LocationList out; - out.id = request->id; + std::vector result; if (res) if (auto ls_range = GetLsRange(wfile, *res)) { - lsLocation &ls_loc = out.result.emplace_back(); + lsLocation &ls_loc = result.emplace_back(); ls_loc.uri = params.textDocument.uri; ls_loc.range = *ls_range; } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_CclsNavigate); diff --git a/src/messages/ccls_reload.cc b/src/messages/ccls_reload.cc index 2c5f3bed..0d4ade3a 100644 --- a/src/messages/ccls_reload.cc +++ b/src/messages/ccls_reload.cc @@ -16,7 +16,7 @@ using namespace ccls; namespace { MethodType kMethodType = "$ccls/reload"; -struct In_CclsReload : public NotificationInMessage { +struct In_cclsReload : public NotificationMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { bool dependencies = true; @@ -24,14 +24,13 @@ struct In_CclsReload : public NotificationInMessage { std::vector blacklist; } params; }; -MAKE_REFLECT_STRUCT(In_CclsReload::Params, dependencies, whitelist, - blacklist); -MAKE_REFLECT_STRUCT(In_CclsReload, params); -REGISTER_IN_MESSAGE(In_CclsReload); +MAKE_REFLECT_STRUCT(In_cclsReload::Params, dependencies, whitelist, blacklist); +MAKE_REFLECT_STRUCT(In_cclsReload, params); +REGISTER_IN_MESSAGE(In_cclsReload); -struct Handler_CclsReload : BaseMessageHandler { +struct Handler_cclsReload : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - void Run(In_CclsReload *request) override { + void Run(In_cclsReload *request) override { const auto ¶ms = request->params; // Send index requests for every file. if (params.whitelist.empty() && params.blacklist.empty()) { @@ -79,5 +78,5 @@ struct Handler_CclsReload : BaseMessageHandler { } } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsReload); +REGISTER_MESSAGE_HANDLER(Handler_cclsReload); } // namespace diff --git a/src/messages/ccls_vars.cc b/src/messages/ccls_vars.cc index 01d2a972..00626e7f 100644 --- a/src/messages/ccls_vars.cc +++ b/src/messages/ccls_vars.cc @@ -9,7 +9,7 @@ using namespace ccls; namespace { MethodType kMethodType = "$ccls/vars"; -struct In_CclsVars : public RequestInMessage { +struct In_cclsVars : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params : lsTextDocumentPositionParams { // 1: field @@ -18,14 +18,14 @@ struct In_CclsVars : public RequestInMessage { unsigned kind = ~0u; } params; }; -MAKE_REFLECT_STRUCT(In_CclsVars::Params, textDocument, position, kind); -MAKE_REFLECT_STRUCT(In_CclsVars, id, params); -REGISTER_IN_MESSAGE(In_CclsVars); +MAKE_REFLECT_STRUCT(In_cclsVars::Params, textDocument, position, kind); +MAKE_REFLECT_STRUCT(In_cclsVars, id, params); +REGISTER_IN_MESSAGE(In_cclsVars); -struct Handler_CclsVars : BaseMessageHandler { +struct Handler_cclsVars : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } - void Run(In_CclsVars *request) override { + void Run(In_cclsVars *request) override { auto ¶ms = request->params; QueryFile *file; if (!FindFileOrFail(db, project, request->id, @@ -35,8 +35,7 @@ struct Handler_CclsVars : BaseMessageHandler { WorkingFile *working_file = working_files->GetFileByFilename(file->def->path); - Out_LocationList out; - out.id = request->id; + std::vector result; for (SymbolRef sym : FindSymbolsAtLocation(working_file, file, params.position)) { Usr usr = sym.usr; @@ -51,14 +50,14 @@ struct Handler_CclsVars : BaseMessageHandler { [[fallthrough]]; } case SymbolKind::Type: - out.result = GetLsLocations( + result = GetLsLocations( db, working_files, GetVarDeclarations(db, db->Type(usr).instances, params.kind)); break; } } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; -REGISTER_MESSAGE_HANDLER(Handler_CclsVars); +REGISTER_MESSAGE_HANDLER(Handler_cclsVars); } // namespace diff --git a/src/messages/exit.cc b/src/messages/exit.cc index 9e5682e9..64af3f65 100644 --- a/src/messages/exit.cc +++ b/src/messages/exit.cc @@ -4,7 +4,7 @@ #include "message_handler.h" namespace { -struct In_Exit : public NotificationInMessage { +struct In_Exit : public NotificationMessage { MethodType GetMethodType() const override { return kMethodType_Exit; } }; MAKE_REFLECT_EMPTY_STRUCT(In_Exit); diff --git a/src/messages/initialize.cc b/src/messages/initialize.cc index c2513b8e..72418faa 100644 --- a/src/messages/initialize.cc +++ b/src/messages/initialize.cc @@ -388,7 +388,7 @@ struct lsInitializeError { }; MAKE_REFLECT_STRUCT(lsInitializeError, retry); -struct In_InitializeRequest : public RequestInMessage { +struct In_InitializeRequest : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsInitializeParams params; @@ -396,15 +396,10 @@ struct In_InitializeRequest : public RequestInMessage { MAKE_REFLECT_STRUCT(In_InitializeRequest, id, params); REGISTER_IN_MESSAGE(In_InitializeRequest); -struct Out_InitializeResponse : public lsOutMessage { - struct InitializeResult { - lsServerCapabilities capabilities; - }; - lsRequestId id; - InitializeResult result; +struct lsInitializeResult { + lsServerCapabilities capabilities; }; -MAKE_REFLECT_STRUCT(Out_InitializeResponse::InitializeResult, capabilities); -MAKE_REFLECT_STRUCT(Out_InitializeResponse, jsonrpc, id, result); +MAKE_REFLECT_STRUCT(lsInitializeResult, capabilities); void *Indexer(void *arg_) { MessageHandler *h; @@ -474,13 +469,10 @@ struct Handler_Initialize : BaseMessageHandler { // Send initialization before starting indexers, so we don't send a // status update too early. - // TODO: query request->params.capabilities.textDocument and support - // only things the client supports. - - Out_InitializeResponse out; - out.id = request->id; - - pipeline::WriteStdout(kMethodType, out); + { + lsInitializeResult result; + pipeline::Reply(request->id, result); + } // Set project root. EnsureEndsInSlash(project_path); diff --git a/src/messages/shutdown.cc b/src/messages/shutdown.cc index c43ddc41..f19f3e03 100644 --- a/src/messages/shutdown.cc +++ b/src/messages/shutdown.cc @@ -8,24 +8,17 @@ using namespace ccls; namespace { MethodType kMethodType = "shutdown"; -struct In_Shutdown : public RequestInMessage { +struct In_Shutdown : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } }; MAKE_REFLECT_STRUCT(In_Shutdown, id); REGISTER_IN_MESSAGE(In_Shutdown); -struct Out_Shutdown : public lsOutMessage { - lsRequestId id; - JsonNull result; -}; -MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result); - struct Handler_Shutdown : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } void Run(In_Shutdown *request) override { - Out_Shutdown out; - out.id = request->id; - pipeline::WriteStdout(kMethodType, out); + JsonNull result; + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_Shutdown); diff --git a/src/messages/textDocument_codeAction.cc b/src/messages/textDocument_codeAction.cc index d3d6dd22..ffaa62cd 100644 --- a/src/messages/textDocument_codeAction.cc +++ b/src/messages/textDocument_codeAction.cc @@ -9,7 +9,7 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/codeAction"; -struct In_TextDocumentCodeAction : public RequestInMessage { +struct In_TextDocumentCodeAction : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } // Contains additional diagnostic information about the context in which @@ -42,13 +42,6 @@ struct lsCodeAction { }; MAKE_REFLECT_STRUCT(lsCodeAction, title, kind, edit); -struct Out_TextDocumentCodeAction - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result); - struct Handler_TextDocumentCodeAction : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } @@ -59,20 +52,19 @@ struct Handler_TextDocumentCodeAction working_files->GetFileByFilename(params.textDocument.uri.GetPath()); if (!wfile) return; - Out_TextDocumentCodeAction out; - out.id = request->id; + std::vector result; std::vector diagnostics; working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; }); for (lsDiagnostic &diag : diagnostics) if (diag.fixits_.size()) { - lsCodeAction &cmd = out.result.emplace_back(); + lsCodeAction &cmd = result.emplace_back(); cmd.title = "FixIt: " + diag.message; auto &edit = cmd.edit.documentChanges.emplace_back(); edit.textDocument.uri = params.textDocument.uri; edit.textDocument.version = wfile->version; edit.edits = diag.fixits_; } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction); diff --git a/src/messages/textDocument_codeLens.cc b/src/messages/textDocument_codeLens.cc index a0c99bf6..a0c1fc2e 100644 --- a/src/messages/textDocument_codeLens.cc +++ b/src/messages/textDocument_codeLens.cc @@ -36,12 +36,6 @@ struct Cmd_xref { }; MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field); -struct Out_xref : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_xref, jsonrpc, id, result); - template std::string ToString(T &v) { rapidjson::StringBuffer output; @@ -57,7 +51,7 @@ struct CommonCodeLensParams { WorkingFile *wfile; }; -struct In_TextDocumentCodeLens : public RequestInMessage { +struct In_TextDocumentCodeLens : public RequestMessage { MethodType GetMethodType() const override { return codeLens; } struct Params { lsTextDocumentIdentifier textDocument; @@ -67,20 +61,12 @@ MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens::Params, textDocument); MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens, id, params); REGISTER_IN_MESSAGE(In_TextDocumentCodeLens); -struct Out_TextDocumentCodeLens - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result); - struct Handler_TextDocumentCodeLens : BaseMessageHandler { MethodType GetMethodType() const override { return codeLens; } void Run(In_TextDocumentCodeLens *request) override { auto ¶ms = request->params; - Out_TextDocumentCodeLens out; - out.id = request->id; + std::vector result; std::string path = params.textDocument.uri.GetPath(); QueryFile *file; @@ -95,7 +81,7 @@ struct Handler_TextDocumentCodeLens std::optional range = GetLsRange(wfile, use.range); if (!range) return; - lsCodeLens &code_lens = out.result.emplace_back(); + lsCodeLens &code_lens = result.emplace_back(); code_lens.range = *range; code_lens.command = lsCommand(); code_lens.command->command = std::string(ccls_xref); @@ -166,12 +152,12 @@ struct Handler_TextDocumentCodeLens }; } - pipeline::WriteStdout(codeLens, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens); -struct In_WorkspaceExecuteCommand : public RequestInMessage { +struct In_WorkspaceExecuteCommand : public RequestMessage { MethodType GetMethodType() const override { return executeCommand; } lsCommand params; }; @@ -191,12 +177,11 @@ struct Handler_WorkspaceExecuteCommand if (params.command == ccls_xref) { Cmd_xref cmd; Reflect(json_reader, cmd); - Out_xref out; - out.id = request->id; + std::vector result; auto Map = [&](auto &&uses) { for (auto &use : uses) if (auto loc = GetLsLocation(db, working_files, use)) - out.result.push_back(std::move(*loc)); + result.push_back(std::move(*loc)); }; switch (cmd.kind) { case SymbolKind::Func: { @@ -235,7 +220,7 @@ struct Handler_WorkspaceExecuteCommand default: break; } - pipeline::WriteStdout(executeCommand, out); + pipeline::Reply(request->id, result); } } }; diff --git a/src/messages/textDocument_completion.cc b/src/messages/textDocument_completion.cc index 481d5959..9477533a 100644 --- a/src/messages/textDocument_completion.cc +++ b/src/messages/textDocument_completion.cc @@ -54,28 +54,21 @@ struct lsCompletionParams : lsTextDocumentPositionParams { }; MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context); -struct In_TextDocumentComplete : public RequestInMessage { +struct In_TextDocumentComplete : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsCompletionParams params; }; MAKE_REFLECT_STRUCT(In_TextDocumentComplete, id, params); REGISTER_IN_MESSAGE(In_TextDocumentComplete); -struct lsTextDocumentCompleteResult { +struct lsCompletionList { // This list it not complete. Further typing should result in recomputing // this list. bool isIncomplete = false; // The completion items. std::vector items; }; -MAKE_REFLECT_STRUCT(lsTextDocumentCompleteResult, isIncomplete, items); - -struct Out_TextDocumentComplete - : public lsOutMessage { - lsRequestId id; - lsTextDocumentCompleteResult result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result); +MAKE_REFLECT_STRUCT(lsCompletionList, isIncomplete, items); void DecorateIncludePaths(const std::smatch &match, std::vector *items) { @@ -141,11 +134,11 @@ template char *tofixedbase64(T input, char *out) { // Pre-filters completion responses before sending to vscode. This results in a // significantly snappier completion experience as vscode is easily overloaded // when given 1000+ completion items. -void FilterCandidates(Out_TextDocumentComplete *complete_response, +void FilterCandidates(lsCompletionList &result, const std::string &complete_text, lsPosition begin_pos, lsPosition end_pos, const std::string &buffer_line) { assert(begin_pos.line == end_pos.line); - auto &items = complete_response->result.items; + auto &items = result.items; // People usually does not want to insert snippets or parenthesis when // changing function or type names, e.g. "str.|()" or "std::|". @@ -161,7 +154,7 @@ void FilterCandidates(Out_TextDocumentComplete *complete_response, int max_num = g_config->completion.maxNum; if (items.size() > max_num) { items.resize(max_num); - complete_response->result.isIncomplete = true; + result.isIncomplete = true; } for (auto &item : items) { @@ -485,13 +478,12 @@ struct Handler_TextDocumentCompletion static CompleteConsumerCache> cache; const auto ¶ms = request->params; - Out_TextDocumentComplete out; - out.id = request->id; + lsCompletionList result; std::string path = params.textDocument.uri.GetPath(); WorkingFile *file = working_files->GetFileByFilename(path); if (!file) { - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); return; } @@ -536,7 +528,7 @@ struct Handler_TextDocumentCompletion } if (did_fail_check) { - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); return; } } @@ -549,8 +541,7 @@ struct Handler_TextDocumentCompletion ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line); if (preprocess.ok && preprocess.keyword.compare("include") == 0) { - Out_TextDocumentComplete out; - out.id = request->id; + lsCompletionList result; { std::unique_lock lock( include_complete->completion_items_mutex, std::defer_lock); @@ -559,14 +550,14 @@ struct Handler_TextDocumentCompletion std::string quote = preprocess.match[5]; for (auto &item : include_complete->completion_items) if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\"")) - out.result.items.push_back(item); + result.items.push_back(item); } begin_pos.character = 0; end_pos.character = (int)buffer_line.size(); - FilterCandidates(&out, preprocess.pattern, begin_pos, end_pos, + FilterCandidates(result, preprocess.pattern, begin_pos, end_pos, buffer_line); - DecorateIncludePaths(preprocess.match, &out.result.items); - pipeline::WriteStdout(kMethodType, out); + DecorateIncludePaths(preprocess.match, &result.items); + pipeline::Reply(request->id, result); } else { std::string path = params.textDocument.uri.GetPath(); CompletionManager::OnComplete callback = @@ -575,13 +566,12 @@ struct Handler_TextDocumentCompletion if (!OptConsumer) return; auto *Consumer = static_cast(OptConsumer); - Out_TextDocumentComplete out; - out.id = id; - out.result.items = Consumer->ls_items; + lsCompletionList result; + result.items = Consumer->ls_items; - FilterCandidates(&out, completion_text, begin_pos, end_pos, + FilterCandidates(result, completion_text, begin_pos, end_pos, buffer_line); - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(id, result); if (!Consumer->from_cache) { cache.WithLock([&]() { cache.path = path; diff --git a/src/messages/textDocument_definition.cc b/src/messages/textDocument_definition.cc index 9ed42798..0e4575b7 100644 --- a/src/messages/textDocument_definition.cc +++ b/src/messages/textDocument_definition.cc @@ -14,7 +14,7 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/definition"; -struct In_TextDocumentDefinition : public RequestInMessage { +struct In_TextDocumentDefinition : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; @@ -54,9 +54,7 @@ struct Handler_TextDocumentDefinition params.textDocument.uri.GetPath(), &file, &file_id)) return; - Out_LocationList out; - out.id = request->id; - + std::vector result; Maybe on_def; WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); lsPosition &ls_pos = params.position; @@ -92,19 +90,18 @@ struct Handler_TextDocumentDefinition uses.push_back(*on_def); } auto locs = GetLsLocations(db, working_files, uses); - out.result.insert(out.result.end(), locs.begin(), locs.end()); + result.insert(result.end(), locs.begin(), locs.end()); } - if (out.result.size()) { - std::sort(out.result.begin(), out.result.end()); - out.result.erase(std::unique(out.result.begin(), out.result.end()), - out.result.end()); + if (result.size()) { + std::sort(result.begin(), result.end()); + result.erase(std::unique(result.begin(), result.end()), result.end()); } else { Maybe range; // Check #include for (const IndexInclude &include : file->def->includes) { if (include.line == ls_pos.line) { - out.result.push_back( + result.push_back( lsLocation{lsDocumentUri::FromPath(include.resolved_path)}); range = {{0, 0}, {0, 0}}; break; @@ -165,12 +162,12 @@ struct Handler_TextDocumentDefinition Maybe dr = GetDefinitionSpell(db, best_sym); assert(dr); if (auto loc = GetLsLocation(db, working_files, *dr)) - out.result.push_back(*loc); + result.push_back(*loc); } } } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition); diff --git a/src/messages/textDocument_did.cc b/src/messages/textDocument_did.cc index a76f8889..7fb72b2e 100644 --- a/src/messages/textDocument_did.cc +++ b/src/messages/textDocument_did.cc @@ -15,7 +15,7 @@ MethodType didClose = "textDocument/didClose"; MethodType didOpen = "textDocument/didOpen"; MethodType didSave = "textDocument/didSave"; -struct In_TextDocumentDidChange : public NotificationInMessage { +struct In_TextDocumentDidChange : public NotificationMessage { MethodType GetMethodType() const override { return didChange; } lsTextDocumentDidChangeParams params; }; @@ -39,7 +39,7 @@ struct Handler_TextDocumentDidChange }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange); -struct In_TextDocumentDidClose : public NotificationInMessage { +struct In_TextDocumentDidClose : public NotificationMessage { MethodType GetMethodType() const override { return didClose; } struct Params { lsTextDocumentIdentifier textDocument; @@ -56,19 +56,13 @@ struct Handler_TextDocumentDidClose void Run(In_TextDocumentDidClose *request) override { std::string path = request->params.textDocument.uri.GetPath(); - // Clear any diagnostics for the file. - Out_TextDocumentPublishDiagnostics out; - out.params.uri = request->params.textDocument.uri; - pipeline::WriteStdout(didClose, out); - - // Remove internal state. working_files->OnClose(request->params.textDocument); clang_complete->OnClose(path); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose); -struct In_TextDocumentDidOpen : public NotificationInMessage { +struct In_TextDocumentDidOpen : public NotificationMessage { MethodType GetMethodType() const override { return didOpen; } struct Params { @@ -101,9 +95,9 @@ struct Handler_TextDocumentDidOpen QueryFile *file = nullptr; FindFileOrFail(db, project, std::nullopt, path, &file); - if (file && file->def) { - EmitSkippedRanges(working_file, file->def->skipped_ranges); - EmitSemanticHighlighting(db, working_file, file); + if (file) { + EmitSkippedRanges(working_file, *file); + EmitSemanticHighlight(db, working_file, *file); } include_complete->AddFile(working_file->filename); @@ -125,7 +119,7 @@ struct Handler_TextDocumentDidOpen }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen); -struct In_TextDocumentDidSave : public NotificationInMessage { +struct In_TextDocumentDidSave : public NotificationMessage { MethodType GetMethodType() const override { return didSave; } struct Params { diff --git a/src/messages/textDocument_documentHighlight.cc b/src/messages/textDocument_documentHighlight.cc index 72be0cc0..48fe8157 100644 --- a/src/messages/textDocument_documentHighlight.cc +++ b/src/messages/textDocument_documentHighlight.cc @@ -27,20 +27,13 @@ struct lsDocumentHighlight { }; MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role); -struct In_TextDocumentDocumentHighlight : public RequestInMessage { +struct In_TextDocumentDocumentHighlight : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; MAKE_REFLECT_STRUCT(In_TextDocumentDocumentHighlight, id, params); REGISTER_IN_MESSAGE(In_TextDocumentDocumentHighlight); -struct Out_TextDocumentDocumentHighlight - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentHighlight, jsonrpc, id, result); - struct Handler_TextDocumentDocumentHighlight : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } @@ -51,14 +44,12 @@ struct Handler_TextDocumentDocumentHighlight request->params.textDocument.uri.GetPath(), &file, &file_id)) return; - WorkingFile *working_file = - working_files->GetFileByFilename(file->def->path); - Out_TextDocumentDocumentHighlight out; - out.id = request->id; + WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); + std::vector result; - std::vector syms = FindSymbolsAtLocation( - working_file, file, request->params.position, true); + std::vector syms = + FindSymbolsAtLocation(wfile, file, request->params.position, true); for (auto [sym, refcnt] : file->symbol2refcnt) { if (refcnt <= 0) continue; @@ -78,11 +69,11 @@ struct Handler_TextDocumentDocumentHighlight else highlight.kind = lsDocumentHighlight::Text; highlight.role = sym.role; - out.result.push_back(highlight); + result.push_back(highlight); } } - std::sort(out.result.begin(), out.result.end()); - pipeline::WriteStdout(kMethodType, out); + std::sort(result.begin(), result.end()); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight); diff --git a/src/messages/textDocument_documentSymbol.cc b/src/messages/textDocument_documentSymbol.cc index 63fcbaef..e58aba80 100644 --- a/src/messages/textDocument_documentSymbol.cc +++ b/src/messages/textDocument_documentSymbol.cc @@ -12,7 +12,7 @@ MAKE_HASHABLE(SymbolIdx, t.usr, t.kind); namespace { MethodType kMethodType = "textDocument/documentSymbol"; -struct In_TextDocumentDocumentSymbol : public RequestInMessage { +struct In_TextDocumentDocumentSymbol : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { lsTextDocumentIdentifier textDocument; @@ -28,20 +28,6 @@ MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol::Params, textDocument, all, MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol, id, params); REGISTER_IN_MESSAGE(In_TextDocumentDocumentSymbol); -struct Out_SimpleDocumentSymbol - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_SimpleDocumentSymbol, jsonrpc, id, result); - -struct Out_TextDocumentDocumentSymbol - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result); - struct lsDocumentSymbol { std::string name; std::string detail; @@ -57,13 +43,6 @@ void Reflect(Writer &vis, std::unique_ptr &v) { Reflect(vis, *v); } -struct Out_HierarchicalDocumentSymbol - : public lsOutMessage { - lsRequestId id; - std::vector> result; -}; -MAKE_REFLECT_STRUCT(Out_HierarchicalDocumentSymbol, jsonrpc, id, result); - template bool Ignore(const Def *def) { return false; @@ -95,15 +74,14 @@ struct Handler_TextDocumentDocumentSymbol const auto &symbol2refcnt = params.all ? file->symbol2refcnt : file->outline2refcnt; if (params.startLine >= 0) { - Out_SimpleDocumentSymbol out; - out.id = request->id; + std::vector result; for (auto [sym, refcnt] : symbol2refcnt) if (refcnt > 0 && params.startLine <= sym.range.start.line && sym.range.start.line <= params.endLine) if (auto loc = GetLsLocation(db, working_files, sym, file_id)) - out.result.push_back(loc->range); - std::sort(out.result.begin(), out.result.end()); - pipeline::WriteStdout(kMethodType, out); + result.push_back(loc->range); + std::sort(result.begin(), result.end()); + pipeline::Reply(request->id, result); } else if (g_config->client.hierarchicalDocumentSymbolSupport) { std::unordered_map> sym2ds; std::vector> funcs; @@ -195,15 +173,13 @@ struct Handler_TextDocumentDocumentSymbol ds->children.push_back(std::move(it->second)); } } - Out_HierarchicalDocumentSymbol out; - out.id = request->id; + std::vector> result; for (auto &[_, ds] : sym2ds) if (ds) - out.result.push_back(std::move(ds)); - pipeline::WriteStdout(kMethodType, out); + result.push_back(std::move(ds)); + pipeline::Reply(request->id, result); } else { - Out_TextDocumentDocumentSymbol out; - out.id = request->id; + std::vector result; for (auto [sym, refcnt] : symbol2refcnt) { if (refcnt <= 0) continue; if (std::optional info = @@ -215,11 +191,11 @@ struct Handler_TextDocumentDocumentSymbol continue; if (auto loc = GetLsLocation(db, working_files, sym, file_id)) { info->location = *loc; - out.result.push_back(*info); + result.push_back(*info); } } } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } } }; diff --git a/src/messages/textDocument_formatting.cc b/src/messages/textDocument_formatting.cc index b776efe4..1cc19397 100644 --- a/src/messages/textDocument_formatting.cc +++ b/src/messages/textDocument_formatting.cc @@ -24,13 +24,6 @@ struct lsFormattingOptions { }; MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces); -struct Out_TextDocumentFormatting - : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentFormatting, jsonrpc, id, result); - llvm::Expected FormatCode(std::string_view code, std::string_view file, tooling::Range Range) { StringRef Code(code.data(), code.size()), File(file.data(), file.size()); @@ -79,20 +72,17 @@ void Format(WorkingFile *wfile, tooling::Range range, lsRequestId id) { auto ReplsOrErr = FormatCode(code, wfile->filename, range); if (ReplsOrErr) { - Out_TextDocumentFormatting out; - out.id = id; - out.result = ReplacementsToEdits(code, *ReplsOrErr); - pipeline::WriteStdout(formatting, out); + auto result = ReplacementsToEdits(code, *ReplsOrErr); + pipeline::Reply(id, result); } else { - Out_Error err; - err.id = id; - err.error.code = lsErrorCodes::UnknownErrorCode; - err.error.message = llvm::toString(ReplsOrErr.takeError()); - pipeline::WriteStdout(kMethodType_Unknown, err); + lsResponseError err; + err.code = lsErrorCodes::UnknownErrorCode; + err.message = llvm::toString(ReplsOrErr.takeError()); + pipeline::ReplyError(id, err); } } -struct In_TextDocumentFormatting : public RequestInMessage { +struct In_TextDocumentFormatting : public RequestMessage { MethodType GetMethodType() const override { return formatting; } struct Params { lsTextDocumentIdentifier textDocument; @@ -120,7 +110,7 @@ struct Handler_TextDocumentFormatting }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting); -struct In_TextDocumentOnTypeFormatting : public RequestInMessage { +struct In_TextDocumentOnTypeFormatting : public RequestMessage { MethodType GetMethodType() const override { return onTypeFormatting; } struct Params { lsTextDocumentIdentifier textDocument; @@ -156,7 +146,7 @@ struct Handler_TextDocumentOnTypeFormatting }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentOnTypeFormatting); -struct In_TextDocumentRangeFormatting : public RequestInMessage { +struct In_TextDocumentRangeFormatting : public RequestMessage { MethodType GetMethodType() const override { return rangeFormatting; } struct Params { lsTextDocumentIdentifier textDocument; diff --git a/src/messages/textDocument_hover.cc b/src/messages/textDocument_hover.cc index 548eae8c..6d95f88e 100644 --- a/src/messages/textDocument_hover.cc +++ b/src/messages/textDocument_hover.cc @@ -58,25 +58,18 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) { return {hover, ls_comments}; } -struct In_TextDocumentHover : public RequestInMessage { +struct In_TextDocumentHover : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; MAKE_REFLECT_STRUCT(In_TextDocumentHover, id, params); REGISTER_IN_MESSAGE(In_TextDocumentHover); -struct Out_TextDocumentHover : public lsOutMessage { - struct Result { - std::vector contents; - std::optional range; - }; - - lsRequestId id; - std::optional result; +struct lsHover { + std::vector contents; + std::optional range; }; -MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range); -MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, jsonrpc, id, - result); +MAKE_REFLECT_STRUCT(lsHover, contents, range); struct Handler_TextDocumentHover : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } @@ -87,33 +80,27 @@ struct Handler_TextDocumentHover : BaseMessageHandler { params.textDocument.uri.GetPath(), &file)) return; - WorkingFile *working_file = - working_files->GetFileByFilename(file->def->path); + WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); + lsHover result; - Out_TextDocumentHover out; - out.id = request->id; - - for (SymbolRef sym : - FindSymbolsAtLocation(working_file, file, params.position)) { - // Found symbol. Return hover. + for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) { std::optional ls_range = GetLsRange( working_files->GetFileByFilename(file->def->path), sym.range); if (!ls_range) continue; - auto[hover, comments] = GetHover(db, file->def->language, sym, file->id); + auto [hover, comments] = GetHover(db, file->def->language, sym, file->id); if (comments || hover) { - out.result = Out_TextDocumentHover::Result(); - out.result->range = *ls_range; + result.range = *ls_range; if (comments) - out.result->contents.push_back(*comments); + result.contents.push_back(*comments); if (hover) - out.result->contents.push_back(*hover); + result.contents.push_back(*hover); break; } } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover); diff --git a/src/messages/textDocument_implementation.cc b/src/messages/textDocument_implementation.cc deleted file mode 100644 index c5a871c8..00000000 --- a/src/messages/textDocument_implementation.cc +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#include "message_handler.h" -#include "pipeline.hh" -#include "query_utils.h" -using namespace ccls; - -namespace { -MethodType kMethodType = "textDocument/implementation"; - -struct In_TextDocumentImplementation : public RequestInMessage { - MethodType GetMethodType() const override { return kMethodType; } - lsTextDocumentPositionParams params; -}; -MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params); -REGISTER_IN_MESSAGE(In_TextDocumentImplementation); - -struct Handler_TextDocumentImplementation - : BaseMessageHandler { - MethodType GetMethodType() const override { return kMethodType; } - void Run(In_TextDocumentImplementation *request) override { - QueryFile *file; - if (!FindFileOrFail(db, project, request->id, - request->params.textDocument.uri.GetPath(), &file)) { - return; - } - - WorkingFile *working_file = - working_files->GetFileByFilename(file->def->path); - - Out_LocationList out; - out.id = request->id; - for (SymbolRef sym : - FindSymbolsAtLocation(working_file, file, request->params.position)) { - if (sym.kind == SymbolKind::Type) { - QueryType &type = db->GetType(sym); - out.result = GetLsLocations(db, working_files, - GetTypeDeclarations(db, type.derived)); - break; - } else if (sym.kind == SymbolKind::Func) { - QueryFunc &func = db->GetFunc(sym); - out.result = GetLsLocations(db, working_files, - GetFuncDeclarations(db, func.derived)); - break; - } - } - pipeline::WriteStdout(kMethodType, out); - } -}; -REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation); -} // namespace diff --git a/src/messages/textDocument_references.cc b/src/messages/textDocument_references.cc index 7dbc5192..795dc605 100644 --- a/src/messages/textDocument_references.cc +++ b/src/messages/textDocument_references.cc @@ -12,7 +12,7 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/references"; -struct In_TextDocumentReferences : public RequestInMessage { +struct In_TextDocumentReferences : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct lsReferenceContext { bool base = true; @@ -48,11 +48,10 @@ struct Handler_TextDocumentReferences if (!FindFileOrFail(db, project, request->id, params.textDocument.uri.GetPath(), &file)) return; - Out_LocationList out; - out.id = request->id; + std::vector result; WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); if (!file) { - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); return; } @@ -74,7 +73,7 @@ struct Handler_TextDocumentReferences !(use.role & params.context.excludeRole) && seen_uses.insert(use).second) if (auto loc = GetLsLocation(db, working_files, use)) { - out.result.push_back(*loc); + result.push_back(*loc); } }; WithEntity(db, sym, [&](const auto &entity) { @@ -104,7 +103,7 @@ struct Handler_TextDocumentReferences break; } - if (out.result.empty()) { + if (result.empty()) { // |path| is the #include line. If the cursor is not on such line but line // = 0, // use the current filename. @@ -122,16 +121,16 @@ struct Handler_TextDocumentReferences for (const IndexInclude &include : file1.def->includes) if (include.resolved_path == path) { // Another file |file1| has the same include line. - lsLocation &loc = out.result.emplace_back(); + lsLocation &loc = result.emplace_back(); loc.uri = lsDocumentUri::FromPath(file1.def->path); loc.range.start.line = loc.range.end.line = include.line; break; } } - if ((int)out.result.size() >= g_config->xref.maxNum) - out.result.resize(g_config->xref.maxNum); - pipeline::WriteStdout(kMethodType, out); + if ((int)result.size() >= g_config->xref.maxNum) + result.resize(g_config->xref.maxNum); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences); diff --git a/src/messages/textDocument_rename.cc b/src/messages/textDocument_rename.cc index 410ebb1f..02a17b01 100644 --- a/src/messages/textDocument_rename.cc +++ b/src/messages/textDocument_rename.cc @@ -51,7 +51,7 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *working_files, return edit; } -struct In_TextDocumentRename : public RequestInMessage { +struct In_TextDocumentRename : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { // The document to format. @@ -72,12 +72,6 @@ MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, textDocument, position, MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params); REGISTER_IN_MESSAGE(In_TextDocumentRename); -struct Out_TextDocumentRename : public lsOutMessage { - lsRequestId id; - lsWorkspaceEdit result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result); - struct Handler_TextDocumentRename : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } void Run(In_TextDocumentRename *request) override { @@ -85,25 +79,19 @@ struct Handler_TextDocumentRename : BaseMessageHandler { QueryFile *file; if (!FindFileOrFail(db, project, request->id, request->params.textDocument.uri.GetPath(), &file, - &file_id)) { + &file_id)) return; - } - - WorkingFile *working_file = - working_files->GetFileByFilename(file->def->path); - - Out_TextDocumentRename out; - out.id = request->id; + WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); + lsWorkspaceEdit result; for (SymbolRef sym : - FindSymbolsAtLocation(working_file, file, request->params.position)) { - // Found symbol. Return references to rename. - out.result = + FindSymbolsAtLocation(wfile, file, request->params.position)) { + result = BuildWorkspaceEdit(db, working_files, sym, request->params.newName); break; } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename); diff --git a/src/messages/textDocument_signatureHelp.cc b/src/messages/textDocument_signatureHelp.cc index d64030ad..ee8bef91 100644 --- a/src/messages/textDocument_signatureHelp.cc +++ b/src/messages/textDocument_signatureHelp.cc @@ -43,20 +43,13 @@ struct lsSignatureHelp { MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature, activeParameter); -struct In_TextDocumentSignatureHelp : public RequestInMessage { +struct In_TextDocumentSignatureHelp : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; MAKE_REFLECT_STRUCT(In_TextDocumentSignatureHelp, id, params); REGISTER_IN_MESSAGE(In_TextDocumentSignatureHelp); -struct Out_TextDocumentSignatureHelp - : public lsOutMessage { - lsRequestId id; - lsSignatureHelp result; -}; -MAKE_REFLECT_STRUCT(Out_TextDocumentSignatureHelp, jsonrpc, id, result); - std::string BuildOptional(const CodeCompletionString &CCS, std::vector &ls_params) { std::string ret; @@ -187,10 +180,7 @@ struct Handler_TextDocumentSignatureHelp if (!OptConsumer) return; auto *Consumer = static_cast(OptConsumer); - Out_TextDocumentSignatureHelp out; - out.id = id; - out.result = Consumer->ls_sighelp; - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(id, Consumer->ls_sighelp); if (!Consumer->from_cache) { cache.WithLock([&]() { cache.path = path; diff --git a/src/messages/textDocument_typeDefinition.cc b/src/messages/textDocument_typeDefinition.cc index 8dcdac71..209e3802 100644 --- a/src/messages/textDocument_typeDefinition.cc +++ b/src/messages/textDocument_typeDefinition.cc @@ -9,7 +9,7 @@ using namespace ccls; namespace { MethodType kMethodType = "textDocument/typeDefinition"; -struct In_TextDocumentTypeDefinition : public RequestInMessage { +struct In_TextDocumentTypeDefinition : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } lsTextDocumentPositionParams params; }; @@ -28,18 +28,17 @@ struct Handler_TextDocumentTypeDefinition WorkingFile *working_file = working_files->GetFileByFilename(file->def->path); - Out_LocationList out; - out.id = request->id; + std::vector result; auto Add = [&](const QueryType &type) { for (const auto &def : type.def) if (def.spell) { if (auto ls_loc = GetLsLocation(db, working_files, *def.spell)) - out.result.push_back(*ls_loc); + result.push_back(*ls_loc); } - if (out.result.empty()) + if (result.empty()) for (const DeclRef &dr : type.declarations) if (auto ls_loc = GetLsLocation(db, working_files, dr)) - out.result.push_back(*ls_loc); + result.push_back(*ls_loc); }; for (SymbolRef sym : FindSymbolsAtLocation(working_file, file, request->params.position)) { @@ -63,7 +62,7 @@ struct Handler_TextDocumentTypeDefinition } } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition); diff --git a/src/messages/workspace_did.cc b/src/messages/workspace_did.cc index 949436f5..46ae4cb5 100644 --- a/src/messages/workspace_did.cc +++ b/src/messages/workspace_did.cc @@ -25,6 +25,7 @@ using namespace ccls; namespace { MethodType didChangeConfiguration = "workspace/didChangeConfiguration", + didChangeWatchedFiles = "workspace/didChangeWatchedFiles", didChangeWorkspaceFolders = "workspace/didChangeWorkspaceFolders"; struct lsDidChangeConfigurationParams { @@ -32,7 +33,7 @@ struct lsDidChangeConfigurationParams { }; MAKE_REFLECT_STRUCT(lsDidChangeConfigurationParams, placeholder); -struct In_workspaceDidChangeConfiguration : public NotificationInMessage { +struct In_workspaceDidChangeConfiguration : public NotificationMessage { MethodType GetMethodType() const override { return didChangeConfiguration; } lsDidChangeConfigurationParams params; }; @@ -53,12 +54,66 @@ struct Handler_workspaceDidChangeConfiguration }; REGISTER_MESSAGE_HANDLER(Handler_workspaceDidChangeConfiguration); +enum class lsFileChangeType { + Created = 1, + Changed = 2, + Deleted = 3, +}; +MAKE_REFLECT_TYPE_PROXY(lsFileChangeType); + +struct lsFileEvent { + lsDocumentUri uri; + lsFileChangeType type; +}; +MAKE_REFLECT_STRUCT(lsFileEvent, uri, type); + +struct lsDidChangeWatchedFilesParams { + std::vector changes; +}; +MAKE_REFLECT_STRUCT(lsDidChangeWatchedFilesParams, changes); + +struct In_WorkspaceDidChangeWatchedFiles : public NotificationMessage { + MethodType GetMethodType() const override { return didChangeWatchedFiles; } + lsDidChangeWatchedFilesParams params; +}; +MAKE_REFLECT_STRUCT(In_WorkspaceDidChangeWatchedFiles, params); +REGISTER_IN_MESSAGE(In_WorkspaceDidChangeWatchedFiles); + +struct Handler_WorkspaceDidChangeWatchedFiles + : BaseMessageHandler { + MethodType GetMethodType() const override { return didChangeWatchedFiles; } + void Run(In_WorkspaceDidChangeWatchedFiles *request) override { + for (lsFileEvent &event : request->params.changes) { + std::string path = event.uri.GetPath(); + IndexMode mode = working_files->GetFileByFilename(path) + ? IndexMode::Normal + : IndexMode::NonInteractive; + switch (event.type) { + case lsFileChangeType::Created: + case lsFileChangeType::Changed: { + pipeline::Index(path, {}, mode); + if (mode == IndexMode::Normal) + clang_complete->NotifySave(path); + else + clang_complete->OnClose(path); + break; + } + case lsFileChangeType::Deleted: + pipeline::Index(path, {}, mode); + clang_complete->OnClose(path); + break; + } + } + } +}; +REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles); + struct lsWorkspaceFoldersChangeEvent { std::vector added, removed; }; MAKE_REFLECT_STRUCT(lsWorkspaceFoldersChangeEvent, added, removed); -struct In_workspaceDidChangeWorkspaceFolders : public NotificationInMessage { +struct In_workspaceDidChangeWorkspaceFolders : public NotificationMessage { MethodType GetMethodType() const override { return didChangeWorkspaceFolders; } diff --git a/src/messages/workspace_didChangeWatchedFiles.cc b/src/messages/workspace_didChangeWatchedFiles.cc deleted file mode 100644 index 90c8e600..00000000 --- a/src/messages/workspace_didChangeWatchedFiles.cc +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#include "clang_complete.hh" -#include "message_handler.h" -#include "pipeline.hh" -#include "project.h" -#include "working_files.h" -using namespace ccls; - -namespace { -MethodType kMethodType = "workspace/didChangeWatchedFiles"; - -enum class lsFileChangeType { - Created = 1, - Changed = 2, - Deleted = 3, -}; -MAKE_REFLECT_TYPE_PROXY(lsFileChangeType); - -struct lsFileEvent { - lsDocumentUri uri; - lsFileChangeType type; -}; -MAKE_REFLECT_STRUCT(lsFileEvent, uri, type); - -struct lsDidChangeWatchedFilesParams { - std::vector changes; -}; -MAKE_REFLECT_STRUCT(lsDidChangeWatchedFilesParams, changes); - -struct In_WorkspaceDidChangeWatchedFiles : public NotificationInMessage { - MethodType GetMethodType() const override { return kMethodType; } - lsDidChangeWatchedFilesParams params; -}; -MAKE_REFLECT_STRUCT(In_WorkspaceDidChangeWatchedFiles, params); -REGISTER_IN_MESSAGE(In_WorkspaceDidChangeWatchedFiles); - -struct Handler_WorkspaceDidChangeWatchedFiles - : BaseMessageHandler { - MethodType GetMethodType() const override { return kMethodType; } - void Run(In_WorkspaceDidChangeWatchedFiles *request) override { - for (lsFileEvent &event : request->params.changes) { - std::string path = event.uri.GetPath(); - IndexMode mode = working_files->GetFileByFilename(path) - ? IndexMode::Normal - : IndexMode::NonInteractive; - switch (event.type) { - case lsFileChangeType::Created: - case lsFileChangeType::Changed: { - pipeline::Index(path, {}, mode); - if (mode == IndexMode::Normal) - clang_complete->NotifySave(path); - else - clang_complete->OnClose(path); - break; - } - case lsFileChangeType::Deleted: - pipeline::Index(path, {}, mode); - clang_complete->OnClose(path); - break; - } - } - } -}; -REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles); -} // namespace diff --git a/src/messages/workspace_symbol.cc b/src/messages/workspace_symbol.cc index 50a15b7d..02f2b59a 100644 --- a/src/messages/workspace_symbol.cc +++ b/src/messages/workspace_symbol.cc @@ -42,7 +42,7 @@ bool AddSymbol( return true; } -struct In_WorkspaceSymbol : public RequestInMessage { +struct In_WorkspaceSymbol : public RequestMessage { MethodType GetMethodType() const override { return kMethodType; } struct Params { std::string query; @@ -53,20 +53,11 @@ MAKE_REFLECT_STRUCT(In_WorkspaceSymbol::Params, query); MAKE_REFLECT_STRUCT(In_WorkspaceSymbol, id, params); REGISTER_IN_MESSAGE(In_WorkspaceSymbol); -struct Out_WorkspaceSymbol : public lsOutMessage { - lsRequestId id; - std::vector result; -}; -MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result); - -///// Fuzzy matching struct Handler_WorkspaceSymbol : BaseMessageHandler { MethodType GetMethodType() const override { return kMethodType; } void Run(In_WorkspaceSymbol *request) override { - Out_WorkspaceSymbol out; - out.id = request->id; - + std::vector result; std::string query = request->params.query; // {symbol info, matching detailed_name or short_name, index} @@ -116,20 +107,20 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler { std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) { return std::get<1>(l) > std::get<1>(r); }); - out.result.reserve(cands.size()); + result.reserve(cands.size()); for (auto &cand : cands) { // Discard awful candidates. if (std::get<1>(cand) <= FuzzyMatcher::kMinScore) break; - out.result.push_back(std::get<0>(cand)); + result.push_back(std::get<0>(cand)); } } else { - out.result.reserve(cands.size()); + result.reserve(cands.size()); for (auto &cand : cands) - out.result.push_back(std::get<0>(cand)); + result.push_back(std::get<0>(cand)); } - pipeline::WriteStdout(kMethodType, out); + pipeline::Reply(request->id, result); } }; REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol); diff --git a/src/method.cc b/src/method.cc deleted file mode 100644 index d3523281..00000000 --- a/src/method.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#include "method.h" - -MethodType kMethodType_Unknown = "$unknown"; -MethodType kMethodType_Exit = "exit"; -MethodType kMethodType_TextDocumentPublishDiagnostics = - "textDocument/publishDiagnostics"; -MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges"; -MethodType kMethodType_CclsPublishSemanticHighlighting = - "$ccls/publishSemanticHighlighting"; - -void Reflect(Reader &visitor, lsRequestId &value) { - if (visitor.IsInt64()) { - value.type = lsRequestId::kInt; - value.value = int(visitor.GetInt64()); - } else if (visitor.IsInt()) { - value.type = lsRequestId::kInt; - value.value = visitor.GetInt(); - } else if (visitor.IsString()) { - value.type = lsRequestId::kString; - value.value = atoll(visitor.GetString()); - } else { - value.type = lsRequestId::kNone; - value.value = -1; - } -} - -void Reflect(Writer &visitor, lsRequestId &value) { - switch (value.type) { - case lsRequestId::kNone: - visitor.Null(); - break; - case lsRequestId::kInt: - visitor.Int(value.value); - break; - case lsRequestId::kString: - auto s = std::to_string(value.value); - visitor.String(s.c_str(), s.length()); - break; - } -} diff --git a/src/method.h b/src/method.h deleted file mode 100644 index f36864f7..00000000 --- a/src/method.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017-2018 ccls Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "serializer.h" -#include "utils.h" - -#include - -using MethodType = const char *; -extern MethodType kMethodType_Unknown; -extern MethodType kMethodType_Exit; -extern MethodType kMethodType_TextDocumentPublishDiagnostics; -extern MethodType kMethodType_CclsPublishSkippedRanges; -extern MethodType kMethodType_CclsPublishSemanticHighlighting; - -struct lsRequestId { - // The client can send the request id as an int or a string. We should output - // the same format we received. - enum Type { kNone, kInt, kString }; - Type type = kNone; - - int value = -1; - - bool Valid() const { return type != kNone; } -}; -void Reflect(Reader &visitor, lsRequestId &value); -void Reflect(Writer &visitor, lsRequestId &value); - -struct InMessage { - virtual ~InMessage() = default; - - virtual MethodType GetMethodType() const = 0; - virtual lsRequestId GetRequestId() const = 0; -}; - -struct RequestInMessage : public InMessage { - // number or string, actually no null - lsRequestId id; - lsRequestId GetRequestId() const override { return id; } -}; - -// NotificationInMessage does not have |id|. -struct NotificationInMessage : public InMessage { - lsRequestId GetRequestId() const override { return lsRequestId(); } -}; diff --git a/src/pipeline.cc b/src/pipeline.cc index 928a5706..1a20a0bf 100644 --- a/src/pipeline.cc +++ b/src/pipeline.cc @@ -14,6 +14,9 @@ #include "platform.h" #include "project.h" #include "query_utils.h" +#include "serializers/json.h" + +#include #include #include @@ -64,18 +67,13 @@ struct Index_Request { int64_t ts = tick++; }; -struct Stdout_Request { - MethodType method; - std::string content; -}; - MultiQueueWaiter *main_waiter; MultiQueueWaiter *indexer_waiter; MultiQueueWaiter *stdout_waiter; ThreadedQueue> *on_request; ThreadedQueue *index_request; ThreadedQueue *on_indexed; -ThreadedQueue *for_stdout; +ThreadedQueue *for_stdout; struct InMemoryIndexFile { std::string content; @@ -287,11 +285,10 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles, if (!ok) { if (request.id.Valid()) { - Out_Error out; - out.id = request.id; - out.error.code = lsErrorCodes::InternalError; - out.error.message = "Failed to index " + path_to_index; - pipeline::WriteStdout(kMethodType_Unknown, out); + lsResponseError err; + err.code = lsErrorCodes::InternalError; + err.message = "failed to index " + path_to_index; + pipeline::ReplyError(request.id, err); } return true; } @@ -351,7 +348,7 @@ void Init() { index_request = new ThreadedQueue(indexer_waiter); stdout_waiter = new MultiQueueWaiter; - for_stdout = new ThreadedQueue(stdout_waiter); + for_stdout = new ThreadedQueue(stdout_waiter); } void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project, @@ -371,8 +368,8 @@ void Main_OnIndexed(DB *db, WorkingFiles *working_files, IndexUpdate *update) { std::string filename = LowerPathIfInsensitive(f->filename); if (db->name2file_id.find(filename) == db->name2file_id.end()) continue; - QueryFile *file = &db->files[db->name2file_id[filename]]; - EmitSemanticHighlighting(db, f.get(), file); + QueryFile &file = db->files[db->name2file_id[filename]]; + EmitSemanticHighlight(db, f.get(), file); } return; } @@ -391,8 +388,9 @@ void Main_OnIndexed(DB *db, WorkingFiles *working_files, IndexUpdate *update) { // request.path wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content : def_u.second); - EmitSkippedRanges(wfile, def_u.first.skipped_ranges); - EmitSemanticHighlighting(db, wfile, &db->files[update->file_id]); + QueryFile &file = db->files[update->file_id]; + EmitSkippedRanges(wfile, file); + EmitSemanticHighlight(db, wfile, file); } } } @@ -402,21 +400,20 @@ void LaunchStdin() { set_thread_name("stdin"); while (true) { std::unique_ptr message; - std::optional err = + std::optional error = MessageRegistry::instance()->ReadMessageFromStdin(&message); // Message parsing can fail if we don't recognize the method. - if (err) { + if (error) { // The message may be partially deserialized. // Emit an error ResponseMessage if |id| is available. if (message) { lsRequestId id = message->GetRequestId(); if (id.Valid()) { - Out_Error out; - out.id = id; - out.error.code = lsErrorCodes::InvalidParams; - out.error.message = std::move(*err); - WriteStdout(kMethodType_Unknown, out); + lsResponseError err; + err.code = lsErrorCodes::InvalidParams; + err.message = std::move(*error); + ReplyError(id, err); } } continue; @@ -441,20 +438,12 @@ void LaunchStdout() { set_thread_name("stdout"); while (true) { - std::vector messages = for_stdout->DequeueAll(); - if (messages.empty()) { - stdout_waiter->Wait(for_stdout); - continue; - } - - for (auto &message : messages) { -#ifdef _WIN32 - fwrite(message.content.c_str(), message.content.size(), 1, stdout); - fflush(stdout); -#else - write(1, message.content.c_str(), message.content.size()); -#endif + std::vector messages = for_stdout->DequeueAll(); + for (auto &s : messages) { + llvm::outs() << "Content-Length: " << s.size() << "\r\n\r\n" << s; + llvm::outs().flush(); } + stdout_waiter->Wait(for_stdout); } }) .detach(); @@ -468,20 +457,17 @@ void MainLoop() { CompletionManager clang_complete( &project, &working_files, [&](std::string path, std::vector diagnostics) { - Out_TextDocumentPublishDiagnostics out; - out.params.uri = lsDocumentUri::FromPath(path); - out.params.diagnostics = diagnostics; - ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, - out); + lsPublishDiagnosticsParams params; + params.uri = lsDocumentUri::FromPath(path); + params.diagnostics = diagnostics; + Notify("textDocument/publishDiagnostics", params); }, [](lsRequestId id) { if (id.Valid()) { - Out_Error out; - out.id = id; - out.error.code = lsErrorCodes::InternalError; - out.error.message = "Dropping completion request; a newer request " - "has come in that will be serviced instead."; - pipeline::WriteStdout(kMethodType_Unknown, out); + lsResponseError err; + err.code = lsErrorCodes::InternalError; + err.message = "drop older completion request"; + ReplyError(id, err); } }); @@ -554,14 +540,54 @@ std::optional LoadIndexedContent(const std::string &path) { return ReadContent(GetCachePath(path)); } -void WriteStdout(MethodType method, lsBaseOutMessage &response) { - std::ostringstream sstream; - response.Write(sstream); +void Notify(const char *method, const std::function &fn) { + rapidjson::StringBuffer output; + rapidjson::Writer w(output); + w.StartObject(); + w.Key("jsonrpc"); + w.String("2.0"); + w.Key("method"); + w.String(method); + w.Key("params"); + JsonWriter writer(&w); + fn(writer); + w.EndObject(); + for_stdout->PushBack(output.GetString()); +} - Stdout_Request out; - out.content = sstream.str(); - out.method = method; - for_stdout->PushBack(std::move(out)); +static void Reply(lsRequestId id, const char *key, + const std::function &fn) { + rapidjson::StringBuffer output; + rapidjson::Writer w(output); + w.StartObject(); + w.Key("jsonrpc"); + w.String("2.0"); + w.Key("id"); + switch (id.type) { + case lsRequestId::kNone: + w.Null(); + break; + case lsRequestId::kInt: + w.Int(id.value); + break; + case lsRequestId::kString: + auto s = std::to_string(id.value); + w.String(s.c_str(), s.length()); + break; + } + w.Key(key); + JsonWriter writer(&w); + fn(writer); + w.EndObject(); + for_stdout->PushBack(output.GetString()); +} + +void Reply(lsRequestId id, const std::function &fn) { + Reply(id, "result", fn); +} + +void ReplyError(lsRequestId id, const std::function &fn) { + Reply(id, "error", fn); } } // namespace ccls::pipeline diff --git a/src/pipeline.hh b/src/pipeline.hh index 42230ad4..be46ea62 100644 --- a/src/pipeline.hh +++ b/src/pipeline.hh @@ -3,8 +3,7 @@ #pragma once -#include "lsp_diagnostic.h" -#include "method.h" +#include "lsp.h" #include "query.h" #include @@ -18,7 +17,6 @@ struct GroupMatch; struct VFS; struct Project; struct WorkingFiles; -struct lsBaseOutMessage; struct VFS { struct State { @@ -55,6 +53,20 @@ void Index(const std::string &path, const std::vector &args, IndexMode mode, lsRequestId id = {}); std::optional LoadIndexedContent(const std::string& path); -void WriteStdout(MethodType method, lsBaseOutMessage &response); + +void Notify(const char *method, const std::function &fn); +template void Notify(const char *method, T &result) { + Notify(method, [&](Writer &w) { Reflect(w, result); }); +} + +void Reply(lsRequestId id, const std::function &fn); +template void Reply(lsRequestId id, T &result) { + Reply(id, [&](Writer &w) { Reflect(w, result); }); +} + +void ReplyError(lsRequestId id, const std::function &fn); +template void ReplyError(lsRequestId id, T &result) { + ReplyError(id, [&](Writer &w) { Reflect(w, result); }); +} } // namespace pipeline } // namespace ccls diff --git a/src/project.h b/src/project.h index c90032ce..ad7b576d 100644 --- a/src/project.h +++ b/src/project.h @@ -5,7 +5,6 @@ #include "config.h" #include "lsp.h" -#include "method.h" #include #include diff --git a/src/serializer.cc b/src/serializer.cc index b1640017..eb6c15bd 100644 --- a/src/serializer.cc +++ b/src/serializer.cc @@ -20,7 +20,13 @@ using namespace llvm; bool gTestOutputMode = false; -//// Elementary types +Reader::~Reader() {} +BinaryReader::~BinaryReader() {} +JsonReader::~JsonReader() {} + +Writer::~Writer() {} +BinaryWriter::~BinaryWriter() {} +JsonWriter::~JsonWriter() {} void Reflect(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); } void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); } diff --git a/src/serializer.h b/src/serializer.h index 9bbd00af..517d2147 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -26,11 +26,10 @@ class StringRef; enum class SerializeFormat { Binary, Json }; struct JsonNull {}; -struct mandatory_optional_tag {}; class Reader { public: - virtual ~Reader() {} + virtual ~Reader(); virtual SerializeFormat Format() const = 0; virtual bool IsBool() = 0; @@ -60,7 +59,7 @@ public: class Writer { public: - virtual ~Writer() {} + virtual ~Writer(); virtual SerializeFormat Format() const = 0; virtual void Null() = 0; @@ -85,8 +84,6 @@ struct IndexFile; #define REFLECT_MEMBER_START() ReflectMemberStart(visitor) #define REFLECT_MEMBER_END() ReflectMemberEnd(visitor); #define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name) -#define REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \ - ReflectMember(visitor, #name, value.name, mandatory_optional_tag{}) #define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value) #define MAKE_REFLECT_TYPE_PROXY(type_name) \ @@ -103,8 +100,6 @@ struct IndexFile; } #define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name); -#define _MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \ - REFLECT_MEMBER_MANDATORY_OPTIONAL(name); #define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \ template void Reflect(TVisitor &visitor, type &value) { \ @@ -119,13 +114,6 @@ struct IndexFile; REFLECT_MEMBER_END(); \ } -#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \ - template void Reflect(TVisitor &visitor, type &value) { \ - REFLECT_MEMBER_START(); \ - MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \ - REFLECT_MEMBER_END(); \ - } - // clang-format off // Config has many fields, we need to support at least its number of fields. #define NUM_VA_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,N,...) N @@ -256,13 +244,6 @@ void ReflectMember(Writer &visitor, const char *name, Maybe &value) { } } -template -void ReflectMember(Writer &visitor, const char *name, T &value, - mandatory_optional_tag) { - visitor.Key(name); - Reflect(visitor, value); -} - template void Reflect(Reader &vis, std::pair &v) { vis.Member("L", [&]() { Reflect(vis, v.first); }); diff --git a/src/serializers/binary.h b/src/serializers/binary.h index d35dd9f2..1f2fa047 100644 --- a/src/serializers/binary.h +++ b/src/serializers/binary.h @@ -34,6 +34,7 @@ class BinaryReader : public Reader { public: BinaryReader(std::string_view buf) : p_(buf.data()) {} + virtual ~BinaryReader(); SerializeFormat Format() const override { return SerializeFormat::Binary; } bool IsBool() override { return true; } @@ -98,6 +99,7 @@ class BinaryWriter : public Writer { void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); } public: + virtual ~BinaryWriter(); SerializeFormat Format() const override { return SerializeFormat::Binary; } std::string Take() { return std::move(buf_); } diff --git a/src/serializers/json.h b/src/serializers/json.h index 636f29fc..0c3c31c4 100644 --- a/src/serializers/json.h +++ b/src/serializers/json.h @@ -14,6 +14,7 @@ class JsonReader : public Reader { public: JsonReader(rapidjson::GenericValue> *m) : m_(m) {} + virtual ~JsonReader(); SerializeFormat Format() const override { return SerializeFormat::Json; } rapidjson::GenericValue> &m() { return *m_; } @@ -83,6 +84,7 @@ class JsonWriter : public Writer { public: JsonWriter(rapidjson::Writer *m) : m_(m) {} + virtual ~JsonWriter(); SerializeFormat Format() const override { return SerializeFormat::Json; } rapidjson::Writer &m() { return *m_; } diff --git a/src/working_files.cc b/src/working_files.cc index e3cb245e..69b483e4 100644 --- a/src/working_files.cc +++ b/src/working_files.cc @@ -303,6 +303,8 @@ void WorkingFile::ComputeLineMapping() { std::optional WorkingFile::GetBufferPosFromIndexPos(int line, int *column, bool is_end) { + if (line == (int)index_lines.size() && !*column) + return buffer_content.size(); if (line < 0 || line >= (int)index_lines.size()) { LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, " << index_lines.size() << ")) in " << filename; @@ -317,7 +319,6 @@ std::optional WorkingFile::GetBufferPosFromIndexPos(int line, int *column, std::optional WorkingFile::GetIndexPosFromBufferPos(int line, int *column, bool is_end) { - // See GetBufferLineFromIndexLine for additional comments. if (line < 0 || line >= (int)buffer_lines.size()) return std::nullopt; diff --git a/src/working_files.h b/src/working_files.h index 0750de6b..94cef1b5 100644 --- a/src/working_files.h +++ b/src/working_files.h @@ -3,7 +3,7 @@ #pragma once -#include "lsp_diagnostic.h" +#include "lsp.h" #include "utils.h" #include