incoming_messages.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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/incoming_messages.h"
  5. #include "toolchain/language_server/handle.h"
  6. namespace Carbon::LanguageServer {
  7. // Parses a JSON value into a specific parameter type. The name of the method is
  8. // used when producing errors.
  9. template <typename ParamsT>
  10. inline auto Parse(llvm::StringRef name, const llvm::json::Value& raw_params)
  11. -> llvm::Expected<ParamsT> {
  12. ParamsT params;
  13. llvm::json::Path::Root root;
  14. if (!clang::clangd::fromJSON(raw_params, params, root)) {
  15. return llvm::make_error<clang::clangd::LSPError>(
  16. llvm::formatv("in call to `{0}`, JSON parse failed: {1}", name,
  17. llvm::fmt_consume(root.getError())),
  18. clang::clangd::ErrorCode::InvalidParams);
  19. }
  20. return std::move(params);
  21. }
  22. template <typename ParamsT, typename ResultT>
  23. auto IncomingMessages::AddCallHandler(
  24. llvm::StringRef name,
  25. void (*handler)(Context&, const ParamsT&,
  26. llvm::function_ref<void(llvm::Expected<ResultT>)>))
  27. -> void {
  28. CallHandler parsing_handler =
  29. [name, handler](
  30. Context& context, llvm::json::Value raw_params,
  31. llvm::function_ref<void(llvm::Expected<llvm::json::Value>)> on_done)
  32. -> void {
  33. auto params = Parse<ParamsT>(name, raw_params);
  34. if (!params) {
  35. on_done(params.takeError());
  36. return;
  37. }
  38. handler(context, *params, on_done);
  39. };
  40. auto result = call_handlers_.Insert(name, parsing_handler);
  41. CARBON_CHECK(result.is_inserted(), "Duplicate handler: {0}", name);
  42. }
  43. template <typename ParamsT>
  44. auto IncomingMessages::AddNotificationHandler(llvm::StringRef name,
  45. void (*handler)(Context&,
  46. const ParamsT&))
  47. -> void {
  48. NotificationHandler parsing_handler =
  49. [name, handler](Context& context, llvm::json::Value raw_params) -> void {
  50. auto params = Parse<ParamsT>(name, raw_params);
  51. if (!params) {
  52. // TODO: Maybe we should do something more with this error?
  53. llvm::consumeError(params.takeError());
  54. }
  55. handler(context, *params);
  56. };
  57. auto result = notification_handlers_.Insert(name, parsing_handler);
  58. CARBON_CHECK(result.is_inserted(), "Duplicate handler: {0}", name);
  59. }
  60. IncomingMessages::IncomingMessages(clang::clangd::Transport* transport,
  61. Context* context)
  62. : transport_(transport), context_(context) {
  63. AddCallHandler("textDocument/documentSymbol", &HandleDocumentSymbol);
  64. AddCallHandler("initialize", &HandleInitialize);
  65. AddNotificationHandler("textDocument/didChange",
  66. &HandleDidChangeTextDocument);
  67. AddNotificationHandler("textDocument/didOpen", &HandleDidOpenTextDocument);
  68. }
  69. auto IncomingMessages::onCall(llvm::StringRef name, llvm::json::Value params,
  70. llvm::json::Value id) -> bool {
  71. if (auto result = call_handlers_.Lookup(name)) {
  72. (result.value())(*context_, std::move(params),
  73. [&](llvm::Expected<llvm::json::Value> reply) {
  74. transport_->reply(id, std::move(reply));
  75. });
  76. } else {
  77. transport_->reply(id, llvm::make_error<clang::clangd::LSPError>(
  78. llvm::formatv("call `{0}` not found", name),
  79. clang::clangd::ErrorCode::MethodNotFound));
  80. }
  81. return true;
  82. }
  83. auto IncomingMessages::onNotify(llvm::StringRef name, llvm::json::Value value)
  84. -> bool {
  85. if (name == "exit") {
  86. return false;
  87. }
  88. if (auto result = notification_handlers_.Lookup(name)) {
  89. (result.value())(*context_, std::move(value));
  90. } else {
  91. clang::clangd::log("notification `{0}` not found", name);
  92. }
  93. return true;
  94. }
  95. } // namespace Carbon::LanguageServer