diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2021-02-12 15:17:48 +1100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-02-12 15:17:48 +1100 |
commit | d6c05b09dd7cbaba0fcae65929a2c2dd55e9d994 (patch) | |
tree | 1d813f7f0acc543f6da96c429a5cc2fd19b606f1 /cli/lsp/analysis.rs | |
parent | 46da7c6aff3c10af6a067f4229644d2de444a3a7 (diff) |
feat(lsp): add deno cache code actions (#9471)
Diffstat (limited to 'cli/lsp/analysis.rs')
-rw-r--r-- | cli/lsp/analysis.rs | 179 |
1 files changed, 133 insertions, 46 deletions
diff --git a/cli/lsp/analysis.rs b/cli/lsp/analysis.rs index b79a9ec65..8600301a5 100644 --- a/cli/lsp/analysis.rs +++ b/cli/lsp/analysis.rs @@ -15,6 +15,7 @@ use deno_core::error::custom_error; use deno_core::error::AnyError; use deno_core::serde::Deserialize; use deno_core::serde::Serialize; +use deno_core::serde_json; use deno_core::serde_json::json; use deno_core::ModuleResolutionError; use deno_core::ModuleSpecifier; @@ -152,6 +153,23 @@ pub enum ResolvedDependencyErr { Missing, } +impl ResolvedDependencyErr { + pub fn as_code(&self) -> lsp::NumberOrString { + match self { + Self::InvalidDowngrade => { + lsp::NumberOrString::String("invalid-downgrade".to_string()) + } + Self::InvalidLocalImport => { + lsp::NumberOrString::String("invalid-local-import".to_string()) + } + Self::InvalidSpecifier(_) => { + lsp::NumberOrString::String("invalid-specifier".to_string()) + } + Self::Missing => lsp::NumberOrString::String("missing".to_string()), + } + } +} + impl fmt::Display for ResolvedDependencyErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -351,30 +369,34 @@ fn is_equivalent_code( /// action for a given set of actions. fn is_preferred( action: &tsc::CodeFixAction, - actions: &[(lsp::CodeAction, tsc::CodeFixAction)], + actions: &[CodeActionKind], fix_priority: u32, only_one: bool, ) -> bool { - actions.iter().all(|(_, a)| { - if action == a { - return true; - } - if a.fix_id.is_some() { - return true; - } - if let Some((other_fix_priority, _)) = - PREFERRED_FIXES.get(a.fix_name.as_str()) - { - match other_fix_priority.cmp(&fix_priority) { - Ordering::Less => return true, - Ordering::Greater => return false, - Ordering::Equal => (), + actions.iter().all(|i| { + if let CodeActionKind::Tsc(_, a) = i { + if action == a { + return true; + } + if a.fix_id.is_some() { + return true; } - if only_one && action.fix_name == a.fix_name { - return false; + if let Some((other_fix_priority, _)) = + PREFERRED_FIXES.get(a.fix_name.as_str()) + { + match other_fix_priority.cmp(&fix_priority) { + Ordering::Less => return true, + Ordering::Greater => return false, + Ordering::Equal => (), + } + if only_one && action.fix_name == a.fix_name { + return false; + } } + true + } else { + true } - true }) } @@ -404,13 +426,58 @@ pub struct CodeActionData { pub fix_id: String, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct DenoFixData { + pub specifier: ModuleSpecifier, +} + +#[derive(Debug, Clone)] +enum CodeActionKind { + Deno(lsp::CodeAction), + Tsc(lsp::CodeAction, tsc::CodeFixAction), +} + +#[derive(Debug, Hash, PartialEq, Eq)] +enum FixAllKind { + Tsc(String), +} + #[derive(Debug, Default)] pub struct CodeActionCollection { - actions: Vec<(lsp::CodeAction, tsc::CodeFixAction)>, - fix_all_actions: HashMap<String, (lsp::CodeAction, tsc::CodeFixAction)>, + actions: Vec<CodeActionKind>, + fix_all_actions: HashMap<FixAllKind, CodeActionKind>, } impl CodeActionCollection { + pub(crate) fn add_deno_fix_action( + &mut self, + diagnostic: &lsp::Diagnostic, + ) -> Result<(), AnyError> { + if let Some(data) = diagnostic.data.clone() { + let fix_data: DenoFixData = serde_json::from_value(data)?; + let code_action = lsp::CodeAction { + title: format!( + "Cache \"{}\" and its dependencies.", + fix_data.specifier + ), + kind: Some(lsp::CodeActionKind::QUICKFIX), + diagnostics: Some(vec![diagnostic.clone()]), + edit: None, + command: Some(lsp::Command { + title: "".to_string(), + command: "deno.cache".to_string(), + arguments: Some(vec![json!([fix_data.specifier])]), + }), + is_preferred: None, + disabled: None, + data: None, + }; + self.actions.push(CodeActionKind::Deno(code_action)); + } + Ok(()) + } + /// Add a TypeScript code fix action to the code actions collection. pub(crate) async fn add_ts_fix_action( &mut self, @@ -442,19 +509,28 @@ impl CodeActionCollection { disabled: None, data: None, }; - self.actions.retain(|(c, a)| { - !(action.fix_name == a.fix_name && code_action.edit == c.edit) + self.actions.retain(|i| match i { + CodeActionKind::Tsc(c, a) => { + !(action.fix_name == a.fix_name && code_action.edit == c.edit) + } + _ => true, }); - self.actions.push((code_action, action.clone())); + self + .actions + .push(CodeActionKind::Tsc(code_action, action.clone())); if let Some(fix_id) = &action.fix_id { - if let Some((existing_fix_all, existing_action)) = - self.fix_all_actions.get(fix_id) + if let Some(CodeActionKind::Tsc(existing_fix_all, existing_action)) = + self.fix_all_actions.get(&FixAllKind::Tsc(fix_id.clone())) { - self.actions.retain(|(c, _)| c != existing_fix_all); - self - .actions - .push((existing_fix_all.clone(), existing_action.clone())); + self.actions.retain(|i| match i { + CodeActionKind::Tsc(c, _) => c != existing_fix_all, + _ => true, + }); + self.actions.push(CodeActionKind::Tsc( + existing_fix_all.clone(), + existing_action.clone(), + )); } } Ok(()) @@ -488,15 +564,21 @@ impl CodeActionCollection { disabled: None, data, }; - if let Some((existing, _)) = - self.fix_all_actions.get(&action.fix_id.clone().unwrap()) + if let Some(CodeActionKind::Tsc(existing, _)) = self + .fix_all_actions + .get(&FixAllKind::Tsc(action.fix_id.clone().unwrap())) { - self.actions.retain(|(c, _)| c != existing); + self.actions.retain(|i| match i { + CodeActionKind::Tsc(c, _) => c != existing, + _ => true, + }); } - self.actions.push((code_action.clone(), action.clone())); + self + .actions + .push(CodeActionKind::Tsc(code_action.clone(), action.clone())); self.fix_all_actions.insert( - action.fix_id.clone().unwrap(), - (code_action, action.clone()), + FixAllKind::Tsc(action.fix_id.clone().unwrap()), + CodeActionKind::Tsc(code_action, action.clone()), ); } @@ -505,7 +587,10 @@ impl CodeActionCollection { self .actions .into_iter() - .map(|(c, _)| lsp::CodeActionOrCommand::CodeAction(c)) + .map(|i| match i { + CodeActionKind::Tsc(c, _) => lsp::CodeActionOrCommand::CodeAction(c), + CodeActionKind::Deno(c) => lsp::CodeActionOrCommand::CodeAction(c), + }) .collect() } @@ -521,7 +606,7 @@ impl CodeActionCollection { if action.fix_id.is_none() || self .fix_all_actions - .contains_key(&action.fix_id.clone().unwrap()) + .contains_key(&FixAllKind::Tsc(action.fix_id.clone().unwrap())) { false } else { @@ -543,15 +628,17 @@ impl CodeActionCollection { /// when all actions are added to the collection. pub fn set_preferred_fixes(&mut self) { let actions = self.actions.clone(); - for (code_action, action) in self.actions.iter_mut() { - if action.fix_id.is_some() { - continue; - } - if let Some((fix_priority, only_one)) = - PREFERRED_FIXES.get(action.fix_name.as_str()) - { - code_action.is_preferred = - Some(is_preferred(action, &actions, *fix_priority, *only_one)); + for entry in self.actions.iter_mut() { + if let CodeActionKind::Tsc(code_action, action) = entry { + if action.fix_id.is_some() { + continue; + } + if let Some((fix_priority, only_one)) = + PREFERRED_FIXES.get(action.fix_name.as_str()) + { + code_action.is_preferred = + Some(is_preferred(action, &actions, *fix_priority, *only_one)); + } } } } |