Trigger VSCode to rename after extract variable assist is applied

When the user applies the "Extract Variable" assist, the cursor is
positioned at the newly inserted variable. This commit adds a command
to the assist that triggers the rename action in VSCode. This way, the
user can quickly rename the variable after applying the assist.

Fixes part of: #17579
This commit is contained in:
bors 2024-07-11 08:55:34 +00:00 committed by Josh McKinney
parent 5577e4e3b1
commit 8efe8a8528
No known key found for this signature in database
GPG key ID: 722287396A903BC5
17 changed files with 80 additions and 33 deletions

View file

@ -185,11 +185,11 @@ impl Assists {
return None;
}
let mut trigger_signature_help = false;
let mut command = None;
let source_change = if self.resolve.should_resolve(&id) {
let mut builder = SourceChangeBuilder::new(self.file);
f(&mut builder);
trigger_signature_help = builder.trigger_signature_help;
command = builder.command.take();
Some(builder.finish())
} else {
None
@ -197,7 +197,7 @@ impl Assists {
let label = Label::new(label);
let group = group.cloned();
self.buf.push(Assist { id, label, group, target, source_change, trigger_signature_help });
self.buf.push(Assist { id, label, group, target, source_change, command });
Some(())
}

View file

@ -135,6 +135,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
}
}
}
edit.rename();
}
Anchor::Replace(stmt) => {
cov_mark::hit!(test_extract_var_expr_stmt);
@ -149,6 +150,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
}
}
}
edit.rename();
}
Anchor::WrapInBlock(to_wrap) => {
let indent_to = to_wrap.indent_level();
@ -192,6 +194,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
}
}
}
edit.rename();
// fixup indentation of block
block.indent(indent_to);

View file

@ -454,7 +454,7 @@ pub fn test_some_range(a: int) -> bool {
group: None,
target: 59..60,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_variable_assist);
@ -470,7 +470,7 @@ pub fn test_some_range(a: int) -> bool {
group: None,
target: 59..60,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_function_assist);
@ -500,7 +500,7 @@ pub fn test_some_range(a: int) -> bool {
group: None,
target: 59..60,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_variable_assist);
@ -516,7 +516,7 @@ pub fn test_some_range(a: int) -> bool {
group: None,
target: 59..60,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_function_assist);
@ -587,7 +587,9 @@ pub fn test_some_range(a: int) -> bool {
is_snippet: true,
},
),
trigger_signature_help: false,
command: Some(
Rename,
),
}
"#]]
.assert_debug_eq(&extract_into_variable_assist);
@ -603,7 +605,7 @@ pub fn test_some_range(a: int) -> bool {
group: None,
target: 59..60,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_function_assist);
@ -666,7 +668,9 @@ pub fn test_some_range(a: int) -> bool {
is_snippet: true,
},
),
trigger_signature_help: false,
command: Some(
Rename,
),
}
"#]]
.assert_debug_eq(&extract_into_variable_assist);
@ -715,7 +719,7 @@ pub fn test_some_range(a: int) -> bool {
is_snippet: true,
},
),
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&extract_into_function_assist);

View file

@ -29,7 +29,16 @@ pub struct Assist {
/// cumbersome, especially if you want to embed an assist into another data
/// structure, such as a diagnostic.
pub source_change: Option<SourceChange>,
pub trigger_signature_help: bool,
/// The command to execute after the assist is applied.
pub command: Option<Command>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Command {
/// Show the parameter hints popup.
TriggerSignatureHelp,
/// Rename the just inserted item.
Rename,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]

View file

@ -5,7 +5,7 @@
use std::{collections::hash_map::Entry, iter, mem};
use crate::SnippetCap;
use crate::{assists::Command, SnippetCap};
use base_db::{AnchoredPathBuf, FileId};
use itertools::Itertools;
use nohash_hasher::IntMap;
@ -194,7 +194,7 @@ pub struct SourceChangeBuilder {
pub edit: TextEditBuilder,
pub file_id: FileId,
pub source_change: SourceChange,
pub trigger_signature_help: bool,
pub command: Option<Command>,
/// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin.
pub mutated_tree: Option<TreeMutator>,
@ -236,7 +236,7 @@ impl SourceChangeBuilder {
edit: TextEdit::builder(),
file_id,
source_change: SourceChange::default(),
trigger_signature_help: false,
command: None,
mutated_tree: None,
snippet_builder: None,
}
@ -304,8 +304,15 @@ impl SourceChangeBuilder {
let file_system_edit = FileSystemEdit::MoveFile { src, dst };
self.source_change.push_file_system_edit(file_system_edit);
}
/// Triggers the parameter hint popup after the assist is applied
pub fn trigger_signature_help(&mut self) {
self.trigger_signature_help = true;
self.command = Some(Command::TriggerSignatureHelp);
}
/// Renames the item at the cursor position after the assist is applied
pub fn rename(&mut self) {
self.command = Some(Command::Rename);
}
/// Adds a tabstop snippet to place the cursor before `node`

View file

@ -98,7 +98,7 @@ fn quickfix_for_redundant_assoc_item(
group: None,
target: range,
source_change: Some(source_change_builder.finish()),
trigger_signature_help: false,
command: None,
}])
}

View file

@ -82,7 +82,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
original_range.file_id,
TextEdit::replace(original_range.range, code),
)),
trigger_signature_help: false,
command: None,
})
.collect();

View file

@ -130,7 +130,7 @@ fn add_variant_to_union(
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
command: None,
})
}
@ -173,7 +173,7 @@ fn add_field_to_struct_fix(
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
command: None,
})
}
None => {
@ -204,7 +204,7 @@ fn add_field_to_struct_fix(
group: None,
target: error_range.range,
source_change: Some(src_change_builder.finish()),
trigger_signature_help: false,
command: None,
})
}
Some(FieldList::TupleFieldList(_tuple)) => {
@ -266,7 +266,7 @@ fn method_fix(
file_id,
TextEdit::insert(range.end(), "()".to_owned()),
)),
trigger_signature_help: false,
command: None,
})
}
#[cfg(test)]

View file

@ -108,7 +108,7 @@ fn field_fix(
(file_id, TextEdit::insert(range.start(), "(".to_owned())),
(file_id, TextEdit::insert(range.end(), ")".to_owned())),
])),
trigger_signature_help: false,
command: None,
})
}
@ -191,7 +191,7 @@ fn assoc_func_fix(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedMethodCall) -
file_id,
TextEdit::replace(range, assoc_func_call_expr_string),
)),
trigger_signature_help: false,
command: None,
})
} else {
None

View file

@ -73,7 +73,7 @@ fn fixes(
diagnostic_range.file_id,
TextEdit::replace(name_range, format!("_{}", var_name.display(db))),
)),
trigger_signature_help: false,
command: None,
}])
}

View file

@ -613,7 +613,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
group: None,
target,
source_change: None,
trigger_signature_help: false,
command: None,
}
}

View file

@ -45,7 +45,7 @@ pub(crate) fn ssr_assists(
group: Some(GroupLabel("Apply SSR".into())),
target: comment_range,
source_change,
trigger_signature_help: false,
command: None,
};
ssr_assists.push(assist);
@ -143,7 +143,7 @@ mod tests {
is_snippet: false,
},
),
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&apply_in_file_assist);
@ -196,7 +196,7 @@ mod tests {
is_snippet: false,
},
),
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&apply_in_workspace_assist);
@ -236,7 +236,7 @@ mod tests {
),
target: 10..21,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&apply_in_file_assist);
@ -256,7 +256,7 @@ mod tests {
),
target: 10..21,
source_change: None,
trigger_signature_help: false,
command: None,
}
"#]]
.assert_debug_eq(&apply_in_workspace_assist);

View file

@ -1135,6 +1135,7 @@ pub struct ClientCommandsConfig {
pub show_reference: bool,
pub goto_location: bool,
pub trigger_parameter_hints: bool,
pub rename: bool,
}
#[derive(Debug)]
@ -1901,6 +1902,7 @@ impl Config {
show_reference: get("rust-analyzer.showReferences"),
goto_location: get("rust-analyzer.gotoLocation"),
trigger_parameter_hints: get("editor.action.triggerParameterHints"),
rename: get("editor.action.rename"),
}
}

View file

@ -13,7 +13,7 @@ use ide::{
NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
};
use ide_db::{rust_doc::format_docs, FxHasher};
use ide_db::{assists, rust_doc::format_docs, FxHasher};
use itertools::Itertools;
use paths::{Utf8Component, Utf8Prefix};
use semver::VersionReq;
@ -1336,8 +1336,14 @@ pub(crate) fn code_action(
command: None,
};
if assist.trigger_signature_help && snap.config.client_commands().trigger_parameter_hints {
if assist.command == Some(assists::Command::TriggerSignatureHelp)
&& snap.config.client_commands().trigger_parameter_hints
{
res.command = Some(command::trigger_parameter_hints());
} else if assist.command == Some(assists::Command::Rename)
&& snap.config.client_commands().rename
{
res.command = Some(command::rename());
}
match (assist.source_change, resolve_data) {
@ -1715,6 +1721,14 @@ pub(crate) mod command {
arguments: None,
}
}
pub(crate) fn rename() -> lsp_types::Command {
lsp_types::Command {
title: "rename".into(),
command: "rust-analyzer.rename".into(),
arguments: None,
}
}
}
pub(crate) fn implementation_title(count: usize) -> String {

View file

@ -348,6 +348,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
"rust-analyzer.showReferences",
"rust-analyzer.gotoLocation",
"editor.action.triggerParameterHints",
"editor.action.rename",
],
},
...capabilities.experimental,

View file

@ -118,6 +118,12 @@ export function triggerParameterHints(_: CtxInit): Cmd {
};
}
export function rename(_: CtxInit): Cmd {
return async () => {
await vscode.commands.executeCommand("editor.action.rename");
};
}
export function openLogs(ctx: CtxInit): Cmd {
return async () => {
if (ctx.client.outputChannel) {

View file

@ -190,6 +190,7 @@ function createCommands(): Record<string, CommandFactory> {
runSingle: { enabled: commands.runSingle },
showReferences: { enabled: commands.showReferences },
triggerParameterHints: { enabled: commands.triggerParameterHints },
rename: { enabled: commands.rename },
openLogs: { enabled: commands.openLogs },
revealDependency: { enabled: commands.revealDependency },
};