This commit is contained in:
Jacob Dufault 2017-03-25 14:57:06 -07:00
parent a31ebb131c
commit 68938bc3df
3 changed files with 101 additions and 107 deletions

View File

@ -37,13 +37,13 @@ struct IndexTranslationUnitResponse {
}; };
// TODO: Rename TypedBidiMessageQueue to IpcTransport? // TODO: Rename TypedBidiMessageQueue to IpcTransport?
using IpcMessageQueue = TypedBidiMessageQueue<lsMethodId, BaseIpcMessage>; using IpcMessageQueue = TypedBidiMessageQueue<IpcId, BaseIpcMessage>;
using IndexRequestQueue = ThreadedQueue<IndexTranslationUnitRequest>; using IndexRequestQueue = ThreadedQueue<IndexTranslationUnitRequest>;
using IndexResponseQueue = ThreadedQueue<IndexTranslationUnitResponse>; using IndexResponseQueue = ThreadedQueue<IndexTranslationUnitResponse>;
template<typename TMessage> template<typename TMessage>
void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) { void SendMessage(IpcMessageQueue& t, MessageQueue* destination, TMessage& message) {
t.SendMessage(destination, TMessage::kMethod, message); t.SendMessage(destination, TMessage::kIpcId, message);
} }
std::unordered_map<std::string, std::string> ParseOptions(int argc, std::unordered_map<std::string, std::string> ParseOptions(int argc,
@ -79,48 +79,6 @@ bool HasOption(const std::unordered_map<std::string, std::string>& options,
return options.find(option) != options.end(); return options.find(option) != options.end();
} }
std::unique_ptr<BaseIpcMessage> ParseMessage() {
int content_length = -1;
int iteration = 0;
while (true) {
if (++iteration > 10) {
assert(false && "bad parser state");
exit(1);
}
std::string line;
std::getline(std::cin, line);
// std::cin >> line;
if (line.compare(0, 14, "Content-Length") == 0) {
content_length = atoi(line.c_str() + 16);
}
if (line == "\r")
break;
}
// bad input that is not a message.
if (content_length < 0) {
std::cerr << "parsing command failed (no Content-Length header)"
<< std::endl;
return nullptr;
}
std::string content;
content.reserve(content_length);
for (int i = 0; i < content_length; ++i) {
char c;
std::cin >> c;
content += c;
}
rapidjson::Document document;
document.Parse(content.c_str(), content_length);
assert(!document.HasParseError());
return MessageRegistry::instance()->Parse(document);
}
std::string Join(const std::vector<std::string>& elements, std::string sep) { std::string Join(const std::vector<std::string>& elements, std::string sep) {
bool first = true; bool first = true;
@ -135,19 +93,19 @@ std::string Join(const std::vector<std::string>& elements, std::string sep) {
} }
struct Ipc_Quit : public IpcMessage<Ipc_Quit> { struct Ipc_Quit : public IpcMessage<Ipc_Quit> {
static constexpr lsMethodId kMethod = lsMethodId::Quit; static constexpr IpcId kIpcId = IpcId::Quit;
}; };
template <typename TVisitor> template <typename TVisitor>
void Reflect(TVisitor& visitor, Ipc_Quit& value) {} void Reflect(TVisitor& visitor, Ipc_Quit& value) {}
struct Ipc_IsAlive : public IpcMessage<Ipc_IsAlive> { struct Ipc_IsAlive : public IpcMessage<Ipc_IsAlive> {
static constexpr lsMethodId kMethod = lsMethodId::IsAlive; static constexpr IpcId kIpcId = IpcId::IsAlive;
}; };
template <typename TVisitor> template <typename TVisitor>
void Reflect(TVisitor& visitor, Ipc_IsAlive& value) {} void Reflect(TVisitor& visitor, Ipc_IsAlive& value) {}
struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> { struct Ipc_OpenProject : public IpcMessage<Ipc_OpenProject> {
static constexpr lsMethodId kMethod = lsMethodId::OpenProject; static constexpr IpcId kIpcId = IpcId::OpenProject;
std::string project_path; std::string project_path;
}; };
template <typename TVisitor> template <typename TVisitor>
@ -156,7 +114,7 @@ void Reflect(TVisitor& visitor, Ipc_OpenProject& value) {
} }
struct Ipc_Cout : public IpcMessage<Ipc_Cout> { struct Ipc_Cout : public IpcMessage<Ipc_Cout> {
static constexpr lsMethodId kMethod = lsMethodId::Cout; static constexpr IpcId kIpcId = IpcId::Cout;
std::string content; std::string content;
}; };
template <typename TVisitor> template <typename TVisitor>
@ -171,14 +129,14 @@ void SendOutMessageToClient(IpcMessageQueue* queue, T& response) {
Ipc_Cout out; Ipc_Cout out;
out.content = sstream.str(); out.content = sstream.str();
queue->SendMessage(&queue->for_client, Ipc_Cout::kMethod, out); queue->SendMessage(&queue->for_client, Ipc_Cout::kIpcId, out);
} }
template<typename T> template<typename T>
void RegisterId(IpcMessageQueue* t) { void RegisterId(IpcMessageQueue* t) {
t->RegisterId(T::kMethod, t->RegisterId(T::kIpcId,
[](Writer& visitor, BaseIpcMessage& message) { [](Writer& visitor, BaseIpcMessage& message) {
T& m = static_cast<T&>(message); T& m = static_cast<T&>(message);
Reflect(visitor, m); Reflect(visitor, m);
@ -374,19 +332,19 @@ void QueryDbMainLoop(
// << std::endl; // << std::endl;
switch (message->method_id) { switch (message->method_id) {
case lsMethodId::Quit: { case IpcId::Quit: {
std::cerr << "Got quit message (exiting)" << std::endl; std::cerr << "Got quit message (exiting)" << std::endl;
exit(0); exit(0);
break; break;
} }
case lsMethodId::IsAlive: { case IpcId::IsAlive: {
Ipc_IsAlive response; Ipc_IsAlive response;
language_client->SendMessage(&language_client->for_client, response.method_id, response); language_client->SendMessage(&language_client->for_client, response.method_id, response);
break; break;
} }
case lsMethodId::OpenProject: { case IpcId::OpenProject: {
Ipc_OpenProject* msg = static_cast<Ipc_OpenProject*>(message.get()); Ipc_OpenProject* msg = static_cast<Ipc_OpenProject*>(message.get());
std::string path = msg->project_path; std::string path = msg->project_path;
@ -408,7 +366,7 @@ void QueryDbMainLoop(
break; break;
} }
case lsMethodId::TextDocumentDocumentSymbol: { case IpcId::TextDocumentDocumentSymbol: {
auto msg = static_cast<Ipc_TextDocumentDocumentSymbol*>(message.get()); auto msg = static_cast<Ipc_TextDocumentDocumentSymbol*>(message.get());
Out_TextDocumentDocumentSymbol response; Out_TextDocumentDocumentSymbol response;
@ -473,7 +431,7 @@ void QueryDbMainLoop(
break; break;
} }
case lsMethodId::TextDocumentCodeLens: { case IpcId::TextDocumentCodeLens: {
auto msg = static_cast<Ipc_TextDocumentCodeLens*>(message.get()); auto msg = static_cast<Ipc_TextDocumentCodeLens*>(message.get());
Out_TextDocumentCodeLens response; Out_TextDocumentCodeLens response;
@ -528,7 +486,7 @@ void QueryDbMainLoop(
break; break;
} }
case lsMethodId::WorkspaceSymbol: { case IpcId::WorkspaceSymbol: {
auto msg = static_cast<Ipc_WorkspaceSymbol*>(message.get()); auto msg = static_cast<Ipc_WorkspaceSymbol*>(message.get());
Out_WorkspaceSymbol response; Out_WorkspaceSymbol response;
@ -675,7 +633,7 @@ void QueryDbMain() {
// |ipc| is connected to a server. // |ipc| is connected to a server.
void LanguageServerStdinLoop(IpcMessageQueue* ipc) { void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
while (true) { while (true) {
std::unique_ptr<BaseIpcMessage> message = ParseMessage(); std::unique_ptr<BaseIpcMessage> message = MessageRegistry::instance()->ReadMessageFromStdin();
// Message parsing can fail if we don't recognize the method. // Message parsing can fail if we don't recognize the method.
if (!message) if (!message)
@ -686,7 +644,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
switch (message->method_id) { switch (message->method_id) {
// TODO: For simplicitly lets just proxy the initialize request like // TODO: For simplicitly lets just proxy the initialize request like
// all other requests so that stdin loop thread becomes super simple. // all other requests so that stdin loop thread becomes super simple.
case lsMethodId::Initialize: { case IpcId::Initialize: {
auto request = static_cast<Ipc_InitializeRequest*>(message.get()); auto request = static_cast<Ipc_InitializeRequest*>(message.get());
if (request->params.rootUri) { if (request->params.rootUri) {
std::string project_path = request->params.rootUri->GetPath(); std::string project_path = request->params.rootUri->GetPath();
@ -695,7 +653,7 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
<< std::endl; << std::endl;
Ipc_OpenProject open_project; Ipc_OpenProject open_project;
open_project.project_path = project_path; open_project.project_path = project_path;
ipc->SendMessage(&ipc->for_server, Ipc_OpenProject::kMethod, open_project); ipc->SendMessage(&ipc->for_server, Ipc_OpenProject::kIpcId, open_project);
} }
auto response = Out_InitializeResponse(); auto response = Out_InitializeResponse();
@ -709,9 +667,9 @@ void LanguageServerStdinLoop(IpcMessageQueue* ipc) {
break; break;
} }
case lsMethodId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
case lsMethodId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:
case lsMethodId::WorkspaceSymbol: { case IpcId::WorkspaceSymbol: {
ipc->SendMessage(&ipc->for_server, message->method_id, *message.get()); ipc->SendMessage(&ipc->for_server, message->method_id, *message.get());
break; break;
} }
@ -723,13 +681,13 @@ void LanguageServerMainLoop(IpcMessageQueue* ipc) {
std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc->GetMessages(&ipc->for_client); std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc->GetMessages(&ipc->for_client);
for (auto& message : messages) { for (auto& message : messages) {
switch (message->method_id) { switch (message->method_id) {
case lsMethodId::Quit: { case IpcId::Quit: {
std::cerr << "Got quit message (exiting)" << std::endl; std::cerr << "Got quit message (exiting)" << std::endl;
exit(0); exit(0);
break; break;
} }
case lsMethodId::Cout: { case IpcId::Cout: {
auto msg = static_cast<Ipc_Cout*>(message.get()); auto msg = static_cast<Ipc_Cout*>(message.get());
std::cout << msg->content; std::cout << msg->content;
std::cout.flush(); std::cout.flush();
@ -756,7 +714,7 @@ bool IsQueryDbProcessRunning(IpcMessageQueue* ipc) {
// Check if we got an IsAlive message back. // Check if we got an IsAlive message back.
std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc->GetMessages(&ipc->for_client); std::vector<std::unique_ptr<BaseIpcMessage>> messages = ipc->GetMessages(&ipc->for_client);
for (auto& message : messages) { for (auto& message : messages) {
if (lsMethodId::IsAlive == message->method_id) if (IpcId::IsAlive == message->method_id)
return true; return true;
} }

View File

@ -0,0 +1 @@
//#include "language_server_api.h"

View File

@ -6,6 +6,7 @@
#include <optional.h> #include <optional.h>
#include <rapidjson/writer.h> #include <rapidjson/writer.h>
#include <algorithm>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <unordered_map> #include <unordered_map>
@ -21,7 +22,7 @@ using std::experimental::nullopt;
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
enum class lsMethodId : int { enum class IpcId : int {
// Language server specific requests. // Language server specific requests.
CancelRequest = 0, CancelRequest = 0,
Initialize, Initialize,
@ -37,13 +38,13 @@ enum class lsMethodId : int {
OpenProject, OpenProject,
Cout Cout
}; };
MAKE_ENUM_HASHABLE(lsMethodId); MAKE_ENUM_HASHABLE(IpcId);
template<typename TVisitor> template<typename TVisitor>
void Reflect(TVisitor& visitor, lsMethodId& value) { void Reflect(TVisitor& visitor, IpcId& value) {
int value0 = static_cast<int>(value); int value0 = static_cast<int>(value);
Reflect(visitor, value0); Reflect(visitor, value0);
value = static_cast<lsMethodId>(value0); value = static_cast<IpcId>(value0);
} }
struct RequestId { struct RequestId {
@ -121,23 +122,24 @@ void Reflect(Reader& visitor, RequestId& id) {
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
const char* MethodIdToString(lsMethodId id) { const char* MethodIdToString(IpcId id) {
switch (id) { switch (id) {
case lsMethodId::CancelRequest: case IpcId::CancelRequest:
return "$/cancelRequest"; return "$/cancelRequest";
case lsMethodId::Initialize: case IpcId::Initialize:
return "initialize"; return "initialize";
case lsMethodId::Initialized: case IpcId::Initialized:
return "initialized"; return "initialized";
case lsMethodId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
return "textDocument/documentSymbol"; return "textDocument/documentSymbol";
case lsMethodId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:
return "textDocument/codeLens"; return "textDocument/codeLens";
case lsMethodId::CodeLensResolve: case IpcId::CodeLensResolve:
return "codeLens/resolve"; return "codeLens/resolve";
case lsMethodId::WorkspaceSymbol: case IpcId::WorkspaceSymbol:
return "workspace/symbol"; return "workspace/symbol";
default: default:
assert(false);
exit(1); exit(1);
} }
} }
@ -153,7 +155,7 @@ struct MessageRegistry {
template<typename T> template<typename T>
void Register() { void Register() {
std::string method_name = MethodIdToString(T::kMethod); std::string method_name = MethodIdToString(T::kIpcId);
allocators[method_name] = [](Reader& visitor) { allocators[method_name] = [](Reader& visitor) {
auto result = MakeUnique<T>(); auto result = MakeUnique<T>();
Reflect(visitor, *result); Reflect(visitor, *result);
@ -161,6 +163,49 @@ struct MessageRegistry {
}; };
} }
std::unique_ptr<BaseIpcMessage> ReadMessageFromStdin() {
int content_length = -1;
int iteration = 0;
while (true) {
if (++iteration > 10) {
assert(false && "bad parser state");
exit(1);
}
std::string line;
std::getline(std::cin, line);
// std::cin >> line;
if (line.compare(0, 14, "Content-Length") == 0) {
content_length = atoi(line.c_str() + 16);
}
if (line == "\r")
break;
}
// bad input that is not a message.
if (content_length < 0) {
std::cerr << "parsing command failed (no Content-Length header)"
<< std::endl;
return nullptr;
}
std::string content;
content.reserve(content_length);
for (int i = 0; i < content_length; ++i) {
char c;
std::cin >> c;
content += c;
}
rapidjson::Document document;
document.Parse(content.c_str(), content_length);
assert(!document.HasParseError());
return Parse(document);
}
std::unique_ptr<BaseIpcMessage> Parse(Reader& visitor) { std::unique_ptr<BaseIpcMessage> Parse(Reader& visitor) {
std::string jsonrpc = visitor["jsonrpc"].GetString(); std::string jsonrpc = visitor["jsonrpc"].GetString();
if (jsonrpc != "2.0") if (jsonrpc != "2.0")
@ -188,13 +233,13 @@ MessageRegistry* MessageRegistry::instance() {
} }
struct BaseIpcMessage { struct BaseIpcMessage {
const lsMethodId method_id; const IpcId method_id;
BaseIpcMessage(lsMethodId method_id) : method_id(method_id) {} BaseIpcMessage(IpcId method_id) : method_id(method_id) {}
}; };
template <typename T> template <typename T>
struct IpcMessage : public BaseIpcMessage { struct IpcMessage : public BaseIpcMessage {
IpcMessage() : BaseIpcMessage(T::kMethod) {} IpcMessage() : BaseIpcMessage(T::kIpcId) {}
}; };
template<typename TDerived> template<typename TDerived>
@ -1182,8 +1227,8 @@ void Reflect(TVisitor& visitor, lsInitializeResult& value) {
} }
struct Ipc_InitializeRequest : public IpcMessage<Ipc_InitializeRequest>{ struct Ipc_InitializeRequest : public IpcMessage<Ipc_InitializeRequest> {
const static lsMethodId kMethod = lsMethodId::Initialize; const static IpcId kIpcId = IpcId::Initialize;
RequestId id; RequestId id;
lsInitializeParams params; lsInitializeParams params;
@ -1209,8 +1254,8 @@ void Reflect(TVisitor& visitor, Out_InitializeResponse& value) {
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Ipc_InitializedNotification : public IpcMessage<Ipc_InitializedNotification>{ struct Ipc_InitializedNotification : public IpcMessage<Ipc_InitializedNotification> {
const static lsMethodId kMethod = lsMethodId::Initialized; const static IpcId kIpcId = IpcId::Initialized;
RequestId id; RequestId id;
}; };
@ -1264,7 +1309,7 @@ void Reflect(TVisitor& visitor, Ipc_InitializedNotification& value) {
// Cancel an existing request. // Cancel an existing request.
struct Ipc_CancelRequest : public IpcMessage<Ipc_CancelRequest> { struct Ipc_CancelRequest : public IpcMessage<Ipc_CancelRequest> {
static const lsMethodId kMethod = lsMethodId::CancelRequest; static const IpcId kIpcId = IpcId::CancelRequest;
RequestId id; RequestId id;
}; };
template<typename TVisitor> template<typename TVisitor>
@ -1284,8 +1329,8 @@ void Reflect(TVisitor& visitor, lsDocumentSymbolParams& value) {
REFLECT_MEMBER(textDocument); REFLECT_MEMBER(textDocument);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Ipc_TextDocumentDocumentSymbol : public IpcMessage<Ipc_TextDocumentDocumentSymbol>{ struct Ipc_TextDocumentDocumentSymbol : public IpcMessage<Ipc_TextDocumentDocumentSymbol> {
const static lsMethodId kMethod = lsMethodId::TextDocumentDocumentSymbol; const static IpcId kIpcId = IpcId::TextDocumentDocumentSymbol;
RequestId id; RequestId id;
lsDocumentSymbolParams params; lsDocumentSymbolParams params;
@ -1297,7 +1342,7 @@ void Reflect(TVisitor& visitor, Ipc_TextDocumentDocumentSymbol& value) {
REFLECT_MEMBER(params); REFLECT_MEMBER(params);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Out_TextDocumentDocumentSymbol : public lsOutMessage<Out_TextDocumentDocumentSymbol>{ struct Out_TextDocumentDocumentSymbol : public lsOutMessage<Out_TextDocumentDocumentSymbol> {
RequestId id; RequestId id;
std::vector<lsSymbolInformation> result; std::vector<lsSymbolInformation> result;
}; };
@ -1347,9 +1392,8 @@ void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) {
Reflect(*it, value.locations); Reflect(*it, value.locations);
} }
using TCodeLens = lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>; using TCodeLens = lsCodeLens<lsCodeLensUserData, lsCodeLensCommandArguments>;
struct Ipc_TextDocumentCodeLens : public IpcMessage<Ipc_TextDocumentCodeLens>{ struct Ipc_TextDocumentCodeLens : public IpcMessage<Ipc_TextDocumentCodeLens> {
const static lsMethodId kMethod = lsMethodId::TextDocumentCodeLens; const static IpcId kIpcId = IpcId::TextDocumentCodeLens;
RequestId id; RequestId id;
lsDocumentCodeLensParams params; lsDocumentCodeLensParams params;
}; };
@ -1372,8 +1416,8 @@ void Reflect(TVisitor& visitor, Out_TextDocumentCodeLens& value) {
REFLECT_MEMBER(result); REFLECT_MEMBER(result);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Ipc_CodeLensResolve : public IpcMessage<Ipc_CodeLensResolve>{ struct Ipc_CodeLensResolve : public IpcMessage<Ipc_CodeLensResolve> {
const static lsMethodId kMethod = lsMethodId::CodeLensResolve; const static IpcId kIpcId = IpcId::CodeLensResolve;
RequestId id; RequestId id;
TCodeLens params; TCodeLens params;
@ -1408,8 +1452,8 @@ void Reflect(TVisitor& visitor, lsWorkspaceSymbolParams& value) {
REFLECT_MEMBER(query); REFLECT_MEMBER(query);
REFLECT_MEMBER_END(); REFLECT_MEMBER_END();
} }
struct Ipc_WorkspaceSymbol : public IpcMessage<Ipc_WorkspaceSymbol >{ struct Ipc_WorkspaceSymbol : public IpcMessage<Ipc_WorkspaceSymbol > {
const static lsMethodId kMethod = lsMethodId::WorkspaceSymbol; const static IpcId kIpcId = IpcId::WorkspaceSymbol;
RequestId id; RequestId id;
lsWorkspaceSymbolParams params; lsWorkspaceSymbolParams params;
}; };
@ -1461,20 +1505,11 @@ struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
enum class DisplayType { enum class DisplayType {
Show, Log Show, Log
}; };
DisplayType display_type = DisplayType::Show; DisplayType display_type = DisplayType::Show;
std::string method() { std::string method() {
switch (display_type) { if (display_type == DisplayType::Log)
case Out_ShowLogMessage::DisplayType::Show:
return "window/showMessage";
break;
case Out_ShowLogMessage::DisplayType::Log:
return "window/logMessage"; return "window/logMessage";
break; return "window/showMessage";
}
assert(false);
return "window/logMessage";
} }
Out_ShowLogMessageParams params; Out_ShowLogMessageParams params;