mirror of
https://github.com/MaskRay/ccls.git
synced 2025-02-20 07:30:50 +00:00
wip
This commit is contained in:
parent
cc4d49794d
commit
fdd798f995
260
command_line.cc
260
command_line.cc
@ -134,38 +134,44 @@ std::unique_ptr<InMessage> ParseMessage() {
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct BaseIpcMessage : public IpcMessage {
|
||||
BaseIpcMessage() : IpcMessage(T::kIpcId) {}
|
||||
|
||||
// IpcMessage:
|
||||
void Serialize(Writer& writer) override {
|
||||
T& value = *static_cast<T*>(this);
|
||||
Reflect(writer, value);
|
||||
}
|
||||
void Deserialize(Reader& reader) override {
|
||||
T& value = *static_cast<T*>(this);
|
||||
Reflect(reader, value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct IpcMessage_Quit : public BaseIpcMessage<IpcMessage_Quit> {
|
||||
static IpcMessageId kId;
|
||||
static constexpr IpcId kIpcId = IpcId::Quit;
|
||||
};
|
||||
IpcMessageId IpcMessage_Quit::kId = "Quit";
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_Quit& value) {}
|
||||
|
||||
|
||||
struct IpcMessage_IsAlive : public BaseIpcMessage<IpcMessage_IsAlive> {
|
||||
static IpcMessageId kId;
|
||||
static constexpr IpcId kIpcId = IpcId::IsAlive;
|
||||
};
|
||||
IpcMessageId IpcMessage_IsAlive::kId = "IsAlive";
|
||||
|
||||
|
||||
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_IsAlive& value) {}
|
||||
|
||||
|
||||
struct IpcMessage_OpenProject : public BaseIpcMessage<IpcMessage_OpenProject> {
|
||||
static IpcMessageId kId;
|
||||
|
||||
static constexpr IpcId kIpcId = IpcId::OpenProject;
|
||||
std::string project_path;
|
||||
|
||||
// BaseIpcMessage:
|
||||
void Serialize(Writer& writer) override {
|
||||
writer.String(project_path.c_str(), project_path.size());
|
||||
}
|
||||
void Deserialize(Reader& reader) override {
|
||||
project_path = reader.GetString();
|
||||
}
|
||||
};
|
||||
IpcMessageId IpcMessage_OpenProject::kId = "OpenProject";
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_OpenProject& value) {
|
||||
Reflect(visitor, value.project_path);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -173,108 +179,72 @@ IpcMessageId IpcMessage_OpenProject::kId = "OpenProject";
|
||||
|
||||
|
||||
|
||||
struct IpcMessage_LanguageServerRequest : public BaseIpcMessage<IpcMessage_LanguageServerRequest> {
|
||||
static constexpr IpcId kIpcId = IpcId::LanguageServerRequest;
|
||||
// TODO: provide a way to get the request state.
|
||||
lsMethodId method_id;
|
||||
};
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_LanguageServerRequest& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(method_id);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
struct IpcMessage_DocumentSymbolsRequest : public BaseIpcMessage<IpcMessage_DocumentSymbolsRequest> {
|
||||
RequestId id;
|
||||
static constexpr IpcId kIpcId = IpcId::DocumentSymbolsRequest;
|
||||
RequestId request_id;
|
||||
std::string document;
|
||||
|
||||
// BaseIpcMessage:
|
||||
static IpcMessageId kId;
|
||||
void Serialize(Writer& visitor) override {
|
||||
// TODO: dedup
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(document);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
void Deserialize(Reader& visitor) override {
|
||||
// TODO: dedup
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(document);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
};
|
||||
IpcMessageId IpcMessage_DocumentSymbolsRequest::kId = "IpcMessage_DocumentSymbolsRequest";
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsRequest& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(request_id);
|
||||
REFLECT_MEMBER(document);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
struct IpcMessage_DocumentSymbolsResponse : public BaseIpcMessage<IpcMessage_DocumentSymbolsResponse> {
|
||||
RequestId id;
|
||||
static constexpr IpcId kIpcId = IpcId::DocumentSymbolsResponse;
|
||||
RequestId request_id;
|
||||
std::vector<lsSymbolInformation> symbols;
|
||||
|
||||
// BaseIpcMessage:
|
||||
static IpcMessageId kId;
|
||||
void Serialize(Writer& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
void Deserialize(Reader& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
};
|
||||
IpcMessageId IpcMessage_DocumentSymbolsResponse::kId = "IpcMessage_DocumentSymbolsResponse";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_DocumentSymbolsResponse& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(request_id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
struct IpcMessage_WorkspaceSymbolsRequest : public BaseIpcMessage<IpcMessage_WorkspaceSymbolsRequest> {
|
||||
RequestId id;
|
||||
static constexpr IpcId kIpcId = IpcId::WorkspaceSymbolsRequest;
|
||||
RequestId request_id;
|
||||
std::string query;
|
||||
|
||||
// BaseIpcMessage:
|
||||
static IpcMessageId kId;
|
||||
void Serialize(Writer& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(query);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
void Deserialize(Reader& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(query);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
};
|
||||
IpcMessageId IpcMessage_WorkspaceSymbolsRequest::kId = "IpcMessage_WorkspaceSymbolsRequest";
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsRequest& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(request_id);
|
||||
REFLECT_MEMBER(query);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
struct IpcMessage_WorkspaceSymbolsResponse : public BaseIpcMessage<IpcMessage_WorkspaceSymbolsResponse> {
|
||||
RequestId id;
|
||||
static constexpr IpcId kIpcId = IpcId::WorkspaceSymbolsResponse;
|
||||
RequestId request_id;
|
||||
std::vector<lsSymbolInformation> symbols;
|
||||
|
||||
// BaseIpcMessage:
|
||||
static IpcMessageId kId;
|
||||
void Serialize(Writer& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
void Deserialize(Reader& visitor) override {
|
||||
auto& value = *this;
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
};
|
||||
IpcMessageId IpcMessage_WorkspaceSymbolsResponse::kId = "IpcMessage_WorkspaceSymbolsResponse";
|
||||
|
||||
|
||||
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IpcMessage_WorkspaceSymbolsResponse& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER(request_id);
|
||||
REFLECT_MEMBER(symbols);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -301,21 +271,23 @@ IpcMessageId IpcMessage_WorkspaceSymbolsResponse::kId = "IpcMessage_WorkspaceSym
|
||||
|
||||
|
||||
void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) {
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> messages = ipc->TakeMessages();
|
||||
std::vector<std::unique_ptr<IpcMessage>> messages = ipc->TakeMessages();
|
||||
|
||||
for (auto& message : messages) {
|
||||
std::cerr << "Processing message " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
|
||||
std::cerr << "Processing message " << static_cast<int>(message->ipc_id) << std::endl;
|
||||
|
||||
if (IpcMessage_Quit::kId == message->runtime_id()) {
|
||||
switch (message->ipc_id) {
|
||||
case IpcId::Quit: {
|
||||
break;
|
||||
}
|
||||
|
||||
else if (IpcMessage_IsAlive::kId == message->runtime_id()) {
|
||||
case IpcId::IsAlive: {
|
||||
IpcMessage_IsAlive response;
|
||||
ipc->SendToClient(0, &response); // todo: make non-blocking
|
||||
break;
|
||||
}
|
||||
|
||||
else if (IpcMessage_OpenProject::kId == message->runtime_id()) {
|
||||
case IpcId::OpenProject: {
|
||||
IpcMessage_OpenProject* msg = static_cast<IpcMessage_OpenProject*>(message.get());
|
||||
std::string path = msg->project_path;
|
||||
|
||||
@ -330,14 +302,14 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) {
|
||||
db->ApplyIndexUpdate(&update);
|
||||
}
|
||||
std::cerr << "Done" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
else if (IpcMessage_DocumentSymbolsRequest::kId == message->runtime_id()) {
|
||||
case IpcId::DocumentSymbolsRequest: {
|
||||
auto msg = static_cast<IpcMessage_DocumentSymbolsRequest*>(message.get());
|
||||
|
||||
IpcMessage_DocumentSymbolsResponse response;
|
||||
response.id = msg->id;
|
||||
response.request_id = msg->request_id;
|
||||
|
||||
std::cerr << "Wanted file " << msg->document << std::endl;
|
||||
for (auto& file : db->files) {
|
||||
@ -355,7 +327,7 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) {
|
||||
lsSymbolInformation info;
|
||||
info.location.range.start.line = ref.loc.line - 1; // TODO: cleanup indexer to negate by 1.
|
||||
info.location.range.start.character = ref.loc.column - 1; // TODO: cleanup indexer to negate by 1.
|
||||
// TODO: store range information.
|
||||
// TODO: store range information.
|
||||
info.location.range.end.line = info.location.range.start.line;
|
||||
info.location.range.end.character = info.location.range.start.character;
|
||||
|
||||
@ -405,13 +377,15 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) {
|
||||
|
||||
|
||||
ipc->SendToClient(0, &response);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
else if (IpcMessage_WorkspaceSymbolsRequest::kId == message->runtime_id()) {
|
||||
case IpcId::WorkspaceSymbolsRequest: {
|
||||
auto msg = static_cast<IpcMessage_WorkspaceSymbolsRequest*>(message.get());
|
||||
|
||||
IpcMessage_WorkspaceSymbolsResponse response;
|
||||
response.id = msg->id;
|
||||
response.request_id = msg->request_id;
|
||||
|
||||
std::cerr << "- Considering " << db->qualified_names.size() << " candidates " << std::endl;
|
||||
|
||||
@ -493,12 +467,14 @@ void QueryDbMainLoop(IpcServer* ipc, QueryableDatabase* db) {
|
||||
|
||||
|
||||
ipc->SendToClient(0, &response);
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
std::cerr << "Unhandled IPC message with kind " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
|
||||
default: {
|
||||
std::cerr << "Unhandled IPC message with kind " << static_cast<int>(message->ipc_id) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,7 +551,7 @@ void LanguageServerStdinLoop(IpcClient* ipc) {
|
||||
auto request = static_cast<In_DocumentSymbolRequest*>(message.get());
|
||||
|
||||
IpcMessage_DocumentSymbolsRequest ipc_request;
|
||||
ipc_request.id = request->id.value();
|
||||
ipc_request.request_id = request->id.value();
|
||||
ipc_request.document = request->params.textDocument.uri.GetPath();
|
||||
std::cerr << "Request textDocument=" << ipc_request.document << std::endl;
|
||||
ipc->SendToServer(&ipc_request);
|
||||
@ -586,7 +562,7 @@ void LanguageServerStdinLoop(IpcClient* ipc) {
|
||||
{
|
||||
auto request = static_cast<In_WorkspaceSymbolRequest*>(message.get());
|
||||
IpcMessage_WorkspaceSymbolsRequest ipc_request;
|
||||
ipc_request.id = request->id.value();
|
||||
ipc_request.request_id = request->id.value();
|
||||
ipc_request.query = request->params.query;
|
||||
std::cerr << "Request query=" << ipc_request.query << std::endl;
|
||||
ipc->SendToServer(&ipc_request);
|
||||
@ -597,37 +573,41 @@ void LanguageServerStdinLoop(IpcClient* ipc) {
|
||||
}
|
||||
|
||||
void LanguageServerMainLoop(IpcClient* ipc) {
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> messages = ipc->TakeMessages();
|
||||
std::vector<std::unique_ptr<IpcMessage>> messages = ipc->TakeMessages();
|
||||
for (auto& message : messages) {
|
||||
if (IpcMessage_Quit::kId == message->runtime_id()) {
|
||||
switch (message->ipc_id) {
|
||||
case IpcId::Quit: {
|
||||
exit(0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
else if (IpcMessage_DocumentSymbolsResponse::kId == message->runtime_id()) {
|
||||
case IpcId::DocumentSymbolsResponse: {
|
||||
auto msg = static_cast<IpcMessage_DocumentSymbolsResponse*>(message.get());
|
||||
|
||||
auto response = Out_DocumentSymbolResponse();
|
||||
response.id = msg->id;
|
||||
response.id = msg->request_id;
|
||||
response.result = msg->symbols;
|
||||
response.Send();
|
||||
std::cerr << "Send symbol response to client (" << response.result.size() << " symbols)" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (IpcMessage_WorkspaceSymbolsResponse::kId == message->runtime_id()) {
|
||||
case IpcId::WorkspaceSymbolsResponse: {
|
||||
auto msg = static_cast<IpcMessage_WorkspaceSymbolsResponse*>(message.get());
|
||||
|
||||
auto response = Out_WorkspaceSymbolResponse();
|
||||
response.id = msg->id;
|
||||
response.id = msg->request_id;
|
||||
response.result = msg->symbols;
|
||||
response.Send();
|
||||
std::cerr << "Send symbol response to client (" << response.result.size() << " symbols)" << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
std::cerr << "Unhandled IPC message with kind " << message->runtime_id() << " (hash " << message->hashed_runtime_id() << ")" << std::endl;
|
||||
default: {
|
||||
std::cerr << "Unhandled IPC message with kind " << static_cast<int>(message->ipc_id) << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -645,10 +625,10 @@ void LanguageServerMain(std::string process_name) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(20));
|
||||
|
||||
// Check if we got an IsAlive message back.
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> messages = client_ipc.TakeMessages();
|
||||
std::vector<std::unique_ptr<IpcMessage>> messages = client_ipc.TakeMessages();
|
||||
bool has_server = false;
|
||||
for (auto& message : messages) {
|
||||
if (message->runtime_id() == IpcMessage_IsAlive::kId) {
|
||||
if (IpcId::IsAlive == message->ipc_id) {
|
||||
has_server = true;
|
||||
break;
|
||||
}
|
||||
@ -668,13 +648,13 @@ void LanguageServerMain(std::string process_name) {
|
||||
/*stderr*/[](const char* bytes, size_t n) {
|
||||
for (int i = 0; i < n; ++i)
|
||||
std::cerr << bytes[i];
|
||||
},
|
||||
},
|
||||
/*open_stdin*/false);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
// Pass empty process name so we only try to start the querydb once.
|
||||
LanguageServerMain("");
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// for debugging attach
|
||||
@ -767,16 +747,14 @@ int main(int argc, char** argv) {
|
||||
_setmode(_fileno(stdin), O_BINARY);
|
||||
#endif
|
||||
|
||||
IpcRegistry::instance()->Register<IpcMessage_Quit>();
|
||||
IpcRegistry::instance()->Register<IpcMessage_Quit>(IpcId::Quit);
|
||||
IpcRegistry::instance()->Register<IpcMessage_IsAlive>(IpcId::IsAlive);
|
||||
IpcRegistry::instance()->Register<IpcMessage_OpenProject>(IpcId::OpenProject);
|
||||
|
||||
IpcRegistry::instance()->Register<IpcMessage_IsAlive>();
|
||||
IpcRegistry::instance()->Register<IpcMessage_OpenProject>();
|
||||
|
||||
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsRequest>();
|
||||
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsResponse>();
|
||||
|
||||
IpcRegistry::instance()->Register<IpcMessage_WorkspaceSymbolsRequest>();
|
||||
IpcRegistry::instance()->Register<IpcMessage_WorkspaceSymbolsResponse>();
|
||||
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsRequest>(IpcId::DocumentSymbolsRequest);
|
||||
IpcRegistry::instance()->Register<IpcMessage_DocumentSymbolsResponse>(IpcId::DocumentSymbolsResponse);
|
||||
IpcRegistry::instance()->Register<IpcMessage_WorkspaceSymbolsRequest>(IpcId::WorkspaceSymbolsRequest);
|
||||
IpcRegistry::instance()->Register<IpcMessage_WorkspaceSymbolsResponse>(IpcId::WorkspaceSymbolsResponse);
|
||||
|
||||
MessageRegistry::instance()->Register<In_CancelRequest>();
|
||||
MessageRegistry::instance()->Register<In_InitializeRequest>();
|
||||
|
58
ipc.cc
58
ipc.cc
@ -1,15 +1,19 @@
|
||||
#include "ipc.h"
|
||||
|
||||
|
||||
|
||||
#include "serializer.h"
|
||||
|
||||
namespace {
|
||||
struct JsonMessage {
|
||||
int message_id;
|
||||
IpcId ipc_id;
|
||||
size_t payload_size;
|
||||
|
||||
const char* payload();
|
||||
void SetPayload(size_t payload_size, const char* payload);
|
||||
const char* payload() {
|
||||
return reinterpret_cast<const char*>(this) + sizeof(JsonMessage);
|
||||
}
|
||||
void SetPayload(size_t payload_size, const char* payload) {
|
||||
char* payload_dest = reinterpret_cast<char*>(this) + sizeof(JsonMessage);
|
||||
this->payload_size = payload_size;
|
||||
memcpy(payload_dest, payload, payload_size);
|
||||
}
|
||||
};
|
||||
|
||||
JsonMessage* get_free_message(IpcDirectionalChannel* channel) {
|
||||
@ -34,24 +38,10 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
const char* JsonMessage::payload() {
|
||||
return reinterpret_cast<const char*>(this) + sizeof(JsonMessage);
|
||||
}
|
||||
|
||||
void JsonMessage::SetPayload(size_t payload_size, const char* payload) {
|
||||
char* payload_dest = reinterpret_cast<char*>(this) + sizeof(JsonMessage);
|
||||
this->payload_size = payload_size;
|
||||
memcpy(payload_dest, payload, payload_size);
|
||||
}
|
||||
|
||||
void BaseIpcMessageElided::Serialize(Writer& writer) {}
|
||||
|
||||
void BaseIpcMessageElided::Deserialize(Reader& reader) {}
|
||||
|
||||
IpcRegistry* IpcRegistry::instance_ = nullptr;
|
||||
|
||||
std::unique_ptr<BaseIpcMessageElided> IpcRegistry::Allocate(int id) {
|
||||
return std::unique_ptr<BaseIpcMessageElided>((*allocators)[id]());
|
||||
std::unique_ptr<IpcMessage> IpcRegistry::Allocate(IpcId id) {
|
||||
return std::unique_ptr<IpcMessage>((*allocators)[id]());
|
||||
}
|
||||
|
||||
IpcDirectionalChannel::IpcDirectionalChannel(const std::string& name) {
|
||||
@ -64,7 +54,9 @@ IpcDirectionalChannel::~IpcDirectionalChannel() {
|
||||
delete[] local_block;
|
||||
}
|
||||
|
||||
void IpcDirectionalChannel::PushMessage(BaseIpcMessageElided* message) {
|
||||
void IpcDirectionalChannel::PushMessage(IpcMessage* message) {
|
||||
assert(message->ipc_id != IpcId::Invalid);
|
||||
|
||||
rapidjson::StringBuffer output;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||
writer.SetFormatOptions(
|
||||
@ -95,18 +87,18 @@ void IpcDirectionalChannel::PushMessage(BaseIpcMessageElided* message) {
|
||||
if ((*shared->shared_bytes_used + sizeof(JsonMessage) + payload_size) >= shmem_size)
|
||||
continue;
|
||||
|
||||
get_free_message(this)->message_id = message->hashed_runtime_id();
|
||||
get_free_message(this)->ipc_id = message->ipc_id;
|
||||
get_free_message(this)->SetPayload(payload_size, output.GetString());
|
||||
|
||||
*shared->shared_bytes_used += sizeof(JsonMessage) + get_free_message(this)->payload_size;
|
||||
assert(*shared->shared_bytes_used < shmem_size);
|
||||
get_free_message(this)->message_id = -1;
|
||||
get_free_message(this)->ipc_id = IpcId::Invalid;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcDirectionalChannel::TakeMessages() {
|
||||
std::vector<std::unique_ptr<IpcMessage>> IpcDirectionalChannel::TakeMessages() {
|
||||
size_t remaining_bytes = 0;
|
||||
// Move data from shared memory into a local buffer. Do this
|
||||
// before parsing the blocks so that other processes can begin
|
||||
@ -117,14 +109,14 @@ std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcDirectionalChannel::TakeMe
|
||||
|
||||
memcpy(local_block, shared->shared_start, *shared->shared_bytes_used);
|
||||
*shared->shared_bytes_used = 0;
|
||||
get_free_message(this)->message_id = -1;
|
||||
get_free_message(this)->ipc_id = IpcId::Invalid;
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> result;
|
||||
std::vector<std::unique_ptr<IpcMessage>> result;
|
||||
|
||||
char* message = local_block;
|
||||
while (remaining_bytes > 0) {
|
||||
std::unique_ptr<BaseIpcMessageElided> base_message = IpcRegistry::instance()->Allocate(as_message(message)->message_id);
|
||||
std::unique_ptr<IpcMessage> base_message = IpcRegistry::instance()->Allocate(as_message(message)->ipc_id);
|
||||
|
||||
rapidjson::Document document;
|
||||
document.Parse(as_message(message)->payload(), as_message(message)->payload_size);
|
||||
@ -147,7 +139,7 @@ std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcDirectionalChannel::TakeMe
|
||||
IpcServer::IpcServer(const std::string& name)
|
||||
: name_(name), server_(NameToServerName(name)) {}
|
||||
|
||||
void IpcServer::SendToClient(int client_id, BaseIpcMessageElided* message) {
|
||||
void IpcServer::SendToClient(int client_id, IpcMessage* message) {
|
||||
// Find or create the client.
|
||||
auto it = clients_.find(client_id);
|
||||
if (it == clients_.end())
|
||||
@ -156,17 +148,17 @@ void IpcServer::SendToClient(int client_id, BaseIpcMessageElided* message) {
|
||||
clients_[client_id]->PushMessage(message);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcServer::TakeMessages() {
|
||||
std::vector<std::unique_ptr<IpcMessage>> IpcServer::TakeMessages() {
|
||||
return server_.TakeMessages();
|
||||
}
|
||||
|
||||
IpcClient::IpcClient(const std::string& name, int client_id)
|
||||
: server_(NameToServerName(name)), client_(NameToClientName(name, client_id)) {}
|
||||
|
||||
void IpcClient::SendToServer(BaseIpcMessageElided* message) {
|
||||
void IpcClient::SendToServer(IpcMessage* message) {
|
||||
server_.PushMessage(message);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> IpcClient::TakeMessages() {
|
||||
std::vector<std::unique_ptr<IpcMessage>> IpcClient::TakeMessages() {
|
||||
return client_.TakeMessages();
|
||||
}
|
||||
|
126
ipc.h
126
ipc.h
@ -15,63 +15,46 @@
|
||||
// TODO: We need to add support for payloads larger than the maximum shared memory buffer size.
|
||||
|
||||
|
||||
using IpcMessageId = std::string;
|
||||
enum class IpcId : int {
|
||||
// Invalid request id.
|
||||
Invalid = 0,
|
||||
|
||||
struct BaseIpcMessageElided {
|
||||
virtual IpcMessageId runtime_id() const = 0;
|
||||
virtual int hashed_runtime_id() const = 0;
|
||||
Quit = 1,
|
||||
IsAlive,
|
||||
OpenProject,
|
||||
|
||||
virtual void Serialize(Writer& writer);
|
||||
virtual void Deserialize(Reader& reader);
|
||||
// This is a language server request. The actual request method
|
||||
// id is embedded within the request state.
|
||||
LanguageServerRequest,
|
||||
// TODO: remove
|
||||
DocumentSymbolsRequest,
|
||||
DocumentSymbolsResponse,
|
||||
WorkspaceSymbolsRequest,
|
||||
WorkspaceSymbolsResponse
|
||||
};
|
||||
|
||||
// Usage:
|
||||
//
|
||||
// class IpcMessage_Foo : public BaseIpcMessage<IpcMessage_Foo> {
|
||||
// static IpcMessageId kId;
|
||||
//
|
||||
// // BaseIpcMessage:
|
||||
// ...
|
||||
// }
|
||||
// IpcMessageId IpcMessage_Foo::kId = "Foo";
|
||||
//
|
||||
//
|
||||
// main() {
|
||||
// IpcRegistry::instance()->Register<IpcMessage_Foo>();
|
||||
// }
|
||||
//
|
||||
// Note: This is a template so that the statics are stored separately
|
||||
// per type.
|
||||
template<typename T>
|
||||
struct BaseIpcMessage : BaseIpcMessageElided {
|
||||
BaseIpcMessage();
|
||||
virtual ~BaseIpcMessage();
|
||||
|
||||
// Populated by IpcRegistry::RegisterAllocator.
|
||||
static IpcMessageId runtime_id_;
|
||||
static int hashed_runtime_id_;
|
||||
struct IpcMessage {
|
||||
IpcMessage(IpcId ipc_id) : ipc_id(ipc_id) {}
|
||||
virtual ~IpcMessage() {}
|
||||
|
||||
// BaseIpcMessageElided:
|
||||
IpcMessageId runtime_id() const override {
|
||||
return runtime_id_;
|
||||
}
|
||||
int hashed_runtime_id() const override {
|
||||
return hashed_runtime_id_;
|
||||
}
|
||||
const IpcId ipc_id;
|
||||
|
||||
virtual void Serialize(Writer& writer) = 0;
|
||||
virtual void Deserialize(Reader& reader) = 0;
|
||||
};
|
||||
|
||||
struct IpcRegistry {
|
||||
using Allocator = std::function<BaseIpcMessageElided*()>;
|
||||
using Allocator = std::function<IpcMessage*()>;
|
||||
|
||||
// Use unique_ptrs so we can initialize on first use
|
||||
// (static init order might not be right).
|
||||
std::unique_ptr<std::unordered_map<int, Allocator>> allocators;
|
||||
std::unique_ptr<std::unordered_map<int, std::string>> hash_to_id;
|
||||
std::unique_ptr<std::unordered_map<IpcId, Allocator>> allocators;
|
||||
|
||||
template<typename T>
|
||||
void Register();
|
||||
void Register(IpcId id);
|
||||
|
||||
std::unique_ptr<BaseIpcMessageElided> Allocate(int id);
|
||||
std::unique_ptr<IpcMessage> Allocate(IpcId id);
|
||||
|
||||
static IpcRegistry* instance() {
|
||||
if (!instance_)
|
||||
@ -82,25 +65,16 @@ struct IpcRegistry {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void IpcRegistry::Register() {
|
||||
if (!allocators) {
|
||||
allocators = MakeUnique<std::unordered_map<int, Allocator>>();
|
||||
hash_to_id = MakeUnique<std::unordered_map<int, std::string>>();
|
||||
}
|
||||
void IpcRegistry::Register(IpcId id) {
|
||||
if (!allocators)
|
||||
allocators = MakeUnique<std::unordered_map<IpcId, Allocator>>();
|
||||
|
||||
IpcMessageId id = T::kId;
|
||||
assert(allocators->find(id) == allocators->end() &&
|
||||
"There is already an IPC message with the given id");
|
||||
|
||||
int hash = std::hash<IpcMessageId>()(id);
|
||||
auto it = allocators->find(hash);
|
||||
assert(allocators->find(hash) == allocators->end() && "There is already an IPC message with the given id");
|
||||
|
||||
(*hash_to_id)[hash] = id;
|
||||
(*allocators)[hash] = []() {
|
||||
(*allocators)[id] = [id]() {
|
||||
return new T();
|
||||
};
|
||||
|
||||
T::runtime_id_ = id;
|
||||
T::hashed_runtime_id_ = hash;
|
||||
}
|
||||
|
||||
|
||||
@ -115,8 +89,8 @@ struct IpcDirectionalChannel {
|
||||
explicit IpcDirectionalChannel(const std::string& name);
|
||||
~IpcDirectionalChannel();
|
||||
|
||||
void PushMessage(BaseIpcMessageElided* message);
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
|
||||
void PushMessage(IpcMessage* message);
|
||||
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
||||
|
||||
// Pointer to process shared memory and process shared mutex.
|
||||
std::unique_ptr<PlatformSharedMemory> shared;
|
||||
@ -129,8 +103,8 @@ struct IpcDirectionalChannel {
|
||||
struct IpcServer {
|
||||
IpcServer(const std::string& name);
|
||||
|
||||
void SendToClient(int client_id, BaseIpcMessageElided* message);
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
|
||||
void SendToClient(int client_id, IpcMessage* message);
|
||||
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
@ -141,36 +115,12 @@ private:
|
||||
struct IpcClient {
|
||||
IpcClient(const std::string& name, int client_id);
|
||||
|
||||
void SendToServer(BaseIpcMessageElided* message);
|
||||
std::vector<std::unique_ptr<BaseIpcMessageElided>> TakeMessages();
|
||||
void SendToServer(IpcMessage* message);
|
||||
std::vector<std::unique_ptr<IpcMessage>> TakeMessages();
|
||||
|
||||
IpcDirectionalChannel* client() { return &client_; }
|
||||
|
||||
private:
|
||||
IpcDirectionalChannel server_;
|
||||
IpcDirectionalChannel client_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
BaseIpcMessage<T>::BaseIpcMessage() {
|
||||
assert(!runtime_id_.empty() && "Message is not registered using IpcRegistry::RegisterAllocator");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
BaseIpcMessage<T>::~BaseIpcMessage() {}
|
||||
|
||||
template<typename T>
|
||||
IpcMessageId BaseIpcMessage<T>::runtime_id_;
|
||||
|
||||
template<typename T>
|
||||
int BaseIpcMessage<T>::hashed_runtime_id_ = -1;
|
||||
};
|
@ -18,6 +18,21 @@ using std::experimental::nullopt;
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
enum class lsMethodId : int {
|
||||
// Language server specific requests.
|
||||
CancelRequest = 0,
|
||||
Initialize,
|
||||
Initialized,
|
||||
TextDocumentDocumentSymbol,
|
||||
WorkspaceSymbol,
|
||||
};
|
||||
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, lsMethodId& value) {
|
||||
int value0 = static_cast<int>(value);
|
||||
Reflect(visitor, value0);
|
||||
value = static_cast<lsMethodId>(value0);
|
||||
}
|
||||
|
||||
struct RequestId {
|
||||
optional<int> id0;
|
||||
@ -25,11 +40,12 @@ struct RequestId {
|
||||
};
|
||||
|
||||
void Reflect(Writer& visitor, RequestId& value) {
|
||||
assert(value.id0.has_value() || value.id1.has_value());
|
||||
|
||||
if (value.id0) {
|
||||
Reflect(visitor, value.id0.value());
|
||||
}
|
||||
else {
|
||||
assert(value.id1.has_value());
|
||||
Reflect(visitor, value.id1.value());
|
||||
}
|
||||
}
|
||||
@ -214,14 +230,6 @@ struct OutNotificationMessage : public OutMessage {
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
enum class lsMethodId {
|
||||
CancelRequest,
|
||||
Initialize,
|
||||
Initialized,
|
||||
TextDocumentDocumentSymbol,
|
||||
WorkspaceSymbol,
|
||||
};
|
||||
|
||||
const char* MethodIdToString(lsMethodId id) {
|
||||
switch (id) {
|
||||
case lsMethodId::CancelRequest:
|
||||
@ -303,18 +311,18 @@ struct InMessage {
|
||||
const lsMethodId method_id;
|
||||
optional<RequestId> id;
|
||||
|
||||
InMessage(lsMethodId method_id, optional<RequestId> id, Reader& reader)
|
||||
InMessage(lsMethodId method_id, optional<RequestId> id, Reader& reader)
|
||||
// We verify there are no duplicate hashes inside of MessageRegistry.
|
||||
: method_id(method_id), id(id) {}
|
||||
};
|
||||
|
||||
struct InRequestMessage : public InMessage {
|
||||
InRequestMessage(lsMethodId method, optional<RequestId> id, Reader& reader)
|
||||
InRequestMessage(lsMethodId method, optional<RequestId> id, Reader& reader)
|
||||
: InMessage(method, id, reader) {}
|
||||
};
|
||||
|
||||
struct InNotificationMessage : public InMessage {
|
||||
InNotificationMessage(lsMethodId method, optional<RequestId> id, Reader& reader)
|
||||
InNotificationMessage(lsMethodId method, optional<RequestId> id, Reader& reader)
|
||||
: InMessage(method, id, reader) {}
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user