Fork of daniellemaywood.uk/gleam — Wasm codegen work
2

Configure Feed

Select the types of activity you want to include in your feed.

fix extract variable action with records

author
Giacomo Cavalieri
committer
Louis Pilfold
date (Apr 26, 2026, 10:54 AM +0100) commit 5508413b parent 34b4178b change-id vksvxurx
+108 -10
+54 -10
language-server/src/code_action.rs
··· 3476 3476 }); 3477 3477 } 3478 3478 3479 + fn visit_typed_expr_call( 3480 + &mut self, 3481 + location: &'ast SrcSpan, 3482 + type_: &'ast Arc<Type>, 3483 + fun: &'ast TypedExpr, 3484 + arguments: &'ast [TypedCallArg], 3485 + open_parenthesis: &'ast Option<u32>, 3486 + ) { 3487 + // Function calls need some extra care. If we're inspecting a record 3488 + // call like this one: `Wibble(wobble, woo)` and the cursor is over the 3489 + // constructor itself we never want to allow extracting it, or it would 3490 + // result in the following code: 3491 + // 3492 + // ```gleam 3493 + // Wibble(wobble, woo) 3494 + // // ^^ Cursor here 3495 + // 3496 + // let wibble = Wibble 3497 + // wibble(wobble, woo) 3498 + // // That's a bit silly! 3499 + // ``` 3500 + let fun_range = self.edits.src_span_to_lsp_range(fun.location()); 3501 + if within(self.params.range, fun_range) && fun.is_record_constructor_function() { 3502 + return; 3503 + } 3504 + 3505 + // Otherwise we just keep visiting like usual, no special handling is 3506 + // required. 3507 + ast::visit::visit_typed_expr_call(self, location, type_, fun, arguments, open_parenthesis); 3508 + } 3509 + 3479 3510 fn visit_typed_expr(&mut self, expr: &'ast TypedExpr) { 3480 3511 let expr_location = expr.location(); 3481 3512 let expr_range = self.edits.src_span_to_lsp_range(expr_location); ··· 3531 3562 return; 3532 3563 } 3533 3564 3534 - // Expressions that don't make sense to extract 3535 - TypedExpr::Panic { .. } 3536 - | TypedExpr::Echo { .. } 3537 - | TypedExpr::Block { .. } 3538 - | TypedExpr::ModuleSelect { .. } 3539 - | TypedExpr::Invalid { .. } 3540 - | TypedExpr::PositionalAccess { .. } 3541 - | TypedExpr::Var { .. } => (), 3542 - 3543 3565 TypedExpr::Int { location, .. } 3544 3566 | TypedExpr::Float { location, .. } 3545 3567 | TypedExpr::String { location, .. } ··· 3556 3578 | TypedExpr::BitArray { location, .. } 3557 3579 | TypedExpr::RecordUpdate { location, .. } 3558 3580 | TypedExpr::NegateBool { location, .. } 3559 - | TypedExpr::NegateInt { location, .. } => { 3581 + | TypedExpr::NegateInt { location, .. } 3582 + // It generally makes no sense to extract variables, the only 3583 + // exception is for records with no fields (like `True` and 3584 + // `False`): in the AST those are `Var`s with a `Record` 3585 + // constructor. Extracting them is allowed! 3586 + | TypedExpr::Var { 3587 + constructor: 3588 + ValueConstructor { 3589 + variant: type_::ValueConstructorVariant::Record { .. }, 3590 + .. 3591 + }, 3592 + location, 3593 + .. 3594 + } => { 3560 3595 if let Some(ExtractVariablePosition::CallArg) = self.position { 3561 3596 // Don't update latest statement, we don't want to insert the extracted 3562 3597 // variable inside the parenthesis where the call argument is located. ··· 3568 3603 name: self.generate_candidate_name(expr.type_()), 3569 3604 }); 3570 3605 } 3606 + 3607 + // Expressions that don't make sense to extract 3608 + TypedExpr::Panic { .. } 3609 + | TypedExpr::Echo { .. } 3610 + | TypedExpr::Block { .. } 3611 + | TypedExpr::ModuleSelect { .. } 3612 + | TypedExpr::Invalid { .. } 3613 + | TypedExpr::PositionalAccess { .. } 3614 + | TypedExpr::Var { .. } => (), 3571 3615 } 3572 3616 3573 3617 ast::visit::visit_typed_expr(self, expr);
+22
language-server/src/tests/action.rs
··· 5696 5696 } 5697 5697 5698 5698 #[test] 5699 + fn extract_can_extract_number_used_as_call_argument() { 5700 + assert_code_action!( 5701 + EXTRACT_VARIABLE, 5702 + r#"pub fn main() { 5703 + wibble(label: 1) 5704 + }"#, 5705 + find_position_of("1").to_selection() 5706 + ); 5707 + } 5708 + 5709 + #[test] 5710 + fn extract_can_extract_bool_used_as_call_argument() { 5711 + assert_code_action!( 5712 + EXTRACT_VARIABLE, 5713 + r#"pub fn main() { 5714 + wibble(label: True) 5715 + }"#, 5716 + find_position_of("True").to_selection() 5717 + ); 5718 + } 5719 + 5720 + #[test] 5699 5721 fn extract_variable_ignores_names_in_other_branches() { 5700 5722 assert_code_action!( 5701 5723 EXTRACT_VARIABLE,
+16
language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_can_extract_bool_used_as_call_argument.snap
··· 1 + --- 2 + source: language-server/src/tests/action.rs 3 + expression: "pub fn main() {\n wibble(label: True)\n}" 4 + --- 5 + ----- BEFORE ACTION 6 + pub fn main() { 7 + wibble(label: True) 8 + 9 + } 10 + 11 + 12 + ----- AFTER ACTION 13 + pub fn main() { 14 + let bool = True 15 + wibble(label: bool) 16 + }
+16
language-server/src/tests/snapshots/gleam_language_server__tests__action__extract_can_extract_number_used_as_call_argument.snap
··· 1 + --- 2 + source: language-server/src/tests/action.rs 3 + expression: "pub fn main() {\n wibble(label: 1)\n}" 4 + --- 5 + ----- BEFORE ACTION 6 + pub fn main() { 7 + wibble(label: 1) 8 + 9 + } 10 + 11 + 12 + ----- AFTER ACTION 13 + pub fn main() { 14 + let int = 1 15 + wibble(label: int) 16 + }