Skip to content

Commit 22bad62

Browse files
committed
Improved collapsing nested cases with list tails
1 parent 8c803d9 commit 22bad62

File tree

5 files changed

+54
-34
lines changed

5 files changed

+54
-34
lines changed

compiler-core/src/ast.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2661,6 +2661,10 @@ impl SrcSpan {
26612661
end: self.end.max(with.end),
26622662
}
26632663
}
2664+
2665+
pub fn len(&self) -> usize {
2666+
(self.end - self.start) as usize
2667+
}
26642668
}
26652669

26662670
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -3165,7 +3169,7 @@ pub enum BoundVariableName {
31653169
ListTail {
31663170
name: EcoString,
31673171
/// The location of the whole tail, from the `..` prefix until the end of the variable.
3168-
tail_prefix_location: SrcSpan,
3172+
tail_location: SrcSpan,
31693173
},
31703174
/// Any other variable name.
31713175
Regular { name: EcoString },
@@ -3412,7 +3416,7 @@ impl TypedPattern {
34123416
variables.push(BoundVariable {
34133417
name: BoundVariableName::ListTail {
34143418
name,
3415-
tail_prefix_location: tail.location,
3419+
tail_location: tail.location,
34163420
},
34173421
location,
34183422
type_: type_.clone(),

compiler-core/src/language_server/code_action.rs

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use ecow::{EcoString, eco_format};
2828
use im::HashMap;
2929
use itertools::Itertools;
3030
use lsp_types::{CodeAction, CodeActionKind, CodeActionParams, Position, Range, TextEdit, Url};
31-
use regex::Regex;
3231
use vec1::{Vec1, vec1};
3332

3433
use super::{
@@ -4801,8 +4800,7 @@ impl<'a, IO> PatternMatchOnValue<'a, IO> {
48014800
};
48024801

48034802
let variable_start = (variable_location.start - clause_location.start) as usize;
4804-
let variable_end =
4805-
variable_start + (variable_location.end - variable_location.start) as usize;
4803+
let variable_end = variable_start + variable_location.len();
48064804

48074805
let clause_code = code_at(self.module, clause_location);
48084806
let patterns = patterns
@@ -8273,34 +8271,43 @@ impl<'a> CollapseNestedCase<'a> {
82738271
name: BoundVariableName::Regular { .. } | BoundVariableName::ListTail { .. },
82748272
..
82758273
} => {
8276-
// If the variable is a regular variable we'll have to replace
8277-
// it entirely with the new pattern taking its place.
8274+
let trimmed_contents = new_content.trim();
8275+
8276+
let pattern_is_literal_list =
8277+
trimmed_contents.starts_with("[") && trimmed_contents.ends_with("]");
8278+
let pattern_is_discard = trimmed_contents == "_";
8279+
8280+
let span_to_replace = match (
8281+
&matched_variable.name,
8282+
// We verify whether the pattern is compatible with the list prefix `..`.
8283+
// For example, `..var` is valid syntax, but `..[]` and `.._` are not.
8284+
pattern_is_literal_list || pattern_is_discard,
8285+
) {
8286+
// We normally replace the selected variable with the pattern.
8287+
(BoundVariableName::Regular { .. }, _) => matched_variable_span,
8288+
8289+
// If the selected pattern is not a list, we also replace it normally.
8290+
(BoundVariableName::ListTail { .. }, false) => matched_variable_span,
8291+
// If the pattern is a list to also remove the list tail prefix.
8292+
(BoundVariableName::ListTail { tail_location, .. }, true) => {
8293+
// When it's a list literal, we remove the surrounding brackets.
8294+
let len = trimmed_contents.len();
8295+
if let Some(slice) = new_content.trim().get(1..(len - 1)) {
8296+
new_content = slice.to_string()
8297+
};
82788298

8279-
let variable_span_to_use = if let BoundVariableName::ListTail {
8280-
tail_prefix_location: prefix_and_variable_span,
8281-
..
8282-
} = matched_variable.name
8283-
{
8284-
// We need to un-nest the list when replacing the tail
8285-
let surrounding_brackets = Regex::new(r"(^\[|\]$)").expect("a valid regex");
8286-
new_content = surrounding_brackets
8287-
.replace_all(new_content.trim(), "")
8288-
.to_string();
8289-
8290-
// We need to also remove the prefix when replacing the variable
8291-
// at the tail of the list
8292-
prefix_and_variable_span
8293-
} else {
8294-
matched_variable_span
8299+
*tail_location
8300+
}
8301+
8302+
(BoundVariableName::ShorthandLabel { .. }, _) => unreachable!(),
82958303
};
82968304

8297-
let variable_start_in_pattern =
8298-
(variable_span_to_use.start - matched_pattern_span.start) as usize;
8299-
let variable_length =
8300-
(variable_span_to_use.end - variable_span_to_use.start) as usize;
8305+
let start_of_pattern =
8306+
(span_to_replace.start - matched_pattern_span.start) as usize;
8307+
let pattern_length = span_to_replace.len();
83018308

8302-
let variable_end_in_pattern = variable_start_in_pattern + variable_length;
8303-
let replaced_range = variable_start_in_pattern..variable_end_in_pattern;
8309+
let end_of_pattern = start_of_pattern + pattern_length;
8310+
let replaced_range = start_of_pattern..end_of_pattern;
83048311

83058312
new_pattern.replace_range(replaced_range, &new_content);
83068313
}

compiler-core/src/language_server/engine.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1469,7 +1469,7 @@ fn code_action_unused_values(
14691469
}
14701470

14711471
// Sort spans by start position, with longer spans coming first
1472-
unused_values.sort_by_key(|span| (span.start, -(span.end as i64 - span.start as i64)));
1472+
unused_values.sort_by_key(|span| (span.start, -(span.len() as i64)));
14731473

14741474
let mut processed_lsp_range = Vec::new();
14751475

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9981,7 +9981,10 @@ fn collapse_nested_case_combines_list_with_tail() {
99819981
[[1]] -> 1
99829982
[_, [3, 4]] -> 3
99839983
[_, _, [5, 6, 7], _] -> 5
9984-
_ -> -1
9984+
tail_list -> {
9985+
echo tail_list
9986+
-1
9987+
}
99859988
}
99869989
_ -> -1
99879990
}

compiler-core/src/language_server/tests/snapshots/gleam_core__language_server__tests__action__collapse_nested_case_combines_list_with_tail.snap

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
source: compiler-core/src/language_server/tests/action.rs
3-
expression: "pub fn main(elems: List(List(Int))) {\n case elems {\n [] -> 0\n [_, ..tail] ->\n case tail {\n [] -> -1\n [[1]] -> 1\n [_, [3, 4]] -> 3\n [_, _, [5, 6, 7], _] -> 5\n _ -> -1\n }\n _ -> -1\n }\n}"
3+
expression: "pub fn main(elems: List(List(Int))) {\n case elems {\n [] -> 0\n [_, ..tail] ->\n case tail {\n [] -> -1\n [[1]] -> 1\n [_, [3, 4]] -> 3\n [_, _, [5, 6, 7], _] -> 5\n tail_list -> {\n echo tail_list\n -1\n }\n }\n _ -> -1\n }\n}"
44
---
55
----- BEFORE ACTION
66
pub fn main(elems: List(List(Int))) {
@@ -13,7 +13,10 @@ pub fn main(elems: List(List(Int))) {
1313
[[1]] -> 1
1414
[_, [3, 4]] -> 3
1515
[_, _, [5, 6, 7], _] -> 5
16-
_ -> -1
16+
tail_list -> {
17+
echo tail_list
18+
-1
19+
}
1720
}
1821
_ -> -1
1922
}
@@ -28,7 +31,10 @@ pub fn main(elems: List(List(Int))) {
2831
[_, [1]] -> 1
2932
[_, _, [3, 4]] -> 3
3033
[_, _, _, [5, 6, 7], _] -> 5
31-
[_, _] -> -1
34+
[_, ..tail_list] -> {
35+
echo tail_list
36+
-1
37+
}
3238
_ -> -1
3339
}
3440
}

0 commit comments

Comments
 (0)