language_server.cpp 3.0 KB

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