4141#include < format>
4242#include < iostream>
4343#include < set>
44+ #include < unordered_map>
4445#include < vector>
4546
4647namespace 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
275276class 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
410499int startServer (const CLI& cli) {
411- Server server;
500+ Server server{cli} ;
412501 auto exitCode = server.start ();
413502 return exitCode;
414503}
0 commit comments