diff options
Diffstat (limited to 'crates/ra_ide/src/completion/patterns.rs')
-rw-r--r-- | crates/ra_ide/src/completion/patterns.rs | 96 |
1 files changed, 45 insertions, 51 deletions
diff --git a/crates/ra_ide/src/completion/patterns.rs b/crates/ra_ide/src/completion/patterns.rs index 145f01786..31d32ccd9 100644 --- a/crates/ra_ide/src/completion/patterns.rs +++ b/crates/ra_ide/src/completion/patterns.rs | |||
@@ -3,48 +3,47 @@ use ra_syntax::{ | |||
3 | ast::{self, LoopBodyOwner}, | 3 | ast::{self, LoopBodyOwner}, |
4 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, | 4 | match_ast, AstNode, Direction, NodeOrToken, SyntaxElement, |
5 | SyntaxKind::*, | 5 | SyntaxKind::*, |
6 | SyntaxNode, | 6 | SyntaxNode, SyntaxToken, |
7 | }; | 7 | }; |
8 | 8 | ||
9 | pub(crate) fn inside_impl(element: SyntaxElement) -> bool { | 9 | pub(crate) fn inside_impl(element: SyntaxElement) -> bool { |
10 | let node = match element { | 10 | element.ancestors().find(|it| it.kind() == IMPL_DEF).is_some() |
11 | NodeOrToken::Node(node) => node, | 11 | } |
12 | NodeOrToken::Token(token) => token.parent(), | 12 | |
13 | }; | 13 | pub(crate) fn inside_trait(element: SyntaxElement) -> bool { |
14 | node.ancestors().find(|it| it.kind() == IMPL_DEF).is_some() | 14 | element.ancestors().find(|it| it.kind() == TRAIT_DEF).is_some() |
15 | } | 15 | } |
16 | 16 | ||
17 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { | 17 | pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool { |
18 | let node = match element { | 18 | element.ancestors().find(|it| it.kind() == BIND_PAT).is_some() |
19 | NodeOrToken::Node(node) => node, | ||
20 | NodeOrToken::Token(token) => token.parent(), | ||
21 | }; | ||
22 | node.ancestors().find(|it| it.kind() == BIND_PAT).is_some() | ||
23 | } | 19 | } |
24 | 20 | ||
25 | pub(crate) fn has_ref_pat_parent(element: SyntaxElement) -> bool { | 21 | pub(crate) fn has_ref_pat_parent(element: SyntaxElement) -> bool { |
26 | let node = match element { | 22 | element.ancestors().find(|it| it.kind() == REF_PAT).is_some() |
27 | NodeOrToken::Node(node) => node, | ||
28 | NodeOrToken::Token(token) => token.parent(), | ||
29 | }; | ||
30 | node.ancestors().find(|it| it.kind() == REF_PAT).is_some() | ||
31 | } | 23 | } |
32 | 24 | ||
33 | pub(crate) fn goes_after_unsafe(element: SyntaxElement) -> bool { | 25 | pub(crate) fn goes_after_unsafe(element: SyntaxElement) -> bool { |
34 | if let Some(token) = previous_non_triva_element(element).and_then(|it| it.into_token()) { | 26 | element |
35 | if token.kind() == UNSAFE_KW { | 27 | .into_token() |
36 | return true; | 28 | .and_then(|it| previous_non_trivia_token(it)) |
37 | } | 29 | .filter(|it| it.kind() == UNSAFE_KW) |
38 | } | 30 | .is_some() |
39 | false | ||
40 | } | 31 | } |
41 | 32 | ||
42 | pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { | 33 | pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool { |
43 | not_same_range_parent(element).filter(|it| it.kind() == BLOCK_EXPR).is_some() | 34 | not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some() |
44 | } | 35 | } |
45 | 36 | ||
46 | pub(crate) fn has_item_list_parent(element: SyntaxElement) -> bool { | 37 | pub(crate) fn has_item_list_parent(element: SyntaxElement) -> bool { |
47 | not_same_range_parent(element).filter(|it| it.kind() == ITEM_LIST).is_some() | 38 | not_same_range_ancestor(element).filter(|it| it.kind() == ITEM_LIST).is_some() |
39 | } | ||
40 | |||
41 | pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool { | ||
42 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT_DEF).is_some() | ||
43 | } | ||
44 | |||
45 | pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool { | ||
46 | previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL_DEF).is_some() | ||
48 | } | 47 | } |
49 | 48 | ||
50 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | 49 | pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { |
@@ -73,20 +72,30 @@ pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool { | |||
73 | false | 72 | false |
74 | } | 73 | } |
75 | 74 | ||
76 | fn not_same_range_parent(element: SyntaxElement) -> Option<SyntaxNode> { | 75 | fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> { |
77 | let node = match element { | 76 | element |
78 | NodeOrToken::Node(node) => node, | 77 | .ancestors() |
79 | NodeOrToken::Token(token) => token.parent(), | 78 | .take_while(|it| it.text_range() == element.text_range()) |
80 | }; | 79 | .last() |
81 | let range = node.text_range(); | 80 | .and_then(|it| it.parent()) |
82 | node.ancestors().take_while(|it| it.text_range() == range).last().and_then(|it| it.parent()) | ||
83 | } | 81 | } |
84 | 82 | ||
85 | fn previous_non_triva_element(element: SyntaxElement) -> Option<SyntaxElement> { | 83 | fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> { |
86 | // trying to get first non triva sibling if we have one | 84 | let mut token = token.prev_token(); |
85 | while let Some(inner) = token.clone() { | ||
86 | if !inner.kind().is_trivia() { | ||
87 | return Some(inner); | ||
88 | } else { | ||
89 | token = inner.prev_token(); | ||
90 | } | ||
91 | } | ||
92 | None | ||
93 | } | ||
94 | |||
95 | fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> { | ||
87 | let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev); | 96 | let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev); |
88 | let mut wrapped = if let Some(sibling) = token_sibling { | 97 | if let Some(sibling) = token_sibling { |
89 | sibling | 98 | Some(sibling) |
90 | } else { | 99 | } else { |
91 | // if not trying to find first ancestor which has such a sibling | 100 | // if not trying to find first ancestor which has such a sibling |
92 | let node = match element { | 101 | let node = match element { |
@@ -98,21 +107,6 @@ fn previous_non_triva_element(element: SyntaxElement) -> Option<SyntaxElement> { | |||
98 | let prev_sibling_node = top_node.ancestors().find(|it| { | 107 | let prev_sibling_node = top_node.ancestors().find(|it| { |
99 | non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some() | 108 | non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some() |
100 | })?; | 109 | })?; |
101 | non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)? | 110 | non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev) |
102 | }; | ||
103 | // TODO: Check if this can be simplified | ||
104 | // Matklad: I think you can avoid this loop if you use SyntaxToken::prev_token -- unlike prev_sibling_or_token, it works across parents. | ||
105 | // traversing the tree down to get the last token or node, i.e. the closest one | ||
106 | loop { | ||
107 | if let Some(token) = wrapped.as_token() { | ||
108 | return Some(NodeOrToken::Token(token.clone())); | ||
109 | } else { | ||
110 | let new = wrapped.as_node().and_then(|n| n.last_child_or_token()); | ||
111 | if new.is_some() { | ||
112 | wrapped = new.unwrap().clone(); | ||
113 | } else { | ||
114 | return Some(wrapped); | ||
115 | } | ||
116 | } | ||
117 | } | 111 | } |
118 | } | 112 | } |