5#include <llvm/ADT/SmallString.h>
6#include <llvm/Support/CommandLine.h>
17#include <system_error>
21llvm::cl::opt<int> ClientProcessID{
24 "Client process ID, if this PID died, the server should exit."),
25 llvm::cl::init(getppid())};
31static llvm::json::Object encodeError(llvm::Error
Error) {
34 auto HandlerFn = [&](
const LSPError &E) -> llvm::Error {
37 return llvm::Error::success();
39 if (llvm::Error Unhandled = llvm::handleErrors(std::move(
Error), HandlerFn))
40 Message = llvm::toString(std::move(Unhandled));
42 return llvm::json::Object{
43 {
"message", std::move(Message)},
44 {
"code", int64_t(Code)},
50 llvm::StringRef Message =
51 O.getString(
"message").value_or(
"Unspecified error");
52 if (std::optional<int64_t> Code = O.getInteger(
"code"))
53 return llvm::make_error<LSPError>(Message.str(),
ErrorCode(*Code));
54 return llvm::make_error<llvm::StringError>(llvm::inconvertibleErrorCode(),
62 {
"params", std::move(Params)},
66 llvm::json::Value ID) {
69 {
"id", std::move(ID)},
71 {
"params", std::move(Params)},
75 llvm::Expected<llvm::json::Value> Result) {
79 {
"id", std::move(ID)},
80 {
"result", std::move(*Result)},
85 {
"id", std::move(ID)},
86 {
"error", encodeError(Result.takeError())},
93 vlog(
">>> {0}", Message);
94 std::lock_guard<std::mutex> Guard(Mutex);
96 llvm::raw_svector_ostream SVecOS(OutputBuffer);
97 SVecOS << (Pretty ? llvm::formatv(
"{0:2}", Message)
98 : llvm::formatv(
"{0}", Message));
99 Outs <<
"Content-Length: " << OutputBuffer.size() <<
"\r\n\r\n"
106 auto *
Object = Message.getAsObject();
108 Object->getString(
"jsonrpc") != std::optional<llvm::StringRef>(
"2.0")) {
109 elog(
"Not a JSON-RPC 2.0 message: {0:2}", Message);
113 std::optional<llvm::json::Value> ID;
114 if (
auto *I =
Object->get(
"id"))
119 elog(
"No method and no response ID: {0:2}", Message);
122 if (
auto *Err =
Object->getObject(
"error"))
126 llvm::json::Value Result =
nullptr;
127 if (
auto *R =
Object->get(
"result"))
128 Result = std::move(*R);
129 return Handler.
onReply(std::move(*ID), std::move(Result));
132 llvm::json::Value Params =
nullptr;
133 if (
auto *P =
Object->get(
"params"))
134 Params = std::move(*P);
137 return Handler.
onCall(*
Method, std::move(Params), std::move(*ID));
141bool readLine(
int fd,
const std::atomic<bool> &Close,
142 llvm::SmallString<128> &Line) {
145 std::vector<pollfd> FDs;
146 FDs.emplace_back(pollfd{
154 int Poll = poll(FDs.data(), FDs.size(), 1000);
162 if (FDs[0].revents & (POLLHUP | POLLNVAL)) {
166 if (FDs[0].revents & POLLIN) {
167 ssize_t BytesRead = read(fd, &Ch, 1);
168 if (BytesRead == -1) {
171 }
else if (BytesRead == 0)
180 if (kill(ClientProcessID, 0) < 0) {
188 unsigned long long ContentLength = 0;
189 llvm::SmallString<128> Line;
194 llvm::StringRef LineRef = Line;
197 if (LineRef.consume_front(
"Content-Length: ")) {
198 llvm::getAsUnsignedInteger(LineRef.trim(), 0, ContentLength);
203 if (LineRef.trim().empty())
208 JSONString.resize(ContentLength);
209 for (
size_t Pos = 0,
Read; Pos < ContentLength; Pos +=
Read) {
211 Read = read(
In, JSONString.data() + Pos, ContentLength - Pos);
214 elog(
"Input was aborted. Read only {0} bytes of expected {1}.", Pos,
224 llvm::SmallString<128> Line;
225 bool IsInputBlock =
false;
227 auto LineRef = Line.str().trim();
230 if (LineRef.starts_with(
"#"))
234 if (LineRef.starts_with(
"```")) {
235 IsInputBlock =
false;
241 if (LineRef.starts_with(
"```json"))
257 assert(
false &&
"Invalid stream style");
258 __builtin_unreachable();
262 std::string JSONString;
263 llvm::SmallString<128> Line;
267 vlog(
"<<< {0}", JSONString);
268 if (
auto ExpectedParsedJSON = llvm::json::parse(JSONString)) {
269 if (!
dispatch(*ExpectedParsedJSON, Handler))
272 auto Err = ExpectedParsedJSON.takeError();
273 elog(
"The received json cannot be parsed, reason: {0}", Err);
bool dispatch(llvm::json::Value Message, MessageHandler &Handler)
JSONStreamStyle StreamStyle
bool readStandardMessage(std::string &JSONString)
bool readMessage(std::string &JSONString)
bool readDelimitedMessage(std::string &JSONString)
void loop(MessageHandler &Handler)
virtual bool onReply(llvm::json::Value ID, llvm::Expected< llvm::json::Value > Result)=0
virtual bool onNotify(llvm::StringRef Method, llvm::json::Value)=0
virtual bool onCall(llvm::StringRef Method, llvm::json::Value Params, llvm::json::Value ID)=0
void sendMessage(llvm::json::Value Message)
void notify(llvm::StringRef Method, llvm::json::Value Params)
void reply(llvm::json::Value ID, llvm::Expected< llvm::json::Value > Result)
void call(llvm::StringRef Method, llvm::json::Value Params, llvm::json::Value ID)
Whether current platform treats paths case insensitively.
llvm::Error decodeError(const llvm::json::Object &O)
Decode the given JSON object into an error.
void elog(const char *Fmt, Ts &&...Vals)
void vlog(const char *Fmt, Ts &&...Vals)
bool readLine(int fd, const std::atomic< bool > &Close, llvm::SmallString< 128 > &Line)