aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/tests.rs1
-rw-r--r--crates/ide_completion/src/test_utils.rs1
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs85
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs115
-rw-r--r--crates/ide_db/src/helpers/merge_imports.rs4
-rw-r--r--crates/rust-analyzer/src/config.rs25
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs1
-rw-r--r--docs/user/generated_config.adoc9
-rw-r--r--editors/code/package.json9
10 files changed, 219 insertions, 33 deletions
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index bb1ca0b3d..1739302bf 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -26,6 +26,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
26 insert_use: InsertUseConfig { 26 insert_use: InsertUseConfig {
27 granularity: ImportGranularity::Crate, 27 granularity: ImportGranularity::Crate,
28 prefix_kind: hir::PrefixKind::Plain, 28 prefix_kind: hir::PrefixKind::Plain,
29 enforce_granularity: true,
29 group: true, 30 group: true,
30 }, 31 },
31}; 32};
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index b150a5c3f..37be575e5 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -25,6 +25,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
25 insert_use: InsertUseConfig { 25 insert_use: InsertUseConfig {
26 granularity: ImportGranularity::Crate, 26 granularity: ImportGranularity::Crate,
27 prefix_kind: PrefixKind::Plain, 27 prefix_kind: PrefixKind::Plain,
28 enforce_granularity: true,
28 group: true, 29 group: true,
29 }, 30 },
30}; 31};
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 1fdd110cc..e7ae69302 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -4,12 +4,14 @@ use std::cmp::Ordering;
4use hir::Semantics; 4use hir::Semantics;
5use syntax::{ 5use syntax::{
6 algo, 6 algo,
7 ast::{self, make, AstNode, ModuleItemOwner, PathSegmentKind}, 7 ast::{self, make, AstNode, ModuleItemOwner, PathSegmentKind, VisibilityOwner},
8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, 8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 helpers::merge_imports::{try_merge_imports, use_tree_path_cmp, MergeBehavior}, 12 helpers::merge_imports::{
13 common_prefix, eq_visibility, try_merge_imports, use_tree_path_cmp, MergeBehavior,
14 },
13 RootDatabase, 15 RootDatabase,
14}; 16};
15 17
@@ -18,8 +20,6 @@ pub use hir::PrefixKind;
18/// How imports should be grouped into use statements. 20/// How imports should be grouped into use statements.
19#[derive(Copy, Clone, Debug, PartialEq, Eq)] 21#[derive(Copy, Clone, Debug, PartialEq, Eq)]
20pub enum ImportGranularity { 22pub enum ImportGranularity {
21 /// Try to guess the granularity of imports on a per module basis by observing the existing imports.
22 Guess,
23 /// Do not change the granularity of any imports and preserve the original structure written by the developer. 23 /// Do not change the granularity of any imports and preserve the original structure written by the developer.
24 Preserve, 24 Preserve,
25 /// Merge imports from the same crate into a single use statement. 25 /// Merge imports from the same crate into a single use statement.
@@ -33,6 +33,7 @@ pub enum ImportGranularity {
33#[derive(Clone, Copy, Debug, PartialEq, Eq)] 33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
34pub struct InsertUseConfig { 34pub struct InsertUseConfig {
35 pub granularity: ImportGranularity, 35 pub granularity: ImportGranularity,
36 pub enforce_granularity: bool,
36 pub prefix_kind: PrefixKind, 37 pub prefix_kind: PrefixKind,
37 pub group: bool, 38 pub group: bool,
38} 39}
@@ -81,40 +82,88 @@ impl ImportScope {
81 } 82 }
82 } 83 }
83 84
84 fn guess_merge_behavior_from_scope(&self) -> Option<MergeBehavior> { 85 fn guess_granularity_from_scope(&self) -> ImportGranularityGuess {
86 // The idea is simple, just check each import as well as the import and its precedent together for
87 // whether they fulfill a granularity criteria.
85 let use_stmt = |item| match item { 88 let use_stmt = |item| match item {
86 ast::Item::Use(use_) => use_.use_tree(), 89 ast::Item::Use(use_) => {
90 let use_tree = use_.use_tree()?;
91 Some((use_tree, use_.visibility()))
92 }
87 _ => None, 93 _ => None,
88 }; 94 };
89 let use_stmts = match self { 95 let mut use_stmts = match self {
90 ImportScope::File(f) => f.items(), 96 ImportScope::File(f) => f.items(),
91 ImportScope::Module(m) => m.items(), 97 ImportScope::Module(m) => m.items(),
92 } 98 }
93 .filter_map(use_stmt); 99 .filter_map(use_stmt);
94 let mut res = None; 100 let mut res = ImportGranularityGuess::Unknown;
95 for tree in use_stmts { 101 let (mut prev, mut prev_vis) = match use_stmts.next() {
96 if let Some(list) = tree.use_tree_list() { 102 Some(it) => it,
97 if list.use_trees().any(|tree| tree.use_tree_list().is_some()) { 103 None => return res,
98 // double nested tree list, can only be a crate style import at this point 104 };
99 return Some(MergeBehavior::Crate); 105 loop {
106 if let Some(use_tree_list) = prev.use_tree_list() {
107 if use_tree_list.use_trees().any(|tree| tree.use_tree_list().is_some()) {
108 // Nested tree lists can only occur in crate style, or with no proper style being enforced in the file.
109 break ImportGranularityGuess::Crate;
110 } else {
111 // Could still be crate-style so continue looking.
112 res = ImportGranularityGuess::CrateOrModule;
100 } 113 }
101 // has to be at least a module style based import, might be crate style tho so look further
102 res = Some(MergeBehavior::Module);
103 } 114 }
115
116 let (curr, curr_vis) = match use_stmts.next() {
117 Some(it) => it,
118 None => break res,
119 };
120 if eq_visibility(prev_vis, curr_vis.clone()) {
121 if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) {
122 if let Some(_) = common_prefix(&prev_path, &curr_path) {
123 if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() {
124 // Same prefix but no use tree lists so this has to be of item style.
125 break ImportGranularityGuess::Item; // this overwrites CrateOrModule, technically the file doesn't adhere to anything here.
126 } else {
127 // Same prefix with item tree lists, has to be module style as it
128 // can't be crate style since the trees wouldn't share a prefix then.
129 break ImportGranularityGuess::Module;
130 }
131 }
132 }
133 }
134 prev = curr;
135 prev_vis = curr_vis;
104 } 136 }
105 res
106 } 137 }
107} 138}
108 139
140#[derive(PartialEq, PartialOrd, Debug, Clone, Copy)]
141enum ImportGranularityGuess {
142 Unknown,
143 Item,
144 Module,
145 Crate,
146 CrateOrModule,
147}
148
109/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 149/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
110pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { 150pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
111 let _p = profile::span("insert_use"); 151 let _p = profile::span("insert_use");
112 let mb = match cfg.granularity { 152 let mut mb = match cfg.granularity {
113 ImportGranularity::Guess => scope.guess_merge_behavior_from_scope(),
114 ImportGranularity::Crate => Some(MergeBehavior::Crate), 153 ImportGranularity::Crate => Some(MergeBehavior::Crate),
115 ImportGranularity::Module => Some(MergeBehavior::Module), 154 ImportGranularity::Module => Some(MergeBehavior::Module),
116 ImportGranularity::Item | ImportGranularity::Preserve => None, 155 ImportGranularity::Item | ImportGranularity::Preserve => None,
117 }; 156 };
157 if !cfg.enforce_granularity {
158 let file_granularity = scope.guess_granularity_from_scope();
159 mb = match file_granularity {
160 ImportGranularityGuess::Unknown => mb,
161 ImportGranularityGuess::Item => None,
162 ImportGranularityGuess::Module => Some(MergeBehavior::Module),
163 ImportGranularityGuess::Crate => Some(MergeBehavior::Crate),
164 ImportGranularityGuess::CrateOrModule => mb.or(Some(MergeBehavior::Crate)),
165 };
166 }
118 167
119 let use_item = 168 let use_item =
120 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); 169 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index f99857a89..f795bbf00 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -631,6 +631,104 @@ fn merge_last_fail3() {
631 ); 631 );
632} 632}
633 633
634#[test]
635fn guess_empty() {
636 check_guess("", ImportGranularityGuess::Unknown);
637}
638
639#[test]
640fn guess_single() {
641 check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate);
642 check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown);
643 check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule);
644}
645
646#[test]
647fn guess_unknown() {
648 check_guess(
649 r"
650use foo::bar::baz;
651use oof::rab::xuq;
652",
653 ImportGranularityGuess::Unknown,
654 );
655}
656
657#[test]
658fn guess_item() {
659 check_guess(
660 r"
661use foo::bar::baz;
662use foo::bar::qux;
663",
664 ImportGranularityGuess::Item,
665 );
666}
667
668#[test]
669fn guess_module() {
670 check_guess(
671 r"
672use foo::bar::baz;
673use foo::bar::{qux, quux};
674",
675 ImportGranularityGuess::Module,
676 );
677 // this is a rather odd case, technically this file isn't following any style properly.
678 check_guess(
679 r"
680use foo::bar::baz;
681use foo::{baz::{qux, quux}, bar};
682",
683 ImportGranularityGuess::Module,
684 );
685}
686
687#[test]
688fn guess_crate_or_module() {
689 check_guess(
690 r"
691use foo::bar::baz;
692use oof::bar::{qux, quux};
693",
694 ImportGranularityGuess::CrateOrModule,
695 );
696}
697
698#[test]
699fn guess_crate() {
700 check_guess(
701 r"
702use frob::bar::baz;
703use foo::{baz::{qux, quux}, bar};
704",
705 ImportGranularityGuess::Crate,
706 );
707}
708
709#[test]
710fn guess_skips_differing_vis() {
711 check_guess(
712 r"
713use foo::bar::baz;
714pub use foo::bar::qux;
715",
716 ImportGranularityGuess::Unknown,
717 );
718}
719
720#[test]
721fn guess_grouping_matters() {
722 check_guess(
723 r"
724use foo::bar::baz;
725use oof::bar::baz;
726use foo::bar::qux;
727",
728 ImportGranularityGuess::Unknown,
729 );
730}
731
634fn check( 732fn check(
635 path: &str, 733 path: &str,
636 ra_fixture_before: &str, 734 ra_fixture_before: &str,
@@ -651,7 +749,16 @@ fn check(
651 .find_map(ast::Path::cast) 749 .find_map(ast::Path::cast)
652 .unwrap(); 750 .unwrap();
653 751
654 insert_use(&file, path, InsertUseConfig { granularity, prefix_kind: PrefixKind::Plain, group }); 752 insert_use(
753 &file,
754 path,
755 InsertUseConfig {
756 granularity,
757 enforce_granularity: true,
758 prefix_kind: PrefixKind::Plain,
759 group,
760 },
761 );
655 let result = file.as_syntax_node().to_string(); 762 let result = file.as_syntax_node().to_string();
656 assert_eq_text!(ra_fixture_after, &result); 763 assert_eq_text!(ra_fixture_after, &result);
657} 764}
@@ -686,3 +793,9 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior
686 let result = try_merge_imports(&use0, &use1, mb); 793 let result = try_merge_imports(&use0, &use1, mb);
687 assert_eq!(result.map(|u| u.to_string()), None); 794 assert_eq!(result.map(|u| u.to_string()), None);
688} 795}
796
797fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) {
798 let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone();
799 let file = super::ImportScope::from(syntax).unwrap();
800 assert_eq!(file.guess_granularity_from_scope(), expected);
801}
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index 8fb40e837..546f2d0c4 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -181,7 +181,7 @@ fn recursive_merge(
181} 181}
182 182
183/// Traverses both paths until they differ, returning the common prefix of both. 183/// Traverses both paths until they differ, returning the common prefix of both.
184fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { 184pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
185 let mut res = None; 185 let mut res = None;
186 let mut lhs_curr = lhs.first_qualifier_or_self(); 186 let mut lhs_curr = lhs.first_qualifier_or_self();
187 let mut rhs_curr = rhs.first_qualifier_or_self(); 187 let mut rhs_curr = rhs.first_qualifier_or_self();
@@ -289,7 +289,7 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
289 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text)) 289 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text))
290} 290}
291 291
292fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool { 292pub fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
293 match (vis0, vis1) { 293 match (vis0, vis1) {
294 (None, None) => true, 294 (None, None) => true,
295 // FIXME: Don't use the string representation to check for equality 295 // FIXME: Don't use the string representation to check for equality
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index a34ca97ac..867d72ea4 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -33,16 +33,18 @@ use crate::{
33// be specified directly in `package.json`. 33// be specified directly in `package.json`.
34config_data! { 34config_data! {
35 struct ConfigData { 35 struct ConfigData {
36 /// The strategy to use when inserting new imports or merging imports. 36 /// How imports should be grouped into use statements.
37 assist_importGranularity | 37 assist_importGranularity |
38 assist_importMergeBehavior | 38 assist_importMergeBehavior |
39 assist_importMergeBehaviour: ImportGranularityDef = "\"guess\"", 39 assist_importMergeBehaviour: ImportGranularityDef = "\"crate\"",
40 /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
41 assist_importEnforceGranularity: bool = "false",
40 /// The path structure for newly inserted paths to use. 42 /// The path structure for newly inserted paths to use.
41 assist_importPrefix: ImportPrefixDef = "\"plain\"", 43 assist_importPrefix: ImportPrefixDef = "\"plain\"",
42 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 44 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
43 assist_importGroup: bool = "true", 45 assist_importGroup: bool = "true",
44 /// Show function name and docs in parameter hints. 46 /// Show function name and docs in parameter hints.
45 callInfo_full: bool = "true", 47 callInfo_full: bool = "true",
46 48
47 /// Automatically refresh project info via `cargo metadata` on 49 /// Automatically refresh project info via `cargo metadata` on
48 /// `Cargo.toml` changes. 50 /// `Cargo.toml` changes.
@@ -610,12 +612,12 @@ impl Config {
610 fn insert_use_config(&self) -> InsertUseConfig { 612 fn insert_use_config(&self) -> InsertUseConfig {
611 InsertUseConfig { 613 InsertUseConfig {
612 granularity: match self.data.assist_importGranularity { 614 granularity: match self.data.assist_importGranularity {
613 ImportGranularityDef::Guess => ImportGranularity::Guess,
614 ImportGranularityDef::Preserve => ImportGranularity::Preserve, 615 ImportGranularityDef::Preserve => ImportGranularity::Preserve,
615 ImportGranularityDef::Item => ImportGranularity::Item, 616 ImportGranularityDef::Item => ImportGranularity::Item,
616 ImportGranularityDef::Crate => ImportGranularity::Crate, 617 ImportGranularityDef::Crate => ImportGranularity::Crate,
617 ImportGranularityDef::Module => ImportGranularity::Module, 618 ImportGranularityDef::Module => ImportGranularity::Module,
618 }, 619 },
620 enforce_granularity: self.data.assist_importEnforceGranularity,
619 prefix_kind: match self.data.assist_importPrefix { 621 prefix_kind: match self.data.assist_importPrefix {
620 ImportPrefixDef::Plain => PrefixKind::Plain, 622 ImportPrefixDef::Plain => PrefixKind::Plain,
621 ImportPrefixDef::ByCrate => PrefixKind::ByCrate, 623 ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
@@ -721,7 +723,6 @@ enum ManifestOrProjectJson {
721#[serde(rename_all = "snake_case")] 723#[serde(rename_all = "snake_case")]
722enum ImportGranularityDef { 724enum ImportGranularityDef {
723 Preserve, 725 Preserve,
724 Guess,
725 #[serde(alias = "none")] 726 #[serde(alias = "none")]
726 Item, 727 Item,
727 #[serde(alias = "full")] 728 #[serde(alias = "full")]
@@ -891,6 +892,16 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
891 "Merge imports from the same module into a single `use` statement." 892 "Merge imports from the same module into a single `use` statement."
892 ], 893 ],
893 }, 894 },
895 "ImportGranularityDef" => set! {
896 "type": "string",
897 "enum": ["preserve", "crate", "module", "item"],
898 "enumDescriptions": [
899 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
900 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
901 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
902 "Flatten imports so that each has its own use statement."
903 ],
904 },
894 "ImportPrefixDef" => set! { 905 "ImportPrefixDef" => set! {
895 "type": "string", 906 "type": "string",
896 "enum": [ 907 "enum": [
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index cd0b8d559..781073fe5 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -138,6 +138,7 @@ fn integrated_completion_benchmark() {
138 insert_use: InsertUseConfig { 138 insert_use: InsertUseConfig {
139 granularity: ImportGranularity::Crate, 139 granularity: ImportGranularity::Crate,
140 prefix_kind: hir::PrefixKind::ByCrate, 140 prefix_kind: hir::PrefixKind::ByCrate,
141 enforce_granularity: true,
141 group: true, 142 group: true,
142 }, 143 },
143 }; 144 };
@@ -171,6 +172,7 @@ fn integrated_completion_benchmark() {
171 insert_use: InsertUseConfig { 172 insert_use: InsertUseConfig {
172 granularity: ImportGranularity::Crate, 173 granularity: ImportGranularity::Crate,
173 prefix_kind: hir::PrefixKind::ByCrate, 174 prefix_kind: hir::PrefixKind::ByCrate,
175 enforce_granularity: true,
174 group: true, 176 group: true,
175 }, 177 },
176 }; 178 };
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 64d5f9e2e..ef9e0aee9 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1179,6 +1179,7 @@ mod tests {
1179 insert_use: InsertUseConfig { 1179 insert_use: InsertUseConfig {
1180 granularity: ImportGranularity::Item, 1180 granularity: ImportGranularity::Item,
1181 prefix_kind: PrefixKind::Plain, 1181 prefix_kind: PrefixKind::Plain,
1182 enforce_granularity: true,
1182 group: true, 1183 group: true,
1183 }, 1184 },
1184 }, 1185 },
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index feba43ff1..b2c1f6261 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -1,7 +1,12 @@
1[[rust-analyzer.assist.importMergeBehavior]]rust-analyzer.assist.importMergeBehavior (default: `"crate"`):: 1[[rust-analyzer.assist.importGranularity]]rust-analyzer.assist.importGranularity (default: `"crate"`)::
2+ 2+
3-- 3--
4The strategy to use when inserting new imports or merging imports. 4How imports should be grouped into use statements.
5--
6[[rust-analyzer.assist.importEnforceGranularity]]rust-analyzer.assist.importEnforceGranularity (default: `false`)::
7+
8--
9Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
5-- 10--
6[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`):: 11[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`)::
7+ 12+
diff --git a/editors/code/package.json b/editors/code/package.json
index 06ce86987..48d12b35a 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -387,23 +387,26 @@
387 "$generated-start": false, 387 "$generated-start": false,
388 "rust-analyzer.assist.importGranularity": { 388 "rust-analyzer.assist.importGranularity": {
389 "markdownDescription": "How imports should be grouped into use statements.", 389 "markdownDescription": "How imports should be grouped into use statements.",
390 "default": "guess", 390 "default": "crate",
391 "type": "string", 391 "type": "string",
392 "enum": [ 392 "enum": [
393 "guess",
394 "preserve", 393 "preserve",
395 "crate", 394 "crate",
396 "module", 395 "module",
397 "item" 396 "item"
398 ], 397 ],
399 "enumDescriptions": [ 398 "enumDescriptions": [
400 "Try to guess the granularity of imports on a per module basis by observing the existing imports.",
401 "Do not change the granularity of any imports and preserve the original structure written by the developer.", 399 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
402 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", 400 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
403 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", 401 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
404 "Flatten imports so that each has its own use statement." 402 "Flatten imports so that each has its own use statement."
405 ] 403 ]
406 }, 404 },
405 "rust-analyzer.assist.importEnforceGranularity": {
406 "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
407 "default": false,
408 "type": "boolean"
409 },
407 "rust-analyzer.assist.importPrefix": { 410 "rust-analyzer.assist.importPrefix": {
408 "markdownDescription": "The path structure for newly inserted paths to use.", 411 "markdownDescription": "The path structure for newly inserted paths to use.",
409 "default": "plain", 412 "default": "plain",