diff options
-rw-r--r-- | Cargo.lock | 1 | ||||
-rw-r--r-- | crates/hir/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/hir/src/semantics.rs | 76 | ||||
-rw-r--r-- | crates/hir_def/src/body/tests.rs | 28 | ||||
-rw-r--r-- | crates/hir_def/src/test_db.rs | 9 | ||||
-rw-r--r-- | crates/hir_expand/src/lib.rs | 70 | ||||
-rw-r--r-- | crates/ide/src/display/navigation_target.rs | 23 | ||||
-rw-r--r-- | crates/proc_macro_srv/src/lib.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/args.rs | 5 | ||||
-rw-r--r-- | crates/rust-analyzer/src/bin/main.rs | 3 | ||||
-rw-r--r-- | crates/rust-analyzer/src/cli/analysis_stats.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 430 | ||||
-rw-r--r-- | crates/test_utils/src/lib.rs | 26 | ||||
-rw-r--r-- | docs/dev/README.md | 2 | ||||
-rw-r--r-- | editors/code/package.json | 624 |
16 files changed, 781 insertions, 527 deletions
diff --git a/Cargo.lock b/Cargo.lock index 1101770e7..c6994127b 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -1550,6 +1550,7 @@ version = "1.0.60" | |||
1550 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1551 | checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" | 1551 | checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" |
1552 | dependencies = [ | 1552 | dependencies = [ |
1553 | "indexmap", | ||
1553 | "itoa", | 1554 | "itoa", |
1554 | "ryu", | 1555 | "ryu", |
1555 | "serde", | 1556 | "serde", |
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index c7c7377d7..302a52491 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs | |||
@@ -39,7 +39,7 @@ pub use crate::{ | |||
39 | Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, | 39 | Struct, Trait, Type, TypeAlias, TypeParam, Union, VariantDef, |
40 | }, | 40 | }, |
41 | has_source::HasSource, | 41 | has_source::HasSource, |
42 | semantics::{original_range, PathResolution, Semantics, SemanticsScope}, | 42 | semantics::{PathResolution, Semantics, SemanticsScope}, |
43 | }; | 43 | }; |
44 | 44 | ||
45 | pub use hir_def::{ | 45 | pub use hir_def::{ |
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs index c61a430e1..4315ad48b 100644 --- a/crates/hir/src/semantics.rs +++ b/crates/hir/src/semantics.rs | |||
@@ -13,10 +13,7 @@ use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; | |||
13 | use hir_ty::associated_type_shorthand_candidates; | 13 | use hir_ty::associated_type_shorthand_candidates; |
14 | use itertools::Itertools; | 14 | use itertools::Itertools; |
15 | use rustc_hash::{FxHashMap, FxHashSet}; | 15 | use rustc_hash::{FxHashMap, FxHashSet}; |
16 | use syntax::{ | 16 | use syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode, SyntaxToken, TextSize}; |
17 | algo::{find_node_at_offset, skip_trivia_token}, | ||
18 | ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, | ||
19 | }; | ||
20 | 17 | ||
21 | use crate::{ | 18 | use crate::{ |
22 | code_model::Access, | 19 | code_model::Access, |
@@ -25,7 +22,7 @@ use crate::{ | |||
25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 22 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
26 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 23 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
27 | AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, | 24 | AssocItem, Callable, Crate, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, |
28 | Module, ModuleDef, Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, | 25 | Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, VariantDef, |
29 | }; | 26 | }; |
30 | 27 | ||
31 | #[derive(Debug, Clone, PartialEq, Eq)] | 28 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -372,7 +369,7 @@ impl<'db> SemanticsImpl<'db> { | |||
372 | 369 | ||
373 | fn original_range(&self, node: &SyntaxNode) -> FileRange { | 370 | fn original_range(&self, node: &SyntaxNode) -> FileRange { |
374 | let node = self.find_file(node.clone()); | 371 | let node = self.find_file(node.clone()); |
375 | original_range(self.db, node.as_ref()) | 372 | node.as_ref().original_file_range(self.db.upcast()) |
376 | } | 373 | } |
377 | 374 | ||
378 | fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { | 375 | fn diagnostics_display_range(&self, diagnostics: &dyn Diagnostic) -> FileRange { |
@@ -380,7 +377,7 @@ impl<'db> SemanticsImpl<'db> { | |||
380 | let root = self.db.parse_or_expand(src.file_id).unwrap(); | 377 | let root = self.db.parse_or_expand(src.file_id).unwrap(); |
381 | let node = src.value.to_node(&root); | 378 | let node = src.value.to_node(&root); |
382 | self.cache(root, src.file_id); | 379 | self.cache(root, src.file_id); |
383 | original_range(self.db, src.with_value(&node)) | 380 | src.with_value(&node).original_file_range(self.db.upcast()) |
384 | } | 381 | } |
385 | 382 | ||
386 | fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { | 383 | fn ancestors_with_macros(&self, node: SyntaxNode) -> impl Iterator<Item = SyntaxNode> + '_ { |
@@ -771,68 +768,3 @@ impl<'a> SemanticsScope<'a> { | |||
771 | resolve_hir_path(self.db, &self.resolver, &path) | 768 | resolve_hir_path(self.db, &self.resolver, &path) |
772 | } | 769 | } |
773 | } | 770 | } |
774 | |||
775 | // FIXME: Change `HasSource` trait to work with `Semantics` and remove this? | ||
776 | pub fn original_range(db: &dyn HirDatabase, node: InFile<&SyntaxNode>) -> FileRange { | ||
777 | if let Some(range) = original_range_opt(db, node) { | ||
778 | let original_file = range.file_id.original_file(db.upcast()); | ||
779 | if range.file_id == original_file.into() { | ||
780 | return FileRange { file_id: original_file, range: range.value }; | ||
781 | } | ||
782 | |||
783 | log::error!("Fail to mapping up more for {:?}", range); | ||
784 | return FileRange { file_id: range.file_id.original_file(db.upcast()), range: range.value }; | ||
785 | } | ||
786 | |||
787 | // Fall back to whole macro call | ||
788 | if let Some(expansion) = node.file_id.expansion_info(db.upcast()) { | ||
789 | if let Some(call_node) = expansion.call_node() { | ||
790 | return FileRange { | ||
791 | file_id: call_node.file_id.original_file(db.upcast()), | ||
792 | range: call_node.value.text_range(), | ||
793 | }; | ||
794 | } | ||
795 | } | ||
796 | |||
797 | FileRange { file_id: node.file_id.original_file(db.upcast()), range: node.value.text_range() } | ||
798 | } | ||
799 | |||
800 | fn original_range_opt( | ||
801 | db: &dyn HirDatabase, | ||
802 | node: InFile<&SyntaxNode>, | ||
803 | ) -> Option<InFile<TextRange>> { | ||
804 | let expansion = node.file_id.expansion_info(db.upcast())?; | ||
805 | |||
806 | // the input node has only one token ? | ||
807 | let single = skip_trivia_token(node.value.first_token()?, Direction::Next)? | ||
808 | == skip_trivia_token(node.value.last_token()?, Direction::Prev)?; | ||
809 | |||
810 | Some(node.value.descendants().find_map(|it| { | ||
811 | let first = skip_trivia_token(it.first_token()?, Direction::Next)?; | ||
812 | let first = ascend_call_token(db, &expansion, node.with_value(first))?; | ||
813 | |||
814 | let last = skip_trivia_token(it.last_token()?, Direction::Prev)?; | ||
815 | let last = ascend_call_token(db, &expansion, node.with_value(last))?; | ||
816 | |||
817 | if (!single && first == last) || (first.file_id != last.file_id) { | ||
818 | return None; | ||
819 | } | ||
820 | |||
821 | Some(first.with_value(first.value.text_range().cover(last.value.text_range()))) | ||
822 | })?) | ||
823 | } | ||
824 | |||
825 | fn ascend_call_token( | ||
826 | db: &dyn HirDatabase, | ||
827 | expansion: &ExpansionInfo, | ||
828 | token: InFile<SyntaxToken>, | ||
829 | ) -> Option<InFile<SyntaxToken>> { | ||
830 | let (mapped, origin) = expansion.map_token_up(token.as_ref())?; | ||
831 | if origin != Origin::Call { | ||
832 | return None; | ||
833 | } | ||
834 | if let Some(info) = mapped.file_id.expansion_info(db.upcast()) { | ||
835 | return ascend_call_token(db, &info, mapped); | ||
836 | } | ||
837 | Some(mapped) | ||
838 | } | ||
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs index 6dba9817d..de77d5fc9 100644 --- a/crates/hir_def/src/body/tests.rs +++ b/crates/hir_def/src/body/tests.rs | |||
@@ -134,3 +134,31 @@ fn f() { | |||
134 | "#, | 134 | "#, |
135 | ); | 135 | ); |
136 | } | 136 | } |
137 | |||
138 | #[test] | ||
139 | fn dollar_crate_in_builtin_macro() { | ||
140 | check_diagnostics( | ||
141 | r#" | ||
142 | #[macro_export] | ||
143 | #[rustc_builtin_macro] | ||
144 | macro_rules! format_args {} | ||
145 | |||
146 | #[macro_export] | ||
147 | macro_rules! arg { | ||
148 | () => {} | ||
149 | } | ||
150 | |||
151 | #[macro_export] | ||
152 | macro_rules! outer { | ||
153 | () => { | ||
154 | $crate::format_args!( "", $crate::arg!(1) ) | ||
155 | }; | ||
156 | } | ||
157 | |||
158 | fn f() { | ||
159 | outer!(); | ||
160 | //^^^^^^^^ leftover tokens | ||
161 | } | ||
162 | "#, | ||
163 | ) | ||
164 | } | ||
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs index 00fe711fe..f8b150850 100644 --- a/crates/hir_def/src/test_db.rs +++ b/crates/hir_def/src/test_db.rs | |||
@@ -157,11 +157,12 @@ impl TestDB { | |||
157 | db.diagnostics(|d| { | 157 | db.diagnostics(|d| { |
158 | let src = d.display_source(); | 158 | let src = d.display_source(); |
159 | let root = db.parse_or_expand(src.file_id).unwrap(); | 159 | let root = db.parse_or_expand(src.file_id).unwrap(); |
160 | // FIXME: macros... | 160 | |
161 | let file_id = src.file_id.original_file(db); | 161 | let node = src.map(|ptr| ptr.to_node(&root)); |
162 | let range = src.value.to_node(&root).text_range(); | 162 | let frange = node.as_ref().original_file_range(db); |
163 | |||
163 | let message = d.message().to_owned(); | 164 | let message = d.message().to_owned(); |
164 | actual.entry(file_id).or_default().push((range, message)); | 165 | actual.entry(frange.file_id).or_default().push((frange.range, message)); |
165 | }); | 166 | }); |
166 | 167 | ||
167 | for (file_id, diags) in actual.iter_mut() { | 168 | for (file_id, diags) in actual.iter_mut() { |
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs index 2633fd8f7..1a9428514 100644 --- a/crates/hir_expand/src/lib.rs +++ b/crates/hir_expand/src/lib.rs | |||
@@ -20,11 +20,11 @@ pub use mbe::{ExpandError, ExpandResult}; | |||
20 | use std::hash::Hash; | 20 | use std::hash::Hash; |
21 | use std::sync::Arc; | 21 | use std::sync::Arc; |
22 | 22 | ||
23 | use base_db::{impl_intern_key, salsa, CrateId, FileId}; | 23 | use base_db::{impl_intern_key, salsa, CrateId, FileId, FileRange}; |
24 | use syntax::{ | 24 | use syntax::{ |
25 | algo, | 25 | algo::{self, skip_trivia_token}, |
26 | ast::{self, AstNode}, | 26 | ast::{self, AstNode}, |
27 | SyntaxNode, SyntaxToken, TextSize, | 27 | Direction, SyntaxNode, SyntaxToken, TextRange, TextSize, |
28 | }; | 28 | }; |
29 | 29 | ||
30 | use crate::ast_id_map::FileAstId; | 30 | use crate::ast_id_map::FileAstId; |
@@ -445,6 +445,70 @@ impl InFile<SyntaxNode> { | |||
445 | } | 445 | } |
446 | } | 446 | } |
447 | 447 | ||
448 | impl<'a> InFile<&'a SyntaxNode> { | ||
449 | pub fn original_file_range(self, db: &dyn db::AstDatabase) -> FileRange { | ||
450 | if let Some(range) = original_range_opt(db, self) { | ||
451 | let original_file = range.file_id.original_file(db); | ||
452 | if range.file_id == original_file.into() { | ||
453 | return FileRange { file_id: original_file, range: range.value }; | ||
454 | } | ||
455 | |||
456 | log::error!("Fail to mapping up more for {:?}", range); | ||
457 | return FileRange { file_id: range.file_id.original_file(db), range: range.value }; | ||
458 | } | ||
459 | |||
460 | // Fall back to whole macro call. | ||
461 | let mut node = self.cloned(); | ||
462 | while let Some(call_node) = node.file_id.call_node(db) { | ||
463 | node = call_node; | ||
464 | } | ||
465 | |||
466 | let orig_file = node.file_id.original_file(db); | ||
467 | assert_eq!(node.file_id, orig_file.into()); | ||
468 | FileRange { file_id: orig_file, range: node.value.text_range() } | ||
469 | } | ||
470 | } | ||
471 | |||
472 | fn original_range_opt( | ||
473 | db: &dyn db::AstDatabase, | ||
474 | node: InFile<&SyntaxNode>, | ||
475 | ) -> Option<InFile<TextRange>> { | ||
476 | let expansion = node.file_id.expansion_info(db)?; | ||
477 | |||
478 | // the input node has only one token ? | ||
479 | let single = skip_trivia_token(node.value.first_token()?, Direction::Next)? | ||
480 | == skip_trivia_token(node.value.last_token()?, Direction::Prev)?; | ||
481 | |||
482 | Some(node.value.descendants().find_map(|it| { | ||
483 | let first = skip_trivia_token(it.first_token()?, Direction::Next)?; | ||
484 | let first = ascend_call_token(db, &expansion, node.with_value(first))?; | ||
485 | |||
486 | let last = skip_trivia_token(it.last_token()?, Direction::Prev)?; | ||
487 | let last = ascend_call_token(db, &expansion, node.with_value(last))?; | ||
488 | |||
489 | if (!single && first == last) || (first.file_id != last.file_id) { | ||
490 | return None; | ||
491 | } | ||
492 | |||
493 | Some(first.with_value(first.value.text_range().cover(last.value.text_range()))) | ||
494 | })?) | ||
495 | } | ||
496 | |||
497 | fn ascend_call_token( | ||
498 | db: &dyn db::AstDatabase, | ||
499 | expansion: &ExpansionInfo, | ||
500 | token: InFile<SyntaxToken>, | ||
501 | ) -> Option<InFile<SyntaxToken>> { | ||
502 | let (mapped, origin) = expansion.map_token_up(token.as_ref())?; | ||
503 | if origin != Origin::Call { | ||
504 | return None; | ||
505 | } | ||
506 | if let Some(info) = mapped.file_id.expansion_info(db) { | ||
507 | return ascend_call_token(db, &info, mapped); | ||
508 | } | ||
509 | Some(mapped) | ||
510 | } | ||
511 | |||
448 | impl InFile<SyntaxToken> { | 512 | impl InFile<SyntaxToken> { |
449 | pub fn ancestors_with_macros( | 513 | pub fn ancestors_with_macros( |
450 | self, | 514 | self, |
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs index 0c429a262..4790d648a 100644 --- a/crates/ide/src/display/navigation_target.rs +++ b/crates/ide/src/display/navigation_target.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use either::Either; | 3 | use either::Either; |
4 | use hir::{original_range, AssocItem, FieldSource, HasSource, InFile, ModuleSource}; | 4 | use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource}; |
5 | use ide_db::base_db::{FileId, SourceDatabase}; | 5 | use ide_db::base_db::{FileId, SourceDatabase}; |
6 | use ide_db::{defs::Definition, RootDatabase}; | 6 | use ide_db::{defs::Definition, RootDatabase}; |
7 | use syntax::{ | 7 | use syntax::{ |
@@ -62,7 +62,8 @@ impl NavigationTarget { | |||
62 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { | 62 | pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { |
63 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); | 63 | let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); |
64 | if let Some(src) = module.declaration_source(db) { | 64 | if let Some(src) = module.declaration_source(db) { |
65 | let frange = original_range(db, src.as_ref().map(|it| it.syntax())); | 65 | let node = src.as_ref().map(|it| it.syntax()); |
66 | let frange = node.original_file_range(db); | ||
66 | let mut res = NavigationTarget::from_syntax( | 67 | let mut res = NavigationTarget::from_syntax( |
67 | frange.file_id, | 68 | frange.file_id, |
68 | name, | 69 | name, |
@@ -104,8 +105,8 @@ impl NavigationTarget { | |||
104 | let name = | 105 | let name = |
105 | node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); | 106 | node.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); |
106 | let focus_range = | 107 | let focus_range = |
107 | node.value.name().map(|it| original_range(db, node.with_value(it.syntax())).range); | 108 | node.value.name().map(|it| node.with_value(it.syntax()).original_file_range(db).range); |
108 | let frange = original_range(db, node.map(|it| it.syntax())); | 109 | let frange = node.map(|it| it.syntax()).original_file_range(db); |
109 | 110 | ||
110 | NavigationTarget::from_syntax( | 111 | NavigationTarget::from_syntax( |
111 | frange.file_id, | 112 | frange.file_id, |
@@ -124,7 +125,7 @@ impl NavigationTarget { | |||
124 | ) -> NavigationTarget { | 125 | ) -> NavigationTarget { |
125 | let name = | 126 | let name = |
126 | named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); | 127 | named.value.name().map(|it| it.text().clone()).unwrap_or_else(|| SmolStr::new("_")); |
127 | let frange = original_range(db, node.map(|it| it.syntax())); | 128 | let frange = node.map(|it| it.syntax()).original_file_range(db); |
128 | 129 | ||
129 | NavigationTarget::from_syntax( | 130 | NavigationTarget::from_syntax( |
130 | frange.file_id, | 131 | frange.file_id, |
@@ -236,7 +237,7 @@ impl ToNav for hir::Module { | |||
236 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) | 237 | (node.syntax(), node.name().map(|it| it.syntax().text_range())) |
237 | } | 238 | } |
238 | }; | 239 | }; |
239 | let frange = original_range(db, src.with_value(syntax)); | 240 | let frange = src.with_value(syntax).original_file_range(db); |
240 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) | 241 | NavigationTarget::from_syntax(frange.file_id, name, focus, frange.range, syntax.kind()) |
241 | } | 242 | } |
242 | } | 243 | } |
@@ -246,14 +247,14 @@ impl ToNav for hir::ImplDef { | |||
246 | let src = self.source(db); | 247 | let src = self.source(db); |
247 | let derive_attr = self.is_builtin_derive(db); | 248 | let derive_attr = self.is_builtin_derive(db); |
248 | let frange = if let Some(item) = &derive_attr { | 249 | let frange = if let Some(item) = &derive_attr { |
249 | original_range(db, item.syntax()) | 250 | item.syntax().original_file_range(db) |
250 | } else { | 251 | } else { |
251 | original_range(db, src.as_ref().map(|it| it.syntax())) | 252 | src.as_ref().map(|it| it.syntax()).original_file_range(db) |
252 | }; | 253 | }; |
253 | let focus_range = if derive_attr.is_some() { | 254 | let focus_range = if derive_attr.is_some() { |
254 | None | 255 | None |
255 | } else { | 256 | } else { |
256 | src.value.self_ty().map(|ty| original_range(db, src.with_value(ty.syntax())).range) | 257 | src.value.self_ty().map(|ty| src.with_value(ty.syntax()).original_file_range(db).range) |
257 | }; | 258 | }; |
258 | 259 | ||
259 | NavigationTarget::from_syntax( | 260 | NavigationTarget::from_syntax( |
@@ -278,7 +279,7 @@ impl ToNav for hir::Field { | |||
278 | res | 279 | res |
279 | } | 280 | } |
280 | FieldSource::Pos(it) => { | 281 | FieldSource::Pos(it) => { |
281 | let frange = original_range(db, src.with_value(it.syntax())); | 282 | let frange = src.with_value(it.syntax()).original_file_range(db); |
282 | NavigationTarget::from_syntax( | 283 | NavigationTarget::from_syntax( |
283 | frange.file_id, | 284 | frange.file_id, |
284 | "".into(), | 285 | "".into(), |
@@ -331,7 +332,7 @@ impl ToNav for hir::Local { | |||
331 | } | 332 | } |
332 | Either::Right(it) => it.syntax().clone(), | 333 | Either::Right(it) => it.syntax().clone(), |
333 | }; | 334 | }; |
334 | let full_range = original_range(db, src.with_value(&node)); | 335 | let full_range = src.with_value(&node).original_file_range(db); |
335 | let name = match self.name(db) { | 336 | let name = match self.name(db) { |
336 | Some(it) => it.to_string().into(), | 337 | Some(it) => it.to_string().into(), |
337 | None => "".into(), | 338 | None => "".into(), |
diff --git a/crates/proc_macro_srv/src/lib.rs b/crates/proc_macro_srv/src/lib.rs index 6e890f8e2..9cca96994 100644 --- a/crates/proc_macro_srv/src/lib.rs +++ b/crates/proc_macro_srv/src/lib.rs | |||
@@ -40,7 +40,8 @@ impl ProcMacroSrv { | |||
40 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { | 40 | match expander.expand(&task.macro_name, &task.macro_body, task.attributes.as_ref()) { |
41 | Ok(expansion) => Ok(ExpansionResult { expansion }), | 41 | Ok(expansion) => Ok(ExpansionResult { expansion }), |
42 | Err(msg) => { | 42 | Err(msg) => { |
43 | Err(format!("Cannot perform expansion for {}: error {:?}", &task.macro_name, msg)) | 43 | let msg = msg.as_str().unwrap_or("<unknown error>"); |
44 | Err(format!("proc-macro panicked: {}", msg)) | ||
44 | } | 45 | } |
45 | } | 46 | } |
46 | } | 47 | } |
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml index 0a055b039..039976e4b 100644 --- a/crates/rust-analyzer/Cargo.toml +++ b/crates/rust-analyzer/Cargo.toml | |||
@@ -27,7 +27,7 @@ pico-args = "0.3.1" | |||
27 | oorandom = "11.1.2" | 27 | oorandom = "11.1.2" |
28 | rustc-hash = "1.1.0" | 28 | rustc-hash = "1.1.0" |
29 | serde = { version = "1.0.106", features = ["derive"] } | 29 | serde = { version = "1.0.106", features = ["derive"] } |
30 | serde_json = "1.0.48" | 30 | serde_json = { version = "1.0.48", features = ["preserve_order"] } |
31 | threadpool = "1.7.1" | 31 | threadpool = "1.7.1" |
32 | rayon = "1.5" | 32 | rayon = "1.5" |
33 | mimalloc = { version = "0.1.19", default-features = false, optional = true } | 33 | mimalloc = { version = "0.1.19", default-features = false, optional = true } |
diff --git a/crates/rust-analyzer/src/bin/args.rs b/crates/rust-analyzer/src/bin/args.rs index 8ddf1e031..0a471154e 100644 --- a/crates/rust-analyzer/src/bin/args.rs +++ b/crates/rust-analyzer/src/bin/args.rs | |||
@@ -28,6 +28,7 @@ pub(crate) enum Command { | |||
28 | StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> }, | 28 | StructuredSearch { debug_snippet: Option<String>, patterns: Vec<SsrPattern> }, |
29 | ProcMacro, | 29 | ProcMacro, |
30 | RunServer, | 30 | RunServer, |
31 | PrintConfigSchema, | ||
31 | Version, | 32 | Version, |
32 | Help, | 33 | Help, |
33 | } | 34 | } |
@@ -135,6 +136,10 @@ impl Args { | |||
135 | return Ok(Args { verbosity, log_file: None, command: Command::Help }); | 136 | return Ok(Args { verbosity, log_file: None, command: Command::Help }); |
136 | } | 137 | } |
137 | 138 | ||
139 | if matches.contains("--print-config-schema") { | ||
140 | return Ok(Args { verbosity, log_file, command: Command::PrintConfigSchema }); | ||
141 | } | ||
142 | |||
138 | let subcommand = match matches.subcommand()? { | 143 | let subcommand = match matches.subcommand()? { |
139 | Some(it) => it, | 144 | Some(it) => it, |
140 | None => { | 145 | None => { |
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs index 21fba8302..defdcbd74 100644 --- a/crates/rust-analyzer/src/bin/main.rs +++ b/crates/rust-analyzer/src/bin/main.rs | |||
@@ -31,6 +31,9 @@ fn try_main() -> Result<()> { | |||
31 | setup_logging(args.log_file)?; | 31 | setup_logging(args.log_file)?; |
32 | match args.command { | 32 | match args.command { |
33 | args::Command::RunServer => run_server()?, | 33 | args::Command::RunServer => run_server()?, |
34 | args::Command::PrintConfigSchema => { | ||
35 | println!("{:#}", Config::json_schema()); | ||
36 | } | ||
34 | args::Command::ProcMacro => proc_macro_srv::cli::run()?, | 37 | args::Command::ProcMacro => proc_macro_srv::cli::run()?, |
35 | 38 | ||
36 | args::Command::Parse { no_dump } => cli::parse(no_dump)?, | 39 | args::Command::Parse { no_dump } => cli::parse(no_dump)?, |
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs index 98ef0cd68..58d284d47 100644 --- a/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/crates/rust-analyzer/src/cli/analysis_stats.rs | |||
@@ -8,7 +8,7 @@ use std::{ | |||
8 | 8 | ||
9 | use hir::{ | 9 | use hir::{ |
10 | db::{AstDatabase, DefDatabase, HirDatabase}, | 10 | db::{AstDatabase, DefDatabase, HirDatabase}, |
11 | original_range, AssocItem, Crate, HasSource, HirDisplay, ModuleDef, | 11 | AssocItem, Crate, HasSource, HirDisplay, ModuleDef, |
12 | }; | 12 | }; |
13 | use hir_def::FunctionId; | 13 | use hir_def::FunctionId; |
14 | use hir_ty::{Ty, TypeWalk}; | 14 | use hir_ty::{Ty, TypeWalk}; |
@@ -232,7 +232,7 @@ impl AnalysisStatsCmd { | |||
232 | // But also, we should just turn the type mismatches into diagnostics and provide these | 232 | // But also, we should just turn the type mismatches into diagnostics and provide these |
233 | let root = db.parse_or_expand(src.file_id).unwrap(); | 233 | let root = db.parse_or_expand(src.file_id).unwrap(); |
234 | let node = src.map(|e| e.to_node(&root).syntax().clone()); | 234 | let node = src.map(|e| e.to_node(&root).syntax().clone()); |
235 | let original_range = original_range(db, node.as_ref()); | 235 | let original_range = node.as_ref().original_file_range(db); |
236 | let path = vfs.file_path(original_range.file_id); | 236 | let path = vfs.file_path(original_range.file_id); |
237 | let line_index = | 237 | let line_index = |
238 | host.analysis().file_line_index(original_range.file_id).unwrap(); | 238 | host.analysis().file_line_index(original_range.file_id).unwrap(); |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index 5243b50c8..345a56978 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -13,14 +13,166 @@ use flycheck::FlycheckConfig; | |||
13 | use hir::PrefixKind; | 13 | use hir::PrefixKind; |
14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; | 14 | use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; |
15 | use ide_db::helpers::insert_use::MergeBehaviour; | 15 | use ide_db::helpers::insert_use::MergeBehaviour; |
16 | use itertools::Itertools; | ||
16 | use lsp_types::{ClientCapabilities, MarkupKind}; | 17 | use lsp_types::{ClientCapabilities, MarkupKind}; |
17 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; | 18 | use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest}; |
18 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::FxHashSet; |
19 | use serde::Deserialize; | 20 | use serde::{de::DeserializeOwned, Deserialize}; |
20 | use vfs::AbsPathBuf; | 21 | use vfs::AbsPathBuf; |
21 | 22 | ||
22 | use crate::{caps::enabled_completions_resolve_capabilities, diagnostics::DiagnosticsMapConfig}; | 23 | use crate::{caps::enabled_completions_resolve_capabilities, diagnostics::DiagnosticsMapConfig}; |
23 | 24 | ||
25 | config_data! { | ||
26 | struct ConfigData { | ||
27 | /// The strategy to use when inserting new imports or merging imports. | ||
28 | assist_importMergeBehaviour: MergeBehaviourDef = "\"full\"", | ||
29 | /// The path structure for newly inserted paths to use. | ||
30 | assist_importPrefix: ImportPrefixDef = "\"plain\"", | ||
31 | |||
32 | /// Show function name and docs in parameter hints. | ||
33 | callInfo_full: bool = "true", | ||
34 | |||
35 | /// Automatically refresh project info via `cargo metadata` on | ||
36 | /// Cargo.toml changes. | ||
37 | cargo_autoreload: bool = "true", | ||
38 | /// Activate all available features. | ||
39 | cargo_allFeatures: bool = "false", | ||
40 | /// List of features to activate. | ||
41 | cargo_features: Vec<String> = "[]", | ||
42 | /// Run `cargo check` on startup to get the correct value for package | ||
43 | /// OUT_DIRs. | ||
44 | cargo_loadOutDirsFromCheck: bool = "false", | ||
45 | /// Do not activate the `default` feature. | ||
46 | cargo_noDefaultFeatures: bool = "false", | ||
47 | /// Compilation target (target triple). | ||
48 | cargo_target: Option<String> = "null", | ||
49 | /// Internal config for debugging, disables loading of sysroot crates. | ||
50 | cargo_noSysroot: bool = "false", | ||
51 | |||
52 | /// Run specified `cargo check` command for diagnostics on save. | ||
53 | checkOnSave_enable: bool = "true", | ||
54 | /// Check with all features (will be passed as `--all-features`). | ||
55 | /// Defaults to `rust-analyzer.cargo.allFeatures`. | ||
56 | checkOnSave_allFeatures: Option<bool> = "null", | ||
57 | /// Check all targets and tests (will be passed as `--all-targets`). | ||
58 | checkOnSave_allTargets: bool = "true", | ||
59 | /// Cargo command to use for `cargo check`. | ||
60 | checkOnSave_command: String = "\"check\"", | ||
61 | /// Do not activate the `default` feature. | ||
62 | checkOnSave_noDefaultFeatures: Option<bool> = "null", | ||
63 | /// Check for a specific target. Defaults to | ||
64 | /// `rust-analyzer.cargo.target`. | ||
65 | checkOnSave_target: Option<String> = "null", | ||
66 | /// Extra arguments for `cargo check`. | ||
67 | checkOnSave_extraArgs: Vec<String> = "[]", | ||
68 | /// List of features to activate. Defaults to | ||
69 | /// `rust-analyzer.cargo.features`. | ||
70 | checkOnSave_features: Option<Vec<String>> = "null", | ||
71 | /// Advanced option, fully override the command rust-analyzer uses for | ||
72 | /// checking. The command should include `--message-format=json` or | ||
73 | /// similar option. | ||
74 | checkOnSave_overrideCommand: Option<Vec<String>> = "null", | ||
75 | |||
76 | /// Whether to add argument snippets when completing functions. | ||
77 | completion_addCallArgumentSnippets: bool = "true", | ||
78 | /// Whether to add parenthesis when completing functions. | ||
79 | completion_addCallParenthesis: bool = "true", | ||
80 | /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. | ||
81 | completion_postfix_enable: bool = "true", | ||
82 | /// Toggles the additional completions that automatically add imports when completed. | ||
83 | /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. | ||
84 | completion_autoimport_enable: bool = "true", | ||
85 | |||
86 | /// Whether to show native rust-analyzer diagnostics. | ||
87 | diagnostics_enable: bool = "true", | ||
88 | /// Whether to show experimental rust-analyzer diagnostics that might | ||
89 | /// have more false positives than usual. | ||
90 | diagnostics_enableExperimental: bool = "true", | ||
91 | /// List of rust-analyzer diagnostics to disable. | ||
92 | diagnostics_disabled: FxHashSet<String> = "[]", | ||
93 | /// List of warnings that should be displayed with info severity.\nThe | ||
94 | /// warnings will be indicated by a blue squiggly underline in code and | ||
95 | /// a blue icon in the problems panel. | ||
96 | diagnostics_warningsAsHint: Vec<String> = "[]", | ||
97 | /// List of warnings that should be displayed with hint severity.\nThe | ||
98 | /// warnings will be indicated by faded text or three dots in code and | ||
99 | /// will not show up in the problems panel. | ||
100 | diagnostics_warningsAsInfo: Vec<String> = "[]", | ||
101 | |||
102 | /// Controls file watching implementation. | ||
103 | files_watcher: String = "\"client\"", | ||
104 | |||
105 | /// Whether to show `Debug` action. Only applies when | ||
106 | /// `#rust-analyzer.hoverActions.enable#` is set. | ||
107 | hoverActions_debug: bool = "true", | ||
108 | /// Whether to show HoverActions in Rust files. | ||
109 | hoverActions_enable: bool = "true", | ||
110 | /// Whether to show `Go to Type Definition` action. Only applies when | ||
111 | /// `#rust-analyzer.hoverActions.enable#` is set. | ||
112 | hoverActions_gotoTypeDef: bool = "true", | ||
113 | /// Whether to show `Implementations` action. Only applies when | ||
114 | /// `#rust-analyzer.hoverActions.enable#` is set. | ||
115 | hoverActions_implementations: bool = "true", | ||
116 | /// Whether to show `Run` action. Only applies when | ||
117 | /// `#rust-analyzer.hoverActions.enable#` is set. | ||
118 | hoverActions_run: bool = "true", | ||
119 | /// Use markdown syntax for links in hover. | ||
120 | hoverActions_linksInHover: bool = "true", | ||
121 | |||
122 | /// Whether to show inlay type hints for method chains. | ||
123 | inlayHints_chainingHints: bool = "true", | ||
124 | /// Maximum length for inlay hints. | ||
125 | inlayHints_maxLength: Option<usize> = "null", | ||
126 | /// Whether to show function parameter name inlay hints at the call | ||
127 | /// site. | ||
128 | inlayHints_parameterHints: bool = "true", | ||
129 | /// Whether to show inlay type hints for variables. | ||
130 | inlayHints_typeHints: bool = "true", | ||
131 | |||
132 | /// Whether to show `Debug` lens. Only applies when | ||
133 | /// `#rust-analyzer.lens.enable#` is set. | ||
134 | lens_debug: bool = "true", | ||
135 | /// Whether to show CodeLens in Rust files. | ||
136 | lens_enable: bool = "true", | ||
137 | /// Whether to show `Implementations` lens. Only applies when | ||
138 | /// `#rust-analyzer.lens.enable#` is set. | ||
139 | lens_implementations: bool = "true", | ||
140 | /// Whether to show `Run` lens. Only applies when | ||
141 | /// `#rust-analyzer.lens.enable#` is set. | ||
142 | lens_run: bool = "true", | ||
143 | /// Whether to show `Method References` lens. Only applies when | ||
144 | /// `#rust-analyzer.lens.enable#` is set. | ||
145 | lens_methodReferences: bool = "false", | ||
146 | |||
147 | /// Disable project auto-discovery in favor of explicitly specified set | ||
148 | /// of projects. \nElements must be paths pointing to Cargo.toml, | ||
149 | /// rust-project.json, or JSON objects in rust-project.json format. | ||
150 | linkedProjects: Vec<ManifestOrProjectJson> = "[]", | ||
151 | /// Number of syntax trees rust-analyzer keeps in memory. | ||
152 | lruCapacity: Option<usize> = "null", | ||
153 | /// Whether to show `can't find Cargo.toml` error message. | ||
154 | notifications_cargoTomlNotFound: bool = "true", | ||
155 | /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be | ||
156 | /// enabled. | ||
157 | procMacro_enable: bool = "false", | ||
158 | |||
159 | /// Command to be executed instead of 'cargo' for runnables. | ||
160 | runnables_overrideCargo: Option<String> = "null", | ||
161 | /// Additional arguments to be passed to cargo for runnables such as | ||
162 | /// tests or binaries.\nFor example, it may be '--release'. | ||
163 | runnables_cargoExtraArgs: Vec<String> = "[]", | ||
164 | |||
165 | /// Path to the rust compiler sources, for usage in rustc_private projects. | ||
166 | rustcSource : Option<String> = "null", | ||
167 | |||
168 | /// Additional arguments to rustfmt. | ||
169 | rustfmt_extraArgs: Vec<String> = "[]", | ||
170 | /// Advanced option, fully override the command rust-analyzer uses for | ||
171 | /// formatting. | ||
172 | rustfmt_overrideCommand: Option<Vec<String>> = "null", | ||
173 | } | ||
174 | } | ||
175 | |||
24 | #[derive(Debug, Clone)] | 176 | #[derive(Debug, Clone)] |
25 | pub struct Config { | 177 | pub struct Config { |
26 | pub client_caps: ClientCapsConfig, | 178 | pub client_caps: ClientCapsConfig, |
@@ -149,25 +301,27 @@ pub struct ClientCapsConfig { | |||
149 | 301 | ||
150 | impl Config { | 302 | impl Config { |
151 | pub fn new(root_path: AbsPathBuf) -> Self { | 303 | pub fn new(root_path: AbsPathBuf) -> Self { |
152 | Config { | 304 | // Defaults here don't matter, we'll immediately re-write them with |
305 | // ConfigData. | ||
306 | let mut res = Config { | ||
153 | client_caps: ClientCapsConfig::default(), | 307 | client_caps: ClientCapsConfig::default(), |
154 | 308 | ||
155 | publish_diagnostics: true, | 309 | publish_diagnostics: false, |
156 | diagnostics: DiagnosticsConfig::default(), | 310 | diagnostics: DiagnosticsConfig::default(), |
157 | diagnostics_map: DiagnosticsMapConfig::default(), | 311 | diagnostics_map: DiagnosticsMapConfig::default(), |
158 | lru_capacity: None, | 312 | lru_capacity: None, |
159 | proc_macro_srv: None, | 313 | proc_macro_srv: None, |
160 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, | 314 | files: FilesConfig { watcher: FilesWatcher::Notify, exclude: Vec::new() }, |
161 | notifications: NotificationsConfig { cargo_toml_not_found: true }, | 315 | notifications: NotificationsConfig { cargo_toml_not_found: false }, |
162 | 316 | ||
163 | cargo_autoreload: true, | 317 | cargo_autoreload: false, |
164 | cargo: CargoConfig::default(), | 318 | cargo: CargoConfig::default(), |
165 | rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, | 319 | rustfmt: RustfmtConfig::Rustfmt { extra_args: Vec::new() }, |
166 | flycheck: Some(FlycheckConfig::CargoCommand { | 320 | flycheck: Some(FlycheckConfig::CargoCommand { |
167 | command: "check".to_string(), | 321 | command: String::new(), |
168 | target_triple: None, | 322 | target_triple: None, |
169 | no_default_features: false, | 323 | no_default_features: false, |
170 | all_targets: true, | 324 | all_targets: false, |
171 | all_features: false, | 325 | all_features: false, |
172 | extra_args: Vec::new(), | 326 | extra_args: Vec::new(), |
173 | features: Vec::new(), | 327 | features: Vec::new(), |
@@ -175,35 +329,32 @@ impl Config { | |||
175 | runnables: RunnablesConfig::default(), | 329 | runnables: RunnablesConfig::default(), |
176 | 330 | ||
177 | inlay_hints: InlayHintsConfig { | 331 | inlay_hints: InlayHintsConfig { |
178 | type_hints: true, | 332 | type_hints: false, |
179 | parameter_hints: true, | 333 | parameter_hints: false, |
180 | chaining_hints: true, | 334 | chaining_hints: false, |
181 | max_length: None, | 335 | max_length: None, |
182 | }, | 336 | }, |
183 | completion: CompletionConfig { | 337 | completion: CompletionConfig::default(), |
184 | enable_postfix_completions: true, | ||
185 | enable_autoimport_completions: true, | ||
186 | add_call_parenthesis: true, | ||
187 | add_call_argument_snippets: true, | ||
188 | ..CompletionConfig::default() | ||
189 | }, | ||
190 | assist: AssistConfig::default(), | 338 | assist: AssistConfig::default(), |
191 | call_info_full: true, | 339 | call_info_full: false, |
192 | lens: LensConfig::default(), | 340 | lens: LensConfig::default(), |
193 | hover: HoverConfig::default(), | 341 | hover: HoverConfig::default(), |
194 | semantic_tokens_refresh: false, | 342 | semantic_tokens_refresh: false, |
195 | linked_projects: Vec::new(), | 343 | linked_projects: Vec::new(), |
196 | root_path, | 344 | root_path, |
197 | } | 345 | }; |
346 | res.do_update(serde_json::json!({})); | ||
347 | res | ||
198 | } | 348 | } |
199 | |||
200 | pub fn update(&mut self, json: serde_json::Value) { | 349 | pub fn update(&mut self, json: serde_json::Value) { |
201 | log::info!("Config::update({:#})", json); | 350 | log::info!("Config::update({:#})", json); |
202 | |||
203 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { | 351 | if json.is_null() || json.as_object().map_or(false, |it| it.is_empty()) { |
204 | return; | 352 | return; |
205 | } | 353 | } |
206 | 354 | self.do_update(json); | |
355 | log::info!("Config::update() = {:#?}", self); | ||
356 | } | ||
357 | fn do_update(&mut self, json: serde_json::Value) { | ||
207 | let data = ConfigData::from_json(json); | 358 | let data = ConfigData::from_json(json); |
208 | 359 | ||
209 | self.publish_diagnostics = data.diagnostics_enable; | 360 | self.publish_diagnostics = data.diagnostics_enable; |
@@ -349,8 +500,6 @@ impl Config { | |||
349 | links_in_hover: data.hoverActions_linksInHover, | 500 | links_in_hover: data.hoverActions_linksInHover, |
350 | markdown: true, | 501 | markdown: true, |
351 | }; | 502 | }; |
352 | |||
353 | log::info!("Config::update() = {:#?}", self); | ||
354 | } | 503 | } |
355 | 504 | ||
356 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { | 505 | pub fn update_caps(&mut self, caps: &ClientCapabilities) { |
@@ -434,6 +583,10 @@ impl Config { | |||
434 | } | 583 | } |
435 | } | 584 | } |
436 | } | 585 | } |
586 | |||
587 | pub fn json_schema() -> serde_json::Value { | ||
588 | ConfigData::json_schema() | ||
589 | } | ||
437 | } | 590 | } |
438 | 591 | ||
439 | #[derive(Deserialize)] | 592 | #[derive(Deserialize)] |
@@ -459,94 +612,167 @@ enum ImportPrefixDef { | |||
459 | ByCrate, | 612 | ByCrate, |
460 | } | 613 | } |
461 | 614 | ||
462 | macro_rules! config_data { | 615 | macro_rules! _config_data { |
463 | (struct $name:ident { $($field:ident: $ty:ty = $default:expr,)*}) => { | 616 | (struct $name:ident { |
617 | $( | ||
618 | $(#[doc=$doc:literal])* | ||
619 | $field:ident: $ty:ty = $default:expr, | ||
620 | )* | ||
621 | }) => { | ||
464 | #[allow(non_snake_case)] | 622 | #[allow(non_snake_case)] |
465 | struct $name { $($field: $ty,)* } | 623 | struct $name { $($field: $ty,)* } |
466 | impl $name { | 624 | impl $name { |
467 | fn from_json(mut json: serde_json::Value) -> $name { | 625 | fn from_json(mut json: serde_json::Value) -> $name { |
468 | $name {$( | 626 | $name {$( |
469 | $field: { | 627 | $field: get_field(&mut json, stringify!($field), $default), |
470 | let pointer = stringify!($field).replace('_', "/"); | ||
471 | let pointer = format!("/{}", pointer); | ||
472 | json.pointer_mut(&pointer) | ||
473 | .and_then(|it| serde_json::from_value(it.take()).ok()) | ||
474 | .unwrap_or($default) | ||
475 | }, | ||
476 | )*} | 628 | )*} |
477 | } | 629 | } |
478 | } | ||
479 | 630 | ||
631 | fn json_schema() -> serde_json::Value { | ||
632 | schema(&[ | ||
633 | $({ | ||
634 | let field = stringify!($field); | ||
635 | let ty = stringify!($ty); | ||
636 | (field, ty, &[$($doc),*], $default) | ||
637 | },)* | ||
638 | ]) | ||
639 | } | ||
640 | } | ||
480 | }; | 641 | }; |
481 | } | 642 | } |
643 | use _config_data as config_data; | ||
644 | |||
645 | fn get_field<T: DeserializeOwned>( | ||
646 | json: &mut serde_json::Value, | ||
647 | field: &'static str, | ||
648 | default: &str, | ||
649 | ) -> T { | ||
650 | let default = serde_json::from_str(default).unwrap(); | ||
651 | |||
652 | let mut pointer = field.replace('_', "/"); | ||
653 | pointer.insert(0, '/'); | ||
654 | json.pointer_mut(&pointer) | ||
655 | .and_then(|it| serde_json::from_value(it.take()).ok()) | ||
656 | .unwrap_or(default) | ||
657 | } | ||
482 | 658 | ||
483 | config_data! { | 659 | fn schema(fields: &[(&'static str, &'static str, &[&str], &str)]) -> serde_json::Value { |
484 | struct ConfigData { | 660 | for ((f1, ..), (f2, ..)) in fields.iter().zip(&fields[1..]) { |
485 | assist_importMergeBehaviour: MergeBehaviourDef = MergeBehaviourDef::Full, | 661 | fn key(f: &str) -> &str { |
486 | assist_importPrefix: ImportPrefixDef = ImportPrefixDef::Plain, | 662 | f.splitn(2, "_").next().unwrap() |
487 | 663 | }; | |
488 | callInfo_full: bool = true, | 664 | assert!(key(f1) <= key(f2), "wrong field order: {:?} {:?}", f1, f2); |
489 | 665 | } | |
490 | cargo_autoreload: bool = true, | 666 | |
491 | cargo_allFeatures: bool = false, | 667 | let map = fields |
492 | cargo_features: Vec<String> = Vec::new(), | 668 | .iter() |
493 | cargo_loadOutDirsFromCheck: bool = false, | 669 | .map(|(field, ty, doc, default)| { |
494 | cargo_noDefaultFeatures: bool = false, | 670 | let name = field.replace("_", "."); |
495 | cargo_target: Option<String> = None, | 671 | let name = format!("rust-analyzer.{}", name); |
496 | cargo_noSysroot: bool = false, | 672 | let props = field_props(field, ty, doc, default); |
497 | 673 | (name, props) | |
498 | checkOnSave_enable: bool = true, | 674 | }) |
499 | checkOnSave_allFeatures: Option<bool> = None, | 675 | .collect::<serde_json::Map<_, _>>(); |
500 | checkOnSave_allTargets: bool = true, | 676 | map.into() |
501 | checkOnSave_command: String = "check".into(), | 677 | } |
502 | checkOnSave_noDefaultFeatures: Option<bool> = None, | 678 | |
503 | checkOnSave_target: Option<String> = None, | 679 | fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json::Value { |
504 | checkOnSave_extraArgs: Vec<String> = Vec::new(), | 680 | let doc = doc.iter().map(|it| it.trim()).join(" "); |
505 | checkOnSave_features: Option<Vec<String>> = None, | 681 | assert!( |
506 | checkOnSave_overrideCommand: Option<Vec<String>> = None, | 682 | doc.ends_with('.') && doc.starts_with(char::is_uppercase), |
507 | 683 | "bad docs for {}: {:?}", | |
508 | completion_addCallArgumentSnippets: bool = true, | 684 | field, |
509 | completion_addCallParenthesis: bool = true, | 685 | doc |
510 | completion_postfix_enable: bool = true, | 686 | ); |
511 | completion_autoimport_enable: bool = true, | 687 | let default = default.parse::<serde_json::Value>().unwrap(); |
512 | 688 | ||
513 | diagnostics_enable: bool = true, | 689 | let mut map = serde_json::Map::default(); |
514 | diagnostics_enableExperimental: bool = true, | 690 | macro_rules! set { |
515 | diagnostics_disabled: FxHashSet<String> = FxHashSet::default(), | 691 | ($($key:literal: $value:tt),*$(,)?) => {{$( |
516 | diagnostics_warningsAsHint: Vec<String> = Vec::new(), | 692 | map.insert($key.into(), serde_json::json!($value)); |
517 | diagnostics_warningsAsInfo: Vec<String> = Vec::new(), | 693 | )*}}; |
518 | |||
519 | files_watcher: String = "client".into(), | ||
520 | |||
521 | hoverActions_debug: bool = true, | ||
522 | hoverActions_enable: bool = true, | ||
523 | hoverActions_gotoTypeDef: bool = true, | ||
524 | hoverActions_implementations: bool = true, | ||
525 | hoverActions_run: bool = true, | ||
526 | hoverActions_linksInHover: bool = true, | ||
527 | |||
528 | inlayHints_chainingHints: bool = true, | ||
529 | inlayHints_maxLength: Option<usize> = None, | ||
530 | inlayHints_parameterHints: bool = true, | ||
531 | inlayHints_typeHints: bool = true, | ||
532 | |||
533 | lens_debug: bool = true, | ||
534 | lens_enable: bool = true, | ||
535 | lens_implementations: bool = true, | ||
536 | lens_run: bool = true, | ||
537 | lens_methodReferences: bool = false, | ||
538 | |||
539 | linkedProjects: Vec<ManifestOrProjectJson> = Vec::new(), | ||
540 | lruCapacity: Option<usize> = None, | ||
541 | notifications_cargoTomlNotFound: bool = true, | ||
542 | procMacro_enable: bool = false, | ||
543 | |||
544 | runnables_overrideCargo: Option<String> = None, | ||
545 | runnables_cargoExtraArgs: Vec<String> = Vec::new(), | ||
546 | |||
547 | rustfmt_extraArgs: Vec<String> = Vec::new(), | ||
548 | rustfmt_overrideCommand: Option<Vec<String>> = None, | ||
549 | |||
550 | rustcSource : Option<String> = None, | ||
551 | } | 694 | } |
695 | set!("markdownDescription": doc); | ||
696 | set!("default": default); | ||
697 | |||
698 | match ty { | ||
699 | "bool" => set!("type": "boolean"), | ||
700 | "String" => set!("type": "string"), | ||
701 | "Vec<String>" => set! { | ||
702 | "type": "array", | ||
703 | "items": { "type": "string" }, | ||
704 | }, | ||
705 | "FxHashSet<String>" => set! { | ||
706 | "type": "array", | ||
707 | "items": { "type": "string" }, | ||
708 | "uniqueItems": true, | ||
709 | }, | ||
710 | "Option<usize>" => set! { | ||
711 | "type": ["null", "integer"], | ||
712 | "minimum": 0, | ||
713 | }, | ||
714 | "Option<String>" => set! { | ||
715 | "type": ["null", "string"], | ||
716 | }, | ||
717 | "Option<bool>" => set! { | ||
718 | "type": ["null", "boolean"], | ||
719 | }, | ||
720 | "Option<Vec<String>>" => set! { | ||
721 | "type": ["null", "array"], | ||
722 | "items": { "type": "string" }, | ||
723 | }, | ||
724 | "MergeBehaviourDef" => set! { | ||
725 | "type": "string", | ||
726 | "enum": ["none", "full", "last"], | ||
727 | "enumDescriptions": [ | ||
728 | "No merging", | ||
729 | "Merge all layers of the import trees", | ||
730 | "Only merge the last layer of the import trees" | ||
731 | ], | ||
732 | }, | ||
733 | "ImportPrefixDef" => set! { | ||
734 | "type": "string", | ||
735 | "enum": [ | ||
736 | "plain", | ||
737 | "by_self", | ||
738 | "by_crate" | ||
739 | ], | ||
740 | "enumDescriptions": [ | ||
741 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | ||
742 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | ||
743 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | ||
744 | ], | ||
745 | }, | ||
746 | "Vec<ManifestOrProjectJson>" => set! { | ||
747 | "type": "array", | ||
748 | "items": { "type": ["string", "object"] }, | ||
749 | }, | ||
750 | _ => panic!("{}: {}", ty, default), | ||
751 | } | ||
752 | |||
753 | map.into() | ||
754 | } | ||
755 | |||
756 | #[test] | ||
757 | fn schema_in_sync_with_package_json() { | ||
758 | fn remove_ws(text: &str) -> String { | ||
759 | text.replace(char::is_whitespace, "") | ||
760 | } | ||
761 | |||
762 | let s = Config::json_schema(); | ||
763 | let schema = format!("{:#}", s); | ||
764 | let schema = schema.trim_start_matches('{').trim_end_matches('}'); | ||
765 | |||
766 | let package_json = std::env::current_dir() | ||
767 | .unwrap() | ||
768 | .ancestors() | ||
769 | .nth(2) | ||
770 | .unwrap() | ||
771 | .join("editors/code/package.json"); | ||
772 | let package_json = std::fs::read_to_string(&package_json).unwrap(); | ||
773 | |||
774 | let p = remove_ws(&package_json); | ||
775 | let s = remove_ws(&schema); | ||
776 | |||
777 | assert!(p.contains(&s), "update config in package.json. New config:\n{:#}", schema); | ||
552 | } | 778 | } |
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs index a49be4602..05940a546 100644 --- a/crates/test_utils/src/lib.rs +++ b/crates/test_utils/src/lib.rs | |||
@@ -321,12 +321,11 @@ fn lines_match_works() { | |||
321 | /// as paths). You can use a `"{...}"` string literal as a wildcard for | 321 | /// as paths). You can use a `"{...}"` string literal as a wildcard for |
322 | /// arbitrary nested JSON. Arrays are sorted before comparison. | 322 | /// arbitrary nested JSON. Arrays are sorted before comparison. |
323 | pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { | 323 | pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a Value, &'a Value)> { |
324 | use serde_json::Value::*; | ||
325 | match (expected, actual) { | 324 | match (expected, actual) { |
326 | (&Number(ref l), &Number(ref r)) if l == r => None, | 325 | (Value::Number(l), Value::Number(r)) if l == r => None, |
327 | (&Bool(l), &Bool(r)) if l == r => None, | 326 | (Value::Bool(l), Value::Bool(r)) if l == r => None, |
328 | (&String(ref l), &String(ref r)) if lines_match(l, r) => None, | 327 | (Value::String(l), Value::String(r)) if lines_match(l, r) => None, |
329 | (&Array(ref l), &Array(ref r)) => { | 328 | (Value::Array(l), Value::Array(r)) => { |
330 | if l.len() != r.len() { | 329 | if l.len() != r.len() { |
331 | return Some((expected, actual)); | 330 | return Some((expected, actual)); |
332 | } | 331 | } |
@@ -350,17 +349,26 @@ pub fn find_mismatch<'a>(expected: &'a Value, actual: &'a Value) -> Option<(&'a | |||
350 | None | 349 | None |
351 | } | 350 | } |
352 | } | 351 | } |
353 | (&Object(ref l), &Object(ref r)) => { | 352 | (Value::Object(l), Value::Object(r)) => { |
353 | fn sorted_values(obj: &serde_json::Map<String, Value>) -> Vec<&Value> { | ||
354 | let mut entries = obj.iter().collect::<Vec<_>>(); | ||
355 | entries.sort_by_key(|it| it.0); | ||
356 | entries.into_iter().map(|(_k, v)| v).collect::<Vec<_>>() | ||
357 | } | ||
358 | |||
354 | let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); | 359 | let same_keys = l.len() == r.len() && l.keys().all(|k| r.contains_key(k)); |
355 | if !same_keys { | 360 | if !same_keys { |
356 | return Some((expected, actual)); | 361 | return Some((expected, actual)); |
357 | } | 362 | } |
358 | 363 | ||
359 | l.values().zip(r.values()).filter_map(|(l, r)| find_mismatch(l, r)).next() | 364 | let l = sorted_values(l); |
365 | let r = sorted_values(r); | ||
366 | |||
367 | l.into_iter().zip(r).filter_map(|(l, r)| find_mismatch(l, r)).next() | ||
360 | } | 368 | } |
361 | (&Null, &Null) => None, | 369 | (Value::Null, Value::Null) => None, |
362 | // magic string literal "{...}" acts as wildcard for any sub-JSON | 370 | // magic string literal "{...}" acts as wildcard for any sub-JSON |
363 | (&String(ref l), _) if l == "{...}" => None, | 371 | (Value::String(l), _) if l == "{...}" => None, |
364 | _ => Some((expected, actual)), | 372 | _ => Some((expected, actual)), |
365 | } | 373 | } |
366 | } | 374 | } |
diff --git a/docs/dev/README.md b/docs/dev/README.md index ca324493f..2795f6b5c 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -170,7 +170,7 @@ In general, API is centered around UI concerns -- the result of the call is what | |||
170 | The results are 100% Rust specific though. | 170 | The results are 100% Rust specific though. |
171 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. | 171 | Shout outs to LSP developers for popularizing the idea that "UI" is a good place to draw a boundary at. |
172 | 172 | ||
173 | ## LSP is sateless | 173 | ## LSP is stateless |
174 | 174 | ||
175 | The protocol is implemented in the mostly stateless way. | 175 | The protocol is implemented in the mostly stateless way. |
176 | A good mental model is HTTP, which doesn't store per-client state, and instead relies on devices like cookies to maintain an illusion of state. | 176 | A good mental model is HTTP, which doesn't store per-client state, and instead relies on devices like cookies to maintain an illusion of state. |
diff --git a/editors/code/package.json b/editors/code/package.json index dbde37005..ca5f2ebc8 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -215,169 +215,6 @@ | |||
215 | "type": "object", | 215 | "type": "object", |
216 | "title": "Rust Analyzer", | 216 | "title": "Rust Analyzer", |
217 | "properties": { | 217 | "properties": { |
218 | "rust-analyzer.lruCapacity": { | ||
219 | "type": [ | ||
220 | "null", | ||
221 | "integer" | ||
222 | ], | ||
223 | "default": null, | ||
224 | "minimum": 0, | ||
225 | "exclusiveMinimum": true, | ||
226 | "description": "Number of syntax trees rust-analyzer keeps in memory." | ||
227 | }, | ||
228 | "rust-analyzer.files.watcher": { | ||
229 | "type": "string", | ||
230 | "enum": [ | ||
231 | "client", | ||
232 | "notify" | ||
233 | ], | ||
234 | "default": "client", | ||
235 | "description": "Controls file watching implementation." | ||
236 | }, | ||
237 | "rust-analyzer.files.exclude": { | ||
238 | "type": "array", | ||
239 | "items": { | ||
240 | "type": "string" | ||
241 | }, | ||
242 | "default": [], | ||
243 | "description": "Paths to exclude from analysis." | ||
244 | }, | ||
245 | "rust-analyzer.notifications.cargoTomlNotFound": { | ||
246 | "type": "boolean", | ||
247 | "default": true, | ||
248 | "markdownDescription": "Whether to show `can't find Cargo.toml` error message" | ||
249 | }, | ||
250 | "rust-analyzer.cargo.autoreload": { | ||
251 | "type": "boolean", | ||
252 | "default": true, | ||
253 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes" | ||
254 | }, | ||
255 | "rust-analyzer.cargo.noDefaultFeatures": { | ||
256 | "type": "boolean", | ||
257 | "default": false, | ||
258 | "markdownDescription": "Do not activate the `default` feature" | ||
259 | }, | ||
260 | "rust-analyzer.cargo.allFeatures": { | ||
261 | "type": "boolean", | ||
262 | "default": false, | ||
263 | "description": "Activate all available features" | ||
264 | }, | ||
265 | "rust-analyzer.cargo.features": { | ||
266 | "type": "array", | ||
267 | "items": { | ||
268 | "type": "string" | ||
269 | }, | ||
270 | "default": [], | ||
271 | "description": "List of features to activate" | ||
272 | }, | ||
273 | "rust-analyzer.cargo.loadOutDirsFromCheck": { | ||
274 | "type": "boolean", | ||
275 | "default": false, | ||
276 | "markdownDescription": "Run `cargo check` on startup to get the correct value for package OUT_DIRs" | ||
277 | }, | ||
278 | "rust-analyzer.cargo.target": { | ||
279 | "type": [ | ||
280 | "null", | ||
281 | "string" | ||
282 | ], | ||
283 | "default": null, | ||
284 | "description": "Specify the compilation target" | ||
285 | }, | ||
286 | "rust-analyzer.noSysroot": { | ||
287 | "markdownDescription": "Internal config for debugging, disables loading of sysroot crates", | ||
288 | "type": "boolean", | ||
289 | "default": false | ||
290 | }, | ||
291 | "rust-analyzer.rustfmt.extraArgs": { | ||
292 | "type": "array", | ||
293 | "items": { | ||
294 | "type": "string" | ||
295 | }, | ||
296 | "default": [], | ||
297 | "description": "Additional arguments to rustfmt" | ||
298 | }, | ||
299 | "rust-analyzer.rustfmt.overrideCommand": { | ||
300 | "type": [ | ||
301 | "null", | ||
302 | "array" | ||
303 | ], | ||
304 | "items": { | ||
305 | "type": "string", | ||
306 | "minItems": 1 | ||
307 | }, | ||
308 | "default": null, | ||
309 | "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for formatting." | ||
310 | }, | ||
311 | "rust-analyzer.checkOnSave.enable": { | ||
312 | "type": "boolean", | ||
313 | "default": true, | ||
314 | "markdownDescription": "Run specified `cargo check` command for diagnostics on save" | ||
315 | }, | ||
316 | "rust-analyzer.checkOnSave.extraArgs": { | ||
317 | "type": "array", | ||
318 | "items": { | ||
319 | "type": "string" | ||
320 | }, | ||
321 | "markdownDescription": "Extra arguments for `cargo check`", | ||
322 | "default": [] | ||
323 | }, | ||
324 | "rust-analyzer.checkOnSave.command": { | ||
325 | "type": "string", | ||
326 | "default": "check", | ||
327 | "markdownDescription": "Cargo command to use for `cargo check`" | ||
328 | }, | ||
329 | "rust-analyzer.checkOnSave.overrideCommand": { | ||
330 | "type": [ | ||
331 | "null", | ||
332 | "array" | ||
333 | ], | ||
334 | "items": { | ||
335 | "type": "string", | ||
336 | "minItems": 1 | ||
337 | }, | ||
338 | "default": null, | ||
339 | "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option." | ||
340 | }, | ||
341 | "rust-analyzer.checkOnSave.allTargets": { | ||
342 | "type": "boolean", | ||
343 | "default": true, | ||
344 | "markdownDescription": "Check all targets and tests (will be passed as `--all-targets`)" | ||
345 | }, | ||
346 | "rust-analyzer.checkOnSave.noDefaultFeatures": { | ||
347 | "type": [ | ||
348 | "null", | ||
349 | "boolean" | ||
350 | ], | ||
351 | "default": null, | ||
352 | "markdownDescription": "Do not activate the `default` feature" | ||
353 | }, | ||
354 | "rust-analyzer.checkOnSave.allFeatures": { | ||
355 | "type": [ | ||
356 | "null", | ||
357 | "boolean" | ||
358 | ], | ||
359 | "default": null, | ||
360 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`." | ||
361 | }, | ||
362 | "rust-analyzer.checkOnSave.features": { | ||
363 | "type": [ | ||
364 | "null", | ||
365 | "array" | ||
366 | ], | ||
367 | "items": { | ||
368 | "type": "string" | ||
369 | }, | ||
370 | "default": null, | ||
371 | "description": "List of features to activate. Defaults to `rust-analyzer.cargo.features`." | ||
372 | }, | ||
373 | "rust-analyzer.checkOnSave.target": { | ||
374 | "type": [ | ||
375 | "null", | ||
376 | "string" | ||
377 | ], | ||
378 | "default": null, | ||
379 | "description": "Check for a specific target. Defaults to `rust-analyzer.cargo.target`." | ||
380 | }, | ||
381 | "rust-analyzer.cargoRunner": { | 218 | "rust-analyzer.cargoRunner": { |
382 | "type": [ | 219 | "type": [ |
383 | "null", | 220 | "null", |
@@ -420,59 +257,6 @@ | |||
420 | "default": true, | 257 | "default": true, |
421 | "description": "Whether to show inlay hints" | 258 | "description": "Whether to show inlay hints" |
422 | }, | 259 | }, |
423 | "rust-analyzer.inlayHints.typeHints": { | ||
424 | "type": "boolean", | ||
425 | "default": true, | ||
426 | "description": "Whether to show inlay type hints for variables." | ||
427 | }, | ||
428 | "rust-analyzer.inlayHints.chainingHints": { | ||
429 | "type": "boolean", | ||
430 | "default": true, | ||
431 | "description": "Whether to show inlay type hints for method chains." | ||
432 | }, | ||
433 | "rust-analyzer.inlayHints.parameterHints": { | ||
434 | "type": "boolean", | ||
435 | "default": true, | ||
436 | "description": "Whether to show function parameter name inlay hints at the call site." | ||
437 | }, | ||
438 | "rust-analyzer.inlayHints.maxLength": { | ||
439 | "type": [ | ||
440 | "null", | ||
441 | "integer" | ||
442 | ], | ||
443 | "default": 20, | ||
444 | "minimum": 0, | ||
445 | "exclusiveMinimum": true, | ||
446 | "description": "Maximum length for inlay hints" | ||
447 | }, | ||
448 | "rust-analyzer.completion.addCallParenthesis": { | ||
449 | "type": "boolean", | ||
450 | "default": true, | ||
451 | "description": "Whether to add parenthesis when completing functions" | ||
452 | }, | ||
453 | "rust-analyzer.completion.addCallArgumentSnippets": { | ||
454 | "type": "boolean", | ||
455 | "default": true, | ||
456 | "description": "Whether to add argument snippets when completing functions" | ||
457 | }, | ||
458 | "rust-analyzer.completion.postfix.enable": { | ||
459 | "type": "boolean", | ||
460 | "default": true, | ||
461 | "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc." | ||
462 | }, | ||
463 | "rust-analyzer.completion.autoimport.enable": { | ||
464 | "type": "boolean", | ||
465 | "default": true, | ||
466 | "markdownDescription": [ | ||
467 | "Toggles the additional completions that automatically add imports when completed.", | ||
468 | "Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled" | ||
469 | ] | ||
470 | }, | ||
471 | "rust-analyzer.callInfo.full": { | ||
472 | "type": "boolean", | ||
473 | "default": true, | ||
474 | "description": "Show function name and docs in parameter hints" | ||
475 | }, | ||
476 | "rust-analyzer.updates.channel": { | 260 | "rust-analyzer.updates.channel": { |
477 | "type": "string", | 261 | "type": "string", |
478 | "enum": [ | 262 | "enum": [ |
@@ -520,11 +304,6 @@ | |||
520 | "type": "boolean", | 304 | "type": "boolean", |
521 | "default": false | 305 | "default": false |
522 | }, | 306 | }, |
523 | "rust-analyzer.procMacro.enable": { | ||
524 | "description": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.", | ||
525 | "type": "boolean", | ||
526 | "default": false | ||
527 | }, | ||
528 | "rust-analyzer.debug.engine": { | 307 | "rust-analyzer.debug.engine": { |
529 | "type": "string", | 308 | "type": "string", |
530 | "enum": [ | 309 | "enum": [ |
@@ -557,157 +336,362 @@ | |||
557 | "default": {}, | 336 | "default": {}, |
558 | "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" | 337 | "description": "Optional settings passed to the debug engine. Example:\n{ \"lldb\": { \"terminal\":\"external\"} }" |
559 | }, | 338 | }, |
560 | "rust-analyzer.lens.enable": { | 339 | "rust-analyzer.assist.importMergeBehaviour": { |
561 | "description": "Whether to show CodeLens in Rust files.", | 340 | "markdownDescription": "The strategy to use when inserting new imports or merging imports.", |
562 | "type": "boolean", | 341 | "default": "full", |
563 | "default": true | 342 | "type": "string", |
343 | "enum": [ | ||
344 | "none", | ||
345 | "full", | ||
346 | "last" | ||
347 | ], | ||
348 | "enumDescriptions": [ | ||
349 | "No merging", | ||
350 | "Merge all layers of the import trees", | ||
351 | "Only merge the last layer of the import trees" | ||
352 | ] | ||
564 | }, | 353 | }, |
565 | "rust-analyzer.lens.run": { | 354 | "rust-analyzer.assist.importPrefix": { |
566 | "markdownDescription": "Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | 355 | "markdownDescription": "The path structure for newly inserted paths to use.", |
567 | "type": "boolean", | 356 | "default": "plain", |
568 | "default": true | 357 | "type": "string", |
358 | "enum": [ | ||
359 | "plain", | ||
360 | "by_self", | ||
361 | "by_crate" | ||
362 | ], | ||
363 | "enumDescriptions": [ | ||
364 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | ||
365 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | ||
366 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | ||
367 | ] | ||
569 | }, | 368 | }, |
570 | "rust-analyzer.lens.debug": { | 369 | "rust-analyzer.callInfo.full": { |
571 | "markdownDescription": "Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | 370 | "markdownDescription": "Show function name and docs in parameter hints.", |
572 | "type": "boolean", | 371 | "default": true, |
573 | "default": true | 372 | "type": "boolean" |
574 | }, | 373 | }, |
575 | "rust-analyzer.lens.implementations": { | 374 | "rust-analyzer.cargo.autoreload": { |
576 | "markdownDescription": "Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | 375 | "markdownDescription": "Automatically refresh project info via `cargo metadata` on Cargo.toml changes.", |
577 | "type": "boolean", | 376 | "default": true, |
578 | "default": true | 377 | "type": "boolean" |
579 | }, | 378 | }, |
580 | "rust-analyzer.lens.methodReferences": { | 379 | "rust-analyzer.cargo.allFeatures": { |
581 | "markdownDescription": "Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | 380 | "markdownDescription": "Activate all available features.", |
582 | "type": "boolean", | 381 | "default": false, |
583 | "default": false | 382 | "type": "boolean" |
584 | }, | 383 | }, |
585 | "rust-analyzer.hoverActions.enable": { | 384 | "rust-analyzer.cargo.features": { |
586 | "description": "Whether to show HoverActions in Rust files.", | 385 | "markdownDescription": "List of features to activate.", |
587 | "type": "boolean", | 386 | "default": [], |
588 | "default": true | 387 | "type": "array", |
388 | "items": { | ||
389 | "type": "string" | ||
390 | } | ||
589 | }, | 391 | }, |
590 | "rust-analyzer.hoverActions.implementations": { | 392 | "rust-analyzer.cargo.loadOutDirsFromCheck": { |
591 | "markdownDescription": "Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | 393 | "markdownDescription": "Run `cargo check` on startup to get the correct value for package OUT_DIRs.", |
592 | "type": "boolean", | 394 | "default": false, |
593 | "default": true | 395 | "type": "boolean" |
594 | }, | 396 | }, |
595 | "rust-analyzer.hoverActions.run": { | 397 | "rust-analyzer.cargo.noDefaultFeatures": { |
596 | "markdownDescription": "Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | 398 | "markdownDescription": "Do not activate the `default` feature.", |
597 | "type": "boolean", | 399 | "default": false, |
598 | "default": true | 400 | "type": "boolean" |
599 | }, | 401 | }, |
600 | "rust-analyzer.hoverActions.debug": { | 402 | "rust-analyzer.cargo.target": { |
601 | "markdownDescription": "Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | 403 | "markdownDescription": "Compilation target (target triple).", |
602 | "type": "boolean", | 404 | "default": null, |
603 | "default": true | 405 | "type": [ |
406 | "null", | ||
407 | "string" | ||
408 | ] | ||
604 | }, | 409 | }, |
605 | "rust-analyzer.hoverActions.gotoTypeDef": { | 410 | "rust-analyzer.cargo.noSysroot": { |
606 | "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | 411 | "markdownDescription": "Internal config for debugging, disables loading of sysroot crates.", |
607 | "type": "boolean", | 412 | "default": false, |
608 | "default": true | 413 | "type": "boolean" |
609 | }, | 414 | }, |
610 | "rust-analyzer.linkedProjects": { | 415 | "rust-analyzer.checkOnSave.enable": { |
611 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format", | 416 | "markdownDescription": "Run specified `cargo check` command for diagnostics on save.", |
417 | "default": true, | ||
418 | "type": "boolean" | ||
419 | }, | ||
420 | "rust-analyzer.checkOnSave.allFeatures": { | ||
421 | "markdownDescription": "Check with all features (will be passed as `--all-features`). Defaults to `rust-analyzer.cargo.allFeatures`.", | ||
422 | "default": null, | ||
423 | "type": [ | ||
424 | "null", | ||
425 | "boolean" | ||
426 | ] | ||
427 | }, | ||
428 | "rust-analyzer.checkOnSave.allTargets": { | ||
429 | "markdownDescription": "Check all targets and tests (will be passed as `--all-targets`).", | ||
430 | "default": true, | ||
431 | "type": "boolean" | ||
432 | }, | ||
433 | "rust-analyzer.checkOnSave.command": { | ||
434 | "markdownDescription": "Cargo command to use for `cargo check`.", | ||
435 | "default": "check", | ||
436 | "type": "string" | ||
437 | }, | ||
438 | "rust-analyzer.checkOnSave.noDefaultFeatures": { | ||
439 | "markdownDescription": "Do not activate the `default` feature.", | ||
440 | "default": null, | ||
441 | "type": [ | ||
442 | "null", | ||
443 | "boolean" | ||
444 | ] | ||
445 | }, | ||
446 | "rust-analyzer.checkOnSave.target": { | ||
447 | "markdownDescription": "Check for a specific target. Defaults to `rust-analyzer.cargo.target`.", | ||
448 | "default": null, | ||
449 | "type": [ | ||
450 | "null", | ||
451 | "string" | ||
452 | ] | ||
453 | }, | ||
454 | "rust-analyzer.checkOnSave.extraArgs": { | ||
455 | "markdownDescription": "Extra arguments for `cargo check`.", | ||
456 | "default": [], | ||
612 | "type": "array", | 457 | "type": "array", |
613 | "items": { | 458 | "items": { |
614 | "type": [ | 459 | "type": "string" |
615 | "string", | 460 | } |
616 | "object" | 461 | }, |
617 | ] | 462 | "rust-analyzer.checkOnSave.features": { |
618 | }, | 463 | "markdownDescription": "List of features to activate. Defaults to `rust-analyzer.cargo.features`.", |
619 | "default": null | 464 | "default": null, |
465 | "type": [ | ||
466 | "null", | ||
467 | "array" | ||
468 | ], | ||
469 | "items": { | ||
470 | "type": "string" | ||
471 | } | ||
472 | }, | ||
473 | "rust-analyzer.checkOnSave.overrideCommand": { | ||
474 | "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for checking. The command should include `--message-format=json` or similar option.", | ||
475 | "default": null, | ||
476 | "type": [ | ||
477 | "null", | ||
478 | "array" | ||
479 | ], | ||
480 | "items": { | ||
481 | "type": "string" | ||
482 | } | ||
483 | }, | ||
484 | "rust-analyzer.completion.addCallArgumentSnippets": { | ||
485 | "markdownDescription": "Whether to add argument snippets when completing functions.", | ||
486 | "default": true, | ||
487 | "type": "boolean" | ||
488 | }, | ||
489 | "rust-analyzer.completion.addCallParenthesis": { | ||
490 | "markdownDescription": "Whether to add parenthesis when completing functions.", | ||
491 | "default": true, | ||
492 | "type": "boolean" | ||
493 | }, | ||
494 | "rust-analyzer.completion.postfix.enable": { | ||
495 | "markdownDescription": "Whether to show postfix snippets like `dbg`, `if`, `not`, etc.", | ||
496 | "default": true, | ||
497 | "type": "boolean" | ||
498 | }, | ||
499 | "rust-analyzer.completion.autoimport.enable": { | ||
500 | "markdownDescription": "Toggles the additional completions that automatically add imports when completed. Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.", | ||
501 | "default": true, | ||
502 | "type": "boolean" | ||
620 | }, | 503 | }, |
621 | "rust-analyzer.diagnostics.enable": { | 504 | "rust-analyzer.diagnostics.enable": { |
622 | "type": "boolean", | 505 | "markdownDescription": "Whether to show native rust-analyzer diagnostics.", |
623 | "default": true, | 506 | "default": true, |
624 | "markdownDescription": "Whether to show native rust-analyzer diagnostics." | 507 | "type": "boolean" |
625 | }, | 508 | }, |
626 | "rust-analyzer.diagnostics.enableExperimental": { | 509 | "rust-analyzer.diagnostics.enableExperimental": { |
627 | "type": "boolean", | 510 | "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual.", |
628 | "default": true, | 511 | "default": true, |
629 | "markdownDescription": "Whether to show experimental rust-analyzer diagnostics that might have more false positives than usual." | 512 | "type": "boolean" |
630 | }, | 513 | }, |
631 | "rust-analyzer.diagnostics.disabled": { | 514 | "rust-analyzer.diagnostics.disabled": { |
515 | "markdownDescription": "List of rust-analyzer diagnostics to disable.", | ||
516 | "default": [], | ||
632 | "type": "array", | 517 | "type": "array", |
633 | "uniqueItems": true, | ||
634 | "items": { | 518 | "items": { |
635 | "type": "string" | 519 | "type": "string" |
636 | }, | 520 | }, |
637 | "description": "List of rust-analyzer diagnostics to disable", | 521 | "uniqueItems": true |
638 | "default": [] | ||
639 | }, | 522 | }, |
640 | "rust-analyzer.diagnostics.warningsAsInfo": { | 523 | "rust-analyzer.diagnostics.warningsAsHint": { |
524 | "markdownDescription": "List of warnings that should be displayed with info severity.\\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | ||
525 | "default": [], | ||
641 | "type": "array", | 526 | "type": "array", |
642 | "uniqueItems": true, | ||
643 | "items": { | 527 | "items": { |
644 | "type": "string" | 528 | "type": "string" |
645 | }, | 529 | } |
646 | "description": "List of warnings that should be displayed with info severity.\nThe warnings will be indicated by a blue squiggly underline in code and a blue icon in the problems panel.", | ||
647 | "default": [] | ||
648 | }, | 530 | }, |
649 | "rust-analyzer.diagnostics.warningsAsHint": { | 531 | "rust-analyzer.diagnostics.warningsAsInfo": { |
532 | "markdownDescription": "List of warnings that should be displayed with hint severity.\\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | ||
533 | "default": [], | ||
650 | "type": "array", | 534 | "type": "array", |
651 | "uniqueItems": true, | ||
652 | "items": { | 535 | "items": { |
653 | "type": "string" | 536 | "type": "string" |
654 | }, | 537 | } |
655 | "description": "List of warnings that should be displayed with hint severity.\nThe warnings will be indicated by faded text or three dots in code and will not show up in the problems panel.", | ||
656 | "default": [] | ||
657 | }, | 538 | }, |
658 | "rust-analyzer.assist.importMergeBehaviour": { | 539 | "rust-analyzer.files.watcher": { |
659 | "type": "string", | 540 | "markdownDescription": "Controls file watching implementation.", |
660 | "enum": [ | 541 | "default": "client", |
661 | "none", | 542 | "type": "string" |
662 | "full", | ||
663 | "last" | ||
664 | ], | ||
665 | "enumDescriptions": [ | ||
666 | "No merging", | ||
667 | "Merge all layers of the import trees", | ||
668 | "Only merge the last layer of the import trees" | ||
669 | ], | ||
670 | "default": "full", | ||
671 | "description": "The strategy to use when inserting new imports or merging imports." | ||
672 | }, | 543 | }, |
673 | "rust-analyzer.assist.importPrefix": { | 544 | "rust-analyzer.hoverActions.debug": { |
674 | "type": "string", | 545 | "markdownDescription": "Whether to show `Debug` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", |
675 | "enum": [ | 546 | "default": true, |
676 | "plain", | 547 | "type": "boolean" |
677 | "by_self", | 548 | }, |
678 | "by_crate" | 549 | "rust-analyzer.hoverActions.enable": { |
550 | "markdownDescription": "Whether to show HoverActions in Rust files.", | ||
551 | "default": true, | ||
552 | "type": "boolean" | ||
553 | }, | ||
554 | "rust-analyzer.hoverActions.gotoTypeDef": { | ||
555 | "markdownDescription": "Whether to show `Go to Type Definition` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | ||
556 | "default": true, | ||
557 | "type": "boolean" | ||
558 | }, | ||
559 | "rust-analyzer.hoverActions.implementations": { | ||
560 | "markdownDescription": "Whether to show `Implementations` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | ||
561 | "default": true, | ||
562 | "type": "boolean" | ||
563 | }, | ||
564 | "rust-analyzer.hoverActions.run": { | ||
565 | "markdownDescription": "Whether to show `Run` action. Only applies when `#rust-analyzer.hoverActions.enable#` is set.", | ||
566 | "default": true, | ||
567 | "type": "boolean" | ||
568 | }, | ||
569 | "rust-analyzer.hoverActions.linksInHover": { | ||
570 | "markdownDescription": "Use markdown syntax for links in hover.", | ||
571 | "default": true, | ||
572 | "type": "boolean" | ||
573 | }, | ||
574 | "rust-analyzer.inlayHints.chainingHints": { | ||
575 | "markdownDescription": "Whether to show inlay type hints for method chains.", | ||
576 | "default": true, | ||
577 | "type": "boolean" | ||
578 | }, | ||
579 | "rust-analyzer.inlayHints.maxLength": { | ||
580 | "markdownDescription": "Maximum length for inlay hints.", | ||
581 | "default": null, | ||
582 | "type": [ | ||
583 | "null", | ||
584 | "integer" | ||
679 | ], | 585 | ], |
680 | "enumDescriptions": [ | 586 | "minimum": 0 |
681 | "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", | 587 | }, |
682 | "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", | 588 | "rust-analyzer.inlayHints.parameterHints": { |
683 | "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." | 589 | "markdownDescription": "Whether to show function parameter name inlay hints at the call site.", |
590 | "default": true, | ||
591 | "type": "boolean" | ||
592 | }, | ||
593 | "rust-analyzer.inlayHints.typeHints": { | ||
594 | "markdownDescription": "Whether to show inlay type hints for variables.", | ||
595 | "default": true, | ||
596 | "type": "boolean" | ||
597 | }, | ||
598 | "rust-analyzer.lens.debug": { | ||
599 | "markdownDescription": "Whether to show `Debug` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | ||
600 | "default": true, | ||
601 | "type": "boolean" | ||
602 | }, | ||
603 | "rust-analyzer.lens.enable": { | ||
604 | "markdownDescription": "Whether to show CodeLens in Rust files.", | ||
605 | "default": true, | ||
606 | "type": "boolean" | ||
607 | }, | ||
608 | "rust-analyzer.lens.implementations": { | ||
609 | "markdownDescription": "Whether to show `Implementations` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | ||
610 | "default": true, | ||
611 | "type": "boolean" | ||
612 | }, | ||
613 | "rust-analyzer.lens.run": { | ||
614 | "markdownDescription": "Whether to show `Run` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | ||
615 | "default": true, | ||
616 | "type": "boolean" | ||
617 | }, | ||
618 | "rust-analyzer.lens.methodReferences": { | ||
619 | "markdownDescription": "Whether to show `Method References` lens. Only applies when `#rust-analyzer.lens.enable#` is set.", | ||
620 | "default": false, | ||
621 | "type": "boolean" | ||
622 | }, | ||
623 | "rust-analyzer.linkedProjects": { | ||
624 | "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set of projects. \\nElements must be paths pointing to Cargo.toml, rust-project.json, or JSON objects in rust-project.json format.", | ||
625 | "default": [], | ||
626 | "type": "array", | ||
627 | "items": { | ||
628 | "type": [ | ||
629 | "string", | ||
630 | "object" | ||
631 | ] | ||
632 | } | ||
633 | }, | ||
634 | "rust-analyzer.lruCapacity": { | ||
635 | "markdownDescription": "Number of syntax trees rust-analyzer keeps in memory.", | ||
636 | "default": null, | ||
637 | "type": [ | ||
638 | "null", | ||
639 | "integer" | ||
684 | ], | 640 | ], |
685 | "default": "plain", | 641 | "minimum": 0 |
686 | "description": "The path structure for newly inserted paths to use." | 642 | }, |
643 | "rust-analyzer.notifications.cargoTomlNotFound": { | ||
644 | "markdownDescription": "Whether to show `can't find Cargo.toml` error message.", | ||
645 | "default": true, | ||
646 | "type": "boolean" | ||
647 | }, | ||
648 | "rust-analyzer.procMacro.enable": { | ||
649 | "markdownDescription": "Enable Proc macro support, cargo.loadOutDirsFromCheck must be enabled.", | ||
650 | "default": false, | ||
651 | "type": "boolean" | ||
687 | }, | 652 | }, |
688 | "rust-analyzer.runnables.overrideCargo": { | 653 | "rust-analyzer.runnables.overrideCargo": { |
654 | "markdownDescription": "Command to be executed instead of 'cargo' for runnables.", | ||
655 | "default": null, | ||
689 | "type": [ | 656 | "type": [ |
690 | "null", | 657 | "null", |
691 | "string" | 658 | "string" |
692 | ], | 659 | ] |
693 | "default": null, | ||
694 | "description": "Command to be executed instead of 'cargo' for runnables." | ||
695 | }, | 660 | }, |
696 | "rust-analyzer.runnables.cargoExtraArgs": { | 661 | "rust-analyzer.runnables.cargoExtraArgs": { |
662 | "markdownDescription": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\\nFor example, it may be '--release'.", | ||
663 | "default": [], | ||
697 | "type": "array", | 664 | "type": "array", |
698 | "items": { | 665 | "items": { |
699 | "type": "string" | 666 | "type": "string" |
700 | }, | 667 | } |
701 | "default": [], | ||
702 | "description": "Additional arguments to be passed to cargo for runnables such as tests or binaries.\nFor example, it may be '--release'" | ||
703 | }, | 668 | }, |
704 | "rust-analyzer.rustcSource": { | 669 | "rust-analyzer.rustcSource": { |
670 | "markdownDescription": "Path to the rust compiler sources, for usage in rustc_private projects.", | ||
671 | "default": null, | ||
705 | "type": [ | 672 | "type": [ |
706 | "null", | 673 | "null", |
707 | "string" | 674 | "string" |
708 | ], | 675 | ] |
676 | }, | ||
677 | "rust-analyzer.rustfmt.extraArgs": { | ||
678 | "markdownDescription": "Additional arguments to rustfmt.", | ||
679 | "default": [], | ||
680 | "type": "array", | ||
681 | "items": { | ||
682 | "type": "string" | ||
683 | } | ||
684 | }, | ||
685 | "rust-analyzer.rustfmt.overrideCommand": { | ||
686 | "markdownDescription": "Advanced option, fully override the command rust-analyzer uses for formatting.", | ||
709 | "default": null, | 687 | "default": null, |
710 | "description": "Path to the rust compiler sources, for usage in rustc_private projects." | 688 | "type": [ |
689 | "null", | ||
690 | "array" | ||
691 | ], | ||
692 | "items": { | ||
693 | "type": "string" | ||
694 | } | ||
711 | } | 695 | } |
712 | } | 696 | } |
713 | }, | 697 | }, |