From 8384b2cc38acc6e8c1741e8d2d6a66f74b7f02b3 Mon Sep 17 00:00:00 2001 From: Hrvoje Ban Date: Wed, 9 Jan 2019 20:35:38 +0100 Subject: Extend selection for list items --- crates/ra_ide_api_light/src/extend_selection.rs | 131 +++++++++++++++++++++++- 1 file changed, 127 insertions(+), 4 deletions(-) (limited to 'crates/ra_ide_api_light/src') diff --git a/crates/ra_ide_api_light/src/extend_selection.rs b/crates/ra_ide_api_light/src/extend_selection.rs index 08cae5a51..db93db208 100644 --- a/crates/ra_ide_api_light/src/extend_selection.rs +++ b/crates/ra_ide_api_light/src/extend_selection.rs @@ -6,6 +6,21 @@ use ra_syntax::{ pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option { let string_kinds = [COMMENT, STRING, RAW_STRING, BYTE_STRING, RAW_BYTE_STRING]; + let list_kinds = [ + FIELD_PAT_LIST, + MATCH_ARM_LIST, + NAMED_FIELD_LIST, + NAMED_FIELD_DEF_LIST, + POS_FIELD_LIST, + ENUM_VARIANT_LIST, + USE_TREE_LIST, + TYPE_PARAM_LIST, + TYPE_ARG_LIST, + PARAM_LIST, + ARG_LIST, + ARRAY_EXPR, + ]; + if range.is_empty() { let offset = range.start(); let mut leaves = find_leaf_at_offset(root, offset); @@ -26,9 +41,25 @@ pub fn extend_selection(root: &SyntaxNode, range: TextRange) -> Option(l: &'a SyntaxNode, r: &'a SyntaxNode) -> &'a SyntaxNode { } } +/// Extend list item selection to include nearby comma and whitespace. +fn extend_list_item(node: &SyntaxNode) -> Option { + fn is_single_line_ws(node: &SyntaxNode) -> bool { + node.kind() == WHITESPACE && !node.leaf_text().unwrap().contains('\n') + } + + fn nearby_comma(node: &SyntaxNode, dir: Direction) -> Option<&SyntaxNode> { + node.siblings(dir) + .skip(1) + .skip_while(|node| is_single_line_ws(node)) + .next() + .filter(|node| node.kind() == COMMA) + } + + if let Some(comma_node) = nearby_comma(node, Direction::Prev) { + return Some(TextRange::from_to( + comma_node.range().start(), + node.range().end(), + )); + } + + if let Some(comma_node) = nearby_comma(node, Direction::Next) { + // Include any following whitespace when comma if after list item. + let final_node = comma_node + .siblings(Direction::Next) + .skip(1) + .next() + .filter(|node| is_single_line_ws(node)) + .unwrap_or(comma_node); + + return Some(TextRange::from_to( + node.range().start(), + final_node.range().end(), + )); + } + + return None; +} + fn extend_comments(node: &SyntaxNode) -> Option { let prev = adj_comments(node, Direction::Prev); let next = adj_comments(node, Direction::Next); @@ -145,7 +215,60 @@ mod tests { } #[test] - fn test_extend_selection_start_of_the_lind() { + fn test_extend_selection_list() { + do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); + do_check( + r#"fn foo(<|>x: i32, y: i32) {}"#, + &["x", "x: i32", "x: i32, "], + ); + do_check( + r#"fn foo(<|>x: i32,y: i32) {}"#, + &["x", "x: i32", "x: i32,"], + ); + do_check( + r#"fn foo(x: i32, <|>y: i32) {}"#, + &["y", "y: i32", ", y: i32"], + ); + do_check( + r#"fn foo(x: i32, <|>y: i32, ) {}"#, + &["y", "y: i32", ", y: i32"], + ); + do_check( + r#"fn foo(x: i32,<|>y: i32) {}"#, + &["y", "y: i32", ",y: i32"], + ); + + do_check( + r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, + &["22", "22 , "], + ); + do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); + do_check( + r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, + &["33", ", 33"], + ); + + do_check( + r#" +const FOO: [usize; 2] = [ + 22, + <|>33, +]"#, + &["33", "33,"], + ); + + do_check( + r#" +const FOO: [usize; 2] = [ + 22 + , 33<|>, +]"#, + &["33", ", 33"], + ); + } + + #[test] + fn test_extend_selection_start_of_the_line() { do_check( r#" impl S { -- cgit v1.2.3