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 4a1eea75db
commit bc4dc6720b
48 changed files with 716 additions and 1097 deletions

View File

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

View File

@ -5,8 +5,8 @@
#include "clang_tu.hh"
#include "lru_cache.h"
#include "lsp.h"
#include "lsp_completion.h"
#include "lsp_diagnostic.h"
#include "project.h"
#include "threaded_queue.h"
#include "working_files.h"

View File

@ -9,19 +9,22 @@
#include <queue>
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;
for (auto &entry : root.children)
for (auto &entry : root->children)
q.push(&entry);
while (q.size()) {
auto *entry = q.front();
q.pop();
if (entry->location.uri.raw_uri.size())
out.result.push_back({entry->location});
ret.push_back({entry->location});
for (auto &entry1 : entry->children)
q.push(&entry1);
}
std::sort(out.result.begin(), out.result.end());
out.result.erase(std::unique(out.result.begin(), out.result.end()),
out.result.end());
std::sort(ret.begin(), ret.end());
ret.erase(std::unique(ret.begin(), ret.end()), ret.end());
return ret;
}

View File

@ -4,7 +4,6 @@
#pragma once
#include "lsp.h"
#include "lsp_diagnostic.h"
#include "maybe.h"
#include "position.h"
#include "serializer.h"

View File

@ -6,11 +6,46 @@
#include "log.hh"
#include "serializers/json.h"
#include <rapidjson/writer.h>
#include <rapidjson/document.h>
#include <algorithm>
#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;
lsTextDocumentIdentifier
@ -134,29 +169,6 @@ MessageRegistry *MessageRegistry::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 result;
result.SetPath(path);
@ -261,9 +273,3 @@ void Reflect(Writer &visitor, lsMarkedString &value) {
Reflect(visitor, value.value);
}
}
std::string Out_ShowLogMessage::method() {
if (display_type == DisplayType::Log)
return "window/logMessage";
return "window/showMessage";
}

156
src/lsp.h
View File

@ -4,13 +4,42 @@
#pragma once
#include "config.h"
#include "method.h"
#include "serializer.h"
#include "utils.h"
#include <iosfwd>
#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) \
static MessageRegistryRegister<type> type##message_handler_instance_;
@ -41,45 +70,38 @@ template <typename T> struct MessageRegistryRegister {
}
};
struct lsBaseOutMessage {
virtual ~lsBaseOutMessage();
virtual void ReflectWriter(Writer &) = 0;
enum class lsErrorCodes {
// Defined by JSON RPC
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
// Send the message to the language client by writing it to stdout.
void Write(std::ostream &out);
};
template <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));
}
// Defined by the protocol.
RequestCancelled = -32800,
};
MAKE_REFLECT_TYPE_PROXY(lsErrorCodes);
struct lsResponseError {
enum class lsErrorCodes : int {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
RequestCancelled = -32800,
};
// A number indicating the error type that occurred.
lsErrorCodes code;
// Short description.
// A string providing a short description of the error.
std::string message;
void Write(Writer &visitor);
// A Primitive or Structured value that contains additional
// information about the error. Can be omitted.
// std::optional<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";
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
@ -305,35 +327,55 @@ MAKE_REFLECT_STRUCT(lsWorkspaceFolder, uri, name);
enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
MAKE_REFLECT_TYPE_PROXY(lsMessageType)
struct Out_ShowLogMessageParams {
enum class lsDiagnosticSeverity {
// Reports an error.
Error = 1,
// Reports a warning.
Warning = 2,
// Reports an information.
Information = 3,
// Reports a hint.
Hint = 4
};
MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity);
struct lsDiagnostic {
// The range at which the message applies.
lsRange range;
// The diagnostic's severity. Can be omitted. If omitted it is up to the
// client to interpret diagnostics as error, warning, info or hint.
std::optional<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;
std::string message;
};
MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, 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);
MAKE_REFLECT_STRUCT(lsShowMessageParams, type, message);
// Used to identify the language at a file level. The ordering is important, as
// a file previously identified as `C`, will be changed to `Cpp` if it

View File

@ -1,103 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "lsp.h"
enum class lsDiagnosticSeverity {
// Reports an error.
Error = 1,
// Reports a warning.
Warning = 2,
// Reports an information.
Information = 3,
// Reports a hint.
Hint = 4
};
MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity);
struct lsDiagnostic {
// The range at which the message applies.
lsRange range;
// The diagnostic's severity. Can be omitted. If omitted it is up to the
// client to interpret diagnostics as error, warning, info or hint.
std::optional<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

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

View File

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

View File

@ -4,7 +4,6 @@
#pragma once
#include "lsp.h"
#include "method.h"
#include "query.h"
#include <memory>
@ -23,30 +22,6 @@ struct DB;
struct WorkingFile;
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:
//
@ -91,8 +66,6 @@ bool FindFileOrFail(DB *db, Project *project, std::optional<lsRequestId> id,
const std::string &absolute_path,
QueryFile **out_query_file, int *out_file_id = nullptr);
void EmitSkippedRanges(WorkingFile *working_file,
const std::vector<Range> &skipped_ranges);
void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file);
void EmitSemanticHighlighting(DB *db, WorkingFile *working_file,
QueryFile *file);
void EmitSemanticHighlight(DB *db, WorkingFile *wfile, QueryFile &file);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -36,12 +36,6 @@ struct Cmd_xref {
};
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>
std::string ToString(T &v) {
rapidjson::StringBuffer output;
@ -57,7 +51,7 @@ struct CommonCodeLensParams {
WorkingFile *wfile;
};
struct In_TextDocumentCodeLens : public RequestInMessage {
struct In_TextDocumentCodeLens : public RequestMessage {
MethodType GetMethodType() const override { return codeLens; }
struct Params {
lsTextDocumentIdentifier textDocument;
@ -67,20 +61,12 @@ MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens::Params, textDocument);
MAKE_REFLECT_STRUCT(In_TextDocumentCodeLens, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentCodeLens);
struct Out_TextDocumentCodeLens
: public lsOutMessage<Out_TextDocumentCodeLens> {
lsRequestId id;
std::vector<lsCodeLens> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentCodeLens, jsonrpc, id, result);
struct Handler_TextDocumentCodeLens
: BaseMessageHandler<In_TextDocumentCodeLens> {
MethodType GetMethodType() const override { return codeLens; }
void Run(In_TextDocumentCodeLens *request) override {
auto &params = request->params;
Out_TextDocumentCodeLens out;
out.id = request->id;
std::vector<lsCodeLens> result;
std::string path = params.textDocument.uri.GetPath();
QueryFile *file;
@ -95,7 +81,7 @@ struct Handler_TextDocumentCodeLens
std::optional<lsRange> range = GetLsRange(wfile, use.range);
if (!range)
return;
lsCodeLens &code_lens = out.result.emplace_back();
lsCodeLens &code_lens = result.emplace_back();
code_lens.range = *range;
code_lens.command = lsCommand();
code_lens.command->command = std::string(ccls_xref);
@ -166,12 +152,12 @@ struct Handler_TextDocumentCodeLens
};
}
pipeline::WriteStdout(codeLens, out);
pipeline::Reply(request->id, result);
}
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentCodeLens);
struct In_WorkspaceExecuteCommand : public RequestInMessage {
struct In_WorkspaceExecuteCommand : public RequestMessage {
MethodType GetMethodType() const override { return executeCommand; }
lsCommand params;
};
@ -191,12 +177,11 @@ struct Handler_WorkspaceExecuteCommand
if (params.command == ccls_xref) {
Cmd_xref cmd;
Reflect(json_reader, cmd);
Out_xref out;
out.id = request->id;
std::vector<lsLocation> result;
auto Map = [&](auto &&uses) {
for (auto &use : uses)
if (auto loc = GetLsLocation(db, working_files, use))
out.result.push_back(std::move(*loc));
result.push_back(std::move(*loc));
};
switch (cmd.kind) {
case SymbolKind::Func: {
@ -235,7 +220,7 @@ struct Handler_WorkspaceExecuteCommand
default:
break;
}
pipeline::WriteStdout(executeCommand, out);
pipeline::Reply(request->id, result);
}
}
};

View File

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

View File

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

View File

@ -15,7 +15,7 @@ MethodType didClose = "textDocument/didClose";
MethodType didOpen = "textDocument/didOpen";
MethodType didSave = "textDocument/didSave";
struct In_TextDocumentDidChange : public NotificationInMessage {
struct In_TextDocumentDidChange : public NotificationMessage {
MethodType GetMethodType() const override { return didChange; }
lsTextDocumentDidChangeParams params;
};
@ -39,7 +39,7 @@ struct Handler_TextDocumentDidChange
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidChange);
struct In_TextDocumentDidClose : public NotificationInMessage {
struct In_TextDocumentDidClose : public NotificationMessage {
MethodType GetMethodType() const override { return didClose; }
struct Params {
lsTextDocumentIdentifier textDocument;
@ -56,19 +56,13 @@ struct Handler_TextDocumentDidClose
void Run(In_TextDocumentDidClose *request) override {
std::string path = request->params.textDocument.uri.GetPath();
// Clear any diagnostics for the file.
Out_TextDocumentPublishDiagnostics out;
out.params.uri = request->params.textDocument.uri;
pipeline::WriteStdout(didClose, out);
// Remove internal state.
working_files->OnClose(request->params.textDocument);
clang_complete->OnClose(path);
}
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidClose);
struct In_TextDocumentDidOpen : public NotificationInMessage {
struct In_TextDocumentDidOpen : public NotificationMessage {
MethodType GetMethodType() const override { return didOpen; }
struct Params {
@ -101,9 +95,9 @@ struct Handler_TextDocumentDidOpen
QueryFile *file = nullptr;
FindFileOrFail(db, project, std::nullopt, path, &file);
if (file && file->def) {
EmitSkippedRanges(working_file, file->def->skipped_ranges);
EmitSemanticHighlighting(db, working_file, file);
if (file) {
EmitSkippedRanges(working_file, *file);
EmitSemanticHighlight(db, working_file, *file);
}
include_complete->AddFile(working_file->filename);
@ -125,7 +119,7 @@ struct Handler_TextDocumentDidOpen
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentDidOpen);
struct In_TextDocumentDidSave : public NotificationInMessage {
struct In_TextDocumentDidSave : public NotificationMessage {
MethodType GetMethodType() const override { return didSave; }
struct Params {

View File

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

View File

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

View File

@ -24,13 +24,6 @@ struct lsFormattingOptions {
};
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>
FormatCode(std::string_view code, std::string_view file, tooling::Range Range) {
StringRef Code(code.data(), code.size()), File(file.data(), file.size());
@ -79,20 +72,17 @@ void Format(WorkingFile *wfile, tooling::Range range, lsRequestId id) {
auto ReplsOrErr =
FormatCode(code, wfile->filename, range);
if (ReplsOrErr) {
Out_TextDocumentFormatting out;
out.id = id;
out.result = ReplacementsToEdits(code, *ReplsOrErr);
pipeline::WriteStdout(formatting, out);
auto result = ReplacementsToEdits(code, *ReplsOrErr);
pipeline::Reply(id, result);
} else {
Out_Error err;
err.id = id;
err.error.code = lsErrorCodes::UnknownErrorCode;
err.error.message = llvm::toString(ReplsOrErr.takeError());
pipeline::WriteStdout(kMethodType_Unknown, err);
lsResponseError err;
err.code = lsErrorCodes::UnknownErrorCode;
err.message = llvm::toString(ReplsOrErr.takeError());
pipeline::ReplyError(id, err);
}
}
struct In_TextDocumentFormatting : public RequestInMessage {
struct In_TextDocumentFormatting : public RequestMessage {
MethodType GetMethodType() const override { return formatting; }
struct Params {
lsTextDocumentIdentifier textDocument;
@ -120,7 +110,7 @@ struct Handler_TextDocumentFormatting
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentFormatting);
struct In_TextDocumentOnTypeFormatting : public RequestInMessage {
struct In_TextDocumentOnTypeFormatting : public RequestMessage {
MethodType GetMethodType() const override { return onTypeFormatting; }
struct Params {
lsTextDocumentIdentifier textDocument;
@ -156,7 +146,7 @@ struct Handler_TextDocumentOnTypeFormatting
};
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentOnTypeFormatting);
struct In_TextDocumentRangeFormatting : public RequestInMessage {
struct In_TextDocumentRangeFormatting : public RequestMessage {
MethodType GetMethodType() const override { return rangeFormatting; }
struct Params {
lsTextDocumentIdentifier textDocument;

View File

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

View File

@ -1,52 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "message_handler.h"
#include "pipeline.hh"
#include "query_utils.h"
using namespace ccls;
namespace {
MethodType kMethodType = "textDocument/implementation";
struct In_TextDocumentImplementation : public RequestInMessage {
MethodType GetMethodType() const override { return kMethodType; }
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params);
REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
struct Handler_TextDocumentImplementation
: BaseMessageHandler<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

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

View File

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

View File

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

View File

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

View File

@ -25,6 +25,7 @@ using namespace ccls;
namespace {
MethodType didChangeConfiguration = "workspace/didChangeConfiguration",
didChangeWatchedFiles = "workspace/didChangeWatchedFiles",
didChangeWorkspaceFolders = "workspace/didChangeWorkspaceFolders";
struct lsDidChangeConfigurationParams {
@ -32,7 +33,7 @@ struct lsDidChangeConfigurationParams {
};
MAKE_REFLECT_STRUCT(lsDidChangeConfigurationParams, placeholder);
struct In_workspaceDidChangeConfiguration : public NotificationInMessage {
struct In_workspaceDidChangeConfiguration : public NotificationMessage {
MethodType GetMethodType() const override { return didChangeConfiguration; }
lsDidChangeConfigurationParams params;
};
@ -53,12 +54,66 @@ struct Handler_workspaceDidChangeConfiguration
};
REGISTER_MESSAGE_HANDLER(Handler_workspaceDidChangeConfiguration);
enum class lsFileChangeType {
Created = 1,
Changed = 2,
Deleted = 3,
};
MAKE_REFLECT_TYPE_PROXY(lsFileChangeType);
struct lsFileEvent {
lsDocumentUri uri;
lsFileChangeType type;
};
MAKE_REFLECT_STRUCT(lsFileEvent, uri, type);
struct lsDidChangeWatchedFilesParams {
std::vector<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 {
std::vector<lsWorkspaceFolder> added, removed;
};
MAKE_REFLECT_STRUCT(lsWorkspaceFoldersChangeEvent, added, removed);
struct In_workspaceDidChangeWorkspaceFolders : public NotificationInMessage {
struct In_workspaceDidChangeWorkspaceFolders : public NotificationMessage {
MethodType GetMethodType() const override {
return didChangeWorkspaceFolders;
}

View File

@ -1,67 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "clang_complete.hh"
#include "message_handler.h"
#include "pipeline.hh"
#include "project.h"
#include "working_files.h"
using namespace ccls;
namespace {
MethodType kMethodType = "workspace/didChangeWatchedFiles";
enum class lsFileChangeType {
Created = 1,
Changed = 2,
Deleted = 3,
};
MAKE_REFLECT_TYPE_PROXY(lsFileChangeType);
struct lsFileEvent {
lsDocumentUri uri;
lsFileChangeType type;
};
MAKE_REFLECT_STRUCT(lsFileEvent, uri, type);
struct lsDidChangeWatchedFilesParams {
std::vector<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

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

View File

@ -1,43 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#include "method.h"
MethodType kMethodType_Unknown = "$unknown";
MethodType kMethodType_Exit = "exit";
MethodType kMethodType_TextDocumentPublishDiagnostics =
"textDocument/publishDiagnostics";
MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges";
MethodType kMethodType_CclsPublishSemanticHighlighting =
"$ccls/publishSemanticHighlighting";
void Reflect(Reader &visitor, lsRequestId &value) {
if (visitor.IsInt64()) {
value.type = lsRequestId::kInt;
value.value = int(visitor.GetInt64());
} else if (visitor.IsInt()) {
value.type = lsRequestId::kInt;
value.value = visitor.GetInt();
} else if (visitor.IsString()) {
value.type = lsRequestId::kString;
value.value = atoll(visitor.GetString());
} else {
value.type = lsRequestId::kNone;
value.value = -1;
}
}
void Reflect(Writer &visitor, lsRequestId &value) {
switch (value.type) {
case lsRequestId::kNone:
visitor.Null();
break;
case lsRequestId::kInt:
visitor.Int(value.value);
break;
case lsRequestId::kString:
auto s = std::to_string(value.value);
visitor.String(s.c_str(), s.length());
break;
}
}

View File

@ -1,47 +0,0 @@
// Copyright 2017-2018 ccls Authors
// SPDX-License-Identifier: Apache-2.0
#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

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

View File

@ -3,8 +3,7 @@
#pragma once
#include "lsp_diagnostic.h"
#include "method.h"
#include "lsp.h"
#include "query.h"
#include <atomic>
@ -18,7 +17,6 @@ struct GroupMatch;
struct VFS;
struct Project;
struct WorkingFiles;
struct lsBaseOutMessage;
struct VFS {
struct State {
@ -55,6 +53,20 @@ void Index(const std::string &path, const std::vector<const char *> &args,
IndexMode mode, lsRequestId id = {});
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 ccls

View File

@ -5,7 +5,6 @@
#include "config.h"
#include "lsp.h"
#include "method.h"
#include <functional>
#include <mutex>

View File

@ -20,7 +20,13 @@ using namespace llvm;
bool gTestOutputMode = false;
//// Elementary types
Reader::~Reader() {}
BinaryReader::~BinaryReader() {}
JsonReader::~JsonReader() {}
Writer::~Writer() {}
BinaryWriter::~BinaryWriter() {}
JsonWriter::~JsonWriter() {}
void Reflect(Reader &visitor, uint8_t &value) { value = visitor.GetUInt8(); }
void Reflect(Writer &visitor, uint8_t &value) { visitor.UInt8(value); }

View File

@ -26,11 +26,10 @@ class StringRef;
enum class SerializeFormat { Binary, Json };
struct JsonNull {};
struct mandatory_optional_tag {};
class Reader {
public:
virtual ~Reader() {}
virtual ~Reader();
virtual SerializeFormat Format() const = 0;
virtual bool IsBool() = 0;
@ -60,7 +59,7 @@ public:
class Writer {
public:
virtual ~Writer() {}
virtual ~Writer();
virtual SerializeFormat Format() const = 0;
virtual void Null() = 0;
@ -85,8 +84,6 @@ struct IndexFile;
#define REFLECT_MEMBER_START() ReflectMemberStart(visitor)
#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor);
#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name)
#define REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \
ReflectMember(visitor, #name, value.name, mandatory_optional_tag{})
#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value)
#define MAKE_REFLECT_TYPE_PROXY(type_name) \
@ -103,8 +100,6 @@ struct IndexFile;
}
#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name);
#define _MAPPABLE_REFLECT_MEMBER_MANDATORY_OPTIONAL(name) \
REFLECT_MEMBER_MANDATORY_OPTIONAL(name);
#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \
template <typename TVisitor> void Reflect(TVisitor &visitor, type &value) { \
@ -119,13 +114,6 @@ struct IndexFile;
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
// Config has many fields, we need to support at least its number of fields.
#define NUM_VA_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,N,...) N
@ -256,13 +244,6 @@ void ReflectMember(Writer &visitor, const char *name, Maybe<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>
void Reflect(Reader &vis, std::pair<L, R> &v) {
vis.Member("L", [&]() { Reflect(vis, v.first); });

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
#pragma once
#include "lsp_diagnostic.h"
#include "lsp.h"
#include "utils.h"
#include <mutex>