mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-30 06:35:01 +01:00
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.
77 lines
3.0 KiB
C++
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
|