aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/libeditor/src/completion.rs123
-rw-r--r--crates/libsyntax2/Cargo.toml2
-rw-r--r--crates/libsyntax2/src/ast/generated.rs22
-rw-r--r--crates/libsyntax2/src/grammar.ron3
-rw-r--r--crates/libsyntax2/src/grammar/mod.rs2
-rw-r--r--crates/libsyntax2/src/syntax_kinds/generated.rs2
-rw-r--r--crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt11
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt11
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt11
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt15
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt11
-rw-r--r--crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt41
-rw-r--r--crates/server/src/main_loop/handlers.rs16
14 files changed, 208 insertions, 77 deletions
diff --git a/crates/libeditor/src/completion.rs b/crates/libeditor/src/completion.rs
index 7e8669822..65527db62 100644
--- a/crates/libeditor/src/completion.rs
+++ b/crates/libeditor/src/completion.rs
@@ -12,7 +12,8 @@ use {
12}; 12};
13 13
14#[derive(Debug)] 14#[derive(Debug)]
15pub struct CompletionItem { 15pub struct
16 CompletionItem {
16 pub name: String, 17 pub name: String,
17 pub snippet: Option<String> 18 pub snippet: Option<String>
18} 19}
@@ -25,10 +26,17 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI
25 file.incremental_reparse(&edit)? 26 file.incremental_reparse(&edit)?
26 }; 27 };
27 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?; 28 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), offset)?;
29 if !is_ident_expr(name_ref) {
30 return None;
31 }
32
28 let mut res = Vec::new(); 33 let mut res = Vec::new();
29 if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() { 34 if let Some(fn_def) = ancestors(name_ref.syntax()).filter_map(ast::FnDef::cast).next() {
35 complete_keywords(&file, Some(fn_def), name_ref, &mut res);
30 let scopes = FnScopes::new(fn_def); 36 let scopes = FnScopes::new(fn_def);
31 complete_fn(name_ref, &scopes, &mut res); 37 complete_fn(name_ref, &scopes, &mut res);
38 } else {
39 complete_keywords(&file, None, name_ref, &mut res);
32 } 40 }
33 if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() { 41 if let Some(root) = ancestors(name_ref.syntax()).filter_map(ast::Root::cast).next() {
34 let scope = ModuleScope::new(root); 42 let scope = ModuleScope::new(root);
@@ -43,6 +51,42 @@ pub fn scope_completion(file: &File, offset: TextUnit) -> Option<Vec<CompletionI
43 Some(res) 51 Some(res)
44} 52}
45 53
54fn is_ident_expr(name_ref: ast::NameRef) -> bool {
55 match ancestors(name_ref.syntax()).filter_map(ast::Expr::cast).next() {
56 None => false,
57 Some(expr) => {
58 expr.syntax().range() == name_ref.syntax().range()
59 }
60 }
61}
62
63fn complete_keywords(file: &File, fn_def: Option<ast::FnDef>, name_ref: ast::NameRef, acc: &mut Vec<CompletionItem>) {
64 acc.push(keyword("if", "if $0 { }"));
65 acc.push(keyword("match", "match $0 { }"));
66 acc.push(keyword("while", "while $0 { }"));
67 acc.push(keyword("loop", "loop {$0}"));
68
69 if let Some(off) = name_ref.syntax().range().start().checked_sub(2.into()) {
70 if let Some(if_expr) = find_node_at_offset::<ast::IfExpr>(file.syntax(), off) {
71 if if_expr.syntax().range().end() < name_ref.syntax().range().start() {
72 acc.push(keyword("else", "else {$0}"));
73 acc.push(keyword("else if", "else if $0 { }"));
74 }
75 }
76 }
77
78 // if let Some(fn_def) = fn_def {
79 // acc.push(keyword("return", ""))
80 // }
81
82 fn keyword(kw: &str, snip: &str) -> CompletionItem {
83 CompletionItem {
84 name: kw.to_string(),
85 snippet: Some(snip.to_string()),
86 }
87 }
88}
89
46fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) { 90fn complete_fn(name_ref: ast::NameRef, scopes: &FnScopes, acc: &mut Vec<CompletionItem>) {
47 acc.extend( 91 acc.extend(
48 scopes.scope_chain(name_ref.syntax()) 92 scopes.scope_chain(name_ref.syntax())
@@ -59,29 +103,44 @@ mod tests {
59 use super::*; 103 use super::*;
60 use test_utils::{assert_eq_dbg, extract_offset}; 104 use test_utils::{assert_eq_dbg, extract_offset};
61 105
62 fn do_check(code: &str, expected_completions: &str) { 106 fn check_scope_completion(code: &str, expected_completions: &str) {
63 let (off, code) = extract_offset(&code); 107 let (off, code) = extract_offset(&code);
64 let file = File::parse(&code); 108 let file = File::parse(&code);
65 let completions = scope_completion(&file, off).unwrap(); 109 let completions = scope_completion(&file, off)
110 .unwrap()
111 .into_iter()
112 .filter(|c| c.snippet.is_none())
113 .collect::<Vec<_>>();
114 assert_eq_dbg(expected_completions, &completions);
115 }
116
117 fn check_snippet_completion(code: &str, expected_completions: &str) {
118 let (off, code) = extract_offset(&code);
119 let file = File::parse(&code);
120 let completions = scope_completion(&file, off)
121 .unwrap()
122 .into_iter()
123 .filter(|c| c.snippet.is_some())
124 .collect::<Vec<_>>();
66 assert_eq_dbg(expected_completions, &completions); 125 assert_eq_dbg(expected_completions, &completions);
67 } 126 }
68 127
69 #[test] 128 #[test]
70 fn test_completion_let_scope() { 129 fn test_completion_let_scope() {
71 do_check(r" 130 check_scope_completion(r"
72 fn quux(x: i32) { 131 fn quux(x: i32) {
73 let y = 92; 132 let y = 92;
74 1 + <|>; 133 1 + <|>;
75 let z = (); 134 let z = ();
76 } 135 }
77 ", r#"[CompletionItem { name: "y" }, 136 ", r#"[CompletionItem { name: "y", snippet: None },
78 CompletionItem { name: "x" }, 137 CompletionItem { name: "x", snippet: None },
79 CompletionItem { name: "quux" }]"#); 138 CompletionItem { name: "quux", snippet: None }]"#);
80 } 139 }
81 140
82 #[test] 141 #[test]
83 fn test_completion_if_let_scope() { 142 fn test_completion_if_let_scope() {
84 do_check(r" 143 check_scope_completion(r"
85 fn quux() { 144 fn quux() {
86 if let Some(x) = foo() { 145 if let Some(x) = foo() {
87 let y = 92; 146 let y = 92;
@@ -91,33 +150,61 @@ mod tests {
91 1 + <|> 150 1 + <|>
92 } 151 }
93 } 152 }
94 ", r#"[CompletionItem { name: "b" }, 153 ", r#"[CompletionItem { name: "b", snippet: None },
95 CompletionItem { name: "a" }, 154 CompletionItem { name: "a", snippet: None },
96 CompletionItem { name: "quux" }]"#); 155 CompletionItem { name: "quux", snippet: None }]"#);
97 } 156 }
98 157
99 #[test] 158 #[test]
100 fn test_completion_for_scope() { 159 fn test_completion_for_scope() {
101 do_check(r" 160 check_scope_completion(r"
102 fn quux() { 161 fn quux() {
103 for x in &[1, 2, 3] { 162 for x in &[1, 2, 3] {
104 <|> 163 <|>
105 } 164 }
106 } 165 }
107 ", r#"[CompletionItem { name: "x" }, 166 ", r#"[CompletionItem { name: "x", snippet: None },
108 CompletionItem { name: "quux" }]"#); 167 CompletionItem { name: "quux", snippet: None }]"#);
109 } 168 }
110 169
111 #[test] 170 #[test]
112 fn test_completion_mod_scope() { 171 fn test_completion_mod_scope() {
113 do_check(r" 172 check_scope_completion(r"
114 struct Foo; 173 struct Foo;
115 enum Baz {} 174 enum Baz {}
116 fn quux() { 175 fn quux() {
117 <|> 176 <|>
118 } 177 }
119 ", r#"[CompletionItem { name: "Foo" }, 178 ", r#"[CompletionItem { name: "Foo", snippet: None },
120 CompletionItem { name: "Baz" }, 179 CompletionItem { name: "Baz", snippet: None },
121 CompletionItem { name: "quux" }]"#); 180 CompletionItem { name: "quux", snippet: None }]"#);
181 }
182
183 #[test]
184 fn test_completion_kewords() {
185 check_snippet_completion(r"
186 fn quux() {
187 <|>
188 }
189 ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
190 CompletionItem { name: "match", snippet: Some("match $0 { }") },
191 CompletionItem { name: "while", snippet: Some("while $0 { }") },
192 CompletionItem { name: "loop", snippet: Some("loop {$0}") }]"#);
193 }
194
195 #[test]
196 fn test_completion_else() {
197 check_snippet_completion(r"
198 fn quux() {
199 if true {
200 ()
201 } <|>
202 }
203 ", r#"[CompletionItem { name: "if", snippet: Some("if $0 { }") },
204 CompletionItem { name: "match", snippet: Some("match $0 { }") },
205 CompletionItem { name: "while", snippet: Some("while $0 { }") },
206 CompletionItem { name: "loop", snippet: Some("loop {$0}") },
207 CompletionItem { name: "else", snippet: Some("else {$0}") },
208 CompletionItem { name: "else if", snippet: Some("else if $0 { }") }]"#);
122 } 209 }
123} 210}
diff --git a/crates/libsyntax2/Cargo.toml b/crates/libsyntax2/Cargo.toml
index 918c02775..3e5a83290 100644
--- a/crates/libsyntax2/Cargo.toml
+++ b/crates/libsyntax2/Cargo.toml
@@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8unicode-xid = "0.1.0" 8unicode-xid = "0.1.0"
9text_unit = "0.1.3" 9text_unit = "0.1.4"
10itertools = "0.7.8" 10itertools = "0.7.8"
11drop_bomb = "0.1.4" 11drop_bomb = "0.1.4"
12parking_lot = "0.6.0" 12parking_lot = "0.6.0"
diff --git a/crates/libsyntax2/src/ast/generated.rs b/crates/libsyntax2/src/ast/generated.rs
index 999023e3d..e8743caa8 100644
--- a/crates/libsyntax2/src/ast/generated.rs
+++ b/crates/libsyntax2/src/ast/generated.rs
@@ -523,6 +523,10 @@ impl<'a> FnDef<'a> {
523 pub fn body(self) -> Option<Block<'a>> { 523 pub fn body(self) -> Option<Block<'a>> {
524 super::child_opt(self) 524 super::child_opt(self)
525 } 525 }
526
527 pub fn ret_type(self) -> Option<RetType<'a>> {
528 super::child_opt(self)
529 }
526} 530}
527 531
528// FnPointerType 532// FnPointerType
@@ -1412,6 +1416,24 @@ impl<'a> AstNode<'a> for ReferenceType<'a> {
1412 1416
1413impl<'a> ReferenceType<'a> {} 1417impl<'a> ReferenceType<'a> {}
1414 1418
1419// RetType
1420#[derive(Debug, Clone, Copy)]
1421pub struct RetType<'a> {
1422 syntax: SyntaxNodeRef<'a>,
1423}
1424
1425impl<'a> AstNode<'a> for RetType<'a> {
1426 fn cast(syntax: SyntaxNodeRef<'a>) -> Option<Self> {
1427 match syntax.kind() {
1428 RET_TYPE => Some(RetType { syntax }),
1429 _ => None,
1430 }
1431 }
1432 fn syntax(self) -> SyntaxNodeRef<'a> { self.syntax }
1433}
1434
1435impl<'a> RetType<'a> {}
1436
1415// ReturnExpr 1437// ReturnExpr
1416#[derive(Debug, Clone, Copy)] 1438#[derive(Debug, Clone, Copy)]
1417pub struct ReturnExpr<'a> { 1439pub struct ReturnExpr<'a> {
diff --git a/crates/libsyntax2/src/grammar.ron b/crates/libsyntax2/src/grammar.ron
index f8fa7b694..f1907d1ce 100644
--- a/crates/libsyntax2/src/grammar.ron
+++ b/crates/libsyntax2/src/grammar.ron
@@ -119,6 +119,7 @@ Grammar(
119 "STRUCT_DEF", 119 "STRUCT_DEF",
120 "ENUM_DEF", 120 "ENUM_DEF",
121 "FN_DEF", 121 "FN_DEF",
122 "RET_TYPE",
122 "EXTERN_CRATE_ITEM", 123 "EXTERN_CRATE_ITEM",
123 "MODULE", 124 "MODULE",
124 "USE_ITEM", 125 "USE_ITEM",
@@ -252,8 +253,10 @@ Grammar(
252 options: [ 253 options: [
253 ["param_list", "ParamList"], 254 ["param_list", "ParamList"],
254 ["body", "Block"], 255 ["body", "Block"],
256 ["ret_type", "RetType"]
255 ], 257 ],
256 ), 258 ),
259 "RetType": (),
257 "StructDef": ( 260 "StructDef": (
258 traits: [ 261 traits: [
259 "NameOwner", 262 "NameOwner",
diff --git a/crates/libsyntax2/src/grammar/mod.rs b/crates/libsyntax2/src/grammar/mod.rs
index 496d28349..1acecac41 100644
--- a/crates/libsyntax2/src/grammar/mod.rs
+++ b/crates/libsyntax2/src/grammar/mod.rs
@@ -119,8 +119,10 @@ fn abi(p: &mut Parser) {
119 119
120fn opt_fn_ret_type(p: &mut Parser) -> bool { 120fn opt_fn_ret_type(p: &mut Parser) -> bool {
121 if p.at(THIN_ARROW) { 121 if p.at(THIN_ARROW) {
122 let m = p.start();
122 p.bump(); 123 p.bump();
123 types::type_(p); 124 types::type_(p);
125 m.complete(p, RET_TYPE);
124 true 126 true
125 } else { 127 } else {
126 false 128 false
diff --git a/crates/libsyntax2/src/syntax_kinds/generated.rs b/crates/libsyntax2/src/syntax_kinds/generated.rs
index 0a22b11c2..7882bded9 100644
--- a/crates/libsyntax2/src/syntax_kinds/generated.rs
+++ b/crates/libsyntax2/src/syntax_kinds/generated.rs
@@ -119,6 +119,7 @@ pub enum SyntaxKind {
119 STRUCT_DEF, 119 STRUCT_DEF,
120 ENUM_DEF, 120 ENUM_DEF,
121 FN_DEF, 121 FN_DEF,
122 RET_TYPE,
122 EXTERN_CRATE_ITEM, 123 EXTERN_CRATE_ITEM,
123 MODULE, 124 MODULE,
124 USE_ITEM, 125 USE_ITEM,
@@ -380,6 +381,7 @@ impl SyntaxKind {
380 STRUCT_DEF => &SyntaxInfo { name: "STRUCT_DEF" }, 381 STRUCT_DEF => &SyntaxInfo { name: "STRUCT_DEF" },
381 ENUM_DEF => &SyntaxInfo { name: "ENUM_DEF" }, 382 ENUM_DEF => &SyntaxInfo { name: "ENUM_DEF" },
382 FN_DEF => &SyntaxInfo { name: "FN_DEF" }, 383 FN_DEF => &SyntaxInfo { name: "FN_DEF" },
384 RET_TYPE => &SyntaxInfo { name: "RET_TYPE" },
383 EXTERN_CRATE_ITEM => &SyntaxInfo { name: "EXTERN_CRATE_ITEM" }, 385 EXTERN_CRATE_ITEM => &SyntaxInfo { name: "EXTERN_CRATE_ITEM" },
384 MODULE => &SyntaxInfo { name: "MODULE" }, 386 MODULE => &SyntaxInfo { name: "MODULE" },
385 USE_ITEM => &SyntaxInfo { name: "USE_ITEM" }, 387 USE_ITEM => &SyntaxInfo { name: "USE_ITEM" },
diff --git a/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt
index 400442c51..edd801599 100644
--- a/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt
+++ b/crates/libsyntax2/tests/data/parser/err/0010_unsafe_lambda_block.txt
@@ -17,13 +17,14 @@ ROOT@[0; 42)
17 PIPE@[16; 17) 17 PIPE@[16; 17)
18 PIPE@[17; 18) 18 PIPE@[17; 18)
19 WHITESPACE@[18; 19) 19 WHITESPACE@[18; 19)
20 THIN_ARROW@[19; 21) 20 RET_TYPE@[19; 24)
21 WHITESPACE@[21; 22) 21 THIN_ARROW@[19; 21)
22 TUPLE_TYPE@[22; 24) 22 WHITESPACE@[21; 22)
23 L_PAREN@[22; 23) 23 TUPLE_TYPE@[22; 24)
24 R_PAREN@[23; 24) 24 L_PAREN@[22; 23)
25 err: `expected a block` 25 R_PAREN@[23; 24)
26 err: `expected SEMI` 26 err: `expected a block`
27 err: `expected SEMI`
27 WHITESPACE@[24; 25) 28 WHITESPACE@[24; 25)
28 EXPR_STMT@[25; 39) 29 EXPR_STMT@[25; 39)
29 BLOCK_EXPR@[25; 38) 30 BLOCK_EXPR@[25; 38)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt
index 7d0ecfbd1..203839636 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0030_fn_pointer_type_with_ret.txt
@@ -13,10 +13,11 @@ ROOT@[0; 21)
13 L_PAREN@[11; 12) 13 L_PAREN@[11; 12)
14 R_PAREN@[12; 13) 14 R_PAREN@[12; 13)
15 WHITESPACE@[13; 14) 15 WHITESPACE@[13; 14)
16 THIN_ARROW@[14; 16) 16 RET_TYPE@[14; 19)
17 WHITESPACE@[16; 17) 17 THIN_ARROW@[14; 16)
18 TUPLE_TYPE@[17; 19) 18 WHITESPACE@[16; 17)
19 L_PAREN@[17; 18) 19 TUPLE_TYPE@[17; 19)
20 R_PAREN@[18; 19) 20 L_PAREN@[17; 18)
21 R_PAREN@[18; 19)
21 SEMI@[19; 20) 22 SEMI@[19; 20)
22 WHITESPACE@[20; 21) 23 WHITESPACE@[20; 21)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt
index 41461f2a6..f6b962b2c 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0031_for_type.txt
@@ -21,10 +21,11 @@ ROOT@[0; 29)
21 L_PAREN@[19; 20) 21 L_PAREN@[19; 20)
22 R_PAREN@[20; 21) 22 R_PAREN@[20; 21)
23 WHITESPACE@[21; 22) 23 WHITESPACE@[21; 22)
24 THIN_ARROW@[22; 24) 24 RET_TYPE@[22; 27)
25 WHITESPACE@[24; 25) 25 THIN_ARROW@[22; 24)
26 TUPLE_TYPE@[25; 27) 26 WHITESPACE@[24; 25)
27 L_PAREN@[25; 26) 27 TUPLE_TYPE@[25; 27)
28 R_PAREN@[26; 27) 28 L_PAREN@[25; 26)
29 R_PAREN@[26; 27)
29 SEMI@[27; 28) 30 SEMI@[27; 28)
30 WHITESPACE@[28; 29) 31 WHITESPACE@[28; 29)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt
index 0df6c8f51..a3d235ce1 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0038_function_ret_type.txt
@@ -21,11 +21,12 @@ ROOT@[0; 30)
21 L_PAREN@[18; 19) 21 L_PAREN@[18; 19)
22 R_PAREN@[19; 20) 22 R_PAREN@[19; 20)
23 WHITESPACE@[20; 21) 23 WHITESPACE@[20; 21)
24 THIN_ARROW@[21; 23) 24 RET_TYPE@[21; 26)
25 WHITESPACE@[23; 24) 25 THIN_ARROW@[21; 23)
26 TUPLE_TYPE@[24; 26) 26 WHITESPACE@[23; 24)
27 L_PAREN@[24; 25) 27 TUPLE_TYPE@[24; 26)
28 R_PAREN@[25; 26) 28 L_PAREN@[24; 25)
29 R_PAREN@[25; 26)
29 WHITESPACE@[26; 27) 30 WHITESPACE@[26; 27)
30 BLOCK@[27; 29) 31 BLOCK@[27; 29)
31 L_CURLY@[27; 28) 32 L_CURLY@[27; 28)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt
index 6b34bc302..6f8304db3 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0066_lambda_expr.txt
@@ -28,13 +28,14 @@ ROOT@[0; 79)
28 PIPE@[26; 27) 28 PIPE@[26; 27)
29 PIPE@[27; 28) 29 PIPE@[27; 28)
30 WHITESPACE@[28; 29) 30 WHITESPACE@[28; 29)
31 THIN_ARROW@[29; 31) 31 RET_TYPE@[29; 35)
32 WHITESPACE@[31; 32) 32 THIN_ARROW@[29; 31)
33 PATH_TYPE@[32; 35) 33 WHITESPACE@[31; 32)
34 PATH@[32; 35) 34 PATH_TYPE@[32; 35)
35 PATH_SEGMENT@[32; 35) 35 PATH@[32; 35)
36 NAME_REF@[32; 35) 36 PATH_SEGMENT@[32; 35)
37 IDENT@[32; 35) "i32" 37 NAME_REF@[32; 35)
38 IDENT@[32; 35) "i32"
38 WHITESPACE@[35; 36) 39 WHITESPACE@[35; 36)
39 BLOCK@[36; 42) 40 BLOCK@[36; 42)
40 L_CURLY@[36; 37) 41 L_CURLY@[36; 37)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt
index 1b1a8a9e2..26a690d3a 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0093_path_fn_trait_args.txt
@@ -35,11 +35,12 @@ ROOT@[0; 32)
35 IDENT@[19; 22) "i32" 35 IDENT@[19; 22) "i32"
36 R_PAREN@[22; 23) 36 R_PAREN@[22; 23)
37 WHITESPACE@[23; 24) 37 WHITESPACE@[23; 24)
38 THIN_ARROW@[24; 26) 38 RET_TYPE@[24; 29)
39 WHITESPACE@[26; 27) 39 THIN_ARROW@[24; 26)
40 TUPLE_TYPE@[27; 29) 40 WHITESPACE@[26; 27)
41 L_PAREN@[27; 28) 41 TUPLE_TYPE@[27; 29)
42 R_PAREN@[28; 29) 42 L_PAREN@[27; 28)
43 R_PAREN@[28; 29)
43 R_ANGLE@[29; 30) 44 R_ANGLE@[29; 30)
44 SEMI@[30; 31) 45 SEMI@[30; 31)
45 WHITESPACE@[31; 32) 46 WHITESPACE@[31; 32)
diff --git a/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt
index 0703d1da2..4b864f741 100644
--- a/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt
+++ b/crates/libsyntax2/tests/data/parser/inline/0095_path_type_with_bounds.txt
@@ -8,26 +8,27 @@ ROOT@[0; 27)
8 L_PAREN@[6; 7) 8 L_PAREN@[6; 7)
9 R_PAREN@[7; 8) 9 R_PAREN@[7; 8)
10 WHITESPACE@[8; 9) 10 WHITESPACE@[8; 9)
11 THIN_ARROW@[9; 11) 11 RET_TYPE@[9; 23)
12 WHITESPACE@[11; 12) 12 THIN_ARROW@[9; 11)
13 PATH_TYPE@[12; 23) 13 WHITESPACE@[11; 12)
14 PATH@[12; 23) 14 PATH_TYPE@[12; 23)
15 PATH_SEGMENT@[12; 23) 15 PATH@[12; 23)
16 NAME_REF@[12; 15) 16 PATH_SEGMENT@[12; 23)
17 IDENT@[12; 15) "Box" 17 NAME_REF@[12; 15)
18 TYPE_ARG_LIST@[15; 23) 18 IDENT@[12; 15) "Box"
19 L_ANGLE@[15; 16) 19 TYPE_ARG_LIST@[15; 23)
20 TYPE_ARG@[16; 22) 20 L_ANGLE@[15; 16)
21 PATH_TYPE@[16; 22) 21 TYPE_ARG@[16; 22)
22 PATH@[16; 17) 22 PATH_TYPE@[16; 22)
23 PATH_SEGMENT@[16; 17) 23 PATH@[16; 17)
24 NAME_REF@[16; 17) 24 PATH_SEGMENT@[16; 17)
25 IDENT@[16; 17) "T" 25 NAME_REF@[16; 17)
26 WHITESPACE@[17; 18) 26 IDENT@[16; 17) "T"
27 PLUS@[18; 19) 27 WHITESPACE@[17; 18)
28 WHITESPACE@[19; 20) 28 PLUS@[18; 19)
29 LIFETIME@[20; 22) "'f" 29 WHITESPACE@[19; 20)
30 R_ANGLE@[22; 23) 30 LIFETIME@[20; 22) "'f"
31 R_ANGLE@[22; 23)
31 WHITESPACE@[23; 24) 32 WHITESPACE@[23; 24)
32 BLOCK@[24; 26) 33 BLOCK@[24; 26)
33 L_CURLY@[24; 25) 34 L_CURLY@[24; 25)
diff --git a/crates/server/src/main_loop/handlers.rs b/crates/server/src/main_loop/handlers.rs
index 92ffb30c3..3ee0873f4 100644
--- a/crates/server/src/main_loop/handlers.rs
+++ b/crates/server/src/main_loop/handlers.rs
@@ -4,7 +4,7 @@ use languageserver_types::{
4 Diagnostic, DiagnosticSeverity, Url, DocumentSymbol, 4 Diagnostic, DiagnosticSeverity, Url, DocumentSymbol,
5 Command, TextDocumentIdentifier, WorkspaceEdit, 5 Command, TextDocumentIdentifier, WorkspaceEdit,
6 SymbolInformation, Position, Location, TextEdit, 6 SymbolInformation, Position, Location, TextEdit,
7 CompletionItem, 7 CompletionItem, InsertTextFormat, CompletionItemKind,
8}; 8};
9use serde_json::{to_value, from_value}; 9use serde_json::{to_value, from_value};
10use url_serde; 10use url_serde;
@@ -331,9 +331,17 @@ pub fn handle_completion(
331 Some(items) => items, 331 Some(items) => items,
332 }; 332 };
333 let items = items.into_iter() 333 let items = items.into_iter()
334 .map(|item| CompletionItem { 334 .map(|item| {
335 label: item.name, 335 let mut res = CompletionItem {
336 .. Default::default() 336 label: item.name,
337 .. Default::default()
338 };
339 if let Some(snip) = item.snippet {
340 res.insert_text = Some(snip);
341 res.insert_text_format = Some(InsertTextFormat::Snippet);
342 res.kind = Some(CompletionItemKind::Keyword);
343 };
344 res
337 }) 345 })
338 .collect(); 346 .collect();
339 347