Skip to content

Commit e46c73d

Browse files
bors[bot]aee11
andauthored
Merge #2088
2088: Extend selection in trait bound extends to plus r=matklad a=aee11 When multiple traits bounds are present, expanded selection from a single trait bound will include the nearest plus sign (and whitespace after) before including the whole trait bound. Fixes: #2055 Co-authored-by: Alexander Elís Ebenesersson <alex2789@gmail.com>
2 parents 7dfbe28 + 3e7e3fd commit e46c73d

File tree

1 file changed

+72
-10
lines changed

1 file changed

+72
-10
lines changed

crates/ra_ide_api/src/extend_selection.rs

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use ra_syntax::{
55
algo::find_covering_element,
66
ast::{self, AstNode, AstToken},
77
Direction, NodeOrToken,
8-
SyntaxKind::*,
8+
SyntaxKind::{self, *},
99
SyntaxNode, SyntaxToken, TextRange, TextUnit, TokenAtOffset, T,
1010
};
1111

@@ -29,10 +29,12 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
2929
USE_TREE_LIST,
3030
TYPE_PARAM_LIST,
3131
TYPE_ARG_LIST,
32+
TYPE_BOUND_LIST,
3233
PARAM_LIST,
3334
ARG_LIST,
3435
ARRAY_EXPR,
3536
TUPLE_EXPR,
37+
WHERE_CLAUSE,
3638
];
3739

3840
if range.is_empty() {
@@ -146,13 +148,17 @@ fn pick_best<'a>(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken {
146148
}
147149
}
148150

149-
/// Extend list item selection to include nearby comma and whitespace.
151+
/// Extend list item selection to include nearby delimiter and whitespace.
150152
fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
151153
fn is_single_line_ws(node: &SyntaxToken) -> bool {
152154
node.kind() == WHITESPACE && !node.text().contains('\n')
153155
}
154156

155-
fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<SyntaxToken> {
157+
fn nearby_delimiter(
158+
delimiter_kind: SyntaxKind,
159+
node: &SyntaxNode,
160+
dir: Direction,
161+
) -> Option<SyntaxToken> {
156162
node.siblings_with_tokens(dir)
157163
.skip(1)
158164
.skip_while(|node| match node {
@@ -161,19 +167,26 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
161167
})
162168
.next()
163169
.and_then(|it| it.into_token())
164-
.filter(|node| node.kind() == T![,])
170+
.filter(|node| node.kind() == delimiter_kind)
165171
}
166172

167-
if let Some(comma_node) = nearby_comma(node, Direction::Prev) {
168-
return Some(TextRange::from_to(comma_node.text_range().start(), node.text_range().end()));
173+
let delimiter = match node.kind() {
174+
TYPE_BOUND => T![+],
175+
_ => T![,],
176+
};
177+
if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) {
178+
return Some(TextRange::from_to(
179+
delimiter_node.text_range().start(),
180+
node.text_range().end(),
181+
));
169182
}
170-
if let Some(comma_node) = nearby_comma(node, Direction::Next) {
171-
// Include any following whitespace when comma if after list item.
172-
let final_node = comma_node
183+
if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) {
184+
// Include any following whitespace when delimiter is after list item.
185+
let final_node = delimiter_node
173186
.next_sibling_or_token()
174187
.and_then(|it| it.into_token())
175188
.filter(|node| is_single_line_ws(node))
176-
.unwrap_or(comma_node);
189+
.unwrap_or(delimiter_node);
177190

178191
return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end()));
179192
}
@@ -387,4 +400,53 @@ fn bar(){}
387400
&["foo", "\" fn foo() {\""],
388401
);
389402
}
403+
404+
#[test]
405+
fn test_extend_trait_bounds_list_in_where_clause() {
406+
do_check(
407+
r#"
408+
fn foo<R>()
409+
where
410+
R: req::Request + 'static,
411+
R::Params: DeserializeOwned<|> + panic::UnwindSafe + 'static,
412+
R::Result: Serialize + 'static,
413+
"#,
414+
&[
415+
"DeserializeOwned",
416+
"DeserializeOwned + ",
417+
"DeserializeOwned + panic::UnwindSafe + 'static",
418+
"R::Params: DeserializeOwned + panic::UnwindSafe + 'static",
419+
"R::Params: DeserializeOwned + panic::UnwindSafe + 'static,",
420+
],
421+
);
422+
do_check(r#"fn foo<T>() where T: <|>Copy"#, &["Copy"]);
423+
do_check(r#"fn foo<T>() where T: <|>Copy + Display"#, &["Copy", "Copy + "]);
424+
do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]);
425+
do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]);
426+
do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]);
427+
do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "+ Display"]);
428+
do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]);
429+
}
430+
431+
#[test]
432+
fn test_extend_trait_bounds_list_inline() {
433+
do_check(r#"fn foo<T: <|>Copy>() {}"#, &["Copy"]);
434+
do_check(r#"fn foo<T: <|>Copy + Display>() {}"#, &["Copy", "Copy + "]);
435+
do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]);
436+
do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]);
437+
do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]);
438+
do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "+ Display"]);
439+
do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]);
440+
do_check(
441+
r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#,
442+
&[
443+
"Copy",
444+
"Copy + ",
445+
"Copy + Display",
446+
"T: Copy + Display",
447+
"T: Copy + Display, ",
448+
"<T: Copy + Display, U: Copy>",
449+
],
450+
);
451+
}
390452
}

0 commit comments

Comments
 (0)