feat: Allow “Extract variable” to be invoked on field names in record expressions. - #23213
Conversation
| // expression. | ||
| let kind = node.kind(); | ||
| ast::Expr::can_cast(kind) || kind == SyntaxKind::RECORD_EXPR_FIELD | ||
| }) |
There was a problem hiding this comment.
Why add this? I noticed without this, dont_extract_in_pattern would still pass through
Try not to break
There was a problem hiding this comment.
On revisiting this, there were several problems.
- The
dont_extract_in_patterntest did not actually test this code path, because the test had a selection and this is the empty-selection code path. I’ve fixed that by adding another test, and also split out those tests to a separate commit to clarify that they are testing existing behavior. - I don’t actually need to rewrite this as much as I did. I’ve now kept the existing structure, and only changed
ast::Expr::castinto the broader condition needed to operate on field names. - The
skip(1)was entirely my mistake in understanding the existing code, and has been removed.
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
63fa313 to
68abcda
Compare
| .is_some_and(|p| p.kind() == SyntaxKind::RECORD_EXPR_FIELD)) | ||
| })?; | ||
|
|
||
| node.ancestors().find_map(valid_target_expr(ctx))?.syntax().clone() |
There was a problem hiding this comment.
Don't be so complicated, just:
let expr = ancestors_at_offset(ctx.source_file().syntax(), ctx.offset())
- .next()
- .and_then(ast::Expr::cast)?;
+ .find(|it| !ast::NameRef::can_cast(it.kind()))
+ .and_then(either::Either::<ast::Expr, ast::RecordExprField>::cast)?;
expr.syntax().ancestors().find_map(valid_target_expr(ctx))?.syntax().clone()… expressions.
This change allows a “mistake” I make very often to succeed: putting
the cursor on “foo” in `Struct { foo: bar() }` when I want to
extract `let foo = bar();`.
It is also groundwork for being able to extract multiple field
expressions at once.
| // field, or a record field’s name. This prevents the assist from appearing when | ||
| // it is unlikely to be relevant, such as when the cursor is in a pattern. | ||
| // (If we did not want to restrict it this way, we could just apply | ||
| // `valid_target_expr()` to all ancestors.) |
There was a problem hiding this comment.
Redundant comments, we have testing
There was a problem hiding this comment.
This comment is not for specifying the desired functionality, but for someone reading the code (like me) to understand what the goal of this piece of the code is. Not having this part explained was a significant obstacle; I had to dig into git-blame to understand what the code was supposed to achieve.
This change allows a “mistake” I make very often to succeed: putting the cursor on “foo” in
Struct { foo: bar() }when I want to extractlet foo = bar();.It is also preparation for being able to extract multiple field expressions at once (#21863), because it generalizes the analysis of the selection to be able to work on nodes that are not themselves expressions.
Notes
The added
take_while()and the testsdont_extract_in_pattern_*are an attempt to preserve the behavior added in #18982, but that PR did not add any tests or clearly specify what effect it was intended to have, so I may have gotten it wrong.This is only my second contribution to assists, so all feedback is welcome.