Skip to content

Commit 195c44a

Browse files
giacomocavalierilpil
authored andcommitted
make sure the "turn into pipe" code action is suggested in final step of a pipe
1 parent 499dc4a commit 195c44a

5 files changed

+86
-15
lines changed

CHANGELOG.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@
1919
- Fixed a bug where triggering the "Generate function" code action to generate
2020
a function in a different module could cause the generated function to appear
2121
in the middle of an existing function, resulting in invalid code.
22-
2322
([Surya Rose](https://github.com/GearsDatapacks))
2423

24+
- Fixed a bug where the "turn into pipe" code action would not trigger inside
25+
the final step of a pipeline.
26+
([Giacomo Cavalieri](https://github.com/giacomocavalieri))
27+
2528
## v1.13.0-rc1 - 2025-09-29
2629

2730
### Compiler

compiler-core/src/language_server/code_action.rs

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6292,10 +6292,13 @@ pub struct ConvertToPipe<'a> {
62926292
params: &'a CodeActionParams,
62936293
edits: TextEdits<'a>,
62946294
argument_to_pipe: Option<ConvertToPipeArg<'a>>,
6295-
/// this will be true if we're visiting the call on the right hand side of a
6296-
/// use expression. So we can skip it and not try to turn it into a
6297-
/// function.
6298-
visiting_use_call: bool,
6295+
visited_item: VisitedItem,
6296+
}
6297+
6298+
pub enum VisitedItem {
6299+
RegularExpression,
6300+
UseRightHandSide,
6301+
PipelineFinalStep,
62996302
}
63006303

63016304
/// Holds all the data needed by the "convert to pipe" code action to properly
@@ -6336,7 +6339,7 @@ impl<'a> ConvertToPipe<'a> {
63366339
module,
63376340
params,
63386341
edits: TextEdits::new(line_numbers),
6339-
visiting_use_call: false,
6342+
visited_item: VisitedItem::RegularExpression,
63406343
argument_to_pipe: None,
63416344
}
63426345
}
@@ -6433,13 +6436,16 @@ impl<'ast> ast::visit::Visit<'ast> for ConvertToPipe<'ast> {
64336436
// If we're visiting the typed function produced by typing a use, we
64346437
// skip the thing itself and only visit its arguments and called
64356438
// function, that is the body of the use.
6436-
if self.visiting_use_call {
6437-
self.visiting_use_call = false;
6438-
ast::visit::visit_typed_expr(self, fun);
6439-
arguments
6440-
.iter()
6441-
.for_each(|arg| ast::visit::visit_typed_call_arg(self, arg));
6442-
return;
6439+
match self.visited_item {
6440+
VisitedItem::RegularExpression => (),
6441+
VisitedItem::UseRightHandSide | VisitedItem::PipelineFinalStep => {
6442+
self.visited_item = VisitedItem::RegularExpression;
6443+
ast::visit::visit_typed_expr(self, fun);
6444+
arguments
6445+
.iter()
6446+
.for_each(|arg| ast::visit::visit_typed_call_arg(self, arg));
6447+
return;
6448+
}
64436449
}
64446450

64456451
// We only visit a call if the cursor is somewhere within its location,
@@ -6496,16 +6502,18 @@ impl<'ast> ast::visit::Visit<'ast> for ConvertToPipe<'ast> {
64966502
_location: &'ast SrcSpan,
64976503
first_value: &'ast TypedPipelineAssignment,
64986504
_assignments: &'ast [(TypedPipelineAssignment, PipelineAssignmentKind)],
6499-
_finally: &'ast TypedExpr,
6505+
finally: &'ast TypedExpr,
65006506
_finally_kind: &'ast PipelineAssignmentKind,
65016507
) {
65026508
// We can only apply the action on the first step of a pipeline, so we
65036509
// visit just that one and skip all the others.
65046510
ast::visit::visit_typed_pipeline_assignment(self, first_value);
6511+
self.visited_item = VisitedItem::PipelineFinalStep;
6512+
ast::visit::visit_typed_expr(self, finally);
65056513
}
65066514

65076515
fn visit_typed_use(&mut self, use_: &'ast TypedUse) {
6508-
self.visiting_use_call = true;
6516+
self.visited_item = VisitedItem::UseRightHandSide;
65096517
ast::visit::visit_typed_use(self, use_);
65106518
}
65116519
}

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8393,6 +8393,32 @@ pub fn main() {
83938393
);
83948394
}
83958395

8396+
#[test]
8397+
fn convert_to_pipe_works_in_anonymous_function_inside_a_pipeline() {
8398+
assert_code_action!(
8399+
CONVERT_TO_PIPE,
8400+
"
8401+
pub fn main() {
8402+
wibble |> wobble(fn() { woo(1) })
8403+
}
8404+
",
8405+
find_position_of("woo").to_selection()
8406+
);
8407+
}
8408+
8409+
#[test]
8410+
fn convert_to_pipe_works_in_final_step_of_a_pipeline() {
8411+
assert_code_action!(
8412+
CONVERT_TO_PIPE,
8413+
"
8414+
pub fn main() {
8415+
wibble |> wobble(woo(1))
8416+
}
8417+
",
8418+
find_position_of("woo").to_selection()
8419+
);
8420+
}
8421+
83968422
#[test]
83978423
fn convert_to_pipe_with_function_call_with_labelled_arguments_inserts_hole() {
83988424
assert_code_action!(
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n wibble |> wobble(fn() { woo(1) })\n}\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
wibble |> wobble(fn() { woo(1) })
9+
10+
}
11+
12+
13+
----- AFTER ACTION
14+
15+
pub fn main() {
16+
wibble |> wobble(fn() { 1 |> woo })
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
source: compiler-core/src/language_server/tests/action.rs
3+
expression: "\npub fn main() {\n wibble |> wobble(woo(1))\n}\n"
4+
---
5+
----- BEFORE ACTION
6+
7+
pub fn main() {
8+
wibble |> wobble(woo(1))
9+
10+
}
11+
12+
13+
----- AFTER ACTION
14+
15+
pub fn main() {
16+
wibble |> wobble(1 |> woo)
17+
}

0 commit comments

Comments
 (0)