11using json = nlohmann::json;
15 size_t contentLength = 0;
20 if (!std::getline(std::cin, line))
23 if (!line.empty() && line.back() ==
'\r')
29 const std::string prefix =
"Content-Length: ";
30 if (line.rfind(prefix, 0) == 0)
31 contentLength = std::stoull(line.substr(prefix.size()));
34 if (contentLength == 0)
37 std::string body(contentLength,
'\0');
38 std::cin.read(body.data(),
static_cast<std::streamsize
>(contentLength));
44 const std::string body = msg.dump();
45 std::cout <<
"Content-Length: " << body.size() <<
"\r\n\r\n" << body;
51 return {{
"jsonrpc",
"2.0"}, {
"id",
id}, {
"result", std::move(result)}};
56 return {{
"jsonrpc",
"2.0"}, {
"id",
id}, {
"error", {{
"code", code}, {
"message", message}}}};
61 return {{
"jsonrpc",
"2.0"}, {
"method", method}, {
"params", std::move(params)}};
64static void publishDiagnostics(
const std::string &uri,
const std::vector<Phasor::LSP::Diagnostic> &diags)
66 json arr = json::array();
67 for (
const auto &d : diags)
69 arr.push_back({{
"range",
70 {{
"start", {{
"line", d.startLine}, {
"character", d.startColumn}}},
71 {
"end", {{
"line", d.endLine}, {
"character", d.endColumn}}}}},
73 {
"message", d.message}});
80 return {{
"start", {{
"line", line}, {
"character", col}}}, {
"end", {{
"line", line}, {
"character", col + 1}}}};
85 return {{
"capabilities", {
86 {
"textDocumentSync", 1},
87 {
"hoverProvider",
true},
88 {
"definitionProvider",
true}}},
89 {
"serverInfo", {{
"name",
"phasor-lsp"}, {
"version",
"0.1.0"}}}};
94 const std::string uri = params[
"textDocument"][
"uri"];
95 const size_t line = params[
"position"][
"line"];
96 const size_t col = params[
"position"][
"character"];
98 auto text = lsp.
getHover(uri, line, col);
99 if (!text.has_value())
103 {{
"kind",
"markdown"},
104 {
"value",
"```phasor\n" + *text +
"\n```"}}},
110 const std::string uri = params[
"textDocument"][
"uri"];
111 const size_t line = params[
"position"][
"line"];
112 const size_t col = params[
"position"][
"character"];
115 if (!loc.has_value())
118 return {{
"uri", loc->uri}, {
"range",
makePointRange(loc->line, loc->column)}};
124 _setmode(_fileno(stdout), _O_BINARY);
125 _setmode(_fileno(stdin), _O_BINARY);
127 std::ios::sync_with_stdio(
false);
141 msg = json::parse(raw);
143 catch (
const json::parse_error &e)
149 const bool isRequest = msg.contains(
"id");
150 const json id = isRequest ? msg[
"id"] :
json(
nullptr);
151 const std::string method = msg.value(
"method",
"");
152 const json ¶ms = msg.contains(
"params") ? msg[
"params"] :
json(
nullptr);
154 if (method ==
"initialize")
158 else if (method ==
"initialized")
161 else if (method ==
"shutdown")
166 else if (method ==
"exit")
171 else if (method ==
"textDocument/didOpen")
173 const std::string uri = params[
"textDocument"][
"uri"];
174 const std::string text = params[
"textDocument"][
"text"];
178 else if (method ==
"textDocument/didChange")
180 const std::string uri = params[
"textDocument"][
"uri"];
181 if (params.contains(
"contentChanges") && !params[
"contentChanges"].empty())
183 const std::string text = params[
"contentChanges"][0][
"text"];
188 else if (method ==
"textDocument/didClose")
190 const std::string uri = params[
"textDocument"][
"uri"];
195 else if (method ==
"textDocument/hover")
200 else if (method ==
"textDocument/definition")
static json handleDefinition(Phasor::LSP &lsp, const json ¶ms)
static void writeMessage(const json &msg)
static json handleHover(Phasor::LSP &lsp, const json ¶ms)
static json handleInitialize(const json &)
static std::string readMessage()
static json makeError(const json &id, int code, const std::string &message)
static json makePointRange(size_t line, size_t col)
static json makeNotification(const std::string &method, json params)
static json makeResponse(const json &id, json result)
static void publishDiagnostics(const std::string &uri, const std::vector< Phasor::LSP::Diagnostic > &diags)
std::optional< Location > getDefinition(const std::string &uri, size_t line, size_t column)
void openDocument(const std::string &uri, const std::string &text)
void closeDocument(const std::string &uri)
std::vector< Diagnostic > getDiagnostics(const std::string &uri) const
std::optional< std::string > getHover(const std::string &uri, size_t line, size_t column)
void changeDocument(const std::string &uri, const std::string &newText)