Add pipeline::{Notify,Reply,ReplyError} and simplify message handling

Delete method.{cc,h}
Rename $ccls/setSkippedRanges to $ccls/publishSkippedRanges
Rename $ccls/publishSemanticHighlighting to $ccls/publishSemanticHighlight; stableId -> id
This commit is contained in:
Fangrui Song 2019-01-09 15:19:17 +08:00
parent 79352b451c
commit fc1db06538
48 changed files with 716 additions and 1157 deletions

View File

@ -187,7 +187,6 @@ target_sources(ccls PRIVATE
src/main.cc src/main.cc
src/include_complete.cc src/include_complete.cc
src/indexer.cc src/indexer.cc
src/method.cc
src/log.cc src/log.cc
src/lsp.cc src/lsp.cc
src/match.cc src/match.cc
@ -225,12 +224,10 @@ target_sources(ccls PRIVATE
src/messages/textDocument_documentHighlight.cc src/messages/textDocument_documentHighlight.cc
src/messages/textDocument_documentSymbol.cc src/messages/textDocument_documentSymbol.cc
src/messages/textDocument_hover.cc src/messages/textDocument_hover.cc
src/messages/textDocument_implementation.cc
src/messages/textDocument_references.cc src/messages/textDocument_references.cc
src/messages/textDocument_rename.cc src/messages/textDocument_rename.cc
src/messages/textDocument_signatureHelp.cc src/messages/textDocument_signatureHelp.cc
src/messages/textDocument_typeDefinition.cc src/messages/textDocument_typeDefinition.cc
src/messages/workspace_did.cc src/messages/workspace_did.cc
src/messages/workspace_didChangeWatchedFiles.cc
src/messages/workspace_symbol.cc src/messages/workspace_symbol.cc
) )

View File

@ -17,8 +17,8 @@ limitations under the License.
#include "clang_tu.hh" #include "clang_tu.hh"
#include "lru_cache.h" #include "lru_cache.h"
#include "lsp.h"
#include "lsp_completion.h" #include "lsp_completion.h"
#include "lsp_diagnostic.h"
#include "project.h" #include "project.h"
#include "threaded_queue.h" #include "threaded_queue.h"
#include "working_files.h" #include "working_files.h"

View File

@ -21,19 +21,22 @@ limitations under the License.
#include <queue> #include <queue>
template <typename Node> template <typename Node>
void FlattenHierarchy(const Node &root, Out_LocationList &out) { std::vector<lsLocation> FlattenHierarchy(const std::optional<Node> &root) {
if (!root)
return {};
std::vector<lsLocation> ret;
std::queue<const Node *> q; std::queue<const Node *> q;
for (auto &entry : root.children) for (auto &entry : root->children)
q.push(&entry); q.push(&entry);
while (q.size()) { while (q.size()) {
auto *entry = q.front(); auto *entry = q.front();
q.pop(); q.pop();
if (entry->location.uri.raw_uri.size()) if (entry->location.uri.raw_uri.size())
out.result.push_back({entry->location}); ret.push_back({entry->location});
for (auto &entry1 : entry->children) for (auto &entry1 : entry->children)
q.push(&entry1); q.push(&entry1);
} }
std::sort(out.result.begin(), out.result.end()); std::sort(ret.begin(), ret.end());
out.result.erase(std::unique(out.result.begin(), out.result.end()), ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
out.result.end()); return ret;
} }

View File

@ -16,7 +16,6 @@ limitations under the License.
#pragma once #pragma once
#include "lsp.h" #include "lsp.h"
#include "lsp_diagnostic.h"
#include "maybe.h" #include "maybe.h"
#include "position.h" #include "position.h"
#include "serializer.h" #include "serializer.h"

View File

@ -18,10 +18,45 @@ limitations under the License.
#include "log.hh" #include "log.hh"
#include "serializers/json.h" #include "serializers/json.h"
#include <rapidjson/writer.h> #include <rapidjson/document.h>
#include <stdio.h> #include <stdio.h>
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; MessageRegistry *MessageRegistry::instance_ = nullptr;
lsTextDocumentIdentifier lsTextDocumentIdentifier
@ -145,29 +180,6 @@ MessageRegistry *MessageRegistry::instance() {
return instance_; return instance_;
} }
lsBaseOutMessage::~lsBaseOutMessage() = default;
void lsBaseOutMessage::Write(std::ostream &out) {
rapidjson::StringBuffer output;
rapidjson::Writer<rapidjson::StringBuffer> 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<int>(this->code);
visitor.StartObject();
REFLECT_MEMBER2("code", code2);
REFLECT_MEMBER(message);
visitor.EndObject();
}
lsDocumentUri lsDocumentUri::FromPath(const std::string &path) { lsDocumentUri lsDocumentUri::FromPath(const std::string &path) {
lsDocumentUri result; lsDocumentUri result;
result.SetPath(path); result.SetPath(path);
@ -272,9 +284,3 @@ void Reflect(Writer &visitor, lsMarkedString &value) {
Reflect(visitor, value.value); Reflect(visitor, value.value);
} }
} }
std::string Out_ShowLogMessage::method() {
if (display_type == DisplayType::Log)
return "window/logMessage";
return "window/showMessage";
}

156
src/lsp.h
View File

@ -16,13 +16,42 @@ limitations under the License.
#pragma once #pragma once
#include "config.h" #include "config.h"
#include "method.h"
#include "serializer.h" #include "serializer.h"
#include "utils.h" #include "utils.h"
#include <iosfwd> #include <iosfwd>
#include <unordered_map> #include <unordered_map>
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) \ #define REGISTER_IN_MESSAGE(type) \
static MessageRegistryRegister<type> type##message_handler_instance_; static MessageRegistryRegister<type> type##message_handler_instance_;
@ -53,45 +82,38 @@ template <typename T> struct MessageRegistryRegister {
} }
}; };
struct lsBaseOutMessage { enum class lsErrorCodes {
virtual ~lsBaseOutMessage(); // Defined by JSON RPC
virtual void ReflectWriter(Writer &) = 0; 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. // Defined by the protocol.
void Write(std::ostream &out); RequestCancelled = -32800,
};
template <typename TDerived> 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<TDerived &>(*this));
}
}; };
MAKE_REFLECT_TYPE_PROXY(lsErrorCodes);
struct lsResponseError { struct lsResponseError {
enum class lsErrorCodes : int { // A number indicating the error type that occurred.
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
RequestCancelled = -32800,
};
lsErrorCodes code; lsErrorCodes code;
// Short description.
// A string providing a short description of the error.
std::string message; std::string message;
void Write(Writer &visitor); // A Primitive or Structured value that contains additional
// information about the error. Can be omitted.
// std::optional<D> 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";
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
@ -317,35 +339,55 @@ MAKE_REFLECT_STRUCT(lsWorkspaceFolder, uri, name);
enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
MAKE_REFLECT_TYPE_PROXY(lsMessageType) 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<lsDiagnosticSeverity> 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<lsTextEdit> 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<lsDiagnostic> diagnostics;
};
MAKE_REFLECT_STRUCT(lsPublishDiagnosticsParams, uri, diagnostics);
struct lsShowMessageParams {
lsMessageType type = lsMessageType::Error; lsMessageType type = lsMessageType::Error;
std::string message; std::string message;
}; };
MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message); MAKE_REFLECT_STRUCT(lsShowMessageParams, type, message);
struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
enum class DisplayType { Show, Log };
DisplayType display_type = DisplayType::Show;
std::string method();
Out_ShowLogMessageParams params;
};
template <typename TVisitor>
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<Out_LocationList> {
lsRequestId id;
std::vector<lsLocation> result;
};
MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);
// Used to identify the language at a file level. The ordering is important, as // 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 // a file previously identified as `C`, will be changed to `Cpp` if it

View File

@ -1,115 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#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<lsDiagnosticSeverity> 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<lsTextEdit> 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<Out_Error> {
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<D> 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<Out_TextDocumentPublishDiagnostics> {
struct Params {
// The URI for which diagnostic information is reported.
lsDocumentUri uri;
// An array of diagnostic information items.
std::vector<lsDiagnostic> diagnostics;
};
Params params;
};
template <typename TVisitor>
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);

View File

@ -30,12 +30,11 @@ std::optional<Matcher> Matcher::Create(const std::string &search) {
); );
return m; return m;
} catch (const std::exception &e) { } catch (const std::exception &e) {
Out_ShowLogMessage out; lsShowMessageParams params;
out.display_type = Out_ShowLogMessage::DisplayType::Show; params.type = lsMessageType::Error;
out.params.type = lsMessageType::Error; params.message =
out.params.message = "failed to parse EMCAScript regex " + search + " : " + e.what();
"ccls: Parsing EMCAScript regex \"" + search + "\" failed; " + e.what(); pipeline::Notify(window_showMessage, params);
pipeline::WriteStdout(kMethodType_Unknown, out);
return std::nullopt; return std::nullopt;
} }
} }

View File

@ -30,23 +30,36 @@ MAKE_HASHABLE(SymbolIdx, t.usr, t.kind);
namespace { namespace {
struct Out_CclsSetSkippedRanges struct CclsSemanticHighlightSymbol {
: public lsOutMessage<Out_CclsSetSkippedRanges> { int id = 0;
struct Params { lsSymbolKind parentKind;
lsDocumentUri uri; lsSymbolKind kind;
std::vector<lsRange> skippedRanges; uint8_t storage;
}; std::vector<std::pair<int, int>> ranges;
std::string method = "$ccls/setSkippedRanges";
Params params; // `lsRanges` is used to compute `ranges`.
std::vector<lsRange> lsRanges;
}; };
MAKE_REFLECT_STRUCT(Out_CclsSetSkippedRanges::Params, uri, skippedRanges);
MAKE_REFLECT_STRUCT(Out_CclsSetSkippedRanges, jsonrpc, method, params); struct CclsSemanticHighlightParams {
lsDocumentUri uri;
std::vector<CclsSemanticHighlightSymbol> symbols;
};
MAKE_REFLECT_STRUCT(CclsSemanticHighlightSymbol, id, parentKind, kind, storage,
ranges, lsRanges);
MAKE_REFLECT_STRUCT(CclsSemanticHighlightParams, uri, symbols);
struct CclsSetSkippedRangesParams {
lsDocumentUri uri;
std::vector<lsRange> skippedRanges;
};
MAKE_REFLECT_STRUCT(CclsSetSkippedRangesParams, uri, skippedRanges);
struct ScanLineEvent { struct ScanLineEvent {
lsPosition pos; lsPosition pos;
lsPosition end_pos; // Second key when there is a tie for insertion events. lsPosition end_pos; // Second key when there is a tie for insertion events.
int id; int id;
Out_CclsPublishSemanticHighlighting::Symbol *symbol; CclsSemanticHighlightSymbol *symbol;
bool operator<(const ScanLineEvent &other) const { bool operator<(const ScanLineEvent &other) const {
// See the comments below when insertion/deletion events are inserted. // See the comments below when insertion/deletion events are inserted.
if (!(pos == other.pos)) if (!(pos == other.pos))
@ -68,7 +81,6 @@ MessageHandler::MessageHandler() {
message_handlers->push_back(this); message_handlers->push_back(this);
} }
// static
std::vector<MessageHandler *> *MessageHandler::message_handlers = nullptr; std::vector<MessageHandler *> *MessageHandler::message_handlers = nullptr;
bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id, bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
@ -98,46 +110,40 @@ bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
} }
if (id) { if (id) {
Out_Error out; lsResponseError err;
out.id = *id;
if (has_entry) { if (has_entry) {
out.error.code = lsErrorCodes::ServerNotInitialized; err.code = lsErrorCodes::ServerNotInitialized;
out.error.message = absolute_path + " is being indexed"; err.message = absolute_path + " is being indexed";
} else { } else {
out.error.code = lsErrorCodes::InternalError; err.code = lsErrorCodes::InternalError;
out.error.message = "Unable to find file " + absolute_path; err.message = "unable to find " + absolute_path;
} }
LOG_S(INFO) << out.error.message; pipeline::ReplyError(*id, err);
pipeline::WriteStdout(kMethodType_Unknown, out);
} }
return false; return false;
} }
void EmitSkippedRanges(WorkingFile *working_file, void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
const std::vector<Range> &skipped_ranges) { CclsSetSkippedRangesParams params;
Out_CclsSetSkippedRanges out; params.uri = lsDocumentUri::FromPath(wfile->filename);
out.params.uri = lsDocumentUri::FromPath(working_file->filename); for (Range skipped : file.def->skipped_ranges)
for (Range skipped : skipped_ranges) { if (auto ls_skipped = GetLsRange(wfile, skipped))
std::optional<lsRange> ls_skipped = GetLsRange(working_file, skipped); params.skippedRanges.push_back(*ls_skipped);
if (ls_skipped) pipeline::Notify("$ccls/publishSkippedRanges", params);
out.params.skippedRanges.push_back(*ls_skipped);
}
pipeline::WriteStdout(kMethodType_CclsPublishSkippedRanges, out);
} }
void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) { void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file) {
static GroupMatch match(g_config->highlight.whitelist, static GroupMatch match(g_config->highlight.whitelist,
g_config->highlight.blacklist); g_config->highlight.blacklist);
assert(file->def); assert(file.def);
if (wfile->buffer_content.size() > g_config->highlight.largeFileSize || if (wfile->buffer_content.size() > g_config->highlight.largeFileSize ||
!match.IsMatch(file->def->path)) !match.IsMatch(file.def->path))
return; return;
// Group symbols together. // Group symbols together.
std::unordered_map<SymbolIdx, Out_CclsPublishSemanticHighlighting::Symbol> std::unordered_map<SymbolIdx, CclsSemanticHighlightSymbol> grouped_symbols;
grouped_symbols; for (auto [sym, refcnt] : file.symbol2refcnt) {
for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0) continue; if (refcnt <= 0) continue;
std::string_view detailed_name; std::string_view detailed_name;
lsSymbolKind parent_kind = lsSymbolKind::Unknown; lsSymbolKind parent_kind = lsSymbolKind::Unknown;
@ -217,8 +223,8 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
if (it != grouped_symbols.end()) { if (it != grouped_symbols.end()) {
it->second.lsRanges.push_back(*loc); it->second.lsRanges.push_back(*loc);
} else { } else {
Out_CclsPublishSemanticHighlighting::Symbol symbol; CclsSemanticHighlightSymbol symbol;
symbol.stableId = idx; symbol.id = idx;
symbol.parentKind = parent_kind; symbol.parentKind = parent_kind;
symbol.kind = kind; symbol.kind = kind;
symbol.storage = storage; symbol.storage = storage;
@ -232,7 +238,7 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
std::vector<ScanLineEvent> events; std::vector<ScanLineEvent> events;
int id = 0; int id = 0;
for (auto &entry : grouped_symbols) { for (auto &entry : grouped_symbols) {
Out_CclsPublishSemanticHighlighting::Symbol &symbol = entry.second; CclsSemanticHighlightSymbol &symbol = entry.second;
for (auto &loc : symbol.lsRanges) { for (auto &loc : symbol.lsRanges) {
// For ranges sharing the same start point, the one with leftmost end // For ranges sharing the same start point, the one with leftmost end
// point comes first. // point comes first.
@ -267,13 +273,11 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
deleted[~events[i].id] = 1; deleted[~events[i].id] = 1;
} }
Out_CclsPublishSemanticHighlighting out; CclsSemanticHighlightParams params;
out.params.uri = lsDocumentUri::FromPath(wfile->filename); params.uri = lsDocumentUri::FromPath(wfile->filename);
// Transform lsRange into pair<int, int> (offset pairs) // Transform lsRange into pair<int, int> (offset pairs)
if (!g_config->highlight.lsRanges) { if (!g_config->highlight.lsRanges) {
std::vector< std::vector<std::pair<lsRange, CclsSemanticHighlightSymbol *>> scratch;
std::pair<lsRange, Out_CclsPublishSemanticHighlighting::Symbol *>>
scratch;
for (auto &entry : grouped_symbols) { for (auto &entry : grouped_symbols) {
for (auto &range : entry.second.lsRanges) for (auto &range : entry.second.lsRanges)
scratch.emplace_back(range, &entry.second); scratch.emplace_back(range, &entry.second);
@ -315,6 +319,6 @@ void EmitSemanticHighlighting(DB *db, WorkingFile *wfile, QueryFile *file) {
for (auto &entry : grouped_symbols) for (auto &entry : grouped_symbols)
if (entry.second.ranges.size() || entry.second.lsRanges.size()) if (entry.second.ranges.size() || entry.second.lsRanges.size())
out.params.symbols.push_back(std::move(entry.second)); params.symbols.push_back(std::move(entry.second));
pipeline::WriteStdout(kMethodType_CclsPublishSemanticHighlighting, out); pipeline::Notify("$ccls/publishSemanticHighlight", params);
} }

View File

@ -16,7 +16,6 @@ limitations under the License.
#pragma once #pragma once
#include "lsp.h" #include "lsp.h"
#include "method.h"
#include "query.h" #include "query.h"
#include <memory> #include <memory>
@ -35,30 +34,6 @@ struct DB;
struct WorkingFile; struct WorkingFile;
struct WorkingFiles; struct WorkingFiles;
struct Out_CclsPublishSemanticHighlighting
: public lsOutMessage<Out_CclsPublishSemanticHighlighting> {
struct Symbol {
int stableId = 0;
lsSymbolKind parentKind;
lsSymbolKind kind;
uint8_t storage;
std::vector<std::pair<int, int>> ranges;
// `lsRanges` is used to compute `ranges`.
std::vector<lsRange> lsRanges;
};
struct Params {
lsDocumentUri uri;
std::vector<Symbol> 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: // Usage:
// //
@ -103,8 +78,6 @@ bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
const std::string &absolute_path, const std::string &absolute_path,
QueryFile **out_query_file, int *out_file_id = nullptr); QueryFile **out_query_file, int *out_file_id = nullptr);
void EmitSkippedRanges(WorkingFile *working_file, void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file);
const std::vector<Range> &skipped_ranges);
void EmitSemanticHighlighting(DB *db, WorkingFile *working_file, void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file);
QueryFile *file);

View File

@ -38,7 +38,7 @@ bool operator&(CallType lhs, CallType rhs) {
return uint8_t(lhs) & uint8_t(rhs); return uint8_t(lhs) & uint8_t(rhs);
} }
struct In_CclsCall : public RequestInMessage { struct In_cclsCall : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
@ -62,34 +62,29 @@ struct In_CclsCall : public RequestInMessage {
}; };
Params params; Params params;
}; };
MAKE_REFLECT_STRUCT(In_CclsCall::Params, textDocument, position, id, MAKE_REFLECT_STRUCT(In_cclsCall::Params, textDocument, position, id, callee,
callee, callType, qualified, levels, hierarchy); callType, qualified, levels, hierarchy);
MAKE_REFLECT_STRUCT(In_CclsCall, id, params); MAKE_REFLECT_STRUCT(In_cclsCall, id, params);
REGISTER_IN_MESSAGE(In_CclsCall); REGISTER_IN_MESSAGE(In_cclsCall);
struct Out_CclsCall : public lsOutMessage<Out_CclsCall> { struct Out_cclsCall {
struct Entry { Usr usr;
Usr usr; std::string id;
std::string id; std::string_view name;
std::string_view name; lsLocation location;
lsLocation location; CallType callType = CallType::Direct;
CallType callType = CallType::Direct; int numChildren;
int numChildren; // Empty if the |levels| limit is reached.
// Empty if the |levels| limit is reached. std::vector<Out_cclsCall> children;
std::vector<Entry> children; bool operator==(const Out_cclsCall &o) const {
bool operator==(const Entry &o) const { return location == o.location; } return location == o.location;
bool operator<(const Entry &o) const { return location < o.location; } }
}; bool operator<(const Out_cclsCall &o) const { return location < o.location; }
lsRequestId id;
std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsCall::Entry, id, name, location, callType, MAKE_REFLECT_STRUCT(Out_cclsCall, id, name, location, callType, numChildren,
numChildren, children); children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsCall, jsonrpc, id,
result);
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) { CallType call_type, bool qualified, int levels) {
const QueryFunc &func = m->db->Func(entry->usr); const QueryFunc &func = m->db->Func(entry->usr);
const QueryFunc::Def *def = func.AnyDef(); const QueryFunc::Def *def = func.AnyDef();
@ -99,7 +94,7 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee,
auto handle = [&](SymbolRef sym, int file_id, CallType call_type1) { auto handle = [&](SymbolRef sym, int file_id, CallType call_type1) {
entry->numChildren++; entry->numChildren++;
if (levels > 0) { if (levels > 0) {
Out_CclsCall::Entry entry1; Out_cclsCall entry1;
entry1.id = std::to_string(sym.usr); entry1.id = std::to_string(sym.usr);
entry1.usr = sym.usr; entry1.usr = sym.usr;
if (auto loc = GetLsLocation(m->db, m->working_files, if (auto loc = GetLsLocation(m->db, m->working_files,
@ -179,17 +174,17 @@ bool Expand(MessageHandler *m, Out_CclsCall::Entry *entry, bool callee,
return true; return true;
} }
struct Handler_CclsCall : BaseMessageHandler<In_CclsCall> { struct Handler_cclsCall : BaseMessageHandler<In_cclsCall> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
std::optional<Out_CclsCall::Entry> std::optional<Out_cclsCall> BuildInitial(Usr root_usr, bool callee,
BuildInitial(Usr root_usr, bool callee, CallType call_type, bool qualified, CallType call_type, bool qualified,
int levels) { int levels) {
const auto *def = db->Func(root_usr).AnyDef(); const auto *def = db->Func(root_usr).AnyDef();
if (!def) if (!def)
return {}; return {};
Out_CclsCall::Entry entry; Out_cclsCall entry;
entry.id = std::to_string(root_usr); entry.id = std::to_string(root_usr);
entry.usr = root_usr; entry.usr = root_usr;
entry.callType = CallType::Direct; entry.callType = CallType::Direct;
@ -202,25 +197,22 @@ struct Handler_CclsCall : BaseMessageHandler<In_CclsCall> {
return entry; return entry;
} }
void Run(In_CclsCall *request) override { void Run(In_cclsCall *request) override {
auto &params = request->params; auto &params = request->params;
Out_CclsCall out; std::optional<Out_cclsCall> result;
out.id = request->id;
if (params.id.size()) { if (params.id.size()) {
try { try {
params.usr = std::stoull(params.id); params.usr = std::stoull(params.id);
} catch (...) { } catch (...) {
return; return;
} }
Out_CclsCall::Entry entry; result.emplace();
entry.id = std::to_string(params.usr); result->id = std::to_string(params.usr);
entry.usr = params.usr; result->usr = params.usr;
entry.callType = CallType::Direct; result->callType = CallType::Direct;
if (db->HasFunc(params.usr)) 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); params.levels);
out.result = std::move(entry);
} else { } else {
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
@ -231,24 +223,21 @@ struct Handler_CclsCall : BaseMessageHandler<In_CclsCall> {
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, params.position)) { FindSymbolsAtLocation(working_file, file, params.position)) {
if (sym.kind == SymbolKind::Func) { if (sym.kind == SymbolKind::Func) {
out.result = BuildInitial(sym.usr, params.callee, params.callType, result = BuildInitial(sym.usr, params.callee, params.callType,
params.qualified, params.levels); params.qualified, params.levels);
break; break;
} }
} }
} }
if (params.hierarchy) { if (params.hierarchy)
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; else {
auto out = FlattenHierarchy(result);
pipeline::Reply(request->id, out);
} }
Out_LocationList out1;
out1.id = request->id;
if (out.result)
FlattenHierarchy<Out_CclsCall::Entry>(*out.result, out1);
pipeline::WriteStdout(kMethodType, out1);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsCall); REGISTER_MESSAGE_HANDLER(Handler_cclsCall);
} // namespace } // namespace

View File

@ -25,51 +25,46 @@ MAKE_REFLECT_STRUCT(QueryFile::Def, path, args, language, skipped_ranges,
namespace { namespace {
MethodType cclsInfo = "$ccls/info", fileInfo = "$ccls/fileInfo"; MethodType cclsInfo = "$ccls/info", fileInfo = "$ccls/fileInfo";
struct In_cclsInfo : public RequestInMessage { struct In_cclsInfo : public RequestMessage {
MethodType GetMethodType() const override { return cclsInfo; } MethodType GetMethodType() const override { return cclsInfo; }
}; };
MAKE_REFLECT_STRUCT(In_cclsInfo, id); MAKE_REFLECT_STRUCT(In_cclsInfo, id);
REGISTER_IN_MESSAGE(In_cclsInfo); REGISTER_IN_MESSAGE(In_cclsInfo);
struct Out_cclsInfo : public lsOutMessage<Out_cclsInfo> { struct Out_cclsInfo {
lsRequestId id; struct DB {
struct Result { int files, funcs, types, vars;
struct DB { } db;
int files, funcs, types, vars; struct Pipeline {
} db; int pendingIndexRequests;
struct Pipeline { } pipeline;
int pendingIndexRequests; struct Project {
} pipeline; int entries;
struct Project { } project;
int entries;
} project;
} result;
}; };
MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::DB, files, funcs, types, vars); MAKE_REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars);
MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::Pipeline, pendingIndexRequests); MAKE_REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests);
MAKE_REFLECT_STRUCT(Out_cclsInfo::Result::Project, entries); MAKE_REFLECT_STRUCT(Out_cclsInfo::Project, entries);
MAKE_REFLECT_STRUCT(Out_cclsInfo::Result, db, pipeline, project); MAKE_REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project);
MAKE_REFLECT_STRUCT(Out_cclsInfo, jsonrpc, id, result);
struct Handler_cclsInfo : BaseMessageHandler<In_cclsInfo> { struct Handler_cclsInfo : BaseMessageHandler<In_cclsInfo> {
MethodType GetMethodType() const override { return cclsInfo; } MethodType GetMethodType() const override { return cclsInfo; }
void Run(In_cclsInfo *request) override { void Run(In_cclsInfo *request) override {
Out_cclsInfo out; Out_cclsInfo result;
out.id = request->id; result.db.files = db->files.size();
out.result.db.files = db->files.size(); result.db.funcs = db->funcs.size();
out.result.db.funcs = db->funcs.size(); result.db.types = db->types.size();
out.result.db.types = db->types.size(); result.db.vars = db->vars.size();
out.result.db.vars = db->vars.size(); result.pipeline.pendingIndexRequests = pipeline::pending_index_requests;
out.result.pipeline.pendingIndexRequests = pipeline::pending_index_requests; result.project.entries = 0;
out.result.project.entries = 0;
for (auto &[_, folder] : project->root2folder) for (auto &[_, folder] : project->root2folder)
out.result.project.entries += folder.entries.size(); result.project.entries += folder.entries.size();
pipeline::WriteStdout(cclsInfo, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_cclsInfo); REGISTER_MESSAGE_HANDLER(Handler_cclsInfo);
struct In_cclsFileInfo : public RequestInMessage { struct In_cclsFileInfo : public RequestMessage {
MethodType GetMethodType() const override { return fileInfo; } MethodType GetMethodType() const override { return fileInfo; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -79,12 +74,6 @@ MAKE_REFLECT_STRUCT(In_cclsFileInfo::Params, textDocument);
MAKE_REFLECT_STRUCT(In_cclsFileInfo, id, params); MAKE_REFLECT_STRUCT(In_cclsFileInfo, id, params);
REGISTER_IN_MESSAGE(In_cclsFileInfo); REGISTER_IN_MESSAGE(In_cclsFileInfo);
struct Out_cclsFileInfo : public lsOutMessage<Out_cclsFileInfo> {
lsRequestId id;
QueryFile::Def result;
};
MAKE_REFLECT_STRUCT(Out_cclsFileInfo, jsonrpc, id, result);
struct Handler_cclsFileInfo : BaseMessageHandler<In_cclsFileInfo> { struct Handler_cclsFileInfo : BaseMessageHandler<In_cclsFileInfo> {
MethodType GetMethodType() const override { return fileInfo; } MethodType GetMethodType() const override { return fileInfo; }
void Run(In_cclsFileInfo *request) override { void Run(In_cclsFileInfo *request) override {
@ -93,15 +82,14 @@ struct Handler_cclsFileInfo : BaseMessageHandler<In_cclsFileInfo> {
request->params.textDocument.uri.GetPath(), &file)) request->params.textDocument.uri.GetPath(), &file))
return; return;
Out_cclsFileInfo out; QueryFile::Def result;
out.id = request->id;
// Expose some fields of |QueryFile::Def|. // Expose some fields of |QueryFile::Def|.
out.result.path = file->def->path; result.path = file->def->path;
out.result.args = file->def->args; result.args = file->def->args;
out.result.language = file->def->language; result.language = file->def->language;
out.result.includes = file->def->includes; result.includes = file->def->includes;
out.result.skipped_ranges = file->def->skipped_ranges; result.skipped_ranges = file->def->skipped_ranges;
pipeline::WriteStdout(fileInfo, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_cclsFileInfo); REGISTER_MESSAGE_HANDLER(Handler_cclsFileInfo);

View File

@ -22,9 +22,10 @@ using namespace ccls;
#include <unordered_set> #include <unordered_set>
namespace { 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; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
// If id+kind are specified, expand a node; otherwise textDocument+position // If id+kind are specified, expand a node; otherwise textDocument+position
@ -44,39 +45,32 @@ struct In_CclsInheritance : public RequestInMessage {
} params; } params;
}; };
MAKE_REFLECT_STRUCT(In_CclsInheritance::Params, textDocument, position, MAKE_REFLECT_STRUCT(In_cclsInheritance::Params, textDocument, position, id,
id, kind, derived, qualified, levels, hierarchy); kind, derived, qualified, levels, hierarchy);
MAKE_REFLECT_STRUCT(In_CclsInheritance, id, params); MAKE_REFLECT_STRUCT(In_cclsInheritance, id, params);
REGISTER_IN_MESSAGE(In_CclsInheritance); REGISTER_IN_MESSAGE(In_cclsInheritance);
struct Out_CclsInheritance struct Out_cclsInheritance {
: public lsOutMessage<Out_CclsInheritance> { Usr usr;
struct Entry { std::string id;
Usr usr; SymbolKind kind;
std::string id; std::string_view name;
SymbolKind kind; lsLocation location;
std::string_view name; // For unexpanded nodes, this is an upper bound because some entities may be
lsLocation location; // undefined. If it is 0, there are no members.
// For unexpanded nodes, this is an upper bound because some entities may be int numChildren;
// undefined. If it is 0, there are no members. // Empty if the |levels| limit is reached.
int numChildren; std::vector<Out_cclsInheritance> children;
// Empty if the |levels| limit is reached.
std::vector<Entry> children;
};
lsRequestId id;
std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsInheritance::Entry, id, kind, name, MAKE_REFLECT_STRUCT(Out_cclsInheritance, id, kind, name, location, numChildren,
location, numChildren, children); children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsInheritance, jsonrpc,
id, result);
bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry, bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool derived, bool qualified, int levels); bool qualified, int levels);
template <typename Q> template <typename Q>
bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry, bool ExpandHelper(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool derived, bool qualified, int levels, Q &entity) { bool qualified, int levels, Q &entity) {
const auto *def = entity.AnyDef(); const auto *def = entity.AnyDef();
if (def) { if (def) {
entry->name = def->Name(qualified); entry->name = def->Name(qualified);
@ -97,7 +91,7 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry,
for (auto usr : entity.derived) { for (auto usr : entity.derived) {
if (!seen.insert(usr).second) if (!seen.insert(usr).second)
continue; continue;
Out_CclsInheritance::Entry entry1; Out_cclsInheritance entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
entry1.usr = usr; entry1.usr = usr;
entry1.kind = entry->kind; entry1.kind = entry->kind;
@ -112,7 +106,7 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry,
for (auto usr : def->bases) { for (auto usr : def->bases) {
if (!seen.insert(usr).second) if (!seen.insert(usr).second)
continue; continue;
Out_CclsInheritance::Entry entry1; Out_cclsInheritance entry1;
entry1.id = std::to_string(usr); entry1.id = std::to_string(usr);
entry1.usr = usr; entry1.usr = usr;
entry1.kind = entry->kind; entry1.kind = entry->kind;
@ -126,8 +120,8 @@ bool ExpandHelper(MessageHandler *m, Out_CclsInheritance::Entry *entry,
return true; return true;
} }
bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry, bool Expand(MessageHandler *m, Out_cclsInheritance *entry, bool derived,
bool derived, bool qualified, int levels) { bool qualified, int levels) {
if (entry->kind == SymbolKind::Func) if (entry->kind == SymbolKind::Func)
return ExpandHelper(m, entry, derived, qualified, levels, return ExpandHelper(m, entry, derived, qualified, levels,
m->db->Func(entry->usr)); m->db->Func(entry->usr));
@ -136,13 +130,12 @@ bool Expand(MessageHandler *m, Out_CclsInheritance::Entry *entry,
m->db->Type(entry->usr)); m->db->Type(entry->usr));
} }
struct Handler_CclsInheritance struct Handler_cclsInheritance : BaseMessageHandler<In_cclsInheritance> {
: BaseMessageHandler<In_CclsInheritance> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
std::optional<Out_CclsInheritance::Entry> std::optional<Out_cclsInheritance> BuildInitial(SymbolRef sym, bool derived,
BuildInitial(SymbolRef sym, bool derived, bool qualified, int levels) { bool qualified, int levels) {
Out_CclsInheritance::Entry entry; Out_cclsInheritance entry;
entry.id = std::to_string(sym.usr); entry.id = std::to_string(sym.usr);
entry.usr = sym.usr; entry.usr = sym.usr;
entry.kind = sym.kind; entry.kind = sym.kind;
@ -150,25 +143,24 @@ struct Handler_CclsInheritance
return entry; return entry;
} }
void Run(In_CclsInheritance *request) override { void Run(In_cclsInheritance *request) override {
auto &params = request->params; auto &params = request->params;
Out_CclsInheritance out; std::optional<Out_cclsInheritance> result;
out.id = request->id;
if (params.id.size()) { if (params.id.size()) {
try { try {
params.usr = std::stoull(params.id); params.usr = std::stoull(params.id);
} catch (...) { } catch (...) {
return; return;
} }
Out_CclsInheritance::Entry entry; result.emplace();
entry.id = std::to_string(params.usr); result->id = std::to_string(params.usr);
entry.usr = params.usr; result->usr = params.usr;
entry.kind = params.kind; result->kind = params.kind;
if (((entry.kind == SymbolKind::Func && db->HasFunc(entry.usr)) || if (!(((params.kind == SymbolKind::Func && db->HasFunc(params.usr)) ||
(entry.kind == SymbolKind::Type && db->HasType(entry.usr))) && (params.kind == SymbolKind::Type && db->HasType(params.usr))) &&
Expand(this, &entry, params.derived, params.qualified, params.levels)) Expand(this, &*result, params.derived, params.qualified,
out.result = std::move(entry); params.levels)))
result.reset();
} else { } else {
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
@ -178,23 +170,38 @@ struct Handler_CclsInheritance
for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position))
if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) { if (sym.kind == SymbolKind::Func || sym.kind == SymbolKind::Type) {
out.result = BuildInitial(sym, params.derived, params.qualified, result = BuildInitial(sym, params.derived, params.qualified,
params.levels); params.levels);
break; break;
} }
} }
if (params.hierarchy) { if (params.hierarchy)
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; else {
auto out = FlattenHierarchy(result);
pipeline::Reply(request->id, out);
} }
Out_LocationList out1;
out1.id = request->id;
if (out.result)
FlattenHierarchy<Out_CclsInheritance::Entry>(*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<In_textDocumentImplementation> {
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 } // namespace

View File

@ -30,7 +30,7 @@ using namespace clang;
namespace { namespace {
MethodType kMethodType = "$ccls/member"; MethodType kMethodType = "$ccls/member";
struct In_CclsMember : public RequestInMessage { struct In_cclsMember : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
@ -52,42 +52,36 @@ struct In_CclsMember : public RequestInMessage {
} params; } params;
}; };
MAKE_REFLECT_STRUCT(In_CclsMember::Params, textDocument, position, id, MAKE_REFLECT_STRUCT(In_cclsMember::Params, textDocument, position, id,
qualified, levels, kind, hierarchy); qualified, levels, kind, hierarchy);
MAKE_REFLECT_STRUCT(In_CclsMember, id, params); MAKE_REFLECT_STRUCT(In_cclsMember, id, params);
REGISTER_IN_MESSAGE(In_CclsMember); REGISTER_IN_MESSAGE(In_cclsMember);
struct Out_CclsMember : public lsOutMessage<Out_CclsMember> { struct Out_cclsMember {
struct Entry { Usr usr;
Usr usr; std::string id;
std::string id; std::string_view name;
std::string_view name; std::string fieldName;
std::string fieldName; lsLocation location;
lsLocation location; // For unexpanded nodes, this is an upper bound because some entities may be
// For unexpanded nodes, this is an upper bound because some entities may be // undefined. If it is 0, there are no members.
// undefined. If it is 0, there are no members. int numChildren = 0;
int numChildren = 0; // Empty if the |levels| limit is reached.
// Empty if the |levels| limit is reached. std::vector<Out_cclsMember> children;
std::vector<Entry> children;
};
lsRequestId id;
std::optional<Entry> result;
}; };
MAKE_REFLECT_STRUCT(Out_CclsMember::Entry, id, name, fieldName, MAKE_REFLECT_STRUCT(Out_cclsMember, id, name, fieldName, location, numChildren,
location, numChildren, children); children);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_CclsMember, jsonrpc, id,
result);
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
bool qualified, int levels, SymbolKind memberKind); int levels, SymbolKind memberKind);
// Add a field to |entry| which is a Func/Type. // Add a field to |entry| which is a Func/Type.
void DoField(MessageHandler *m, Out_CclsMember::Entry *entry, void DoField(MessageHandler *m, Out_cclsMember *entry, const QueryVar &var,
const QueryVar &var, int64_t offset, bool qualified, int levels) { int64_t offset, bool qualified, int levels) {
const QueryVar::Def *def1 = var.AnyDef(); const QueryVar::Def *def1 = var.AnyDef();
if (!def1) if (!def1)
return; return;
Out_CclsMember::Entry entry1; Out_cclsMember entry1;
// With multiple inheritance, the offset is incorrect. // With multiple inheritance, the offset is incorrect.
if (offset >= 0) { if (offset >= 0) {
if (offset / 8 < 10) if (offset / 8 < 10)
@ -124,8 +118,8 @@ void DoField(MessageHandler *m, Out_CclsMember::Entry *entry,
} }
// Expand a type node by adding members recursively to it. // Expand a type node by adding members recursively to it.
bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry, bool Expand(MessageHandler *m, Out_cclsMember *entry, bool qualified,
bool qualified, int levels, SymbolKind memberKind) { int levels, SymbolKind memberKind) {
if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) { if (0 < entry->usr && entry->usr <= BuiltinType::LastKind) {
entry->name = ClangBuiltinTypeName(int(entry->usr)); entry->name = ClangBuiltinTypeName(int(entry->usr));
return true; return true;
@ -157,7 +151,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
} }
if (def->alias_of) { if (def->alias_of) {
const QueryType::Def *def1 = m->db->Type(def->alias_of).AnyDef(); 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.id = std::to_string(def->alias_of);
entry1.usr = def->alias_of; entry1.usr = def->alias_of;
if (def1 && def1->spell) { if (def1 && def1->spell) {
@ -187,7 +181,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
if (seen1.insert(usr).second) { if (seen1.insert(usr).second) {
QueryFunc &func1 = m->db->Func(usr); QueryFunc &func1 = m->db->Func(usr);
if (const QueryFunc::Def *def1 = func1.AnyDef()) { if (const QueryFunc::Def *def1 = func1.AnyDef()) {
Out_CclsMember::Entry entry1; Out_cclsMember entry1;
entry1.fieldName = def1->Name(false); entry1.fieldName = def1->Name(false);
if (def1->spell) { if (def1->spell) {
if (auto loc = if (auto loc =
@ -208,7 +202,7 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
if (seen1.insert(usr).second) { if (seen1.insert(usr).second) {
QueryType &type1 = m->db->Type(usr); QueryType &type1 = m->db->Type(usr);
if (const QueryType::Def *def1 = type1.AnyDef()) { if (const QueryType::Def *def1 = type1.AnyDef()) {
Out_CclsMember::Entry entry1; Out_cclsMember entry1;
entry1.fieldName = def1->Name(false); entry1.fieldName = def1->Name(false);
if (def1->spell) { if (def1->spell) {
if (auto loc = if (auto loc =
@ -239,12 +233,12 @@ bool Expand(MessageHandler *m, Out_CclsMember::Entry *entry,
return true; return true;
} }
struct Handler_CclsMember struct Handler_cclsMember : BaseMessageHandler<In_cclsMember> {
: BaseMessageHandler<In_CclsMember> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
std::optional<Out_CclsMember::Entry> std::optional<Out_cclsMember> BuildInitial(SymbolKind kind, Usr root_usr,
BuildInitial(SymbolKind kind, Usr root_usr, bool qualified, int levels, SymbolKind memberKind) { bool qualified, int levels,
SymbolKind memberKind) {
switch (kind) { switch (kind) {
default: default:
return {}; return {};
@ -253,7 +247,7 @@ struct Handler_CclsMember
if (!def) if (!def)
return {}; return {};
Out_CclsMember::Entry entry; Out_cclsMember entry;
// Not type, |id| is invalid. // Not type, |id| is invalid.
entry.name = def->Name(qualified); entry.name = def->Name(qualified);
if (def->spell) { if (def->spell) {
@ -273,7 +267,7 @@ struct Handler_CclsMember
if (!def) if (!def)
return {}; return {};
Out_CclsMember::Entry entry; Out_cclsMember entry;
entry.id = std::to_string(root_usr); entry.id = std::to_string(root_usr);
entry.usr = root_usr; entry.usr = root_usr;
if (def->spell) { if (def->spell) {
@ -287,24 +281,22 @@ struct Handler_CclsMember
} }
} }
void Run(In_CclsMember *request) override { void Run(In_cclsMember *request) override {
auto &params = request->params; auto &params = request->params;
Out_CclsMember out; std::optional<Out_cclsMember> result;
out.id = request->id;
if (params.id.size()) { if (params.id.size()) {
try { try {
params.usr = std::stoull(params.id); params.usr = std::stoull(params.id);
} catch (...) { } catch (...) {
return; return;
} }
Out_CclsMember::Entry entry; result.emplace();
entry.id = std::to_string(params.usr); result->id = std::to_string(params.usr);
entry.usr = params.usr; result->usr = params.usr;
// entry.name is empty as it is known by the client. // entry.name is empty as it is known by the client.
if (db->HasType(entry.usr) && if (!(db->HasType(params.usr) && Expand(this, &*result, params.qualified,
Expand(this, &entry, params.qualified, params.levels, params.kind)) params.levels, params.kind)))
out.result = std::move(entry); result.reset();
} else { } else {
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
@ -316,14 +308,14 @@ struct Handler_CclsMember
switch (sym.kind) { switch (sym.kind) {
case SymbolKind::Func: case SymbolKind::Func:
case SymbolKind::Type: case SymbolKind::Type:
out.result = BuildInitial(sym.kind, sym.usr, params.qualified, result = BuildInitial(sym.kind, sym.usr, params.qualified,
params.levels, params.kind); params.levels, params.kind);
break; break;
case SymbolKind::Var: { case SymbolKind::Var: {
const QueryVar::Def *def = db->GetVar(sym).AnyDef(); const QueryVar::Def *def = db->GetVar(sym).AnyDef();
if (def && def->type) if (def && def->type)
out.result = BuildInitial(SymbolKind::Type, def->type, result = BuildInitial(SymbolKind::Type, def->type, params.qualified,
params.qualified, params.levels, params.kind); params.levels, params.kind);
break; break;
} }
default: default:
@ -333,17 +325,14 @@ struct Handler_CclsMember
} }
} }
if (params.hierarchy) { if (params.hierarchy)
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; else {
auto out = FlattenHierarchy(result);
pipeline::Reply(request->id, out);
} }
Out_LocationList out1;
out1.id = request->id;
if (out.result)
FlattenHierarchy<Out_CclsMember::Entry>(*out.result, out1);
pipeline::WriteStdout(kMethodType, out1);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsMember); REGISTER_MESSAGE_HANDLER(Handler_cclsMember);
} // namespace } // namespace

View File

@ -21,7 +21,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/navigate"; MethodType kMethodType = "$ccls/navigate";
struct In_CclsNavigate : public RequestInMessage { struct In_CclsNavigate : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -100,15 +100,14 @@ struct Handler_CclsNavigate : BaseMessageHandler<In_CclsNavigate> {
res = sym.range; res = sym.range;
break; break;
} }
Out_LocationList out; std::vector<lsLocation> result;
out.id = request->id;
if (res) if (res)
if (auto ls_range = GetLsRange(wfile, *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.uri = params.textDocument.uri;
ls_loc.range = *ls_range; ls_loc.range = *ls_range;
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsNavigate); REGISTER_MESSAGE_HANDLER(Handler_CclsNavigate);

View File

@ -28,7 +28,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/reload"; MethodType kMethodType = "$ccls/reload";
struct In_CclsReload : public NotificationInMessage { struct In_cclsReload : public NotificationMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
bool dependencies = true; bool dependencies = true;
@ -36,14 +36,13 @@ struct In_CclsReload : public NotificationInMessage {
std::vector<std::string> blacklist; std::vector<std::string> blacklist;
} params; } params;
}; };
MAKE_REFLECT_STRUCT(In_CclsReload::Params, dependencies, whitelist, MAKE_REFLECT_STRUCT(In_cclsReload::Params, dependencies, whitelist, blacklist);
blacklist); MAKE_REFLECT_STRUCT(In_cclsReload, params);
MAKE_REFLECT_STRUCT(In_CclsReload, params); REGISTER_IN_MESSAGE(In_cclsReload);
REGISTER_IN_MESSAGE(In_CclsReload);
struct Handler_CclsReload : BaseMessageHandler<In_CclsReload> { struct Handler_cclsReload : BaseMessageHandler<In_cclsReload> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsReload *request) override { void Run(In_cclsReload *request) override {
const auto &params = request->params; const auto &params = request->params;
// Send index requests for every file. // Send index requests for every file.
if (params.whitelist.empty() && params.blacklist.empty()) { if (params.whitelist.empty() && params.blacklist.empty()) {
@ -91,5 +90,5 @@ struct Handler_CclsReload : BaseMessageHandler<In_CclsReload> {
} }
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsReload); REGISTER_MESSAGE_HANDLER(Handler_cclsReload);
} // namespace } // namespace

View File

@ -21,7 +21,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "$ccls/vars"; MethodType kMethodType = "$ccls/vars";
struct In_CclsVars : public RequestInMessage { struct In_cclsVars : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params : lsTextDocumentPositionParams { struct Params : lsTextDocumentPositionParams {
// 1: field // 1: field
@ -30,14 +30,14 @@ struct In_CclsVars : public RequestInMessage {
unsigned kind = ~0u; unsigned kind = ~0u;
} params; } params;
}; };
MAKE_REFLECT_STRUCT(In_CclsVars::Params, textDocument, position, kind); MAKE_REFLECT_STRUCT(In_cclsVars::Params, textDocument, position, kind);
MAKE_REFLECT_STRUCT(In_CclsVars, id, params); MAKE_REFLECT_STRUCT(In_cclsVars, id, params);
REGISTER_IN_MESSAGE(In_CclsVars); REGISTER_IN_MESSAGE(In_cclsVars);
struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> { struct Handler_cclsVars : BaseMessageHandler<In_cclsVars> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_CclsVars *request) override { void Run(In_cclsVars *request) override {
auto &params = request->params; auto &params = request->params;
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
@ -47,8 +47,7 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
WorkingFile *working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; std::vector<lsLocation> result;
out.id = request->id;
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, params.position)) { FindSymbolsAtLocation(working_file, file, params.position)) {
Usr usr = sym.usr; Usr usr = sym.usr;
@ -63,14 +62,14 @@ struct Handler_CclsVars : BaseMessageHandler<In_CclsVars> {
[[fallthrough]]; [[fallthrough]];
} }
case SymbolKind::Type: case SymbolKind::Type:
out.result = GetLsLocations( result = GetLsLocations(
db, working_files, db, working_files,
GetVarDeclarations(db, db->Type(usr).instances, params.kind)); GetVarDeclarations(db, db->Type(usr).instances, params.kind));
break; break;
} }
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_CclsVars); REGISTER_MESSAGE_HANDLER(Handler_cclsVars);
} // namespace } // namespace

View File

@ -16,7 +16,7 @@ limitations under the License.
#include "message_handler.h" #include "message_handler.h"
namespace { namespace {
struct In_Exit : public NotificationInMessage { struct In_Exit : public NotificationMessage {
MethodType GetMethodType() const override { return kMethodType_Exit; } MethodType GetMethodType() const override { return kMethodType_Exit; }
}; };
MAKE_REFLECT_EMPTY_STRUCT(In_Exit); MAKE_REFLECT_EMPTY_STRUCT(In_Exit);

View File

@ -400,7 +400,7 @@ struct lsInitializeError {
}; };
MAKE_REFLECT_STRUCT(lsInitializeError, retry); MAKE_REFLECT_STRUCT(lsInitializeError, retry);
struct In_InitializeRequest : public RequestInMessage { struct In_InitializeRequest : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsInitializeParams params; lsInitializeParams params;
@ -408,15 +408,10 @@ struct In_InitializeRequest : public RequestInMessage {
MAKE_REFLECT_STRUCT(In_InitializeRequest, id, params); MAKE_REFLECT_STRUCT(In_InitializeRequest, id, params);
REGISTER_IN_MESSAGE(In_InitializeRequest); REGISTER_IN_MESSAGE(In_InitializeRequest);
struct Out_InitializeResponse : public lsOutMessage<Out_InitializeResponse> { struct lsInitializeResult {
struct InitializeResult { lsServerCapabilities capabilities;
lsServerCapabilities capabilities;
};
lsRequestId id;
InitializeResult result;
}; };
MAKE_REFLECT_STRUCT(Out_InitializeResponse::InitializeResult, capabilities); MAKE_REFLECT_STRUCT(lsInitializeResult, capabilities);
MAKE_REFLECT_STRUCT(Out_InitializeResponse, jsonrpc, id, result);
void *Indexer(void *arg_) { void *Indexer(void *arg_) {
MessageHandler *h; MessageHandler *h;
@ -486,13 +481,10 @@ struct Handler_Initialize : BaseMessageHandler<In_InitializeRequest> {
// Send initialization before starting indexers, so we don't send a // Send initialization before starting indexers, so we don't send a
// status update too early. // status update too early.
// TODO: query request->params.capabilities.textDocument and support {
// only things the client supports. lsInitializeResult result;
pipeline::Reply(request->id, result);
Out_InitializeResponse out; }
out.id = request->id;
pipeline::WriteStdout(kMethodType, out);
// Set project root. // Set project root.
EnsureEndsInSlash(project_path); EnsureEndsInSlash(project_path);

View File

@ -20,24 +20,17 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "shutdown"; MethodType kMethodType = "shutdown";
struct In_Shutdown : public RequestInMessage { struct In_Shutdown : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
}; };
MAKE_REFLECT_STRUCT(In_Shutdown, id); MAKE_REFLECT_STRUCT(In_Shutdown, id);
REGISTER_IN_MESSAGE(In_Shutdown); REGISTER_IN_MESSAGE(In_Shutdown);
struct Out_Shutdown : public lsOutMessage<Out_Shutdown> {
lsRequestId id;
JsonNull result;
};
MAKE_REFLECT_STRUCT(Out_Shutdown, jsonrpc, id, result);
struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> { struct Handler_Shutdown : BaseMessageHandler<In_Shutdown> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_Shutdown *request) override { void Run(In_Shutdown *request) override {
Out_Shutdown out; JsonNull result;
out.id = request->id; pipeline::Reply(request->id, result);
pipeline::WriteStdout(kMethodType, out);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_Shutdown); REGISTER_MESSAGE_HANDLER(Handler_Shutdown);

View File

@ -21,7 +21,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/codeAction"; MethodType kMethodType = "textDocument/codeAction";
struct In_TextDocumentCodeAction : public RequestInMessage { struct In_TextDocumentCodeAction : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
// Contains additional diagnostic information about the context in which // Contains additional diagnostic information about the context in which
@ -54,13 +54,6 @@ struct lsCodeAction {
}; };
MAKE_REFLECT_STRUCT(lsCodeAction, title, kind, edit); MAKE_REFLECT_STRUCT(lsCodeAction, title, kind, edit);
struct Out_TextDocumentCodeAction
: public lsOutMessage<Out_TextDocumentCodeAction> {
lsRequestId id;
std::vector<lsCodeAction> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeAction, jsonrpc, id, result);
struct Handler_TextDocumentCodeAction struct Handler_TextDocumentCodeAction
: BaseMessageHandler<In_TextDocumentCodeAction> { : BaseMessageHandler<In_TextDocumentCodeAction> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
@ -71,20 +64,19 @@ struct Handler_TextDocumentCodeAction
working_files->GetFileByFilename(params.textDocument.uri.GetPath()); working_files->GetFileByFilename(params.textDocument.uri.GetPath());
if (!wfile) if (!wfile)
return; return;
Out_TextDocumentCodeAction out; std::vector<lsCodeAction> result;
out.id = request->id;
std::vector<lsDiagnostic> diagnostics; std::vector<lsDiagnostic> diagnostics;
working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; }); working_files->DoAction([&]() { diagnostics = wfile->diagnostics_; });
for (lsDiagnostic &diag : diagnostics) for (lsDiagnostic &diag : diagnostics)
if (diag.fixits_.size()) { if (diag.fixits_.size()) {
lsCodeAction &cmd = out.result.emplace_back(); lsCodeAction &cmd = result.emplace_back();
cmd.title = "FixIt: " + diag.message; cmd.title = "FixIt: " + diag.message;
auto &edit = cmd.edit.documentChanges.emplace_back(); auto &edit = cmd.edit.documentChanges.emplace_back();
edit.textDocument.uri = params.textDocument.uri; edit.textDocument.uri = params.textDocument.uri;
edit.textDocument.version = wfile->version; edit.textDocument.version = wfile->version;
edit.edits = diag.fixits_; edit.edits = diag.fixits_;
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeAction);

View File

@ -48,12 +48,6 @@ struct Cmd_xref {
}; };
MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field); MAKE_REFLECT_STRUCT(Cmd_xref, usr, kind, field);
struct Out_xref : public lsOutMessage<Out_xref> {
lsRequestId id;
std::vector<lsLocation> result;
};
MAKE_REFLECT_STRUCT(Out_xref, jsonrpc, id, result);
template <typename T> template <typename T>
std::string ToString(T &v) { std::string ToString(T &v) {
rapidjson::StringBuffer output; rapidjson::StringBuffer output;
@ -69,7 +63,7 @@ struct CommonCodeLensParams {
WorkingFile *wfile; WorkingFile *wfile;
}; };
struct In_TextDocumentCodeLens : public RequestInMessage { struct In_TextDocumentCodeLens : public RequestMessage {
MethodType GetMethodType() const override { return codeLens; } MethodType GetMethodType() const override { return codeLens; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -79,20 +73,12 @@ MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens::Params, textDocument);
MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentCodeLens); REGISTER_IN_MESSAGE(In_TextDocumentCodeLens);
struct Out_TextDocumentCodeLens
: public lsOutMessage<Out_TextDocumentCodeLens> {
lsRequestId id;
std::vector<lsCodeLens> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
struct Handler_TextDocumentCodeLens struct Handler_TextDocumentCodeLens
: BaseMessageHandler<In_TextDocumentCodeLens> { : BaseMessageHandler<In_TextDocumentCodeLens> {
MethodType GetMethodType() const override { return codeLens; } MethodType GetMethodType() const override { return codeLens; }
void Run(In_TextDocumentCodeLens *request) override { void Run(In_TextDocumentCodeLens *request) override {
auto &params = request->params; auto &params = request->params;
Out_TextDocumentCodeLens out; std::vector<lsCodeLens> result;
out.id = request->id;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
QueryFile *file; QueryFile *file;
@ -107,7 +93,7 @@ struct Handler_TextDocumentCodeLens
std::optional<lsRange> range = GetLsRange(wfile, use.range); std::optional<lsRange> range = GetLsRange(wfile, use.range);
if (!range) if (!range)
return; return;
lsCodeLens &code_lens = out.result.emplace_back(); lsCodeLens &code_lens = result.emplace_back();
code_lens.range = *range; code_lens.range = *range;
code_lens.command = lsCommand(); code_lens.command = lsCommand();
code_lens.command->command = std::string(ccls_xref); code_lens.command->command = std::string(ccls_xref);
@ -178,12 +164,12 @@ struct Handler_TextDocumentCodeLens
}; };
} }
pipeline::WriteStdout(codeLens, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
struct In_WorkspaceExecuteCommand : public RequestInMessage { struct In_WorkspaceExecuteCommand : public RequestMessage {
MethodType GetMethodType() const override { return executeCommand; } MethodType GetMethodType() const override { return executeCommand; }
lsCommand params; lsCommand params;
}; };
@ -203,12 +189,11 @@ struct Handler_WorkspaceExecuteCommand
if (params.command == ccls_xref) { if (params.command == ccls_xref) {
Cmd_xref cmd; Cmd_xref cmd;
Reflect(json_reader, cmd); Reflect(json_reader, cmd);
Out_xref out; std::vector<lsLocation> result;
out.id = request->id;
auto Map = [&](auto &&uses) { auto Map = [&](auto &&uses) {
for (auto &use : uses) for (auto &use : uses)
if (auto loc = GetLsLocation(db, working_files, use)) if (auto loc = GetLsLocation(db, working_files, use))
out.result.push_back(std::move(*loc)); result.push_back(std::move(*loc));
}; };
switch (cmd.kind) { switch (cmd.kind) {
case SymbolKind::Func: { case SymbolKind::Func: {
@ -247,7 +232,7 @@ struct Handler_WorkspaceExecuteCommand
default: default:
break; break;
} }
pipeline::WriteStdout(executeCommand, out); pipeline::Reply(request->id, result);
} }
} }
}; };

View File

@ -66,28 +66,21 @@ struct lsCompletionParams : lsTextDocumentPositionParams {
}; };
MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context); MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context);
struct In_TextDocumentComplete : public RequestInMessage { struct In_TextDocumentComplete : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsCompletionParams params; lsCompletionParams params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentComplete, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentComplete, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentComplete); REGISTER_IN_MESSAGE(In_TextDocumentComplete);
struct lsTextDocumentCompleteResult { struct lsCompletionList {
// This list it not complete. Further typing should result in recomputing // This list it not complete. Further typing should result in recomputing
// this list. // this list.
bool isIncomplete = false; bool isIncomplete = false;
// The completion items. // The completion items.
std::vector<lsCompletionItem> items; std::vector<lsCompletionItem> items;
}; };
MAKE_REFLECT_STRUCT(lsTextDocumentCompleteResult, isIncomplete, items); MAKE_REFLECT_STRUCT(lsCompletionList, isIncomplete, items);
struct Out_TextDocumentComplete
: public lsOutMessage<Out_TextDocumentComplete> {
lsRequestId id;
lsTextDocumentCompleteResult result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentComplete, jsonrpc, id, result);
void DecorateIncludePaths(const std::smatch &match, void DecorateIncludePaths(const std::smatch &match,
std::vector<lsCompletionItem> *items) { std::vector<lsCompletionItem> *items) {
@ -153,11 +146,11 @@ template <typename T> char *tofixedbase64(T input, char *out) {
// Pre-filters completion responses before sending to vscode. This results in a // Pre-filters completion responses before sending to vscode. This results in a
// significantly snappier completion experience as vscode is easily overloaded // significantly snappier completion experience as vscode is easily overloaded
// when given 1000+ completion items. // when given 1000+ completion items.
void FilterCandidates(Out_TextDocumentComplete *complete_response, void FilterCandidates(lsCompletionList &result,
const std::string &complete_text, lsPosition begin_pos, const std::string &complete_text, lsPosition begin_pos,
lsPosition end_pos, const std::string &buffer_line) { lsPosition end_pos, const std::string &buffer_line) {
assert(begin_pos.line == end_pos.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 // People usually does not want to insert snippets or parenthesis when
// changing function or type names, e.g. "str.|()" or "std::|<int>". // changing function or type names, e.g. "str.|()" or "std::|<int>".
@ -173,7 +166,7 @@ void FilterCandidates(Out_TextDocumentComplete *complete_response,
int max_num = g_config->completion.maxNum; int max_num = g_config->completion.maxNum;
if (items.size() > max_num) { if (items.size() > max_num) {
items.resize(max_num); items.resize(max_num);
complete_response->result.isIncomplete = true; result.isIncomplete = true;
} }
for (auto &item : items) { for (auto &item : items) {
@ -497,13 +490,12 @@ struct Handler_TextDocumentCompletion
static CompleteConsumerCache<std::vector<lsCompletionItem>> cache; static CompleteConsumerCache<std::vector<lsCompletionItem>> cache;
const auto &params = request->params; const auto &params = request->params;
Out_TextDocumentComplete out; lsCompletionList result;
out.id = request->id;
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
WorkingFile *file = working_files->GetFileByFilename(path); WorkingFile *file = working_files->GetFileByFilename(path);
if (!file) { if (!file) {
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; return;
} }
@ -548,7 +540,7 @@ struct Handler_TextDocumentCompletion
} }
if (did_fail_check) { if (did_fail_check) {
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; return;
} }
} }
@ -561,8 +553,7 @@ struct Handler_TextDocumentCompletion
ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line); ParseIncludeLineResult preprocess = ParseIncludeLine(buffer_line);
if (preprocess.ok && preprocess.keyword.compare("include") == 0) { if (preprocess.ok && preprocess.keyword.compare("include") == 0) {
Out_TextDocumentComplete out; lsCompletionList result;
out.id = request->id;
{ {
std::unique_lock<std::mutex> lock( std::unique_lock<std::mutex> lock(
include_complete->completion_items_mutex, std::defer_lock); include_complete->completion_items_mutex, std::defer_lock);
@ -571,14 +562,14 @@ struct Handler_TextDocumentCompletion
std::string quote = preprocess.match[5]; std::string quote = preprocess.match[5];
for (auto &item : include_complete->completion_items) for (auto &item : include_complete->completion_items)
if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\"")) if (quote.empty() || quote == (item.use_angle_brackets_ ? "<" : "\""))
out.result.items.push_back(item); result.items.push_back(item);
} }
begin_pos.character = 0; begin_pos.character = 0;
end_pos.character = (int)buffer_line.size(); 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); buffer_line);
DecorateIncludePaths(preprocess.match, &out.result.items); DecorateIncludePaths(preprocess.match, &result.items);
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} else { } else {
std::string path = params.textDocument.uri.GetPath(); std::string path = params.textDocument.uri.GetPath();
CompletionManager::OnComplete callback = CompletionManager::OnComplete callback =
@ -587,13 +578,12 @@ struct Handler_TextDocumentCompletion
if (!OptConsumer) if (!OptConsumer)
return; return;
auto *Consumer = static_cast<CompletionConsumer *>(OptConsumer); auto *Consumer = static_cast<CompletionConsumer *>(OptConsumer);
Out_TextDocumentComplete out; lsCompletionList result;
out.id = id; result.items = Consumer->ls_items;
out.result.items = Consumer->ls_items;
FilterCandidates(&out, completion_text, begin_pos, end_pos, FilterCandidates(result, completion_text, begin_pos, end_pos,
buffer_line); buffer_line);
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(id, result);
if (!Consumer->from_cache) { if (!Consumer->from_cache) {
cache.WithLock([&]() { cache.WithLock([&]() {
cache.path = path; cache.path = path;

View File

@ -26,7 +26,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/definition"; MethodType kMethodType = "textDocument/definition";
struct In_TextDocumentDefinition : public RequestInMessage { struct In_TextDocumentDefinition : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
@ -66,9 +66,7 @@ struct Handler_TextDocumentDefinition
params.textDocument.uri.GetPath(), &file, &file_id)) params.textDocument.uri.GetPath(), &file, &file_id))
return; return;
Out_LocationList out; std::vector<lsLocation> result;
out.id = request->id;
Maybe<Use> on_def; Maybe<Use> on_def;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
lsPosition &ls_pos = params.position; lsPosition &ls_pos = params.position;
@ -104,19 +102,18 @@ struct Handler_TextDocumentDefinition
uses.push_back(*on_def); uses.push_back(*on_def);
} }
auto locs = GetLsLocations(db, working_files, uses); 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()) { if (result.size()) {
std::sort(out.result.begin(), out.result.end()); std::sort(result.begin(), result.end());
out.result.erase(std::unique(out.result.begin(), out.result.end()), result.erase(std::unique(result.begin(), result.end()), result.end());
out.result.end());
} else { } else {
Maybe<Range> range; Maybe<Range> range;
// Check #include // Check #include
for (const IndexInclude &include : file->def->includes) { for (const IndexInclude &include : file->def->includes) {
if (include.line == ls_pos.line) { if (include.line == ls_pos.line) {
out.result.push_back( result.push_back(
lsLocation{lsDocumentUri::FromPath(include.resolved_path)}); lsLocation{lsDocumentUri::FromPath(include.resolved_path)});
range = {{0, 0}, {0, 0}}; range = {{0, 0}, {0, 0}};
break; break;
@ -177,12 +174,12 @@ struct Handler_TextDocumentDefinition
Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym); Maybe<DeclRef> dr = GetDefinitionSpell(db, best_sym);
assert(dr); assert(dr);
if (auto loc = GetLsLocation(db, working_files, *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); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDefinition);

View File

@ -27,7 +27,7 @@ MethodType didClose = "textDocument/didClose";
MethodType didOpen = "textDocument/didOpen"; MethodType didOpen = "textDocument/didOpen";
MethodType didSave = "textDocument/didSave"; MethodType didSave = "textDocument/didSave";
struct In_TextDocumentDidChange : public NotificationInMessage { struct In_TextDocumentDidChange : public NotificationMessage {
MethodType GetMethodType() const override { return didChange; } MethodType GetMethodType() const override { return didChange; }
lsTextDocumentDidChangeParams params; lsTextDocumentDidChangeParams params;
}; };
@ -51,7 +51,7 @@ struct Handler_TextDocumentDidChange
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange);
struct In_TextDocumentDidClose : public NotificationInMessage { struct In_TextDocumentDidClose : public NotificationMessage {
MethodType GetMethodType() const override { return didClose; } MethodType GetMethodType() const override { return didClose; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -68,19 +68,13 @@ struct Handler_TextDocumentDidClose
void Run(In_TextDocumentDidClose *request) override { void Run(In_TextDocumentDidClose *request) override {
std::string path = request->params.textDocument.uri.GetPath(); 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); working_files->OnClose(request->params.textDocument);
clang_complete->OnClose(path); clang_complete->OnClose(path);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose);
struct In_TextDocumentDidOpen : public NotificationInMessage { struct In_TextDocumentDidOpen : public NotificationMessage {
MethodType GetMethodType() const override { return didOpen; } MethodType GetMethodType() const override { return didOpen; }
struct Params { struct Params {
@ -113,9 +107,9 @@ struct Handler_TextDocumentDidOpen
QueryFile *file = nullptr; QueryFile *file = nullptr;
FindFileOrFail(db, project, std::nullopt, path, &file); FindFileOrFail(db, project, std::nullopt, path, &file);
if (file && file->def) { if (file) {
EmitSkippedRanges(working_file, file->def->skipped_ranges); EmitSkippedRanges(working_file, *file);
EmitSemanticHighlighting(db, working_file, file); EmitSemanticHighlight(db, working_file, *file);
} }
include_complete->AddFile(working_file->filename); include_complete->AddFile(working_file->filename);
@ -137,7 +131,7 @@ struct Handler_TextDocumentDidOpen
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
struct In_TextDocumentDidSave : public NotificationInMessage { struct In_TextDocumentDidSave : public NotificationMessage {
MethodType GetMethodType() const override { return didSave; } MethodType GetMethodType() const override { return didSave; }
struct Params { struct Params {

View File

@ -39,20 +39,13 @@ struct lsDocumentHighlight {
}; };
MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role); MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind, role);
struct In_TextDocumentDocumentHighlight : public RequestInMessage { struct In_TextDocumentDocumentHighlight : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentHighlight, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentDocumentHighlight, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentDocumentHighlight); REGISTER_IN_MESSAGE(In_TextDocumentDocumentHighlight);
struct Out_TextDocumentDocumentHighlight
: public lsOutMessage<Out_TextDocumentDocumentHighlight> {
lsRequestId id;
std::vector<lsDocumentHighlight> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentHighlight, jsonrpc, id, result);
struct Handler_TextDocumentDocumentHighlight struct Handler_TextDocumentDocumentHighlight
: BaseMessageHandler<In_TextDocumentDocumentHighlight> { : BaseMessageHandler<In_TextDocumentDocumentHighlight> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
@ -63,14 +56,12 @@ struct Handler_TextDocumentDocumentHighlight
request->params.textDocument.uri.GetPath(), &file, request->params.textDocument.uri.GetPath(), &file,
&file_id)) &file_id))
return; return;
WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path);
Out_TextDocumentDocumentHighlight out; WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
out.id = request->id; std::vector<lsDocumentHighlight> result;
std::vector<SymbolRef> syms = FindSymbolsAtLocation( std::vector<SymbolRef> syms =
working_file, file, request->params.position, true); FindSymbolsAtLocation(wfile, file, request->params.position, true);
for (auto [sym, refcnt] : file->symbol2refcnt) { for (auto [sym, refcnt] : file->symbol2refcnt) {
if (refcnt <= 0) if (refcnt <= 0)
continue; continue;
@ -90,11 +81,11 @@ struct Handler_TextDocumentDocumentHighlight
else else
highlight.kind = lsDocumentHighlight::Text; highlight.kind = lsDocumentHighlight::Text;
highlight.role = sym.role; highlight.role = sym.role;
out.result.push_back(highlight); result.push_back(highlight);
} }
} }
std::sort(out.result.begin(), out.result.end()); std::sort(result.begin(), result.end());
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDocumentHighlight);

View File

@ -24,7 +24,7 @@ MAKE_HASHABLE(SymbolIdx, t.usr, t.kind);
namespace { namespace {
MethodType kMethodType = "textDocument/documentSymbol"; MethodType kMethodType = "textDocument/documentSymbol";
struct In_TextDocumentDocumentSymbol : public RequestInMessage { struct In_TextDocumentDocumentSymbol : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -40,20 +40,6 @@ MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol::Params, textDocument, all,
MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentDocumentSymbol, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentDocumentSymbol); REGISTER_IN_MESSAGE(In_TextDocumentDocumentSymbol);
struct Out_SimpleDocumentSymbol
: public lsOutMessage<Out_SimpleDocumentSymbol> {
lsRequestId id;
std::vector<lsRange> result;
};
MAKE_REFLECT_STRUCT(Out_SimpleDocumentSymbol, jsonrpc, id, result);
struct Out_TextDocumentDocumentSymbol
: public lsOutMessage<Out_TextDocumentDocumentSymbol> {
lsRequestId id;
std::vector<lsSymbolInformation> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
struct lsDocumentSymbol { struct lsDocumentSymbol {
std::string name; std::string name;
std::string detail; std::string detail;
@ -69,13 +55,6 @@ void Reflect(Writer &vis, std::unique_ptr<lsDocumentSymbol> &v) {
Reflect(vis, *v); Reflect(vis, *v);
} }
struct Out_HierarchicalDocumentSymbol
: public lsOutMessage<Out_HierarchicalDocumentSymbol> {
lsRequestId id;
std::vector<std::unique_ptr<lsDocumentSymbol>> result;
};
MAKE_REFLECT_STRUCT(Out_HierarchicalDocumentSymbol, jsonrpc, id, result);
template <typename Def> template <typename Def>
bool Ignore(const Def *def) { bool Ignore(const Def *def) {
return false; return false;
@ -107,15 +86,14 @@ struct Handler_TextDocumentDocumentSymbol
const auto &symbol2refcnt = const auto &symbol2refcnt =
params.all ? file->symbol2refcnt : file->outline2refcnt; params.all ? file->symbol2refcnt : file->outline2refcnt;
if (params.startLine >= 0) { if (params.startLine >= 0) {
Out_SimpleDocumentSymbol out; std::vector<lsRange> result;
out.id = request->id;
for (auto [sym, refcnt] : symbol2refcnt) for (auto [sym, refcnt] : symbol2refcnt)
if (refcnt > 0 && params.startLine <= sym.range.start.line && if (refcnt > 0 && params.startLine <= sym.range.start.line &&
sym.range.start.line <= params.endLine) sym.range.start.line <= params.endLine)
if (auto loc = GetLsLocation(db, working_files, sym, file_id)) if (auto loc = GetLsLocation(db, working_files, sym, file_id))
out.result.push_back(loc->range); result.push_back(loc->range);
std::sort(out.result.begin(), out.result.end()); std::sort(result.begin(), result.end());
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} else if (g_config->client.hierarchicalDocumentSymbolSupport) { } else if (g_config->client.hierarchicalDocumentSymbolSupport) {
std::unordered_map<SymbolIdx, std::unique_ptr<lsDocumentSymbol>> sym2ds; std::unordered_map<SymbolIdx, std::unique_ptr<lsDocumentSymbol>> sym2ds;
std::vector<std::pair<const QueryFunc::Def *, lsDocumentSymbol *>> funcs; std::vector<std::pair<const QueryFunc::Def *, lsDocumentSymbol *>> funcs;
@ -207,15 +185,13 @@ struct Handler_TextDocumentDocumentSymbol
ds->children.push_back(std::move(it->second)); ds->children.push_back(std::move(it->second));
} }
} }
Out_HierarchicalDocumentSymbol out; std::vector<std::unique_ptr<lsDocumentSymbol>> result;
out.id = request->id;
for (auto &[_, ds] : sym2ds) for (auto &[_, ds] : sym2ds)
if (ds) if (ds)
out.result.push_back(std::move(ds)); result.push_back(std::move(ds));
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} else { } else {
Out_TextDocumentDocumentSymbol out; std::vector<lsSymbolInformation> result;
out.id = request->id;
for (auto [sym, refcnt] : symbol2refcnt) { for (auto [sym, refcnt] : symbol2refcnt) {
if (refcnt <= 0) continue; if (refcnt <= 0) continue;
if (std::optional<lsSymbolInformation> info = if (std::optional<lsSymbolInformation> info =
@ -227,11 +203,11 @@ struct Handler_TextDocumentDocumentSymbol
continue; continue;
if (auto loc = GetLsLocation(db, working_files, sym, file_id)) { if (auto loc = GetLsLocation(db, working_files, sym, file_id)) {
info->location = *loc; info->location = *loc;
out.result.push_back(*info); result.push_back(*info);
} }
} }
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
} }
}; };

View File

@ -36,13 +36,6 @@ struct lsFormattingOptions {
}; };
MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces); MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
struct Out_TextDocumentFormatting
: public lsOutMessage<Out_TextDocumentFormatting> {
lsRequestId id;
std::vector<lsTextEdit> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentFormatting, jsonrpc, id, result);
llvm::Expected<tooling::Replacements> llvm::Expected<tooling::Replacements>
FormatCode(std::string_view code, std::string_view file, tooling::Range Range) { FormatCode(std::string_view code, std::string_view file, tooling::Range Range) {
StringRef Code(code.data(), code.size()), File(file.data(), file.size()); StringRef Code(code.data(), code.size()), File(file.data(), file.size());
@ -91,20 +84,17 @@ void Format(WorkingFile *wfile, tooling::Range range, lsRequestId id) {
auto ReplsOrErr = auto ReplsOrErr =
FormatCode(code, wfile->filename, range); FormatCode(code, wfile->filename, range);
if (ReplsOrErr) { if (ReplsOrErr) {
Out_TextDocumentFormatting out; auto result = ReplacementsToEdits(code, *ReplsOrErr);
out.id = id; pipeline::Reply(id, result);
out.result = ReplacementsToEdits(code, *ReplsOrErr);
pipeline::WriteStdout(formatting, out);
} else { } else {
Out_Error err; lsResponseError err;
err.id = id; err.code = lsErrorCodes::UnknownErrorCode;
err.error.code = lsErrorCodes::UnknownErrorCode; err.message = llvm::toString(ReplsOrErr.takeError());
err.error.message = llvm::toString(ReplsOrErr.takeError()); pipeline::ReplyError(id, err);
pipeline::WriteStdout(kMethodType_Unknown, err);
} }
} }
struct In_TextDocumentFormatting : public RequestInMessage { struct In_TextDocumentFormatting : public RequestMessage {
MethodType GetMethodType() const override { return formatting; } MethodType GetMethodType() const override { return formatting; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -132,7 +122,7 @@ struct Handler_TextDocumentFormatting
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting);
struct In_TextDocumentOnTypeFormatting : public RequestInMessage { struct In_TextDocumentOnTypeFormatting : public RequestMessage {
MethodType GetMethodType() const override { return onTypeFormatting; } MethodType GetMethodType() const override { return onTypeFormatting; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;
@ -168,7 +158,7 @@ struct Handler_TextDocumentOnTypeFormatting
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentOnTypeFormatting); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentOnTypeFormatting);
struct In_TextDocumentRangeFormatting : public RequestInMessage { struct In_TextDocumentRangeFormatting : public RequestMessage {
MethodType GetMethodType() const override { return rangeFormatting; } MethodType GetMethodType() const override { return rangeFormatting; }
struct Params { struct Params {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;

View File

@ -70,25 +70,18 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
return {hover, ls_comments}; return {hover, ls_comments};
} }
struct In_TextDocumentHover : public RequestInMessage { struct In_TextDocumentHover : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentHover, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentHover, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentHover); REGISTER_IN_MESSAGE(In_TextDocumentHover);
struct Out_TextDocumentHover : public lsOutMessage<Out_TextDocumentHover> { struct lsHover {
struct Result { std::vector<lsMarkedString> contents;
std::vector<lsMarkedString> contents; std::optional<lsRange> range;
std::optional<lsRange> range;
};
lsRequestId id;
std::optional<Result> result;
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentHover::Result, contents, range); MAKE_REFLECT_STRUCT(lsHover, contents, range);
MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(Out_TextDocumentHover, jsonrpc, id,
result);
struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> { struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
@ -99,33 +92,27 @@ struct Handler_TextDocumentHover : BaseMessageHandler<In_TextDocumentHover> {
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
WorkingFile *working_file = WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
working_files->GetFileByFilename(file->def->path); lsHover result;
Out_TextDocumentHover out; for (SymbolRef sym : FindSymbolsAtLocation(wfile, file, params.position)) {
out.id = request->id;
for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, params.position)) {
// Found symbol. Return hover.
std::optional<lsRange> ls_range = GetLsRange( std::optional<lsRange> ls_range = GetLsRange(
working_files->GetFileByFilename(file->def->path), sym.range); working_files->GetFileByFilename(file->def->path), sym.range);
if (!ls_range) if (!ls_range)
continue; 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) { if (comments || hover) {
out.result = Out_TextDocumentHover::Result(); result.range = *ls_range;
out.result->range = *ls_range;
if (comments) if (comments)
out.result->contents.push_back(*comments); result.contents.push_back(*comments);
if (hover) if (hover)
out.result->contents.push_back(*hover); result.contents.push_back(*hover);
break; break;
} }
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentHover);

View File

@ -1,64 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#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<In_TextDocumentImplementation> {
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

View File

@ -24,7 +24,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/references"; MethodType kMethodType = "textDocument/references";
struct In_TextDocumentReferences : public RequestInMessage { struct In_TextDocumentReferences : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct lsReferenceContext { struct lsReferenceContext {
bool base = true; bool base = true;
@ -60,11 +60,10 @@ struct Handler_TextDocumentReferences
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
params.textDocument.uri.GetPath(), &file)) params.textDocument.uri.GetPath(), &file))
return; return;
Out_LocationList out; std::vector<lsLocation> result;
out.id = request->id;
WorkingFile *wfile = working_files->GetFileByFilename(file->def->path); WorkingFile *wfile = working_files->GetFileByFilename(file->def->path);
if (!file) { if (!file) {
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
return; return;
} }
@ -86,7 +85,7 @@ struct Handler_TextDocumentReferences
!(use.role & params.context.excludeRole) && !(use.role & params.context.excludeRole) &&
seen_uses.insert(use).second) seen_uses.insert(use).second)
if (auto loc = GetLsLocation(db, working_files, use)) { if (auto loc = GetLsLocation(db, working_files, use)) {
out.result.push_back(*loc); result.push_back(*loc);
} }
}; };
WithEntity(db, sym, [&](const auto &entity) { WithEntity(db, sym, [&](const auto &entity) {
@ -116,7 +115,7 @@ struct Handler_TextDocumentReferences
break; break;
} }
if (out.result.empty()) { if (result.empty()) {
// |path| is the #include line. If the cursor is not on such line but line // |path| is the #include line. If the cursor is not on such line but line
// = 0, // = 0,
// use the current filename. // use the current filename.
@ -134,16 +133,16 @@ struct Handler_TextDocumentReferences
for (const IndexInclude &include : file1.def->includes) for (const IndexInclude &include : file1.def->includes)
if (include.resolved_path == path) { if (include.resolved_path == path) {
// Another file |file1| has the same include line. // 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.uri = lsDocumentUri::FromPath(file1.def->path);
loc.range.start.line = loc.range.end.line = include.line; loc.range.start.line = loc.range.end.line = include.line;
break; break;
} }
} }
if ((int)out.result.size() >= g_config->xref.maxNum) if ((int)result.size() >= g_config->xref.maxNum)
out.result.resize(g_config->xref.maxNum); result.resize(g_config->xref.maxNum);
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentReferences);

View File

@ -63,7 +63,7 @@ lsWorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *working_files,
return edit; return edit;
} }
struct In_TextDocumentRename : public RequestInMessage { struct In_TextDocumentRename : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
// The document to format. // The document to format.
@ -84,12 +84,6 @@ MAKE_REFLECT_STRUCT(In_TextDocumentRename::Params, textDocument, position,
MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentRename, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentRename); REGISTER_IN_MESSAGE(In_TextDocumentRename);
struct Out_TextDocumentRename : public lsOutMessage<Out_TextDocumentRename> {
lsRequestId id;
lsWorkspaceEdit result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentRename, jsonrpc, id, result);
struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> { struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_TextDocumentRename *request) override { void Run(In_TextDocumentRename *request) override {
@ -97,25 +91,19 @@ struct Handler_TextDocumentRename : BaseMessageHandler<In_TextDocumentRename> {
QueryFile *file; QueryFile *file;
if (!FindFileOrFail(db, project, request->id, if (!FindFileOrFail(db, project, request->id,
request->params.textDocument.uri.GetPath(), &file, request->params.textDocument.uri.GetPath(), &file,
&file_id)) { &file_id))
return; 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 : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(wfile, file, request->params.position)) {
// Found symbol. Return references to rename. result =
out.result =
BuildWorkspaceEdit(db, working_files, sym, request->params.newName); BuildWorkspaceEdit(db, working_files, sym, request->params.newName);
break; break;
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentRename);

View File

@ -55,20 +55,13 @@ struct lsSignatureHelp {
MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature, MAKE_REFLECT_STRUCT(lsSignatureHelp, signatures, activeSignature,
activeParameter); activeParameter);
struct In_TextDocumentSignatureHelp : public RequestInMessage { struct In_TextDocumentSignatureHelp : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
MAKE_REFLECT_STRUCT(In_TextDocumentSignatureHelp, id, params); MAKE_REFLECT_STRUCT(In_TextDocumentSignatureHelp, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentSignatureHelp); REGISTER_IN_MESSAGE(In_TextDocumentSignatureHelp);
struct Out_TextDocumentSignatureHelp
: public lsOutMessage<Out_TextDocumentSignatureHelp> {
lsRequestId id;
lsSignatureHelp result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentSignatureHelp, jsonrpc, id, result);
std::string BuildOptional(const CodeCompletionString &CCS, std::string BuildOptional(const CodeCompletionString &CCS,
std::vector<lsParameterInformation> &ls_params) { std::vector<lsParameterInformation> &ls_params) {
std::string ret; std::string ret;
@ -199,10 +192,7 @@ struct Handler_TextDocumentSignatureHelp
if (!OptConsumer) if (!OptConsumer)
return; return;
auto *Consumer = static_cast<SignatureHelpConsumer *>(OptConsumer); auto *Consumer = static_cast<SignatureHelpConsumer *>(OptConsumer);
Out_TextDocumentSignatureHelp out; pipeline::Reply(id, Consumer->ls_sighelp);
out.id = id;
out.result = Consumer->ls_sighelp;
pipeline::WriteStdout(kMethodType, out);
if (!Consumer->from_cache) { if (!Consumer->from_cache) {
cache.WithLock([&]() { cache.WithLock([&]() {
cache.path = path; cache.path = path;

View File

@ -21,7 +21,7 @@ using namespace ccls;
namespace { namespace {
MethodType kMethodType = "textDocument/typeDefinition"; MethodType kMethodType = "textDocument/typeDefinition";
struct In_TextDocumentTypeDefinition : public RequestInMessage { struct In_TextDocumentTypeDefinition : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params; lsTextDocumentPositionParams params;
}; };
@ -40,18 +40,17 @@ struct Handler_TextDocumentTypeDefinition
WorkingFile *working_file = WorkingFile *working_file =
working_files->GetFileByFilename(file->def->path); working_files->GetFileByFilename(file->def->path);
Out_LocationList out; std::vector<lsLocation> result;
out.id = request->id;
auto Add = [&](const QueryType &type) { auto Add = [&](const QueryType &type) {
for (const auto &def : type.def) for (const auto &def : type.def)
if (def.spell) { if (def.spell) {
if (auto ls_loc = GetLsLocation(db, working_files, *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) for (const DeclRef &dr : type.declarations)
if (auto ls_loc = GetLsLocation(db, working_files, dr)) if (auto ls_loc = GetLsLocation(db, working_files, dr))
out.result.push_back(*ls_loc); result.push_back(*ls_loc);
}; };
for (SymbolRef sym : for (SymbolRef sym :
FindSymbolsAtLocation(working_file, file, request->params.position)) { FindSymbolsAtLocation(working_file, file, request->params.position)) {
@ -75,7 +74,7 @@ struct Handler_TextDocumentTypeDefinition
} }
} }
pipeline::WriteStdout(kMethodType, out); pipeline::Reply(request->id, result);
} }
}; };
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition); REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);

View File

@ -25,6 +25,7 @@ using namespace ccls;
namespace { namespace {
MethodType didChangeConfiguration = "workspace/didChangeConfiguration", MethodType didChangeConfiguration = "workspace/didChangeConfiguration",
didChangeWatchedFiles = "workspace/didChangeWatchedFiles",
didChangeWorkspaceFolders = "workspace/didChangeWorkspaceFolders"; didChangeWorkspaceFolders = "workspace/didChangeWorkspaceFolders";
struct lsDidChangeConfigurationParams { struct lsDidChangeConfigurationParams {
@ -32,7 +33,7 @@ struct lsDidChangeConfigurationParams {
}; };
MAKE_REFLECT_STRUCT(lsDidChangeConfigurationParams, placeholder); MAKE_REFLECT_STRUCT(lsDidChangeConfigurationParams, placeholder);
struct In_workspaceDidChangeConfiguration : public NotificationInMessage { struct In_workspaceDidChangeConfiguration : public NotificationMessage {
MethodType GetMethodType() const override { return didChangeConfiguration; } MethodType GetMethodType() const override { return didChangeConfiguration; }
lsDidChangeConfigurationParams params; lsDidChangeConfigurationParams params;
}; };
@ -53,12 +54,66 @@ struct Handler_workspaceDidChangeConfiguration
}; };
REGISTER_MESSAGE_HANDLER(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<lsFileEvent> 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<In_WorkspaceDidChangeWatchedFiles> {
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 { struct lsWorkspaceFoldersChangeEvent {
std::vector<lsWorkspaceFolder> added, removed; std::vector<lsWorkspaceFolder> added, removed;
}; };
MAKE_REFLECT_STRUCT(lsWorkspaceFoldersChangeEvent, added, removed); MAKE_REFLECT_STRUCT(lsWorkspaceFoldersChangeEvent, added, removed);
struct In_workspaceDidChangeWorkspaceFolders : public NotificationInMessage { struct In_workspaceDidChangeWorkspaceFolders : public NotificationMessage {
MethodType GetMethodType() const override { MethodType GetMethodType() const override {
return didChangeWorkspaceFolders; return didChangeWorkspaceFolders;
} }

View File

@ -1,79 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#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<lsFileEvent> 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<In_WorkspaceDidChangeWatchedFiles> {
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

View File

@ -54,7 +54,7 @@ bool AddSymbol(
return true; return true;
} }
struct In_WorkspaceSymbol : public RequestInMessage { struct In_WorkspaceSymbol : public RequestMessage {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
struct Params { struct Params {
std::string query; std::string query;
@ -65,20 +65,11 @@ MAKE_REFLECT_STRUCT(In_WorkspaceSymbol::Params, query);
MAKE_REFLECT_STRUCT(In_WorkspaceSymbol, id, params); MAKE_REFLECT_STRUCT(In_WorkspaceSymbol, id, params);
REGISTER_IN_MESSAGE(In_WorkspaceSymbol); REGISTER_IN_MESSAGE(In_WorkspaceSymbol);
struct Out_WorkspaceSymbol : public lsOutMessage<Out_WorkspaceSymbol> {
lsRequestId id;
std::vector<lsSymbolInformation> result;
};
MAKE_REFLECT_STRUCT(Out_WorkspaceSymbol, jsonrpc, id, result);
///// Fuzzy matching
struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> { struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
MethodType GetMethodType() const override { return kMethodType; } MethodType GetMethodType() const override { return kMethodType; }
void Run(In_WorkspaceSymbol *request) override { void Run(In_WorkspaceSymbol *request) override {
Out_WorkspaceSymbol out; std::vector<lsSymbolInformation> result;
out.id = request->id;
std::string query = request->params.query; std::string query = request->params.query;
// {symbol info, matching detailed_name or short_name, index} // {symbol info, matching detailed_name or short_name, index}
@ -128,20 +119,20 @@ struct Handler_WorkspaceSymbol : BaseMessageHandler<In_WorkspaceSymbol> {
std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) { std::sort(cands.begin(), cands.end(), [](const auto &l, const auto &r) {
return std::get<1>(l) > std::get<1>(r); return std::get<1>(l) > std::get<1>(r);
}); });
out.result.reserve(cands.size()); result.reserve(cands.size());
for (auto &cand : cands) { for (auto &cand : cands) {
// Discard awful candidates. // Discard awful candidates.
if (std::get<1>(cand) <= FuzzyMatcher::kMinScore) if (std::get<1>(cand) <= FuzzyMatcher::kMinScore)
break; break;
out.result.push_back(std::get<0>(cand)); result.push_back(std::get<0>(cand));
} }
} else { } else {
out.result.reserve(cands.size()); result.reserve(cands.size());
for (auto &cand : cands) 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); REGISTER_MESSAGE_HANDLER(Handler_WorkspaceSymbol);

View File

@ -1,55 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#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;
}
}

View File

@ -1,59 +0,0 @@
/* Copyright 2017-2018 ccls Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#pragma once
#include "serializer.h"
#include "utils.h"
#include <string>
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(); }
};

View File

@ -26,6 +26,9 @@ limitations under the License.
#include "platform.h" #include "platform.h"
#include "project.h" #include "project.h"
#include "query_utils.h" #include "query_utils.h"
#include "serializers/json.h"
#include <rapidjson/writer.h>
#include <llvm/Support/Threading.h> #include <llvm/Support/Threading.h>
#include <llvm/Support/Timer.h> #include <llvm/Support/Timer.h>
@ -76,18 +79,13 @@ struct Index_Request {
int64_t ts = tick++; int64_t ts = tick++;
}; };
struct Stdout_Request {
MethodType method;
std::string content;
};
MultiQueueWaiter *main_waiter; MultiQueueWaiter *main_waiter;
MultiQueueWaiter *indexer_waiter; MultiQueueWaiter *indexer_waiter;
MultiQueueWaiter *stdout_waiter; MultiQueueWaiter *stdout_waiter;
ThreadedQueue<std::unique_ptr<InMessage>> *on_request; ThreadedQueue<std::unique_ptr<InMessage>> *on_request;
ThreadedQueue<Index_Request> *index_request; ThreadedQueue<Index_Request> *index_request;
ThreadedQueue<IndexUpdate> *on_indexed; ThreadedQueue<IndexUpdate> *on_indexed;
ThreadedQueue<Stdout_Request> *for_stdout; ThreadedQueue<std::string> *for_stdout;
struct InMemoryIndexFile { struct InMemoryIndexFile {
std::string content; std::string content;
@ -299,11 +297,10 @@ bool Indexer_Parse(CompletionManager *completion, WorkingFiles *wfiles,
if (!ok) { if (!ok) {
if (request.id.Valid()) { if (request.id.Valid()) {
Out_Error out; lsResponseError err;
out.id = request.id; err.code = lsErrorCodes::InternalError;
out.error.code = lsErrorCodes::InternalError; err.message = "failed to index " + path_to_index;
out.error.message = "Failed to index " + path_to_index; pipeline::ReplyError(request.id, err);
pipeline::WriteStdout(kMethodType_Unknown, out);
} }
return true; return true;
} }
@ -363,7 +360,7 @@ void Init() {
index_request = new ThreadedQueue<Index_Request>(indexer_waiter); index_request = new ThreadedQueue<Index_Request>(indexer_waiter);
stdout_waiter = new MultiQueueWaiter; stdout_waiter = new MultiQueueWaiter;
for_stdout = new ThreadedQueue<Stdout_Request>(stdout_waiter); for_stdout = new ThreadedQueue<std::string>(stdout_waiter);
} }
void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project, void Indexer_Main(CompletionManager *completion, VFS *vfs, Project *project,
@ -383,8 +380,8 @@ void Main_OnIndexed(DB *db, WorkingFiles *working_files, IndexUpdate *update) {
std::string filename = LowerPathIfInsensitive(f->filename); std::string filename = LowerPathIfInsensitive(f->filename);
if (db->name2file_id.find(filename) == db->name2file_id.end()) if (db->name2file_id.find(filename) == db->name2file_id.end())
continue; continue;
QueryFile *file = &db->files[db->name2file_id[filename]]; QueryFile &file = db->files[db->name2file_id[filename]];
EmitSemanticHighlighting(db, f.get(), file); EmitSemanticHighlight(db, f.get(), file);
} }
return; return;
} }
@ -403,8 +400,9 @@ void Main_OnIndexed(DB *db, WorkingFiles *working_files, IndexUpdate *update) {
// request.path // request.path
wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content wfile->SetIndexContent(g_config->index.onChange ? wfile->buffer_content
: def_u.second); : def_u.second);
EmitSkippedRanges(wfile, def_u.first.skipped_ranges); QueryFile &file = db->files[update->file_id];
EmitSemanticHighlighting(db, wfile, &db->files[update->file_id]); EmitSkippedRanges(wfile, file);
EmitSemanticHighlight(db, wfile, file);
} }
} }
} }
@ -414,21 +412,20 @@ void LaunchStdin() {
set_thread_name("stdin"); set_thread_name("stdin");
while (true) { while (true) {
std::unique_ptr<InMessage> message; std::unique_ptr<InMessage> message;
std::optional<std::string> err = std::optional<std::string> error =
MessageRegistry::instance()->ReadMessageFromStdin(&message); MessageRegistry::instance()->ReadMessageFromStdin(&message);
// Message parsing can fail if we don't recognize the method. // Message parsing can fail if we don't recognize the method.
if (err) { if (error) {
// The message may be partially deserialized. // The message may be partially deserialized.
// Emit an error ResponseMessage if |id| is available. // Emit an error ResponseMessage if |id| is available.
if (message) { if (message) {
lsRequestId id = message->GetRequestId(); lsRequestId id = message->GetRequestId();
if (id.Valid()) { if (id.Valid()) {
Out_Error out; lsResponseError err;
out.id = id; err.code = lsErrorCodes::InvalidParams;
out.error.code = lsErrorCodes::InvalidParams; err.message = std::move(*error);
out.error.message = std::move(*err); ReplyError(id, err);
WriteStdout(kMethodType_Unknown, out);
} }
} }
continue; continue;
@ -453,20 +450,12 @@ void LaunchStdout() {
set_thread_name("stdout"); set_thread_name("stdout");
while (true) { while (true) {
std::vector<Stdout_Request> messages = for_stdout->DequeueAll(); std::vector<std::string> messages = for_stdout->DequeueAll();
if (messages.empty()) { for (auto &s : messages) {
stdout_waiter->Wait(for_stdout); llvm::outs() << "Content-Length: " << s.size() << "\r\n\r\n" << s;
continue; llvm::outs().flush();
}
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
} }
stdout_waiter->Wait(for_stdout);
} }
}) })
.detach(); .detach();
@ -480,20 +469,17 @@ void MainLoop() {
CompletionManager clang_complete( CompletionManager clang_complete(
&project, &working_files, &project, &working_files,
[&](std::string path, std::vector<lsDiagnostic> diagnostics) { [&](std::string path, std::vector<lsDiagnostic> diagnostics) {
Out_TextDocumentPublishDiagnostics out; lsPublishDiagnosticsParams params;
out.params.uri = lsDocumentUri::FromPath(path); params.uri = lsDocumentUri::FromPath(path);
out.params.diagnostics = diagnostics; params.diagnostics = diagnostics;
ccls::pipeline::WriteStdout(kMethodType_TextDocumentPublishDiagnostics, Notify("textDocument/publishDiagnostics", params);
out);
}, },
[](lsRequestId id) { [](lsRequestId id) {
if (id.Valid()) { if (id.Valid()) {
Out_Error out; lsResponseError err;
out.id = id; err.code = lsErrorCodes::InternalError;
out.error.code = lsErrorCodes::InternalError; err.message = "drop older completion request";
out.error.message = "Dropping completion request; a newer request " ReplyError(id, err);
"has come in that will be serviced instead.";
pipeline::WriteStdout(kMethodType_Unknown, out);
} }
}); });
@ -566,14 +552,54 @@ std::optional<std::string> LoadIndexedContent(const std::string &path) {
return ReadContent(GetCachePath(path)); return ReadContent(GetCachePath(path));
} }
void WriteStdout(MethodType method, lsBaseOutMessage &response) { void Notify(const char *method, const std::function<void(Writer &)> &fn) {
std::ostringstream sstream; rapidjson::StringBuffer output;
response.Write(sstream); rapidjson::Writer<rapidjson::StringBuffer> 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; static void Reply(lsRequestId id, const char *key,
out.content = sstream.str(); const std::function<void(Writer &)> &fn) {
out.method = method; rapidjson::StringBuffer output;
for_stdout->PushBack(std::move(out)); rapidjson::Writer<rapidjson::StringBuffer> 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<void(Writer &)> &fn) {
Reply(id, "result", fn);
}
void ReplyError(lsRequestId id, const std::function<void(Writer &)> &fn) {
Reply(id, "error", fn);
} }
} // namespace ccls::pipeline } // namespace ccls::pipeline

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "lsp_diagnostic.h" #include "lsp.h"
#include "method.h"
#include "query.h" #include "query.h"
#include <atomic> #include <atomic>
@ -15,7 +14,6 @@ struct GroupMatch;
struct VFS; struct VFS;
struct Project; struct Project;
struct WorkingFiles; struct WorkingFiles;
struct lsBaseOutMessage;
struct VFS { struct VFS {
struct State { struct State {
@ -52,6 +50,20 @@ void Index(const std::string &path, const std::vector<const char *> &args,
IndexMode mode, lsRequestId id = {}); IndexMode mode, lsRequestId id = {});
std::optional<std::string> LoadIndexedContent(const std::string& path); std::optional<std::string> LoadIndexedContent(const std::string& path);
void WriteStdout(MethodType method, lsBaseOutMessage &response);
void Notify(const char *method, const std::function<void(Writer &)> &fn);
template <typename T> void Notify(const char *method, T &result) {
Notify(method, [&](Writer &w) { Reflect(w, result); });
}
void Reply(lsRequestId id, const std::function<void(Writer &)> &fn);
template <typename T> void Reply(lsRequestId id, T &result) {
Reply(id, [&](Writer &w) { Reflect(w, result); });
}
void ReplyError(lsRequestId id, const std::function<void(Writer &)> &fn);
template <typename T> void ReplyError(lsRequestId id, T &result) {
ReplyError(id, [&](Writer &w) { Reflect(w, result); });
}
} // namespace pipeline } // namespace pipeline
} // namespace ccls } // namespace ccls

View File

@ -17,7 +17,6 @@ limitations under the License.
#include "config.h" #include "config.h"
#include "lsp.h" #include "lsp.h"
#include "method.h"
#include <functional> #include <functional>
#include <mutex> #include <mutex>

View File

@ -32,7 +32,13 @@ using namespace llvm;
bool gTestOutputMode = false; 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(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); }
void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); } void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); }

View File

@ -38,11 +38,10 @@ class StringRef;
enum class SerializeFormat { Binary, Json }; enum class SerializeFormat { Binary, Json };
struct JsonNull {}; struct JsonNull {};
struct mandatory_optional_tag {};
class Reader { class Reader {
public: public:
virtual ~Reader() {} virtual ~Reader();
virtual SerializeFormat Format() const = 0; virtual SerializeFormat Format() const = 0;
virtual bool IsBool() = 0; virtual bool IsBool() = 0;
@ -72,7 +71,7 @@ public:
class Writer { class Writer {
public: public:
virtual ~Writer() {} virtual ~Writer();
virtual SerializeFormat Format() const = 0; virtual SerializeFormat Format() const = 0;
virtual void Null() = 0; virtual void Null() = 0;
@ -97,8 +96,6 @@ struct IndexFile;
#define REFLECT_MEMBER_START() ReflectMemberStart(visitor) #define REFLECT_MEMBER_START() ReflectMemberStart(visitor)
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor); #define REFLECT_MEMBER_END() ReflectMemberEnd(visitor);
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name) #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 REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
#define MAKE_REFLECT_TYPE_PROXY(type_name) \ #define MAKE_REFLECT_TYPE_PROXY(type_name) \
@ -115,8 +112,6 @@ struct IndexFile;
} }
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name); #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, ...) \ #define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \ template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
@ -131,13 +126,6 @@ struct IndexFile;
REFLECT_MEMBER_END(); \ REFLECT_MEMBER_END(); \
} }
#define MAKE_REFLECT_STRUCT_MANDATORY_OPTIONAL(type, ...) \
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
REFLECT_MEMBER_START(); \
MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL, __VA_ARGS__) \
REFLECT_MEMBER_END(); \
}
// clang-format off // clang-format off
// Config has many fields, we need to support at least its number of fields. // 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 #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
@ -268,13 +256,6 @@ void ReflectMember(Writer &visitor, const char *name, Maybe<T> &value) {
} }
} }
template <typename T>
void ReflectMember(Writer &visitor, const char *name, T &value,
mandatory_optional_tag) {
visitor.Key(name);
Reflect(visitor, value);
}
template <typename L, typename R> template <typename L, typename R>
void Reflect(Reader &vis, std::pair<L, R> &v) { void Reflect(Reader &vis, std::pair<L, R> &v) {
vis.Member("L", [&]() { Reflect(vis, v.first); }); vis.Member("L", [&]() { Reflect(vis, v.first); });

View File

@ -46,6 +46,7 @@ class BinaryReader : public Reader {
public: public:
BinaryReader(std::string_view buf) : p_(buf.data()) {} BinaryReader(std::string_view buf) : p_(buf.data()) {}
virtual ~BinaryReader();
SerializeFormat Format() const override { return SerializeFormat::Binary; } SerializeFormat Format() const override { return SerializeFormat::Binary; }
bool IsBool() override { return true; } bool IsBool() override { return true; }
@ -110,6 +111,7 @@ class BinaryWriter : public Writer {
void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); } void VarInt(int64_t n) { VarUInt(uint64_t(n) << 1 ^ n >> 63); }
public: public:
virtual ~BinaryWriter();
SerializeFormat Format() const override { return SerializeFormat::Binary; } SerializeFormat Format() const override { return SerializeFormat::Binary; }
std::string Take() { return std::move(buf_); } std::string Take() { return std::move(buf_); }

View File

@ -26,6 +26,7 @@ class JsonReader : public Reader {
public: public:
JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>> *m) : m_(m) {} JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>> *m) : m_(m) {}
virtual ~JsonReader();
SerializeFormat Format() const override { return SerializeFormat::Json; } SerializeFormat Format() const override { return SerializeFormat::Json; }
rapidjson::GenericValue<rapidjson::UTF8<>> &m() { return *m_; } rapidjson::GenericValue<rapidjson::UTF8<>> &m() { return *m_; }
@ -95,6 +96,7 @@ class JsonWriter : public Writer {
public: public:
JsonWriter(rapidjson::Writer<rapidjson::StringBuffer> *m) : m_(m) {} JsonWriter(rapidjson::Writer<rapidjson::StringBuffer> *m) : m_(m) {}
virtual ~JsonWriter();
SerializeFormat Format() const override { return SerializeFormat::Json; } SerializeFormat Format() const override { return SerializeFormat::Json; }
rapidjson::Writer<rapidjson::StringBuffer> &m() { return *m_; } rapidjson::Writer<rapidjson::StringBuffer> &m() { return *m_; }

View File

@ -315,6 +315,8 @@ void WorkingFile::ComputeLineMapping() {
std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column, std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
bool is_end) { bool is_end) {
if (line == (int)index_lines.size() && !*column)
return buffer_content.size();
if (line < 0 || line >= (int)index_lines.size()) { if (line < 0 || line >= (int)index_lines.size()) {
LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, " LOG_S(WARNING) << "bad index_line (got " << line << ", expected [0, "
<< index_lines.size() << ")) in " << filename; << index_lines.size() << ")) in " << filename;
@ -329,7 +331,6 @@ std::optional<int> WorkingFile::GetBufferPosFromIndexPos(int line, int *column,
std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column, std::optional<int> WorkingFile::GetIndexPosFromBufferPos(int line, int *column,
bool is_end) { bool is_end) {
// See GetBufferLineFromIndexLine for additional comments.
if (line < 0 || line >= (int)buffer_lines.size()) if (line < 0 || line >= (int)buffer_lines.size())
return std::nullopt; return std::nullopt;

View File

@ -15,7 +15,7 @@ limitations under the License.
#pragma once #pragma once
#include "lsp_diagnostic.h" #include "lsp.h"
#include "utils.h" #include "utils.h"
#include <mutex> #include <mutex>