use std::collections::HashMap; use serde::Deserialize; use serde_json::json; use serde_json::Value; use erg_common::traits::Locational; use erg_compiler::artifact::BuildRunnable; use erg_compiler::hir::Expr; use lsp_types::{ CodeAction, CodeActionKind, CodeActionParams, Diagnostic, TextEdit, Url, WorkspaceEdit, }; use crate::server::{ELSResult, Server}; use crate::util; impl Server { fn send_eliminate_unused_vars_action( &self, _msg: &Value, uri: &Url, diag: Diagnostic, ) -> ELSResult> { let mut map = HashMap::new(); let Some(visitor) = self.get_visitor(uri) else { Self::send_log("visitor not found")?; return Ok(vec![]); }; let Some(expr) = visitor.get_min_expr(diag.range) else { Self::send_log("expr not found")?; return Ok(vec![]); }; if let Expr::Def(def) = expr { let mut range = util::loc_to_range(def.loc()).unwrap(); let next = lsp_types::Range { start: lsp_types::Position { line: range.end.line, character: range.end.character, }, end: lsp_types::Position { line: range.end.line, character: range.end.character + 1, }, }; let code = util::get_ranged_code_from_uri(uri, next)?; match code.as_ref().map(|s| &s[..]) { None => { range.end.line += 1; range.end.character = 0; } Some(";") => range.end.character += 1, Some(other) => { Self::send_log(format!("? {other}"))?; } } let edit = TextEdit::new(range, "".to_string()); map.insert(uri.clone(), vec![edit]); let edit = WorkspaceEdit::new(map); let action = CodeAction { title: "Eliminate unused variables".to_string(), kind: Some(CodeActionKind::QUICKFIX), diagnostics: Some(vec![diag]), edit: Some(edit), ..Default::default() }; Ok(vec![action]) } else { Ok(vec![]) } } pub(crate) fn send_code_action(&self, msg: &Value) -> ELSResult<()> { Self::send_log(format!("code action requested: {msg}"))?; let params = CodeActionParams::deserialize(&msg["params"])?; let result = match params .context .only .as_ref() .and_then(|kinds| kinds.first().map(|s| s.as_str())) { Some("quickfix") => self.send_quick_fix(msg, params)?, None => self.send_normal_action(msg, params)?, Some(other) => { Self::send_log(&format!("Unknown code action requested: {other}"))?; vec![] } }; Self::send( &json!({ "jsonrpc": "2.0", "id": msg["id"].as_i64().unwrap(), "result": result }), ) } fn send_normal_action( &self, msg: &Value, params: CodeActionParams, ) -> ELSResult> { self.send_quick_fix(msg, params) } fn send_quick_fix(&self, msg: &Value, params: CodeActionParams) -> ELSResult> { let mut result: Vec = vec![]; let uri = util::normalize_url(params.text_document.uri); for diag in params.context.diagnostics.into_iter() { match &diag.message { unused if unused.ends_with("is not used") => { result.extend(self.send_eliminate_unused_vars_action(msg, &uri, diag)?); } _ => { Self::send_log(&format!("Unknown diagnostic for action: {}", diag.message))?; } } } Ok(result) } }