summaryrefslogtreecommitdiff
path: root/cli/lsp/refactor.rs
diff options
context:
space:
mode:
authorJean Pierre <jeanp413@hotmail.com>2021-08-05 20:46:32 -0500
committerGitHub <noreply@github.com>2021-08-06 11:46:32 +1000
commit728d205d9d2551a356a022b6b083bcdcf081f3bf (patch)
treec0823fef3a96ed164379c5297d521fce9b2628d8 /cli/lsp/refactor.rs
parent3f0cf9619fce71a8898c495501df4bdb0e07e735 (diff)
feat(lsp): implement refactoring code actions (#11555)
Closes: denoland/vscode_deno#433
Diffstat (limited to 'cli/lsp/refactor.rs')
-rw-r--r--cli/lsp/refactor.rs131
1 files changed, 131 insertions, 0 deletions
diff --git a/cli/lsp/refactor.rs b/cli/lsp/refactor.rs
new file mode 100644
index 000000000..17ab4d5de
--- /dev/null
+++ b/cli/lsp/refactor.rs
@@ -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
+}