1use lark_actor::{self, Actor, LspResponse, QueryRequest};
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4use std::collections::VecDeque;
5use std::io;
6use std::io::prelude::{Read, Write};
7use std::sync::mpsc::Sender;
8use url::Url;
9
10#[derive(Debug, Serialize, Deserialize)]
13#[serde(tag = "method")]
14#[allow(non_camel_case_types)]
15pub enum LSPCommand {
16 initialize {
17 id: usize,
18 params: languageserver_types::InitializeParams,
19 },
20 initialized,
21 #[serde(rename = "textDocument/didOpen")]
22 didOpen {
23 params: languageserver_types::DidOpenTextDocumentParams,
24 },
25 #[serde(rename = "textDocument/didChange")]
26 didChange {
27 params: languageserver_types::DidChangeTextDocumentParams,
28 },
29 #[serde(rename = "textDocument/hover")]
30 hover {
31 id: usize,
32 params: languageserver_types::TextDocumentPositionParams,
33 },
34 #[serde(rename = "textDocument/completion")]
35 completion {
36 id: usize,
37 params: languageserver_types::CompletionParams,
38 },
39 #[serde(rename = "textDocument/definition")]
40 definition {
41 id: usize,
42 params: languageserver_types::TextDocumentPositionParams,
43 },
44 #[serde(rename = "textDocument/references")]
45 references {
46 id: usize,
47 params: languageserver_types::TextDocumentPositionParams,
48 },
49 #[serde(rename = "textDocument/rename")]
50 rename {
51 id: usize,
52 params: languageserver_types::RenameParams,
53 },
54 #[serde(rename = "$/cancelRequest")]
55 cancelRequest {
56 params: languageserver_types::CancelParams,
57 },
58 #[serde(rename = "completionItem/resolve")]
59 completionItemResolve {
60 id: usize,
61 params: languageserver_types::CompletionItem,
62 },
63}
64
65#[derive(Debug, Serialize, Deserialize)]
68pub struct JsonRPCResponse<T> {
69 jsonrpc: String,
70 pub id: usize,
71 pub result: T,
72}
73impl<T> JsonRPCResponse<T> {
74 pub fn new(id: usize, result: T) -> Self {
75 JsonRPCResponse {
76 jsonrpc: "2.0".into(),
77 id,
78 result,
79 }
80 }
81}
82
83#[derive(Debug, Serialize, Deserialize)]
86pub struct JsonRPCNotification<T> {
87 jsonrpc: String,
88 pub method: String,
89 pub params: T,
90}
91impl<T> JsonRPCNotification<T> {
92 pub fn new(method: String, params: T) -> Self {
93 JsonRPCNotification {
94 jsonrpc: "2.0".into(),
95 method,
96 params,
97 }
98 }
99}
100
101fn send_response<T: Serialize>(id: usize, result: T) {
103 let response = JsonRPCResponse::new(id, result);
104 let response_raw = serde_json::to_string(&response).unwrap();
105
106 print!("Content-Length: {}\r\n\r\n", response_raw.len());
107 print!("{}", response_raw);
108 let _ = io::stdout().flush();
109}
110
111fn send_notification<T: Serialize>(method: String, notice: T) {
113 let response = JsonRPCNotification::new(method, notice);
114 let response_raw = serde_json::to_string(&response).unwrap();
115
116 print!("Content-Length: {}\r\n\r\n", response_raw.len());
117 print!("{}", response_raw);
118 let _ = io::stdout().flush();
119}
120
121pub struct LspResponder;
128
129impl Actor for LspResponder {
130 type InMessage = LspResponse;
131
132 fn receive_messages(&mut self, messages: &mut VecDeque<Self::InMessage>) {
136 match messages.pop_front().unwrap() {
137 LspResponse::Type(id, ty) => {
138 let result = languageserver_types::Hover {
139 contents: languageserver_types::HoverContents::Scalar(
140 languageserver_types::MarkedString::from_markdown(ty),
141 ),
142 range: None,
143 };
144
145 send_response(id, result);
146 }
147 LspResponse::Range(id, uri, range) => {
148 let result = languageserver_types::Location { uri, range };
149
150 send_response(id, result);
151 }
152 LspResponse::Ranges(id, vec_of_uri_range) => {
153 let result: Vec<languageserver_types::Location> = vec_of_uri_range
154 .into_iter()
155 .map(|x| languageserver_types::Location {
156 uri: x.0,
157 range: x.1,
158 })
159 .collect();
160
161 send_response(id, result);
162 }
163 LspResponse::WorkspaceEdits(id, vec_of_edits) => {
164 let mut map_of_edits: HashMap<Url, Vec<languageserver_types::TextEdit>> =
165 HashMap::new();
166
167 for edit in vec_of_edits.into_iter() {
168 let entry = map_of_edits.entry(edit.0).or_insert(vec![]);
169 (*entry).push(languageserver_types::TextEdit {
170 range: edit.1,
171 new_text: edit.2,
172 });
173 }
174
175 let result = languageserver_types::WorkspaceEdit {
176 changes: Some(map_of_edits),
177 document_changes: None,
178 };
179
180 send_response(id, result);
181 }
182 LspResponse::Nothing(id) => {
183 send_response(id, ());
184 }
185 LspResponse::Completions(id, completions) => {
186 let mut completion_items = vec![];
187
188 for completion in completions {
189 completion_items.push(languageserver_types::CompletionItem::new_simple(
190 completion.0,
191 completion.1,
192 ));
193 }
194
195 let result = languageserver_types::CompletionList {
196 is_incomplete: false,
197 items: completion_items,
198 };
199
200 send_response(id, result);
201 }
202 LspResponse::Initialized(id) => {
203 let result = languageserver_types::InitializeResult {
204 capabilities: languageserver_types::ServerCapabilities {
205 text_document_sync: Some(
206 languageserver_types::TextDocumentSyncCapability::Kind(
207 languageserver_types::TextDocumentSyncKind::Incremental,
208 ),
209 ),
210 hover_provider: Some(true),
211 completion_provider: None,
218 signature_help_provider: None,
219 definition_provider: Some(true),
220 type_definition_provider: None,
221 implementation_provider: None,
222 references_provider: Some(true),
223 document_highlight_provider: None,
224 document_symbol_provider: None,
225 workspace_symbol_provider: None,
226 code_action_provider: None,
227 code_lens_provider: None,
228 document_formatting_provider: None,
229 document_range_formatting_provider: None,
230 document_on_type_formatting_provider: None,
231 rename_provider: Some(
232 languageserver_types::RenameProviderCapability::Simple(true),
233 ),
234 color_provider: None,
235 folding_range_provider: None,
236 execute_command_provider: None,
237 workspace: None,
238 },
239 };
240
241 send_response(id, result);
242 }
243 LspResponse::Diagnostics(url, diagnostics) => {
244 let lsp_diagnostics: Vec<languageserver_types::Diagnostic> = diagnostics
245 .iter()
246 .map(|(range, diag)| {
247 languageserver_types::Diagnostic::new_simple(*range, diag.clone())
248 })
249 .collect();
250
251 let notice = languageserver_types::PublishDiagnosticsParams {
252 uri: url,
253 diagnostics: lsp_diagnostics,
254 };
255
256 send_notification("textDocument/publishDiagnostics".into(), notice);
257 }
258 }
259 }
260}
261
262pub fn lsp_serve(send_to_query_channel: Sender<QueryRequest>) {
266 loop {
267 let mut input = String::new();
268 match io::stdin().read_line(&mut input) {
269 Ok(_) => {
270 let content_length_items: Vec<&str> = input.split(' ').collect();
271 if content_length_items[0] == "Content-Length:" {
272 let num_bytes: usize = content_length_items[1].trim().parse().unwrap();
273 let mut buffer = vec![0u8; num_bytes + 2];
274 let _ = io::stdin().read_exact(&mut buffer);
275
276 let buffer_string = String::from_utf8(buffer).unwrap();
277
278 let command = serde_json::from_str::<LSPCommand>(&buffer_string);
279
280 match command {
281 Ok(LSPCommand::initialize { id, .. }) => {
282 let _ = send_to_query_channel.send(QueryRequest::Initialize(id));
283 }
284 Ok(LSPCommand::initialized) => {
285 }
287 Ok(LSPCommand::didOpen { params }) => {
288 let _ = send_to_query_channel.send(QueryRequest::OpenFile(
291 params.text_document.uri.clone(),
292 params.text_document.text.clone(),
293 ));
294 }
295 Ok(LSPCommand::didChange { params }) => {
296 let changes = params
299 .content_changes
300 .iter()
301 .map(|x| (x.range.unwrap(), x.text.clone()))
302 .collect();
303
304 let _ = send_to_query_channel.send(QueryRequest::EditFile(
305 params.text_document.uri.clone(),
306 changes,
307 ));
308 }
309 Ok(LSPCommand::hover { id, params }) => {
310 let _ = send_to_query_channel.send(QueryRequest::TypeAtPosition(
313 id,
314 params.text_document.uri.clone(),
315 params.position.clone(),
316 ));
317 }
318 Ok(LSPCommand::definition { id, params }) => {
319 let _ = send_to_query_channel.send(QueryRequest::DefinitionAtPosition(
320 id,
321 params.text_document.uri.clone(),
322 params.position.clone(),
323 ));
324 }
325 Ok(LSPCommand::references { id, params }) => {
326 let _ = send_to_query_channel.send(QueryRequest::ReferencesAtPosition(
327 id,
328 params.text_document.uri.clone(),
329 params.position.clone(),
330 true,
331 ));
332 }
333 Ok(LSPCommand::rename { id, params }) => {
334 let _ = send_to_query_channel.send(QueryRequest::RenameAtPosition(
335 id,
336 params.text_document.uri.clone(),
337 params.position.clone(),
338 params.new_name.clone(),
339 ));
340 }
341 Ok(LSPCommand::completion { .. }) => {
342 }
344 Ok(LSPCommand::completionItemResolve { .. }) => {
345 }
349 Ok(LSPCommand::cancelRequest {
350 params: languageserver_types::CancelParams { id },
351 }) => match id {
352 languageserver_types::NumberOrString::Number(_num) => {
353 }
359 _ => unimplemented!(
360 "Non-number cancellation IDs not currently supported"
361 ),
362 },
363 Err(e) => eprintln!("Error handling command: {:?}", e),
364 }
365 }
366 }
367 Err(error) => eprintln!("error: {}", error),
368 }
369 }
370}