mirror of
https://github.com/denoland/deno.git
synced 2025-08-04 02:48:24 +00:00
feat(lsp): implement refactoring code actions (#11555)
Closes: denoland/vscode_deno#433
This commit is contained in:
parent
3f0cf9619f
commit
728d205d9d
12 changed files with 882 additions and 93 deletions
131
cli/lsp/refactor.rs
Normal file
131
cli/lsp/refactor.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
// The logic of this module is heavily influenced by
|
||||
// https://github.com/microsoft/vscode/blob/main/extensions/typescript-language-features/src/languageFeatures/refactor.ts
|
||||
|
||||
use deno_core::serde::Deserialize;
|
||||
use deno_core::serde::Serialize;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use lspower::lsp;
|
||||
|
||||
pub struct RefactorCodeActionKind {
|
||||
pub kind: lsp::CodeActionKind,
|
||||
matches_callback: Box<dyn Fn(&str) -> bool + Send + Sync>,
|
||||
}
|
||||
|
||||
impl RefactorCodeActionKind {
|
||||
pub fn matches(&self, tag: &str) -> bool {
|
||||
(self.matches_callback)(tag)
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref EXTRACT_FUNCTION: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_EXTRACT.as_str(), "function"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("function_")),
|
||||
};
|
||||
|
||||
pub static ref EXTRACT_CONSTANT: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_EXTRACT.as_str(), "constant"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("constant_")),
|
||||
};
|
||||
|
||||
pub static ref EXTRACT_TYPE: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_EXTRACT.as_str(), "type"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Extract to type alias")),
|
||||
};
|
||||
|
||||
pub static ref EXTRACT_INTERFACE: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_EXTRACT.as_str(), "interface"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Extract to interface")),
|
||||
};
|
||||
|
||||
pub static ref MOVE_NEWFILE: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR.as_str(), "move", "newFile"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Move to a new file")),
|
||||
};
|
||||
|
||||
pub static ref REWRITE_IMPORT: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_REWRITE.as_str(), "import"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Convert namespace import") || tag.starts_with("Convert named imports")),
|
||||
};
|
||||
|
||||
pub static ref REWRITE_EXPORT: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_REWRITE.as_str(), "export"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Convert default export") || tag.starts_with("Convert named export")),
|
||||
};
|
||||
|
||||
pub static ref REWRITE_ARROW_BRACES: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_REWRITE.as_str(), "arrow", "braces"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Add or remove braces in an arrow function")),
|
||||
};
|
||||
|
||||
pub static ref REWRITE_PARAMETERS_TO_DESTRUCTURED: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_REWRITE.as_str(), "parameters", "toDestructured"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Convert parameters to destructured object")),
|
||||
};
|
||||
|
||||
pub static ref REWRITE_PROPERTY_GENERATEACCESSORS: RefactorCodeActionKind = RefactorCodeActionKind {
|
||||
kind : [lsp::CodeActionKind::REFACTOR_REWRITE.as_str(), "property", "generateAccessors"].join(".").into(),
|
||||
matches_callback: Box::new(|tag: &str| tag.starts_with("Generate 'get' and 'set' accessors")),
|
||||
};
|
||||
|
||||
pub static ref ALL_KNOWN_REFACTOR_ACTION_KINDS: Vec<&'static RefactorCodeActionKind> = vec![
|
||||
&EXTRACT_FUNCTION,
|
||||
&EXTRACT_CONSTANT,
|
||||
&EXTRACT_TYPE,
|
||||
&EXTRACT_INTERFACE,
|
||||
&MOVE_NEWFILE,
|
||||
&REWRITE_IMPORT,
|
||||
&REWRITE_EXPORT,
|
||||
&REWRITE_ARROW_BRACES,
|
||||
&REWRITE_PARAMETERS_TO_DESTRUCTURED,
|
||||
&REWRITE_PROPERTY_GENERATEACCESSORS
|
||||
];
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct RefactorCodeActionData {
|
||||
pub specifier: ModuleSpecifier,
|
||||
pub range: lsp::Range,
|
||||
pub refactor_name: String,
|
||||
pub action_name: String,
|
||||
}
|
||||
|
||||
pub fn prune_invalid_actions(
|
||||
actions: &[lsp::CodeAction],
|
||||
number_of_invalid: usize,
|
||||
) -> Vec<lsp::CodeAction> {
|
||||
let mut available_actions = Vec::<lsp::CodeAction>::new();
|
||||
let mut invalid_common_actions = Vec::<lsp::CodeAction>::new();
|
||||
let mut invalid_uncommon_actions = Vec::<lsp::CodeAction>::new();
|
||||
for action in actions {
|
||||
if action.disabled.is_none() {
|
||||
available_actions.push(action.clone());
|
||||
continue;
|
||||
}
|
||||
|
||||
// These are the common refactors that we should always show if applicable.
|
||||
let action_kind =
|
||||
action.kind.as_ref().map(|a| a.as_str()).unwrap_or_default();
|
||||
if action_kind.starts_with(EXTRACT_CONSTANT.kind.as_str())
|
||||
|| action_kind.starts_with(EXTRACT_FUNCTION.kind.as_str())
|
||||
{
|
||||
invalid_common_actions.push(action.clone());
|
||||
continue;
|
||||
}
|
||||
|
||||
// These are the remaining refactors that we can show if we haven't reached the max limit with just common refactors.
|
||||
invalid_uncommon_actions.push(action.clone());
|
||||
}
|
||||
|
||||
let mut prioritized_actions = Vec::<lsp::CodeAction>::new();
|
||||
prioritized_actions.extend(invalid_common_actions);
|
||||
prioritized_actions.extend(invalid_uncommon_actions);
|
||||
let top_n_invalid = prioritized_actions
|
||||
[0..std::cmp::min(number_of_invalid, prioritized_actions.len())]
|
||||
.to_vec();
|
||||
available_actions.extend(top_n_invalid);
|
||||
available_actions
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue