mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-27 10:02:03 +00:00
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:
parent
79352b451c
commit
fc1db06538
@ -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
|
||||
)
|
||||
|
@ -17,8 +17,8 @@ limitations under the License.
|
||||
|
||||
#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"
|
||||
|
@ -21,19 +21,22 @@ limitations under the License.
|
||||
#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;
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "lsp.h"
|
||||
#include "lsp_diagnostic.h"
|
||||
#include "maybe.h"
|
||||
#include "position.h"
|
||||
#include "serializer.h"
|
||||
|
66
src/lsp.cc
66
src/lsp.cc
@ -18,10 +18,45 @@ limitations under the License.
|
||||
#include "log.hh"
|
||||
#include "serializers/json.h"
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
MethodType kMethodType_Exit = "exit";
|
||||
|
||||
void Reflect(Reader &visitor, lsRequestId &value) {
|
||||
if (visitor.IsInt64()) {
|
||||
value.type = lsRequestId::kInt;
|
||||
value.value = int(visitor.GetInt64());
|
||||
} else if (visitor.IsInt()) {
|
||||
value.type = lsRequestId::kInt;
|
||||
value.value = visitor.GetInt();
|
||||
} else if (visitor.IsString()) {
|
||||
value.type = lsRequestId::kString;
|
||||
value.value = atoll(visitor.GetString());
|
||||
} else {
|
||||
value.type = lsRequestId::kNone;
|
||||
value.value = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Reflect(Writer &visitor, lsRequestId &value) {
|
||||
switch (value.type) {
|
||||
case lsRequestId::kNone:
|
||||
visitor.Null();
|
||||
break;
|
||||
case lsRequestId::kInt:
|
||||
visitor.Int(value.value);
|
||||
break;
|
||||
case lsRequestId::kString:
|
||||
auto s = std::to_string(value.value);
|
||||
visitor.String(s.c_str(), s.length());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InMessage::~InMessage() {}
|
||||
|
||||
MessageRegistry *MessageRegistry::instance_ = nullptr;
|
||||
|
||||
lsTextDocumentIdentifier
|
||||
@ -145,29 +180,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);
|
||||
@ -272,9 +284,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
156
src/lsp.h
@ -16,13 +16,42 @@ limitations under the License.
|
||||
#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_;
|
||||
|
||||
@ -53,45 +82,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";
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -317,35 +339,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
|
||||
|
@ -1,115 +0,0 @@
|
||||
/* Copyright 2017-2018 ccls Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lsp.h"
|
||||
|
||||
enum class lsDiagnosticSeverity {
|
||||
// Reports an error.
|
||||
Error = 1,
|
||||
// Reports a warning.
|
||||
Warning = 2,
|
||||
// Reports an information.
|
||||
Information = 3,
|
||||
// Reports a hint.
|
||||
Hint = 4
|
||||
};
|
||||
MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity);
|
||||
|
||||
struct lsDiagnostic {
|
||||
// The range at which the message applies.
|
||||
lsRange range;
|
||||
|
||||
// The diagnostic's severity. Can be omitted. If omitted it is up to the
|
||||
// client to interpret diagnostics as error, warning, info or hint.
|
||||
std::optional<lsDiagnosticSeverity> severity;
|
||||
|
||||
// The diagnostic's code. Can be omitted.
|
||||
int code = 0;
|
||||
|
||||
// A human-readable string describing the source of this
|
||||
// diagnostic, e.g. 'typescript' or 'super lint'.
|
||||
std::string source = "ccls";
|
||||
|
||||
// The diagnostic's message.
|
||||
std::string message;
|
||||
|
||||
// Non-serialized set of fixits.
|
||||
std::vector<lsTextEdit> fixits_;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, source, message);
|
||||
|
||||
enum class lsErrorCodes {
|
||||
// Defined by JSON RPC
|
||||
ParseError = -32700,
|
||||
InvalidRequest = -32600,
|
||||
MethodNotFound = -32601,
|
||||
InvalidParams = -32602,
|
||||
InternalError = -32603,
|
||||
serverErrorStart = -32099,
|
||||
serverErrorEnd = -32000,
|
||||
ServerNotInitialized = -32002,
|
||||
UnknownErrorCode = -32001,
|
||||
|
||||
// Defined by the protocol.
|
||||
RequestCancelled = -32800,
|
||||
};
|
||||
MAKE_REFLECT_TYPE_PROXY(lsErrorCodes);
|
||||
struct Out_Error : public lsOutMessage<Out_Error> {
|
||||
struct lsResponseError {
|
||||
// A number indicating the error type that occurred.
|
||||
lsErrorCodes code;
|
||||
|
||||
// A string providing a short description of the error.
|
||||
std::string message;
|
||||
|
||||
// A Primitive or Structured value that contains additional
|
||||
// information about the error. Can be omitted.
|
||||
// std::optional<D> data;
|
||||
};
|
||||
|
||||
lsRequestId id;
|
||||
|
||||
// The error object in case a request fails.
|
||||
lsResponseError error;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(Out_Error::lsResponseError, code, message);
|
||||
MAKE_REFLECT_STRUCT(Out_Error, jsonrpc, id, error);
|
||||
|
||||
// Diagnostics
|
||||
struct Out_TextDocumentPublishDiagnostics
|
||||
: public lsOutMessage<Out_TextDocumentPublishDiagnostics> {
|
||||
struct Params {
|
||||
// The URI for which diagnostic information is reported.
|
||||
lsDocumentUri uri;
|
||||
|
||||
// An array of diagnostic information items.
|
||||
std::vector<lsDiagnostic> diagnostics;
|
||||
};
|
||||
|
||||
Params params;
|
||||
};
|
||||
template <typename TVisitor>
|
||||
void Reflect(TVisitor &visitor, Out_TextDocumentPublishDiagnostics &value) {
|
||||
std::string method = "textDocument/publishDiagnostics";
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(jsonrpc);
|
||||
REFLECT_MEMBER2("method", method);
|
||||
REFLECT_MEMBER(params);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
MAKE_REFLECT_STRUCT(Out_TextDocumentPublishDiagnostics::Params, uri,
|
||||
diagnostics);
|
11
src/match.cc
11
src/match.cc
@ -30,12 +30,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;
|
||||
}
|
||||
}
|
||||
|
@ -30,23 +30,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))
|
||||
@ -68,7 +81,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,
|
||||
@ -98,46 +110,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;
|
||||
@ -217,8 +223,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;
|
||||
@ -232,7 +238,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.
|
||||
@ -267,13 +273,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);
|
||||
@ -315,6 +319,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);
|
||||
}
|
||||
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#include "lsp.h"
|
||||
#include "method.h"
|
||||
#include "query.h"
|
||||
|
||||
#include <memory>
|
||||
@ -35,30 +34,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:
|
||||
//
|
||||
@ -103,8 +78,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);
|
||||
|
@ -38,7 +38,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 {
|
||||
@ -62,34 +62,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();
|
||||
@ -99,7 +94,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,
|
||||
@ -179,17 +174,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;
|
||||
@ -202,25 +197,22 @@ struct Handler_CclsCall : BaseMessageHandler<In_CclsCall> {
|
||||
return entry;
|
||||
}
|
||||
|
||||
void Run(In_CclsCall *request) override {
|
||||
void Run(In_cclsCall *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsCall out;
|
||||
out.id = request->id;
|
||||
|
||||
std::optional<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,
|
||||
@ -231,24 +223,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
|
||||
|
@ -25,51 +25,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;
|
||||
@ -79,12 +74,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 {
|
||||
@ -93,15 +82,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);
|
||||
|
@ -22,9 +22,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
|
||||
@ -44,39 +45,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);
|
||||
@ -97,7 +91,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;
|
||||
@ -112,7 +106,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;
|
||||
@ -126,8 +120,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));
|
||||
@ -136,13 +130,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;
|
||||
@ -150,25 +143,24 @@ struct Handler_CclsInheritance
|
||||
return entry;
|
||||
}
|
||||
|
||||
void Run(In_CclsInheritance *request) override {
|
||||
void Run(In_cclsInheritance *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsInheritance out;
|
||||
out.id = request->id;
|
||||
|
||||
std::optional<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,
|
||||
@ -178,23 +170,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
|
||||
|
@ -30,7 +30,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 {
|
||||
@ -52,42 +52,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)
|
||||
@ -124,8 +118,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;
|
||||
@ -157,7 +151,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) {
|
||||
@ -187,7 +181,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 =
|
||||
@ -208,7 +202,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 =
|
||||
@ -239,12 +233,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 {};
|
||||
@ -253,7 +247,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) {
|
||||
@ -273,7 +267,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) {
|
||||
@ -287,24 +281,22 @@ struct Handler_CclsMember
|
||||
}
|
||||
}
|
||||
|
||||
void Run(In_CclsMember *request) override {
|
||||
void Run(In_cclsMember *request) override {
|
||||
auto ¶ms = request->params;
|
||||
Out_CclsMember out;
|
||||
out.id = request->id;
|
||||
|
||||
std::optional<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,
|
||||
@ -316,14 +308,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:
|
||||
@ -333,17 +325,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
|
||||
|
@ -21,7 +21,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;
|
||||
@ -100,15 +100,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);
|
||||
|
@ -28,7 +28,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;
|
||||
@ -36,14 +36,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 ¶ms = request->params;
|
||||
// Send index requests for every file.
|
||||
if (params.whitelist.empty() && params.blacklist.empty()) {
|
||||
@ -91,5 +90,5 @@ struct Handler_CclsReload : BaseMessageHandler<In_CclsReload> {
|
||||
}
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_CclsReload);
|
||||
REGISTER_MESSAGE_HANDLER(Handler_cclsReload);
|
||||
} // namespace
|
||||
|
@ -21,7 +21,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
|
||||
@ -30,14 +30,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 ¶ms = request->params;
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
@ -47,8 +47,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;
|
||||
@ -63,14 +62,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
|
||||
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||
#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);
|
||||
|
@ -400,7 +400,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;
|
||||
@ -408,15 +408,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;
|
||||
@ -486,13 +481,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);
|
||||
|
@ -20,24 +20,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);
|
||||
|
@ -21,7 +21,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
|
||||
@ -54,13 +54,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; }
|
||||
@ -71,20 +64,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);
|
||||
|
@ -48,12 +48,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;
|
||||
@ -69,7 +63,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;
|
||||
@ -79,20 +73,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 ¶ms = request->params;
|
||||
Out_TextDocumentCodeLens out;
|
||||
out.id = request->id;
|
||||
std::vector<lsCodeLens> result;
|
||||
std::string path = params.textDocument.uri.GetPath();
|
||||
|
||||
QueryFile *file;
|
||||
@ -107,7 +93,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);
|
||||
@ -178,12 +164,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;
|
||||
};
|
||||
@ -203,12 +189,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: {
|
||||
@ -247,7 +232,7 @@ struct Handler_WorkspaceExecuteCommand
|
||||
default:
|
||||
break;
|
||||
}
|
||||
pipeline::WriteStdout(executeCommand, out);
|
||||
pipeline::Reply(request->id, result);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -66,28 +66,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) {
|
||||
@ -153,11 +146,11 @@ template <typename T> char *tofixedbase64(T input, char *out) {
|
||||
// Pre-filters completion responses before sending to vscode. This results in a
|
||||
// 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>".
|
||||
@ -173,7 +166,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) {
|
||||
@ -497,13 +490,12 @@ struct Handler_TextDocumentCompletion
|
||||
static CompleteConsumerCache<std::vector<lsCompletionItem>> cache;
|
||||
|
||||
const auto ¶ms = request->params;
|
||||
Out_TextDocumentComplete out;
|
||||
out.id = request->id;
|
||||
lsCompletionList result;
|
||||
|
||||
std::string path = params.textDocument.uri.GetPath();
|
||||
WorkingFile *file = working_files->GetFileByFilename(path);
|
||||
if (!file) {
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
pipeline::Reply(request->id, result);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -548,7 +540,7 @@ struct Handler_TextDocumentCompletion
|
||||
}
|
||||
|
||||
if (did_fail_check) {
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
pipeline::Reply(request->id, result);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -561,8 +553,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);
|
||||
@ -571,14 +562,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 =
|
||||
@ -587,13 +578,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;
|
||||
|
@ -26,7 +26,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;
|
||||
};
|
||||
@ -66,9 +66,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;
|
||||
@ -104,19 +102,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;
|
||||
@ -177,12 +174,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);
|
||||
|
@ -27,7 +27,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;
|
||||
};
|
||||
@ -51,7 +51,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;
|
||||
@ -68,19 +68,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 {
|
||||
@ -113,9 +107,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);
|
||||
@ -137,7 +131,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 {
|
||||
|
@ -39,20 +39,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; }
|
||||
@ -63,14 +56,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;
|
||||
@ -90,11 +81,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);
|
||||
|
@ -24,7 +24,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;
|
||||
@ -40,20 +40,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;
|
||||
@ -69,13 +55,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;
|
||||
@ -107,15 +86,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;
|
||||
@ -207,15 +185,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 =
|
||||
@ -227,11 +203,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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -36,13 +36,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());
|
||||
@ -91,20 +84,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;
|
||||
@ -132,7 +122,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;
|
||||
@ -168,7 +158,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;
|
||||
|
@ -70,25 +70,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; }
|
||||
@ -99,33 +92,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);
|
||||
|
@ -1,64 +0,0 @@
|
||||
/* Copyright 2017-2018 ccls Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "message_handler.h"
|
||||
#include "pipeline.hh"
|
||||
#include "query_utils.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "textDocument/implementation";
|
||||
|
||||
struct In_TextDocumentImplementation : public RequestInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
lsTextDocumentPositionParams params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_TextDocumentImplementation, id, params);
|
||||
REGISTER_IN_MESSAGE(In_TextDocumentImplementation);
|
||||
|
||||
struct Handler_TextDocumentImplementation
|
||||
: BaseMessageHandler<In_TextDocumentImplementation> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_TextDocumentImplementation *request) override {
|
||||
QueryFile *file;
|
||||
if (!FindFileOrFail(db, project, request->id,
|
||||
request->params.textDocument.uri.GetPath(), &file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WorkingFile *working_file =
|
||||
working_files->GetFileByFilename(file->def->path);
|
||||
|
||||
Out_LocationList out;
|
||||
out.id = request->id;
|
||||
for (SymbolRef sym :
|
||||
FindSymbolsAtLocation(working_file, file, request->params.position)) {
|
||||
if (sym.kind == SymbolKind::Type) {
|
||||
QueryType &type = db->GetType(sym);
|
||||
out.result = GetLsLocations(db, working_files,
|
||||
GetTypeDeclarations(db, type.derived));
|
||||
break;
|
||||
} else if (sym.kind == SymbolKind::Func) {
|
||||
QueryFunc &func = db->GetFunc(sym);
|
||||
out.result = GetLsLocations(db, working_files,
|
||||
GetFuncDeclarations(db, func.derived));
|
||||
break;
|
||||
}
|
||||
}
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentImplementation);
|
||||
} // namespace
|
@ -24,7 +24,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;
|
||||
@ -60,11 +60,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;
|
||||
}
|
||||
|
||||
@ -86,7 +85,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) {
|
||||
@ -116,7 +115,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.
|
||||
@ -134,16 +133,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);
|
||||
|
@ -63,7 +63,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.
|
||||
@ -84,12 +84,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 {
|
||||
@ -97,25 +91,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);
|
||||
|
@ -55,20 +55,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;
|
||||
@ -199,10 +192,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;
|
||||
|
@ -21,7 +21,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;
|
||||
};
|
||||
@ -40,18 +40,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)) {
|
||||
@ -75,7 +74,7 @@ struct Handler_TextDocumentTypeDefinition
|
||||
}
|
||||
}
|
||||
|
||||
pipeline::WriteStdout(kMethodType, out);
|
||||
pipeline::Reply(request->id, result);
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_TextDocumentTypeDefinition);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -1,79 +0,0 @@
|
||||
/* Copyright 2017-2018 ccls Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "clang_complete.hh"
|
||||
#include "message_handler.h"
|
||||
#include "pipeline.hh"
|
||||
#include "project.h"
|
||||
#include "working_files.h"
|
||||
using namespace ccls;
|
||||
|
||||
namespace {
|
||||
MethodType kMethodType = "workspace/didChangeWatchedFiles";
|
||||
|
||||
enum class lsFileChangeType {
|
||||
Created = 1,
|
||||
Changed = 2,
|
||||
Deleted = 3,
|
||||
};
|
||||
MAKE_REFLECT_TYPE_PROXY(lsFileChangeType);
|
||||
|
||||
struct lsFileEvent {
|
||||
lsDocumentUri uri;
|
||||
lsFileChangeType type;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsFileEvent, uri, type);
|
||||
|
||||
struct lsDidChangeWatchedFilesParams {
|
||||
std::vector<lsFileEvent> changes;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(lsDidChangeWatchedFilesParams, changes);
|
||||
|
||||
struct In_WorkspaceDidChangeWatchedFiles : public NotificationInMessage {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
lsDidChangeWatchedFilesParams params;
|
||||
};
|
||||
MAKE_REFLECT_STRUCT(In_WorkspaceDidChangeWatchedFiles, params);
|
||||
REGISTER_IN_MESSAGE(In_WorkspaceDidChangeWatchedFiles);
|
||||
|
||||
struct Handler_WorkspaceDidChangeWatchedFiles
|
||||
: BaseMessageHandler<In_WorkspaceDidChangeWatchedFiles> {
|
||||
MethodType GetMethodType() const override { return kMethodType; }
|
||||
void Run(In_WorkspaceDidChangeWatchedFiles *request) override {
|
||||
for (lsFileEvent &event : request->params.changes) {
|
||||
std::string path = event.uri.GetPath();
|
||||
IndexMode mode = working_files->GetFileByFilename(path)
|
||||
? IndexMode::Normal
|
||||
: IndexMode::NonInteractive;
|
||||
switch (event.type) {
|
||||
case lsFileChangeType::Created:
|
||||
case lsFileChangeType::Changed: {
|
||||
pipeline::Index(path, {}, mode);
|
||||
if (mode == IndexMode::Normal)
|
||||
clang_complete->NotifySave(path);
|
||||
else
|
||||
clang_complete->OnClose(path);
|
||||
break;
|
||||
}
|
||||
case lsFileChangeType::Deleted:
|
||||
pipeline::Index(path, {}, mode);
|
||||
clang_complete->OnClose(path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
REGISTER_MESSAGE_HANDLER(Handler_WorkspaceDidChangeWatchedFiles);
|
||||
} // namespace
|
@ -54,7 +54,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;
|
||||
@ -65,20 +65,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}
|
||||
@ -128,20 +119,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);
|
||||
|
@ -1,55 +0,0 @@
|
||||
/* Copyright 2017-2018 ccls Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#include "method.h"
|
||||
|
||||
MethodType kMethodType_Unknown = "$unknown";
|
||||
MethodType kMethodType_Exit = "exit";
|
||||
MethodType kMethodType_TextDocumentPublishDiagnostics =
|
||||
"textDocument/publishDiagnostics";
|
||||
MethodType kMethodType_CclsPublishSkippedRanges = "$ccls/publishSkippedRanges";
|
||||
MethodType kMethodType_CclsPublishSemanticHighlighting =
|
||||
"$ccls/publishSemanticHighlighting";
|
||||
|
||||
void Reflect(Reader &visitor, lsRequestId &value) {
|
||||
if (visitor.IsInt64()) {
|
||||
value.type = lsRequestId::kInt;
|
||||
value.value = int(visitor.GetInt64());
|
||||
} else if (visitor.IsInt()) {
|
||||
value.type = lsRequestId::kInt;
|
||||
value.value = visitor.GetInt();
|
||||
} else if (visitor.IsString()) {
|
||||
value.type = lsRequestId::kString;
|
||||
value.value = atoll(visitor.GetString());
|
||||
} else {
|
||||
value.type = lsRequestId::kNone;
|
||||
value.value = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void Reflect(Writer &visitor, lsRequestId &value) {
|
||||
switch (value.type) {
|
||||
case lsRequestId::kNone:
|
||||
visitor.Null();
|
||||
break;
|
||||
case lsRequestId::kInt:
|
||||
visitor.Int(value.value);
|
||||
break;
|
||||
case lsRequestId::kString:
|
||||
auto s = std::to_string(value.value);
|
||||
visitor.String(s.c_str(), s.length());
|
||||
break;
|
||||
}
|
||||
}
|
59
src/method.h
59
src/method.h
@ -1,59 +0,0 @@
|
||||
/* Copyright 2017-2018 ccls Authors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
==============================================================================*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "serializer.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using MethodType = const char *;
|
||||
extern MethodType kMethodType_Unknown;
|
||||
extern MethodType kMethodType_Exit;
|
||||
extern MethodType kMethodType_TextDocumentPublishDiagnostics;
|
||||
extern MethodType kMethodType_CclsPublishSkippedRanges;
|
||||
extern MethodType kMethodType_CclsPublishSemanticHighlighting;
|
||||
|
||||
struct lsRequestId {
|
||||
// The client can send the request id as an int or a string. We should output
|
||||
// the same format we received.
|
||||
enum Type { kNone, kInt, kString };
|
||||
Type type = kNone;
|
||||
|
||||
int value = -1;
|
||||
|
||||
bool Valid() const { return type != kNone; }
|
||||
};
|
||||
void Reflect(Reader &visitor, lsRequestId &value);
|
||||
void Reflect(Writer &visitor, lsRequestId &value);
|
||||
|
||||
struct InMessage {
|
||||
virtual ~InMessage() = default;
|
||||
|
||||
virtual MethodType GetMethodType() const = 0;
|
||||
virtual lsRequestId GetRequestId() const = 0;
|
||||
};
|
||||
|
||||
struct RequestInMessage : public InMessage {
|
||||
// number or string, actually no null
|
||||
lsRequestId id;
|
||||
lsRequestId GetRequestId() const override { return id; }
|
||||
};
|
||||
|
||||
// NotificationInMessage does not have |id|.
|
||||
struct NotificationInMessage : public InMessage {
|
||||
lsRequestId GetRequestId() const override { return lsRequestId(); }
|
||||
};
|
134
src/pipeline.cc
134
src/pipeline.cc
@ -26,6 +26,9 @@ limitations under the License.
|
||||
#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>
|
||||
@ -76,18 +79,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;
|
||||
@ -299,11 +297,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;
|
||||
}
|
||||
@ -363,7 +360,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,
|
||||
@ -383,8 +380,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;
|
||||
}
|
||||
@ -403,8 +400,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -414,21 +412,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;
|
||||
@ -453,20 +450,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();
|
||||
@ -480,20 +469,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);
|
||||
}
|
||||
});
|
||||
|
||||
@ -566,14 +552,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
|
||||
|
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "lsp_diagnostic.h"
|
||||
#include "method.h"
|
||||
#include "lsp.h"
|
||||
#include "query.h"
|
||||
|
||||
#include <atomic>
|
||||
@ -15,7 +14,6 @@ struct GroupMatch;
|
||||
struct VFS;
|
||||
struct Project;
|
||||
struct WorkingFiles;
|
||||
struct lsBaseOutMessage;
|
||||
|
||||
struct VFS {
|
||||
struct State {
|
||||
@ -52,6 +50,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
|
||||
|
@ -17,7 +17,6 @@ limitations under the License.
|
||||
|
||||
#include "config.h"
|
||||
#include "lsp.h"
|
||||
#include "method.h"
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
@ -32,7 +32,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); }
|
||||
|
@ -38,11 +38,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;
|
||||
@ -72,7 +71,7 @@ public:
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual ~Writer() {}
|
||||
virtual ~Writer();
|
||||
virtual SerializeFormat Format() const = 0;
|
||||
|
||||
virtual void Null() = 0;
|
||||
@ -97,8 +96,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) \
|
||||
@ -115,8 +112,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) { \
|
||||
@ -131,13 +126,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
|
||||
@ -268,13 +256,6 @@ void ReflectMember(Writer &visitor, const char *name, Maybe<T> &value) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ReflectMember(Writer &visitor, const char *name, T &value,
|
||||
mandatory_optional_tag) {
|
||||
visitor.Key(name);
|
||||
Reflect(visitor, value);
|
||||
}
|
||||
|
||||
template <typename L, typename R>
|
||||
void Reflect(Reader &vis, std::pair<L, R> &v) {
|
||||
vis.Member("L", [&]() { Reflect(vis, v.first); });
|
||||
|
@ -46,6 +46,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; }
|
||||
@ -110,6 +111,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_); }
|
||||
|
||||
|
@ -26,6 +26,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_; }
|
||||
|
||||
@ -95,6 +96,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_; }
|
||||
|
||||
|
@ -315,6 +315,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;
|
||||
@ -329,7 +331,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;
|
||||
|
||||
|
@ -15,7 +15,7 @@ limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "lsp_diagnostic.h"
|
||||
#include "lsp.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <mutex>
|
||||
|
Loading…
Reference in New Issue
Block a user