diff options
-rw-r--r-- | crates/ra_ide/src/completion/complete_keyword.rs | 5 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/completion_context.rs | 13 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/patterns.rs | 96 |
3 files changed, 59 insertions, 55 deletions
diff --git a/crates/ra_ide/src/completion/complete_keyword.rs b/crates/ra_ide/src/completion/complete_keyword.rs index 5b56c6275..50f003949 100644 --- a/crates/ra_ide/src/completion/complete_keyword.rs +++ b/crates/ra_ide/src/completion/complete_keyword.rs | |||
@@ -62,7 +62,7 @@ fn add_keyword( | |||
62 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { | 62 | pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionContext) { |
63 | add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); | 63 | add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); |
64 | add_keyword(ctx, acc, "type", "type ", ctx.is_new_item || ctx.block_expr_parent); | 64 | add_keyword(ctx, acc, "type", "type ", ctx.is_new_item || ctx.block_expr_parent); |
65 | add_keyword(ctx, acc, "fn", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); | 65 | add_keyword(ctx, acc, "use", "fn $0() {}", ctx.is_new_item || ctx.block_expr_parent); |
66 | add_keyword(ctx, acc, "impl", "impl $0 {}", ctx.is_new_item); | 66 | add_keyword(ctx, acc, "impl", "impl $0 {}", ctx.is_new_item); |
67 | add_keyword(ctx, acc, "trait", "impl $0 {}", ctx.is_new_item); | 67 | add_keyword(ctx, acc, "trait", "impl $0 {}", ctx.is_new_item); |
68 | add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !ctx.after_unsafe); | 68 | add_keyword(ctx, acc, "enum", "enum $0 {}", ctx.is_new_item && !ctx.after_unsafe); |
@@ -72,7 +72,6 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
72 | add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent); | 72 | add_keyword(ctx, acc, "loop", "loop {$0}", ctx.block_expr_parent); |
73 | add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent); | 73 | add_keyword(ctx, acc, "while", "while $0 {}", ctx.block_expr_parent); |
74 | add_keyword(ctx, acc, "let", "let ", ctx.after_if || ctx.block_expr_parent); | 74 | add_keyword(ctx, acc, "let", "let ", ctx.after_if || ctx.block_expr_parent); |
75 | add_keyword(ctx, acc, "let", "let ", ctx.after_if || ctx.block_expr_parent); | ||
76 | add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if); | 75 | add_keyword(ctx, acc, "else", "else {$0}", ctx.after_if); |
77 | add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if); | 76 | add_keyword(ctx, acc, "else if", "else if $0 {}", ctx.after_if); |
78 | add_keyword(ctx, acc, "mod", "mod $0 {}", ctx.is_new_item || ctx.block_expr_parent); | 77 | add_keyword(ctx, acc, "mod", "mod $0 {}", ctx.is_new_item || ctx.block_expr_parent); |
@@ -88,6 +87,8 @@ pub(super) fn complete_expr_keyword(acc: &mut Completions, ctx: &CompletionConte | |||
88 | add_keyword(ctx, acc, "break", "break;", ctx.in_loop_body && ctx.can_be_stmt); | 87 | add_keyword(ctx, acc, "break", "break;", ctx.in_loop_body && ctx.can_be_stmt); |
89 | add_keyword(ctx, acc, "continue", "continue", ctx.in_loop_body && !ctx.can_be_stmt); | 88 | add_keyword(ctx, acc, "continue", "continue", ctx.in_loop_body && !ctx.can_be_stmt); |
90 | add_keyword(ctx, acc, "break", "break", ctx.in_loop_body && !ctx.can_be_stmt); | 89 | add_keyword(ctx, acc, "break", "break", ctx.in_loop_body && !ctx.can_be_stmt); |
90 | add_keyword(ctx, acc, "pub", "pub ", ctx.is_new_item && !ctx.inside_trait); | ||
91 | add_keyword(ctx, acc, "where", "where ", ctx.trait_as_prev_sibling || ctx.impl_as_prev_sibling); | ||
91 | complete_use_tree_keyword(acc, ctx); | 92 | complete_use_tree_keyword(acc, ctx); |
92 | 93 | ||
93 | let fn_def = match &ctx.function_syntax { | 94 | let fn_def = match &ctx.function_syntax { |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index 1ef07d8f4..e579e2ee2 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -12,8 +12,8 @@ use ra_syntax::{ | |||
12 | use ra_text_edit::Indel; | 12 | use ra_text_edit::Indel; |
13 | 13 | ||
14 | use super::patterns::{ | 14 | use super::patterns::{ |
15 | goes_after_unsafe, has_bind_pat_parent, has_block_expr_parent, has_ref_pat_parent, | 15 | goes_after_unsafe, has_bind_pat_parent, has_block_expr_parent, has_impl_as_prev_sibling, |
16 | is_in_loop_body, | 16 | has_ref_pat_parent, has_trait_as_prev_sibling, inside_trait, is_in_loop_body, |
17 | }; | 17 | }; |
18 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; | 18 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; |
19 | use test_utils::mark; | 19 | use test_utils::mark; |
@@ -69,6 +69,9 @@ pub(crate) struct CompletionContext<'a> { | |||
69 | pub(super) bind_pat_parent: bool, | 69 | pub(super) bind_pat_parent: bool, |
70 | pub(super) ref_pat_parent: bool, | 70 | pub(super) ref_pat_parent: bool, |
71 | pub(super) in_loop_body: bool, | 71 | pub(super) in_loop_body: bool, |
72 | pub(super) inside_trait: bool, | ||
73 | pub(super) trait_as_prev_sibling: bool, | ||
74 | pub(super) impl_as_prev_sibling: bool, | ||
72 | } | 75 | } |
73 | 76 | ||
74 | impl<'a> CompletionContext<'a> { | 77 | impl<'a> CompletionContext<'a> { |
@@ -132,6 +135,9 @@ impl<'a> CompletionContext<'a> { | |||
132 | ref_pat_parent: false, | 135 | ref_pat_parent: false, |
133 | bind_pat_parent: false, | 136 | bind_pat_parent: false, |
134 | block_expr_parent: false, | 137 | block_expr_parent: false, |
138 | inside_trait: false, | ||
139 | trait_as_prev_sibling: false, | ||
140 | impl_as_prev_sibling: false, | ||
135 | }; | 141 | }; |
136 | 142 | ||
137 | let mut original_file = original_file.syntax().clone(); | 143 | let mut original_file = original_file.syntax().clone(); |
@@ -210,6 +216,9 @@ impl<'a> CompletionContext<'a> { | |||
210 | self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); | 216 | self.bind_pat_parent = has_bind_pat_parent(syntax_element.clone()); |
211 | self.ref_pat_parent = has_ref_pat_parent(syntax_element.clone()); | 217 | self.ref_pat_parent = has_ref_pat_parent(syntax_element.clone()); |
212 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); | 218 | self.in_loop_body = is_in_loop_body(syntax_element.clone()); |
219 | self.inside_trait = inside_trait(syntax_element.clone()); | ||
220 | self.impl_as_prev_sibling = has_impl_as_prev_sibling(syntax_element.clone()); | ||
221 | self.trait_as_prev_sibling = has_trait_as_prev_sibling(syntax_element.clone()); | ||
213 | } | 222 | } |
214 | 223 | ||
215 | fn fill( | 224 | fn fill( |
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 | } |