Fork of daniellemaywood.uk/gleam — Wasm codegen work
201 kB
9711 lines
1use itertools::Itertools;
2use lsp_types::{
3 CodeActionContext, CodeActionParams, PartialResultParams, Position, Range, Url,
4 WorkDoneProgressParams,
5};
6
7use super::*;
8
9fn code_actions(tester: &TestProject<'_>, range: Range) -> Option<Vec<lsp_types::CodeAction>> {
10 let position = Position {
11 line: 0,
12 character: 0,
13 };
14
15 tester.at(position, |engine, params, _| {
16 let params = CodeActionParams {
17 text_document: params.text_document,
18 range,
19 context: CodeActionContext::default(),
20 work_done_progress_params: WorkDoneProgressParams::default(),
21 partial_result_params: PartialResultParams::default(),
22 };
23 engine.code_actions(params).result.unwrap()
24 })
25}
26
27fn actions_with_title(
28 titles: Vec<&str>,
29 tester: &TestProject<'_>,
30 range: Range,
31) -> Vec<lsp_types::CodeAction> {
32 code_actions(tester, range)
33 .into_iter()
34 .flatten()
35 .filter(|action| titles.contains(&action.title.as_str()))
36 .collect_vec()
37}
38
39fn owned_actions_with_title(
40 titles: Vec<&str>,
41 tester: TestProject<'_>,
42 range: Range,
43) -> Vec<lsp_types::CodeAction> {
44 actions_with_title(titles, &tester, range)
45}
46
47fn apply_code_action(title: &str, tester: TestProject<'_>, range: Range) -> String {
48 let titles = vec![title];
49 let changes = actions_with_title(titles, &tester, range)
50 .pop()
51 .expect("No action with the given title")
52 .edit
53 .expect("No workspace edit found")
54 .changes
55 .expect("No text edit found");
56 apply_code_edit(tester, changes)
57}
58
59fn apply_code_edit(
60 tester: TestProject<'_>,
61 changes: HashMap<Url, Vec<lsp_types::TextEdit>>,
62) -> String {
63 let mut changed_files: HashMap<Url, String> = HashMap::new();
64 for (uri, change) in changes {
65 let code = match changed_files.get(&uri) {
66 Some(code) => code,
67 None => tester
68 .src_from_module_url(&uri)
69 .expect(&format!("no src for url {:?}", uri)),
70 };
71 let code = super::apply_code_edit(code, change);
72 let _ = changed_files.insert(uri, code);
73 }
74
75 show_code_edits(tester, changed_files)
76}
77
78fn show_code_edits(tester: TestProject<'_>, changed_files: HashMap<Url, String>) -> String {
79 let format_code = |url: &Url, code: &String| {
80 format!(
81 "// --- Edits applied to module '{}'\n{}",
82 tester.module_name_from_url(url).expect("a module"),
83 code
84 )
85 };
86
87 // If the file that changed is the main one we just show its code.
88 if changed_files.len() == 1 {
89 let mut changed = changed_files.iter().peekable();
90 let (url, code) = changed.peek().unwrap();
91 if tester.module_name_from_url(url) == Some("app".into()) {
92 code.to_string()
93 } else {
94 format_code(url, code)
95 }
96 } else {
97 // If more than a single file changed we want to add the name of the
98 // file before each!
99 changed_files
100 .iter()
101 .map(|(url, code)| format_code(url, code))
102 .join("\n")
103 }
104}
105
106const REMOVE_UNUSED_IMPORTS: &str = "Remove unused imports";
107const REMOVE_REDUNDANT_TUPLES: &str = "Remove redundant tuples";
108const CONVERT_TO_CASE: &str = "Convert to case";
109const USE_LABEL_SHORTHAND_SYNTAX: &str = "Use label shorthand syntax";
110const FILL_LABELS: &str = "Fill labels";
111const ASSIGN_UNUSED_RESULT: &str = "Assign unused Result value to `_`";
112const ADD_MISSING_PATTERNS: &str = "Add missing patterns";
113const ADD_ANNOTATION: &str = "Add type annotation";
114const ADD_ANNOTATIONS: &str = "Add type annotations";
115const CONVERT_FROM_USE: &str = "Convert from `use`";
116const CONVERT_TO_USE: &str = "Convert to `use`";
117const EXTRACT_VARIABLE: &str = "Extract variable";
118const EXTRACT_CONSTANT: &str = "Extract constant";
119const EXPAND_FUNCTION_CAPTURE: &str = "Expand function capture";
120const GENERATE_DYNAMIC_DECODER: &str = "Generate dynamic decoder";
121const GENERATE_TO_JSON_FUNCTION: &str = "Generate to-JSON function";
122const PATTERN_MATCH_ON_ARGUMENT: &str = "Pattern match on argument";
123const PATTERN_MATCH_ON_VARIABLE: &str = "Pattern match on variable";
124const GENERATE_FUNCTION: &str = "Generate function";
125const CONVERT_TO_FUNCTION_CALL: &str = "Convert to function call";
126const INLINE_VARIABLE: &str = "Inline variable";
127const CONVERT_TO_PIPE: &str = "Convert to pipe";
128const INTERPOLATE_STRING: &str = "Interpolate string";
129const FILL_UNUSED_FIELDS: &str = "Fill unused fields";
130const REMOVE_ALL_ECHOS_FROM_THIS_MODULE: &str = "Remove all `echo`s from this module";
131const WRAP_IN_BLOCK: &str = "Wrap in block";
132const GENERATE_VARIANT: &str = "Generate variant";
133const REMOVE_BLOCK: &str = "Remove block";
134const REMOVE_OPAQUE_FROM_PRIVATE_TYPE: &str = "Remove opaque from private type";
135const COLLAPSE_NESTED_CASE: &str = "Collapse nested case";
136
137macro_rules! assert_code_action {
138 ($title:expr, $code:literal, $range:expr $(,)?) => {
139 let project = TestProject::for_source($code);
140 assert_code_action!($title, project, $range);
141 };
142
143 ($title:expr, $project:expr, $range:expr $(,)?) => {
144 let src = $project.src;
145 let range = $range.find_range(src);
146 let result = apply_code_action($title, $project, range);
147 let output = format!(
148 "----- BEFORE ACTION\n{}\n\n----- AFTER ACTION\n{}",
149 hover::show_hover(src, range, range.end),
150 result
151 );
152 insta::assert_snapshot!(insta::internals::AutoName, output, src);
153 };
154}
155
156macro_rules! assert_no_code_actions {
157 ($title:ident $(| $titles:ident)*, $code:literal, $range:expr $(,)?) => {
158 let project = TestProject::for_source($code);
159 assert_no_code_actions!($title $(| $titles)*, project, $range);
160 };
161
162 ($title:ident $(| $titles:ident)*, $project:expr, $range:expr $(,)?) => {
163 let src = $project.src;
164 let range = $range.find_range(src);
165 let all_titles = vec![$title $(, $titles)*];
166 let expected: Vec<lsp_types::CodeAction> = vec![];
167 let result = owned_actions_with_title(all_titles, $project, range);
168 assert_eq!(expected, result);
169 };
170}
171
172#[test]
173fn fix_truncated_segment_1() {
174 let name = "Replace with `1`";
175 assert_code_action!(
176 name,
177 r#"
178pub fn main() {
179 <<1, 257, 259:size(1)>>
180}"#,
181 find_position_of("257").to_selection()
182 );
183}
184
185#[test]
186fn fix_truncated_segment_2() {
187 let name = "Replace with `0`";
188 assert_code_action!(
189 name,
190 r#"
191pub fn main() {
192 <<1, 1024:size(10)>>
193}"#,
194 find_position_of("size").to_selection()
195 );
196}
197
198#[test]
199fn generate_variant_with_fields_in_same_module() {
200 assert_code_action!(
201 GENERATE_VARIANT,
202 r#"
203pub type Wibble {
204 Wibble
205}
206
207pub fn main() -> Wibble {
208 Wobble(1)
209}"#,
210 find_position_of("Wobble").to_selection()
211 );
212}
213
214#[test]
215fn generate_variant_with_no_fields_in_same_module() {
216 assert_code_action!(
217 GENERATE_VARIANT,
218 r#"
219pub type Wibble {
220 Wibble
221}
222
223pub fn main() -> Wibble {
224 Wobble
225}"#,
226 find_position_of("Wobble").to_selection()
227 );
228}
229
230#[test]
231fn generate_variant_with_labels_in_same_module() {
232 assert_code_action!(
233 GENERATE_VARIANT,
234 r#"
235pub type Wibble {
236 Wibble
237}
238
239pub fn main() -> Wibble {
240 Wobble("hello", label: 1)
241}"#,
242 find_position_of("Wobble").to_selection()
243 );
244}
245
246#[test]
247fn generate_variant_from_pattern_with_fields() {
248 assert_code_action!(
249 GENERATE_VARIANT,
250 r#"
251pub type Wibble {
252 Wibble
253}
254
255pub fn new() { Wibble }
256
257pub fn main() -> Wibble {
258 let assert Wobble(1) = new()
259}
260
261"#,
262 find_position_of("Wobble").to_selection()
263 );
264}
265
266#[test]
267fn generate_variant_from_pattern_with_labelled_fields() {
268 assert_code_action!(
269 GENERATE_VARIANT,
270 r#"
271pub type Wibble {
272 Wibble
273}
274
275pub fn new() { Wibble }
276
277pub fn main() -> Wibble {
278 let assert Wobble("hello", label: 1) = new()
279}
280
281"#,
282 find_position_of("Wobble").to_selection()
283 );
284}
285
286#[test]
287fn generate_variant_from_pattern_with_no_fields() {
288 assert_code_action!(
289 GENERATE_VARIANT,
290 r#"
291pub type Wibble {
292 Wibble
293}
294
295pub fn new() { Wibble }
296
297pub fn main() -> Wibble {
298 let assert Wobble = new()
299}
300
301"#,
302 find_position_of("Wobble").to_selection()
303 );
304}
305
306#[test]
307fn generate_unqualified_variant_in_other_module() {
308 let src = r#"
309import other
310
311pub fn main() -> other.Wibble {
312 let assert Wobble = new()
313}
314
315pub fn new() -> other.Wibble { todo }
316"#;
317
318 assert_code_action!(
319 GENERATE_VARIANT,
320 TestProject::for_source(src).add_module("other", "pub type Wibble"),
321 find_position_of("Wobble").to_selection()
322 );
323}
324
325#[test]
326fn generate_qualified_variant_in_other_module() {
327 let src = r#"
328import other
329
330pub fn main() -> other.Wibble {
331 let assert other.Wobble = new()
332}
333
334pub fn new() -> other.Wibble { todo }
335"#;
336 assert_code_action!(
337 GENERATE_VARIANT,
338 TestProject::for_source(src).add_module("other", "pub type Wibble"),
339 find_position_of("Wobble").to_selection()
340 );
341}
342
343#[test]
344fn do_not_generate_variant_if_one_with_the_same_name_exists() {
345 assert_no_code_actions!(
346 GENERATE_VARIANT,
347 r#"
348pub fn main() -> Wibble {
349 let assert Wobble = new()
350}
351
352pub type Wibble {
353 Wobble(n: Int)
354}
355
356pub fn new() -> Wibble { todo }
357"#,
358 find_position_of("Wobble").to_selection()
359 );
360}
361
362#[test]
363fn do_not_generate_variant_if_one_with_the_same_name_exists_in_other_module() {
364 let src = r#"
365import other.{type Wibble}
366
367pub fn main() -> Wibble {
368 let assert Wobble = new()
369}
370
371pub fn new() -> Wibble { todo }
372"#;
373 assert_no_code_actions!(
374 GENERATE_VARIANT,
375 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"),
376 find_position_of("Wobble").to_selection()
377 );
378}
379
380#[test]
381fn do_not_generate_qualified_variant_if_one_with_the_same_name_exists_in_other_module() {
382 let src = r#"
383import other.{type Wibble}
384
385pub fn main() -> Wibble {
386 let assert other.Wobble = new()
387}
388
389pub fn new() -> Wibble { todo }
390"#;
391 assert_no_code_actions!(
392 GENERATE_VARIANT,
393 TestProject::for_source(src).add_module("other", "pub type Wibble { Wobble(String) }"),
394 find_position_of("Wobble").to_selection()
395 );
396}
397
398#[test]
399fn fill_unused_fields_with_ignored_labelled_fields() {
400 assert_code_action!(
401 FILL_UNUSED_FIELDS,
402 r#"
403pub type Wibble { Wibble(Int, label1: String, label2: Int) }
404
405pub fn main() {
406 let Wibble(_, ..) = todo
407}"#,
408 find_position_of("..").to_selection()
409 );
410}
411
412#[test]
413fn fill_unused_fields_with_ignored_positional_fields() {
414 assert_code_action!(
415 FILL_UNUSED_FIELDS,
416 r#"
417pub type Wibble { Wibble(Int, label1: String, label2: Int) }
418
419pub fn main() {
420 let Wibble(label1:, label2:, ..) = todo
421}"#,
422 find_position_of("..").to_selection()
423 );
424}
425
426#[test]
427fn fill_unused_fields_with_all_positional_fields() {
428 assert_code_action!(
429 FILL_UNUSED_FIELDS,
430 r#"
431pub type Wibble { Wibble(Int, String) }
432
433pub fn main() {
434 let Wibble(..) = todo
435}"#,
436 find_position_of("..").to_selection()
437 );
438}
439
440#[test]
441fn fill_unused_fields_with_ignored_mixed_fields() {
442 assert_code_action!(
443 FILL_UNUSED_FIELDS,
444 r#"
445pub type Wibble { Wibble(Int, String, label1: String, label2: Int) }
446
447pub fn main() {
448 let Wibble(_, label2:, ..) = todo
449}"#,
450 find_position_of("..").to_selection()
451 );
452}
453
454#[test]
455fn fill_unused_fields_with_all_ignored_fields() {
456 assert_code_action!(
457 FILL_UNUSED_FIELDS,
458 r#"
459pub type Wibble { Wibble(Int, label1: String, label2: Int) }
460
461pub fn main() {
462 let Wibble(..) = todo
463}"#,
464 find_position_of("..").to_selection()
465 );
466}
467
468#[test]
469fn fill_unused_fields_with_ignored_fields_never_calls_a_positional_arg_as_a_labelled_one() {
470 assert_code_action!(
471 FILL_UNUSED_FIELDS,
472 r#"
473pub type Wibble { Wibble(Int, int: Int) }
474
475pub fn main() {
476 let Wibble(..) = todo
477}"#,
478 find_position_of("..").to_selection()
479 );
480}
481
482#[test]
483fn remove_echo() {
484 assert_code_action!(
485 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
486 "pub fn main() {
487 echo 1 + 2
488}",
489 find_position_of("echo").to_selection()
490 );
491}
492
493#[test]
494fn remove_echo_with_message() {
495 assert_code_action!(
496 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
497 r#"pub fn main() {
498 echo 1 + 2 as "message"
499}"#,
500 find_position_of("echo").to_selection()
501 );
502}
503
504#[test]
505fn remove_echo_with_message_and_comment() {
506 assert_code_action!(
507 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
508 r#"pub fn main() {
509 echo 1 + 2
510 // Hello!
511 as "message"
512}"#,
513 find_position_of("echo").to_selection()
514 );
515}
516
517#[test]
518fn remove_echo_with_message_and_comment_2() {
519 assert_code_action!(
520 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
521 r#"pub fn main() {
522 echo 1 + 2 as
523 // Hello!
524 "message"
525}"#,
526 find_position_of("echo").to_selection()
527 );
528}
529
530#[test]
531fn remove_echo_with_message_and_comment_3() {
532 assert_code_action!(
533 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
534 r#"pub fn main() {
535 echo 1 + 2 as
536 // Hello!
537 "message"
538
539 Nil
540}"#,
541 find_position_of("echo").to_selection()
542 );
543}
544
545#[test]
546fn remove_echo_selecting_expression() {
547 assert_code_action!(
548 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
549 "pub fn main() {
550 echo 1 + 2
551}",
552 find_position_of("1").select_until(find_position_of("2"))
553 );
554}
555
556#[test]
557fn remove_echo_selecting_message() {
558 assert_code_action!(
559 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
560 r#"pub fn main() {
561 echo 1 + 2 as "message"
562}"#,
563 find_position_of("message").to_selection()
564 );
565}
566
567#[test]
568fn remove_echo_as_function_arg() {
569 assert_code_action!(
570 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
571 "pub fn main() {
572 wibble([], echo 1 + 2)
573}",
574 find_position_of("1").to_selection()
575 );
576}
577
578#[test]
579fn remove_echo_in_pipeline_step() {
580 assert_code_action!(
581 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
582 "pub fn main() {
583 [1, 2, 3]
584 |> echo
585 |> wibble
586}",
587 find_position_of("echo").to_selection()
588 );
589}
590
591#[test]
592fn remove_echo_in_pipeline_step_with_message() {
593 assert_code_action!(
594 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
595 r#"pub fn main() {
596 [1, 2, 3]
597 |> echo as message
598 |> wibble
599}"#,
600 find_position_of("echo").to_selection()
601 );
602}
603
604#[test]
605fn remove_echo_in_single_line_pipeline_step() {
606 assert_code_action!(
607 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
608 "pub fn main() {
609 [1, 2, 3] |> echo |> wibble
610}",
611 find_position_of("echo").to_selection()
612 );
613}
614
615#[test]
616fn remove_echo_in_single_line_pipeline_step_with_message() {
617 assert_code_action!(
618 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
619 r#"pub fn main() {
620 [1, 2, 3] |> echo as "message" |> wibble
621}"#,
622 find_position_of("echo").to_selection()
623 );
624}
625
626#[test]
627fn remove_echo_last_in_long_pipeline_step() {
628 assert_code_action!(
629 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
630 "pub fn main() {
631 [1, 2, 3]
632 |> wibble
633 |> echo
634}",
635 find_position_of("echo").to_selection()
636 );
637}
638
639#[test]
640fn remove_echo_last_in_long_pipeline_step_with_message() {
641 assert_code_action!(
642 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
643 r#"pub fn main() {
644 [1, 2, 3]
645 |> wibble
646 |> echo as "message"
647}"#,
648 find_position_of("echo").to_selection()
649 );
650}
651
652#[test]
653fn remove_echo_last_in_short_pipeline_step() {
654 assert_code_action!(
655 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
656 "pub fn main() {
657 [1, 2, 3]
658 |> echo
659}",
660 find_position_of("echo").to_selection()
661 );
662}
663
664#[test]
665fn remove_echo_last_in_short_pipeline_step_with_message() {
666 assert_code_action!(
667 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
668 r#"pub fn main() {
669 [1, 2, 3]
670 |> echo as "message"
671}"#,
672 find_position_of("echo").to_selection()
673 );
674}
675
676#[test]
677fn remove_echo_before_pipeline() {
678 assert_code_action!(
679 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
680 "pub fn main() {
681 echo [1, 2, 3] |> wibble
682}",
683 find_position_of("echo").to_selection()
684 );
685}
686
687#[test]
688fn remove_echo_before_pipeline_selecting_step() {
689 assert_code_action!(
690 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
691 "pub fn main() {
692 echo [1, 2, 3] |> wibble
693}",
694 find_position_of("wibble").to_selection()
695 );
696}
697
698#[test]
699fn remove_echo_removes_all_echos() {
700 assert_code_action!(
701 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
702 "pub fn main() {
703 echo wibble(echo 1, 2)
704}",
705 find_position_of("echo").nth_occurrence(2).to_selection()
706 );
707}
708
709#[test]
710fn remove_echo_removes_all_echos_1() {
711 assert_code_action!(
712 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
713 "pub fn main() {
714 echo 1 |> echo |> echo |> wibble |> echo
715 echo wibble(echo 1, echo 2)
716 echo 1
717}",
718 find_position_of("echo").nth_occurrence(2).to_selection()
719 );
720}
721
722#[test]
723fn remove_echo_removes_entire_echo_statement_used_with_literals() {
724 assert_code_action!(
725 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
726 "pub fn main() {
727 echo 1
728 Nil
729}",
730 find_position_of("echo").to_selection()
731 );
732}
733
734#[test]
735fn remove_echo_removes_entire_echo_statement_used_with_literals_and_message() {
736 assert_code_action!(
737 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
738 r#"pub fn main() {
739 echo 1 as "message"
740 Nil
741}"#,
742 find_position_of("echo").to_selection()
743 );
744}
745
746#[test]
747fn remove_echo_removes_entire_echo_statement_used_with_a_var() {
748 assert_code_action!(
749 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
750 "pub fn main() {
751 let a = 1
752 echo a
753 Nil
754}",
755 find_position_of("echo").to_selection()
756 );
757}
758
759#[test]
760fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals() {
761 assert_code_action!(
762 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
763 r#"pub fn main() {
764 echo 1
765 echo "wibble"
766 Nil
767}"#,
768 find_position_of("echo").to_selection()
769 );
770}
771
772#[test]
773fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_but_stops_at_comments() {
774 assert_code_action!(
775 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
776 r#"pub fn main() {
777 echo 1
778
779 // Oh no I hope I'm not deleted by the code action!!
780 Nil
781}"#,
782 find_position_of("echo").to_selection()
783 );
784}
785
786#[test]
787fn remove_echo_removes_entire_echo_statement_used_with_literals_in_a_fn() {
788 assert_code_action!(
789 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
790 "pub fn main() {
791 fn() {
792 echo 1
793 Nil
794 }
795}",
796 find_position_of("echo").to_selection()
797 );
798}
799
800#[test]
801fn remove_echo_removes_multiple_entire_echo_statement_used_with_literals_in_a_fn() {
802 assert_code_action!(
803 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
804 r#"pub fn main() {
805 fn() {
806 echo 1
807 echo "wibble"
808 Nil
809 }
810}"#,
811 find_position_of("echo").to_selection()
812 );
813}
814
815#[test]
816fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return() {
817 assert_code_action!(
818 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
819 "pub fn main() {
820 echo 1
821}",
822 find_position_of("echo").to_selection()
823 );
824}
825
826#[test]
827fn remove_echo_with_message_removes_does_not_remove_entire_echo_statement_if_its_the_return() {
828 assert_code_action!(
829 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
830 r#"pub fn main() {
831 echo 1 as "message"
832}"#,
833 find_position_of("echo").to_selection()
834 );
835}
836
837#[test]
838fn remove_echo_removes_does_not_remove_entire_echo_statement_if_its_the_return_of_a_fn() {
839 assert_code_action!(
840 REMOVE_ALL_ECHOS_FROM_THIS_MODULE,
841 r#"pub fn main() {
842 fn() {
843 echo 1
844 }
845}"#,
846 find_position_of("echo").to_selection()
847 );
848}
849
850#[test]
851fn split_string() {
852 assert_code_action!(
853 INTERPOLATE_STRING,
854 r#"pub fn main() {
855 "wibble wobble woo"
856}"#,
857 find_position_of("wobble").to_selection()
858 );
859}
860
861#[test]
862fn no_split_string_right_at_the_start() {
863 assert_no_code_actions!(
864 INTERPOLATE_STRING,
865 r#"pub fn main() {
866 "wibble wobble woo"
867}"#,
868 find_position_of("wibble").to_selection()
869 );
870}
871
872#[test]
873fn no_split_string_right_at_the_end() {
874 assert_no_code_actions!(
875 INTERPOLATE_STRING,
876 r#"pub fn main() {
877 "wibble wobble woo"
878}"#,
879 find_position_of("\"").nth_occurrence(2).to_selection()
880 );
881}
882
883#[test]
884fn no_split_string_before_the_start() {
885 assert_no_code_actions!(
886 INTERPOLATE_STRING,
887 r#"pub fn main() {
888 "wibble wobble woo"
889}"#,
890 find_position_of("\"").to_selection()
891 );
892}
893
894#[test]
895fn no_split_string_after_the_end() {
896 assert_no_code_actions!(
897 INTERPOLATE_STRING,
898 r#"pub fn main() {
899 "wibble wobble woo"//we need this comment so we can put the cursor _after_ the closing quote
900}"#,
901 find_position_of("\"/").under_last_char().to_selection()
902 );
903}
904
905#[test]
906fn interpolate_string_inside_string() {
907 assert_code_action!(
908 INTERPOLATE_STRING,
909 r#"pub fn main() {
910 "wibble wobble woo"
911}"#,
912 find_position_of("wobble").select_until(find_position_of("wobble ").under_last_char()),
913 );
914}
915
916#[test]
917fn fallback_to_split_string_when_selecting_invalid_name() {
918 assert_code_action!(
919 INTERPOLATE_STRING,
920 r#"pub fn main() {
921 "wibble wobble woo woo"
922}"#,
923 find_position_of("wobble").select_until(find_position_of("woo ").under_last_char()),
924 );
925}
926
927#[test]
928fn splitting_string_as_first_pipeline_step_inserts_brackets() {
929 assert_code_action!(
930 INTERPOLATE_STRING,
931 r#"pub fn main() {
932 "wibble wobble" |> io.println
933}"#,
934 find_position_of(" wobble").to_selection(),
935 );
936}
937
938#[test]
939fn interpolating_string_as_first_pipeline_step_inserts_brackets() {
940 assert_code_action!(
941 INTERPOLATE_STRING,
942 r#"pub fn main() {
943 "wibble wobble woo" |> io.println
944}"#,
945 find_position_of("wobble ").select_until(find_position_of("wobble ").under_last_char()),
946 );
947}
948
949#[test]
950fn test_remove_unused_simple() {
951 let src = "
952// test
953import // comment
954list as lispy
955import result
956import option
957
958pub fn main() {
959 result.is_ok
960}
961";
962
963 assert_code_action!(
964 REMOVE_UNUSED_IMPORTS,
965 TestProject::for_source(src)
966 .add_hex_module("list", "")
967 .add_hex_module("result", "")
968 .add_hex_module("option", ""),
969 find_position_of("// test").select_until(find_position_of("option")),
970 );
971}
972
973#[test]
974fn test_remove_unused_start_of_file() {
975 let src = "import option
976import result
977
978pub fn main() {
979 result.is_ok
980}
981";
982 assert_code_action!(
983 REMOVE_UNUSED_IMPORTS,
984 TestProject::for_source(src)
985 .add_hex_module("option", "")
986 .add_hex_module("result", ""),
987 find_position_of("import").select_until(find_position_of("pub")),
988 );
989}
990
991#[test]
992fn test_remove_unused_alias() {
993 let src = "
994// test
995import result.{is_ok} as res
996import option
997
998pub fn main() {
999 is_ok
1000}
1001";
1002 assert_code_action!(
1003 REMOVE_UNUSED_IMPORTS,
1004 TestProject::for_source(src)
1005 .add_hex_module("result", "pub fn is_ok() {}")
1006 .add_hex_module("option", ""),
1007 find_position_of("// test").select_until(find_position_of("pub")),
1008 );
1009}
1010
1011#[test]
1012fn test_remove_unused_value() {
1013 let src = "
1014// test
1015import result.{is_ok}
1016import option
1017
1018pub fn main() {
1019 result.is_ok
1020}
1021";
1022 assert_code_action!(
1023 REMOVE_UNUSED_IMPORTS,
1024 TestProject::for_source(src)
1025 .add_hex_module("result", "pub fn is_ok() {}")
1026 .add_hex_module("option", ""),
1027 find_position_of("// test").select_until(find_position_of("pub")),
1028 );
1029}
1030
1031#[test]
1032fn test_remove_aliased_unused_value() {
1033 let src = "
1034// test
1035import result.{is_ok as ok}
1036import option
1037
1038pub fn main() {
1039 result.is_ok
1040}
1041";
1042 assert_code_action!(
1043 REMOVE_UNUSED_IMPORTS,
1044 TestProject::for_source(src)
1045 .add_hex_module("result", "pub fn is_ok() {}")
1046 .add_hex_module("option", ""),
1047 find_position_of("// test").select_until(find_position_of("pub")),
1048 );
1049}
1050
1051#[test]
1052fn test_remove_multiple_unused_values() {
1053 let src = "
1054// test
1055import result.{type Unused, used, unused, unused_again, type Used, used_again}
1056
1057pub fn main(x: Used) {
1058 #(used, used_again)
1059}
1060";
1061 assert_code_action!(
1062 REMOVE_UNUSED_IMPORTS,
1063 TestProject::for_source(src).add_hex_module(
1064 "result",
1065 "
1066pub const used = 1
1067pub const unused = 2
1068pub const unused_again = 3
1069pub const used_again = 4
1070pub type Unused
1071pub type Used
1072"
1073 ),
1074 find_position_of("// test").select_until(find_position_of("pub")),
1075 );
1076}
1077
1078#[test]
1079fn test_remove_multiple_unused_values_2() {
1080 let src = "
1081// test
1082import result.{type Unused, used, unused, type Used, unused_again}
1083
1084pub fn main(x: Used) {
1085 used
1086}
1087";
1088 assert_code_action!(
1089 REMOVE_UNUSED_IMPORTS,
1090 TestProject::for_source(src).add_hex_module(
1091 "result",
1092 "
1093pub const used = 1
1094pub const unused = 2
1095pub const unused_again = 3
1096pub type Unused
1097pub type Used
1098"
1099 ),
1100 find_position_of("// test").select_until(find_position_of("pub")),
1101 );
1102}
1103
1104#[test]
1105fn test_remove_entire_unused_import() {
1106 let src = "
1107// test
1108import result.{unused, unused_again}
1109
1110pub fn main() {
1111 todo
1112}
1113";
1114 assert_code_action!(
1115 REMOVE_UNUSED_IMPORTS,
1116 TestProject::for_source(src).add_hex_module(
1117 "result",
1118 "
1119pub const used = 1
1120pub const unused = 2
1121pub const unused_again = 3
1122pub type Unused
1123pub type Used
1124"
1125 ),
1126 find_position_of("// test").select_until(find_position_of("pub")),
1127 );
1128}
1129
1130#[test]
1131fn test_remove_redundant_tuple_in_case_subject_simple() {
1132 assert_code_action!(
1133 REMOVE_REDUNDANT_TUPLES,
1134 "pub fn main() {
1135 case #(1) { #(a) -> 0 }
1136 case #(1, 2) { #(a, b) -> 0 }
1137}",
1138 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char())
1139 );
1140}
1141
1142#[test]
1143fn test_remove_redundant_tuple_with_catch_all_pattern() {
1144 assert_code_action!(
1145 REMOVE_REDUNDANT_TUPLES,
1146 "pub fn main() {
1147 case #(1, 2) {
1148 #(1, 2) -> 0
1149 _ -> 1
1150 }
1151}",
1152 find_position_of("case").select_until(find_position_of("#(1, 2)").under_last_char())
1153 );
1154}
1155
1156#[test]
1157fn test_remove_multiple_redundant_tuple_with_catch_all_pattern() {
1158 assert_code_action!(
1159 REMOVE_REDUNDANT_TUPLES,
1160 "pub fn main() {
1161 case #(1, 2), #(3, 4) {
1162 #(2, 2), #(2, 2) -> 0
1163 #(1, 2), _ -> 0
1164 _, #(1, 2) -> 0
1165 _, _ -> 1
1166 }
1167}",
1168 find_position_of("case").select_until(find_position_of("#(3, 4)"))
1169 );
1170}
1171
1172#[test]
1173fn test_remove_redundant_tuple_in_case_subject_nested() {
1174 assert_code_action!(
1175 REMOVE_REDUNDANT_TUPLES,
1176 "pub fn main() {
1177 case #(case #(0) { #(a) -> 0 }) { #(b) -> 0 }
1178}",
1179 find_position_of("case").select_until(find_position_of("#(b)"))
1180 );
1181}
1182
1183#[test]
1184fn test_remove_redundant_tuple_in_case_retain_extras() {
1185 assert_code_action!(
1186 REMOVE_REDUNDANT_TUPLES,
1187 "
1188pub fn main() {
1189 case
1190 #(
1191 // first comment
1192 1,
1193 // second comment
1194 2,
1195 3 // third comment before comma
1196
1197 ,
1198
1199 // fourth comment after comma
1200
1201 )
1202 {
1203 #(
1204 // first comment
1205 a,
1206 // second comment
1207 b,
1208 c // third comment before comma
1209
1210 ,
1211
1212 // fourth comment after comma
1213
1214 ) -> 0
1215 }
1216}
1217",
1218 find_position_of("#").select_until(find_position_of("// first"))
1219 );
1220}
1221
1222#[test]
1223fn test_remove_redundant_tuple_in_case_subject_ignore_empty_tuple() {
1224 assert_no_code_actions!(
1225 REMOVE_REDUNDANT_TUPLES,
1226 "
1227pub fn main() {
1228 case #() { #() -> 0 }
1229}
1230",
1231 find_position_of("case").select_until(find_position_of("0"))
1232 );
1233}
1234
1235#[test]
1236fn test_remove_redundant_tuple_in_case_subject_only_safe_remove() {
1237 assert_code_action!(
1238 REMOVE_REDUNDANT_TUPLES,
1239 "
1240pub fn main() {
1241 case #(0), #(1) {
1242 #(1), #(b) -> 0
1243 a, #(0) -> 1 // The first of this clause is not a tuple
1244 #(a), #(b) -> 2
1245 }
1246}
1247",
1248 find_position_of("#(0)").select_until(find_position_of("#(1)"))
1249 );
1250}
1251
1252#[test]
1253fn rename_invalid_const() {
1254 assert_code_action!(
1255 "Rename to my_invalid_constant",
1256 "const myInvalid_Constant = 42",
1257 find_position_of("_Constant").to_selection(),
1258 );
1259}
1260
1261#[test]
1262fn rename_invalid_parameter() {
1263 assert_code_action!(
1264 "Rename to num_a",
1265 "fn add(numA: Int, num_b: Int) { numA + num_b }",
1266 find_position_of("numA").to_selection()
1267 );
1268}
1269
1270#[test]
1271fn rename_invalid_parameter_name2() {
1272 assert_code_action!(
1273 "Rename to param_name",
1274 "fn pass(label paramName: Bool) { paramName }",
1275 find_position_of("paramName").to_selection()
1276 );
1277}
1278
1279#[test]
1280fn rename_invalid_parameter_name3() {
1281 assert_code_action!(
1282 "Rename to num_a",
1283 "pub fn main() {
1284 let add = fn(numA: Int, num_b: Int) { numA + num_b }
1285}",
1286 find_position_of("let add").select_until(find_position_of("num_b"))
1287 );
1288}
1289
1290#[test]
1291fn rename_invalid_parameter_discard() {
1292 assert_code_action!(
1293 "Rename to _ignore_me",
1294 "fn ignore(_ignoreMe: Bool) { 98 }",
1295 find_position_of("ignore").select_until(find_position_of("98"))
1296 );
1297}
1298
1299#[test]
1300fn rename_invalid_parameter_discard_name2() {
1301 assert_code_action!(
1302 "Rename to _ignore_me",
1303 "fn ignore(labelled_discard _ignoreMe: Bool) { 98 }",
1304 find_position_of("ignore").select_until(find_position_of("98"))
1305 );
1306}
1307
1308#[test]
1309fn rename_invalid_parameter_discard_name3() {
1310 assert_code_action!(
1311 "Rename to _ignore_me",
1312 "pub fn main() {
1313 let ignore = fn(_ignoreMe: Bool) { 98 }
1314}",
1315 find_position_of("ignore").select_until(find_position_of("98"))
1316 );
1317}
1318
1319#[test]
1320fn rename_invalid_parameter_label() {
1321 assert_code_action!(
1322 "Rename to this_is_a_label",
1323 "fn func(thisIsALabel param: Int) { param }",
1324 find_position_of("thisIs").select_until(find_position_of("Int"))
1325 );
1326}
1327
1328#[test]
1329fn rename_invalid_parameter_label2() {
1330 assert_code_action!(
1331 "Rename to this_is_a_label",
1332 "fn ignore(thisIsALabel _ignore: Int) { 25 }",
1333 find_position_of("thisIs").under_char('i').to_selection()
1334 );
1335}
1336
1337#[test]
1338fn rename_invalid_constructor() {
1339 assert_code_action!(
1340 "Rename to TheConstructor",
1341 "type MyType { The_Constructor(Int) }",
1342 find_position_of("The_").under_char('h').to_selection(),
1343 );
1344}
1345
1346#[test]
1347fn rename_invalid_constructor_arg() {
1348 assert_code_action!(
1349 "Rename to inner_int",
1350 "type IntWrapper { IntWrapper(innerInt: Int) }",
1351 find_position_of("IntWrapper")
1352 .nth_occurrence(2)
1353 .select_until(find_position_of(": Int"))
1354 );
1355}
1356
1357#[test]
1358fn rename_invalid_custom_type() {
1359 assert_code_action!(
1360 "Rename to BoxedValue",
1361 "type Boxed_value { Box(Int) }",
1362 find_position_of("Box").select_until(find_position_of("_value"))
1363 );
1364}
1365
1366#[test]
1367fn rename_invalid_type_alias() {
1368 assert_code_action!(
1369 "Rename to FancyBool",
1370 "type Fancy_Bool = Bool",
1371 find_position_of("Fancy")
1372 .under_char('a')
1373 .select_until(find_position_of("="))
1374 );
1375}
1376
1377#[test]
1378fn rename_invalid_function() {
1379 assert_code_action!(
1380 "Rename to do_stuff",
1381 "fn doStuff() {}",
1382 find_position_of("fn").select_until(find_position_of("{}"))
1383 );
1384}
1385
1386#[test]
1387fn rename_invalid_variable() {
1388 assert_code_action!(
1389 "Rename to the_answer",
1390 "pub fn main() {
1391 let theAnswer = 42
1392}",
1393 find_position_of("theAnswer").select_until(find_position_of("Answer"))
1394 );
1395}
1396
1397#[test]
1398fn rename_invalid_variable_discard() {
1399 assert_code_action!(
1400 "Rename to _boring_number",
1401 "pub fn main() {
1402 let _boringNumber = 72
1403}",
1404 find_position_of("let").select_until(find_position_of("72"))
1405 );
1406}
1407
1408#[test]
1409fn rename_invalid_use() {
1410 assert_code_action!(
1411 "Rename to use_var",
1412 "fn use_test(f) { f(Nil) }
1413pub fn main() {use useVar <- use_test()}",
1414 find_position_of("use")
1415 .nth_occurrence(2)
1416 .select_until(find_position_of("use_test()"))
1417 );
1418}
1419
1420#[test]
1421fn rename_invalid_use_discard() {
1422 assert_code_action!(
1423 "Rename to _discard_var",
1424 "fn use_test(f) { f(Nil) }
1425pub fn main() {use _discardVar <- use_test()}",
1426 find_position_of("_discardVar")
1427 .under_last_char()
1428 .to_selection()
1429 );
1430}
1431
1432#[test]
1433fn rename_invalid_pattern_assignment() {
1434 assert_code_action!(
1435 "Rename to the_answer",
1436 "pub fn main() {
1437 let assert 42 as theAnswer = 42
1438}",
1439 find_position_of("let").select_until(find_position_of("= 42"))
1440 );
1441}
1442
1443#[test]
1444fn rename_invalid_list_pattern() {
1445 assert_code_action!(
1446 "Rename to the_element",
1447 "pub fn main() {
1448 let assert [theElement] = [9.4]
1449}",
1450 find_position_of("assert").select_until(find_position_of("9.4"))
1451 );
1452}
1453
1454#[test]
1455fn rename_invalid_list_pattern_discard() {
1456 assert_code_action!(
1457 "Rename to _elem_one",
1458 "pub fn main() {
1459 let assert [_elemOne] = [False]
1460}",
1461 find_position_of("[_elemOne]")
1462 .under_char('O')
1463 .to_selection()
1464 );
1465}
1466
1467#[test]
1468fn rename_invalid_constructor_pattern() {
1469 assert_code_action!(
1470 "Rename to inner_value",
1471 "pub type Box { Box(Int) }
1472pub fn main() {
1473 let Box(innerValue) = Box(203)
1474}",
1475 find_position_of("innerValue").to_selection()
1476 );
1477}
1478
1479#[test]
1480fn rename_invalid_constructor_pattern_discard() {
1481 assert_code_action!(
1482 "Rename to _ignored_inner",
1483 "pub type Box { Box(Int) }
1484pub fn main() {
1485 let Box(_ignoredInner) = Box(203)
1486}",
1487 find_position_of("_").select_until(find_position_of("203"))
1488 );
1489}
1490
1491#[test]
1492fn rename_invalid_tuple_pattern() {
1493 assert_code_action!(
1494 "Rename to second_value",
1495 "pub fn main() {
1496 let #(a, secondValue) = #(1, 2)
1497}",
1498 find_position_of("secondValue")
1499 .select_until(find_position_of("secondValue").under_char('n'))
1500 );
1501}
1502
1503#[test]
1504fn rename_invalid_tuple_pattern_discard() {
1505 assert_code_action!(
1506 "Rename to _second_value",
1507 "pub fn main() {
1508 let #(a, _secondValue) = #(1, 2)
1509}",
1510 find_position_of("_secondValue")
1511 .under_char('_')
1512 .select_until(find_position_of("#(1, 2)"))
1513 );
1514}
1515
1516#[test]
1517fn rename_invalid_bit_array_pattern() {
1518 assert_code_action!(
1519 "Rename to bit_value",
1520 "pub fn main() {
1521 let assert <<bitValue>> = <<73>>
1522}",
1523 find_position_of("<<").select_until(find_position_of(">>"))
1524 );
1525}
1526
1527#[test]
1528fn rename_invalid_bit_array_pattern_discard() {
1529 assert_code_action!(
1530 "Rename to _i_dont_care",
1531 "pub fn main() {
1532 let assert <<_iDontCare>> = <<97>>
1533}",
1534 find_position_of("<<").select_until(find_position_of("Care"))
1535 );
1536}
1537
1538#[test]
1539fn rename_invalid_string_prefix_pattern() {
1540 assert_code_action!(
1541 "Rename to cool_suffix",
1542 r#"pub fn main() {
1543 let assert "prefix" <> coolSuffix = "prefix-suffix"
1544}"#,
1545 find_position_of("<>").select_until(find_position_of("-suffix"))
1546 );
1547}
1548
1549#[test]
1550fn rename_invalid_string_prefix_pattern_discard() {
1551 assert_code_action!(
1552 "Rename to _boring_suffix",
1553 r#"pub fn main() {
1554 let assert "prefix" <> _boringSuffix = "prefix-suffix"
1555}"#,
1556 find_position_of("<>").select_until(find_position_of("Suffix"))
1557 );
1558}
1559
1560#[test]
1561fn rename_invalid_string_prefix_pattern_alias() {
1562 assert_code_action!(
1563 "Rename to the_prefix",
1564 r#"pub fn main() {
1565 let assert "prefix" as thePrefix <> _suffix = "prefix-suffix"
1566}"#,
1567 find_position_of("prefix").select_until(find_position_of("-suffix"))
1568 );
1569}
1570
1571#[test]
1572fn rename_invalid_case_variable() {
1573 assert_code_action!(
1574 "Rename to twenty_one",
1575 "pub fn main() {
1576 case 21 { twentyOne -> {Nil} }
1577}",
1578 find_position_of("case").select_until(find_position_of("Nil"))
1579 );
1580}
1581
1582#[test]
1583fn rename_invalid_case_variable_discard() {
1584 assert_code_action!(
1585 "Rename to _twenty_one",
1586 "pub fn main() {
1587 case 21 { _twentyOne -> {Nil} }
1588}",
1589 find_position_of("21").select_until(find_position_of("->"))
1590 );
1591}
1592
1593#[test]
1594fn rename_invalid_type_parameter_name() {
1595 assert_code_action!(
1596 "Rename to inner_type",
1597 "type Wrapper(innerType) {}",
1598 find_position_of("innerType").select_until(find_position_of(")"))
1599 );
1600}
1601
1602#[test]
1603fn rename_invalid_type_alias_parameter_name() {
1604 assert_code_action!(
1605 "Rename to phantom_type",
1606 "type Phantom(phantomType) = Int",
1607 find_position_of("phantomType").select_until(find_position_of(")"))
1608 );
1609}
1610
1611#[test]
1612fn rename_invalid_function_type_parameter_name() {
1613 assert_code_action!(
1614 "Rename to some_type",
1615 "fn identity(value: someType) { value }",
1616 find_position_of("someType").select_until(find_position_of(")"))
1617 );
1618}
1619
1620#[test]
1621fn test_convert_assert_result_to_case() {
1622 assert_code_action!(
1623 CONVERT_TO_CASE,
1624 "pub fn main() {
1625 let assert Ok(value) = Ok(1)
1626}",
1627 find_position_of("assert").select_until(find_position_of("assert").under_char('r')),
1628 );
1629}
1630
1631#[test]
1632fn test_convert_let_assert_to_case_indented() {
1633 assert_code_action!(
1634 CONVERT_TO_CASE,
1635 "pub fn main() {
1636 {
1637 let assert Ok(value) = Ok(1)
1638 }
1639}",
1640 find_position_of("Ok").to_selection()
1641 );
1642}
1643
1644#[test]
1645fn test_convert_let_assert_to_case_multi_variables() {
1646 assert_code_action!(
1647 CONVERT_TO_CASE,
1648 "pub fn main() {
1649 let assert [var1, var2, _var3, var4] = [1, 2, 3, 4]
1650}",
1651 find_position_of("var1").select_until(find_position_of("_var").under_last_char())
1652 );
1653}
1654
1655#[test]
1656fn test_convert_let_assert_to_case_discard() {
1657 assert_code_action!(
1658 CONVERT_TO_CASE,
1659 "pub fn main() {
1660 let assert [_elem] = [6]
1661}",
1662 find_position_of("assert").select_until(find_position_of("[6]").under_last_char()),
1663 );
1664}
1665
1666#[test]
1667fn test_convert_let_assert_to_case_no_variables() {
1668 assert_code_action!(
1669 CONVERT_TO_CASE,
1670 "pub fn main() {
1671 let assert [] = []
1672}",
1673 find_position_of("[]").to_selection(),
1674 );
1675}
1676
1677#[test]
1678fn test_convert_let_assert_alias_to_case() {
1679 assert_code_action!(
1680 CONVERT_TO_CASE,
1681 "pub fn main() {
1682 let assert 10 as ten = 10
1683}",
1684 find_position_of("as").select_until(find_position_of("ten")),
1685 );
1686}
1687
1688#[test]
1689fn test_convert_let_assert_tuple_to_case() {
1690 assert_code_action!(
1691 CONVERT_TO_CASE,
1692 "pub fn main() {
1693 let assert #(first, 10, third) = #(5, 10, 15)
1694}
1695",
1696 find_position_of("let").to_selection(),
1697 );
1698}
1699
1700#[test]
1701fn test_convert_let_assert_bit_array_to_case() {
1702 assert_code_action!(
1703 CONVERT_TO_CASE,
1704 "pub fn main() {
1705 let assert <<bits1, bits2>> = <<73, 98>>
1706}",
1707 find_position_of("bits").select_until(find_position_of("2")),
1708 );
1709}
1710
1711#[test]
1712fn test_convert_let_assert_string_prefix_to_case() {
1713 assert_code_action!(
1714 CONVERT_TO_CASE,
1715 r#"pub fn main() {
1716 let assert "_" <> thing = "_Hello"
1717}"#,
1718 find_position_of("_").to_selection()
1719 );
1720}
1721
1722#[test]
1723fn test_convert_let_assert_string_prefix_pattern_alias_to_case() {
1724 assert_code_action!(
1725 CONVERT_TO_CASE,
1726 r#"pub fn main() {
1727 let assert "123" as one_two_three <> rest = "123456"
1728}"#,
1729 find_position_of("123").select_until(find_position_of("123456")),
1730 );
1731}
1732
1733#[test]
1734fn test_convert_inner_let_assert_to_case() {
1735 assert_code_action!(
1736 CONVERT_TO_CASE,
1737 r#"pub fn main() {
1738 let assert [wibble] = {
1739 let assert Ok(wobble) = {
1740 Ok(1)
1741 }
1742 [wobble]
1743 }
1744}"#,
1745 find_position_of("wobble").under_char('l').to_selection()
1746 );
1747}
1748
1749#[test]
1750fn test_convert_outer_let_assert_to_case() {
1751 assert_code_action!(
1752 CONVERT_TO_CASE,
1753 r#"pub fn main() {
1754 let assert [wibble] = {
1755 let assert Ok(wobble) = {
1756 Ok(1)
1757 }
1758 [wobble]
1759 }
1760}"#,
1761 find_position_of("wibble")
1762 .under_char('i')
1763 .select_until(find_position_of("= {")),
1764 );
1765}
1766
1767#[test]
1768fn test_convert_let_assert_with_message_to_case() {
1769 assert_code_action!(
1770 CONVERT_TO_CASE,
1771 r#"
1772pub fn expect(value, message) {
1773 let assert Ok(inner) = value as message
1774 inner
1775}
1776"#,
1777 find_position_of("assert").select_until(find_position_of("=")),
1778 );
1779}
1780
1781#[test]
1782fn test_convert_assert_custom_type_with_label_shorthands_to_case() {
1783 assert_code_action!(
1784 CONVERT_TO_CASE,
1785 "
1786pub type Wibble { Wibble(arg: Int, arg2: Float) }
1787pub fn main() {
1788 let assert Wibble(arg2:, ..) = Wibble(arg: 1, arg2: 1.0)
1789}
1790",
1791 find_position_of("arg2:,").select_until(find_position_of("1.0")),
1792 );
1793}
1794
1795#[test]
1796fn label_shorthand_action_works_on_labelled_call_args() {
1797 assert_code_action!(
1798 USE_LABEL_SHORTHAND_SYNTAX,
1799 r#"
1800pub fn main() {
1801 let arg1 = 1
1802 let arg2 = 2
1803 wibble(arg2: arg2, arg1: arg1)
1804}
1805
1806pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
1807"#,
1808 find_position_of("wibble")
1809 .under_char('i')
1810 .select_until(find_position_of("arg1: arg1")),
1811 );
1812}
1813
1814#[test]
1815fn label_shorthand_action_works_on_labelled_constructor_call_args() {
1816 assert_code_action!(
1817 USE_LABEL_SHORTHAND_SYNTAX,
1818 r#"
1819pub fn main() {
1820 let arg1 = 1
1821 let arg2 = 2
1822 Wibble(arg2: arg2, arg1: arg1)
1823}
1824
1825pub type Wibble { Wibble(arg1: Int, arg2: Int) }
1826"#,
1827 find_position_of("Wibble").select_until(find_position_of("arg1: arg1").under_char(':')),
1828 );
1829}
1830
1831#[test]
1832fn label_shorthand_action_only_applies_to_selected_args() {
1833 assert_code_action!(
1834 USE_LABEL_SHORTHAND_SYNTAX,
1835 r#"
1836pub fn main() {
1837 let arg1 = 1
1838 let arg2 = 2
1839 Wibble(arg2: arg2, arg1: arg1)
1840}
1841
1842pub type Wibble { Wibble(arg1: Int, arg2: Int) }
1843"#,
1844 find_position_of("Wibble").select_until(find_position_of("arg2: arg2").under_char(':')),
1845 );
1846}
1847
1848#[test]
1849fn label_shorthand_action_works_on_labelled_update_call_args() {
1850 assert_code_action!(
1851 USE_LABEL_SHORTHAND_SYNTAX,
1852 r#"
1853pub fn main() {
1854 let arg1 = 1
1855 Wibble(..todo, arg1: arg1)
1856}
1857
1858pub type Wibble { Wibble(arg1: Int, arg2: Int) }
1859"#,
1860 find_position_of("..todo").select_until(find_position_of("arg1: arg1").under_last_char()),
1861 );
1862}
1863
1864#[test]
1865fn label_shorthand_action_works_on_labelled_pattern_call_args() {
1866 assert_code_action!(
1867 USE_LABEL_SHORTHAND_SYNTAX,
1868 r#"
1869pub fn main() {
1870 let Wibble(arg1: arg1, arg2: arg2) = todo
1871 arg1 + arg2
1872}
1873
1874pub type Wibble { Wibble(arg1: Int, arg2: Int) }
1875"#,
1876 find_position_of("let").select_until(find_position_of("todo").under_last_char()),
1877 );
1878}
1879
1880#[test]
1881fn label_shorthand_action_doesnt_come_up_for_arguments_with_different_label() {
1882 assert_no_code_actions!(
1883 USE_LABEL_SHORTHAND_SYNTAX,
1884 r#"
1885pub fn main() {
1886 let Wibble(arg1: arg_1, arg2: arg_2) = todo
1887 arg_1 + arg_2
1888}
1889
1890pub type Wibble { Wibble(arg1: Int, arg2: Int) }
1891"#,
1892 find_position_of("arg_1").select_until(find_position_of("arg_2").under_last_char())
1893 );
1894}
1895
1896#[test]
1897fn fill_in_labelled_args_with_some_arguments_already_supplied() {
1898 assert_code_action!(
1899 FILL_LABELS,
1900 r#"
1901pub fn main() {
1902 wibble(1,)
1903}
1904
1905pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
1906 "#,
1907 find_position_of("wibble(").under_char('b').to_selection(),
1908 );
1909}
1910
1911#[test]
1912fn fill_in_labelled_args_with_some_arguments_already_supplied_2() {
1913 assert_code_action!(
1914 FILL_LABELS,
1915 r#"
1916pub fn main() {
1917 wibble(arg2: 1)
1918}
1919
1920pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
1921 "#,
1922 find_position_of("wibble(").to_selection(),
1923 );
1924}
1925
1926#[test]
1927fn fill_in_labelled_args_with_some_arguments_already_supplied_3() {
1928 assert_code_action!(
1929 FILL_LABELS,
1930 r#"
1931pub fn main() {
1932 wibble(1, arg3: 2)
1933}
1934
1935pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }
1936 "#,
1937 find_position_of("wibble(").to_selection(),
1938 );
1939}
1940
1941#[test]
1942fn fill_in_labelled_args_works_with_regular_function() {
1943 assert_code_action!(
1944 FILL_LABELS,
1945 r#"
1946pub fn main() {
1947 wibble()
1948}
1949
1950pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
1951 "#,
1952 find_position_of("wibble(").to_selection(),
1953 );
1954}
1955
1956#[test]
1957fn fill_in_labelled_args_works_with_record_constructor() {
1958 assert_code_action!(
1959 FILL_LABELS,
1960 r#"
1961pub fn main() {
1962 Wibble()
1963}
1964
1965pub type Wibble { Wibble(arg1: Int, arg2: String) }
1966 "#,
1967 find_position_of("Wibble").select_until(find_position_of("Wibble()").under_last_char()),
1968 );
1969}
1970
1971#[test]
1972fn fill_in_labelled_args_works_with_pipes() {
1973 assert_code_action!(
1974 FILL_LABELS,
1975 r#"
1976pub fn main() {
1977 1 |> wibble()
1978}
1979
1980pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
1981 "#,
1982 find_position_of("wibble()")
1983 .under_last_char()
1984 .to_selection(),
1985 );
1986}
1987
1988#[test]
1989fn fill_in_labelled_args_works_with_pipes_2() {
1990 assert_code_action!(
1991 FILL_LABELS,
1992 r#"
1993pub fn main() {
1994 1 |> wibble()
1995}
1996
1997pub fn wibble(not_labelled, arg1 arg1, arg2 arg2) { Nil }
1998 "#,
1999 find_position_of("wibble()")
2000 .under_last_char()
2001 .to_selection(),
2002 );
2003}
2004
2005#[test]
2006fn fill_in_labelled_args_works_with_use() {
2007 assert_code_action!(
2008 FILL_LABELS,
2009 r#"
2010pub fn main() {
2011 use <- wibble()
2012 todo
2013}
2014
2015pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
2016 "#,
2017 find_position_of("wibble(").select_until(find_position_of("wibble()").under_last_char()),
2018 );
2019}
2020
2021#[test]
2022fn fill_in_labelled_args_works_with_use_2() {
2023 assert_code_action!(
2024 FILL_LABELS,
2025 r#"
2026pub fn main() {
2027 use <- wibble(arg1: 1)
2028 todo
2029}
2030
2031pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }
2032 "#,
2033 find_position_of("wibble(").select_until(find_position_of("1").under_last_char()),
2034 );
2035}
2036
2037#[test]
2038fn fill_in_labelled_args_works_with_use_3() {
2039 assert_code_action!(
2040 FILL_LABELS,
2041 r#"
2042pub fn main() {
2043 use <- wibble(arg2: 2)
2044 todo
2045}
2046
2047pub fn wibble(arg1 arg1, arg2 arg2, arg3 arg3) { Nil }
2048 "#,
2049 find_position_of("wibble(").select_until(find_position_of("2").under_last_char()),
2050 );
2051}
2052
2053#[test]
2054fn fill_in_labelled_args_selects_innermost_function() {
2055 assert_code_action!(
2056 FILL_LABELS,
2057 r#"
2058pub fn main() {
2059 wibble(
2060 wibble()
2061 )
2062}
2063
2064pub fn wibble(arg1 arg1, arg2 arg2) { Nil }
2065 "#,
2066 find_position_of("wibble()")
2067 .under_last_char()
2068 .to_selection(),
2069 );
2070}
2071
2072#[test]
2073fn use_label_shorthand_works_for_nested_calls() {
2074 assert_code_action!(
2075 USE_LABEL_SHORTHAND_SYNTAX,
2076 r#"
2077pub fn wibble(arg arg: Int) -> Int { arg }
2078
2079pub fn main() {
2080 let arg = 1
2081 wibble(wibble(arg: arg))
2082}
2083 "#,
2084 find_position_of("main").select_until(find_position_of("}").nth_occurrence(2)),
2085 );
2086}
2087
2088#[test]
2089fn use_label_shorthand_works_for_nested_record_updates() {
2090 assert_code_action!(
2091 USE_LABEL_SHORTHAND_SYNTAX,
2092 r#"
2093pub type Wibble { Wibble(arg: Int, arg2: Wobble) }
2094pub type Wobble { Wobble(arg: Int, arg2: String) }
2095
2096pub fn main() {
2097 let arg = 1
2098 let arg2 = "a"
2099 Wibble(..todo, arg2: Wobble(arg: arg, arg2: arg2))
2100}
2101 "#,
2102 find_position_of("todo").select_until(find_position_of("arg2: arg2")),
2103 );
2104}
2105
2106#[test]
2107fn use_label_shorthand_works_for_nested_patterns() {
2108 assert_code_action!(
2109 USE_LABEL_SHORTHAND_SYNTAX,
2110 r#"
2111pub type Wibble { Wibble(arg: Int, arg2: Wobble) }
2112pub type Wobble { Wobble(arg: Int, arg2: String) }
2113
2114pub fn main() {
2115 let Wibble(arg2: Wobble(arg: arg, arg2: arg2), ..) = todo
2116}
2117 "#,
2118 find_position_of("main").select_until(find_position_of("todo")),
2119 );
2120}
2121
2122#[test]
2123fn use_label_shorthand_works_for_alternative_patterns() {
2124 assert_code_action!(
2125 USE_LABEL_SHORTHAND_SYNTAX,
2126 r#"
2127pub type Wibble { Wibble(arg: Int, arg2: String) }
2128
2129pub fn main() {
2130 case Wibble(1, "wibble") {
2131 Wibble(arg2: arg2, ..) | Wibble(arg: 1, arg2: arg2) -> todo
2132 }
2133}
2134 "#,
2135 find_position_of("main").select_until(find_position_of("todo")),
2136 );
2137}
2138
2139#[test]
2140fn test_assign_unused_result() {
2141 assert_code_action!(
2142 ASSIGN_UNUSED_RESULT,
2143 r#"
2144pub fn main() {
2145 let x = 1
2146 Ok(x)
2147 Nil
2148}
2149"#,
2150 find_position_of("Ok").select_until(find_position_of("(x)")),
2151 );
2152}
2153
2154#[test]
2155fn test_assign_unused_result_in_block() {
2156 assert_code_action!(
2157 ASSIGN_UNUSED_RESULT,
2158 r#"
2159pub fn main() {
2160 {
2161 let x = 1
2162 Ok(x)
2163 Nil
2164 }
2165 Nil
2166}
2167"#,
2168 find_position_of("Ok").select_until(find_position_of("(x)")),
2169 );
2170}
2171
2172#[test]
2173fn test_assign_unused_result_on_block_start() {
2174 assert_code_action!(
2175 ASSIGN_UNUSED_RESULT,
2176 r#"
2177pub fn main() {
2178 {
2179 let x = 1
2180 Ok(x)
2181 Ok(x)
2182 }
2183 Nil
2184}
2185"#,
2186 find_position_of("{").nth_occurrence(2).to_selection()
2187 );
2188}
2189
2190#[test]
2191fn test_assign_unused_result_on_block_end() {
2192 assert_code_action!(
2193 ASSIGN_UNUSED_RESULT,
2194 r#"
2195pub fn main() {
2196 {
2197 let x = 1
2198 Ok(x)
2199 Ok(x)
2200 }
2201 Nil
2202}
2203"#,
2204 find_position_of("}").to_selection()
2205 );
2206}
2207
2208#[test]
2209#[should_panic(expected = "No action with the given title")]
2210fn test_assign_unused_result_inside_block() {
2211 assert_code_action!(
2212 ASSIGN_UNUSED_RESULT,
2213 r#"
2214pub fn main() {
2215 {
2216 let x = 1
2217 Nil
2218 Ok(x)
2219 }
2220}
2221"#,
2222 find_position_of("Ok").select_until(find_position_of("(x)"))
2223 );
2224}
2225
2226#[test]
2227fn test_assign_unused_result_only_first_action() {
2228 assert_code_action!(
2229 ASSIGN_UNUSED_RESULT,
2230 r#"
2231pub fn main() {
2232 let x = 1
2233 Ok(x)
2234 Ok(x)
2235 Nil
2236}
2237"#,
2238 find_position_of("Ok").select_until(find_position_of("(x)"))
2239 );
2240}
2241
2242#[test]
2243#[should_panic(expected = "No action with the given title")]
2244fn test_assign_unused_result_not_on_return_value() {
2245 assert_code_action!(
2246 ASSIGN_UNUSED_RESULT,
2247 r#"
2248pub fn main() {
2249 let x = 1
2250 Ok(x)
2251}
2252"#,
2253 find_position_of("Ok").select_until(find_position_of("(x)"))
2254 );
2255}
2256
2257#[test]
2258#[should_panic(expected = "No action with the given title")]
2259fn test_assign_unused_result_not_on_return_value_in_block() {
2260 assert_code_action!(
2261 ASSIGN_UNUSED_RESULT,
2262 r#"
2263pub fn main() {
2264 let _ = {
2265 let x = 1
2266 Ok(x)
2267 }
2268 Nil
2269}"#,
2270 find_position_of("Ok").select_until(find_position_of("(x)"))
2271 );
2272}
2273
2274#[test]
2275fn test_import_module_from_function() {
2276 let src = "
2277pub fn main() {
2278 result.is_ok()
2279}
2280";
2281
2282 assert_code_action!(
2283 "Import `result`",
2284 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"),
2285 find_position_of("result").select_until(find_position_of("."))
2286 );
2287}
2288
2289#[test]
2290fn test_import_path_module_from_function() {
2291 let src = r#"
2292pub fn main() {
2293 io.println("Hello, world!")
2294}
2295"#;
2296
2297 assert_code_action!(
2298 "Import `gleam/io`",
2299 TestProject::for_source(src)
2300 .add_hex_module("gleam/io", "pub fn println(message: String) {}"),
2301 find_position_of("io").select_until(find_position_of("."))
2302 );
2303}
2304
2305#[test]
2306fn test_import_module_from_type() {
2307 let src = "type Wobble = wibble.Wubble";
2308
2309 assert_code_action!(
2310 "Import `mod/wibble`",
2311 TestProject::for_source(src).add_hex_module("mod/wibble", "pub type Wubble { Wubble }"),
2312 find_position_of("wibble").select_until(find_position_of("."))
2313 );
2314}
2315
2316#[test]
2317fn test_import_module_from_constructor() {
2318 let src = "
2319pub fn main() {
2320 let value = values.Value(10)
2321}
2322";
2323
2324 assert_code_action!(
2325 "Import `values`",
2326 TestProject::for_source(src).add_hex_module("values", "pub type Value { Value(Int) }"),
2327 find_position_of("values").select_until(find_position_of("."))
2328 );
2329}
2330
2331#[test]
2332fn test_rename_module_for_imported() {
2333 let src = r#"
2334import gleam/io
2335
2336pub fn main() {
2337 i.println("Hello, world!")
2338}
2339"#;
2340
2341 assert_code_action!(
2342 "Did you mean `io`",
2343 TestProject::for_source(src)
2344 .add_hex_module("gleam/io", "pub fn println(message: String) {}"),
2345 find_position_of("i.").select_until(find_position_of("println"))
2346 );
2347}
2348
2349#[test]
2350fn test_import_similar_module() {
2351 let src = "
2352pub fn main() {
2353 reult.is_ok()
2354}
2355";
2356
2357 assert_code_action!(
2358 "Import `result`",
2359 TestProject::for_source(src).add_hex_module("result", "pub fn is_ok() {}"),
2360 find_position_of("reult").select_until(find_position_of("."))
2361 );
2362}
2363
2364#[test]
2365fn test_no_action_to_import_module_without_value() {
2366 // The language server should not suggest a code action
2367 // to import a module if it doesn't have a value with
2368 // the same name as we are trying to access
2369 let src = "
2370pub fn main() {
2371 io.hello_world()
2372}
2373";
2374
2375 let title = "Import `io`";
2376
2377 assert_no_code_actions!(
2378 title,
2379 TestProject::for_source(src).add_hex_module("io", "pub fn println() {}"),
2380 find_position_of("io").select_until(find_position_of("."))
2381 );
2382}
2383
2384#[test]
2385fn test_no_action_to_import_module_without_type() {
2386 let src = "type Name = int.String";
2387
2388 let title = "Import `int`";
2389
2390 assert_no_code_actions!(
2391 title,
2392 TestProject::for_source(src).add_hex_module("int", ""),
2393 find_position_of("int").select_until(find_position_of("."))
2394 );
2395}
2396
2397#[test]
2398fn test_no_action_to_import_module_with_private_value() {
2399 // The language server should not suggest a code action
2400 // to import a module if the value we are trying to
2401 // access is private.
2402 let src = "
2403pub fn main() {
2404 mod.internal()
2405}
2406";
2407
2408 let title = "Import `mod`";
2409
2410 assert_no_code_actions!(
2411 title,
2412 TestProject::for_source(src).add_hex_module("mod", "fn internal() {}"),
2413 find_position_of("mod").select_until(find_position_of("."))
2414 );
2415}
2416
2417#[test]
2418fn test_no_action_to_import_module_with_private_type() {
2419 let src = "type T = module.T";
2420
2421 let title = "Import `module`";
2422
2423 assert_no_code_actions!(
2424 title,
2425 TestProject::for_source(src).add_hex_module("module", "type T { T }"),
2426 find_position_of("module").select_until(find_position_of("."))
2427 );
2428}
2429
2430#[test]
2431fn test_no_action_to_import_module_with_constructor_named_same_as_type() {
2432 let src = "type NotAType = shapes.Rectangle";
2433
2434 let title = "Import `shapes`";
2435
2436 assert_no_code_actions!(
2437 title,
2438 TestProject::for_source(src)
2439 .add_hex_module("shapes", "pub type Shape { Rectangle, Circle }"),
2440 find_position_of("shapes").select_until(find_position_of("."))
2441 );
2442}
2443
2444#[test]
2445fn add_missing_patterns_bool() {
2446 assert_code_action!(
2447 ADD_MISSING_PATTERNS,
2448 "
2449pub fn main(bool: Bool) {
2450 case bool {}
2451}
2452",
2453 find_position_of("case").select_until(find_position_of("bool {"))
2454 );
2455}
2456
2457#[test]
2458fn add_missing_patterns_custom_type() {
2459 assert_code_action!(
2460 ADD_MISSING_PATTERNS,
2461 "
2462type Wibble {
2463 Wibble
2464 Wobble
2465 Wubble
2466}
2467
2468pub fn main(wibble: Wibble) {
2469 case wibble {
2470 Wobble -> Nil
2471 }
2472}
2473",
2474 find_position_of("case").select_until(find_position_of("wibble {"))
2475 );
2476}
2477
2478#[test]
2479fn add_missing_patterns_tuple() {
2480 assert_code_action!(
2481 ADD_MISSING_PATTERNS,
2482 "
2483pub fn main(two_at_once: #(Bool, Result(Int, Nil))) {
2484 case two_at_once {
2485 #(False, Error(_)) -> Nil
2486 }
2487}
2488",
2489 find_position_of("case").select_until(find_position_of("two_at_once {"))
2490 );
2491}
2492
2493#[test]
2494fn add_missing_patterns_list() {
2495 assert_code_action!(
2496 ADD_MISSING_PATTERNS,
2497 "
2498pub fn main() {
2499 let list = [1, 2, 3]
2500 case list {
2501 [a, b, c, 4 as d] -> d
2502 }
2503}
2504",
2505 find_position_of("case").select_until(find_position_of("list {"))
2506 );
2507}
2508
2509#[test]
2510fn add_missing_patterns_infinite() {
2511 assert_code_action!(
2512 ADD_MISSING_PATTERNS,
2513 r#"
2514pub fn main() {
2515 let value = 3
2516 case value {
2517 1 -> "one"
2518 2 -> "two"
2519 3 -> "three"
2520 }
2521}
2522"#,
2523 find_position_of("case").select_until(find_position_of("value {"))
2524 );
2525}
2526
2527#[test]
2528fn add_missing_patterns_multi() {
2529 assert_code_action!(
2530 ADD_MISSING_PATTERNS,
2531 r#"
2532pub fn main(a: Bool) {
2533 let b = 1
2534 case a, b {
2535
2536 }
2537}
2538"#,
2539 find_position_of("case").select_until(find_position_of("b {"))
2540 );
2541}
2542
2543#[test]
2544fn add_missing_patterns_inline() {
2545 // Ensure we correctly detect the indentation, if the case expression
2546 // does not start at the beginning of the line
2547 assert_code_action!(
2548 ADD_MISSING_PATTERNS,
2549 r#"
2550pub fn main(a: Bool) {
2551 let value = case a {}
2552}
2553"#,
2554 find_position_of("case").select_until(find_position_of("a {"))
2555 );
2556}
2557
2558#[test]
2559fn import_module_from_pattern() {
2560 let src = "
2561pub fn main(res) {
2562 case res {
2563 result.Ok(_) -> Nil
2564 result.Error(_) -> Nil
2565 }
2566}
2567";
2568
2569 assert_code_action!(
2570 "Import `result`",
2571 TestProject::for_source(src)
2572 .add_hex_module("result", "pub type Result(v, e) { Ok(v) Error(e) }"),
2573 find_position_of("result").select_until(find_position_of("."))
2574 );
2575}
2576
2577#[test]
2578fn annotate_function() {
2579 assert_code_action!(
2580 ADD_ANNOTATIONS,
2581 r#"
2582pub fn add_one(thing) {
2583 thing + 1
2584}
2585"#,
2586 find_position_of("fn").select_until(find_position_of("("))
2587 );
2588}
2589
2590#[test]
2591fn annotate_function_with_annotated_return_type() {
2592 assert_code_action!(
2593 ADD_ANNOTATION,
2594 r#"
2595pub fn add_one(thing) -> Int {
2596 thing + 1
2597}
2598"#,
2599 find_position_of("fn").select_until(find_position_of("("))
2600 );
2601}
2602
2603#[test]
2604fn annotate_function_with_partially_annotated_parameters() {
2605 assert_code_action!(
2606 ADD_ANNOTATION,
2607 r#"
2608pub fn add(a: Float, b) -> Float {
2609 a +. b
2610}
2611"#,
2612 find_position_of("fn").select_until(find_position_of("("))
2613 );
2614}
2615
2616#[test]
2617fn no_code_action_for_fully_annotated_function() {
2618 assert_no_code_actions!(
2619 ADD_ANNOTATION | ADD_ANNOTATIONS,
2620 r#"
2621pub fn do_a_thing(a: Int, b: Float) -> String {
2622 todo
2623}
2624"#,
2625 find_position_of("fn").select_until(find_position_of("("))
2626 );
2627}
2628
2629#[test]
2630fn annotate_anonymous_function() {
2631 assert_code_action!(
2632 ADD_ANNOTATIONS,
2633 r#"
2634pub fn add_curry(a) {
2635 fn(b) { a + b }
2636}
2637"#,
2638 find_position_of("fn(").select_until(find_position_of("b)"))
2639 );
2640}
2641
2642#[test]
2643fn annotate_anonymous_function_with_annotated_return_type() {
2644 assert_code_action!(
2645 ADD_ANNOTATION,
2646 r#"
2647pub fn add_curry(a) {
2648 fn(b) -> Int { a + b }
2649}
2650"#,
2651 find_position_of("fn(").select_until(find_position_of("b)"))
2652 );
2653}
2654
2655#[test]
2656fn annotate_anonymous_function_with_partially_annotated_parameters() {
2657 assert_code_action!(
2658 ADD_ANNOTATIONS,
2659 r#"
2660pub fn main() {
2661 fn(a, b: Int, c) { a + b + c }
2662}
2663"#,
2664 find_position_of("fn(").select_until(find_position_of("c)"))
2665 );
2666}
2667
2668#[test]
2669fn no_code_action_for_fully_annotated_anonymous_function() {
2670 assert_no_code_actions!(
2671 ADD_ANNOTATION | ADD_ANNOTATIONS,
2672 r#"
2673pub fn main() {
2674 fn(a: Int, b: Int) -> Int { a - b }
2675}
2676"#,
2677 find_position_of("fn(").select_until(find_position_of("Int)"))
2678 );
2679}
2680
2681#[test]
2682fn annotate_use() {
2683 assert_code_action!(
2684 ADD_ANNOTATIONS,
2685 r#"
2686pub fn wibble(wobble: fn(Int, Int) -> Int) {
2687 wobble(1, 2)
2688}
2689
2690pub fn main() {
2691 use a, b <- wibble
2692 a + b
2693}
2694"#,
2695 find_position_of("use").select_until(find_position_of("<-"))
2696 );
2697}
2698
2699#[test]
2700fn annotate_use_with_partially_annotated_parameters() {
2701 assert_code_action!(
2702 ADD_ANNOTATION,
2703 r#"
2704pub fn wibble(wobble: fn(Int, Int) -> Int) {
2705 wobble(1, 2)
2706}
2707
2708pub fn main() {
2709 use a: Int, b <- wibble
2710 a + b
2711}
2712"#,
2713 find_position_of("use").select_until(find_position_of("<-"))
2714 );
2715}
2716
2717#[test]
2718fn no_code_action_for_fully_annotated_use() {
2719 assert_no_code_actions!(
2720 ADD_ANNOTATION | ADD_ANNOTATIONS,
2721 r#"
2722pub fn wibble(wobble: fn(Int, Int) -> Int) {
2723 wobble(1, 2)
2724}
2725
2726pub fn main() {
2727 use a: Int, b: Int <- wibble
2728 a + b
2729}
2730"#,
2731 find_position_of("use").select_until(find_position_of("<-"))
2732 );
2733}
2734
2735#[test]
2736fn annotate_constant() {
2737 assert_code_action!(
2738 ADD_ANNOTATION,
2739 r#"
2740pub const my_constant = 20
2741"#,
2742 find_position_of("const").select_until(find_position_of("="))
2743 );
2744}
2745
2746#[test]
2747fn no_code_action_for_annotated_constant() {
2748 assert_no_code_actions!(
2749 ADD_ANNOTATION | ADD_ANNOTATIONS,
2750 r#"
2751pub const PI: Float = 3.14159
2752"#,
2753 find_position_of("const").select_until(find_position_of("="))
2754 );
2755}
2756
2757#[test]
2758fn annotate_local_variable() {
2759 assert_code_action!(
2760 ADD_ANNOTATION,
2761 r#"
2762pub fn main() {
2763 let my_value = 10
2764}
2765"#,
2766 find_position_of("let").select_until(find_position_of("="))
2767 );
2768}
2769
2770#[test]
2771fn annotate_local_variable_with_pattern() {
2772 assert_code_action!(
2773 ADD_ANNOTATION,
2774 r#"
2775type Wibble {
2776 Wibble(a: Int, b: Int, c: Int)
2777}
2778
2779pub fn main() {
2780 let Wibble(a, b, c) = Wibble(1, 2, 3)
2781}
2782"#,
2783 find_position_of("let").select_until(find_position_of("="))
2784 );
2785}
2786
2787#[test]
2788fn annotate_local_variable_with_pattern2() {
2789 assert_code_action!(
2790 ADD_ANNOTATION,
2791 r#"
2792pub fn main(values) {
2793 let #(left, right) = values
2794}
2795"#,
2796 find_position_of("let").select_until(find_position_of("="))
2797 );
2798}
2799
2800#[test]
2801fn annotate_local_variable_let_assert() {
2802 assert_code_action!(
2803 ADD_ANNOTATION,
2804 r#"
2805pub fn fallible() -> Result(Int, Nil) {
2806 todo
2807}
2808
2809pub fn main() {
2810 let assert Ok(value) = fallible()
2811}
2812"#,
2813 find_position_of("let").select_until(find_position_of("="))
2814 );
2815}
2816
2817#[test]
2818fn annotate_nested_local_variable() {
2819 assert_code_action!(
2820 ADD_ANNOTATION,
2821 r#"
2822pub fn main() {
2823 let a = {
2824 let b = 10
2825 b + 1
2826 }
2827}
2828"#,
2829 find_position_of("let b").select_until(find_position_of("b ="))
2830 );
2831}
2832
2833#[test]
2834fn no_code_action_for_annotated_local_variable() {
2835 assert_no_code_actions!(
2836 ADD_ANNOTATION | ADD_ANNOTATIONS,
2837 r#"
2838pub fn main() {
2839 let typed: Int = 1.2
2840}
2841"#,
2842 find_position_of("let").select_until(find_position_of("="))
2843 );
2844}
2845
2846#[test]
2847fn adding_annotations_correctly_prints_type_variables() {
2848 assert_code_action!(
2849 ADD_ANNOTATIONS,
2850 r#"
2851pub fn map_result(input, function) {
2852 case input {
2853 Ok(value) -> Ok(function(value))
2854 Error(error) -> Error(error)
2855 }
2856}
2857"#,
2858 find_position_of("fn").select_until(find_position_of("("))
2859 );
2860}
2861
2862#[test]
2863fn add_multiple_annotations() {
2864 assert_code_action!(
2865 ADD_ANNOTATIONS,
2866 r#"
2867pub const my_constant = 20
2868
2869pub fn add_my_constant(value) {
2870 let result = value + my_constant
2871 result
2872}
2873"#,
2874 find_position_of("pub const").select_until(find_position_of("}"))
2875 );
2876}
2877
2878#[test]
2879fn different_annotations_create_compatible_type_variables() {
2880 assert_code_action!(
2881 ADD_ANNOTATIONS,
2882 r#"
2883pub fn do_generic_things(a, b) {
2884 let a_value = a
2885 let b_value = b
2886 let other_value = a_value
2887}
2888"#,
2889 find_position_of("let a_value").select_until(find_position_of("}"))
2890 );
2891}
2892
2893#[test]
2894fn adding_annotations_prints_type_variable_names() {
2895 assert_code_action!(
2896 ADD_ANNOTATIONS,
2897 r#"
2898pub fn do_generic_things(a: type_a, b: type_b) {
2899 let a_value = a
2900 let b_value = b
2901 let other_value = a_value
2902}
2903"#,
2904 find_position_of("let a_value").select_until(find_position_of("}"))
2905 );
2906}
2907
2908#[test]
2909fn adding_annotations_prints_contextual_types() {
2910 assert_code_action!(
2911 ADD_ANNOTATION,
2912 r#"
2913pub type IntAlias = Int
2914
2915pub fn main() {
2916 let value = 20
2917}
2918"#,
2919 find_position_of("let").select_until(find_position_of("value"))
2920 );
2921}
2922
2923#[test]
2924fn adding_annotations_prints_contextual_types2() {
2925 assert_code_action!(
2926 ADD_ANNOTATION,
2927 r#"
2928pub type Result
2929
2930pub fn main() {
2931 let value = Ok(12)
2932}
2933"#,
2934 find_position_of("let").select_until(find_position_of("="))
2935 );
2936}
2937
2938#[test]
2939fn adding_annotations_prints_contextual_types3() {
2940 let src = r#"
2941import wibble
2942
2943pub fn main() {
2944 let value = wibble.Wibble
2945}
2946"#;
2947
2948 assert_code_action!(
2949 ADD_ANNOTATION,
2950 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"),
2951 find_position_of("let").select_until(find_position_of("="))
2952 );
2953}
2954
2955#[test]
2956fn add_annotation_triggers_on_function_curly_brace() {
2957 assert_code_action!(
2958 ADD_ANNOTATION,
2959 "pub fn main() { 1 }",
2960 find_position_of("{").to_selection(),
2961 );
2962}
2963
2964#[test]
2965fn add_annotation_triggers_on_empty_space_before_function_curly_brace() {
2966 assert_code_action!(
2967 ADD_ANNOTATION,
2968 "pub fn main() { 1 }",
2969 find_position_of(" ").nth_occurrence(3).to_selection(),
2970 );
2971}
2972
2973#[test]
2974fn adding_annotations_prints_contextual_types4() {
2975 let src = r#"
2976import wibble as wobble
2977
2978pub fn main() {
2979 let value = wobble.Wibble
2980}
2981"#;
2982
2983 assert_code_action!(
2984 ADD_ANNOTATION,
2985 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"),
2986 find_position_of("let").select_until(find_position_of("="))
2987 );
2988}
2989
2990#[test]
2991fn adding_annotations_prints_contextual_types5() {
2992 let src = r#"
2993import wibble.{type Wibble as Wobble}
2994
2995pub fn main() {
2996 let value = wibble.Wibble
2997}
2998"#;
2999
3000 assert_code_action!(
3001 ADD_ANNOTATION,
3002 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble { Wibble }"),
3003 find_position_of("let").select_until(find_position_of("="))
3004 );
3005}
3006
3007#[test]
3008// https://github.com/gleam-lang/gleam/issues/3789
3009fn no_code_actions_to_add_annotations_for_pipe() {
3010 assert_no_code_actions!(
3011 ADD_ANNOTATION | ADD_ANNOTATIONS,
3012 r#"
3013fn do_something(a: Int) { a }
3014
3015pub fn main() {
3016 10 |> do_something
3017}
3018"#,
3019 find_position_of("10").select_until(find_position_of("|>"))
3020 );
3021}
3022
3023#[test]
3024// https://github.com/gleam-lang/gleam/issues/3789#issuecomment-2455805734
3025fn add_correct_type_annotation_for_non_variable_use() {
3026 assert_code_action!(
3027 ADD_ANNOTATION,
3028 r#"
3029fn usable(f) {
3030 f(#(1, 2))
3031}
3032
3033pub fn main() {
3034 use #(a, b) <- usable
3035 a + b
3036}
3037"#,
3038 find_position_of("use").select_until(find_position_of("b)"))
3039 );
3040}
3041
3042#[test]
3043fn test_qualified_to_unqualified_import_basic_with_argument() {
3044 let src = r#"
3045import option
3046
3047pub fn main() {
3048 option.Some(1)
3049}
3050"#;
3051 assert_code_action!(
3052 "Unqualify option.Some",
3053 TestProject::for_source(src)
3054 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3055 find_position_of(".Some").select_until(find_position_of("(1)")),
3056 );
3057}
3058
3059#[test]
3060fn test_qualified_to_unqualified_import_basic_record_without_argument() {
3061 let src = r#"
3062import wobble
3063
3064pub fn main() {
3065 wobble.Wibble
3066}
3067"#;
3068 assert_code_action!(
3069 "Unqualify wobble.Wibble",
3070 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"),
3071 find_position_of(".W").select_until(find_position_of("ibble"))
3072 );
3073}
3074
3075#[test]
3076fn test_qualified_to_unqualified_import_custom_type_record_declaration() {
3077 let src = r#"
3078import wobble
3079
3080pub type Wibble {
3081 Wibble(wibble: wobble.Wobble)
3082}
3083"#;
3084 assert_code_action!(
3085 "Unqualify wobble.Wobble",
3086 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"),
3087 find_position_of(".").select_until(find_position_of("Wobble"))
3088 );
3089}
3090
3091#[test]
3092fn test_qualified_to_unqualified_import_basic_type_without_argument() {
3093 let src = r#"
3094import wobble
3095
3096pub fn identity(x: wobble.Wobble) -> wobble.Wobble {
3097 x
3098}
3099"#;
3100 assert_code_action!(
3101 "Unqualify wobble.Wobble",
3102 TestProject::for_source(src).add_hex_module("wobble", "pub type Wobble { Wibble }"),
3103 find_position_of(".").select_until(find_position_of("Wobble"))
3104 );
3105}
3106
3107#[test]
3108fn test_qualified_to_unqualified_record_value_constructor_module_name() {
3109 let src = r#"
3110import option
3111
3112pub fn main() {
3113 option.Some(1)
3114}
3115"#;
3116 assert_code_action!(
3117 "Unqualify option.Some",
3118 TestProject::for_source(src)
3119 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3120 find_position_of("option").nth_occurrence(2).to_selection()
3121 );
3122}
3123
3124#[test]
3125fn test_qualified_to_unqualified_import_basic_multiple() {
3126 let src = r#"
3127import option
3128
3129pub fn main() {
3130 option.Some(1)
3131 option.Some(1)
3132 todo
3133}
3134"#;
3135 assert_code_action!(
3136 "Unqualify option.Some",
3137 TestProject::for_source(src)
3138 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3139 find_position_of(".Some").select_until(find_position_of("(1)")),
3140 );
3141}
3142
3143#[test]
3144fn test_qualified_to_unqualified_import_when_unqualified_exists() {
3145 let src = r#"
3146import option.{Some}
3147
3148pub fn main() {
3149 option.Some(1)
3150}
3151"#;
3152 assert_code_action!(
3153 "Unqualify option.Some",
3154 TestProject::for_source(src)
3155 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3156 find_position_of(".Some").select_until(find_position_of("(1)")),
3157 );
3158}
3159
3160#[test]
3161fn test_qualified_to_unqualified_import_with_comma() {
3162 let src = r#"
3163import option.{None, }
3164
3165pub fn main() {
3166 option.Some(1)
3167}
3168"#;
3169 assert_code_action!(
3170 "Unqualify option.Some",
3171 TestProject::for_source(src)
3172 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3173 find_position_of(".Some").select_until(find_position_of("(1)")),
3174 );
3175}
3176
3177#[test]
3178fn test_qualified_to_unqualified_import_with_comma_pos_not_end() {
3179 let src = r#"
3180import option.{None, } as opt
3181
3182pub fn main() {
3183 opt.Some(1)
3184}
3185"#;
3186 assert_code_action!(
3187 "Unqualify opt.Some",
3188 TestProject::for_source(src)
3189 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3190 find_position_of(".Some").select_until(find_position_of("(1)")),
3191 );
3192}
3193
3194#[test]
3195fn test_qualified_to_unqualified_import_different_constructors() {
3196 let src = r#"
3197import option
3198
3199pub fn main() {
3200 option.Some(1)
3201 option.None
3202}"#;
3203 assert_code_action!(
3204 "Unqualify option.Some",
3205 TestProject::for_source(src)
3206 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3207 find_position_of(".Some").select_until(find_position_of("(1)")),
3208 );
3209}
3210
3211#[test]
3212fn test_qualified_to_unqualified_import_no_action_when_already_unqualified() {
3213 let src = r#"
3214import option.{Some, None}
3215
3216pub fn main() {
3217 Some(1)
3218 Some(1)
3219 todo
3220}
3221"#;
3222 let title = "Unqualify option.Some";
3223 assert_no_code_actions!(
3224 title,
3225 TestProject::for_source(src)
3226 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3227 find_position_of("Some(").select_until(find_position_of("1)")),
3228 );
3229}
3230
3231#[test]
3232fn test_qualified_to_unqualified_import_with_alias() {
3233 let src = r#"
3234import option as opt
3235
3236pub fn main() {
3237 opt.Some(1)
3238}
3239"#;
3240 assert_code_action!(
3241 "Unqualify opt.Some",
3242 TestProject::for_source(src)
3243 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3244 find_position_of("opt.Some").select_until(find_position_of("(1)")),
3245 );
3246}
3247
3248#[test]
3249fn test_qualified_to_unqualified_import_with_alias_multiple() {
3250 let src = r#"
3251import option as opt
3252
3253pub fn main() {
3254 opt.Some(1)
3255 opt.Some(1)
3256}
3257
3258pub fn identity(x: opt.Option(Int)) -> opt.Option(Int) {
3259 opt.Some(1)
3260 x
3261}
3262"#;
3263 assert_code_action!(
3264 "Unqualify opt.Some",
3265 TestProject::for_source(src)
3266 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3267 find_position_of("opt.Some").select_until(find_position_of("(1)")),
3268 );
3269}
3270
3271#[test]
3272fn test_qualified_to_unqualified_import_multiple_imports() {
3273 let src = r#"
3274import option
3275import wobble
3276
3277pub fn main() {
3278 option.Some(2)
3279 wobble.Wibble(1)
3280}
3281"#;
3282 assert_code_action!(
3283 "Unqualify wobble.Wibble",
3284 TestProject::for_source(src)
3285 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3286 .add_hex_module("wobble", "pub type Wobble { Wibble(Int)} "),
3287 find_position_of(".Wibble").select_until(find_position_of("(1)")),
3288 );
3289}
3290
3291#[test]
3292fn test_qualified_to_unqualified_import_in_case_with_argument() {
3293 let src = r#"
3294import option
3295
3296pub fn main(x) {
3297 case option.Some(1) {
3298 option.Some(value) -> value
3299 option.None -> 0
3300 }
3301}
3302"#;
3303 assert_code_action!(
3304 "Unqualify option.Some",
3305 TestProject::for_source(src)
3306 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3307 find_position_of(".Some(").select_until(find_position_of("(1)"))
3308 );
3309}
3310
3311#[test]
3312fn test_qualified_to_unqualified_import_in_case_without_argument() {
3313 let src = r#"
3314import wobble
3315
3316pub fn main() {
3317 case wobble.Wibble {
3318 wobble.Wibble -> 1
3319 wobble.Wubble(1) -> 2
3320 }
3321}
3322"#;
3323 assert_code_action!(
3324 "Unqualify wobble.Wibble",
3325 TestProject::for_source(src)
3326 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"),
3327 find_position_of(".W").select_until(find_position_of("ibble"))
3328 );
3329}
3330
3331#[test]
3332fn test_qualified_to_unqualified_import_in_pattern() {
3333 let src = r#"
3334import option
3335
3336pub fn main() -> Int {
3337 case option.Some(1) {
3338 option.Some(value) -> value
3339 option.None -> 0
3340 }
3341}
3342"#;
3343 assert_code_action!(
3344 "Unqualify option.Some",
3345 TestProject::for_source(src)
3346 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3347 find_position_of(".Some(va").select_until(find_position_of("lue)")),
3348 );
3349}
3350
3351#[test]
3352fn test_qualified_to_unqualified_import_in_pattern_without_argument() {
3353 let src = r#"
3354import wobble
3355
3356pub fn main() {
3357 case wobble.Wibble {
3358 wobble.Wibble -> 1
3359 wobble.Wubble(1) -> 2
3360 }
3361 let wob = wobble.Wibble
3362 todo
3363}
3364"#;
3365 assert_code_action!(
3366 "Unqualify wobble.Wibble",
3367 TestProject::for_source(src)
3368 .add_hex_module("wobble", "pub type Wobble { Wibble Wubble(Int) }"),
3369 find_position_of("wobble.W").select_until(find_position_of("ibble"))
3370 );
3371}
3372
3373#[test]
3374fn test_qualified_to_unqualified_import_type() {
3375 let src = r#"
3376import option
3377
3378pub fn main(x) -> option.Option(Int) {
3379 option.Some(1)
3380}
3381"#;
3382 assert_code_action!(
3383 "Unqualify option.Option",
3384 TestProject::for_source(src)
3385 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3386 find_position_of(".Option").select_until(find_position_of("(Int)")),
3387 );
3388}
3389
3390#[test]
3391fn test_qualified_to_unqualified_import_nested_type_outer() {
3392 let src = r#"
3393import option
3394import wobble
3395pub fn main(x) -> option.Option(wobble.Wibble) {
3396 todo
3397}
3398"#;
3399 assert_code_action!(
3400 "Unqualify option.Option",
3401 TestProject::for_source(src)
3402 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3403 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"),
3404 find_position_of(".O").select_until(find_position_of("ption(")),
3405 );
3406}
3407
3408#[test]
3409fn test_qualified_to_unqualified_import_nested_constructor_outer() {
3410 let src = r#"
3411import option
3412import wobble
3413pub fn main(x) -> option.Option(wobble.Wibble) {
3414 option.Some(wobble.Wobble(1))
3415}
3416"#;
3417 assert_code_action!(
3418 "Unqualify option.Some",
3419 TestProject::for_source(src)
3420 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3421 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"),
3422 find_position_of(".S").select_until(find_position_of("ome(")),
3423 );
3424}
3425
3426#[test]
3427fn test_qualified_to_unqualified_import_nested_constructor_inner() {
3428 let src = r#"
3429import option
3430import wobble
3431
3432pub fn main(x) -> option.Option(wobble.Wibble) {
3433 option.Some(wobble.Wobble(1))
3434}
3435"#;
3436 assert_code_action!(
3437 "Unqualify wobble.Wobble",
3438 TestProject::for_source(src)
3439 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3440 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"),
3441 find_position_of(".Wobble").select_until(find_position_of("(1)")),
3442 );
3443}
3444
3445#[test]
3446fn test_qualified_to_unqualified_import_nested_type_inner() {
3447 let src = r#"
3448import option
3449import wobble
3450
3451pub fn main(x) -> option.Option(wobble.Wibble) {
3452 todo
3453}
3454"#;
3455 assert_code_action!(
3456 "Unqualify wobble.Wibble",
3457 TestProject::for_source(src)
3458 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3459 .add_hex_module("wobble", "pub type Wibble { Wobble(Int) }"),
3460 find_position_of("wobble.").select_until(find_position_of("Wibble")),
3461 );
3462}
3463
3464#[test]
3465fn test_qualified_to_unqualified_import_below_constructor() {
3466 let src = r#"
3467
3468pub fn main() {
3469 option.Some(1)
3470}
3471
3472import option
3473"#;
3474 assert_code_action!(
3475 "Unqualify option.Some",
3476 TestProject::for_source(src)
3477 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3478 find_position_of(".Some").select_until(find_position_of("(1)")),
3479 );
3480}
3481
3482#[test]
3483fn test_qualified_to_unqualified_import_between_constructors() {
3484 let src = r#"
3485
3486pub fn main() {
3487 option.Some(1)
3488}
3489
3490import option
3491
3492pub fn identity(x: option.Option(Int)) -> option.Option(Int) {
3493 option.Some(1)
3494 x
3495}
3496"#;
3497 assert_code_action!(
3498 "Unqualify option.Some",
3499 TestProject::for_source(src)
3500 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3501 find_position_of(".Some").select_until(find_position_of("(1)")),
3502 );
3503}
3504
3505#[test]
3506fn test_qualified_to_unqualified_import_multiple_line() {
3507 let src = r#"
3508import option.{
3509 type Option,
3510 None,
3511}
3512
3513pub fn main() {
3514 option.Some(1)
3515}
3516"#;
3517 assert_code_action!(
3518 "Unqualify option.Some",
3519 TestProject::for_source(src)
3520 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3521 find_position_of(".Some").select_until(find_position_of("(1)")),
3522 );
3523}
3524
3525#[test]
3526fn test_qualified_to_unqualified_import_multiple_line_bad_format_with_trailing_comma() {
3527 let src = r#"
3528import option.{type Option,
3529 None,
3530
3531}
3532
3533pub fn main() {
3534 option.Some(1)
3535}
3536"#;
3537 assert_code_action!(
3538 "Unqualify option.Some",
3539 TestProject::for_source(src)
3540 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3541 find_position_of(".Some").select_until(find_position_of("(1)")),
3542 );
3543}
3544
3545#[test]
3546fn test_qualified_to_unqualified_import_multiple_line_bad_format_multiple_whitespace() {
3547 let src = r#"
3548import option.{ }
3549
3550pub fn main() {
3551 option.Some(1)
3552}
3553"#;
3554 assert_code_action!(
3555 "Unqualify option.Some",
3556 TestProject::for_source(src)
3557 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3558 find_position_of(".Some").select_until(find_position_of("(1)")),
3559 );
3560}
3561#[test]
3562fn test_qualified_to_unqualified_import_multiple_line_bad_format_without_trailing_comma() {
3563 let src = r#"
3564import option.{type Option,
3565 None
3566
3567}
3568
3569pub fn main() {
3570 option.Some(1)
3571}
3572"#;
3573 assert_code_action!(
3574 "Unqualify option.Some",
3575 TestProject::for_source(src)
3576 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3577 find_position_of(".Some").select_until(find_position_of("(1)")),
3578 );
3579}
3580#[test]
3581fn test_qualified_to_unqualified_import_multiple_line_aliased() {
3582 let src = r#"
3583import option.{
3584 type Option,
3585 None} as opt
3586
3587pub fn main() {
3588 opt.Some(1)
3589}
3590"#;
3591 assert_code_action!(
3592 "Unqualify opt.Some",
3593 TestProject::for_source(src)
3594 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3595 find_position_of(".Some").select_until(find_position_of("(1)")),
3596 );
3597}
3598
3599#[test]
3600fn test_qualified_to_unqualified_import_in_list_and_tuple() {
3601 let src = r#"
3602import option
3603
3604pub fn main() {
3605 let list = [option.Some(1), option.None]
3606 let tuple = #(option.Some(2), option.None)
3607}
3608"#;
3609 assert_code_action!(
3610 "Unqualify option.Some",
3611 TestProject::for_source(src)
3612 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3613 find_position_of("option.Some").select_until(find_position_of("(1)")),
3614 );
3615}
3616
3617#[test]
3618fn test_qualified_to_unqualified_import_multiple_generic_type() {
3619 let src = r#"
3620import result
3621
3622pub fn main() -> result.Result(Int, String) {
3623 result.Ok(1)
3624}
3625"#;
3626 assert_code_action!(
3627 "Unqualify result.Result",
3628 TestProject::for_source(src)
3629 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"),
3630 find_position_of(".Result").select_until(find_position_of("(Int")),
3631 );
3632}
3633
3634#[test]
3635fn test_qualified_to_unqualified_import_constructor_as_argument() {
3636 let src = r#"
3637import option
3638
3639pub fn main() {
3640 option.map(option.Some(1), fn(x) { x + 1 })
3641}
3642"#;
3643 assert_code_action!(
3644 "Unqualify option.Some",
3645 TestProject::for_source(src).add_hex_module(
3646 "option",
3647 "
3648 pub type Option(v) { Some(v) None }
3649 pub fn map(a, f) { todo }
3650 "
3651 ),
3652 find_position_of("option.Some").select_until(find_position_of("(1)")),
3653 );
3654}
3655
3656#[test]
3657fn test_qualified_to_unqualified_import_constructor_different_module_same_type_inner() {
3658 let src = r#"
3659import option
3660import opt
3661
3662pub fn main() -> option.Option(opt.Option(Int)) {
3663 todo
3664}
3665"#;
3666 assert_code_action!(
3667 "Unqualify opt.Option",
3668 TestProject::for_source(src)
3669 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3670 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3671 find_position_of("opt.Option").select_until(find_position_of("(Int)")),
3672 );
3673}
3674#[test]
3675fn test_qualified_to_unqualified_import_constructor_different_module_same_type_outer() {
3676 let src = r#"
3677import option
3678import opt
3679
3680pub fn main() -> option.Option(opt.Option(Int)) {
3681 todo
3682}
3683"#;
3684 assert_code_action!(
3685 "Unqualify option.Option",
3686 TestProject::for_source(src)
3687 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3688 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3689 find_position_of("option.").select_until(find_position_of("Option(")),
3690 );
3691}
3692#[test]
3693fn test_qualified_to_unqualified_import_constructor_different_module_same_name_inner() {
3694 let src = r#"
3695import option
3696import opt
3697
3698pub fn main() {
3699 option.Some(opt.Some(1))
3700 todo
3701}
3702"#;
3703 assert_code_action!(
3704 "Unqualify opt.Some",
3705 TestProject::for_source(src)
3706 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3707 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3708 find_position_of("opt.Some").select_until(find_position_of("(1)")),
3709 );
3710}
3711#[test]
3712fn test_qualified_to_unqualified_import_constructor_different_module_same_name_outer() {
3713 let src = r#"
3714import option
3715import opt
3716
3717pub fn main() {
3718 option.Some(opt.Some(1))
3719}
3720"#;
3721 assert_code_action!(
3722 "Unqualify option.Some",
3723 TestProject::for_source(src)
3724 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3725 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3726 find_position_of("option.").select_until(find_position_of("Some(")),
3727 );
3728}
3729
3730#[test]
3731fn test_qualified_to_unqualified_import_constructor_complex_pattern() {
3732 let src = r#"
3733import option
3734
3735pub fn main() {
3736 case [option.Some(1), option.None] {
3737 [option.None, ..] -> todo
3738 [option.Some(_), ..] -> todo
3739 _ -> todo
3740 }
3741 case option.Some(1), option.Some(2) {
3742 option.None, option.Some(_) -> todo
3743 option.Some(_), option.Some(val) -> todo
3744 _ -> todo
3745 }
3746}
3747"#;
3748 assert_code_action!(
3749 "Unqualify option.Some",
3750 TestProject::for_source(src)
3751 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
3752 find_position_of("option.").select_until(find_position_of("Some(")),
3753 );
3754}
3755
3756#[test]
3757fn test_qualified_to_unqualified_import_constructor_constructor_name_exists() {
3758 let src = r#"
3759import option.{Some}
3760import opt
3761
3762pub fn main() -> option.Option(opt.Option(Int)) {
3763 Some(opt.Some(1))
3764}
3765"#;
3766 let title = "Unqualify opt.Some";
3767 assert_no_code_actions!(
3768 title,
3769 TestProject::for_source(src)
3770 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3771 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3772 find_position_of("opt.").select_until(find_position_of(".Some(")),
3773 );
3774}
3775
3776#[test]
3777fn test_qualified_to_unqualified_import_constructor_constructor_name_exists_below() {
3778 let src = r#"
3779import opt
3780
3781pub fn main() -> option.Option(opt.Option(Int)) {
3782 Some(opt.Some(1))
3783}
3784import option.{Some}
3785"#;
3786 let title = "Unqualify opt.Some";
3787 assert_no_code_actions!(
3788 title,
3789 TestProject::for_source(src)
3790 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3791 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3792 find_position_of("opt.").select_until(find_position_of(".Some(")),
3793 );
3794}
3795
3796#[test]
3797fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists() {
3798 let src = r#"
3799import option.{type Option}
3800import opt
3801
3802pub fn main() -> Option(opt.Option(Int)) {
3803 option.Some(opt.Some(1))
3804}
3805"#;
3806 let title = "Unqualify opt.Option";
3807 assert_no_code_actions!(
3808 title,
3809 TestProject::for_source(src)
3810 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3811 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3812 find_position_of("opt.").select_until(find_position_of(".Option(")),
3813 );
3814}
3815
3816#[test]
3817fn test_qualified_to_unqualified_import_type_constructor_constructor_name_exists_below() {
3818 let src = r#"
3819import opt
3820
3821pub fn main() -> Option(opt.Option(Int)) {
3822 option.Some(opt.Some(1))
3823}
3824import option.{type Option}
3825"#;
3826 let title = "Unqualify opt.Option";
3827 assert_no_code_actions!(
3828 title,
3829 TestProject::for_source(src)
3830 .add_hex_module("option", "pub type Option(v) { Some(v) None }")
3831 .add_hex_module("opt", "pub type Option(v) { Some(v) None }"),
3832 find_position_of("opt.").select_until(find_position_of(".Option(")),
3833 );
3834}
3835#[test]
3836fn test_unqualified_to_qualified_import_function() {
3837 let src = r#"
3838import list.{map}
3839
3840pub fn main() {
3841 let identity = map([1, 2, 3], fn(x) { x })
3842 let double = map([1, 2, 3], fn(x) { x * 2 })
3843}
3844"#;
3845 assert_code_action!(
3846 "Qualify map as list.map",
3847 TestProject::for_source(src).add_hex_module("list", "pub fn map(list, f) { todo }"),
3848 find_position_of("map(").select_until(find_position_of("[1, 2, 3]")),
3849 );
3850}
3851
3852#[test]
3853fn test_unqualified_to_qualified_import_constant() {
3854 let src = r#"
3855import mymath.{pi}
3856
3857pub fn circle_area(radius: Float) -> Float {
3858 pi *. radius *. radius
3859}
3860
3861pub fn circle_circumference(radius: Float) -> Float {
3862 2. *. pi *. radius
3863}
3864"#;
3865 assert_code_action!(
3866 "Qualify pi as mymath.pi",
3867 TestProject::for_source(src).add_hex_module("mymath", "pub const pi = 3.14159"),
3868 find_position_of("pi *.").select_until(find_position_of(" radius")),
3869 );
3870}
3871
3872#[test]
3873fn test_unqualified_to_qualified_import_record_constructor() {
3874 let src = r#"
3875import user.{type User, User}
3876
3877pub fn create_user(name: String) -> User {
3878 User(name: name, id: 1)
3879}
3880"#;
3881 assert_code_action!(
3882 "Qualify User as user.User",
3883 TestProject::for_source(src)
3884 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"),
3885 find_position_of("User(").select_until(find_position_of("name: name")),
3886 );
3887}
3888
3889#[test]
3890fn test_unqualified_to_qualified_import_after_constructor() {
3891 let src = r#"
3892pub fn create_user(name: String) -> User {
3893 User(name: name, id: 1)
3894}
3895
3896import user.{type User, User}
3897"#;
3898 assert_code_action!(
3899 "Qualify User as user.User",
3900 TestProject::for_source(src)
3901 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"),
3902 find_position_of("User(").select_until(find_position_of("name: name")),
3903 );
3904}
3905
3906#[test]
3907fn test_unqualified_to_qualified_import_between_constructors() {
3908 let src = r#"
3909pub fn create_user(name: String) -> User {
3910 User(name: name, id: 1)
3911}
3912
3913import user.{type User, User}
3914
3915pub fn user_list(users: List(User)) -> List(String) {
3916 [User(name: "John", id: 1),
3917 User(name: "Jane", id: 2)]
3918}
3919
3920"#;
3921 assert_code_action!(
3922 "Qualify User as user.User",
3923 TestProject::for_source(src)
3924 .add_hex_module("user", "pub type User { User(name: String, id: Int) }"),
3925 find_position_of("User(").select_until(find_position_of("name: name")),
3926 );
3927}
3928
3929#[test]
3930fn test_unqualified_to_qualified_import_multiple_occurrences() {
3931 let src = r#"
3932import list.{map, filter}
3933
3934pub fn process_list(items: List(Int)) -> List(Int) {
3935 items
3936 |> map(fn(x) { x + 1 })
3937 |> map(fn(x) { x * 2 })
3938}
3939"#;
3940 assert_code_action!(
3941 "Qualify map as list.map",
3942 TestProject::for_source(src).add_hex_module(
3943 "list",
3944 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }"
3945 ),
3946 find_position_of("|> map").select_until(find_position_of("(fn(x)")),
3947 );
3948}
3949
3950#[test]
3951fn test_unqualified_to_qualified_import_in_pattern_matching() {
3952 let src = r#"
3953import result.{type Result, Ok, Error}
3954
3955pub fn process_result(res: Result(Int, String)) -> Int {
3956 case res {
3957 Ok(value) -> value
3958 Error(_) -> 0
3959 }
3960}
3961"#;
3962 assert_code_action!(
3963 "Qualify Ok as result.Ok",
3964 TestProject::for_source(src)
3965 .add_hex_module("result", "pub type Result(a, e) { Ok(a) Error(e) }"),
3966 find_position_of("Ok(").select_until(find_position_of("value)")),
3967 );
3968}
3969
3970#[test]
3971fn test_unqualified_to_qualified_import_type_annotation() {
3972 let src = r#"
3973import option.{type Option, Some}
3974
3975pub fn maybe_increment(x: Option(Int)) -> Option(Int) {
3976 case x {
3977 Some(value) -> Some(value + 1)
3978 _ -> x
3979 }
3980}
3981"#;
3982 assert_code_action!(
3983 "Qualify Option as option.Option",
3984 TestProject::for_source(src)
3985 .add_hex_module("option", "pub type Option(a) { Some(a) None }"),
3986 find_position_of("Opt")
3987 .nth_occurrence(2)
3988 .select_until(find_position_of("ion(")),
3989 );
3990}
3991
3992#[test]
3993fn test_unqualified_to_qualified_import_nested_function_call() {
3994 let src = r#"
3995import list.{map, flatten}
3996import operation.{double}
3997
3998pub fn process_names(names: List(List(Int))) -> List(Int) {
3999 names
4000 |> flatten
4001 |> map(double)
4002}
4003"#;
4004 assert_code_action!(
4005 "Qualify double as operation.double",
4006 TestProject::for_source(src)
4007 .add_hex_module(
4008 "list",
4009 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }
4010pub fn flatten(lists: List(List(a))) -> List(a) { todo }"
4011 )
4012 .add_hex_module("operation", "pub fn double(s: Int) -> Int { todo }"),
4013 find_position_of("(dou").select_until(find_position_of("ble)")),
4014 );
4015}
4016
4017#[test]
4018fn test_unqualified_to_qualified_import_with_alias() {
4019 let src = r#"
4020import list.{map as transform}
4021
4022pub fn double_list(items: List(Int)) -> List(Int) {
4023 transform(items, fn(x) { x * 2 })
4024}
4025"#;
4026 assert_code_action!(
4027 "Qualify transform as list.map",
4028 TestProject::for_source(src).add_hex_module(
4029 "list",
4030 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }"
4031 ),
4032 find_position_of("transform(").select_until(find_position_of("items,")),
4033 );
4034}
4035
4036#[test]
4037fn test_unqualified_to_qualified_import_with_alias_and_module_alias() {
4038 let src = r#"
4039import list.{map as transform} as lst
4040
4041pub fn double_list(items: List(Int)) -> List(Int) {
4042 transform(items, fn(x) { x * 2 })
4043}
4044"#;
4045 assert_code_action!(
4046 "Qualify transform as lst.map",
4047 TestProject::for_source(src).add_hex_module(
4048 "list",
4049 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }"
4050 ),
4051 find_position_of("transform(").select_until(find_position_of("items,")),
4052 );
4053}
4054
4055#[test]
4056fn test_unqualified_to_qualified_import_import_discarded() {
4057 let src = r#"
4058import list.{map as transform} as _
4059
4060pub fn double_list(items: List(Int)) -> List(Int) {
4061 transform(items, fn(x) { x * 2 })
4062}
4063"#;
4064 let title = "Qualify transform as list.map";
4065 assert_no_code_actions!(
4066 title,
4067 TestProject::for_source(src).add_hex_module(
4068 "list",
4069 "pub fn map(list: List(a), with fun: fn(a) -> b) -> List(b) { todo }"
4070 ),
4071 find_position_of("transform(").select_until(find_position_of("items,")),
4072 );
4073}
4074
4075#[test]
4076fn test_unqualified_to_qualified_import_bad_formatted_type_constructor() {
4077 let src = r#"
4078import option.{type Option, Some}
4079
4080pub fn maybe_increment(x: Option(Int)) -> Option(Int) {
4081 case x {
4082 Some(value) -> Some(value + 1)
4083 _ -> x
4084 }
4085}
4086"#;
4087 assert_code_action!(
4088 "Qualify Option as option.Option",
4089 TestProject::for_source(src)
4090 .add_hex_module("option", "pub type Option(a) { Some(a) None }"),
4091 find_position_of("Opt")
4092 .nth_occurrence(2)
4093 .select_until(find_position_of("ion(")),
4094 );
4095}
4096
4097#[test]
4098fn test_unqualified_to_qualified_import_bad_formatted_type_constructor_with_alias() {
4099 let src = r#"
4100import option.{type Option as Maybe, Some}
4101
4102pub fn maybe_increment(x: Maybe(Int)) -> Maybe(Int) {
4103 case x {
4104 Some(value) -> Some(value + 1)
4105 _ -> x
4106 }
4107}
4108"#;
4109 assert_code_action!(
4110 "Qualify Maybe as option.Option",
4111 TestProject::for_source(src)
4112 .add_hex_module("option", "pub type Option(a) { Some(a) None }"),
4113 find_position_of("May")
4114 .nth_occurrence(2)
4115 .select_until(find_position_of("be(")),
4116 );
4117}
4118
4119#[test]
4120fn test_unqualified_to_qualified_import_bad_formatted_comma() {
4121 let src = r#"
4122import option.{type Option , Some}
4123
4124pub fn maybe_increment(x: Option(Int)) -> Option(Int) {
4125 case x {
4126 Some(value) -> Some(value + 1)
4127 _ -> x
4128 }
4129}
4130"#;
4131 assert_code_action!(
4132 "Qualify Option as option.Option",
4133 TestProject::for_source(src)
4134 .add_hex_module("option", "pub type Option(a) { Some(a) None }"),
4135 find_position_of("Opt")
4136 .nth_occurrence(2)
4137 .select_until(find_position_of("ion(")),
4138 );
4139}
4140
4141#[test]
4142fn test_unqualified_to_qualified_import_in_list_and_tuple() {
4143 let src = r#"
4144import option.{Some}
4145
4146pub fn main() {
4147 let list = [Some(1), option.None]
4148 let tuple = #(Some(2), option.None)
4149}
4150"#;
4151 assert_code_action!(
4152 "Qualify Some as option.Some",
4153 TestProject::for_source(src)
4154 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
4155 find_position_of("Some(").select_until(find_position_of("1)")),
4156 );
4157}
4158#[test]
4159fn test_unqualified_to_qualified_import_constructor_complex_pattern() {
4160 let src = r#"
4161import option.{None, Some}
4162
4163pub fn main() {
4164 case [Some(1), None] {
4165 [None, ..] -> todo
4166 [Some(_), ..] -> todo
4167 _ -> todo
4168 }
4169 case Some(1), Some(2) {
4170 None, Some(_) -> todo
4171 Some(_), Some(val) -> todo
4172 _ -> todo
4173 }
4174}
4175"#;
4176 assert_code_action!(
4177 "Qualify Some as option.Some",
4178 TestProject::for_source(src)
4179 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
4180 find_position_of("Some(").select_until(find_position_of("1)")),
4181 );
4182}
4183
4184#[test]
4185fn test_unqualified_to_qualified_import_multiple_line_aliased() {
4186 let src = r#"
4187import option.{
4188 type Option,
4189 None,
4190 Some
4191} as opt
4192
4193pub fn main() {
4194 Some(1)
4195}
4196"#;
4197 assert_code_action!(
4198 "Qualify Some as opt.Some",
4199 TestProject::for_source(src)
4200 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
4201 find_position_of("Some")
4202 .nth_occurrence(2)
4203 .select_until(find_position_of("(1)")),
4204 );
4205}
4206
4207#[test]
4208fn test_unqualified_to_qualified_import_multiple_line_bad_format_without_trailing_comma() {
4209 let src = r#"
4210import option.{type Option,
4211 Some
4212
4213}
4214
4215pub fn main() {
4216 Some(1)
4217}
4218"#;
4219 assert_code_action!(
4220 "Qualify Some as option.Some",
4221 TestProject::for_source(src)
4222 .add_hex_module("option", "pub type Option(v) { Some(v) None }"),
4223 find_position_of("Some")
4224 .nth_occurrence(2)
4225 .select_until(find_position_of("(1)")),
4226 );
4227}
4228
4229#[test]
4230fn test_unqualified_to_qualified_import_variable_shadowing() {
4231 let src = r#"
4232
4233import wibble.{wobble}
4234
4235pub fn example() {
4236 echo wobble
4237
4238 let wobble = 1
4239
4240 echo wobble
4241
4242 let _ = fn(wobble) {
4243 echo wobble
4244 }
4245
4246 todo
4247}
4248"#;
4249
4250 assert_code_action!(
4251 "Qualify wobble as wibble.wobble",
4252 TestProject::for_source(src).add_hex_module("wibble", "pub fn wobble() { todo }"),
4253 find_position_of("wob")
4254 .nth_occurrence(2)
4255 .select_until(find_position_of("ble").nth_occurrence(3))
4256 );
4257}
4258
4259/* TODO: implement qualified unused location
4260#[test]
4261fn test_remove_unused_qualified_action() {
4262 let code = "
4263// test
4264import map.{Map, delete}
4265";
4266 let expected = "
4267// test
4268
4269";
4270 assert_eq!(remove_unused_action(code), expected.to_string())
4271}
4272
4273#[test]
4274fn test_remove_unused_qualified_partial_action() {
4275 let code = "
4276// test
4277import result.{is_ok, is_err}
4278
4279pub fn main() {
4280 is_ok
4281}
4282";
4283 let expected = "
4284// test
4285import result.{is_ok}
4286
4287pub fn main() {
4288 is_ok
4289}
4290";
4291 assert_eq!(remove_unused_action(code), expected.to_string())
4292}
4293
4294#[test]
4295fn test_remove_unused_qualified_partial2_action() {
4296 let code = "
4297// test
4298import result.{all, is_ok, is_err}
4299
4300pub fn main() {
4301 is_ok
4302}
4303";
4304 let expected = "
4305// test
4306import result.{ is_ok}
4307
4308pub fn main() {
4309 is_ok
4310}
4311";
4312 assert_eq!(remove_unused_action(code), expected.to_string())
4313}
4314
4315#[test]
4316fn test_remove_unused_qualified_partial3_action() {
4317 let code = "
4318// test
4319import result.{all, is_ok, is_err} as res
4320
4321pub fn main() {
4322 is_ok
4323}
4324";
4325 let expected = "
4326// test
4327import result.{ is_ok} as res
4328
4329pub fn main() {
4330 is_ok
4331}
4332";
4333 assert_eq!(remove_unused_action(code), expected.to_string())
4334}
4335*/
4336
4337#[test]
4338fn convert_from_use_expression_with_no_parens() {
4339 let src = r#"
4340pub fn main() {
4341 use <- wibble
4342 todo
4343 todo
4344}
4345
4346fn wibble(f) {
4347 f()
4348}
4349"#;
4350 assert_code_action!(
4351 CONVERT_FROM_USE,
4352 TestProject::for_source(src),
4353 find_position_of("use").select_until(find_position_of("wibble")),
4354 );
4355}
4356
4357#[test]
4358fn convert_from_use_expression_with_empty_parens() {
4359 let src = r#"
4360pub fn main() {
4361 use <- wibble()
4362 todo
4363 todo
4364}
4365
4366fn wibble(f) {
4367 f()
4368}
4369"#;
4370 assert_code_action!(
4371 CONVERT_FROM_USE,
4372 TestProject::for_source(src),
4373 find_position_of("use").to_selection(),
4374 );
4375}
4376
4377#[test]
4378fn convert_from_use_expression_with_parens_and_other_args() {
4379 let src = r#"
4380pub fn main() {
4381 use <- wibble(1, 2)
4382 todo
4383 todo
4384}
4385
4386fn wibble(n, m, f) {
4387 f()
4388}
4389"#;
4390 assert_code_action!(
4391 CONVERT_FROM_USE,
4392 TestProject::for_source(src),
4393 find_position_of("wibble").select_until(find_position_of("1")),
4394 );
4395}
4396
4397#[test]
4398fn convert_from_use_expression_with_single_pattern() {
4399 let src = r#"
4400pub fn main() {
4401 use a <- wibble(1, 2)
4402 todo
4403 todo
4404}
4405
4406fn wibble(n, m, f) {
4407 f(1)
4408}
4409"#;
4410 assert_code_action!(
4411 CONVERT_FROM_USE,
4412 TestProject::for_source(src),
4413 find_position_of("a <-").to_selection(),
4414 );
4415}
4416
4417#[test]
4418fn convert_from_use_expression_with_multiple_patterns() {
4419 let src = r#"
4420pub fn main() {
4421 use a, b <- wibble(1, 2)
4422 todo
4423 todo
4424}
4425
4426fn wibble(n, m, f) {
4427 f(1, 2)
4428}
4429"#;
4430 assert_code_action!(
4431 CONVERT_FROM_USE,
4432 TestProject::for_source(src),
4433 find_position_of("wibble").to_selection(),
4434 );
4435}
4436
4437#[test]
4438fn desugar_nested_use_expressions_picks_inner_under_cursor() {
4439 let src = r#"
4440pub fn main() {
4441 use a, b <- wibble(1, 2)
4442 use a, b <- wibble(a, b)
4443 todo
4444}
4445
4446fn wibble(n, m, f) {
4447 f(1, 2)
4448}
4449"#;
4450 assert_code_action!(
4451 CONVERT_FROM_USE,
4452 TestProject::for_source(src),
4453 find_position_of("use").nth_occurrence(2).to_selection(),
4454 );
4455}
4456
4457#[test]
4458fn convert_from_use_only_triggers_on_the_use_line() {
4459 let src = r#"
4460pub fn main() {
4461 use a, b <- wibble(1, 2)
4462 todo
4463}
4464
4465fn wibble(n, m, f) {
4466 f(1, 2)
4467}
4468"#;
4469 assert_no_code_actions!(
4470 CONVERT_FROM_USE,
4471 TestProject::for_source(src),
4472 find_position_of("todo").to_selection(),
4473 );
4474}
4475
4476#[test]
4477fn desugar_nested_use_expressions_picks_inner_under_cursor_2() {
4478 let src = r#"
4479pub fn main() {
4480 use a, b <- wibble(1, 2)
4481 use a, b <- wibble(a, b)
4482 todo
4483}
4484
4485fn wibble(n, m, f) {
4486 f(1, 2)
4487}
4488"#;
4489 assert_code_action!(
4490 CONVERT_FROM_USE,
4491 TestProject::for_source(src),
4492 find_position_of("<-").select_until(find_position_of("wibble")),
4493 );
4494}
4495
4496#[test]
4497fn convert_from_use_expression_with_type_annotations() {
4498 let src = r#"
4499pub fn main() {
4500 use a: Int, b: Int <- wibble(1, 2)
4501 todo
4502}
4503
4504fn wibble(n, m, f) {
4505 f(1, 2)
4506}
4507"#;
4508 assert_code_action!(
4509 CONVERT_FROM_USE,
4510 TestProject::for_source(src),
4511 find_position_of("<-").select_until(find_position_of("wibble")),
4512 );
4513}
4514
4515#[test]
4516fn convert_from_use_expression_doesnt_work_with_complex_patterns() {
4517 let src = r#"
4518pub fn main() {
4519 use #(a, b), 1 <- wibble(1, 2)
4520 todo
4521}
4522
4523fn wibble(n, m, f) {
4524 f(todo, todo)
4525}
4526"#;
4527 assert_no_code_actions!(
4528 CONVERT_FROM_USE,
4529 TestProject::for_source(src),
4530 find_position_of("<-").select_until(find_position_of("wibble")),
4531 );
4532}
4533
4534#[test]
4535fn convert_from_use_with_labels() {
4536 let src = r#"
4537pub fn main() {
4538 use a <- wibble(one: 1, two: 2)
4539 todo
4540}
4541
4542fn wibble(one _, two _, three f) {
4543 f(1)
4544}
4545"#;
4546 assert_code_action!(
4547 CONVERT_FROM_USE,
4548 TestProject::for_source(src),
4549 find_position_of("use").to_selection(),
4550 );
4551}
4552
4553#[test]
4554fn convert_from_use_with_labels_2() {
4555 let src = r#"
4556pub fn main() {
4557 use a <- wibble(1, two: 2)
4558 todo
4559}
4560
4561fn wibble(one _, two _, three f) {
4562 f(1)
4563}
4564"#;
4565 assert_code_action!(
4566 CONVERT_FROM_USE,
4567 TestProject::for_source(src),
4568 find_position_of("use").to_selection(),
4569 );
4570}
4571
4572#[test]
4573fn convert_from_use_with_labels_3() {
4574 let src = r#"
4575pub fn main() {
4576 use a <- wibble(1, three: 3)
4577 todo
4578}
4579
4580fn wibble(one _, two f, three _) {
4581 f(1)
4582}
4583"#;
4584 assert_code_action!(
4585 CONVERT_FROM_USE,
4586 TestProject::for_source(src),
4587 find_position_of("use").to_selection(),
4588 );
4589}
4590
4591#[test]
4592fn convert_from_use_with_labels_4() {
4593 let src = r#"
4594pub fn main() {
4595 use a <- wibble(two: 2, three: 3)
4596 todo
4597}
4598
4599fn wibble(one f, two _, three _) {
4600 f(1)
4601}
4602"#;
4603 assert_code_action!(
4604 CONVERT_FROM_USE,
4605 TestProject::for_source(src),
4606 find_position_of("use").to_selection(),
4607 );
4608}
4609
4610#[test]
4611// https://github.com/gleam-lang/gleam/issues/4149
4612fn convert_from_use_with_trailing_comma() {
4613 let src = r#"
4614pub fn main() {
4615 use a, b <- wibble(1, 2,)
4616 todo
4617}
4618
4619fn wibble(n, m, f) {
4620 f(todo, todo)
4621}
4622"#;
4623 assert_code_action!(
4624 CONVERT_FROM_USE,
4625 TestProject::for_source(src),
4626 find_position_of("<-").select_until(find_position_of("wibble")),
4627 );
4628}
4629
4630#[test]
4631fn convert_from_use_with_trailing_comma_2() {
4632 let src = r#"
4633pub fn main() {
4634 use a, b <- wibble(
4635 1,
4636 2,
4637 )
4638 todo
4639}
4640
4641fn wibble(n, m, f) {
4642 f(todo, todo)
4643}
4644"#;
4645 assert_code_action!(
4646 CONVERT_FROM_USE,
4647 TestProject::for_source(src),
4648 find_position_of("<-").select_until(find_position_of("wibble")),
4649 );
4650}
4651
4652#[test]
4653fn convert_from_use_with_trailing_comma_and_label() {
4654 let src = r#"
4655pub fn main() {
4656 use a, b <- wibble(
4657 1,
4658 wibble: 2,
4659 )
4660 todo
4661}
4662
4663fn wibble(n, wibble m, wobble f) {
4664 f(todo, todo)
4665}
4666"#;
4667 assert_code_action!(
4668 CONVERT_FROM_USE,
4669 TestProject::for_source(src),
4670 find_position_of("<-").select_until(find_position_of("wibble")),
4671 );
4672}
4673
4674#[test]
4675fn convert_from_use_multiline_with_no_trailing_comma() {
4676 let src = r#"
4677pub fn main() {
4678 use a, b <- wibble(
4679 1,
4680 2
4681 )
4682 todo
4683}
4684
4685fn wibble(n, m, f) {
4686 f(todo, todo)
4687}
4688"#;
4689 assert_code_action!(
4690 CONVERT_FROM_USE,
4691 TestProject::for_source(src),
4692 find_position_of("<-").select_until(find_position_of("wibble")),
4693 );
4694}
4695
4696#[test]
4697fn turn_call_into_use_with_single_line_body() {
4698 let src = r#"
4699pub fn main() {
4700 wibble(fn(a, b) { todo })
4701}
4702
4703fn wibble(f) {
4704 f(todo, todo)
4705}
4706"#;
4707 assert_code_action!(
4708 CONVERT_TO_USE,
4709 TestProject::for_source(src),
4710 find_position_of("wibble").to_selection(),
4711 );
4712}
4713
4714#[test]
4715fn turn_call_into_use_with_fn_with_no_args() {
4716 let src = r#"
4717pub fn main() {
4718 wibble(fn() { todo })
4719}
4720
4721fn wibble(f) {
4722 f()
4723}
4724"#;
4725 assert_code_action!(
4726 CONVERT_TO_USE,
4727 TestProject::for_source(src),
4728 find_position_of("wibble").to_selection(),
4729 );
4730}
4731
4732#[test]
4733fn turn_call_with_multiple_arguments_into_use() {
4734 let src = r#"
4735pub fn main() {
4736 wibble(1, 2, fn(a) { todo })
4737}
4738
4739fn wibble(m, n, f) {
4740 f(1)
4741}
4742"#;
4743 assert_code_action!(
4744 CONVERT_TO_USE,
4745 TestProject::for_source(src),
4746 find_position_of("todo").to_selection(),
4747 );
4748}
4749
4750#[test]
4751fn turn_call_with_multiline_fn_into_use() {
4752 let src = r#"
4753pub fn main() {
4754 wibble(1, 2, fn(a) {
4755 todo
4756 case todo {
4757 _ -> todo
4758 }
4759 })
4760}
4761
4762fn wibble(m, n, f) {
4763 f(1)
4764}
4765"#;
4766 assert_code_action!(
4767 CONVERT_TO_USE,
4768 TestProject::for_source(src),
4769 find_position_of("1, 2").select_until(find_position_of("fn(a)")),
4770 );
4771}
4772
4773#[test]
4774fn turn_call_with_fn_with_type_annotations_into_use() {
4775 let src = r#"
4776pub fn main() {
4777 wibble(1, 2, fn(a: Int) {
4778 todo
4779 })
4780}
4781
4782fn wibble(m, n, f) {
4783 f(1)
4784}
4785"#;
4786 assert_code_action!(
4787 CONVERT_TO_USE,
4788 TestProject::for_source(src),
4789 find_position_of("wibble").select_until(find_position_of("a: ")),
4790 );
4791}
4792
4793#[test]
4794fn turn_call_into_use_only_works_on_last_call_in_a_block() {
4795 let src = r#"
4796pub fn main() {
4797 wibble(10, 20, fn(a) { todo })
4798 wibble(1, 2, fn(a) { todo })
4799}
4800
4801fn wibble(m, n, f) {
4802 f(1)
4803}
4804"#;
4805 assert_no_code_actions!(
4806 CONVERT_TO_USE,
4807 TestProject::for_source(src),
4808 find_position_of("10").to_selection(),
4809 );
4810}
4811
4812#[test]
4813fn turn_call_into_use_only_works_on_last_call_in_a_block_2() {
4814 let src = r#"
4815pub fn main() {
4816 {
4817 wibble(10, 20, fn(a) { todo })
4818 wibble(1, 2, fn(a) { todo })
4819 }
4820 Nil
4821}
4822
4823fn wibble(m, n, f) {
4824 f(1)
4825}
4826"#;
4827 assert_no_code_actions!(
4828 CONVERT_TO_USE,
4829 TestProject::for_source(src),
4830 find_position_of("10").to_selection(),
4831 );
4832}
4833
4834#[test]
4835fn turn_call_into_use_with_last_function_in_a_block() {
4836 let src = r#"
4837pub fn main() {
4838 {
4839 wibble(10, 20, fn(a) { todo })
4840 wibble(1, 11, fn(a) { todo })
4841 }
4842 Nil
4843}
4844
4845fn wibble(m, n, f) {
4846 f(1)
4847}
4848"#;
4849 assert_code_action!(
4850 CONVERT_TO_USE,
4851 TestProject::for_source(src),
4852 find_position_of("wibble(1,").select_until(find_position_of("11")),
4853 );
4854}
4855
4856#[test]
4857fn turn_call_into_use_starts_from_innermost_function() {
4858 let src = r#"
4859pub fn main() {
4860 wibble(10, 20, fn(a) {
4861 wibble(30, 40, fn(b) {
4862 a + b
4863 })
4864 })
4865}
4866
4867fn wibble(m, n, f) {
4868 f(1)
4869}
4870"#;
4871 assert_code_action!(
4872 CONVERT_TO_USE,
4873 TestProject::for_source(src),
4874 find_position_of("30").select_until(find_position_of("40")),
4875 );
4876}
4877
4878#[test]
4879fn turn_call_into_use_with_another_use_in_the_way() {
4880 let src = r#"
4881pub fn main() {
4882 wibble(10, 20, fn(a) {
4883 use b <- wibble(30, 40)
4884 a + b
4885 })
4886}
4887
4888fn wibble(m, n, f) {
4889 f(1)
4890}
4891"#;
4892 assert_code_action!(
4893 CONVERT_TO_USE,
4894 TestProject::for_source(src),
4895 find_position_of("use").to_selection(),
4896 );
4897}
4898
4899#[test]
4900fn turn_call_into_use_with_module_function() {
4901 let src = r#"
4902import other
4903pub fn main() {
4904 other.wibble(10, 20, fn(a) {
4905 todo
4906 a + b
4907 })
4908}
4909"#;
4910 assert_code_action!(
4911 CONVERT_TO_USE,
4912 TestProject::for_source(src).add_module("other", "pub fn wibble(n, m, f) { todo }"),
4913 find_position_of("wibble").to_selection(),
4914 );
4915}
4916
4917#[test]
4918// https://github.com/gleam-lang/gleam/issues/4498
4919fn turn_call_into_use_with_out_of_order_arguments() {
4920 assert_code_action!(
4921 CONVERT_TO_USE,
4922 r#"
4923pub fn main() {
4924 fold(0, over: [], with: fn (a, b) { todo })
4925}
4926
4927fn fold(over list: List(a), from acc: acc, with fun: fn(acc, a) -> acc) -> acc {
4928 todo
4929}
4930"#,
4931 find_position_of("fold").to_selection(),
4932 );
4933}
4934
4935#[test]
4936fn inexhaustive_let_result_to_case() {
4937 assert_code_action!(
4938 CONVERT_TO_CASE,
4939 "pub fn main(result) {
4940 let Ok(value) = result
4941}",
4942 find_position_of("let").select_until(find_position_of("=")),
4943 );
4944}
4945
4946#[test]
4947fn inexhaustive_let_to_case_indented() {
4948 assert_code_action!(
4949 CONVERT_TO_CASE,
4950 "pub fn main(result) {
4951 {
4952 let Ok(value) = result
4953 }
4954}",
4955 find_position_of("let").select_until(find_position_of("=")),
4956 );
4957}
4958
4959#[test]
4960fn inexhaustive_let_to_case_multi_variables() {
4961 assert_code_action!(
4962 CONVERT_TO_CASE,
4963 "pub fn main() {
4964 let [var1, var2, _var3, var4] = [1, 2, 3, 4]
4965}",
4966 find_position_of("let").select_until(find_position_of("=")),
4967 );
4968}
4969
4970#[test]
4971fn inexhaustive_let_to_case_discard() {
4972 assert_code_action!(
4973 CONVERT_TO_CASE,
4974 "pub fn main() {
4975 let [_elem] = [6]
4976}",
4977 find_position_of("let").select_until(find_position_of("=")),
4978 );
4979}
4980
4981#[test]
4982fn inexhaustive_let_to_case_no_variables() {
4983 assert_code_action!(
4984 CONVERT_TO_CASE,
4985 "pub fn main() {
4986 let [] = []
4987}",
4988 find_position_of("let").select_until(find_position_of("=")),
4989 );
4990}
4991
4992#[test]
4993fn inexhaustive_let_alias_to_case() {
4994 assert_code_action!(
4995 CONVERT_TO_CASE,
4996 "pub fn main() {
4997 let 10 as ten = 10
4998}",
4999 find_position_of("let").select_until(find_position_of("=")),
5000 );
5001}
5002
5003#[test]
5004fn inexhaustive_let_tuple_to_case() {
5005 assert_code_action!(
5006 CONVERT_TO_CASE,
5007 "pub fn main() {
5008 let #(first, 10, third) = #(5, 10, 15)
5009}
5010",
5011 find_position_of("let").select_until(find_position_of("=")),
5012 );
5013}
5014
5015#[test]
5016fn inexhaustive_let_bit_array_to_case() {
5017 assert_code_action!(
5018 CONVERT_TO_CASE,
5019 "pub fn main() {
5020 let <<bits1, bits2>> = <<73, 98>>
5021}",
5022 find_position_of("let").select_until(find_position_of("=")),
5023 );
5024}
5025
5026#[test]
5027fn inexhaustive_let_string_prefix_to_case() {
5028 assert_code_action!(
5029 CONVERT_TO_CASE,
5030 r#"pub fn main() {
5031 let "_" <> thing = "_Hello"
5032}"#,
5033 find_position_of("let").select_until(find_position_of("=")),
5034 );
5035}
5036
5037#[test]
5038fn inexhaustive_let_string_prefix_pattern_alias_to_case() {
5039 assert_code_action!(
5040 CONVERT_TO_CASE,
5041 r#"pub fn main() {
5042 let "123" as one_two_three <> rest = "123456"
5043}"#,
5044 find_position_of("let").select_until(find_position_of("=")),
5045 );
5046}
5047
5048#[test]
5049fn inner_inexhaustive_let_to_case() {
5050 assert_code_action!(
5051 CONVERT_TO_CASE,
5052 r#"pub fn main(result) {
5053 let [wibble] = {
5054 let Ok(wobble) = {
5055 result
5056 }
5057 [wobble]
5058 }
5059}"#,
5060 find_position_of("let Ok").select_until(find_position_of(") =")),
5061 );
5062}
5063
5064#[test]
5065fn outer_inexhaustive_let_to_case() {
5066 assert_code_action!(
5067 CONVERT_TO_CASE,
5068 r#"pub fn main(result) {
5069 let [wibble] = {
5070 let Ok(wobble) = {
5071 result
5072 }
5073 [wobble]
5074 }
5075}"#,
5076 find_position_of("let [").select_until(find_position_of("] =")),
5077 );
5078}
5079
5080#[test]
5081fn no_code_action_for_exhaustive_let_to_case() {
5082 assert_no_code_actions!(
5083 CONVERT_TO_CASE,
5084 r#"pub fn first(pair) {
5085 let #(first, second) = pair
5086 first
5087}"#,
5088 find_position_of("let").select_until(find_position_of("=")),
5089 );
5090}
5091
5092#[test]
5093fn extract_variable() {
5094 assert_code_action!(
5095 EXTRACT_VARIABLE,
5096 r#"pub fn main() {
5097 list.map([1, 2, 3], int.add(1, _))
5098}"#,
5099 find_position_of("[1").select_until(find_position_of("2"))
5100 );
5101}
5102
5103#[test]
5104fn extract_variable_does_not_extract_a_variable() {
5105 assert_no_code_actions!(
5106 EXTRACT_VARIABLE,
5107 r#"pub fn main() {
5108 let z = 1
5109 let a = [1, 2, z]
5110}"#,
5111 find_position_of("z").nth_occurrence(2).to_selection()
5112 );
5113}
5114
5115#[test]
5116fn extract_variable_does_not_extract_top_level_statement() {
5117 assert_no_code_actions!(
5118 EXTRACT_VARIABLE,
5119 r#"pub fn main() {
5120 let wibble = 1
5121}"#,
5122 find_position_of("1").to_selection()
5123 );
5124}
5125
5126#[test]
5127fn extract_variable_does_not_extract_top_level_statement_inside_block() {
5128 assert_no_code_actions!(
5129 EXTRACT_VARIABLE,
5130 r#"pub fn main() {
5131 let x = {
5132 let y = "y"
5133 let w = "w" <> y
5134 w
5135 }
5136}"#,
5137 find_position_of("y").nth_occurrence(2).to_selection()
5138 );
5139}
5140
5141#[test]
5142fn extract_variable_does_not_extract_top_level_statement_inside_use() {
5143 assert_no_code_actions!(
5144 EXTRACT_VARIABLE,
5145 "
5146pub fn main() {
5147 use x <- try(Ok(1))
5148 let y = 2
5149 Ok(y + x)
5150}
5151pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo }
5152",
5153 find_position_of("2").to_selection()
5154 );
5155}
5156
5157#[test]
5158fn extract_variable_does_not_extract_use() {
5159 assert_no_code_actions!(
5160 EXTRACT_VARIABLE,
5161 "
5162pub fn main() {
5163 use x <- try(Ok(1))
5164 Ok(x)
5165}
5166pub fn try(result: Result(a, e), fun: fn(a) -> Result(b, e)) -> Result(b, e) { todo }
5167",
5168 find_position_of("use").to_selection()
5169 );
5170}
5171
5172#[test]
5173fn extract_variable_does_not_extract_panic() {
5174 assert_no_code_actions!(
5175 EXTRACT_VARIABLE,
5176 r#"pub fn main() {
5177 let x = 1
5178 panic
5179}"#,
5180 find_position_of("panic").to_selection()
5181 );
5182}
5183
5184#[test]
5185fn extract_variable_does_not_extract_echo() {
5186 assert_no_code_actions!(
5187 EXTRACT_VARIABLE,
5188 r#"pub fn main() {
5189 let x = 1
5190 echo x
5191}"#,
5192 find_position_of("echo").to_selection()
5193 );
5194}
5195
5196#[test]
5197fn extract_variable_does_not_extract_assignment() {
5198 assert_no_code_actions!(
5199 EXTRACT_VARIABLE,
5200 r#"pub fn main() {
5201 let x = 1
5202}"#,
5203 find_position_of("x").to_selection()
5204 );
5205}
5206
5207#[test]
5208fn extract_variable_does_not_extract_record_variable_in_record_update() {
5209 assert_no_code_actions!(
5210 EXTRACT_VARIABLE,
5211 r#"
5212type Wibble { Wibble(one: Int, two: Int) }
5213
5214pub fn main() {
5215 let wibble = todo
5216 Wibble(..wibble, one: 1)
5217}"#,
5218 find_position_of("wibble").nth_occurrence(2).to_selection()
5219 );
5220}
5221
5222#[test]
5223fn extract_variable_from_arg_in_pipelined_call() {
5224 assert_code_action!(
5225 EXTRACT_VARIABLE,
5226 "
5227pub fn main() {
5228 let adder = add
5229 let x = [4, 5, 6] |> map2([1, 2, 3], adder)
5230 x
5231}
5232pub fn map2(list1: List(a), list2: List(b), fun: fn(a, b) -> c) -> List(c) { todo }
5233pub fn add(a: Int, b: Int) -> Int { todo }
5234",
5235 find_position_of("[1").to_selection()
5236 );
5237}
5238
5239#[test]
5240fn extract_variable_from_arg_in_pipelined_call_to_capture() {
5241 assert_code_action!(
5242 EXTRACT_VARIABLE,
5243 "
5244pub fn main() {
5245 let adder = add
5246 let x = adder |> reduce([1, 2, 3], _)
5247 x
5248}
5249pub fn reduce(list: List(a), fun: fn(a, a) -> a) -> Result(a, Nil) { todo }
5250pub fn add(a: Int, b: Int) -> Int { todo }
5251",
5252 find_position_of("[1").to_selection()
5253 );
5254}
5255
5256#[test]
5257fn extract_variable_from_arg_in_pipelined_call_of_function_to_capture() {
5258 assert_code_action!(
5259 EXTRACT_VARIABLE,
5260 "
5261pub fn main() {
5262 fn(total, item) { total + item }
5263 |> fold(with: _, from: 0, over: [1, 2, 3])
5264}
5265pub fn fold(over l: List(a), from i: t, with f: fn(t, a) -> t) -> acc { todo }
5266",
5267 find_position_of("fold").to_selection()
5268 );
5269}
5270
5271#[test]
5272fn extract_variable_from_arg_in_nested_function_called_in_pipeline() {
5273 assert_code_action!(
5274 EXTRACT_VARIABLE,
5275 "
5276pub fn main() {
5277 let result =
5278 [1, 2, 3]
5279 |> map(add(_, 1))
5280 |> map(subtract(_, 9))
5281
5282 result
5283}
5284pub fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }
5285pub fn add(a: Int, b: Int) -> Int { todo }
5286pub fn subtract(a: Int, b: Int) -> Int { todo }
5287",
5288 find_position_of("9").to_selection()
5289 );
5290}
5291
5292#[test]
5293fn extract_variable_does_not_extract_an_entire_pipeline_step() {
5294 assert_no_code_actions!(
5295 EXTRACT_VARIABLE,
5296 "
5297pub fn main() {
5298 [1, 2, 3]
5299 |> map(todo)
5300 |> map(todo)
5301}
5302
5303fn map(list, fun) { todo }
5304",
5305 find_position_of("map").to_selection()
5306 );
5307}
5308
5309#[test]
5310fn extract_variable_does_not_extract_the_last_pipeline_step() {
5311 assert_no_code_actions!(
5312 EXTRACT_VARIABLE,
5313 r#"pub fn main() {
5314 [1, 2, 3]
5315 |> map(todo)
5316 |> map(todo)
5317}
5318
5319fn map(list, fun) { todo }
5320"#,
5321 find_position_of("map").to_selection()
5322 );
5323}
5324
5325#[test]
5326fn extract_variable_2() {
5327 assert_code_action!(
5328 EXTRACT_VARIABLE,
5329 "
5330pub fn main() {
5331 map([1, 2, 3], add(1, _))
5332}
5333pub fn add(n, m) { todo }
5334pub fn map(l, f) { todo }
5335",
5336 find_position_of("add").to_selection()
5337 );
5338}
5339
5340#[test]
5341fn extract_variable_from_capture_arguments() {
5342 assert_no_code_actions!(
5343 EXTRACT_VARIABLE,
5344 r#"pub fn main() {
5345 int.add(1, _)
5346}"#,
5347 find_position_of("_").to_selection()
5348 );
5349}
5350
5351#[test]
5352fn extract_variable_from_capture_arguments_2() {
5353 assert_code_action!(
5354 EXTRACT_VARIABLE,
5355 r#"pub fn main() {
5356 int.add(11, _)
5357}"#,
5358 find_position_of("11").to_selection()
5359 );
5360}
5361
5362#[test]
5363fn extract_variable_3() {
5364 assert_code_action!(
5365 EXTRACT_VARIABLE,
5366 r#"pub fn main() {
5367 list.map([1, 2, 3], todo, todo)
5368}"#,
5369 find_position_of("todo")
5370 .nth_occurrence(2)
5371 .select_until(find_position_of("todo)").under_last_char())
5372 );
5373}
5374
5375#[test]
5376fn extract_variable_inside_multiline_function_call() {
5377 assert_code_action!(
5378 EXTRACT_VARIABLE,
5379 r#"pub fn main() {
5380 list.map(
5381 [1, 2, 3],
5382 int.add(1, _),
5383 )
5384}"#,
5385 find_position_of("[1").to_selection()
5386 );
5387}
5388
5389#[test]
5390fn extract_variable_in_case_branch() {
5391 assert_code_action!(
5392 EXTRACT_VARIABLE,
5393 r#"pub fn main() {
5394 case wibble {
5395 _ -> [1, 2, 3]
5396 }
5397}"#,
5398 find_position_of("[1").to_selection()
5399 );
5400}
5401
5402#[test]
5403fn extract_variable_in_multiline_case_subject_branch() {
5404 assert_code_action!(
5405 EXTRACT_VARIABLE,
5406 r#"pub fn main() {
5407 case
5408 list.map(
5409 [1, 2, 3],
5410 int.add(1, _)
5411 )
5412 {
5413 _ -> todo
5414 }
5415}"#,
5416 find_position_of("[1").to_selection()
5417 );
5418}
5419
5420#[test]
5421fn extract_variable_in_case_branch_using_var() {
5422 assert_code_action!(
5423 EXTRACT_VARIABLE,
5424 r#"pub fn main() {
5425 case todo {
5426 Ok(value) -> 2 * value + 1
5427 Error(_) -> panic
5428 }
5429}"#,
5430 find_position_of("2").select_until(find_position_of("value").nth_occurrence(2))
5431 );
5432}
5433
5434#[test]
5435fn extract_variable_in_case_branch_from_second_arg() {
5436 assert_code_action!(
5437 EXTRACT_VARIABLE,
5438 r#"pub fn main() {
5439 case todo {
5440 Ok(_) -> #(Ok(1), Error("s"))
5441 Error(_) -> panic
5442 }
5443}"#,
5444 find_position_of("E").to_selection()
5445 );
5446}
5447
5448#[test]
5449fn extract_variable_in_use() {
5450 assert_code_action!(
5451 EXTRACT_VARIABLE,
5452 r#"pub fn main() {
5453 use <- wibble([1, 2, 3])
5454 todo
5455}"#,
5456 find_position_of("[1").to_selection()
5457 );
5458}
5459
5460#[test]
5461fn extract_variable_inside_use_body() {
5462 assert_code_action!(
5463 EXTRACT_VARIABLE,
5464 r#"pub fn main() {
5465 use <- wibble(todo)
5466 list.map([1, 2, 3], int.add(1, _))
5467 todo
5468}"#,
5469 find_position_of("[1").to_selection()
5470 );
5471}
5472
5473#[test]
5474fn extract_variable_in_multiline_use() {
5475 assert_code_action!(
5476 EXTRACT_VARIABLE,
5477 r#"pub fn main() {
5478 use <- wibble(
5479 [1, 2, 3]
5480 )
5481 todo
5482}"#,
5483 find_position_of("[1").to_selection()
5484 );
5485}
5486
5487#[test]
5488fn extract_variable_after_nested_anonymous_function() {
5489 assert_code_action!(
5490 EXTRACT_VARIABLE,
5491 r#"pub fn main() {
5492 let f = fn() {
5493 let x = 1 + 2
5494 let ff = fn() {
5495 let y = x + 3
5496 let z = y + x
5497 z
5498 }
5499 let z = x * 4
5500 z
5501 }
5502 let y = 5 + 6
5503 f()
5504}"#,
5505 find_position_of("6").to_selection()
5506 );
5507}
5508
5509#[test]
5510fn extract_variable_in_nested_anonymous_function() {
5511 assert_code_action!(
5512 EXTRACT_VARIABLE,
5513 r#"pub fn main() {
5514 let f = fn() {
5515 let x = 1 + 2
5516 let ff = fn() {
5517 let y = x + 3
5518 let z = y + x
5519 z
5520 }
5521 let z = x * 4
5522 z
5523 }
5524 let y = 5 + 6
5525 f()
5526}"#,
5527 find_position_of("4").to_selection()
5528 );
5529}
5530
5531#[test]
5532fn extract_variable_in_double_nested_anonymous_function() {
5533 assert_code_action!(
5534 EXTRACT_VARIABLE,
5535 r#"pub fn main() {
5536 let f = fn() {
5537 let x = 1 + 2
5538 let ff = fn() {
5539 let y = x + 3
5540 let z = y + x
5541 z
5542 }
5543 let z = x * 4
5544 z
5545 }
5546 let y = 5 + 6
5547 f()
5548}"#,
5549 find_position_of("3").to_selection()
5550 );
5551}
5552
5553#[test]
5554fn extract_variable_in_block() {
5555 assert_code_action!(
5556 EXTRACT_VARIABLE,
5557 r#"pub fn main() {
5558 {
5559 todo
5560 wibble([1, 2, 3])
5561 todo
5562 }
5563}"#,
5564 find_position_of("2").select_until(find_position_of("3"))
5565 );
5566}
5567
5568#[test]
5569fn extract_constant_from_call_argument_with_bit_array() {
5570 assert_code_action!(
5571 EXTRACT_CONSTANT,
5572 r#"import gleam/io
5573
5574pub fn main() {
5575 io.debug(<<3:size(8)>>)
5576}"#,
5577 find_position_of("<").select_until(find_position_of("<").nth_occurrence(2))
5578 );
5579}
5580
5581#[test]
5582fn extract_constant_from_call_argument_with_float() {
5583 assert_code_action!(
5584 EXTRACT_CONSTANT,
5585 r#"import gleam/float
5586
5587pub fn main() {
5588 float.ceiling(1.9998)
5589}"#,
5590 find_position_of("1").select_until(find_position_of("8"))
5591 );
5592}
5593
5594#[test]
5595fn extract_constant_from_call_argument_with_int() {
5596 assert_code_action!(
5597 EXTRACT_CONSTANT,
5598 r#"import gleam/list
5599
5600pub fn main() {
5601 list.sample([4, 5, 6], 2)
5602}"#,
5603 find_position_of("2").to_selection()
5604 );
5605}
5606
5607#[test]
5608fn extract_constant_from_call_argument_with_list() {
5609 assert_code_action!(
5610 EXTRACT_CONSTANT,
5611 r#"import gleam/io
5612
5613pub fn main() {
5614 io.debug(["constant", "another constant"])
5615}"#,
5616 find_position_of("[").to_selection()
5617 );
5618}
5619
5620#[test]
5621fn extract_constant_from_call_argument_with_nested_inside() {
5622 assert_code_action!(
5623 EXTRACT_CONSTANT,
5624 r#"import gleam/list
5625
5626pub fn main() {
5627 list.unzip([#(1, 2), #(3, 4)])
5628}"#,
5629 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3))
5630 );
5631}
5632
5633#[test]
5634fn extract_constant_from_call_argument_with_nested_outside() {
5635 assert_code_action!(
5636 EXTRACT_CONSTANT,
5637 r#"import gleam/list
5638
5639pub fn main() {
5640 list.unzip([#(1, 2), #(3, 4)])
5641}"#,
5642 find_position_of("[").to_selection()
5643 );
5644}
5645
5646#[test]
5647fn extract_constant_from_call_argument_with_string() {
5648 assert_code_action!(
5649 EXTRACT_CONSTANT,
5650 r#"import gleam/io
5651
5652pub fn main() {
5653 io.print("constant")
5654}"#,
5655 find_position_of("\"").select_until(find_position_of("\""))
5656 );
5657}
5658
5659#[test]
5660fn extract_constant_from_call_argument_with_tuple() {
5661 assert_code_action!(
5662 EXTRACT_CONSTANT,
5663 r#"import gleam/io
5664
5665pub fn main() {
5666 io.debug(#(1, 2, 3))
5667}"#,
5668 find_position_of("#").select_until(find_position_of("(").nth_occurrence(3))
5669 );
5670}
5671
5672#[test]
5673fn extract_constant_from_declaration_of_float() {
5674 assert_code_action!(
5675 EXTRACT_CONSTANT,
5676 r#"pub fn main() {
5677 let c = 3.1415
5678}"#,
5679 find_position_of("3").select_until(find_position_of("5"))
5680 );
5681}
5682
5683#[test]
5684fn extract_constant_from_whole_declaration_of_float() {
5685 assert_code_action!(
5686 EXTRACT_CONSTANT,
5687 r#"import gleam/io
5688
5689pub fn main() {
5690 let c = 3.1415
5691 io.debug(c)
5692}"#,
5693 find_position_of("l")
5694 .nth_occurrence(2)
5695 .select_until(find_position_of("c"))
5696 );
5697}
5698
5699#[test]
5700fn extract_constant_from_declaration_of_bit_array() {
5701 assert_code_action!(
5702 EXTRACT_CONSTANT,
5703 r#"pub fn main() {
5704 let b = <<"arr":utf32>>
5705}"#,
5706 find_position_of("u")
5707 .nth_occurrence(2)
5708 .select_until(find_position_of(">").nth_occurrence(2))
5709 );
5710}
5711
5712#[test]
5713fn extract_constant_from_whole_declaration_of_bit_array() {
5714 assert_code_action!(
5715 EXTRACT_CONSTANT,
5716 r#"import gleam/io
5717
5718const n = 24
5719
5720pub fn main() {
5721 let bits = <<8080:size(n)>>
5722 bits
5723}"#,
5724 find_position_of("l")
5725 .nth_occurrence(2)
5726 .select_until(find_position_of("s").nth_occurrence(2))
5727 );
5728}
5729
5730#[test]
5731fn extract_constant_from_declaration_of_bin_op() {
5732 assert_code_action!(
5733 EXTRACT_CONSTANT,
5734 r#"pub fn main() {
5735 let twelve = "1" <> "2"
5736}"#,
5737 find_position_of("<").to_selection()
5738 );
5739}
5740
5741#[test]
5742fn extract_constant_from_whole_declaration_of_bin_op() {
5743 assert_code_action!(
5744 EXTRACT_CONSTANT,
5745 r#"import gleam/io
5746
5747pub fn main() {
5748 let twelve = "1" <> "2"
5749 io.print(twelve)
5750}"#,
5751 find_position_of("l")
5752 .nth_occurrence(2)
5753 .select_until(find_position_of("e").nth_occurrence(4))
5754 );
5755}
5756
5757#[test]
5758fn extract_constant_from_declaration_of_int() {
5759 assert_code_action!(
5760 EXTRACT_CONSTANT,
5761 r#"pub fn main() {
5762 let c = 125
5763}"#,
5764 find_position_of("1").select_until(find_position_of("5"))
5765 );
5766}
5767
5768#[test]
5769fn extract_constant_from_whole_declaration_of_int() {
5770 assert_code_action!(
5771 EXTRACT_CONSTANT,
5772 r#"import gleam/io
5773
5774pub fn main() {
5775 let c = 125
5776 io.debug(c)
5777}"#,
5778 find_position_of("l")
5779 .nth_occurrence(2)
5780 .select_until(find_position_of("c"))
5781 );
5782}
5783
5784#[test]
5785fn extract_constant_from_declaration_of_list() {
5786 assert_code_action!(
5787 EXTRACT_CONSTANT,
5788 r#"pub fn main() {
5789 let c = [3.1415, 0.33333333]
5790}"#,
5791 find_position_of("[").to_selection()
5792 );
5793}
5794
5795#[test]
5796fn extract_constant_from_whole_declaration_of_list() {
5797 assert_code_action!(
5798 EXTRACT_CONSTANT,
5799 r#"import gleam/io
5800
5801pub fn main() {
5802 let c = [3.1415, 0.33333333]
5803 io.debug(c)
5804}"#,
5805 find_position_of("l")
5806 .nth_occurrence(2)
5807 .select_until(find_position_of("c"))
5808 );
5809}
5810
5811#[test]
5812fn extract_constant_from_declaration_of_nested_inside() {
5813 assert_code_action!(
5814 EXTRACT_CONSTANT,
5815 r#"pub fn main() {
5816 let c = #([1, 2, 3], [3, 2, 1])
5817}"#,
5818 find_position_of("[").to_selection()
5819 );
5820}
5821
5822#[test]
5823fn extract_constant_from_declaration_of_nested_outside() {
5824 assert_code_action!(
5825 EXTRACT_CONSTANT,
5826 r#"pub fn main() {
5827 let c = #([1, 2, 3], [3, 2, 1])
5828}"#,
5829 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2))
5830 );
5831}
5832
5833#[test]
5834fn extract_constant_from_whole_declaration_of_nested() {
5835 assert_code_action!(
5836 EXTRACT_CONSTANT,
5837 r#"import gleam/io
5838
5839pub fn main() {
5840 let c = #([1, 2, 3], [3, 2, 1])
5841 io.debug(c)
5842}"#,
5843 find_position_of("l")
5844 .nth_occurrence(2)
5845 .select_until(find_position_of("c"))
5846 );
5847}
5848
5849#[test]
5850fn extract_constant_from_declaration_of_string() {
5851 assert_code_action!(
5852 EXTRACT_CONSTANT,
5853 r#"pub fn main() {
5854 let c = "constant"
5855}"#,
5856 find_position_of("\"").select_until(find_position_of("\""))
5857 );
5858}
5859
5860#[test]
5861fn extract_constant_from_whole_declaration_of_string() {
5862 assert_code_action!(
5863 EXTRACT_CONSTANT,
5864 r#"import gleam/io
5865
5866pub fn main() {
5867 let c = "constant"
5868 io.debug(c)
5869}"#,
5870 find_position_of("l")
5871 .nth_occurrence(2)
5872 .select_until(find_position_of("c"))
5873 );
5874}
5875
5876#[test]
5877fn extract_constant_from_declaration_of_tuple() {
5878 assert_code_action!(
5879 EXTRACT_CONSTANT,
5880 r#"pub fn main() {
5881 let #(one, two, three) = #("one", "two", "three")
5882}"#,
5883 find_position_of("#")
5884 .nth_occurrence(2)
5885 .select_until(find_position_of("(").nth_occurrence(3))
5886 );
5887}
5888
5889#[test]
5890fn extract_constant_from_whole_declaration_of_tuple() {
5891 assert_code_action!(
5892 EXTRACT_CONSTANT,
5893 r#"import gleam/io
5894
5895pub fn main() {
5896 let c = #("one", "two", "three")
5897 io.debug(c)
5898}"#,
5899 find_position_of("l")
5900 .nth_occurrence(2)
5901 .select_until(find_position_of("c"))
5902 );
5903}
5904
5905#[test]
5906fn extract_constant_from_literal_within_list() {
5907 assert_code_action!(
5908 EXTRACT_CONSTANT,
5909 r#"pub fn main() {
5910 let c = ["constant", todo]
5911}"#,
5912 find_position_of("\"").select_until(find_position_of("\""))
5913 );
5914}
5915
5916#[test]
5917fn extract_constant_from_list_containing_constant() {
5918 assert_code_action!(
5919 EXTRACT_CONSTANT,
5920 r#"const something = "something"
5921
5922pub fn main() {
5923 let c = ["constant", something]
5924}"#,
5925 find_position_of("[").to_selection()
5926 );
5927}
5928
5929#[test]
5930fn extract_constant_from_literal_within_tuple() {
5931 assert_code_action!(
5932 EXTRACT_CONSTANT,
5933 r#"pub fn main() {
5934 let c = #(0.333334, todo)
5935}"#,
5936 find_position_of("0").select_until(find_position_of("4"))
5937 );
5938}
5939
5940#[test]
5941fn extract_constant_from_tuple_containing_constant() {
5942 assert_code_action!(
5943 EXTRACT_CONSTANT,
5944 r#"const something = "something"
5945
5946pub fn main() {
5947 let c = #(0.333334, something)
5948}"#,
5949 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2))
5950 );
5951}
5952
5953#[test]
5954fn extract_constant_from_nested_inside_in_expr() {
5955 assert_code_action!(
5956 EXTRACT_CONSTANT,
5957 r#"pub fn main() {
5958 [#("a", 0), #("b", 1), #("a", 2)]
5959 |> key_filter("a")
5960}"#,
5961 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2))
5962 );
5963}
5964
5965#[test]
5966fn extract_constant_from_nested_outside_in_expr() {
5967 assert_code_action!(
5968 EXTRACT_CONSTANT,
5969 r#"pub fn main() {
5970 [#("a", 0), #("b", 1), #("a", 2)]
5971 |> key_filter("a")
5972}"#,
5973 find_position_of("[").to_selection()
5974 );
5975}
5976
5977#[test]
5978fn extract_constant_from_return_of_float() {
5979 assert_code_action!(
5980 EXTRACT_CONSTANT,
5981 r#"pub fn main() {
5982 0.25
5983}"#,
5984 find_position_of("0").select_until(find_position_of("5"))
5985 );
5986}
5987
5988#[test]
5989fn extract_constant_from_return_of_int() {
5990 assert_code_action!(
5991 EXTRACT_CONSTANT,
5992 r#"pub fn main() {
5993 100
5994}"#,
5995 find_position_of("1").select_until(find_position_of("0").nth_occurrence(2))
5996 );
5997}
5998
5999#[test]
6000fn extract_constant_from_return_of_list() {
6001 assert_code_action!(
6002 EXTRACT_CONSTANT,
6003 r#"pub fn main() {
6004 [1, 2, 3, 4]
6005}"#,
6006 find_position_of("[").to_selection()
6007 );
6008}
6009
6010#[test]
6011fn extract_constant_from_return_of_nested_outside() {
6012 assert_code_action!(
6013 EXTRACT_CONSTANT,
6014 r#"pub fn main() {
6015 [#(0.25, 0.75), #(0.5, 1.5)]
6016}"#,
6017 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2))
6018 );
6019}
6020
6021#[test]
6022fn extract_constant_from_return_of_string() {
6023 assert_code_action!(
6024 EXTRACT_CONSTANT,
6025 r#"pub fn main() {
6026 "constant"
6027}"#,
6028 find_position_of("\"").select_until(find_position_of("\""))
6029 );
6030}
6031
6032#[test]
6033fn extract_constant_from_return_of_tuple() {
6034 assert_code_action!(
6035 EXTRACT_CONSTANT,
6036 r#"pub fn main() {
6037 #(0.25, 0.75)
6038}"#,
6039 find_position_of("#").select_until(find_position_of("(").nth_occurrence(2))
6040 );
6041}
6042
6043#[test]
6044fn extract_constant_from_taken_name_by_function() {
6045 assert_code_action!(
6046 EXTRACT_CONSTANT,
6047 r#"fn floats() {
6048 [1.0, 2.0]
6049}
6050
6051pub fn main() {
6052 [0.25, 0.75]
6053}"#,
6054 find_position_of("[").nth_occurrence(2).to_selection()
6055 );
6056}
6057
6058#[test]
6059fn extract_constant_from_taken_name_by_constant() {
6060 assert_code_action!(
6061 EXTRACT_CONSTANT,
6062 r#"const ints = [1, 2]
6063
6064pub fn main() {
6065 [5, 50]
6066}"#,
6067 find_position_of("[").nth_occurrence(2).to_selection()
6068 );
6069}
6070
6071#[test]
6072fn extract_constant_in_correct_position_1() {
6073 assert_code_action!(
6074 EXTRACT_CONSTANT,
6075 r#"
6076fn first() {
6077 1
6078}
6079
6080fn second() {
6081 2
6082}
6083
6084fn third() {
6085 3
6086}
6087"#,
6088 find_position_of("1").to_selection()
6089 );
6090}
6091
6092#[test]
6093fn extract_constant_in_correct_position_2() {
6094 assert_code_action!(
6095 EXTRACT_CONSTANT,
6096 r#"
6097fn first() {
6098 1
6099}
6100
6101fn second() {
6102 2
6103}
6104
6105fn third() {
6106 3
6107}
6108"#,
6109 find_position_of("2").to_selection()
6110 );
6111}
6112
6113#[test]
6114fn extract_constant_in_correct_position_3() {
6115 assert_code_action!(
6116 EXTRACT_CONSTANT,
6117 r#"
6118fn first() {
6119 1
6120}
6121
6122fn second() {
6123 2
6124}
6125
6126fn third() {
6127 3
6128}
6129"#,
6130 find_position_of("3").to_selection()
6131 );
6132}
6133
6134#[test]
6135fn extract_constant_declaration_with_proper_indentation() {
6136 assert_code_action!(
6137 EXTRACT_CONSTANT,
6138 r#"
6139pub fn main() {
6140 let fahrenheit = {
6141 let degrees = 64
6142 degrees
6143 }
6144 fahrenheit
6145}
6146"#,
6147 find_position_of("l")
6148 .nth_occurrence(2)
6149 .select_until(find_position_of("s"))
6150 );
6151}
6152
6153#[test]
6154fn extract_constant_from_nil() {
6155 assert_code_action!(
6156 EXTRACT_CONSTANT,
6157 r#"pub fn main() {
6158 let x = Nil
6159 x
6160}
6161"#,
6162 find_position_of("l").select_until(find_position_of("x"))
6163 );
6164}
6165
6166#[test]
6167fn extract_constant_from_non_record_variant_1() {
6168 assert_code_action!(
6169 EXTRACT_CONSTANT,
6170 r#"pub type Auth {
6171 Verified
6172 Unverified
6173}
6174
6175pub fn main() {
6176 let a = Unverified
6177 let a = verify(something, a)
6178
6179 a
6180}
6181"#,
6182 find_position_of("U")
6183 .nth_occurrence(2)
6184 .select_until(find_position_of("d").nth_occurrence(3))
6185 );
6186}
6187
6188#[test]
6189fn extract_constant_from_non_record_variant_2() {
6190 assert_code_action!(
6191 EXTRACT_CONSTANT,
6192 r#"pub type Auth {
6193 Verified
6194 Unverified
6195}
6196
6197pub fn main() {
6198 let a = verify(something, Unverified)
6199
6200 a
6201}
6202"#,
6203 find_position_of("U")
6204 .nth_occurrence(2)
6205 .select_until(find_position_of("d").nth_occurrence(3))
6206 );
6207}
6208
6209#[test]
6210fn extract_constant_from_record_variant_1() {
6211 assert_code_action!(
6212 EXTRACT_CONSTANT,
6213 r#"pub type Auth {
6214 Verified(String)
6215 Unverified
6216}
6217
6218pub fn main() {
6219 let u = Verified("User")
6220 let v = verify(something, u)
6221
6222 v
6223}"#,
6224 find_position_of("l").select_until(find_position_of("u").nth_occurrence(4))
6225 );
6226}
6227
6228#[test]
6229fn extract_constant_from_record_variant_2() {
6230 assert_code_action!(
6231 EXTRACT_CONSTANT,
6232 r#"pub type Auth {
6233 Verified(Int)
6234 Unverified
6235}
6236
6237const auth = True
6238
6239const id = 1234
6240
6241pub fn main() {
6242 let v = verify(auth, Verified(id))
6243
6244 v
6245}"#,
6246 find_position_of("V")
6247 .nth_occurrence(2)
6248 .select_until(find_position_of("(").nth_occurrence(4))
6249 );
6250}
6251
6252#[test]
6253fn extract_constant_from_inside_block() {
6254 assert_code_action!(
6255 EXTRACT_CONSTANT,
6256 r#"pub fn main() {
6257 let fahrenheit = {
6258 let degrees = 64 + 32
6259 degrees
6260 }
6261}"#,
6262 find_position_of("32").to_selection()
6263 );
6264}
6265
6266#[test]
6267fn extract_constant_from_inside_case() {
6268 assert_code_action!(
6269 EXTRACT_CONSTANT,
6270 r#"pub fn main(result) {
6271 case result {
6272 Ok(value) -> value + 1
6273 Error(_) -> panic
6274 }
6275}"#,
6276 find_position_of("1").to_selection()
6277 );
6278}
6279
6280#[test]
6281fn extract_constant_from_inside_use_1() {
6282 assert_code_action!(
6283 EXTRACT_CONSTANT,
6284 r#"pub fn main() {
6285 use x <- result.try(todo)
6286 Ok(123)
6287}"#,
6288 find_position_of("Ok").to_selection()
6289 );
6290}
6291
6292#[test]
6293fn extract_constant_from_inside_use_2() {
6294 assert_code_action!(
6295 EXTRACT_CONSTANT,
6296 r#"const number = 123
6297
6298pub fn main() {
6299 use x <- result.try(todo)
6300 Ok(number)
6301}"#,
6302 find_position_of("Ok").to_selection()
6303 );
6304}
6305
6306#[test]
6307fn do_not_extract_constant_from_pattern() {
6308 assert_no_code_actions!(
6309 EXTRACT_CONSTANT,
6310 r#"pub fn main() {
6311 let #(one, two) = #(1, 2)
6312 one
6313}"#,
6314 find_position_of("l").select_until(find_position_of("(").nth_occurrence(2))
6315 );
6316}
6317
6318#[test]
6319fn do_not_extract_constant_from_fn_call_1() {
6320 assert_no_code_actions!(
6321 EXTRACT_CONSTANT,
6322 r#"import gleam/io
6323
6324pub fn main() {
6325 io.print("constant")
6326}"#,
6327 find_position_of("p")
6328 .nth_occurrence(3)
6329 .select_until(find_position_of("t").nth_occurrence(2))
6330 );
6331}
6332
6333#[test]
6334fn do_not_extract_constant_from_fn_call_2() {
6335 assert_no_code_actions!(
6336 EXTRACT_CONSTANT,
6337 r#"import gleam/list
6338
6339pub fn main() {
6340 let first = list.first([1, 2, 3])
6341 first
6342}"#,
6343 find_position_of("l")
6344 .nth_occurrence(3)
6345 .select_until(find_position_of("t").nth_occurrence(4))
6346 );
6347}
6348
6349#[test]
6350fn do_not_extract_constant_from_bin_op() {
6351 assert_no_code_actions!(
6352 EXTRACT_CONSTANT,
6353 r#"pub fn main() {
6354 let res = 64 < 32
6355 res
6356}"#,
6357 find_position_of("<").to_selection()
6358 );
6359}
6360
6361#[test]
6362fn do_not_extract_constant_from_bit_array_1() {
6363 assert_no_code_actions!(
6364 EXTRACT_CONSTANT,
6365 r#"pub fn main() {
6366 let c = "constant"
6367 let res = <<c:utf16>>
6368 res
6369}"#,
6370 find_position_of("<").to_selection()
6371 );
6372}
6373
6374#[test]
6375fn do_not_extract_constant_from_bit_array_2() {
6376 assert_no_code_actions!(
6377 EXTRACT_CONSTANT,
6378 r#"import gleam/io
6379
6380pub fn main() {
6381 let n = 1234
6382 io.debug(<<8080:size(n)>>)
6383}"#,
6384 find_position_of("<").to_selection()
6385 );
6386}
6387
6388#[test]
6389fn do_not_extract_constant_from_bit_array_3() {
6390 assert_no_code_actions!(
6391 EXTRACT_CONSTANT,
6392 r#"import gleam/io
6393
6394pub fn main() {
6395 let l = 1234
6396 let r = 1234
6397 let result = <<l:size(r)>>
6398 result
6399}"#,
6400 find_position_of("l")
6401 .nth_occurrence(5)
6402 .select_until(find_position_of("t").nth_occurrence(5))
6403 );
6404}
6405
6406#[test]
6407fn do_not_extract_constant_from_list_1() {
6408 assert_no_code_actions!(
6409 EXTRACT_CONSTANT,
6410 r#"pub fn main() {
6411 let c = ["constant", todo]
6412 c
6413}"#,
6414 find_position_of("[").to_selection()
6415 );
6416}
6417
6418#[test]
6419fn do_not_extract_constant_from_list_2() {
6420 assert_no_code_actions!(
6421 EXTRACT_CONSTANT,
6422 r#"pub fn main() {
6423 [10, todo]
6424}"#,
6425 find_position_of("[").to_selection()
6426 );
6427}
6428
6429#[test]
6430fn do_not_extract_constant_from_list_3() {
6431 assert_no_code_actions!(
6432 EXTRACT_CONSTANT,
6433 r#"pub fn main() {
6434 let c = [0.25, todo]
6435 c
6436}"#,
6437 find_position_of("l").select_until(find_position_of("c"))
6438 );
6439}
6440
6441#[test]
6442fn do_not_extract_constant_from_tuple_1() {
6443 assert_no_code_actions!(
6444 EXTRACT_CONSTANT,
6445 r#"pub fn main() {
6446 let c = #("constant", todo)
6447 c
6448}"#,
6449 find_position_of("#").select_until(find_position_of("("))
6450 );
6451}
6452
6453#[test]
6454fn do_not_extract_constant_from_tuple_2() {
6455 assert_no_code_actions!(
6456 EXTRACT_CONSTANT,
6457 r#"pub fn main() {
6458 #(10, todo)
6459}"#,
6460 find_position_of("#").select_until(find_position_of("("))
6461 );
6462}
6463
6464#[test]
6465fn do_not_extract_constant_from_tuple_3() {
6466 assert_no_code_actions!(
6467 EXTRACT_CONSTANT,
6468 r#"pub fn main() {
6469 let c = #(0.25, todo)
6470 c
6471}"#,
6472 find_position_of("l").select_until(find_position_of("c"))
6473 );
6474}
6475
6476#[test]
6477fn do_not_extract_constant_from_nested_1() {
6478 assert_no_code_actions!(
6479 EXTRACT_CONSTANT,
6480 r#"pub fn main() {
6481 let c = list.unzip([#(1, 2), #(3, todo)])
6482 c
6483}"#,
6484 find_position_of("[").to_selection()
6485 );
6486}
6487
6488#[test]
6489fn do_not_extract_constant_from_nested_2() {
6490 assert_no_code_actions!(
6491 EXTRACT_CONSTANT,
6492 r#"pub fn main() {
6493 [[1.25, 1], [0.25, todo]]
6494}"#,
6495 find_position_of("[").to_selection()
6496 );
6497}
6498
6499#[test]
6500fn do_not_extract_constant_from_nested_3() {
6501 assert_no_code_actions!(
6502 EXTRACT_CONSTANT,
6503 r#"import gleam/list
6504
6505pub fn main() {
6506 let c = [#(1, 2), #(3, todo)]
6507 c
6508}"#,
6509 find_position_of("l")
6510 .nth_occurrence(3)
6511 .select_until(find_position_of("c"))
6512 );
6513}
6514
6515#[test]
6516fn do_not_extract_constant_from_record_1() {
6517 assert_no_code_actions!(
6518 EXTRACT_CONSTANT,
6519 r#"type Pair {
6520 Pair(Int, Int)
6521}
6522
6523pub fn main() {
6524 let c = list.unzip([Pair(1, 2), Pair(3, todo)])
6525 c
6526}"#,
6527 find_position_of("P").nth_occurrence(4).to_selection()
6528 );
6529}
6530
6531#[test]
6532fn do_not_extract_constant_from_record_2() {
6533 assert_no_code_actions!(
6534 EXTRACT_CONSTANT,
6535 r#"type Couple {
6536 Couple(l: Float, r: Float)
6537}
6538
6539pub fn main() {
6540 #(Couple(1.25, 1.0), Couple(0.25, todo))
6541}"#,
6542 find_position_of("C").nth_occurrence(4).to_selection()
6543 );
6544}
6545
6546#[test]
6547fn do_not_extract_constant_from_record_update() {
6548 assert_no_code_actions!(
6549 EXTRACT_CONSTANT,
6550 r#"type Couple {
6551 Couple(l: Int, r: Int)
6552}
6553
6554pub fn main() {
6555 let c = Couple(1, 2)
6556 let cc = Couple(..c, 2)
6557 cc
6558}"#,
6559 find_position_of("C")
6560 .nth_occurrence(4)
6561 .select_until(find_position_of("e").nth_occurrence(7))
6562 );
6563}
6564
6565#[test]
6566fn do_not_extract_constant_from_record_capture() {
6567 assert_no_code_actions!(
6568 EXTRACT_CONSTANT,
6569 r#"type Couple {
6570 Couple(l: Int, r: Int)
6571}
6572
6573pub fn main() {
6574 let c = Couple(1, _)
6575 c
6576}"#,
6577 find_position_of("C")
6578 .nth_occurrence(3)
6579 .select_until(find_position_of("e").nth_occurrence(5))
6580 );
6581}
6582
6583#[test]
6584fn do_not_extract_top_level_expression_statement() {
6585 assert_no_code_actions!(
6586 EXTRACT_VARIABLE,
6587 r#"pub fn main() {
6588 1
6589}
6590"#,
6591 find_position_of("1").to_selection()
6592 );
6593}
6594
6595#[test]
6596fn do_not_extract_top_level_expression_in_let_statement() {
6597 assert_no_code_actions!(
6598 EXTRACT_VARIABLE,
6599 r#"pub fn main() {
6600 let a = 1
6601}
6602"#,
6603 find_position_of("1").to_selection()
6604 );
6605}
6606
6607#[test]
6608fn do_not_extract_top_level_module_call() {
6609 let src = r#"
6610import list
6611pub fn main() {
6612 list.map([1, 2, 3], todo)
6613}"#;
6614
6615 assert_no_code_actions!(
6616 EXTRACT_VARIABLE,
6617 TestProject::for_source(src).add_module("list", "pub fn map(l, f) { todo }"),
6618 find_position_of("map").to_selection()
6619 );
6620}
6621
6622#[test]
6623fn expand_function_capture() {
6624 assert_code_action!(
6625 EXPAND_FUNCTION_CAPTURE,
6626 r#"pub fn main() {
6627 wibble(_, 1)
6628}"#,
6629 find_position_of("_").to_selection()
6630 );
6631}
6632
6633#[test]
6634fn expand_function_capture_2() {
6635 assert_code_action!(
6636 EXPAND_FUNCTION_CAPTURE,
6637 r#"pub fn main() {
6638 wibble(1, _)
6639}"#,
6640 find_position_of("wibble").to_selection()
6641 );
6642}
6643
6644#[test]
6645fn expand_function_capture_does_not_shadow_variables() {
6646 assert_code_action!(
6647 EXPAND_FUNCTION_CAPTURE,
6648 r#"pub fn main() {
6649 let value = 1
6650 let value_2 = 2
6651 wibble(value, _, value_2)
6652}"#,
6653 find_position_of("wibble").to_selection()
6654 );
6655}
6656
6657#[test]
6658fn expand_function_capture_picks_a_name_based_on_the_type_of_the_hole() {
6659 assert_code_action!(
6660 EXPAND_FUNCTION_CAPTURE,
6661 r#"pub fn main() {
6662 [1, 2, 3]
6663 |> map(add(_, 1))
6664}
6665
6666pub fn map(l: List(a), f: fn(a) -> b) -> List(b) { todo }
6667pub fn add(n, m) { n + m }
6668"#,
6669 find_position_of("add").to_selection()
6670 );
6671}
6672
6673#[test]
6674fn generate_dynamic_decoder() {
6675 assert_code_action!(
6676 GENERATE_DYNAMIC_DECODER,
6677 "
6678pub type Person {
6679 Person(name: String, age: Int, height: Float, is_cool: Bool, brain: BitArray)
6680}
6681",
6682 find_position_of("type").to_selection()
6683 );
6684}
6685
6686#[test]
6687fn generate_dynamic_decoder_complex_types() {
6688 let src = "
6689import gleam/option
6690import gleam/dynamic
6691import gleam/dict
6692
6693pub type Something
6694
6695pub type Wibble(value) {
6696 Wibble(
6697 maybe: option.Option(Something),
6698 map: dict.Dict(String, List(value)),
6699 unknown: List(dynamic.Dynamic),
6700 )
6701}
6702";
6703
6704 assert_code_action!(
6705 GENERATE_DYNAMIC_DECODER,
6706 TestProject::for_source(src)
6707 .add_module("gleam/option", "pub type Option(a)")
6708 .add_module("gleam/dynamic", "pub type Dynamic")
6709 .add_module("gleam/dict", "pub type Dict(k, v)"),
6710 find_position_of("type W").to_selection()
6711 );
6712}
6713
6714#[test]
6715fn generate_dynamic_decoder_already_imported_module() {
6716 let src = "
6717import gleam/dynamic/decode as dyn_dec
6718
6719pub type Wibble {
6720 Wibble(a: Int, b: Float, c: String)
6721}
6722";
6723
6724 assert_code_action!(
6725 GENERATE_DYNAMIC_DECODER,
6726 TestProject::for_source(src).add_module("gleam/dynamic/decode", "pub type Decoder(a)"),
6727 find_position_of("type W").to_selection()
6728 );
6729}
6730
6731#[test]
6732fn generate_dynamic_decoder_tuple() {
6733 assert_code_action!(
6734 GENERATE_DYNAMIC_DECODER,
6735 "
6736pub type Wibble {
6737 Wibble(tuple: #(Int, Float, #(String, Bool)))
6738}
6739",
6740 find_position_of("type W").to_selection()
6741 );
6742}
6743
6744#[test]
6745fn generate_dynamic_decoder_recursive_type() {
6746 let src = "
6747import gleam/option
6748
6749pub type LinkedList {
6750 LinkedList(value: Int, next: option.Option(LinkedList))
6751}
6752";
6753 assert_code_action!(
6754 GENERATE_DYNAMIC_DECODER,
6755 TestProject::for_source(src).add_module("gleam/option", "pub type Option(a)"),
6756 find_position_of("type").to_selection()
6757 );
6758}
6759
6760#[test]
6761fn generate_dynamic_decoder_for_multi_variant_type() {
6762 assert_code_action!(
6763 GENERATE_DYNAMIC_DECODER,
6764 "
6765pub type Wibble {
6766 Wibble(wibble: Int, next: Wibble)
6767 Wobble(wobble: Float, text: String, values: List(Bool))
6768}
6769",
6770 find_position_of("type").to_selection()
6771 );
6772}
6773
6774#[test]
6775fn generate_dynamic_decoder_for_multi_variant_type_multi_word_name() {
6776 assert_code_action!(
6777 GENERATE_DYNAMIC_DECODER,
6778 "
6779pub type Wibble {
6780 OneTwo(wibble: Int, next: Wibble)
6781 ThreeFour(wobble: Float, text: String, values: List(Bool))
6782 FiveSixSeven(one_two: Int)
6783}
6784",
6785 find_position_of("type").to_selection()
6786 );
6787}
6788
6789#[test]
6790fn generate_dynamic_decoder_for_variant_with_no_fields() {
6791 assert_code_action!(
6792 GENERATE_DYNAMIC_DECODER,
6793 "
6794pub type Wibble {
6795 Wibble
6796}
6797",
6798 find_position_of("type").to_selection()
6799 );
6800}
6801
6802#[test]
6803fn generate_dynamic_decoder_for_variants_with_no_fields() {
6804 assert_code_action!(
6805 GENERATE_DYNAMIC_DECODER,
6806 "
6807pub type Wibble {
6808 Wibble
6809 Wobble
6810 Woo
6811}
6812",
6813 find_position_of("type").to_selection()
6814 );
6815}
6816
6817#[test]
6818fn generate_dynamic_decoder_for_variants_with_mixed_fields() {
6819 assert_code_action!(
6820 GENERATE_DYNAMIC_DECODER,
6821 "
6822pub type Wibble {
6823 Wibble
6824 Wobble(field: String, field2: Int)
6825}
6826",
6827 find_position_of("type").to_selection()
6828 );
6829}
6830
6831#[test]
6832fn no_code_action_to_generate_dynamic_decoder_for_type_without_labels() {
6833 assert_no_code_actions!(
6834 GENERATE_DYNAMIC_DECODER,
6835 "
6836pub type Wibble {
6837 Wibble(Int, Int, String)
6838}
6839",
6840 find_position_of("type").to_selection()
6841 );
6842}
6843
6844#[test]
6845fn pattern_match_on_argument_empty_tuple() {
6846 assert_no_code_actions!(
6847 PATTERN_MATCH_ON_ARGUMENT,
6848 "
6849pub fn main(tuple: #()) {
6850 todo
6851}
6852",
6853 find_position_of("tuple").to_selection()
6854 );
6855}
6856
6857#[test]
6858fn pattern_match_on_argument_single_item_tuple() {
6859 assert_code_action!(
6860 PATTERN_MATCH_ON_ARGUMENT,
6861 "
6862pub fn main(tuple: #(Int)) {
6863 todo
6864}
6865",
6866 find_position_of(":").to_selection()
6867 );
6868}
6869
6870#[test]
6871fn pattern_match_on_argument_multi_item_tuple() {
6872 assert_code_action!(
6873 PATTERN_MATCH_ON_ARGUMENT,
6874 "
6875pub fn main(tuple: #(Int, String, Bool)) {
6876 todo
6877}
6878",
6879 find_position_of("tuple").select_until(find_position_of("Int"))
6880 );
6881}
6882
6883#[test]
6884fn pattern_match_on_argument_uses_case_with_multiple_constructors() {
6885 assert_code_action!(
6886 PATTERN_MATCH_ON_ARGUMENT,
6887 "
6888pub type CannotBeDestructured {
6889 One(one: String)
6890 Two(two: Int)
6891}
6892
6893pub fn main(arg: CannotBeDestructured) {
6894 todo
6895}
6896",
6897 find_position_of("arg").to_selection()
6898 );
6899}
6900
6901#[test]
6902fn pattern_match_on_argument_with_multiple_constructors_is_nicely_formatted_in_function_with_empty_body()
6903 {
6904 assert_code_action!(
6905 PATTERN_MATCH_ON_ARGUMENT,
6906 "
6907pub type CannotBeDestructured {
6908 One(one: String)
6909 Two(two: Int)
6910}
6911
6912pub fn main(arg: CannotBeDestructured) {}
6913",
6914 find_position_of("arg").to_selection()
6915 );
6916}
6917
6918#[test]
6919fn pattern_match_on_argument_uses_label_shorthand_syntax_for_labelled_arguments() {
6920 assert_code_action!(
6921 PATTERN_MATCH_ON_ARGUMENT,
6922 "
6923pub type Wibble {
6924 Wobble(Int, String, i_want_to_see_this: String, and_this: Bool)
6925}
6926
6927pub fn main(arg: Wibble) {
6928 todo
6929}
6930",
6931 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2))
6932 );
6933}
6934
6935#[test]
6936fn pattern_match_on_argument_with_private_type_from_same_module() {
6937 assert_code_action!(
6938 PATTERN_MATCH_ON_ARGUMENT,
6939 "
6940type Wibble {
6941 Wobble(Int, String)
6942}
6943
6944pub fn main(arg: Wibble) {
6945 todo
6946}
6947",
6948 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2))
6949 );
6950}
6951
6952#[test]
6953fn pattern_match_on_value_with_private_type_from_same_module() {
6954 assert_code_action!(
6955 PATTERN_MATCH_ON_VARIABLE,
6956 "
6957type Wibble {
6958 Wobble(Int, String)
6959}
6960
6961pub fn main() {
6962 let wibble = Wobble(1, \"Hello\")
6963 todo
6964}
6965",
6966 find_position_of("wibble").to_selection()
6967 );
6968}
6969
6970#[test]
6971fn pattern_match_on_clause_variable() {
6972 assert_code_action!(
6973 PATTERN_MATCH_ON_VARIABLE,
6974 "
6975pub fn main() {
6976 case maybe_wibble() {
6977 Ok(something) -> 1
6978 Error(_) -> 2
6979 }
6980}
6981
6982type Wibble {
6983 Wobble
6984 Woo
6985}
6986
6987fn maybe_wibble() { Ok(Wobble) }
6988
6989",
6990 find_position_of("something").to_selection()
6991 );
6992}
6993
6994#[test]
6995fn pattern_match_on_clause_variable_nested_pattern() {
6996 assert_code_action!(
6997 PATTERN_MATCH_ON_VARIABLE,
6998 "
6999pub fn main() {
7000 case maybe_wibble() {
7001 Ok(Wobble(something)) -> 1
7002 Error(_) -> 2
7003 }
7004}
7005
7006type Wibble {
7007 Wobble(Wibble)
7008 Woo
7009}
7010
7011fn maybe_wibble() { Ok(Woo) }
7012
7013",
7014 find_position_of("something").to_selection()
7015 );
7016}
7017
7018#[test]
7019fn pattern_match_on_clause_variable_with_block_body() {
7020 assert_code_action!(
7021 PATTERN_MATCH_ON_VARIABLE,
7022 "
7023pub fn main() {
7024 case maybe_wibble() {
7025 Ok(something) -> {
7026 1
7027 2
7028 }
7029 Error(_) -> 2
7030 }
7031}
7032
7033type Wibble {
7034 Wobble
7035 Woo
7036}
7037
7038fn maybe_wibble() { Ok(Wobble) }
7039
7040",
7041 find_position_of("something").to_selection()
7042 );
7043}
7044
7045#[test]
7046fn pattern_match_on_argument_will_use_qualified_name() {
7047 let src = "
7048import wibble
7049
7050pub fn main(arg: wibble.Wibble) {
7051 todo
7052}
7053";
7054
7055 let dep = "
7056pub type Wibble {
7057 ThisShouldBeQualified(label: Int)
7058}
7059";
7060
7061 assert_code_action!(
7062 PATTERN_MATCH_ON_ARGUMENT,
7063 TestProject::for_source(src).add_module("wibble", dep),
7064 find_position_of("wibble").nth_occurrence(2).to_selection()
7065 );
7066}
7067
7068#[test]
7069fn pattern_match_on_argument_will_use_unqualified_name() {
7070 let src = "
7071import wibble.{ThisShouldBeUnqualified}
7072
7073pub fn main(arg: wibble.Wibble) {
7074 todo
7075}
7076";
7077
7078 let dep = "
7079pub type Wibble {
7080 ThisShouldBeUnqualified(label: Int)
7081}
7082";
7083
7084 assert_code_action!(
7085 PATTERN_MATCH_ON_ARGUMENT,
7086 TestProject::for_source(src).add_module("wibble", dep),
7087 find_position_of("Wibble").to_selection()
7088 );
7089}
7090
7091#[test]
7092fn pattern_match_on_argument_will_use_aliased_constructor_name() {
7093 let src = "
7094import wibble.{Wobble as IWantToSeeThisName}
7095
7096pub fn main(arg: wibble.Wibble) {
7097 todo
7098}
7099";
7100
7101 let dep = "
7102pub type Wibble {
7103 Wobble(label: Int)
7104}
7105";
7106
7107 assert_code_action!(
7108 PATTERN_MATCH_ON_ARGUMENT,
7109 TestProject::for_source(src).add_module("wibble", dep),
7110 find_position_of("arg").to_selection()
7111 );
7112}
7113
7114#[test]
7115fn pattern_match_on_argument_will_use_aliased_module_name() {
7116 let src = "
7117import wibble as i_want_to_see_this_name
7118
7119pub fn main(arg: i_want_to_see_this_name.Wibble) {
7120 todo
7121}
7122";
7123
7124 let dep = "
7125pub type Wibble {
7126 Wobble(label: Int)
7127}
7128";
7129
7130 assert_code_action!(
7131 PATTERN_MATCH_ON_ARGUMENT,
7132 TestProject::for_source(src).add_dep_module("wibble", dep),
7133 find_position_of("arg").to_selection()
7134 );
7135}
7136
7137#[test]
7138fn pattern_match_on_argument_not_available_for_internal_type() {
7139 let src = "
7140import wibble
7141
7142pub fn main(arg: wobble.Wibble) {
7143 todo
7144}
7145";
7146
7147 let dep = "
7148@internal
7149pub type Wibble {
7150 Wobble(label: Int)
7151}
7152";
7153
7154 assert_no_code_actions!(
7155 PATTERN_MATCH_ON_ARGUMENT,
7156 TestProject::for_source(src).add_module("wibble", dep),
7157 find_position_of("arg").to_selection()
7158 );
7159}
7160
7161#[test]
7162fn pattern_match_on_argument_available_for_internal_type_defined_in_current_module() {
7163 assert_code_action!(
7164 PATTERN_MATCH_ON_ARGUMENT,
7165 "
7166@internal
7167pub type Wibble {
7168 Wobble(label: Int)
7169}
7170
7171pub fn main(arg: Wibble) {
7172 todo
7173}
7174",
7175 find_position_of("arg").select_until(find_position_of("Wibble").nth_occurrence(2))
7176 );
7177}
7178
7179#[test]
7180fn pattern_match_on_argument_preserves_indentation_of_statement_following_inserted_let() {
7181 assert_code_action!(
7182 PATTERN_MATCH_ON_ARGUMENT,
7183 "pub fn main(arg: #(Int, String)) {
7184 todo
7185//^^^^ This should still have two spaces of indentation!
7186}",
7187 find_position_of("arg").to_selection()
7188 );
7189}
7190
7191#[test]
7192fn pattern_match_on_argument_nicely_formats_code_when_used_on_function_with_empty_body() {
7193 assert_code_action!(
7194 PATTERN_MATCH_ON_ARGUMENT,
7195 "pub fn main(arg: #(Int, String)) {}",
7196 find_position_of("arg").to_selection()
7197 );
7198}
7199
7200#[test]
7201fn pattern_match_on_argument_single_unlabelled_field_is_not_numbered() {
7202 assert_code_action!(
7203 PATTERN_MATCH_ON_ARGUMENT,
7204 "
7205pub type Wibble {
7206 Wibble(Int)
7207}
7208
7209pub fn main(arg: Wibble) {}
7210",
7211 find_position_of(":").to_selection()
7212 );
7213}
7214
7215#[test]
7216fn pattern_match_on_let_assignment() {
7217 assert_code_action!(
7218 PATTERN_MATCH_ON_VARIABLE,
7219 "
7220pub fn main() {
7221 let var = #(1, 2)
7222}
7223",
7224 find_position_of("var").to_selection()
7225 );
7226}
7227
7228#[test]
7229fn pattern_match_on_let_assignment_with_multiple_constructors() {
7230 assert_code_action!(
7231 PATTERN_MATCH_ON_VARIABLE,
7232 "
7233pub type Wibble {
7234 Wobble
7235 Woo
7236}
7237
7238pub fn main() {
7239 let var = Woo
7240 todo
7241}
7242",
7243 find_position_of("var").to_selection()
7244 );
7245}
7246
7247#[test]
7248fn pattern_match_on_use_assignment() {
7249 assert_code_action!(
7250 PATTERN_MATCH_ON_VARIABLE,
7251 "
7252pub fn main() {
7253 use var <- f
7254}
7255
7256fn f(g) { g(#(1, 2)) }
7257",
7258 find_position_of("var").to_selection()
7259 );
7260}
7261
7262#[test]
7263fn pattern_match_on_use_assignment_with_multiple_constructors() {
7264 assert_code_action!(
7265 PATTERN_MATCH_ON_VARIABLE,
7266 "
7267pub type Wibble {
7268 Wobble
7269 Woo
7270}
7271
7272pub fn main() {
7273 use var <- f
7274}
7275
7276fn f(g) { g(Wobble) }
7277",
7278 find_position_of("var").to_selection()
7279 );
7280}
7281
7282#[test]
7283fn pattern_match_on_pattern_use_assignment() {
7284 assert_no_code_actions!(
7285 PATTERN_MATCH_ON_VARIABLE,
7286 "
7287pub fn main() {
7288 use #(a, b) <- f
7289}
7290
7291fn f(g) { g(#(1, 2)) }
7292",
7293 find_position_of("#").to_selection()
7294 );
7295}
7296
7297#[test]
7298fn pattern_match_on_argument_works_on_fn_arguments() {
7299 assert_code_action!(
7300 PATTERN_MATCH_ON_ARGUMENT,
7301 "
7302pub fn main() {
7303 [#(1, 2)]
7304 |> map(fn(tuple) {})
7305}
7306
7307fn map(list: List(a), fun: fn(a) -> b) { todo }
7308",
7309 find_position_of("tuple").to_selection()
7310 );
7311}
7312
7313#[test]
7314fn pattern_match_on_argument_works_on_nested_fn_arguments() {
7315 assert_code_action!(
7316 PATTERN_MATCH_ON_ARGUMENT,
7317 "
7318pub fn main() {
7319 map([[#(1, 2)]], fn(list) {
7320 map(list, fn(tuple) {
7321 todo
7322 })
7323 })
7324}
7325
7326fn map(list: List(a), fun: fn(a) -> b) { todo }
7327",
7328 find_position_of("tuple").to_selection()
7329 );
7330}
7331
7332#[test]
7333fn generate_function_works_with_invalid_call() {
7334 assert_code_action!(
7335 GENERATE_FUNCTION,
7336 "
7337pub fn main() -> Bool {
7338 wibble(1, True, 2.3)
7339}
7340",
7341 find_position_of("wibble").to_selection()
7342 );
7343}
7344
7345#[test]
7346fn generate_function_works_with_pipeline_steps() {
7347 assert_code_action!(
7348 GENERATE_FUNCTION,
7349 "
7350pub fn main() {
7351 [1, 2, 3]
7352 |> sum
7353 |> int_to_string
7354}
7355
7356fn int_to_string(n: Int) -> String {
7357 todo
7358}
7359",
7360 find_position_of("sum").to_selection()
7361 );
7362}
7363
7364#[test]
7365fn generate_function_works_with_pipeline_steps_1() {
7366 assert_code_action!(
7367 GENERATE_FUNCTION,
7368 "
7369pub fn main() {
7370 [1, 2, 3]
7371 |> map(int_to_string)
7372 |> join
7373}
7374
7375fn map(list: List(a), fun: fn(a) -> b) -> List(b) {
7376 todo
7377}
7378
7379fn join(n: List(String)) -> String {
7380 todo
7381}
7382",
7383 find_position_of("int_to_string").to_selection()
7384 );
7385}
7386
7387// https://github.com/gleam-lang/gleam/issues/4177#event-15968345230
7388#[test]
7389fn generate_function_picks_argument_name_based_on_type() {
7390 assert_code_action!(
7391 GENERATE_FUNCTION,
7392 "
7393pub fn main() {
7394 wibble(\"Hello\", 1)
7395}
7396",
7397 find_position_of("wibble").to_selection()
7398 );
7399}
7400
7401#[test]
7402fn generate_function_wont_generate_two_arguments_with_the_same_name_if_they_have_the_same_type() {
7403 assert_code_action!(
7404 GENERATE_FUNCTION,
7405 "
7406pub fn main() {
7407 wibble(2, 1)
7408}
7409",
7410 find_position_of("wibble").to_selection()
7411 );
7412}
7413
7414#[test]
7415fn generate_function_takes_labels_into_account() {
7416 assert_code_action!(
7417 GENERATE_FUNCTION,
7418 "
7419pub fn main() {
7420 wibble(2, n: 1)
7421}
7422",
7423 find_position_of("wibble").to_selection()
7424 );
7425}
7426
7427#[test]
7428fn generate_function_does_not_trigger_if_labels_are_in_the_wrong_order() {
7429 assert_no_code_actions!(
7430 GENERATE_FUNCTION,
7431 "
7432pub fn main() {
7433 wibble(n: 2, 1)
7434}
7435",
7436 find_position_of("wibble").to_selection()
7437 );
7438}
7439
7440#[test]
7441fn generate_function_does_not_trigger_if_there_are_repeated_labels() {
7442 assert_no_code_actions!(
7443 GENERATE_FUNCTION,
7444 "
7445pub fn main() {
7446 wibble(n: 2, n: 1)
7447}
7448",
7449 find_position_of("wibble").to_selection()
7450 );
7451}
7452
7453#[test]
7454fn generate_function_generates_argument_names_from_labels() {
7455 assert_code_action!(
7456 GENERATE_FUNCTION,
7457 "
7458pub fn main() {
7459 add(1, addend: 10)
7460}
7461",
7462 find_position_of("add").to_selection()
7463 );
7464}
7465
7466#[test]
7467fn generate_function_generates_argument_names_from_variables() {
7468 assert_code_action!(
7469 GENERATE_FUNCTION,
7470 "
7471pub fn main() {
7472 let wibble = 10
7473 let wobble = 20
7474
7475 wubble(wibble, wobble, 14)
7476}
7477",
7478 find_position_of("wubble").to_selection()
7479 );
7480}
7481
7482#[test]
7483fn generate_function_labels_and_arguments_can_share_the_same_name() {
7484 assert_code_action!(
7485 GENERATE_FUNCTION,
7486 "
7487pub fn main() {
7488 let wibble = 10
7489 wubble(wibble, wibble: 14)
7490}
7491",
7492 find_position_of("wubble").to_selection()
7493 );
7494}
7495
7496#[test]
7497fn generate_function_arguments_with_same_name_get_renamed() {
7498 assert_code_action!(
7499 GENERATE_FUNCTION,
7500 "
7501pub fn main() {
7502 let wibble = 10
7503 wubble(wibble, wibble)
7504}
7505",
7506 find_position_of("wubble").to_selection()
7507 );
7508}
7509
7510#[test]
7511fn generate_function_arguments_with_labels_and_variables_uses_different_names() {
7512 assert_code_action!(
7513 GENERATE_FUNCTION,
7514 "
7515pub fn main() {
7516 let list = [2, 4, 5]
7517 let value = 1
7518 find(each: value, in: list)
7519}
7520",
7521 find_position_of("find").to_selection()
7522 );
7523}
7524
7525#[test]
7526fn pattern_match_on_argument_generates_unique_names_even_with_labels() {
7527 assert_code_action!(
7528 PATTERN_MATCH_ON_ARGUMENT,
7529 "
7530pub type Wibble {
7531 Wibble(String, string: String)
7532}
7533
7534pub fn main(wibble: Wibble) {
7535 todo
7536}
7537",
7538 find_position_of("wibble").to_selection()
7539 );
7540}
7541
7542#[test]
7543fn extract_variable_with_list_with_plural_name_does_not_add_another_s() {
7544 assert_code_action!(
7545 EXTRACT_VARIABLE,
7546 "
7547pub fn main() {
7548 wibble([Names, Names])
7549}
7550
7551pub type Names {
7552 Names
7553}
7554",
7555 find_position_of("[").to_selection()
7556 );
7557}
7558
7559#[test]
7560fn convert_to_function_call_works_with_argument_in_first_position() {
7561 assert_code_action!(
7562 CONVERT_TO_FUNCTION_CALL,
7563 "
7564pub fn main() {
7565 [1, 2, 3]
7566 |> map(todo)
7567}
7568
7569fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }
7570",
7571 find_position_of("map").to_selection()
7572 );
7573}
7574
7575#[test]
7576fn generate_json_encoder() {
7577 let src = "
7578pub type Person {
7579 Person(name: String, age: Int, height: Float, is_cool: Bool)
7580}
7581";
7582
7583 assert_code_action!(
7584 GENERATE_TO_JSON_FUNCTION,
7585 TestProject::for_source(src).add_package_module(
7586 "gleam_json",
7587 "gleam/json",
7588 "pub type Json"
7589 ),
7590 find_position_of("type").to_selection()
7591 );
7592}
7593
7594#[test]
7595fn convert_to_function_call_works_with_argument_in_first_position_2() {
7596 assert_code_action!(
7597 CONVERT_TO_FUNCTION_CALL,
7598 "
7599pub fn main() {
7600 [1, 2, 3] |> wibble
7601}
7602
7603fn wibble(a) { todo }
7604",
7605 find_position_of("wibble").to_selection()
7606 );
7607}
7608
7609#[test]
7610fn generate_json_encoder_complex_types() {
7611 let src = "
7612import gleam/option
7613import gleam/dict
7614
7615pub type Something
7616
7617pub type Wibble(value) {
7618 Wibble(
7619 maybe: option.Option(Int),
7620 something: Something,
7621 map: dict.Dict(String, List(Float)),
7622 unknown: List(value),
7623 )
7624}
7625";
7626
7627 assert_code_action!(
7628 GENERATE_TO_JSON_FUNCTION,
7629 TestProject::for_source(src)
7630 .add_module("gleam/option", "pub type Option(a)")
7631 .add_module("gleam/dict", "pub type Dict(k, v)")
7632 .add_package_module("gleam_json", "gleam/json", "pub type Json"),
7633 find_position_of("type W").to_selection()
7634 );
7635}
7636
7637#[test]
7638fn convert_to_function_call_works_with_argument_in_first_position_3() {
7639 assert_code_action!(
7640 CONVERT_TO_FUNCTION_CALL,
7641 "
7642pub fn main() {
7643 [1, 2, 3] |> wibble()
7644}
7645
7646fn wibble(a) { todo }
7647",
7648 find_position_of("wibble").to_selection()
7649 );
7650}
7651
7652#[test]
7653fn generate_json_encoder_already_imported_module() {
7654 let src = "
7655import gleam/json as json_encoding
7656
7657pub type Wibble {
7658 Wibble(a: Int, b: Float, c: String)
7659}
7660";
7661
7662 assert_code_action!(
7663 GENERATE_TO_JSON_FUNCTION,
7664 TestProject::for_source(src).add_package_module(
7665 "gleam_json",
7666 "gleam/json",
7667 "pub type Json"
7668 ),
7669 find_position_of("type W").to_selection()
7670 );
7671}
7672
7673#[test]
7674fn convert_to_function_call_works_with_argument_in_first_position_4() {
7675 assert_code_action!(
7676 CONVERT_TO_FUNCTION_CALL,
7677 "
7678pub fn main() {
7679 [1, 2, 3] |> wibble.wobble
7680}
7681",
7682 find_position_of("wibble").to_selection()
7683 );
7684}
7685
7686#[test]
7687fn generate_json_encoder_tuple() {
7688 let src = "
7689pub type Wibble {
7690 Wibble(tuple: #(Int, Float, #(String, Bool)))
7691}
7692";
7693
7694 assert_code_action!(
7695 GENERATE_TO_JSON_FUNCTION,
7696 TestProject::for_source(src).add_package_module(
7697 "gleam_json",
7698 "gleam/json",
7699 "pub type Json"
7700 ),
7701 find_position_of("type W").to_selection()
7702 );
7703}
7704
7705#[test]
7706fn generate_json_encoder_for_variant_with_no_fields() {
7707 let src = "
7708pub type Wibble {
7709 Wibble
7710}
7711";
7712
7713 assert_code_action!(
7714 GENERATE_TO_JSON_FUNCTION,
7715 TestProject::for_source(src).add_package_module(
7716 "gleam_json",
7717 "gleam/json",
7718 "pub type Json"
7719 ),
7720 find_position_of("type W").to_selection()
7721 );
7722}
7723
7724#[test]
7725fn generate_json_encoder_for_type_with_multiple_variants_with_no_fields() {
7726 let src = "
7727pub type Wibble {
7728 Wibble
7729 Wobble
7730 Woo
7731}
7732";
7733
7734 assert_code_action!(
7735 GENERATE_TO_JSON_FUNCTION,
7736 TestProject::for_source(src).add_package_module(
7737 "gleam_json",
7738 "gleam/json",
7739 "pub type Json"
7740 ),
7741 find_position_of("type W").to_selection()
7742 );
7743}
7744
7745#[test]
7746fn generate_json_encoder_for_variants_with_mixed_fields() {
7747 let src = "
7748pub type Wibble {
7749 Wibble
7750 Wobble(field: String, field1: Int)
7751}
7752";
7753
7754 assert_code_action!(
7755 GENERATE_TO_JSON_FUNCTION,
7756 TestProject::for_source(src).add_package_module(
7757 "gleam_json",
7758 "gleam/json",
7759 "pub type Json"
7760 ),
7761 find_position_of("type W").to_selection()
7762 );
7763}
7764
7765#[test]
7766fn convert_to_function_call_works_with_function_producing_another_function() {
7767 assert_code_action!(
7768 CONVERT_TO_FUNCTION_CALL,
7769 "
7770pub fn main() {
7771 1 |> wibble(2)
7772}
7773
7774fn wibble(c) -> fn(a) -> Nil {
7775 fn(_) { Nil }
7776}
7777",
7778 find_position_of("wibble").to_selection()
7779 );
7780}
7781
7782#[test]
7783fn generate_json_encoder_recursive_type() {
7784 let src = "
7785import gleam/option.{Some}
7786
7787pub type LinkedList {
7788 LinkedList(value: Int, next: option.Option(LinkedList))
7789}
7790";
7791 assert_code_action!(
7792 GENERATE_TO_JSON_FUNCTION,
7793 TestProject::for_source(src)
7794 .add_module("gleam/option", "pub type Option(a) { Some(a) None }")
7795 .add_package_module("gleam_json", "gleam/json", "pub type Json"),
7796 find_position_of("type").to_selection()
7797 );
7798}
7799
7800#[test]
7801fn convert_to_function_call_works_with_hole_in_first_position() {
7802 assert_code_action!(
7803 CONVERT_TO_FUNCTION_CALL,
7804 "
7805pub fn main() {
7806 [1, 2, 3]
7807 |> map(_, todo)
7808}
7809
7810fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }
7811",
7812 find_position_of("[").to_selection()
7813 );
7814}
7815
7816#[test]
7817fn generate_json_encoder_list_of_tuples() {
7818 let src = "
7819pub type Wibble {
7820 Wibble(values: List(#(Int, String)))
7821}
7822";
7823
7824 assert_code_action!(
7825 GENERATE_TO_JSON_FUNCTION,
7826 TestProject::for_source(src).add_package_module(
7827 "gleam_json",
7828 "gleam/json",
7829 "pub type Json"
7830 ),
7831 find_position_of("type").to_selection()
7832 );
7833}
7834
7835#[test]
7836fn generate_json_encoder_for_multi_variant_type() {
7837 let src = "
7838pub type Wibble {
7839 Wibble(wibble: Int, next: Wibble)
7840 Wobble(wobble: Float, text: String, values: List(Bool))
7841}
7842";
7843
7844 assert_code_action!(
7845 GENERATE_TO_JSON_FUNCTION,
7846 TestProject::for_source(src).add_package_module(
7847 "gleam_json",
7848 "gleam/json",
7849 "pub type Json"
7850 ),
7851 find_position_of("type").to_selection()
7852 );
7853}
7854
7855#[test]
7856fn generate_json_encoder_for_multi_variant_type_multi_word_name() {
7857 let src = "
7858pub type Wibble {
7859 OneTwoThree(wibble: Int, next: Wibble)
7860 FourFive(wobble: Float, text: String, values: List(Bool))
7861 SixSevenEight(one_two: Float)
7862}
7863";
7864
7865 assert_code_action!(
7866 GENERATE_TO_JSON_FUNCTION,
7867 TestProject::for_source(src).add_package_module(
7868 "gleam_json",
7869 "gleam/json",
7870 "pub type Json"
7871 ),
7872 find_position_of("type").to_selection()
7873 );
7874}
7875
7876#[test]
7877fn convert_to_function_call_works_with_hole_not_in_first_position() {
7878 assert_code_action!(
7879 CONVERT_TO_FUNCTION_CALL,
7880 "
7881pub fn main() {
7882 fn(a) { todo }
7883 |> map([1, 2, 3], _)
7884}
7885
7886fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }
7887",
7888 find_position_of("fn(a)").select_until(find_position_of("map"))
7889 );
7890}
7891
7892#[test]
7893fn convert_to_function_call_always_inlines_the_first_step() {
7894 assert_code_action!(
7895 CONVERT_TO_FUNCTION_CALL,
7896 "
7897pub fn main() {
7898 [1, 2, 3]
7899 |> map(todo)
7900 |> filter(todo)
7901}
7902
7903fn map(list: List(a), fun: fn(a) -> b) -> List(b) { todo }
7904fn filter(list: List(a), fun: fn(a) -> Bool) -> List(b) { todo }
7905",
7906 find_position_of("[1, 2, 3]").select_until(find_position_of("map"))
7907 );
7908}
7909
7910#[test]
7911fn convert_to_function_call_works_with_labelled_argument() {
7912 assert_code_action!(
7913 CONVERT_TO_FUNCTION_CALL,
7914 "
7915pub fn main() {
7916 [1, 2, 3] |> wibble(wobble: _, woo:)
7917}
7918",
7919 find_position_of("wibble").to_selection()
7920 );
7921}
7922
7923#[test]
7924fn convert_to_function_call_works_with_labelled_argument_2() {
7925 assert_code_action!(
7926 CONVERT_TO_FUNCTION_CALL,
7927 "
7928pub fn main() {
7929 [1, 2, 3] |> wibble(wobble:, woo: _)
7930}
7931",
7932 find_position_of("wibble").to_selection()
7933 );
7934}
7935
7936#[test]
7937fn convert_to_function_call_works_when_piping_an_invalid_module_select() {
7938 assert_code_action!(
7939 CONVERT_TO_FUNCTION_CALL,
7940 "
7941pub fn main() {
7942 wibble.wobble |> woo(_)
7943}
7944",
7945 find_position_of("woo").to_selection()
7946 );
7947}
7948
7949#[test]
7950fn convert_to_function_call_works_when_piping_a_module_select() {
7951 let src = "
7952import wibble
7953
7954pub fn main() {
7955 wibble.wobble |> woo(_)
7956}
7957
7958fn woo(n) { todo }
7959";
7960
7961 assert_code_action!(
7962 CONVERT_TO_FUNCTION_CALL,
7963 TestProject::for_source(src).add_module("wibble", "pub const wobble = 1"),
7964 find_position_of("woo").to_selection()
7965 );
7966}
7967
7968#[test]
7969fn convert_to_function_call_works_with_echo() {
7970 assert_code_action!(
7971 CONVERT_TO_FUNCTION_CALL,
7972 "
7973pub fn main() {
7974 wibble.wobble |> echo
7975}
7976",
7977 find_position_of("echo").to_selection()
7978 );
7979}
7980
7981#[test]
7982fn no_code_action_to_generate_json_encoder_for_type_without_labels() {
7983 let src = "
7984pub type Wibble {
7985 Wibble(Int, Int, String)
7986}
7987 ";
7988
7989 assert_no_code_actions!(
7990 GENERATE_TO_JSON_FUNCTION,
7991 TestProject::for_source(src).add_package_module(
7992 "gleam_json",
7993 "gleam/json",
7994 "pub type Json"
7995 ),
7996 find_position_of("type").to_selection()
7997 );
7998}
7999
8000#[test]
8001fn no_code_action_to_generate_json_encoder_without_gleam_json_dependency() {
8002 assert_no_code_actions!(
8003 GENERATE_TO_JSON_FUNCTION,
8004 "
8005pub type Wibble {
8006 Wibble(w: Int)
8007}
8008",
8009 find_position_of("type").to_selection()
8010 );
8011}
8012
8013#[test]
8014fn inline_variable() {
8015 let src = r#"
8016import gleam/io
8017
8018pub fn main() {
8019 let message = "Hello!"
8020 io.println(message)
8021}
8022"#;
8023 assert_code_action!(
8024 INLINE_VARIABLE,
8025 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8026 find_position_of("message)").to_selection()
8027 );
8028}
8029
8030#[test]
8031fn inline_variable_from_definition() {
8032 let src = r#"
8033import gleam/io
8034
8035pub fn main() {
8036 let message = "Hello!"
8037 io.println(message)
8038}
8039"#;
8040 assert_code_action!(
8041 INLINE_VARIABLE,
8042 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8043 find_position_of("message =").to_selection()
8044 );
8045}
8046
8047#[test]
8048fn inline_variable_in_nested_scope() {
8049 let src = r#"
8050import gleam/io
8051
8052pub fn main() {
8053 let _ = {
8054 let message = "Hello!"
8055 io.println(message)
8056 }
8057}
8058"#;
8059 assert_code_action!(
8060 INLINE_VARIABLE,
8061 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8062 find_position_of("message =").to_selection()
8063 );
8064}
8065
8066#[test]
8067fn inline_variable_in_case_scope() {
8068 let src = r#"
8069import gleam/io
8070
8071pub fn main(x) {
8072 case x {
8073 True -> {
8074 let message = "Hello!"
8075 io.println(message)
8076 }
8077 False -> Nil
8078 }
8079}
8080"#;
8081 assert_code_action!(
8082 INLINE_VARIABLE,
8083 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8084 find_position_of("message =").to_selection()
8085 );
8086}
8087
8088#[test]
8089fn no_code_action_to_inline_variable_used_multiple_times() {
8090 let src = r#"
8091import gleam/io
8092
8093pub fn main() {
8094 let message = "Hello!"
8095 io.println(message)
8096 io.debug(message)
8097}
8098"#;
8099 assert_no_code_actions!(
8100 INLINE_VARIABLE,
8101 TestProject::for_source(src).add_module(
8102 "gleam/io",
8103 "pub fn println(value) {} pub fn debug(value) {}"
8104 ),
8105 find_position_of("message =").to_selection()
8106 );
8107}
8108
8109#[test]
8110fn no_code_action_to_inline_variable_defined_in_complex_pattern() {
8111 let src = r#"
8112import gleam/io
8113
8114pub fn main() {
8115 let #(message, second, _) = todo
8116 io.println(message)
8117}
8118"#;
8119 assert_no_code_actions!(
8120 INLINE_VARIABLE,
8121 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8122 find_position_of("message)").to_selection()
8123 );
8124}
8125
8126#[test]
8127fn no_code_action_to_inline_variable_defined_in_case_clause() {
8128 let src = r#"
8129import gleam/io
8130
8131pub fn main(result) {
8132 case result {
8133 Ok(value) -> value
8134 Error(message) -> {
8135 io.println(message)
8136 panic
8137 }
8138 }
8139}
8140"#;
8141 assert_no_code_actions!(
8142 INLINE_VARIABLE,
8143 TestProject::for_source(src).add_module("gleam/io", "pub fn println(value) {}"),
8144 find_position_of("message").nth_occurrence(2).to_selection()
8145 );
8146}
8147
8148#[test]
8149fn convert_to_pipe_with_function_call_on_first_argument() {
8150 assert_code_action!(
8151 CONVERT_TO_PIPE,
8152 "
8153pub fn main() {
8154 wibble(wobble, woo)
8155}
8156",
8157 find_position_of("wobble").to_selection()
8158 );
8159}
8160
8161#[test]
8162fn convert_to_pipe_with_function_call_on_second_argument() {
8163 assert_code_action!(
8164 CONVERT_TO_PIPE,
8165 "
8166pub fn main() {
8167 wibble(wobble, woo)
8168}
8169",
8170 find_position_of("woo").to_selection()
8171 );
8172}
8173
8174#[test]
8175fn convert_to_pipe_with_function_call_on_function_name_extracts_first_argument() {
8176 assert_code_action!(
8177 CONVERT_TO_PIPE,
8178 "
8179pub fn main() {
8180 wibble(wobble, woo)
8181}
8182",
8183 find_position_of("wibble").to_selection()
8184 );
8185}
8186
8187#[test]
8188fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole() {
8189 assert_code_action!(
8190 CONVERT_TO_PIPE,
8191 "
8192pub fn main() {
8193 wibble(wobble: 1, woo: 2)
8194}
8195",
8196 find_position_of("wobble").to_selection()
8197 );
8198}
8199
8200#[test]
8201fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole_2() {
8202 assert_code_action!(
8203 CONVERT_TO_PIPE,
8204 "
8205pub fn main() {
8206 wibble(wobble: 1, woo: 2)
8207}
8208",
8209 find_position_of("woo").to_selection()
8210 );
8211}
8212
8213#[test]
8214fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole() {
8215 assert_code_action!(
8216 CONVERT_TO_PIPE,
8217 "
8218pub fn main() {
8219 wibble(wobble:, woo:)
8220}
8221",
8222 find_position_of("wobble").to_selection()
8223 );
8224}
8225
8226#[test]
8227fn convert_to_pipe_with_function_call_with_shorthand_labelled_argument_inserts_hole_2() {
8228 assert_code_action!(
8229 CONVERT_TO_PIPE,
8230 "
8231pub fn main() {
8232 wibble(wobble:, woo:)
8233}
8234",
8235 find_position_of("woo").to_selection()
8236 );
8237}
8238
8239#[test]
8240fn convert_to_pipe_on_first_step_of_pipeline() {
8241 assert_code_action!(
8242 CONVERT_TO_PIPE,
8243 "
8244pub fn main() {
8245 wibble(wobble, woo) |> wobble
8246}
8247",
8248 find_position_of("wibble").to_selection()
8249 );
8250}
8251
8252#[test]
8253fn convert_to_pipe_not_allowed_on_other_pipeline_steps() {
8254 assert_no_code_actions!(
8255 CONVERT_TO_PIPE,
8256 "
8257pub fn main() {
8258 wibble(wobble) |> wobble(woo)
8259}
8260",
8261 find_position_of("woo").to_selection()
8262 );
8263}
8264
8265#[test]
8266fn convert_to_pipe_with_function_returning_other_function() {
8267 assert_code_action!(
8268 CONVERT_TO_PIPE,
8269 "
8270pub fn main() {
8271 wibble(wobble)(woo)
8272}
8273",
8274 find_position_of("woo").to_selection()
8275 );
8276}
8277
8278#[test]
8279fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use() {
8280 assert_no_code_actions!(
8281 CONVERT_TO_PIPE,
8282 "
8283pub fn main() {
8284 use <- wibble(wobble)
8285 todo
8286}
8287",
8288 find_position_of("wibble").to_selection()
8289 );
8290}
8291
8292#[test]
8293fn convert_to_pipe_does_not_work_on_function_on_the_right_hand_side_of_use_2() {
8294 assert_no_code_actions!(
8295 CONVERT_TO_PIPE,
8296 "
8297pub fn main() {
8298 use <- wibble(wobble)
8299 todo
8300}
8301",
8302 find_position_of("todo").to_selection()
8303 );
8304}
8305
8306#[test]
8307fn convert_to_pipe_does_not_work_on_function_with_capture() {
8308 assert_no_code_actions!(
8309 CONVERT_TO_PIPE,
8310 "import gleam/int
8311
8312pub fn main() {
8313 let sum = int.add(1, _)
8314 sum
8315}
8316",
8317 find_position_of("1").to_selection()
8318 );
8319}
8320
8321#[test]
8322fn convert_to_pipe_does_not_work_on_record_with_capture() {
8323 assert_no_code_actions!(
8324 CONVERT_TO_PIPE,
8325 "pub fn main() {
8326 Ok(_)
8327}
8328",
8329 find_position_of("O").to_selection()
8330 );
8331}
8332
8333#[test]
8334fn convert_to_pipe_works_inside_body_of_use() {
8335 assert_code_action!(
8336 CONVERT_TO_PIPE,
8337 "
8338pub fn main() {
8339 use <- wibble(wobble)
8340 woo(123)
8341}
8342",
8343 find_position_of("woo").to_selection()
8344 );
8345}
8346
8347#[test]
8348fn convert_to_pipe_pipes_the_outermost_argument() {
8349 assert_code_action!(
8350 CONVERT_TO_PIPE,
8351 "
8352pub fn main() {
8353 wibble(wobble(woo))
8354}
8355",
8356 find_position_of("wobble").to_selection()
8357 );
8358}
8359
8360#[test]
8361fn convert_to_pipe_when_first_arg_is_a_pipe_itself() {
8362 assert_code_action!(
8363 CONVERT_TO_PIPE,
8364 "
8365pub fn main() {
8366 wibble(wobble |> woo, waa)
8367}
8368",
8369 find_position_of("wibble").to_selection()
8370 );
8371}
8372
8373#[test]
8374fn convert_to_pipe_with_string_concat_adds_braces() {
8375 assert_code_action!(
8376 CONVERT_TO_PIPE,
8377 "
8378pub fn main() {
8379 wibble(wobble <> woo, waa)
8380}
8381",
8382 find_position_of("wibble").to_selection()
8383 );
8384}
8385
8386#[test]
8387fn convert_to_pipe_with_bool_operator_adds_braces() {
8388 assert_code_action!(
8389 CONVERT_TO_PIPE,
8390 "
8391pub fn main() {
8392 wibble(wobble != woo, waa)
8393}
8394",
8395 find_position_of("wibble").to_selection()
8396 );
8397}
8398
8399#[test]
8400fn convert_to_pipe_with_sum_adds_no_braces() {
8401 assert_code_action!(
8402 CONVERT_TO_PIPE,
8403 "
8404pub fn main() {
8405 wibble(1 + 1, waa)
8406}
8407",
8408 find_position_of("wibble").to_selection()
8409 );
8410}
8411
8412#[test]
8413fn convert_to_pipe_with_comparison_adds_braces() {
8414 assert_code_action!(
8415 CONVERT_TO_PIPE,
8416 "
8417pub fn main() {
8418 wibble(1.0 >=. 0.0, waa)
8419}
8420",
8421 find_position_of("wibble").to_selection()
8422 );
8423}
8424
8425#[test]
8426fn convert_to_pipe_with_complex_binop_adds_braces() {
8427 assert_code_action!(
8428 CONVERT_TO_PIPE,
8429 "
8430fn bug() {
8431 bool.guard(1 == 2 || 2 == 3, Nil, fn() { Nil })
8432}
8433",
8434 find_position_of("||").to_selection()
8435 );
8436}
8437
8438// https://github.com/gleam-lang/gleam/issues/4342
8439#[test]
8440fn inline_variable_in_record_update() {
8441 assert_code_action!(
8442 INLINE_VARIABLE,
8443 "
8444type Couple {
8445 Couple(l: Int, r: Int)
8446}
8447
8448pub fn main() {
8449 let c1 = Couple(l: 1, r: 1)
8450 let c2 = Couple(..c1, r: 1)
8451}
8452",
8453 find_position_of("c1,").to_selection()
8454 );
8455}
8456
8457// https://github.com/gleam-lang/gleam/issues/4430
8458#[test]
8459fn inline_variable_with_record_field() {
8460 assert_code_action!(
8461 INLINE_VARIABLE,
8462 "
8463type Couple {
8464 Couple(l: Int, r: Int)
8465}
8466
8467pub fn main() {
8468 let c1 = Couple(l: 1, r: 1)
8469 let c2 = c1.l
8470 echo c2
8471}
8472",
8473 find_position_of("c2").nth_occurrence(2).to_selection()
8474 );
8475}
8476
8477#[test]
8478fn wrap_case_clause_in_block() {
8479 assert_code_action!(
8480 WRAP_IN_BLOCK,
8481 "
8482pub fn f(option) {
8483 case option {
8484 Some(content) -> content
8485 None -> panic
8486 }
8487}",
8488 find_position_of("content").nth_occurrence(2).to_selection()
8489 );
8490}
8491
8492#[test]
8493fn wrap_nested_case_clause_in_block() {
8494 assert_code_action!(
8495 WRAP_IN_BLOCK,
8496 "
8497pub fn f(result) {
8498 case result {
8499 Ok(reresult) -> {
8500 case reresult {
8501 Ok(w) -> w
8502 Error(_) -> panic
8503 }
8504 }
8505 Error(_) -> panic
8506 }
8507}",
8508 find_position_of("w").nth_occurrence(2).to_selection()
8509 );
8510}
8511
8512#[test]
8513fn wrap_case_clause_with_guard_in_block() {
8514 assert_code_action!(
8515 WRAP_IN_BLOCK,
8516 "
8517pub fn f(option) {
8518 case option {
8519 Some(integer) if integer > 0 -> integer
8520 Some(integer) -> 0
8521 None -> panic
8522 }
8523}",
8524 find_position_of("integer").nth_occurrence(3).to_selection()
8525 );
8526}
8527
8528#[test]
8529fn wrap_case_clause_with_multiple_patterns_in_block() {
8530 assert_code_action!(
8531 WRAP_IN_BLOCK,
8532 "pub type PokemonType {
8533 Air
8534 Water
8535 Fire
8536}
8537
8538 pub fn f(pokemon_type: PokemonType) {
8539 case pokemon_type {
8540 Water | Air -> soak()
8541 Fire -> burn()
8542 }
8543 }",
8544 find_position_of("soak").to_selection()
8545 );
8546}
8547
8548#[test]
8549fn wrap_case_clause_inside_assignment_in_block() {
8550 assert_code_action!(
8551 WRAP_IN_BLOCK,
8552 r#"pub type PokemonType {
8553 Air
8554 Water
8555 Fire
8556}
8557
8558 pub fn f(pokemon_type: PokemonType) {
8559 let damage = case pokemon_type {
8560 Water -> soak()
8561 Fire -> burn()
8562 }
8563
8564 "Pokemon did " <> damage
8565 }"#,
8566 find_position_of("burn").to_selection()
8567 );
8568}
8569
8570#[test]
8571fn wrap_case_assignment_of_record_access_in_block() {
8572 assert_code_action!(
8573 WRAP_IN_BLOCK,
8574 r#"
8575pub type Record {
8576 R(left: Int, right: Int)
8577}
8578
8579pub fn main() {
8580 let r = R(1, 2)
8581 let l = r.left
8582 l
8583}
8584"#,
8585 find_position_of("left").nth_occurrence(2).to_selection()
8586 );
8587}
8588
8589#[test]
8590fn do_not_wrap_case_clause_in_block_1() {
8591 assert_no_code_actions!(
8592 WRAP_IN_BLOCK,
8593 "
8594pub fn f(option) {
8595 case option {
8596 Some(content) -> {
8597 content
8598 }
8599 None -> panic
8600 }
8601}",
8602 find_position_of("content").nth_occurrence(2).to_selection()
8603 );
8604}
8605
8606#[test]
8607fn do_not_wrap_case_clause_in_block_2() {
8608 assert_no_code_actions!(
8609 WRAP_IN_BLOCK,
8610 "
8611pub fn f(result) {
8612 case result {
8613 Ok(reresult) -> {
8614 case reresult {
8615 Ok(w) -> {
8616 w
8617 }
8618 Error(_) -> panic
8619 }
8620 }
8621 Error(_) -> panic
8622 }
8623}",
8624 find_position_of("w").nth_occurrence(2).to_selection()
8625 );
8626}
8627
8628#[test]
8629fn do_not_wrap_case_clause_in_block_3() {
8630 assert_no_code_actions!(
8631 WRAP_IN_BLOCK,
8632 "
8633pub fn f(option) {
8634 case option {
8635 Some(content) -> content
8636 None -> panic
8637 }
8638}",
8639 find_position_of("Some(content)").to_selection()
8640 );
8641}
8642
8643#[test]
8644fn wrap_assignment_value_in_block() {
8645 assert_code_action!(
8646 WRAP_IN_BLOCK,
8647 r#"pub fn main() {
8648 let var = "value"
8649}"#,
8650 find_position_of("value").select_until(find_position_of("e").nth_occurrence(2))
8651 );
8652}
8653
8654#[test]
8655fn do_not_wrap_assignment_value_in_block() {
8656 assert_no_code_actions!(
8657 WRAP_IN_BLOCK,
8658 r#"pub fn main() {
8659 let var = "value"
8660}"#,
8661 find_position_of("var").to_selection()
8662 );
8663}
8664
8665// https://github.com/gleam-lang/gleam/issues/4427
8666#[test]
8667fn extract_constant_function() {
8668 assert_no_code_actions!(
8669 EXTRACT_CONSTANT,
8670 r#"
8671fn print(x) {
8672 Nil
8673}
8674
8675pub fn main() {
8676 print("Hello")
8677}
8678"#,
8679 find_position_of("print").nth_occurrence(2).to_selection()
8680 );
8681}
8682
8683#[test]
8684fn fix_float_operator_on_ints() {
8685 let name = "Use `>=`";
8686 assert_code_action!(
8687 name,
8688 r#"
8689pub fn main() {
8690 1 >=. 2
8691}
8692"#,
8693 find_position_of("1").to_selection()
8694 );
8695}
8696
8697#[test]
8698fn fix_float_operator_on_ints_2() {
8699 let name = "Use `-`";
8700 assert_code_action!(
8701 name,
8702 r#"
8703pub fn main() {
8704 1 -. 2
8705}
8706"#,
8707 find_position_of("1").select_until(find_position_of("2"))
8708 );
8709}
8710
8711#[test]
8712fn fix_float_operator_on_ints_3() {
8713 let name = "Use `*`";
8714 assert_code_action!(
8715 name,
8716 r#"
8717pub fn main() {
8718 1 *. wobble()
8719}
8720
8721fn wobble() { 3 }
8722"#,
8723 find_position_of("*.").to_selection()
8724 );
8725}
8726
8727#[test]
8728fn fix_int_operator_on_floats() {
8729 let name = "Use `>=.`";
8730 assert_code_action!(
8731 name,
8732 r#"
8733pub fn main() {
8734 1.0 >= 2.3
8735}
8736"#,
8737 find_position_of("1").to_selection()
8738 );
8739}
8740
8741#[test]
8742fn fix_int_operator_on_floats_2() {
8743 let name = "Use `-.`";
8744 assert_code_action!(
8745 name,
8746 r#"
8747pub fn main() {
8748 1.12 - 2.0
8749}
8750"#,
8751 find_position_of("1").select_until(find_position_of("2.0"))
8752 );
8753}
8754
8755#[test]
8756fn fix_int_operator_on_floats_3() {
8757 let name = "Use `*.`";
8758 assert_code_action!(
8759 name,
8760 r#"
8761pub fn main() {
8762 1.3 * wobble()
8763}
8764
8765fn wobble() { 3.2 }
8766"#,
8767 find_position_of("*").to_selection()
8768 );
8769}
8770
8771#[test]
8772fn fix_plus_operator_on_strings() {
8773 let name = "Use `<>`";
8774 assert_code_action!(
8775 name,
8776 r#"
8777pub fn main() {
8778 "hello, " + name()
8779}
8780
8781fn name() { "Jak" }
8782"#,
8783 find_position_of("hello").select_until(find_position_of("name()"))
8784 );
8785}
8786
8787// https://github.com/gleam-lang/gleam/issues/4454
8788#[test]
8789fn unqualify_already_imported_type() {
8790 let src = "
8791import wibble.{type Wibble}
8792
8793pub fn main() -> wibble.Wibble {
8794 todo
8795}
8796";
8797
8798 assert_code_action!(
8799 "Unqualify wibble.Wibble",
8800 TestProject::for_source(src).add_hex_module("wibble", "pub type Wibble"),
8801 find_position_of("wibble.Wibble").to_selection(),
8802 );
8803}
8804
8805#[test]
8806fn fill_labels_pattern_constructor() {
8807 assert_code_action!(
8808 FILL_LABELS,
8809 "
8810pub type Wibble {
8811 Wibble(a: Int, b: Float, c: String)
8812 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))
8813}
8814
8815pub fn main(w: Wibble) {
8816 case w {
8817 Wibble(..) -> todo
8818 Wobble() -> todo
8819 }
8820}
8821",
8822 find_position_of("Wobble()").to_selection(),
8823 );
8824}
8825
8826#[test]
8827fn fill_labels_pattern_constructor_let_assignment() {
8828 assert_code_action!(
8829 FILL_LABELS,
8830 "
8831pub type Wibble {
8832 Wibble(a: Int, b: Float, c: String)
8833}
8834
8835pub fn main() {
8836 let Wibble() = todo
8837}
8838",
8839 find_position_of("Wibble()").to_selection(),
8840 );
8841}
8842
8843#[test]
8844fn fill_labels_pattern_constructor_with_some_labels() {
8845 assert_code_action!(
8846 FILL_LABELS,
8847 "
8848pub type Wibble {
8849 Wibble(a: Int, b: Float, c: String)
8850 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))
8851}
8852
8853pub fn main(w: Wibble) {
8854 case w {
8855 Wobble(e: <<>>) -> todo
8856 _ -> todo
8857 }
8858}
8859",
8860 find_position_of("Wobble(e").to_selection(),
8861 );
8862}
8863
8864#[test]
8865fn fill_labels_nested_pattern_constructor() {
8866 assert_code_action!(
8867 FILL_LABELS,
8868 "
8869pub type Wibble {
8870 Wibble(a: Int, b: Float, c: String)
8871 Wobble(d: Bool, e: BitArray, f: List(Result(String, Nil)))
8872}
8873
8874pub fn main() {
8875 case todo {
8876 #([Wobble()], 2, 3) -> todo
8877 _ -> todo
8878 }
8879}
8880",
8881 find_position_of("Wobble()").to_selection(),
8882 );
8883}
8884
8885#[test]
8886// https://github.com/gleam-lang/gleam/issues/4499
8887fn fill_labels_with_function_with_unlabelled_arguments() {
8888 assert_no_code_actions!(
8889 FILL_LABELS,
8890 "
8891pub fn main() {
8892 fold(0, over: [], with: fn(acc, item) { acc + item })
8893}
8894
8895pub fn fold(over list, from initial, with fun) { todo }",
8896 find_position_of("fold").to_selection(),
8897 );
8898}
8899
8900#[test]
8901fn add_missing_patterns_with_labels() {
8902 assert_code_action!(
8903 ADD_MISSING_PATTERNS,
8904 "
8905pub type Wibble {
8906 Wibble(integer: Int, float: Float)
8907 Wobble(string: String, bool: Bool)
8908}
8909
8910pub fn main(w: Wibble) {
8911 case w {}
8912}
8913",
8914 find_position_of("case w").select_until(find_position_of("{}")),
8915 );
8916}
8917
8918// https://github.com/gleam-lang/gleam/issues/3628#issuecomment-2543342212
8919#[test]
8920fn add_missing_patterns_multibyte_grapheme() {
8921 assert_code_action!(
8922 ADD_MISSING_PATTERNS,
8923 r#"
8924// ä
8925fn wibble() {
8926 case True {}
8927}
8928"#,
8929 find_position_of("case").select_until(find_position_of("True {"))
8930 );
8931}
8932
8933// https://github.com/gleam-lang/gleam/issues/4626
8934#[test]
8935fn add_missing_patterns_opaque_type() {
8936 let src = "
8937import mod
8938
8939pub fn main(w: mod.Wibble) {
8940 case w {}
8941}
8942";
8943
8944 assert_code_action!(
8945 ADD_MISSING_PATTERNS,
8946 TestProject::for_source(src).add_hex_module(
8947 "mod",
8948 "pub opaque type Wibble { Wibble(Int) Wobble(String) }"
8949 ),
8950 find_position_of("{}").to_selection(),
8951 );
8952}
8953
8954// https://github.com/gleam-lang/gleam/issues/4653
8955#[test]
8956fn generate_function_capture() {
8957 assert_code_action!(
8958 GENERATE_FUNCTION,
8959 "
8960fn map(list: List(a), f: fn(a) -> b) -> List(b) {
8961 todo
8962}
8963
8964pub fn main() {
8965 map([1, 2, 3], add(_, 1))
8966}
8967",
8968 find_position_of("add").to_selection()
8969 );
8970}
8971
8972// https://github.com/gleam-lang/gleam/issues/4660#issuecomment-2932371619
8973#[test]
8974fn inline_variable_label_shorthand() {
8975 assert_code_action!(
8976 INLINE_VARIABLE,
8977 "
8978pub type Example {
8979 Example(sum: Int, nil: Nil)
8980}
8981
8982pub fn main() {
8983 let sum = 1 + 1
8984
8985 Example(Nil, sum:)
8986}
8987",
8988 find_position_of("sum = ").to_selection()
8989 );
8990}
8991
8992// https://github.com/gleam-lang/gleam/issues/4660
8993#[test]
8994fn no_inline_variable_action_for_parameter() {
8995 assert_no_code_actions!(
8996 INLINE_VARIABLE,
8997 "
8998pub fn main() {
8999 let x = fn(something) {
9000 something
9001 }
9002
9003 x
9004}
9005",
9006 find_position_of("something")
9007 .nth_occurrence(2)
9008 .to_selection()
9009 );
9010}
9011
9012#[test]
9013fn no_inline_variable_action_when_spanning_multiple_items() {
9014 assert_no_code_actions!(
9015 INLINE_VARIABLE,
9016 "
9017pub fn main(x: Int, y: Int) {
9018 let a = 1
9019 let b = 2
9020 main(a, b)
9021}
9022",
9023 find_position_of("main")
9024 .nth_occurrence(2)
9025 .select_until(find_position_of(")").nth_occurrence(2))
9026 );
9027}
9028
9029#[test]
9030fn no_inline_variable_action_for_use_pattern() {
9031 assert_no_code_actions!(
9032 INLINE_VARIABLE,
9033 "
9034pub fn main() {
9035 let x = {
9036 use something <- todo
9037 something
9038 }
9039
9040 x
9041}
9042",
9043 find_position_of("something").to_selection()
9044 );
9045}
9046
9047#[test]
9048fn no_inline_variable_action_for_case_pattern() {
9049 assert_no_code_actions!(
9050 INLINE_VARIABLE,
9051 "
9052pub fn main() {
9053 let x = case todo {
9054 something -> something
9055 }
9056
9057 x
9058}
9059",
9060 find_position_of("something")
9061 .nth_occurrence(2)
9062 .to_selection()
9063 );
9064}
9065
9066// https://github.com/gleam-lang/gleam/issues/4675
9067#[test]
9068fn extract_variable_use() {
9069 assert_no_code_actions!(
9070 EXTRACT_VARIABLE,
9071 "
9072pub fn main() {
9073 #({
9074 use <- todo
9075 todo
9076 })
9077}
9078 ",
9079 find_position_of("use").to_selection()
9080 );
9081}
9082
9083// https://github.com/gleam-lang/gleam/issues/4739
9084#[test]
9085fn do_not_import_internal_modules() {
9086 const IMPORT_MODULE: &str = "Import `package/internal`";
9087 let code = "
9088pub fn main() {
9089 internal.some_internal_function()
9090}
9091";
9092
9093 assert_no_code_actions!(
9094 IMPORT_MODULE,
9095 TestProject::for_source(code).add_package_module(
9096 "package",
9097 "package/internal",
9098 "pub fn some_internal_function() { todo }"
9099 ),
9100 find_position_of("internal").to_selection()
9101 );
9102}
9103
9104#[test]
9105fn import_internal_module_from_same_package() {
9106 let code = "
9107pub fn main() {
9108 internal.some_internal_function()
9109}
9110";
9111
9112 assert_code_action!(
9113 "Import `app/internal`",
9114 TestProject::for_source(code).add_package_module(
9115 "app",
9116 "app/internal",
9117 "pub fn some_internal_function() { todo }"
9118 ),
9119 find_position_of("internal").to_selection()
9120 );
9121}
9122
9123#[test]
9124fn remove_block_1() {
9125 assert_code_action!(
9126 REMOVE_BLOCK,
9127 "pub fn main() {
9128 { 1 }
9129}
9130",
9131 find_position_of("1").to_selection()
9132 );
9133}
9134
9135#[test]
9136fn remove_block_2() {
9137 assert_code_action!(
9138 REMOVE_BLOCK,
9139 "pub fn main() {
9140 { main() <> 2 }
9141}
9142",
9143 find_position_of("}").to_selection()
9144 );
9145}
9146
9147#[test]
9148fn remove_block_3() {
9149 assert_code_action!(
9150 REMOVE_BLOCK,
9151 "pub fn main() {
9152 case 1 {
9153 _ -> { main() <> 2 }
9154 }
9155}
9156",
9157 find_position_of("{").nth_occurrence(3).to_selection()
9158 );
9159}
9160
9161#[test]
9162fn remove_block_triggers_on_the_innermost_selected_block() {
9163 assert_code_action!(
9164 REMOVE_BLOCK,
9165 "pub fn main(x) {
9166 {
9167 main({
9168 1
9169 })
9170 }
9171}
9172",
9173 find_position_of("1").to_selection()
9174 );
9175}
9176
9177#[test]
9178fn remove_block_does_not_unwrap_a_let_assignment() {
9179 assert_no_code_actions!(
9180 REMOVE_BLOCK,
9181 "pub fn main(x) {
9182 {
9183 let a = 1
9184 }
9185}
9186",
9187 find_position_of("let").to_selection()
9188 );
9189}
9190
9191#[test]
9192fn remove_block_unwraps_a_single_expression_in_a_binop() {
9193 assert_code_action!(
9194 REMOVE_BLOCK,
9195 "pub fn main(x) {
9196 { main(1) } * 3
9197}
9198",
9199 find_position_of("main").nth_occurrence(2).to_selection()
9200 );
9201}
9202
9203#[test]
9204fn remove_block_does_not_unwrap_a_binop() {
9205 assert_no_code_actions!(
9206 REMOVE_BLOCK,
9207 "pub fn main(x) {
9208 { 1 * 2 } + 3
9209}
9210",
9211 find_position_of("1").to_selection()
9212 );
9213}
9214
9215#[test]
9216fn remove_block_does_not_unwrap_a_block_with_multiple_statements() {
9217 assert_no_code_actions!(
9218 REMOVE_BLOCK,
9219 "pub fn main(x) {
9220 {
9221 main(1)
9222 main(2)
9223 }
9224}
9225",
9226 find_position_of("1").to_selection()
9227 );
9228}
9229
9230#[test]
9231fn remove_opaque_from_private_type() {
9232 assert_code_action!(
9233 REMOVE_OPAQUE_FROM_PRIVATE_TYPE,
9234 "opaque type Wibble {
9235 Wobble
9236}
9237",
9238 find_position_of("Wibble").to_selection()
9239 );
9240}
9241
9242#[test]
9243fn allow_further_pattern_matching_on_let_tuple_destructuring() {
9244 assert_code_action!(
9245 PATTERN_MATCH_ON_VARIABLE,
9246 "pub fn main(x) {
9247 let #(one, other) = #(Ok(1), Error(Nil))
9248}
9249",
9250 find_position_of("one").to_selection()
9251 );
9252}
9253
9254#[test]
9255fn allow_further_pattern_matching_on_let_record_destructuring() {
9256 assert_code_action!(
9257 PATTERN_MATCH_ON_VARIABLE,
9258 "pub fn main(x) {
9259 let Wibble(field:) = Wibble(Ok(Nil))
9260}
9261
9262pub type Wibble { Wibble(field: Result(Nil, String)) }
9263",
9264 find_position_of("field").to_selection()
9265 );
9266}
9267
9268#[test]
9269fn allow_further_pattern_matching_on_asserted_result() {
9270 assert_code_action!(
9271 PATTERN_MATCH_ON_VARIABLE,
9272 "pub fn main(x) {
9273 let assert Ok(one) = Ok(Error(Nil))
9274}
9275",
9276 find_position_of("one").to_selection()
9277 );
9278}
9279
9280#[test]
9281fn allow_further_pattern_matching_on_asserted_list() {
9282 assert_code_action!(
9283 PATTERN_MATCH_ON_VARIABLE,
9284 "pub fn main(x) {
9285 let assert [first, ..] = [Ok(Nil), ..todo]
9286 todo
9287}
9288",
9289 find_position_of("first").to_selection()
9290 );
9291}
9292
9293#[test]
9294fn pattern_match_on_list_variable() {
9295 assert_code_action!(
9296 PATTERN_MATCH_ON_ARGUMENT,
9297 "pub fn main(a_list: List(a)) {
9298 todo
9299}",
9300 find_position_of("a_list").to_selection()
9301 );
9302}
9303
9304#[test]
9305fn collapse_nested_case() {
9306 assert_code_action!(
9307 COLLAPSE_NESTED_CASE,
9308 "pub fn main(x) {
9309 case x {
9310 Ok(var) -> case var {
9311 1 -> 2
9312 2 -> 4
9313 _ -> -1
9314 }
9315 _ -> todo
9316 }
9317}",
9318 find_position_of("var").to_selection()
9319 );
9320}
9321
9322#[test]
9323fn collapse_nested_case_works_with_blocks() {
9324 assert_code_action!(
9325 COLLAPSE_NESTED_CASE,
9326 "pub fn main(x) {
9327 case x {
9328 Ok(var) -> {
9329 case var {
9330 1 -> 2
9331 2 -> 4
9332 _ -> -1
9333 }
9334 }
9335 _ -> todo
9336 }
9337}",
9338 find_position_of("var").to_selection()
9339 );
9340}
9341
9342#[test]
9343fn collapse_nested_case_works_with_patterns_defining_multiple_variables() {
9344 assert_code_action!(
9345 COLLAPSE_NESTED_CASE,
9346 "pub fn main(x) {
9347 case x {
9348 Wibble(var, var2) ->
9349 case var {
9350 1 -> 2
9351 2 -> 4
9352 _ -> -1
9353 }
9354
9355 Wobble -> todo
9356 }
9357}
9358
9359pub type Wibble {
9360 Wibble(Int, String)
9361 Wobble
9362}
9363",
9364 find_position_of("var").to_selection()
9365 );
9366}
9367
9368#[test]
9369fn collapse_nested_case_does_not_remove_labels() {
9370 assert_code_action!(
9371 COLLAPSE_NESTED_CASE,
9372 "pub fn main(x) {
9373 case x {
9374 Wibble(field2:, field: wibble) ->
9375 case wibble {
9376 1 -> 2
9377 2 -> 4
9378 _ -> -1
9379 }
9380
9381 Wobble -> todo
9382 }
9383}
9384
9385pub type Wibble {
9386 Wibble(field: Int, field2: String)
9387 Wobble
9388}
9389",
9390 find_position_of("field").to_selection()
9391 );
9392}
9393
9394#[test]
9395fn collapse_nested_case_does_not_remove_labels_with_shorthand_syntax() {
9396 assert_code_action!(
9397 COLLAPSE_NESTED_CASE,
9398 "pub fn main(x) {
9399 case x {
9400 Wibble(field2:, field:) ->
9401 case field {
9402 1 -> 2
9403 2 -> 4
9404 _ -> -1
9405 }
9406
9407 Wobble -> todo
9408 }
9409}
9410
9411pub type Wibble {
9412 Wibble(field: Int, field2: String)
9413 Wobble
9414}
9415",
9416 find_position_of("field").to_selection()
9417 );
9418}
9419
9420#[test]
9421fn collapse_nested_case_works_with_alternative_patterns() {
9422 assert_code_action!(
9423 COLLAPSE_NESTED_CASE,
9424 "pub fn main(x) {
9425 case x {
9426 [first, ..rest] ->
9427 case first {
9428 1 | 2 -> True
9429 3 | 4 | 5 -> False
9430 _ -> False
9431 }
9432
9433 [] -> True
9434 }
9435}
9436",
9437 find_position_of("first").to_selection()
9438 );
9439}
9440
9441#[test]
9442fn collapse_nested_case_aliases_variable_if_it_is_used() {
9443 assert_code_action!(
9444 COLLAPSE_NESTED_CASE,
9445 "pub fn main(x) {
9446 case x {
9447 [first, ..rest] ->
9448 case first {
9449 1 | 2 -> first
9450 3 | 4 | 5 -> 5
9451 _ -> 0
9452 }
9453
9454 [] -> -1
9455 }
9456}
9457",
9458 find_position_of("first").to_selection()
9459 );
9460}
9461
9462#[test]
9463fn collapse_nested_case_does_not_ignore_outer_guards() {
9464 assert_code_action!(
9465 COLLAPSE_NESTED_CASE,
9466 "pub fn main(x) {
9467 case x {
9468 [first, ..rest] if True ->
9469 case first {
9470 1 -> 1.1
9471 _ -> 0.0 *. 10.0
9472 }
9473
9474 [] -> 1.1
9475 }
9476}
9477",
9478 find_position_of("first").to_selection()
9479 );
9480}
9481
9482#[test]
9483fn collapse_nested_case_does_not_ignore_inner_guards() {
9484 assert_code_action!(
9485 COLLAPSE_NESTED_CASE,
9486 "pub fn main(x) {
9487 case x {
9488 [first, ..rest] ->
9489 case first {
9490 1 -> 1.1
9491 _ if True -> 0.0 *. 10.0
9492 _ -> 0.0
9493 }
9494
9495 [] -> 1.1
9496 }
9497}
9498",
9499 find_position_of("first").to_selection()
9500 );
9501}
9502
9503#[test]
9504fn collapse_nested_case_combines_inner_and_outer_guards() {
9505 assert_code_action!(
9506 COLLAPSE_NESTED_CASE,
9507 "pub fn main(x) {
9508 case x {
9509 [first, ..rest] if False ->
9510 case first {
9511 1 if False -> 1.1
9512 _ if True -> 0.0 *. 10.0
9513 _ -> 0.0
9514 }
9515
9516 [] -> 1.1
9517 }
9518}
9519",
9520 find_position_of("first").to_selection()
9521 );
9522}
9523
9524#[test]
9525fn collapse_nested_case_combines_inner_and_outer_guards_and_adds_parentheses_when_needed() {
9526 assert_code_action!(
9527 COLLAPSE_NESTED_CASE,
9528 "pub fn main(x) {
9529 case x {
9530 [first, ..rest] if False || True ->
9531 case first {
9532 1 if False && True -> 1.1
9533 _ if True || False -> 0.0 *. 10.0
9534 _ -> 0.0
9535 }
9536
9537 [] -> 1.1
9538 }
9539}
9540",
9541 find_position_of("first").to_selection()
9542 );
9543}
9544
9545// https://github.com/gleam-lang/gleam/issues/3786
9546#[test]
9547fn type_variables_from_other_functions_do_not_change_annotations() {
9548 assert_code_action!(
9549 ADD_ANNOTATIONS,
9550 "
9551fn wibble(a: a, b: b, c: c) -> d { todo }
9552
9553fn pair(a, b) {
9554 #(a, b)
9555}
9556",
9557 find_position_of("pair").to_selection()
9558 );
9559}
9560
9561#[test]
9562fn type_variables_from_other_functions_do_not_change_annotations_constant() {
9563 assert_code_action!(
9564 ADD_ANNOTATION,
9565 "
9566fn wibble(a: a, b: b, c: c) -> d { todo }
9567
9568const empty = []
9569",
9570 find_position_of("empty").to_selection()
9571 );
9572}
9573
9574#[test]
9575fn type_variables_are_not_duplicated_when_adding_annotations() {
9576 assert_code_action!(
9577 ADD_ANNOTATIONS,
9578 "
9579fn wibble(a: a, b: b, c: c) -> d { todo }
9580
9581fn many_args(a, b, c, d: d, e: a, f, g) {
9582 todo
9583}
9584",
9585 find_position_of("many_args").to_selection()
9586 );
9587}
9588
9589#[test]
9590fn type_variables_in_let_bindings_are_considered_when_adding_annotations() {
9591 assert_code_action!(
9592 ADD_ANNOTATIONS,
9593 "
9594fn wibble(a, b, c) {
9595 let x: a = todo
9596 fn(a: b, b: c) -> d {
9597 todo
9598 }
9599}
9600",
9601 find_position_of("wibble").to_selection()
9602 );
9603}
9604
9605#[test]
9606fn generated_function_annotations_are_not_affected_by_other_functions() {
9607 assert_code_action!(
9608 GENERATE_FUNCTION,
9609 "
9610fn wibble(a: a, b: b, c: c) -> d { todo }
9611
9612pub fn main() {
9613 let x = todo
9614 let y = todo
9615 let #(a, b) = something(x, y)
9616 b
9617}
9618",
9619 find_position_of("something").to_selection()
9620 );
9621}
9622
9623#[test]
9624fn generate_function_in_other_module() {
9625 let src = "
9626import wibble
9627
9628pub fn main() {
9629 wibble.wibble()
9630 wibble.wobble()
9631}
9632";
9633
9634 assert_code_action!(
9635 GENERATE_FUNCTION,
9636 TestProject::for_source(src).add_module("wibble", "pub fn wibble() {}"),
9637 find_position_of("wobble").to_selection()
9638 );
9639}
9640
9641#[test]
9642fn generating_function_in_other_module_uses_local_names() {
9643 let src = r#"
9644import wibble
9645
9646pub fn main() -> List(Nil) {
9647 wibble.wibble(1, #(True, "Hello"))
9648}
9649"#;
9650
9651 assert_code_action!(
9652 GENERATE_FUNCTION,
9653 TestProject::for_source(src).add_module(
9654 "wibble",
9655 "import gleam.{type Int as Number, type Bool as Boolean, type String as Text, type Nil as Nothing}"
9656 ),
9657 find_position_of("wibble(").to_selection()
9658 );
9659}
9660
9661#[test]
9662fn generating_function_in_other_module_uses_labels() {
9663 let src = r#"
9664import wibble
9665
9666pub fn main() {
9667 wibble.wibble("Unlabelled", int: 1, bool: True)
9668}
9669"#;
9670
9671 assert_code_action!(
9672 GENERATE_FUNCTION,
9673 TestProject::for_source(src).add_module("wibble", ""),
9674 find_position_of("wibble(").to_selection()
9675 );
9676}
9677
9678#[test]
9679fn no_code_action_to_generate_existing_function_in_other_module() {
9680 let src = r#"
9681import wibble
9682
9683pub fn main() {
9684 wibble.wibble(1, 2, 3)
9685}
9686"#;
9687
9688 assert_no_code_actions!(
9689 GENERATE_FUNCTION,
9690 TestProject::for_source(src).add_module("wibble", "pub fn wibble(a, b, c) { a + b + c }"),
9691 find_position_of("wibble(").to_selection()
9692 );
9693}
9694
9695#[test]
9696fn do_not_generate_function_in_other_package() {
9697 let src = r#"
9698import maths
9699
9700pub fn main() {
9701 maths.add(1, 2)
9702 maths.subtract(1, 2)
9703}
9704"#;
9705
9706 assert_no_code_actions!(
9707 GENERATE_FUNCTION,
9708 TestProject::for_source(src).add_dep_module("maths", "pub fn add(a, b) { a + b }"),
9709 find_position_of("subtract").to_selection()
9710 );
9711}