Skip to content

Commit 4b5a41d

Browse files
giacomocavalierilpil
authored andcommitted
expand underscore
1 parent ea36bb1 commit 4b5a41d

5 files changed

+255
-2
lines changed

CHANGELOG.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,8 @@
184184

185185
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
186186

187-
- The "pattern match on variable" can now be triggered on variables introduced
188-
by other patterns. For example:
187+
- The "pattern match on variable" code action can now be triggered on variables
188+
introduced by other patterns. For example:
189189

190190
```gleam
191191
pub fn main() {
@@ -209,6 +209,36 @@
209209

210210
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
211211

212+
- The "pattern match on variable" code action can now be triggered on variables
213+
in case expressions. For example:
214+
215+
```gleam
216+
pub fn main() {
217+
case find_user() {
218+
Ok(user) -> todo
219+
Error(_) -> todo
220+
}
221+
}
222+
```
223+
224+
Triggering the action over the `user` variable would result in the following
225+
code:
226+
227+
```gleam
228+
pub fn main() {
229+
case find_user() {
230+
Ok(user) ->
231+
case user {
232+
Admin -> todo
233+
Member -> todo
234+
}
235+
Error(_) -> todo
236+
}
237+
}
238+
```
239+
240+
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
241+
212242
- The language server now offers a quick fix to remove `opaque` from a private
213243
type:
214244

compiler-core/src/language_server/code_action.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4353,6 +4353,20 @@ pub enum PatternMatchedValue<'a> {
43534353
///
43544354
assignment_location: SrcSpan,
43554355
},
4356+
/// A variable that is bound in a case branch's pattern. For example:
4357+
/// ```gleam
4358+
/// case wibble {
4359+
/// wobble -> 1
4360+
/// // ^^^^^ This!
4361+
/// }
4362+
/// ```
4363+
///
4364+
ClausePatternVariable {
4365+
variable_name: &'a EcoString,
4366+
variable_type: Arc<Type>,
4367+
clause_body_location: SrcSpan,
4368+
clause_location: SrcSpan,
4369+
},
43564370
UseVariable {
43574371
variable_name: &'a EcoString,
43584372
variable_type: Arc<Type>,
@@ -4411,6 +4425,21 @@ where
44114425
"Pattern match on variable"
44124426
}
44134427

4428+
Some(PatternMatchedValue::ClausePatternVariable {
4429+
variable_name,
4430+
variable_type,
4431+
clause_body_location,
4432+
clause_location,
4433+
}) => {
4434+
self.match_on_clause_variable(
4435+
variable_name,
4436+
variable_type,
4437+
clause_body_location,
4438+
clause_location,
4439+
);
4440+
"Pattern match on variable"
4441+
}
4442+
44144443
None => return vec![],
44154444
};
44164445

@@ -4523,6 +4552,34 @@ where
45234552
);
45244553
}
45254554

4555+
fn match_on_clause_variable(
4556+
&mut self,
4557+
variable_name: &EcoString,
4558+
variable_type: Arc<Type>,
4559+
clause_body_location: SrcSpan,
4560+
clause_location: SrcSpan,
4561+
) {
4562+
let Some(patterns) = self.type_to_destructure_patterns(variable_type.as_ref()) else {
4563+
return;
4564+
};
4565+
4566+
let body_code = code_at(self.module, clause_body_location);
4567+
4568+
let clause_range = self.edits.src_span_to_lsp_range(clause_location);
4569+
let nesting = " ".repeat(2 + clause_range.start.character as usize);
4570+
4571+
let patterns = patterns
4572+
.iter()
4573+
.map(|p| format!(" {nesting}{p} -> {body_code}"))
4574+
.join("\n");
4575+
let pattern_matching = format!("case {variable_name} {{\n{patterns}\n{nesting}}}");
4576+
4577+
self.edits.replace(
4578+
clause_body_location,
4579+
format!("\n{nesting}{pattern_matching}"),
4580+
);
4581+
}
4582+
45264583
/// Will produce a pattern that can be used on the left hand side of a let
45274584
/// assignment to destructure a value of the given type. For example given
45284585
/// this type:
@@ -4761,6 +4818,28 @@ where
47614818
}
47624819
}
47634820

4821+
fn visit_typed_clause(&mut self, clause: &'ast ast::TypedClause) {
4822+
for pattern in clause.pattern.iter() {
4823+
self.visit_typed_pattern(pattern);
4824+
}
4825+
for patterns in clause.alternative_patterns.iter() {
4826+
for pattern in patterns {
4827+
self.visit_typed_pattern(pattern);
4828+
}
4829+
}
4830+
4831+
if let Some((name, type_)) = self.pattern_variable_under_cursor.take() {
4832+
self.selected_value = Some(PatternMatchedValue::ClausePatternVariable {
4833+
variable_name: name,
4834+
variable_type: type_,
4835+
clause_body_location: clause.then.location(),
4836+
clause_location: clause.location(),
4837+
});
4838+
} else {
4839+
self.visit_typed_expr(&clause.then);
4840+
}
4841+
}
4842+
47644843
fn visit_typed_use(&mut self, use_: &'ast TypedUse) {
47654844
if let Some(assignments) = use_.callback_arguments() {
47664845
for variable in assignments {

compiler-core/src/language_server/tests/action.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6967,6 +6967,57 @@ pub fn main() {
69676967
);
69686968
}
69696969

6970+
#[test]
6971+
fn pattern_match_on_clause_variable() {
6972+
assert_code_action!(
6973+
PATTERN_MATCH_ON_VARIABLE,
6974+
"
6975+
pub fn main() {
6976+
case maybe_wibble() {
6977+
Ok(something) -> 1
6978+
Error(_) -> 2
6979+
}
6980+
}
6981+
6982+
type Wibble {
6983+
Wobble
6984+
Woo
6985+
}
6986+
6987+
fn maybe_wibble() { Ok(Wobble) }
6988+
6989+
",
6990+
find_position_of("something").to_selection()
6991+
);
6992+
}
6993+
6994+
#[test]
6995+
fn pattern_match_on_clause_variable_with_block_body() {
6996+
assert_code_action!(
6997+
PATTERN_MATCH_ON_VARIABLE,
6998+
"
6999+
pub fn main() {
7000+
case maybe_wibble() {
7001+
Ok(something) -> {
7002+
1
7003+
2
7004+
}
7005+
Error(_) -> 2
7006+
}
7007+
}
7008+
7009+
type Wibble {
7010+
Wobble
7011+
Woo
7012+
}
7013+
7014+
fn maybe_wibble() { Ok(Wobble) }
7015+
7016+
",
7017+
find_position_of("something").to_selection()
7018+
);
7019+
}
7020+
69707021
#[test]
69717022
fn pattern_match_on_argument_will_use_qualified_name() {
69727023
let src = "
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n case maybe_wibble() {\n Ok(something) -> 1\n Error(_) -> 2\n }\n}\n\ntype Wibble {\n Wobble\n Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
case maybe_wibble() {
9+
Ok(something) -> 1
10+
11+
Error(_) -> 2
12+
}
13+
}
14+
15+
type Wibble {
16+
Wobble
17+
Woo
18+
}
19+
20+
fn maybe_wibble() { Ok(Wobble) }
21+
22+
23+
24+
----- AFTER ACTION
25+
26+
pub fn main() {
27+
case maybe_wibble() {
28+
Ok(something) ->
29+
case something {
30+
Wobble -> 1
31+
Woo -> 1
32+
}
33+
Error(_) -> 2
34+
}
35+
}
36+
37+
type Wibble {
38+
Wobble
39+
Woo
40+
}
41+
42+
fn maybe_wibble() { Ok(Wobble) }
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n case maybe_wibble() {\n Ok(something) -> {\n 1\n 2\n }\n Error(_) -> 2\n }\n}\n\ntype Wibble {\n Wobble\n Woo\n}\n\nfn maybe_wibble() { Ok(Wobble) }\n\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
case maybe_wibble() {
9+
Ok(something) -> {
10+
11+
1
12+
2
13+
}
14+
Error(_) -> 2
15+
}
16+
}
17+
18+
type Wibble {
19+
Wobble
20+
Woo
21+
}
22+
23+
fn maybe_wibble() { Ok(Wobble) }
24+
25+
26+
27+
----- AFTER ACTION
28+
29+
pub fn main() {
30+
case maybe_wibble() {
31+
Ok(something) ->
32+
case something {
33+
Wobble -> {
34+
1
35+
2
36+
}
37+
Woo -> {
38+
1
39+
2
40+
}
41+
}
42+
Error(_) -> 2
43+
}
44+
}
45+
46+
type Wibble {
47+
Wobble
48+
Woo
49+
}
50+
51+
fn maybe_wibble() { Ok(Wobble) }

0 commit comments

Comments
 (0)