diff options
-rw-r--r-- | Cargo.lock | 2 | ||||
-rw-r--r-- | crates/ra_assists/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/auto_import.rs | 49 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/fill_match_arms.rs | 4 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 29 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 22 | ||||
-rw-r--r-- | crates/ra_hir/src/from_id.rs | 21 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_postfix.rs | 140 | ||||
-rw-r--r-- | crates/ra_ide/src/completion/complete_record_literal.rs | 62 | ||||
-rw-r--r-- | crates/ra_ide_db/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_ide_db/src/imports_locator.rs | 8 | ||||
-rw-r--r-- | docs/user/readme.adoc | 10 | ||||
-rw-r--r-- | editors/code/package.json | 12 | ||||
-rw-r--r-- | editors/code/src/client.ts | 6 | ||||
-rw-r--r-- | editors/code/src/config.ts | 124 | ||||
-rw-r--r-- | editors/code/src/main.ts | 14 |
16 files changed, 366 insertions, 139 deletions
diff --git a/Cargo.lock b/Cargo.lock index d6bd2e13e..908319f87 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -884,6 +884,7 @@ version = "0.1.0" | |||
884 | name = "ra_assists" | 884 | name = "ra_assists" |
885 | version = "0.1.0" | 885 | version = "0.1.0" |
886 | dependencies = [ | 886 | dependencies = [ |
887 | "either", | ||
887 | "format-buf", | 888 | "format-buf", |
888 | "itertools 0.9.0", | 889 | "itertools 0.9.0", |
889 | "join_to_string", | 890 | "join_to_string", |
@@ -1045,6 +1046,7 @@ dependencies = [ | |||
1045 | name = "ra_ide_db" | 1046 | name = "ra_ide_db" |
1046 | version = "0.1.0" | 1047 | version = "0.1.0" |
1047 | dependencies = [ | 1048 | dependencies = [ |
1049 | "either", | ||
1048 | "fst", | 1050 | "fst", |
1049 | "log", | 1051 | "log", |
1050 | "once_cell", | 1052 | "once_cell", |
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml index 707746ad5..a87f4052a 100644 --- a/crates/ra_assists/Cargo.toml +++ b/crates/ra_assists/Cargo.toml | |||
@@ -12,6 +12,7 @@ format-buf = "1.0.0" | |||
12 | join_to_string = "0.1.3" | 12 | join_to_string = "0.1.3" |
13 | rustc-hash = "1.1.0" | 13 | rustc-hash = "1.1.0" |
14 | itertools = "0.9.0" | 14 | itertools = "0.9.0" |
15 | either = "1.5.3" | ||
15 | 16 | ||
16 | ra_syntax = { path = "../ra_syntax" } | 17 | ra_syntax = { path = "../ra_syntax" } |
17 | ra_text_edit = { path = "../ra_text_edit" } | 18 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index bb280f633..99682e023 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -17,6 +17,7 @@ use crate::{ | |||
17 | utils::insert_use_statement, | 17 | utils::insert_use_statement, |
18 | AssistId, | 18 | AssistId, |
19 | }; | 19 | }; |
20 | use either::Either; | ||
20 | 21 | ||
21 | // Assist: auto_import | 22 | // Assist: auto_import |
22 | // | 23 | // |
@@ -58,6 +59,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
58 | group.finish() | 59 | group.finish() |
59 | } | 60 | } |
60 | 61 | ||
62 | #[derive(Debug)] | ||
61 | struct AutoImportAssets { | 63 | struct AutoImportAssets { |
62 | import_candidate: ImportCandidate, | 64 | import_candidate: ImportCandidate, |
63 | module_with_name_to_import: Module, | 65 | module_with_name_to_import: Module, |
@@ -127,14 +129,14 @@ impl AutoImportAssets { | |||
127 | ImportsLocator::new(db) | 129 | ImportsLocator::new(db) |
128 | .find_imports(&self.get_search_query()) | 130 | .find_imports(&self.get_search_query()) |
129 | .into_iter() | 131 | .into_iter() |
130 | .filter_map(|module_def| match &self.import_candidate { | 132 | .filter_map(|candidate| match &self.import_candidate { |
131 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { | 133 | ImportCandidate::TraitAssocItem(assoc_item_type, _) => { |
132 | let located_assoc_item = match module_def { | 134 | let located_assoc_item = match candidate { |
133 | ModuleDef::Function(located_function) => located_function | 135 | Either::Left(ModuleDef::Function(located_function)) => located_function |
134 | .as_assoc_item(db) | 136 | .as_assoc_item(db) |
135 | .map(|assoc| assoc.container(db)) | 137 | .map(|assoc| assoc.container(db)) |
136 | .and_then(Self::assoc_to_trait), | 138 | .and_then(Self::assoc_to_trait), |
137 | ModuleDef::Const(located_const) => located_const | 139 | Either::Left(ModuleDef::Const(located_const)) => located_const |
138 | .as_assoc_item(db) | 140 | .as_assoc_item(db) |
139 | .map(|assoc| assoc.container(db)) | 141 | .map(|assoc| assoc.container(db)) |
140 | .and_then(Self::assoc_to_trait), | 142 | .and_then(Self::assoc_to_trait), |
@@ -153,10 +155,11 @@ impl AutoImportAssets { | |||
153 | |_, assoc| Self::assoc_to_trait(assoc.container(db)), | 155 | |_, assoc| Self::assoc_to_trait(assoc.container(db)), |
154 | ) | 156 | ) |
155 | .map(ModuleDef::from) | 157 | .map(ModuleDef::from) |
158 | .map(Either::Left) | ||
156 | } | 159 | } |
157 | ImportCandidate::TraitMethod(function_callee, _) => { | 160 | ImportCandidate::TraitMethod(function_callee, _) => { |
158 | let located_assoc_item = | 161 | let located_assoc_item = |
159 | if let ModuleDef::Function(located_function) = module_def { | 162 | if let Either::Left(ModuleDef::Function(located_function)) = candidate { |
160 | located_function | 163 | located_function |
161 | .as_assoc_item(db) | 164 | .as_assoc_item(db) |
162 | .map(|assoc| assoc.container(db)) | 165 | .map(|assoc| assoc.container(db)) |
@@ -179,10 +182,18 @@ impl AutoImportAssets { | |||
179 | }, | 182 | }, |
180 | ) | 183 | ) |
181 | .map(ModuleDef::from) | 184 | .map(ModuleDef::from) |
185 | .map(Either::Left) | ||
186 | } | ||
187 | _ => Some(candidate), | ||
188 | }) | ||
189 | .filter_map(|candidate| match candidate { | ||
190 | Either::Left(module_def) => { | ||
191 | self.module_with_name_to_import.find_use_path(db, module_def) | ||
192 | } | ||
193 | Either::Right(macro_def) => { | ||
194 | self.module_with_name_to_import.find_use_path(db, macro_def) | ||
182 | } | 195 | } |
183 | _ => Some(module_def), | ||
184 | }) | 196 | }) |
185 | .filter_map(|module_def| self.module_with_name_to_import.find_use_path(db, module_def)) | ||
186 | .filter(|use_path| !use_path.segments.is_empty()) | 197 | .filter(|use_path| !use_path.segments.is_empty()) |
187 | .take(20) | 198 | .take(20) |
188 | .collect::<BTreeSet<_>>() | 199 | .collect::<BTreeSet<_>>() |
@@ -440,6 +451,30 @@ mod tests { | |||
440 | } | 451 | } |
441 | 452 | ||
442 | #[test] | 453 | #[test] |
454 | fn macro_import() { | ||
455 | check_assist( | ||
456 | auto_import, | ||
457 | r" | ||
458 | //- /lib.rs crate:crate_with_macro | ||
459 | #[macro_export] | ||
460 | macro_rules! foo { | ||
461 | () => () | ||
462 | } | ||
463 | |||
464 | //- /main.rs crate:main deps:crate_with_macro | ||
465 | fn main() { | ||
466 | foo<|> | ||
467 | }", | ||
468 | r"use crate_with_macro::foo; | ||
469 | |||
470 | fn main() { | ||
471 | foo<|> | ||
472 | } | ||
473 | ", | ||
474 | ); | ||
475 | } | ||
476 | |||
477 | #[test] | ||
443 | fn auto_import_target() { | 478 | fn auto_import_target() { |
444 | check_assist_target( | 479 | check_assist_target( |
445 | auto_import, | 480 | auto_import, |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index a7c315ca1..add82e5b1 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | use std::iter; | 3 | use std::iter; |
4 | 4 | ||
5 | use hir::{Adt, HasSource, Semantics}; | 5 | use hir::{Adt, HasSource, ModuleDef, Semantics}; |
6 | use itertools::Itertools; | 6 | use itertools::Itertools; |
7 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
8 | 8 | ||
@@ -154,7 +154,7 @@ fn resolve_tuple_of_enum_def( | |||
154 | } | 154 | } |
155 | 155 | ||
156 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { | 156 | fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> Option<ast::Pat> { |
157 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, var.into())?); | 157 | let path = crate::ast_transform::path_to_ast(module.find_use_path(db, ModuleDef::from(var))?); |
158 | 158 | ||
159 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though | 159 | // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though |
160 | let pat: ast::Pat = match var.source(db).value.kind() { | 160 | let pat: ast::Pat = match var.source(db).value.kind() { |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index b8704ea7d..bcc9b3f10 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -165,7 +165,6 @@ mod helpers { | |||
165 | 165 | ||
166 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; | 166 | use ra_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}; |
167 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; | 167 | use ra_ide_db::{symbol_index::SymbolsDatabase, RootDatabase}; |
168 | use ra_syntax::TextRange; | ||
169 | use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset}; | 168 | use test_utils::{add_cursor, assert_eq_text, extract_range_or_offset, RangeOrOffset}; |
170 | 169 | ||
171 | use crate::{AssistCtx, AssistHandler}; | 170 | use crate::{AssistCtx, AssistHandler}; |
@@ -175,8 +174,7 @@ mod helpers { | |||
175 | let (mut db, file_id) = RootDatabase::with_single_file(text); | 174 | let (mut db, file_id) = RootDatabase::with_single_file(text); |
176 | // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`, | 175 | // FIXME: ideally, this should be done by the above `RootDatabase::with_single_file`, |
177 | // but it looks like this might need specialization? :( | 176 | // but it looks like this might need specialization? :( |
178 | let local_roots = vec![db.file_source_root(file_id)]; | 177 | db.set_local_roots(Arc::new(vec![db.file_source_root(file_id)])); |
179 | db.set_local_roots(Arc::new(local_roots)); | ||
180 | (db, file_id) | 178 | (db, file_id) |
181 | } | 179 | } |
182 | 180 | ||
@@ -206,11 +204,24 @@ mod helpers { | |||
206 | } | 204 | } |
207 | 205 | ||
208 | fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) { | 206 | fn check(assist: AssistHandler, before: &str, expected: ExpectedResult) { |
209 | let (range_or_offset, before) = extract_range_or_offset(before); | 207 | let (text_without_caret, file_with_caret_id, range_or_offset, db) = |
210 | let range: TextRange = range_or_offset.into(); | 208 | if before.contains("//-") { |
209 | let (mut db, position) = RootDatabase::with_position(before); | ||
210 | db.set_local_roots(Arc::new(vec![db.file_source_root(position.file_id)])); | ||
211 | ( | ||
212 | db.file_text(position.file_id).as_ref().to_owned(), | ||
213 | position.file_id, | ||
214 | RangeOrOffset::Offset(position.offset), | ||
215 | db, | ||
216 | ) | ||
217 | } else { | ||
218 | let (range_or_offset, text_without_caret) = extract_range_or_offset(before); | ||
219 | let (db, file_id) = with_single_file(&text_without_caret); | ||
220 | (text_without_caret, file_id, range_or_offset, db) | ||
221 | }; | ||
222 | |||
223 | let frange = FileRange { file_id: file_with_caret_id, range: range_or_offset.into() }; | ||
211 | 224 | ||
212 | let (db, file_id) = with_single_file(&before); | ||
213 | let frange = FileRange { file_id, range }; | ||
214 | let sema = Semantics::new(&db); | 225 | let sema = Semantics::new(&db); |
215 | let assist_ctx = AssistCtx::new(&sema, frange, true); | 226 | let assist_ctx = AssistCtx::new(&sema, frange, true); |
216 | 227 | ||
@@ -218,7 +229,7 @@ mod helpers { | |||
218 | (Some(assist), ExpectedResult::After(after)) => { | 229 | (Some(assist), ExpectedResult::After(after)) => { |
219 | let action = assist.0[0].action.clone().unwrap(); | 230 | let action = assist.0[0].action.clone().unwrap(); |
220 | 231 | ||
221 | let mut actual = action.edit.apply(&before); | 232 | let mut actual = action.edit.apply(&text_without_caret); |
222 | match action.cursor_position { | 233 | match action.cursor_position { |
223 | None => { | 234 | None => { |
224 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { | 235 | if let RangeOrOffset::Offset(before_cursor_pos) = range_or_offset { |
@@ -237,7 +248,7 @@ mod helpers { | |||
237 | (Some(assist), ExpectedResult::Target(target)) => { | 248 | (Some(assist), ExpectedResult::Target(target)) => { |
238 | let action = assist.0[0].action.clone().unwrap(); | 249 | let action = assist.0[0].action.clone().unwrap(); |
239 | let range = action.target.expect("expected target on action"); | 250 | let range = action.target.expect("expected target on action"); |
240 | assert_eq_text!(&before[range], target); | 251 | assert_eq_text!(&text_without_caret[range], target); |
241 | } | 252 | } |
242 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), | 253 | (Some(_), ExpectedResult::NotApplicable) => panic!("assist should not be applicable!"), |
243 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { | 254 | (None, ExpectedResult::After(_)) | (None, ExpectedResult::Target(_)) => { |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index e91abf6f5..c5cfd875f 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -33,7 +33,11 @@ use ra_syntax::{ | |||
33 | }; | 33 | }; |
34 | use rustc_hash::FxHashSet; | 34 | use rustc_hash::FxHashSet; |
35 | 35 | ||
36 | use crate::{db::HirDatabase, has_source::HasSource, CallableDef, HirDisplay, InFile, Name}; | 36 | use crate::{ |
37 | db::{DefDatabase, HirDatabase}, | ||
38 | has_source::HasSource, | ||
39 | CallableDef, HirDisplay, InFile, Name, | ||
40 | }; | ||
37 | 41 | ||
38 | /// hir::Crate describes a single crate. It's the main interface with which | 42 | /// hir::Crate describes a single crate. It's the main interface with which |
39 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the | 43 | /// a crate's dependencies interact. Mostly, it should be just a proxy for the |
@@ -274,20 +278,10 @@ impl Module { | |||
274 | /// this module, if possible. | 278 | /// this module, if possible. |
275 | pub fn find_use_path( | 279 | pub fn find_use_path( |
276 | self, | 280 | self, |
277 | db: &dyn HirDatabase, | 281 | db: &dyn DefDatabase, |
278 | item: ModuleDef, | 282 | item: impl Into<ItemInNs>, |
279 | ) -> Option<hir_def::path::ModPath> { | 283 | ) -> Option<hir_def::path::ModPath> { |
280 | // FIXME expose namespace choice | 284 | hir_def::find_path::find_path(db, item.into(), self.into()) |
281 | hir_def::find_path::find_path(db.upcast(), determine_item_namespace(item), self.into()) | ||
282 | } | ||
283 | } | ||
284 | |||
285 | fn determine_item_namespace(module_def: ModuleDef) -> ItemInNs { | ||
286 | match module_def { | ||
287 | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { | ||
288 | ItemInNs::Values(module_def.into()) | ||
289 | } | ||
290 | _ => ItemInNs::Types(module_def.into()), | ||
291 | } | 285 | } |
292 | } | 286 | } |
293 | 287 | ||
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index c179b13c6..62fb52e72 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs | |||
@@ -9,8 +9,8 @@ use hir_def::{ | |||
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::{ | 11 | use crate::{ |
12 | Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local, ModuleDef, StructField, | 12 | code_model::ItemInNs, Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, Local, |
13 | VariantDef, | 13 | MacroDef, ModuleDef, StructField, VariantDef, |
14 | }; | 14 | }; |
15 | 15 | ||
16 | macro_rules! from_id { | 16 | macro_rules! from_id { |
@@ -228,3 +228,20 @@ impl From<(DefWithBodyId, PatId)> for Local { | |||
228 | Local { parent, pat_id } | 228 | Local { parent, pat_id } |
229 | } | 229 | } |
230 | } | 230 | } |
231 | |||
232 | impl From<MacroDef> for ItemInNs { | ||
233 | fn from(macro_def: MacroDef) -> Self { | ||
234 | ItemInNs::Macros(macro_def.into()) | ||
235 | } | ||
236 | } | ||
237 | |||
238 | impl From<ModuleDef> for ItemInNs { | ||
239 | fn from(module_def: ModuleDef) -> Self { | ||
240 | match module_def { | ||
241 | ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { | ||
242 | ItemInNs::Values(module_def.into()) | ||
243 | } | ||
244 | _ => ItemInNs::Types(module_def.into()), | ||
245 | } | ||
246 | } | ||
247 | } | ||
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index 0ba382165..0a00054b2 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -1,6 +1,9 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_syntax::{ast::AstNode, TextRange, TextUnit}; | 3 | use ra_syntax::{ |
4 | ast::{self, AstNode}, | ||
5 | TextRange, TextUnit, | ||
6 | }; | ||
4 | use ra_text_edit::TextEdit; | 7 | use ra_text_edit::TextEdit; |
5 | 8 | ||
6 | use crate::{ | 9 | use crate::{ |
@@ -21,13 +24,8 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
21 | None => return, | 24 | None => return, |
22 | }; | 25 | }; |
23 | 26 | ||
24 | let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal { | 27 | let receiver_text = |
25 | let text = dot_receiver.syntax().text(); | 28 | get_receiver_text(dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); |
26 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
27 | text.slice(without_dot).to_string() | ||
28 | } else { | ||
29 | dot_receiver.syntax().text().to_string() | ||
30 | }; | ||
31 | 29 | ||
32 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { | 30 | let receiver_ty = match ctx.sema.type_of_expr(&dot_receiver) { |
33 | Some(it) => it, | 31 | Some(it) => it, |
@@ -35,10 +33,17 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
35 | }; | 33 | }; |
36 | 34 | ||
37 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { | 35 | if receiver_ty.is_bool() || receiver_ty.is_unknown() { |
38 | postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) | ||
39 | .add_to(acc); | ||
40 | postfix_snippet( | 36 | postfix_snippet( |
41 | ctx, | 37 | ctx, |
38 | &dot_receiver, | ||
39 | "if", | ||
40 | "if expr {}", | ||
41 | &format!("if {} {{$0}}", receiver_text), | ||
42 | ) | ||
43 | .add_to(acc); | ||
44 | postfix_snippet( | ||
45 | ctx, | ||
46 | &dot_receiver, | ||
42 | "while", | 47 | "while", |
43 | "while expr {}", | 48 | "while expr {}", |
44 | &format!("while {} {{\n$0\n}}", receiver_text), | 49 | &format!("while {} {{\n$0\n}}", receiver_text), |
@@ -46,28 +51,70 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
46 | .add_to(acc); | 51 | .add_to(acc); |
47 | } | 52 | } |
48 | 53 | ||
49 | postfix_snippet(ctx, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | 54 | // !&&&42 is a compiler error, ergo process it before considering the references |
55 | postfix_snippet(ctx, &dot_receiver, "not", "!expr", &format!("!{}", receiver_text)).add_to(acc); | ||
50 | 56 | ||
51 | postfix_snippet(ctx, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); | 57 | postfix_snippet(ctx, &dot_receiver, "ref", "&expr", &format!("&{}", receiver_text)).add_to(acc); |
52 | postfix_snippet(ctx, "refm", "&mut expr", &format!("&mut {}", receiver_text)).add_to(acc); | 58 | postfix_snippet(ctx, &dot_receiver, "refm", "&mut expr", &format!("&mut {}", receiver_text)) |
59 | .add_to(acc); | ||
60 | |||
61 | // The rest of the postfix completions create an expression that moves an argument, | ||
62 | // so it's better to consider references now to avoid breaking the compilation | ||
63 | let dot_receiver = include_references(dot_receiver); | ||
64 | let receiver_text = | ||
65 | get_receiver_text(&dot_receiver, ctx.dot_receiver_is_ambiguous_float_literal); | ||
53 | 66 | ||
54 | postfix_snippet( | 67 | postfix_snippet( |
55 | ctx, | 68 | ctx, |
69 | &dot_receiver, | ||
56 | "match", | 70 | "match", |
57 | "match expr {}", | 71 | "match expr {}", |
58 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), | 72 | &format!("match {} {{\n ${{1:_}} => {{$0\\}},\n}}", receiver_text), |
59 | ) | 73 | ) |
60 | .add_to(acc); | 74 | .add_to(acc); |
61 | 75 | ||
62 | postfix_snippet(ctx, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)).add_to(acc); | 76 | postfix_snippet( |
77 | ctx, | ||
78 | &dot_receiver, | ||
79 | "box", | ||
80 | "Box::new(expr)", | ||
81 | &format!("Box::new({})", receiver_text), | ||
82 | ) | ||
83 | .add_to(acc); | ||
63 | 84 | ||
64 | postfix_snippet(ctx, "box", "Box::new(expr)", &format!("Box::new({})", receiver_text)) | 85 | postfix_snippet(ctx, &dot_receiver, "dbg", "dbg!(expr)", &format!("dbg!({})", receiver_text)) |
65 | .add_to(acc); | 86 | .add_to(acc); |
66 | } | 87 | } |
67 | 88 | ||
68 | fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { | 89 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { |
90 | if receiver_is_ambiguous_float_literal { | ||
91 | let text = receiver.syntax().text(); | ||
92 | let without_dot = ..text.len() - TextUnit::of_char('.'); | ||
93 | text.slice(without_dot).to_string() | ||
94 | } else { | ||
95 | receiver.to_string() | ||
96 | } | ||
97 | } | ||
98 | |||
99 | fn include_references(initial_element: &ast::Expr) -> ast::Expr { | ||
100 | let mut resulting_element = initial_element.clone(); | ||
101 | while let Some(parent_ref_element) = | ||
102 | resulting_element.syntax().parent().and_then(ast::RefExpr::cast) | ||
103 | { | ||
104 | resulting_element = ast::Expr::from(parent_ref_element); | ||
105 | } | ||
106 | resulting_element | ||
107 | } | ||
108 | |||
109 | fn postfix_snippet( | ||
110 | ctx: &CompletionContext, | ||
111 | receiver: &ast::Expr, | ||
112 | label: &str, | ||
113 | detail: &str, | ||
114 | snippet: &str, | ||
115 | ) -> Builder { | ||
69 | let edit = { | 116 | let edit = { |
70 | let receiver_syntax = ctx.dot_receiver.as_ref().expect("no receiver available").syntax(); | 117 | let receiver_syntax = receiver.syntax(); |
71 | let receiver_range = ctx.sema.original_range(receiver_syntax).range; | 118 | let receiver_range = ctx.sema.original_range(receiver_syntax).range; |
72 | let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); | 119 | let delete_range = TextRange::from_to(receiver_range.start(), ctx.source_range().end()); |
73 | TextEdit::replace(delete_range, snippet.to_string()) | 120 | TextEdit::replace(delete_range, snippet.to_string()) |
@@ -340,4 +387,63 @@ mod tests { | |||
340 | "### | 387 | "### |
341 | ); | 388 | ); |
342 | } | 389 | } |
390 | |||
391 | #[test] | ||
392 | fn postfix_completion_for_references() { | ||
393 | assert_debug_snapshot!( | ||
394 | do_postfix_completion( | ||
395 | r#" | ||
396 | fn main() { | ||
397 | &&&&42.<|> | ||
398 | } | ||
399 | "#, | ||
400 | ), | ||
401 | @r###" | ||
402 | [ | ||
403 | CompletionItem { | ||
404 | label: "box", | ||
405 | source_range: [56; 56), | ||
406 | delete: [49; 56), | ||
407 | insert: "Box::new(&&&&42)", | ||
408 | detail: "Box::new(expr)", | ||
409 | }, | ||
410 | CompletionItem { | ||
411 | label: "dbg", | ||
412 | source_range: [56; 56), | ||
413 | delete: [49; 56), | ||
414 | insert: "dbg!(&&&&42)", | ||
415 | detail: "dbg!(expr)", | ||
416 | }, | ||
417 | CompletionItem { | ||
418 | label: "match", | ||
419 | source_range: [56; 56), | ||
420 | delete: [49; 56), | ||
421 | insert: "match &&&&42 {\n ${1:_} => {$0\\},\n}", | ||
422 | detail: "match expr {}", | ||
423 | }, | ||
424 | CompletionItem { | ||
425 | label: "not", | ||
426 | source_range: [56; 56), | ||
427 | delete: [53; 56), | ||
428 | insert: "!42", | ||
429 | detail: "!expr", | ||
430 | }, | ||
431 | CompletionItem { | ||
432 | label: "ref", | ||
433 | source_range: [56; 56), | ||
434 | delete: [53; 56), | ||
435 | insert: "&42", | ||
436 | detail: "&expr", | ||
437 | }, | ||
438 | CompletionItem { | ||
439 | label: "refm", | ||
440 | source_range: [56; 56), | ||
441 | delete: [53; 56), | ||
442 | insert: "&mut 42", | ||
443 | detail: "&mut expr", | ||
444 | }, | ||
445 | ] | ||
446 | "### | ||
447 | ); | ||
448 | } | ||
343 | } | 449 | } |
diff --git a/crates/ra_ide/src/completion/complete_record_literal.rs b/crates/ra_ide/src/completion/complete_record_literal.rs index 83ed1d52c..e4e764f58 100644 --- a/crates/ra_ide/src/completion/complete_record_literal.rs +++ b/crates/ra_ide/src/completion/complete_record_literal.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use crate::completion::{CompletionContext, Completions}; | 3 | use crate::completion::{CompletionContext, Completions}; |
4 | use ra_syntax::SmolStr; | ||
4 | 5 | ||
5 | /// Complete fields in fields literals. | 6 | /// Complete fields in fields literals. |
6 | pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { | 7 | pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionContext) { |
@@ -11,8 +12,24 @@ pub(super) fn complete_record_literal(acc: &mut Completions, ctx: &CompletionCon | |||
11 | _ => return, | 12 | _ => return, |
12 | }; | 13 | }; |
13 | 14 | ||
15 | let already_present_names: Vec<SmolStr> = ctx | ||
16 | .record_lit_syntax | ||
17 | .as_ref() | ||
18 | .and_then(|record_literal| record_literal.record_field_list()) | ||
19 | .map(|field_list| field_list.fields()) | ||
20 | .map(|fields| { | ||
21 | fields | ||
22 | .into_iter() | ||
23 | .filter_map(|field| field.name_ref()) | ||
24 | .map(|name_ref| name_ref.text().clone()) | ||
25 | .collect() | ||
26 | }) | ||
27 | .unwrap_or_default(); | ||
28 | |||
14 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { | 29 | for (field, field_ty) in ty.variant_fields(ctx.db, variant) { |
15 | acc.add_field(ctx, field, &field_ty); | 30 | if !already_present_names.contains(&SmolStr::from(field.name(ctx.db).to_string())) { |
31 | acc.add_field(ctx, field, &field_ty); | ||
32 | } | ||
16 | } | 33 | } |
17 | } | 34 | } |
18 | 35 | ||
@@ -178,4 +195,47 @@ mod tests { | |||
178 | ] | 195 | ] |
179 | "###); | 196 | "###); |
180 | } | 197 | } |
198 | |||
199 | #[test] | ||
200 | fn only_missing_fields_are_completed() { | ||
201 | let completions = complete( | ||
202 | r" | ||
203 | struct S { | ||
204 | foo1: u32, | ||
205 | foo2: u32, | ||
206 | bar: u32, | ||
207 | baz: u32, | ||
208 | } | ||
209 | |||
210 | fn main() { | ||
211 | let foo1 = 1; | ||
212 | let s = S { | ||
213 | foo1, | ||
214 | foo2: 5, | ||
215 | <|> | ||
216 | } | ||
217 | } | ||
218 | ", | ||
219 | ); | ||
220 | assert_debug_snapshot!(completions, @r###" | ||
221 | [ | ||
222 | CompletionItem { | ||
223 | label: "bar", | ||
224 | source_range: [302; 302), | ||
225 | delete: [302; 302), | ||
226 | insert: "bar", | ||
227 | kind: Field, | ||
228 | detail: "u32", | ||
229 | }, | ||
230 | CompletionItem { | ||
231 | label: "baz", | ||
232 | source_range: [302; 302), | ||
233 | delete: [302; 302), | ||
234 | insert: "baz", | ||
235 | kind: Field, | ||
236 | detail: "u32", | ||
237 | }, | ||
238 | ] | ||
239 | "###); | ||
240 | } | ||
181 | } | 241 | } |
diff --git a/crates/ra_ide_db/Cargo.toml b/crates/ra_ide_db/Cargo.toml index de4f5bce0..c3921bd40 100644 --- a/crates/ra_ide_db/Cargo.toml +++ b/crates/ra_ide_db/Cargo.toml | |||
@@ -17,6 +17,7 @@ fst = { version = "0.4", default-features = false } | |||
17 | rustc-hash = "1.1.0" | 17 | rustc-hash = "1.1.0" |
18 | superslice = "1.0.0" | 18 | superslice = "1.0.0" |
19 | once_cell = "1.3.1" | 19 | once_cell = "1.3.1" |
20 | either = "1.5.3" | ||
20 | 21 | ||
21 | ra_syntax = { path = "../ra_syntax" } | 22 | ra_syntax = { path = "../ra_syntax" } |
22 | ra_text_edit = { path = "../ra_text_edit" } | 23 | ra_text_edit = { path = "../ra_text_edit" } |
diff --git a/crates/ra_ide_db/src/imports_locator.rs b/crates/ra_ide_db/src/imports_locator.rs index c96351982..bf0d8db60 100644 --- a/crates/ra_ide_db/src/imports_locator.rs +++ b/crates/ra_ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the ra_assists module. | 1 | //! This module contains an import search funcionality that is provided to the ra_assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the ra_assists module. |
3 | 3 | ||
4 | use hir::{ModuleDef, Semantics}; | 4 | use hir::{MacroDef, ModuleDef, Semantics}; |
5 | use ra_prof::profile; | 5 | use ra_prof::profile; |
6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; | 6 | use ra_syntax::{ast, AstNode, SyntaxKind::NAME}; |
7 | 7 | ||
@@ -10,6 +10,7 @@ use crate::{ | |||
10 | symbol_index::{self, FileSymbol, Query}, | 10 | symbol_index::{self, FileSymbol, Query}, |
11 | RootDatabase, | 11 | RootDatabase, |
12 | }; | 12 | }; |
13 | use either::Either; | ||
13 | 14 | ||
14 | pub struct ImportsLocator<'a> { | 15 | pub struct ImportsLocator<'a> { |
15 | sema: Semantics<'a, RootDatabase>, | 16 | sema: Semantics<'a, RootDatabase>, |
@@ -20,7 +21,7 @@ impl<'a> ImportsLocator<'a> { | |||
20 | Self { sema: Semantics::new(db) } | 21 | Self { sema: Semantics::new(db) } |
21 | } | 22 | } |
22 | 23 | ||
23 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<ModuleDef> { | 24 | pub fn find_imports(&mut self, name_to_import: &str) -> Vec<Either<ModuleDef, MacroDef>> { |
24 | let _p = profile("search_for_imports"); | 25 | let _p = profile("search_for_imports"); |
25 | let db = self.sema.db; | 26 | let db = self.sema.db; |
26 | 27 | ||
@@ -43,7 +44,8 @@ impl<'a> ImportsLocator<'a> { | |||
43 | .chain(lib_results.into_iter()) | 44 | .chain(lib_results.into_iter()) |
44 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) | 45 | .filter_map(|import_candidate| self.get_name_definition(&import_candidate)) |
45 | .filter_map(|name_definition_to_import| match name_definition_to_import { | 46 | .filter_map(|name_definition_to_import| match name_definition_to_import { |
46 | Definition::ModuleDef(module_def) => Some(module_def), | 47 | Definition::ModuleDef(module_def) => Some(Either::Left(module_def)), |
48 | Definition::Macro(macro_def) => Some(Either::Right(macro_def)), | ||
47 | _ => None, | 49 | _ => None, |
48 | }) | 50 | }) |
49 | .collect() | 51 | .collect() |
diff --git a/docs/user/readme.adoc b/docs/user/readme.adoc index 0dfc12b52..e00d14dfb 100644 --- a/docs/user/readme.adoc +++ b/docs/user/readme.adoc | |||
@@ -98,6 +98,16 @@ You'll need Cargo, nodejs and npm for this. | |||
98 | 98 | ||
99 | Note that installing via `xtask install` does not work for VS Code Remote, instead you'll need to install the `.vsix` manually. | 99 | Note that installing via `xtask install` does not work for VS Code Remote, instead you'll need to install the `.vsix` manually. |
100 | 100 | ||
101 | ==== Troubleshooting | ||
102 | |||
103 | Here are some useful self-diagnostic commands: | ||
104 | |||
105 | * **Rust Analyzer: Show RA Version** shows the version of `rust-analyzer` binary | ||
106 | * **Rust Analyzer: Status** prints some statistics about the server, like the few latest LSP requests | ||
107 | * To enable server-side logging, run with `env RUST_LOG=info` and see `Output > Rust Analyzer Language Server` in VS Code's panel. | ||
108 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. | ||
109 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. | ||
110 | |||
101 | === Language Server Binary | 111 | === Language Server Binary |
102 | 112 | ||
103 | Other editors generally require `rust-analyzer` binary to be in `$PATH`. | 113 | Other editors generally require `rust-analyzer` binary to be in `$PATH`. |
diff --git a/editors/code/package.json b/editors/code/package.json index eb5748515..1d113ebb6 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -73,10 +73,18 @@ | |||
73 | "type": "string" | 73 | "type": "string" |
74 | }, | 74 | }, |
75 | "args": { | 75 | "args": { |
76 | "type": "array" | 76 | "type": "array", |
77 | "items": { | ||
78 | "type": "string" | ||
79 | } | ||
77 | }, | 80 | }, |
78 | "env": { | 81 | "env": { |
79 | "type": "object" | 82 | "type": "object", |
83 | "patternProperties": { | ||
84 | ".+": { | ||
85 | "type": "string" | ||
86 | } | ||
87 | } | ||
80 | } | 88 | } |
81 | } | 89 | } |
82 | } | 90 | } |
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 08d821dd0..82ca749f3 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts | |||
@@ -99,8 +99,10 @@ export async function createClient(config: Config, serverPath: string): Promise< | |||
99 | // Note that while the CallHierarchyFeature is stable the LSP protocol is not. | 99 | // Note that while the CallHierarchyFeature is stable the LSP protocol is not. |
100 | res.registerFeature(new CallHierarchyFeature(res)); | 100 | res.registerFeature(new CallHierarchyFeature(res)); |
101 | 101 | ||
102 | if (config.highlightingSemanticTokens) { | 102 | if (config.package.enableProposedApi) { |
103 | res.registerFeature(new SemanticTokensFeature(res)); | 103 | if (config.highlightingSemanticTokens) { |
104 | res.registerFeature(new SemanticTokensFeature(res)); | ||
105 | } | ||
104 | } | 106 | } |
105 | 107 | ||
106 | return res; | 108 | return res; |
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index be5296fcf..7668c20b7 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts | |||
@@ -1,29 +1,10 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import { log } from "./util"; | 2 | import { log } from "./util"; |
3 | 3 | ||
4 | export interface InlayHintOptions { | ||
5 | typeHints: boolean; | ||
6 | parameterHints: boolean; | ||
7 | maxLength: number | null; | ||
8 | } | ||
9 | |||
10 | export interface CargoWatchOptions { | ||
11 | enable: boolean; | ||
12 | arguments: string[]; | ||
13 | command: string; | ||
14 | allTargets: boolean; | ||
15 | } | ||
16 | |||
17 | export interface CargoFeatures { | ||
18 | noDefaultFeatures: boolean; | ||
19 | allFeatures: boolean; | ||
20 | features: string[]; | ||
21 | loadOutDirsFromCheck: boolean; | ||
22 | } | ||
23 | |||
24 | export type UpdatesChannel = "stable" | "nightly"; | 4 | export type UpdatesChannel = "stable" | "nightly"; |
25 | 5 | ||
26 | export const NIGHTLY_TAG = "nightly"; | 6 | export const NIGHTLY_TAG = "nightly"; |
7 | |||
27 | export class Config { | 8 | export class Config { |
28 | readonly extensionId = "matklad.rust-analyzer"; | 9 | readonly extensionId = "matklad.rust-analyzer"; |
29 | 10 | ||
@@ -38,37 +19,30 @@ export class Config { | |||
38 | ] | 19 | ] |
39 | .map(opt => `${this.rootSection}.${opt}`); | 20 | .map(opt => `${this.rootSection}.${opt}`); |
40 | 21 | ||
41 | readonly packageJsonVersion: string = vscode | 22 | readonly package: { |
42 | .extensions | 23 | version: string; |
43 | .getExtension(this.extensionId)! | 24 | releaseTag: string | undefined; |
44 | .packageJSON | 25 | enableProposedApi: boolean | undefined; |
45 | .version; | 26 | } = vscode.extensions.getExtension(this.extensionId)!.packageJSON; |
46 | |||
47 | readonly releaseTag: string | undefined = vscode | ||
48 | .extensions | ||
49 | .getExtension(this.extensionId)! | ||
50 | .packageJSON | ||
51 | .releaseTag ?? undefined; | ||
52 | 27 | ||
53 | private cfg!: vscode.WorkspaceConfiguration; | 28 | readonly globalStoragePath: string; |
54 | 29 | ||
55 | constructor(private readonly ctx: vscode.ExtensionContext) { | 30 | constructor(ctx: vscode.ExtensionContext) { |
56 | vscode.workspace.onDidChangeConfiguration(this.onConfigChange, this, ctx.subscriptions); | 31 | this.globalStoragePath = ctx.globalStoragePath; |
57 | this.refreshConfig(); | 32 | vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions); |
33 | this.refreshLogging(); | ||
58 | } | 34 | } |
59 | 35 | ||
60 | private refreshConfig() { | 36 | private refreshLogging() { |
61 | this.cfg = vscode.workspace.getConfiguration(this.rootSection); | 37 | log.setEnabled(this.traceExtension); |
62 | const enableLogging = this.cfg.get("trace.extension") as boolean; | ||
63 | log.setEnabled(enableLogging); | ||
64 | log.debug( | 38 | log.debug( |
65 | "Extension version:", this.packageJsonVersion, | 39 | "Extension version:", this.package.version, |
66 | "using configuration:", this.cfg | 40 | "using configuration:", this.cfg |
67 | ); | 41 | ); |
68 | } | 42 | } |
69 | 43 | ||
70 | private async onConfigChange(event: vscode.ConfigurationChangeEvent) { | 44 | private async onDidChangeConfiguration(event: vscode.ConfigurationChangeEvent) { |
71 | this.refreshConfig(); | 45 | this.refreshLogging(); |
72 | 46 | ||
73 | const requiresReloadOpt = this.requiresReloadOpts.find( | 47 | const requiresReloadOpt = this.requiresReloadOpts.find( |
74 | opt => event.affectsConfiguration(opt) | 48 | opt => event.affectsConfiguration(opt) |
@@ -86,49 +60,53 @@ export class Config { | |||
86 | } | 60 | } |
87 | } | 61 | } |
88 | 62 | ||
89 | get globalStoragePath(): string { return this.ctx.globalStoragePath; } | ||
90 | |||
91 | // We don't do runtime config validation here for simplicity. More on stackoverflow: | 63 | // We don't do runtime config validation here for simplicity. More on stackoverflow: |
92 | // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension | 64 | // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension |
93 | 65 | ||
94 | get serverPath() { return this.cfg.get("serverPath") as null | string; } | 66 | private get cfg(): vscode.WorkspaceConfiguration { |
95 | get channel() { return this.cfg.get<"stable" | "nightly">("updates.channel")!; } | 67 | return vscode.workspace.getConfiguration(this.rootSection); |
96 | get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload") as boolean; } | 68 | } |
97 | get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; } | 69 | |
98 | get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } | 70 | get serverPath() { return this.cfg.get<null | string>("serverPath")!; } |
99 | get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } | 71 | get channel() { return this.cfg.get<UpdatesChannel>("updates.channel")!; } |
100 | get lruCapacity() { return this.cfg.get("lruCapacity") as null | number; } | 72 | get askBeforeDownload() { return this.cfg.get<boolean>("updates.askBeforeDownload")!; } |
101 | get inlayHints(): InlayHintOptions { | 73 | get highlightingSemanticTokens() { return this.cfg.get<boolean>("highlighting.semanticTokens")!; } |
74 | get highlightingOn() { return this.cfg.get<boolean>("highlightingOn")!; } | ||
75 | get rainbowHighlightingOn() { return this.cfg.get<boolean>("rainbowHighlightingOn")!; } | ||
76 | get lruCapacity() { return this.cfg.get<null | number>("lruCapacity")!; } | ||
77 | get excludeGlobs() { return this.cfg.get<string[]>("excludeGlobs")!; } | ||
78 | get useClientWatching() { return this.cfg.get<boolean>("useClientWatching")!; } | ||
79 | get featureFlags() { return this.cfg.get<Record<string, boolean>>("featureFlags")!; } | ||
80 | get rustfmtArgs() { return this.cfg.get<string[]>("rustfmtArgs")!; } | ||
81 | get loadOutDirsFromCheck() { return this.cfg.get<boolean>("loadOutDirsFromCheck")!; } | ||
82 | get traceExtension() { return this.cfg.get<boolean>("trace.extension")!; } | ||
83 | |||
84 | // for internal use | ||
85 | get withSysroot() { return this.cfg.get<boolean>("withSysroot", true)!; } | ||
86 | |||
87 | get inlayHints() { | ||
102 | return { | 88 | return { |
103 | typeHints: this.cfg.get("inlayHints.typeHints") as boolean, | 89 | typeHints: this.cfg.get<boolean>("inlayHints.typeHints")!, |
104 | parameterHints: this.cfg.get("inlayHints.parameterHints") as boolean, | 90 | parameterHints: this.cfg.get<boolean>("inlayHints.parameterHints")!, |
105 | maxLength: this.cfg.get("inlayHints.maxLength") as null | number, | 91 | maxLength: this.cfg.get<null | number>("inlayHints.maxLength")!, |
106 | }; | 92 | }; |
107 | } | 93 | } |
108 | get excludeGlobs() { return this.cfg.get("excludeGlobs") as string[]; } | ||
109 | get useClientWatching() { return this.cfg.get("useClientWatching") as boolean; } | ||
110 | get featureFlags() { return this.cfg.get("featureFlags") as Record<string, boolean>; } | ||
111 | get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } | ||
112 | get loadOutDirsFromCheck() { return this.cfg.get("loadOutDirsFromCheck") as boolean; } | ||
113 | 94 | ||
114 | get cargoWatchOptions(): CargoWatchOptions { | 95 | get cargoWatchOptions() { |
115 | return { | 96 | return { |
116 | enable: this.cfg.get("cargo-watch.enable") as boolean, | 97 | enable: this.cfg.get<boolean>("cargo-watch.enable")!, |
117 | arguments: this.cfg.get("cargo-watch.arguments") as string[], | 98 | arguments: this.cfg.get<string[]>("cargo-watch.arguments")!, |
118 | allTargets: this.cfg.get("cargo-watch.allTargets") as boolean, | 99 | allTargets: this.cfg.get<boolean>("cargo-watch.allTargets")!, |
119 | command: this.cfg.get("cargo-watch.command") as string, | 100 | command: this.cfg.get<string>("cargo-watch.command")!, |
120 | }; | 101 | }; |
121 | } | 102 | } |
122 | 103 | ||
123 | get cargoFeatures(): CargoFeatures { | 104 | get cargoFeatures() { |
124 | return { | 105 | return { |
125 | noDefaultFeatures: this.cfg.get("cargoFeatures.noDefaultFeatures") as boolean, | 106 | noDefaultFeatures: this.cfg.get<boolean>("cargoFeatures.noDefaultFeatures")!, |
126 | allFeatures: this.cfg.get("cargoFeatures.allFeatures") as boolean, | 107 | allFeatures: this.cfg.get<boolean>("cargoFeatures.allFeatures")!, |
127 | features: this.cfg.get("cargoFeatures.features") as string[], | 108 | features: this.cfg.get<string[]>("cargoFeatures.features")!, |
128 | loadOutDirsFromCheck: this.cfg.get("cargoFeatures.loadOutDirsFromCheck") as boolean, | 109 | loadOutDirsFromCheck: this.cfg.get<boolean>("cargoFeatures.loadOutDirsFromCheck")!, |
129 | }; | 110 | }; |
130 | } | 111 | } |
131 | |||
132 | // for internal use | ||
133 | get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; } | ||
134 | } | 112 | } |
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index 5d2da9a76..7b7c19dfc 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts | |||
@@ -110,9 +110,9 @@ async function bootstrap(config: Config, state: PersistentState): Promise<string | |||
110 | } | 110 | } |
111 | 111 | ||
112 | async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> { | 112 | async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> { |
113 | if (config.releaseTag === undefined) return; | 113 | if (config.package.releaseTag === undefined) return; |
114 | if (config.channel === "stable") { | 114 | if (config.channel === "stable") { |
115 | if (config.releaseTag === NIGHTLY_TAG) { | 115 | if (config.package.releaseTag === NIGHTLY_TAG) { |
116 | vscode.window.showWarningMessage(`You are running a nightly version of rust-analyzer extension. | 116 | vscode.window.showWarningMessage(`You are running a nightly version of rust-analyzer extension. |
117 | To switch to stable, uninstall the extension and re-install it from the marketplace`); | 117 | To switch to stable, uninstall the extension and re-install it from the marketplace`); |
118 | } | 118 | } |
@@ -185,7 +185,7 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
185 | } | 185 | } |
186 | return explicitPath; | 186 | return explicitPath; |
187 | }; | 187 | }; |
188 | if (config.releaseTag === undefined) return "rust-analyzer"; | 188 | if (config.package.releaseTag === undefined) return "rust-analyzer"; |
189 | 189 | ||
190 | let binaryName: string | undefined = undefined; | 190 | let binaryName: string | undefined = undefined; |
191 | if (process.arch === "x64" || process.arch === "x32") { | 191 | if (process.arch === "x64" || process.arch === "x32") { |
@@ -211,21 +211,21 @@ async function getServer(config: Config, state: PersistentState): Promise<string | |||
211 | await state.updateServerVersion(undefined); | 211 | await state.updateServerVersion(undefined); |
212 | } | 212 | } |
213 | 213 | ||
214 | if (state.serverVersion === config.packageJsonVersion) return dest; | 214 | if (state.serverVersion === config.package.version) return dest; |
215 | 215 | ||
216 | if (config.askBeforeDownload) { | 216 | if (config.askBeforeDownload) { |
217 | const userResponse = await vscode.window.showInformationMessage( | 217 | const userResponse = await vscode.window.showInformationMessage( |
218 | `Language server version ${config.packageJsonVersion} for rust-analyzer is not installed.`, | 218 | `Language server version ${config.package.version} for rust-analyzer is not installed.`, |
219 | "Download now" | 219 | "Download now" |
220 | ); | 220 | ); |
221 | if (userResponse !== "Download now") return dest; | 221 | if (userResponse !== "Download now") return dest; |
222 | } | 222 | } |
223 | 223 | ||
224 | const release = await fetchRelease(config.releaseTag); | 224 | const release = await fetchRelease(config.package.releaseTag); |
225 | const artifact = release.assets.find(artifact => artifact.name === binaryName); | 225 | const artifact = release.assets.find(artifact => artifact.name === binaryName); |
226 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); | 226 | assert(!!artifact, `Bad release: ${JSON.stringify(release)}`); |
227 | 227 | ||
228 | await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 }); | 228 | await download(artifact.browser_download_url, dest, "Downloading rust-analyzer server", { mode: 0o755 }); |
229 | await state.updateServerVersion(config.packageJsonVersion); | 229 | await state.updateServerVersion(config.package.version); |
230 | return dest; | 230 | return dest; |
231 | } | 231 | } |