language_server.cpp 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/language_server/language_server.h"
  5. #include "clang-tools-extra/clangd/LSPBinder.h"
  6. #include "clang-tools-extra/clangd/Transport.h"
  7. #include "clang-tools-extra/clangd/support/Logger.h"
  8. #include "common/raw_string_ostream.h"
  9. #include "toolchain/diagnostics/diagnostic_emitter.h"
  10. #include "toolchain/language_server/context.h"
  11. #include "toolchain/language_server/incoming_messages.h"
  12. #include "toolchain/language_server/outgoing_messages.h"
  13. namespace Carbon::LanguageServer {
  14. // An adapter for clangd's logging that sends most messages to `error_stream`.
  15. // Verbose logging is only printed if `vlog_stream` is provided, and will be
  16. // sent there.
  17. class Logger : public clang::clangd::Logger {
  18. public:
  19. explicit Logger(llvm::raw_ostream* error_stream,
  20. llvm::raw_ostream* vlog_stream)
  21. : error_logger_(*error_stream, clang::clangd::Logger::Info),
  22. vlog_logger_(vlog_stream
  23. ? std::make_unique<clang::clangd::StreamLogger>(
  24. *vlog_stream, clang::clangd::Logger::Verbose)
  25. : nullptr) {}
  26. auto log(Level level, const char* format,
  27. const llvm::formatv_object_base& message) -> void override {
  28. if (level != clang::clangd::Logger::Verbose) {
  29. error_logger_.log(level, format, message);
  30. } else if (vlog_logger_) {
  31. vlog_logger_->log(level, format, message);
  32. }
  33. }
  34. private:
  35. clang::clangd::StreamLogger error_logger_;
  36. std::unique_ptr<clang::clangd::StreamLogger> vlog_logger_;
  37. };
  38. auto Run(FILE* input_stream, llvm::raw_ostream& output_stream,
  39. llvm::raw_ostream& error_stream, llvm::raw_ostream* vlog_stream,
  40. DiagnosticConsumer& consumer) -> bool {
  41. // The language server internally uses diagnostics for logging issues, but the
  42. // clangd parts have their own logging system. We intercept that here.
  43. Logger logger(&error_stream, vlog_stream);
  44. clang::clangd::LoggingSession logging_session(logger);
  45. // Set up the connection.
  46. std::unique_ptr<clang::clangd::Transport> transport(
  47. clang::clangd::newJSONTransport(input_stream, output_stream,
  48. /*InMirror=*/nullptr,
  49. /*Pretty=*/true));
  50. Context context(&consumer);
  51. // TODO: Use error_stream in IncomingMessages to report dropped errors.
  52. IncomingMessages incoming(transport.get(), &context);
  53. OutgoingMessages outgoing(transport.get());
  54. // Run the server loop.
  55. llvm::Error err = transport->loop(incoming);
  56. if (err) {
  57. RawStringOstream out;
  58. out << err;
  59. CARBON_DIAGNOSTIC(LanguageServerTransportError, Error, "{0}", std::string);
  60. NoLocDiagnosticEmitter emitter(&consumer);
  61. emitter.Emit(LanguageServerTransportError, out.TakeStr());
  62. return false;
  63. }
  64. return true;
  65. }
  66. } // namespace Carbon::LanguageServer