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