Skip to content

Commit af318f7

Browse files
authored
Merge pull request #18529 from cmrschwarz/allow_leading_whitespace_in_merge_match_arms
Improve selection handling for the `merge_match_arms` assist
2 parents 00a8fc1 + effe9ac commit af318f7

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ impl<'a> AssistContext<'a> {
116116
pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> {
117117
find_node_at_offset(self.source_file.syntax(), self.offset())
118118
}
119+
pub(crate) fn find_node_at_trimmed_offset<N: AstNode>(&self) -> Option<N> {
120+
find_node_at_offset(self.source_file.syntax(), self.trimmed_range.start())
121+
}
119122
pub(crate) fn find_node_at_range<N: AstNode>(&self) -> Option<N> {
120123
find_node_at_range(self.source_file.syntax(), self.trimmed_range)
121124
}

src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,29 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, TextRange};
3434
// }
3535
// ```
3636
pub(crate) fn merge_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
37-
let current_arm = ctx.find_node_at_offset::<ast::MatchArm>()?;
37+
let current_arm = ctx.find_node_at_trimmed_offset::<ast::MatchArm>()?;
3838
// Don't try to handle arms with guards for now - can add support for this later
3939
if current_arm.guard().is_some() {
4040
return None;
4141
}
4242
let current_expr = current_arm.expr()?;
4343
let current_text_range = current_arm.syntax().text_range();
4444
let current_arm_types = get_arm_types(ctx, &current_arm);
45+
let multi_arm_selection = !ctx.has_empty_selection()
46+
&& ctx.selection_trimmed().end() > current_arm.syntax().text_range().end();
4547

4648
// We check if the following match arms match this one. We could, but don't,
4749
// compare to the previous match arm as well.
4850
let arms_to_merge = successors(Some(current_arm), |it| neighbor(it, Direction::Next))
4951
.take_while(|arm| match arm.expr() {
5052
Some(expr) if arm.guard().is_none() => {
53+
// don't include match arms that start after our selection
54+
if multi_arm_selection
55+
&& arm.syntax().text_range().start() >= ctx.selection_trimmed().end()
56+
{
57+
return false;
58+
}
59+
5160
let same_text = expr.syntax().text() == current_expr.syntax().text();
5261
if !same_text {
5362
return false;
@@ -298,6 +307,96 @@ fn main() {
298307
)
299308
}
300309

310+
#[test]
311+
fn merge_match_arms_selection_has_leading_whitespace() {
312+
check_assist(
313+
merge_match_arms,
314+
r#"
315+
#[derive(Debug)]
316+
enum X { A, B, C }
317+
318+
fn main() {
319+
match X::A {
320+
$0 X::A => 0,
321+
X::B => 0,$0
322+
X::C => 1,
323+
}
324+
}
325+
"#,
326+
r#"
327+
#[derive(Debug)]
328+
enum X { A, B, C }
329+
330+
fn main() {
331+
match X::A {
332+
X::A | X::B => 0,
333+
X::C => 1,
334+
}
335+
}
336+
"#,
337+
);
338+
}
339+
340+
#[test]
341+
fn merge_match_arms_stops_at_end_of_selection() {
342+
check_assist(
343+
merge_match_arms,
344+
r#"
345+
#[derive(Debug)]
346+
enum X { A, B, C }
347+
348+
fn main() {
349+
match X::A {
350+
$0 X::A => 0,
351+
X::B => 0,
352+
$0X::C => 0,
353+
}
354+
}
355+
"#,
356+
r#"
357+
#[derive(Debug)]
358+
enum X { A, B, C }
359+
360+
fn main() {
361+
match X::A {
362+
X::A | X::B => 0,
363+
X::C => 0,
364+
}
365+
}
366+
"#,
367+
);
368+
}
369+
370+
#[test]
371+
fn merge_match_arms_works_despite_accidental_selection() {
372+
check_assist(
373+
merge_match_arms,
374+
r#"
375+
#[derive(Debug)]
376+
enum X { A, B, C }
377+
378+
fn main() {
379+
match X::A {
380+
X::$0A$0 => 0,
381+
X::B => 0,
382+
X::C => 1,
383+
}
384+
}
385+
"#,
386+
r#"
387+
#[derive(Debug)]
388+
enum X { A, B, C }
389+
390+
fn main() {
391+
match X::A {
392+
X::A | X::B => 0,
393+
X::C => 1,
394+
}
395+
}
396+
"#,
397+
);
398+
}
399+
301400
#[test]
302401
fn merge_match_arms_rejects_guards() {
303402
check_assist_not_applicable(

0 commit comments

Comments
 (0)