Skip to content

Commit 4fa8acc

Browse files
committed
chore: Update C++ documents during the LSP lifecycle
1 parent 6f29a1c commit 4fa8acc

File tree

1 file changed

+93
-4
lines changed

1 file changed

+93
-4
lines changed

src/frontend/cxx/lsp_server.cc

Lines changed: 93 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <format>
4242
#include <iostream>
4343
#include <set>
44+
#include <unordered_map>
4445
#include <vector>
4546

4647
namespace cxx::lsp {
@@ -106,7 +107,7 @@ auto readHeaders(std::istream& input) -> Headers {
106107
return headers;
107108
}
108109

109-
struct Input {
110+
struct CxxDocument {
110111
struct Diagnostics final : cxx::DiagnosticsClient {
111112
json messages = json::array();
112113
Vector<lsp::Diagnostic> diagnostics{messages};
@@ -146,7 +147,7 @@ struct Input {
146147
TranslationUnit unit;
147148
std::unique_ptr<Toolchain> toolchain;
148149

149-
Input(const CLI& cli) : cli(cli), unit(&control, &diagnosticsClient) {}
150+
CxxDocument(const CLI& cli) : cli(cli), unit(&control, &diagnosticsClient) {}
150151

151152
void parse(std::string source, std::string fileName) {
152153
configure();
@@ -273,10 +274,12 @@ struct Input {
273274
};
274275

275276
class Server {
277+
const CLI& cli;
276278
std::istream& input;
279+
std::unordered_map<std::string, std::shared_ptr<CxxDocument>> documents;
277280

278281
public:
279-
Server() : input(std::cin) {}
282+
Server(const CLI& cli) : cli(cli), input(std::cin) {}
280283

281284
auto start() -> int {
282285
while (input.good()) {
@@ -353,14 +356,66 @@ class Server {
353356

354357
void operator()(const DidOpenTextDocumentNotification& notification) {
355358
std::cerr << std::format("Did receive DidOpenTextDocumentNotification\n");
359+
360+
auto textDocument = notification.params().textDocument();
361+
const auto uri = textDocument.uri();
362+
const auto text = textDocument.text();
363+
const auto version = textDocument.version();
364+
365+
auto doc = std::make_shared<CxxDocument>(cli);
366+
doc->parse(std::move(text), pathFromUri(uri));
367+
documents[uri] = doc;
368+
369+
std::cerr << std::format("Parsed document: {}, reported {} messages\n", uri,
370+
doc->diagnosticsClient.messages.size());
356371
}
357372

358373
void operator()(const DidCloseTextDocumentNotification& notification) {
359374
std::cerr << std::format("Did receive DidCloseTextDocumentNotification\n");
375+
376+
const auto uri = notification.params().textDocument().uri();
377+
documents.erase(uri);
360378
}
361379

362380
void operator()(const DidChangeTextDocumentNotification& notification) {
363381
std::cerr << std::format("Did receive DidChangeTextDocumentNotification\n");
382+
383+
const auto textDocument = notification.params().textDocument();
384+
const auto uri = textDocument.uri();
385+
const auto version = textDocument.version();
386+
387+
if (!documents.contains(uri)) {
388+
std::cerr << std::format("Document not found: {}\n", uri);
389+
return;
390+
}
391+
392+
// update the document
393+
auto contentChanges = notification.params().contentChanges();
394+
const std::size_t contentChangeCount = contentChanges.size();
395+
for (std::size_t i = 0; i < contentChangeCount; ++i) {
396+
auto change = contentChanges.at(i);
397+
if (std::holds_alternative<TextDocumentContentChangeWholeDocument>(
398+
change)) {
399+
auto text =
400+
std::get<TextDocumentContentChangeWholeDocument>(change).text();
401+
402+
// parse the document
403+
auto doc = std::make_shared<CxxDocument>(cli);
404+
doc->parse(std::move(text), pathFromUri(uri));
405+
documents[uri] = doc;
406+
407+
std::cerr << std::format("Parsed document: {}, reported {} messages\n",
408+
uri, doc->diagnosticsClient.messages.size());
409+
}
410+
}
411+
}
412+
413+
[[nodiscard]] auto pathFromUri(const std::string& uri) -> std::string {
414+
if (uri.starts_with("file://")) {
415+
return uri.substr(7);
416+
}
417+
418+
lsp_runtime_error(std::format("Unsupported URI scheme: {}\n", uri));
364419
}
365420

366421
//
@@ -374,6 +429,9 @@ class Server {
374429
InitializeResult result(storage);
375430
result.serverInfo<ServerInfo>().name("cxx-lsp").version(CXX_VERSION);
376431
result.capabilities().textDocumentSync(TextDocumentSyncKind::kFull);
432+
result.capabilities().diagnosticProvider<DiagnosticOptions>().identifier(
433+
"cxx-lsp");
434+
// .workspaceDiagnostics(true);
377435

378436
sendToClient(result, request.id());
379437
});
@@ -388,6 +446,37 @@ class Server {
388446
});
389447
}
390448

449+
void operator()(const DocumentDiagnosticRequest& request) {
450+
std::cerr << std::format("Did receive DocumentDiagnosticRequest\n");
451+
452+
auto textDocument = request.params().textDocument();
453+
auto uri = textDocument.uri();
454+
455+
if (!documents.contains(uri)) {
456+
std::cerr << std::format("Document not found: {}\n", uri);
457+
return;
458+
}
459+
460+
auto doc = documents[uri];
461+
462+
withUnsafeJson([&](json storage) {
463+
FullDocumentDiagnosticReport report(storage);
464+
465+
auto diagnostics = Vector<Diagnostic>(doc->diagnosticsClient.messages);
466+
report.items(diagnostics);
467+
468+
// TODO: string literals in C++ LSP API
469+
storage["kind"] = "full";
470+
471+
// TODO: responses in C++ LSP API
472+
json response;
473+
response["jsonrpc"] = "2.0";
474+
response["id"] = std::get<long>(*request.id());
475+
response["result"] = report;
476+
sendToClient(response);
477+
});
478+
}
479+
391480
//
392481
// Other requests
393482
//
@@ -408,7 +497,7 @@ class Server {
408497
};
409498

410499
int startServer(const CLI& cli) {
411-
Server server;
500+
Server server{cli};
412501
auto exitCode = server.start();
413502
return exitCode;
414503
}

0 commit comments

Comments
 (0)