nixd
Loading...
Searching...
No Matches
LSPServer.cpp
Go to the documentation of this file.
4
5#include <llvm/ADT/FunctionExtras.h>
6#include <llvm/Support/Compiler.h>
7#include <llvm/Support/Error.h>
8#include <llvm/Support/JSON.h>
9
10#include <mutex>
11#include <stdexcept>
12
13namespace lspserver {
14
15void LSPServer::run() { In->loop(*this); }
16
17bool LSPServer::onNotify(llvm::StringRef Method, llvm::json::Value Params) {
18 log("<-- {0}", Method);
19 if (Method == "exit")
20 return false;
23 Handler->second(std::move(Params));
24 } else {
25 log("unhandled notification {0}", Method);
26 }
27 return true;
28}
29
30bool LSPServer::onCall(llvm::StringRef Method, llvm::json::Value Params,
31 llvm::json::Value ID) {
32 log("<-- {0}({1})", Method, ID);
34 if (Handler != Registry.MethodHandlers.end())
35 Handler->second(std::move(Params),
36 [=, Method = std::string(Method),
37 this](llvm::Expected<llvm::json::Value> Response) mutable {
38 if (Response) {
39 log("--> reply:{0}({1})", Method, ID);
40 Out->reply(std::move(ID), std::move(Response));
41 } else {
42 llvm::Error Err = Response.takeError();
43 log("--> reply:{0}({1}) {2:ms}, error: {3}", Method, ID,
44 Err);
45 Out->reply(std::move(ID), std::move(Err));
46 }
47 });
48 else
49 return false;
50 return true;
51}
52
53bool LSPServer::onReply(llvm::json::Value ID,
54 llvm::Expected<llvm::json::Value> Result) {
55 log("<-- reply({0})", ID);
56 std::optional<Callback<llvm::json::Value>> CB;
57
58 if (auto OptI = ID.getAsInteger()) {
60 throw std::logic_error("jsonrpc: id is too large (> INT_MAX)");
61 std::lock_guard<std::mutex> Guard(PendingCallsLock);
62 auto I = static_cast<int>(*OptI);
63 if (PendingCalls.contains(I)) {
64 CB = std::move(PendingCalls[I]);
65 PendingCalls.erase(I);
66 }
67 } else {
68 throw std::logic_error("jsonrpc: not an integer message ID");
69 }
70 if (LLVM_UNLIKELY(!CB)) {
71 elog("received a reply with ID {0}, but there was no such call", ID);
72 // Ignore this error
73 return true;
74 }
75 // Invoke the callback outside of the critical zone, because we just do not
76 // need to lock PendingCalls.
77 (*CB)(std::move(Result));
78 return true;
79}
80
81int LSPServer::bindReply(Callback<llvm::json::Value> CB) {
82 std::lock_guard<std::mutex> _(PendingCallsLock);
83 int Ret = TopID++;
84 PendingCalls[Ret] = std::move(CB);
85
86 // Check the limit
87 if (PendingCalls.size() > MaxPendingCalls) {
88 auto Begin = PendingCalls.begin();
89 auto [ID, OldestCallback] =
90 std::tuple{Begin->first, std::move(Begin->second)};
92 error("failed to receive a client reply for request ({0})", ID));
93 elog("more than {0} outstanding LSP calls, forgetting about {1}",
94 MaxPendingCalls, ID);
95 PendingCalls.erase(Begin);
96 }
97 return Ret;
98}
99
100} // namespace lspserver
HandlerRegistry Registry
Definition LSPServer.h:55
Whether current platform treats paths case insensitively.
Definition Connection.h:11
llvm::Error error(std::error_code EC, const char *Fmt, Ts &&...Vals)
Definition Logger.h:70
bool fromJSON(const llvm::json::Value &, URIForFile &, llvm::json::Path)
void elog(const char *Fmt, Ts &&...Vals)
Definition Logger.h:52
void log(const char *Fmt, Ts &&...Vals)
Definition Logger.h:58
HandlerMap< void(JSON)> NotificationHandlers
Definition LSPBinder.h:47
HandlerMap< void(JSON, Callback< JSON >)> MethodHandlers
Definition LSPBinder.h:48