1use std::io::Write;
8use std::str::FromStr;
9use lsp_types as lsp;
10use lsp::request::Request;
11use tree_sitter;
12use std::collections::HashMap;
13use std::sync::Arc;
14
15use crate::{STDRESULT,DYNERR};
16
17pub const TOKEN_TYPES: [&str;21] = ["comment", "string", "keyword", "number", "regexp", "operator", "namespace",
18"type", "struct", "class", "interface", "enum", "typeParameter", "function",
19"method", "decorator", "macro", "variable", "parameter", "property", "label"];
20
21mod rpc_error {
24 pub const PARSE_ERROR: i32 = -32700;
25 }
30
31pub trait Hovers {
34 fn get(&mut self, line: String, row: isize, col: isize) -> Option<lsp::Hover>;
35}
36
37pub trait Completions {
40 fn get(&mut self,lines: &mut std::str::Lines, ctx: &lsp::CompletionContext, pos: &lsp::Position) -> Result<Vec<lsp::CompletionItem>,String>;
41}
42
43pub trait Tokens {
46 fn get(&mut self, txt: &str) -> Result<lsp::SemanticTokens,DYNERR>;
47}
48
49pub trait Checkpoint {
55 fn get_doc(&self) -> super::Document;
57 fn get_line(&self,row: usize) -> Option<String>;
59 fn get_symbols(&self) -> Vec<lsp::DocumentSymbol>;
60 fn get_decs(&self,loc: &lsp::Location) -> Vec<lsp::Location>;
61 fn get_defs(&self,loc: &lsp::Location) -> Vec<lsp::Location>;
62 fn get_refs(&self,loc: &lsp::Location) -> Vec<lsp::Location>;
63 fn get_renamables(&self,loc: &lsp::Location) -> Vec<lsp::Location>;
64 fn get_folding_ranges(&self) -> Vec<lsp::FoldingRange>;
65 fn symbol_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
66 if let Ok(params) = serde_json::from_value::<lsp::DocumentSymbolParams>(req.params) {
67 let uri = super::normalize_client_uri(params.text_document.uri);
68 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
69 *resp = match serde_json::to_value::<Vec<lsp::DocumentSymbol>>(chkpt.get_symbols()) {
70 Ok(result) => lsp_server::Response::new_ok(req.id,Some(result)),
71 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"symbol request failed while parsing".to_string())
72 };
73 }
74 }
75 }
76 fn goto_dec_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
77 if let Ok(params) = serde_json::from_value::<lsp::GotoDefinitionParams>(req.params) {
78 let uri = super::normalize_client_uri(params.text_document_position_params.text_document.uri);
79 let pos = params.text_document_position_params.position;
80 let loc = lsp::Location::new(uri.clone(),lsp::Range::new(pos,pos));
81 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
82 *resp = match serde_json::to_value::<Vec<lsp::Location>>(chkpt.get_decs(&loc)) {
83 Ok(result) => lsp_server::Response::new_ok(req.id,Some(result)),
84 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"goto decs failed while parsing".to_string())
85 };
86 }
87 }
88 }
89 fn goto_def_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
90 if let Ok(params) = serde_json::from_value::<lsp::GotoDefinitionParams>(req.params) {
91 let uri = super::normalize_client_uri(params.text_document_position_params.text_document.uri);
92 let pos = params.text_document_position_params.position;
93 let loc = lsp::Location::new(uri.clone(),lsp::Range::new(pos,pos));
94 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
95 *resp = match serde_json::to_value::<Vec<lsp::Location>>(chkpt.get_defs(&loc)) {
96 Ok(result) => lsp_server::Response::new_ok(req.id,Some(result)),
97 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"goto defs failed while parsing".to_string())
98 };
99 }
100 }
101 }
102 fn goto_ref_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
103 if let Ok(params) = serde_json::from_value::<lsp::ReferenceParams>(req.params) {
104 let uri = super::normalize_client_uri(params.text_document_position.text_document.uri);
105 let pos = params.text_document_position.position;
106 let loc = lsp::Location::new(uri.clone(),lsp::Range::new(pos,pos));
107 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
108 *resp = match serde_json::to_value::<Vec<lsp::Location>>(chkpt.get_refs(&loc)) {
109 Ok(result) => lsp_server::Response::new_ok(req.id,Some(result)),
110 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"goto refs failed while parsing".to_string())
111 };
112 }
113 }
114 }
115 fn rename_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
116 if let Ok(params) = serde_json::from_value::<lsp::RenameParams>(req.params) {
117 let uri = super::normalize_client_uri(params.text_document_position.text_document.uri);
118 let pos = params.text_document_position.position;
119 let sel_loc = lsp::Location::new(uri.clone(),lsp::Range::new(pos,pos));
120 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
121 let mut changes: HashMap<lsp::Uri,Vec<lsp::TextEdit>> = HashMap::new();
122 let locs = chkpt.get_renamables(&sel_loc);
123 for loc in locs {
124 let new_edit = lsp::TextEdit::new(loc.range, params.new_name.clone());
125 match changes.get_mut(&loc.uri) {
126 Some(edits) => edits.push(new_edit),
127 None => {
128 let edits = vec![new_edit];
129 changes.insert(loc.uri,edits);
130 }
131 };
132 }
133 *resp = match serde_json::to_value::<lsp::WorkspaceEdit>(lsp::WorkspaceEdit::new(changes)) {
134 Ok(result) => lsp_server::Response::new_ok(req.id,result),
135 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"rename request failed while parsing".to_string())
136 };
137 }
138 }
139 }
140 fn folding_range_response(chkpts: HashMap<String,Arc<&Self>>, req: lsp_server::Request, resp: &mut lsp_server::Response) {
141 if let Ok(params) = serde_json::from_value::<lsp::FoldingRangeParams>(req.params) {
142 let uri = super::normalize_client_uri(params.text_document.uri);
143 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
144 let folding_ranges = chkpt.get_folding_ranges();
145 *resp = match serde_json::to_value::<Vec<lsp::FoldingRange>>(folding_ranges) {
146 Ok(result) => lsp_server::Response::new_ok(req.id,result),
147 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"folding range request failed while parsing".to_string())
148 };
149 }
150 }
151 }
152 fn hover_response<HOV: Hovers>(chkpts: HashMap<String,Arc<&Self>>, hov: &mut HOV, req: lsp_server::Request, resp: &mut lsp_server::Response) {
153 if let Ok(params) = serde_json::from_value::<lsp::HoverParams>(req.params) {
154 let uri = super::normalize_client_uri(params.text_document_position_params.text_document.uri);
155 let pos = params.text_document_position_params.position;
156 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
157 if let Some(line) = chkpt.get_line(pos.line as usize) {
158 *resp = match hov.get(line,pos.line as isize, pos.character as isize) {
159 Some(hover) => match serde_json::to_value::<lsp::Hover>(hover) {
160 Ok(result) => lsp_server::Response::new_ok(req.id,result),
161 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"hover request failed while parsing".to_string())
162 },
163 None => lsp_server::Response::new_ok(req.id,serde_json::Value::Null)
164 };
165 }
166 }
167 }
168 }
169 fn completion_response<CMP: Completions>(chkpts: HashMap<String,Arc<&Self>>, cmp: &mut CMP, req: lsp_server::Request, resp: &mut lsp_server::Response) {
170 if let Ok(params) = serde_json::from_value::<lsp::CompletionParams>(req.params) {
171 let uri = super::normalize_client_uri(params.text_document_position.text_document.uri);
172 let pos = params.text_document_position.position;
173 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
174 if let Some(ctx) = params.context {
175 *resp = match cmp.get(&mut chkpt.get_doc().text.lines(),&ctx,&pos) {
176 Ok(lst) => {
177 match serde_json::to_value::<lsp::CompletionResponse>(lsp::CompletionResponse::Array(lst)) {
178 Ok(result) => lsp_server::Response::new_ok(req.id,result),
179 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"completion request failed while parsing".to_string())
180 }
181 },
182 Err(s) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,s)
183 };
184 }
185 }
186 }
187 }
188 fn sem_tok_response<TOK: Tokens>(chkpts: HashMap<String,Arc<&Self>>, tok: &mut TOK, req: lsp_server::Request, resp: &mut lsp_server::Response) {
189 if let Ok(params) = serde_json::from_value::<lsp::SemanticTokensParams>(req.params) {
190 let uri: lsp::Uri =super::normalize_client_uri(params.text_document.uri);
191 if let Some(chkpt) = chkpts.get(&uri.to_string()) {
192 let doc = chkpt.get_doc();
193 if let Ok(tok) = tok.get(&doc.text) {
194 *resp = match serde_json::to_value::<lsp::SemanticTokensResult>(lsp::SemanticTokensResult::Tokens(tok)) {
195 Ok(result) => lsp_server::Response::new_ok(req.id,Some(result)),
196 Err(_) => lsp_server::Response::new_err(req.id,rpc_error::PARSE_ERROR,"semantic tokens failed while parsing".to_string())
197 };
198 }
199 }
200 }
201 }
202}
203
204pub trait Analysis {
209 fn init_workspace(&mut self,_source_dirs: Vec<lsp::Uri>,_volatile_docs: Vec<super::Document>) -> STDRESULT {
213 Ok(())
214 }
215 fn analyze(&mut self,doc: &super::Document) -> STDRESULT;
217 fn update_config(&mut self,json_str: &str) -> STDRESULT;
221 fn get_diags(&self,doc: &super::Document) -> Vec<lsp::Diagnostic>;
225 fn get_folds(&self,doc: &super::Document) -> Vec<lsp::FoldingRange>;
226 fn err_warn_info_counts(&self) -> [usize;3];
227 fn eprint_lines_sexpr(&self,doc: &str);
228 fn read_stdin(&self) -> String;
230}
231
232pub struct SemanticTokensBuilder {
233 last_pos: lsp::Position,
234 tok_map: HashMap<String,u32>,
235 tokens: Vec<lsp::SemanticToken>,
236 hex_re: regex::Regex
237}
238
239impl SemanticTokensBuilder {
240 pub fn new() -> Self {
241 let mut tok_map = HashMap::new();
242 let types = Self::get_token_types();
243 for i in 0..types.len() {
244 tok_map.insert(types[i].clone(),i as u32);
245 }
246 Self {
247 last_pos: lsp::Position::new(0,0),
248 tok_map,
249 tokens: Vec::new(),
250 hex_re: regex::Regex::new(r"\\x[0-9a-fA-F][0-9a-fA-F]").expect("bad regex")
251 }
252 }
253 pub fn get_token_types() ->Vec<String> {
254 TOKEN_TYPES.iter().map(|x| x.to_string()).collect()
255 }
256 pub fn reset(&mut self) {
257 self.tokens = Vec::new();
258 self.last_pos = lsp::Position::new(0,0);
259 }
260 pub fn clone_result(&self) -> Result<lsp::SemanticTokens,DYNERR> {
261 Ok(lsp::SemanticTokens {
262 result_id: None,
263 data: self.tokens.clone()
264 })
265 }
266 pub fn process_escapes(&mut self,curs: &tree_sitter::TreeCursor,line: &str,rng: lsp::Range,typ: &str) {
267 let pos0 = rng.start.character;
268 let mut pos = rng.start.character;
269 let txt = super::node_text(&curs.node(), line);
270 let re_clone = self.hex_re.clone();
271 for mtch in re_clone.find_iter(&txt) {
272 let esc_start = pos0 + mtch.start() as u32;
273 let esc_end = pos0 + mtch.end() as u32;
274 let outer = lsp::Range::new(
275 lsp::Position::new(rng.start.line,pos),
276 lsp::Position::new(rng.start.line, esc_start)
277 );
278 self.push(outer,typ);
279 let emb = lsp::Range::new(
280 lsp::Position::new(rng.start.line, esc_start),
281 lsp::Position::new(rng.start.line, esc_end)
282 );
283 self.push(emb, "regexp");
284 pos = esc_end;
285 }
286 let outer = lsp::Range::new(
287 lsp::Position::new(rng.start.line, pos),
288 rng.end
289 );
290 self.push(outer, typ);
291 }
292 pub fn push(&mut self,rng: lsp::Range, typ: &str) {
293 if let Some(code) = self.tok_map.get(typ) {
294 if rng.start.line >= self.last_pos.line {
295 if rng.start.line == self.last_pos.line && rng.start.character < self.last_pos.character {
296 return;
297 }
298 self.tokens.push(lsp::SemanticToken {
299 delta_line: rng.start.line - self.last_pos.line,
300 delta_start: match rng.start.line == self.last_pos.line {
301 true => rng.start.character - self.last_pos.character,
302 false => rng.start.character
303 },
304 length: rng.end.character - rng.start.character,
305 token_type: *code,
306 token_modifiers_bitset: 0
307 });
308 self.last_pos.line = rng.start.line;
309 self.last_pos.character = rng.start.character;
310 }
311 }
312 }
313}
314
315pub fn send_edit_req(connection: &lsp_server::Connection, doc: &lsp::TextDocumentItem, edits: Vec<lsp::TextEdit>) -> Result<(),String> {
316 let mut edit_list = Vec::new();
317 edit_list.push(lsp::TextDocumentEdit {
318 text_document: lsp::OptionalVersionedTextDocumentIdentifier::new(doc.uri.clone(), doc.version),
319 edits: edits.iter().map(|x| lsp::OneOf::Left(x.clone())).collect()
320 });
321 let ws_edit = lsp::WorkspaceEdit {
322 changes: None,
323 document_changes: Some(lsp::DocumentChanges::Edits(edit_list)),
324 change_annotations: None
325 };
326 if let Ok(params) = serde_json::to_value(lsp::ApplyWorkspaceEditParams {label: None,edit: ws_edit}) {
328 let req = lsp_server::Request {
329 id: lsp_server::RequestId::from("renumber".to_string()),
330 method: lsp::request::ApplyWorkspaceEdit::METHOD.to_string(),
331 params
332 };
333 match connection.sender.send(lsp_server::Message::Request(req)) {
334 Ok(()) => Ok(()),
335 Err(_) => Err("could not send".to_string())
336 }
337 } else {
338 Err("could not parse".to_string())
339 }
340}
341
342pub fn basic_diag(range: lsp::Range,mess: &str,severity: lsp::DiagnosticSeverity) -> lsp::Diagnostic {
343 lsp::Diagnostic {
344 range,
345 severity: Some(severity),
346 code: None,
347 code_description: None,
348 source: None,
349 message: mess.to_string(),
350 related_information: None,
351 tags: None,
352 data: None
353 }
354}
355
356pub fn path_in_workspace(full: &lsp::Uri, ws_folder: &Vec<lsp::Uri>) -> String {
360 if ws_folder.len() == 0 {
361 return full.to_string();
362 }
363 let full_path = match super::pathbuf_from_uri(full) {
364 Ok(ans) => ans,
365 Err(_) => return full.to_string()
366 };
367 let ws_path = match super::pathbuf_from_uri(&ws_folder[0]) {
368 Ok(ans) => ans,
369 Err(_) => return full.to_string()
370 };
371 let e_full_canon = full_path.canonicalize();
372 let e_ws_canon = ws_path.canonicalize();
373 match (e_full_canon,e_ws_canon) {
374 (Ok(full_canon),Ok(ws_canon)) => {
375 let mut full_iter = full_canon.iter();
376 let mut ws_iter = ws_canon.iter();
377 while let Some(ws_node) = ws_iter.next() {
378 if let Some(node) = full_iter.next() {
379 if node != ws_node {
380 return full.to_string();
381 }
382 } else {
383 return full.to_string();
384 }
385 }
386 let mut ans = String::new();
387 while let Some(node) = full_iter.next() {
388 ans += &node.to_string_lossy();
389 ans += "/";
390 }
391 if ans.len() < 2 {
392 return full.to_string();
393 }
394 ans.pop();
395 ans
396 },
397 _ => full.to_string()
398 }
399}
400
401fn setup_env_logger(filt: log::LevelFilter, path: &str) {
402 if filt==log::LevelFilter::Off {
403 return;
404 }
405 let a2kit_logging_file = Box::new(std::fs::File::create(path).expect("failed to create log file"));
406 env_logger::Builder::new().format(|buf,record| {
407 writeln!(buf,"{}:{} [{}] - {}",record.file().unwrap_or("unknown"),
408 record.line().unwrap_or(0),
409 record.level(),
410 record.args()
411 )
412 })
413 .filter(Some("a2kit::lang"),filt)
414 .target(env_logger::Target::Pipe(a2kit_logging_file))
415 .init();
416}
417
418pub fn parse_args() -> (Vec<bool>,Vec<String>) {
422 let mut log_level = log::LevelFilter::Off;
423 let mut log_file = "a2kit_log.txt".to_string();
424 let mut suppress_tokens = false;
425
426 let mut args = std::env::args().into_iter();
428 args.next();
429 while let Some(val) = args.next() {
430 if &val == "--log-level" {
431 if let Some(val) = args.next() {
432 log_level = log::LevelFilter::from_str(&val).expect("invalid logging filter");
433 }
434 } else if &val == "--log-file" {
435 if let Some(val) = args.next() {
436 log_file = val;
437 }
438 } else if &val == "--suppress-tokens" {
439 suppress_tokens = true;
441 }
442 }
443 setup_env_logger(log_level, &log_file);
444 (vec![suppress_tokens],vec![])
445}