language_server.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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. Diagnostics::Consumer& 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. OutgoingMessages outgoing(transport.get());
  51. Context context(vlog_stream, &consumer, &outgoing);
  52. IncomingMessages incoming(transport.get(), &context);
  53. // Run the server loop.
  54. llvm::Error err = transport->loop(incoming);
  55. if (err) {
  56. RawStringOstream out;
  57. out << err;
  58. CARBON_DIAGNOSTIC(LanguageServerTransportError, Error, "{0}", std::string);
  59. Diagnostics::NoLocEmitter emitter(&consumer);
  60. emitter.Emit(LanguageServerTransportError, out.TakeStr());
  61. return false;
  62. }
  63. return true;
  64. }
  65. } // namespace Carbon::LanguageServer