Skip to content

Commit 3aea810

Browse files
committed
chore: Handle basic LSP requests
Signed-off-by: Roberto Raggi <[email protected]>
1 parent 5f50f9c commit 3aea810

File tree

5 files changed

+137
-58
lines changed

5 files changed

+137
-58
lines changed

packages/cxx-gen-lsp/src/gen_fwd_h.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class LSPObject {
4545
class LSPRequest : public LSPObject {
4646
public:
4747
using LSPObject::LSPObject;
48+
49+
[[nodiscard]] auto method() const -> std::string {
50+
return repr_->at("method").get<std::string>();
51+
}
4852
};
4953
5054
class LSPResponse : public LSPObject {

packages/cxx-gen-lsp/src/gen_requests_h.ts

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,31 +107,20 @@ export function gen_requests_h({ model, outputDirectory }: { model: MetaModel; o
107107

108108
emit();
109109
emit(`template <typename Visitor>`);
110-
emit(`auto visitRequest(Visitor&& visitor, const LSPRequest& request, const std::string_view& method) -> void {`);
110+
emit(`auto visit(Visitor&& visitor, const LSPRequest& request) -> void {`);
111111
emit(`#define PROCESS_REQUEST_TYPE(NAME, METHOD) \\`);
112-
emit(` if (method == METHOD) \\`);
112+
emit(` if (request.method() == METHOD) \\`);
113113
emit(` return visitor(static_cast<const NAME##Request&>(request));`);
114114
emit();
115-
emit(`FOR_EACH_LSP_REQUEST_TYPE(PROCESS_REQUEST_TYPE)`);
116-
emit();
117-
emit(`#undef PROCESS_REQUEST_TYPE`);
118-
emit();
119-
emit(` lsp_runtime_error("unknown request type");`);
120-
emit(`}`);
121-
emit();
122-
emit(`template <typename Visitor>`);
123-
emit(
124-
`auto visitNotification(Visitor&& visitor, const LSPRequest& notification, const std::string_view& method) -> void {`,
125-
);
126115
emit(`#define PROCESS_NOTIFICATION_TYPE(NAME, METHOD) \\`);
127-
emit(` if (method == METHOD) \\`);
128-
emit(` return visitor(static_cast<const NAME##Notification&>(notification));`);
116+
emit(` if (request.method() == METHOD) \\`);
117+
emit(` return visitor(static_cast<const NAME##Notification&>(request));`);
129118
emit();
119+
emit(`FOR_EACH_LSP_REQUEST_TYPE(PROCESS_REQUEST_TYPE)`);
130120
emit(`FOR_EACH_LSP_NOTIFICATION_TYPE(PROCESS_NOTIFICATION_TYPE)`);
131121
emit();
122+
emit(`#undef PROCESS_REQUEST_TYPE`);
132123
emit(`#undef PROCESS_NOTIFICATION_TYPE`);
133-
emit();
134-
emit(` lsp_runtime_error("unknown notification type");`);
135124
emit(`}`);
136125

137126
emit();

src/frontend/cxx/lsp_server.cc

Lines changed: 117 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,6 @@ auto readHeaders(std::istream& input) -> Headers {
106106
return headers;
107107
}
108108

109-
void sendToClient(const json& message, std::ostream& output = std::cout) {
110-
const auto text = message.dump();
111-
output << "Content-Length: " << text.size() << "\r\n\r\n";
112-
output << text;
113-
output.flush();
114-
};
115-
116109
struct Input {
117110
struct Diagnostics final : cxx::DiagnosticsClient {
118111
json messages = json::array();
@@ -279,31 +272,131 @@ struct Input {
279272
}
280273
};
281274

282-
auto nextRequest() -> std::optional<json> {
283-
auto& input = std::cin;
275+
class Server {
276+
std::istream& input;
284277

285-
const auto headers = readHeaders(input);
278+
public:
279+
Server() : input(std::cin) {}
286280

287-
// Get Content-Length
288-
const auto it = headers.find("Content-Length");
281+
auto start() -> int {
282+
while (input.good()) {
283+
auto req = nextRequest();
289284

290-
if (it == headers.end()) {
291-
return std::nullopt;
292-
};
285+
if (!req.has_value()) {
286+
continue;
287+
}
293288

294-
const auto contentLength = std::stoi(it->value);
289+
visit(*this, LSPRequest(req.value()));
290+
}
295291

296-
// Read content
297-
std::string content(contentLength, '\0');
298-
input.read(content.data(), content.size());
292+
return 0;
293+
}
299294

300-
// Parse JSON
301-
auto request = json::parse(content);
302-
return request;
303-
}
295+
auto nextRequest() -> std::optional<json> {
296+
const auto headers = readHeaders(input);
297+
298+
// Get Content-Length
299+
const auto it = headers.find("Content-Length");
300+
301+
if (it == headers.end()) {
302+
return std::nullopt;
303+
};
304+
305+
const auto contentLength = std::stoi(it->value);
306+
307+
// Read content
308+
std::string content(contentLength, '\0');
309+
input.read(content.data(), content.size());
310+
311+
// Parse JSON
312+
auto request = json::parse(content);
313+
return request;
314+
}
315+
316+
void sendToClient(const json& message, std::ostream& output = std::cout) {
317+
const auto text = message.dump();
318+
output << "Content-Length: " << text.size() << "\r\n\r\n";
319+
output << text;
320+
output.flush();
321+
}
322+
323+
void sendToClient(
324+
const LSPObject& result,
325+
std::optional<std::variant<long, std::string>> id = std::nullopt,
326+
std::ostream& output = std::cout) {
327+
auto response = json::object();
328+
response["jsonrpc"] = "2.0";
329+
330+
if (id.has_value()) {
331+
if (std::holds_alternative<long>(id.value())) {
332+
response["id"] = std::get<long>(id.value());
333+
} else {
334+
response["id"] = std::get<std::string>(id.value());
335+
}
336+
}
337+
338+
response["result"] = result;
339+
340+
sendToClient(response);
341+
}
342+
343+
//
344+
// notifications
345+
//
346+
void operator()(const InitializedNotification& notification) {
347+
std::cerr << std::format("Did receive InitializedNotification\n");
348+
}
349+
350+
void operator()(const ExitNotification& notification) {
351+
std::cerr << std::format("Did receive ExitNotification\n");
352+
}
353+
354+
void operator()(const DidOpenTextDocumentNotification& notification) {
355+
std::cerr << std::format("Did receive DidOpenTextDocumentNotification\n");
356+
}
357+
358+
void operator()(const DidCloseTextDocumentNotification& notification) {
359+
std::cerr << std::format("Did receive DidCloseTextDocumentNotification\n");
360+
}
361+
362+
void operator()(const DidChangeTextDocumentNotification& notification) {
363+
std::cerr << std::format("Did receive DidChangeTextDocumentNotification\n");
364+
}
365+
366+
//
367+
// life cycle requests
368+
//
369+
370+
void operator()(const InitializeRequest& request) {
371+
std::cerr << std::format("Did receive InitializeRequest\n");
372+
auto storage = json::object();
373+
InitializeResult result(storage);
374+
result.serverInfo<ServerInfo>().name("cxx-lsp").version("0.0.1");
375+
result.capabilities().textDocumentSync(TextDocumentSyncKind::kFull);
376+
377+
sendToClient(result, request.id());
378+
}
379+
380+
void operator()(const ShutdownRequest& request) {
381+
std::cerr << std::format("Did receive ShutdownRequest\n");
382+
383+
json storage;
384+
LSPObject result(storage);
385+
386+
sendToClient(result, request.id());
387+
}
388+
389+
//
390+
// Other requests
391+
//
392+
void operator()(const LSPRequest& request) {
393+
std::cerr << "Request: " << request.method() << "\n";
394+
}
395+
};
304396

305397
int startServer(const CLI& cli) {
306-
cxx_runtime_error("not implemented");
398+
Server server;
399+
server.start();
307400
return 0;
308401
}
309402

src/lsp/cxx/lsp/fwd.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,10 @@ class LSPObject {
644644
class LSPRequest : public LSPObject {
645645
public:
646646
using LSPObject::LSPObject;
647+
648+
[[nodiscard]] auto method() const -> std::string {
649+
return repr_->at("method").get<std::string>();
650+
}
647651
};
648652

649653
class LSPResponse : public LSPObject {

src/lsp/cxx/lsp/requests.h

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2544,31 +2544,20 @@ class ProgressNotification final : public LSPRequest {
25442544
};
25452545

25462546
template <typename Visitor>
2547-
auto visitRequest(Visitor&& visitor, const LSPRequest& request,
2548-
const std::string_view& method) -> void {
2547+
auto visit(Visitor&& visitor, const LSPRequest& request) -> void {
25492548
#define PROCESS_REQUEST_TYPE(NAME, METHOD) \
2550-
if (method == METHOD) \
2549+
if (request.method() == METHOD) \
25512550
return visitor(static_cast<const NAME##Request&>(request));
25522551

2553-
FOR_EACH_LSP_REQUEST_TYPE(PROCESS_REQUEST_TYPE)
2554-
2555-
#undef PROCESS_REQUEST_TYPE
2556-
2557-
lsp_runtime_error("unknown request type");
2558-
}
2559-
2560-
template <typename Visitor>
2561-
auto visitNotification(Visitor&& visitor, const LSPRequest& notification,
2562-
const std::string_view& method) -> void {
25632552
#define PROCESS_NOTIFICATION_TYPE(NAME, METHOD) \
2564-
if (method == METHOD) \
2565-
return visitor(static_cast<const NAME##Notification&>(notification));
2553+
if (request.method() == METHOD) \
2554+
return visitor(static_cast<const NAME##Notification&>(request));
25662555

2556+
FOR_EACH_LSP_REQUEST_TYPE(PROCESS_REQUEST_TYPE)
25672557
FOR_EACH_LSP_NOTIFICATION_TYPE(PROCESS_NOTIFICATION_TYPE)
25682558

2559+
#undef PROCESS_REQUEST_TYPE
25692560
#undef PROCESS_NOTIFICATION_TYPE
2570-
2571-
lsp_runtime_error("unknown notification type");
25722561
}
25732562

25742563
} // namespace cxx::lsp

0 commit comments

Comments
 (0)