language_server.cpp 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  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/diagnostic_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(FILE* input_stream, llvm::raw_ostream& output_stream,
  40. llvm::raw_ostream& error_stream, llvm::raw_ostream* vlog_stream,
  41. Diagnostics::Consumer& consumer) -> bool {
  42. // The language server internally uses diagnostics for logging issues, but the
  43. // clangd parts have their own logging system. We intercept that here.
  44. Logger logger(&error_stream, vlog_stream);
  45. clang::clangd::LoggingSession logging_session(logger);
  46. // Set up the connection.
  47. std::unique_ptr<clang::clangd::Transport> transport(
  48. clang::clangd::newJSONTransport(input_stream, output_stream,
  49. /*InMirror=*/nullptr,
  50. /*Pretty=*/true));
  51. OutgoingMessages outgoing(transport.get());
  52. Context context(vlog_stream, &consumer, &outgoing);
  53. IncomingMessages incoming(transport.get(), &context);
  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. Diagnostics::NoLocEmitter emitter(&consumer);
  61. emitter.Emit(LanguageServerTransportError, out.TakeStr());
  62. return false;
  63. }
  64. return true;
  65. }
  66. } // namespace Carbon::LanguageServer