Phasor 3.1.1
Stack VM based Programming Language
Loading...
Searching...
No Matches
LSP_main.cpp
Go to the documentation of this file.
2#include <json.hpp>
3#include <string>
4#include <stdexcept>
5#include <nativeerror.h>
6#ifdef _WIN32
7#include <io.h>
8#include <fcntl.h>
9#endif
10
11using json = nlohmann::json;
12
13static std::string readMessage()
14{
15 size_t contentLength = 0;
16
17 while (true)
18 {
19 std::string line;
20 if (!std::getline(std::cin, line))
21 return "";
22
23 if (!line.empty() && line.back() == '\r')
24 line.pop_back();
25
26 if (line.empty())
27 break;
28
29 const std::string prefix = "Content-Length: ";
30 if (line.rfind(prefix, 0) == 0)
31 contentLength = std::stoull(line.substr(prefix.size()));
32 }
33
34 if (contentLength == 0)
35 return "";
36
37 std::string body(contentLength, '\0');
38 std::cin.read(body.data(), static_cast<std::streamsize>(contentLength));
39 return body;
40}
41
42static void writeMessage(const json &msg)
43{
44 const std::string body = msg.dump();
45 std::cout << "Content-Length: " << body.size() << "\r\n\r\n" << body;
46 std::cout.flush();
47}
48
49static json makeResponse(const json &id, json result)
50{
51 return {{"jsonrpc", "2.0"}, {"id", id}, {"result", std::move(result)}};
52}
53
54static json makeError(const json &id, int code, const std::string &message)
55{
56 return {{"jsonrpc", "2.0"}, {"id", id}, {"error", {{"code", code}, {"message", message}}}};
57}
58
59static json makeNotification(const std::string &method, json params)
60{
61 return {{"jsonrpc", "2.0"}, {"method", method}, {"params", std::move(params)}};
62}
63
64static void publishDiagnostics(const std::string &uri, const std::vector<Phasor::LSP::Diagnostic> &diags)
65{
66 json arr = json::array();
67 for (const auto &d : diags)
68 {
69 arr.push_back({{"range",
70 {{"start", {{"line", d.startLine}, {"character", d.startColumn}}},
71 {"end", {{"line", d.endLine}, {"character", d.endColumn}}}}},
72 {"severity", 1},
73 {"message", d.message}});
74 }
75 writeMessage(makeNotification("textDocument/publishDiagnostics", {{"uri", uri}, {"diagnostics", arr}}));
76}
77
78static json makePointRange(size_t line, size_t col)
79{
80 return {{"start", {{"line", line}, {"character", col}}}, {"end", {{"line", line}, {"character", col + 1}}}};
81}
82
83static json handleInitialize(const json &)
84{
85 return {{"capabilities", {
86 {"textDocumentSync", 1},
87 {"hoverProvider", true},
88 {"definitionProvider", true}}},
89 {"serverInfo", {{"name", "phasor-lsp"}, {"version", "0.1.0"}}}};
90}
91
92static json handleHover(Phasor::LSP &lsp, const json &params)
93{
94 const std::string uri = params["textDocument"]["uri"];
95 const size_t line = params["position"]["line"];
96 const size_t col = params["position"]["character"];
97
98 auto text = lsp.getHover(uri, line, col);
99 if (!text.has_value())
100 return nullptr;
101
102 return {{"contents",
103 {{"kind", "markdown"},
104 {"value", "```phasor\n" + *text + "\n```"}}},
105 {"range", makePointRange(line, col)}};
106}
107
108static json handleDefinition(Phasor::LSP &lsp, const json &params)
109{
110 const std::string uri = params["textDocument"]["uri"];
111 const size_t line = params["position"]["line"];
112 const size_t col = params["position"]["character"];
113
114 auto loc = lsp.getDefinition(uri, line, col);
115 if (!loc.has_value())
116 return nullptr;
117
118 return {{"uri", loc->uri}, {"range", makePointRange(loc->line, loc->column)}};
119}
120
121int main()
122{
123#ifdef _WIN32
124 _setmode(_fileno(stdout), _O_BINARY);
125 _setmode(_fileno(stdin), _O_BINARY);
126#endif
127 std::ios::sync_with_stdio(false);
128
129 Phasor::LSP lsp;
130 bool running = true;
131
132 while (running)
133 {
134 const std::string raw = readMessage();
135 if (raw.empty())
136 break;
137
138 json msg;
139 try
140 {
141 msg = json::parse(raw);
142 }
143 catch (const json::parse_error &e)
144 {
145 writeMessage(makeError(nullptr, -32700, "JSON parse error: " + std::string(e.what())));
146 continue;
147 }
148
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 &params = msg.contains("params") ? msg["params"] : json(nullptr);
153
154 if (method == "initialize")
155 {
157 }
158 else if (method == "initialized")
159 {
160 }
161 else if (method == "shutdown")
162 {
163 writeMessage(makeResponse(id, nullptr));
164 running = false;
165 }
166 else if (method == "exit")
167 {
168 break;
169 }
170
171 else if (method == "textDocument/didOpen")
172 {
173 const std::string uri = params["textDocument"]["uri"];
174 const std::string text = params["textDocument"]["text"];
175 lsp.openDocument(uri, text);
176 publishDiagnostics(uri, lsp.getDiagnostics(uri));
177 }
178 else if (method == "textDocument/didChange")
179 {
180 const std::string uri = params["textDocument"]["uri"];
181 if (params.contains("contentChanges") && !params["contentChanges"].empty())
182 {
183 const std::string text = params["contentChanges"][0]["text"];
184 lsp.changeDocument(uri, text);
185 publishDiagnostics(uri, lsp.getDiagnostics(uri));
186 }
187 }
188 else if (method == "textDocument/didClose")
189 {
190 const std::string uri = params["textDocument"]["uri"];
191 lsp.closeDocument(uri);
192 publishDiagnostics(uri, {});
193 }
194
195 else if (method == "textDocument/hover")
196 {
197 writeMessage(makeResponse(id, handleHover(lsp, params)));
198 }
199
200 else if (method == "textDocument/definition")
201 {
202 writeMessage(makeResponse(id, handleDefinition(lsp, params)));
203 }
204 else if (isRequest)
205 {
206 writeMessage(makeError(id, -32601, "Method not found: " + method));
207 }
208 }
209
210 return 0;
211}
static json handleDefinition(Phasor::LSP &lsp, const json &params)
Definition LSP_main.cpp:108
static void writeMessage(const json &msg)
Definition LSP_main.cpp:42
static json handleHover(Phasor::LSP &lsp, const json &params)
Definition LSP_main.cpp:92
static json handleInitialize(const json &)
Definition LSP_main.cpp:83
static std::string readMessage()
Definition LSP_main.cpp:13
static json makeError(const json &id, int code, const std::string &message)
Definition LSP_main.cpp:54
static json makePointRange(size_t line, size_t col)
Definition LSP_main.cpp:78
nlohmann::json json
Definition LSP_main.cpp:11
int main()
Definition LSP_main.cpp:121
static json makeNotification(const std::string &method, json params)
Definition LSP_main.cpp:59
static json makeResponse(const json &id, json result)
Definition LSP_main.cpp:49
static void publishDiagnostics(const std::string &uri, const std::vector< Phasor::LSP::Diagnostic > &diags)
Definition LSP_main.cpp:64
std::optional< Location > getDefinition(const std::string &uri, size_t line, size_t column)
Definition LSP.cpp:143
void openDocument(const std::string &uri, const std::string &text)
Definition LSP.cpp:71
void closeDocument(const std::string &uri)
Definition LSP.cpp:96
std::vector< Diagnostic > getDiagnostics(const std::string &uri) const
Definition LSP.cpp:101
std::optional< std::string > getHover(const std::string &uri, size_t line, size_t column)
Definition LSP.cpp:117
void changeDocument(const std::string &uri, const std::string &newText)
Definition LSP.cpp:80