Files
carbon-lang/toolchain/language_server/language_server.cpp
T
Jon Ross-Perkins 9e466b9335 Cache calculated file state in LSP (#4897)
Add caching of parsed documents, and testing of the textDocument
handlers. This is based on #4896, which splits out some of the
boilerplate to calls.

Note, this caches the entire parse state because we'll want to try to
emit diagnostics when we see the update, without waiting. It may be
helpful to do that asynchronously, but we don't want to wait for another
call (such as documentSymbol). Really, we'll probably want to also add
check for diagnostics, at least.
2025-02-07 01:04:42 +00:00

77 lines
3.0 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/language_server/language_server.h"
#include "clang-tools-extra/clangd/LSPBinder.h"
#include "clang-tools-extra/clangd/Transport.h"
#include "clang-tools-extra/clangd/support/Logger.h"
#include "common/raw_string_ostream.h"
#include "toolchain/diagnostics/diagnostic_emitter.h"
#include "toolchain/language_server/context.h"
#include "toolchain/language_server/incoming_messages.h"
#include "toolchain/language_server/outgoing_messages.h"
namespace Carbon::LanguageServer {
// An adapter for clangd's logging that sends most messages to `error_stream`.
// Verbose logging is only printed if `vlog_stream` is provided, and will be
// sent there.
class Logger : public clang::clangd::Logger {
public:
explicit Logger(llvm::raw_ostream* error_stream,
llvm::raw_ostream* vlog_stream)
: error_logger_(*error_stream, clang::clangd::Logger::Info),
vlog_logger_(vlog_stream
? std::make_unique<clang::clangd::StreamLogger>(
*vlog_stream, clang::clangd::Logger::Verbose)
: nullptr) {}
auto log(Level level, const char* format,
const llvm::formatv_object_base& message) -> void override {
if (level != clang::clangd::Logger::Verbose) {
error_logger_.log(level, format, message);
} else if (vlog_logger_) {
vlog_logger_->log(level, format, message);
}
}
private:
clang::clangd::StreamLogger error_logger_;
std::unique_ptr<clang::clangd::StreamLogger> vlog_logger_;
};
auto Run(FILE* input_stream, llvm::raw_ostream& output_stream,
llvm::raw_ostream& error_stream, llvm::raw_ostream* vlog_stream,
DiagnosticConsumer& consumer) -> bool {
// The language server internally uses diagnostics for logging issues, but the
// clangd parts have their own logging system. We intercept that here.
Logger logger(&error_stream, vlog_stream);
clang::clangd::LoggingSession logging_session(logger);
// Set up the connection.
std::unique_ptr<clang::clangd::Transport> transport(
clang::clangd::newJSONTransport(input_stream, output_stream,
/*InMirror=*/nullptr,
/*Pretty=*/true));
Context context(vlog_stream, &consumer);
// TODO: Use error_stream in IncomingMessages to report dropped errors.
IncomingMessages incoming(transport.get(), &context);
OutgoingMessages outgoing(transport.get());
// Run the server loop.
llvm::Error err = transport->loop(incoming);
if (err) {
RawStringOstream out;
out << err;
CARBON_DIAGNOSTIC(LanguageServerTransportError, Error, "{0}", std::string);
NoLocDiagnosticEmitter emitter(&consumer);
emitter.Emit(LanguageServerTransportError, out.TakeStr());
return false;
}
return true;
}
} // namespace Carbon::LanguageServer