-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat: highlighting of return values while the cursor is on match
/ if
/ =>
#19546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Here's a demo. 2025-04-09.10.32.29.mov |
8fb7504
to
6d3a9e1
Compare
crates/ide/src/goto_definition.rs
Outdated
fn nav_for_branches( | ||
sema: &Semantics<'_, RootDatabase>, | ||
token: &SyntaxToken, | ||
) -> Option<Vec<NavigationTarget>> { | ||
let db = sema.db; | ||
|
||
let navs = match token.kind() { | ||
T![match] => sema | ||
.descend_into_macros(token.clone()) | ||
.into_iter() | ||
.filter_map(|token| { | ||
let match_expr = sema | ||
.token_ancestors_with_macros(token) | ||
.take_while(|node| !ast::MacroCall::can_cast(node.kind())) | ||
.find_map(ast::MatchExpr::cast)?; | ||
let file_id = sema.hir_file_for(match_expr.syntax()); | ||
let focus_range = match_expr.match_token()?.text_range(); | ||
let match_expr_in_file = InFile::new(file_id, match_expr.into()); | ||
Some(expr_to_nav(db, match_expr_in_file, Some(focus_range))) | ||
}) | ||
.flatten() | ||
.collect_vec(), | ||
|
||
T![=>] => sema | ||
.descend_into_macros(token.clone()) | ||
.into_iter() | ||
.filter_map(|token| { | ||
let match_arm = sema | ||
.token_ancestors_with_macros(token) | ||
.take_while(|node| !ast::MacroCall::can_cast(node.kind())) | ||
.find_map(ast::MatchArm::cast)?; | ||
let match_expr = sema | ||
.ancestors_with_macros(match_arm.syntax().clone()) | ||
.find_map(ast::MatchExpr::cast)?; | ||
let file_id = sema.hir_file_for(match_expr.syntax()); | ||
let focus_range = match_arm.fat_arrow_token()?.text_range(); | ||
let match_expr_in_file = InFile::new(file_id, match_expr.into()); | ||
Some(expr_to_nav(db, match_expr_in_file, Some(focus_range))) | ||
}) | ||
.flatten() | ||
.collect_vec(), | ||
|
||
T![if] => sema | ||
.descend_into_macros(token.clone()) | ||
.into_iter() | ||
.filter_map(|token| { | ||
let if_expr = sema | ||
.token_ancestors_with_macros(token) | ||
.take_while(|node| !ast::MacroCall::can_cast(node.kind())) | ||
.find_map(ast::IfExpr::cast)?; | ||
let file_id = sema.hir_file_for(if_expr.syntax()); | ||
let focus_range = if_expr.if_token()?.text_range(); | ||
let if_expr_in_file = InFile::new(file_id, if_expr.into()); | ||
Some(expr_to_nav(db, if_expr_in_file, Some(focus_range))) | ||
}) | ||
.flatten() | ||
.collect_vec(), | ||
|
||
_ => return Some(Vec::new()), | ||
}; | ||
|
||
Some(navs) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
judging by the tests, this doesn't really do anything signifcant. Can we drop this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose here is "when a user performs a goto-def on the match
kw, server should navigate to the match
kw itself."
This approach is more from a user experience perspective. In VS Code, if a user perform a goto-def on an identifier and the response is the identifier itself, VS Code would understand that this location is a definition. Therefore, VS Code will automatically trigger find-references.
This is very intuitive for users: when I perform ctrl + click
on match
kw, it will automatically trigger find-references to locate all branch exit points.
The current logic here is indeed quite complicated. I will try to simplify it to make it look more elegant.
crates/ide/src/highlight_related.rs
Outdated
@@ -285,11 +290,129 @@ fn highlight_references( | |||
if res.is_empty() { None } else { Some(res.into_iter().collect()) } | |||
} | |||
|
|||
pub(crate) fn highlight_branches( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is hte implementation of this so different from the test. I'd expect this to look fairly similar to hl_exit_points
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For match
and match_arm
, it's much simpler than exit_points
(they only need to handle tail_expr
).
For if
, there is an additional step to find the root node of if-else chains.
I have pushed a new commit to simplify this function.
3789184
to
335d67b
Compare
…y `match`, `if`, or match arm arrow (`=>`)
335d67b
to
e23e442
Compare
Inspired by #18924, a follow-up to #17542.
This PR adds a new feature that highlights the related return values when the cursor is on
match
,if
, or a match arm arrow (=>
). This helps users quickly identify the different possible outcomes of control flow expressions.For
match
keyword:match
keyword itselfFor
=>
(match arm arrow):For
if
keyword:if
keywords in theif-else
chainThis feature works with nested expressions and macros.