]> git.lizzy.rs Git - rust.git/blob - crates/ra_ide_api/src/completion.rs
complete patterns
[rust.git] / crates / ra_ide_api / src / completion.rs
1 mod completion_item;
2 mod completion_context;
3 mod presentation;
4
5 mod complete_dot;
6 mod complete_struct_literal;
7 mod complete_pattern;
8 mod complete_fn_param;
9 mod complete_keyword;
10 mod complete_snippet;
11 mod complete_path;
12 mod complete_scope;
13 mod complete_postfix;
14
15 use ra_db::SourceDatabase;
16 use ra_syntax::ast::{self, AstNode};
17
18 use crate::{
19     db,
20     FilePosition,
21     completion::{
22         completion_item::{Completions, CompletionKind},
23         completion_context::CompletionContext,
24     },
25
26 };
27 #[cfg(test)]
28 use crate::completion::completion_item::{do_completion, check_completion};
29
30 pub use crate::completion::completion_item::{CompletionItem, CompletionItemKind, InsertTextFormat};
31
32 /// Main entry point for completion. We run completion as a two-phase process.
33 ///
34 /// First, we look at the position and collect a so-called `CompletionContext.
35 /// This is a somewhat messy process, because, during completion, syntax tree is
36 /// incomplete and can look really weird.
37 ///
38 /// Once the context is collected, we run a series of completion routines which
39 /// look at the context and produce completion items. One subtlety about this
40 /// phase is that completion engine should not filter by the substring which is
41 /// already present, it should give all possible variants for the identifier at
42 /// the caret. In other words, for
43 ///
44 /// ```no-run
45 /// fn f() {
46 ///     let foo = 92;
47 ///     let _ = bar<|>
48 /// }
49 /// ```
50 ///
51 /// `foo` *should* be present among the completion variants. Filtering by
52 /// identifier prefix/fuzzy match should be done higher in the stack, together
53 /// with ordering of completions (currently this is done by the client).
54 pub(crate) fn completions(db: &db::RootDatabase, position: FilePosition) -> Option<Completions> {
55     let original_file = db.parse(position.file_id);
56     let ctx = CompletionContext::new(db, &original_file, position)?;
57
58     let mut acc = Completions::default();
59
60     complete_fn_param::complete_fn_param(&mut acc, &ctx);
61     complete_keyword::complete_expr_keyword(&mut acc, &ctx);
62     complete_keyword::complete_use_tree_keyword(&mut acc, &ctx);
63     complete_snippet::complete_expr_snippet(&mut acc, &ctx);
64     complete_snippet::complete_item_snippet(&mut acc, &ctx);
65     complete_path::complete_path(&mut acc, &ctx);
66     complete_scope::complete_scope(&mut acc, &ctx);
67     complete_dot::complete_dot(&mut acc, &ctx);
68     complete_struct_literal::complete_struct_literal(&mut acc, &ctx);
69     complete_pattern::complete_pattern(&mut acc, &ctx);
70     complete_postfix::complete_postfix(&mut acc, &ctx);
71     Some(acc)
72 }
73
74 pub fn function_label(node: &ast::FnDef) -> Option<String> {
75     let label: String = if let Some(body) = node.body() {
76         let body_range = body.syntax().range();
77         let label: String = node
78             .syntax()
79             .children()
80             .filter(|child| !child.range().is_subrange(&body_range)) // Filter out body
81             .filter(|child| ast::Comment::cast(child).is_none()) // Filter out comments
82             .filter(|child| ast::Attr::cast(child).is_none()) // Filter out attributes
83             .map(|node| node.text().to_string())
84             .collect();
85         label
86     } else {
87         node.syntax().text().to_string()
88     };
89
90     Some(label.trim().to_owned())
91 }
92
93 pub fn const_label(node: &ast::ConstDef) -> String {
94     let label: String = node
95         .syntax()
96         .children()
97         .filter(|child| ast::Comment::cast(child).is_none())
98         .filter(|child| ast::Attr::cast(child).is_none())
99         .map(|node| node.text().to_string())
100         .collect();
101
102     label.trim().to_owned()
103 }
104
105 pub fn type_label(node: &ast::TypeDef) -> String {
106     let label: String = node
107         .syntax()
108         .children()
109         .filter(|child| ast::Comment::cast(child).is_none())
110         .filter(|child| ast::Attr::cast(child).is_none())
111         .map(|node| node.text().to_string())
112         .collect();
113
114     label.trim().to_owned()
115 }