ide_assists/handlers/
flip_or_pattern.rs

1use syntax::{
2    Direction, T,
3    algo::non_trivia_sibling,
4    ast::{self, AstNode},
5};
6
7use crate::{AssistContext, AssistId, Assists};
8
9// Assist: flip_or_pattern
10//
11// Flips two patterns in an or-pattern.
12//
13// ```
14// fn foo() {
15//     let (a |$0 b) = 1;
16// }
17// ```
18// ->
19// ```
20// fn foo() {
21//     let (b | a) = 1;
22// }
23// ```
24pub(crate) fn flip_or_pattern(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
25    // Only flip on the `|` token
26    let pipe = ctx.find_token_syntax_at_offset(T![|])?;
27
28    let parent = ast::OrPat::cast(pipe.parent()?)?;
29
30    let before = non_trivia_sibling(pipe.clone().into(), Direction::Prev)?.into_node()?;
31    let after = non_trivia_sibling(pipe.clone().into(), Direction::Next)?.into_node()?;
32
33    let target = pipe.text_range();
34    acc.add(AssistId::refactor_rewrite("flip_or_pattern"), "Flip patterns", target, |builder| {
35        let mut editor = builder.make_editor(parent.syntax());
36        editor.replace(before.clone(), after.clone());
37        editor.replace(after, before);
38        builder.add_file_edits(ctx.vfs_file_id(), editor);
39    })
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
47
48    #[test]
49    fn flip_or_pattern_assist_available() {
50        check_assist_target(flip_or_pattern, "fn main(a |$0 b: ()) {}", "|")
51    }
52
53    #[test]
54    fn flip_or_pattern_not_applicable_for_leading_pipe() {
55        check_assist_not_applicable(flip_or_pattern, "fn main(|$0 b: ()) {}")
56    }
57
58    #[test]
59    fn flip_or_pattern_works() {
60        check_assist(
61            flip_or_pattern,
62            "fn foo() { let (a | b |$0 c | d) = 1; }",
63            "fn foo() { let (a | c | b | d) = 1; }",
64        )
65    }
66
67    #[test]
68    fn flip_or_pattern_works_match_guard() {
69        check_assist(
70            flip_or_pattern,
71            "fn foo() { match() { a |$0 b if true => () }}",
72            "fn foo() { match() { b | a if true => () }}",
73        )
74    }
75}