diff options
-rw-r--r-- | crates/ide_assists/src/tests.rs | 1 | ||||
-rw-r--r-- | crates/ide_completion/src/test_utils.rs | 1 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use.rs | 85 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use/tests.rs | 115 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/merge_imports.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 25 | ||||
-rw-r--r-- | crates/rust-analyzer/src/integrated_benchmarks.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 1 | ||||
-rw-r--r-- | docs/user/generated_config.adoc | 9 | ||||
-rw-r--r-- | editors/code/package.json | 9 |
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; | |||
4 | use hir::Semantics; | 4 | use hir::Semantics; |
5 | use syntax::{ | 5 | use 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 | ||
11 | use crate::{ | 11 | use 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)] |
20 | pub enum ImportGranularity { | 22 | pub 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)] |
34 | pub struct InsertUseConfig { | 34 | pub 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)] | ||
141 | enum 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. |
110 | pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { | 150 | pub 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] | ||
635 | fn guess_empty() { | ||
636 | check_guess("", ImportGranularityGuess::Unknown); | ||
637 | } | ||
638 | |||
639 | #[test] | ||
640 | fn 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] | ||
647 | fn guess_unknown() { | ||
648 | check_guess( | ||
649 | r" | ||
650 | use foo::bar::baz; | ||
651 | use oof::rab::xuq; | ||
652 | ", | ||
653 | ImportGranularityGuess::Unknown, | ||
654 | ); | ||
655 | } | ||
656 | |||
657 | #[test] | ||
658 | fn guess_item() { | ||
659 | check_guess( | ||
660 | r" | ||
661 | use foo::bar::baz; | ||
662 | use foo::bar::qux; | ||
663 | ", | ||
664 | ImportGranularityGuess::Item, | ||
665 | ); | ||
666 | } | ||
667 | |||
668 | #[test] | ||
669 | fn guess_module() { | ||
670 | check_guess( | ||
671 | r" | ||
672 | use foo::bar::baz; | ||
673 | use 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" | ||
680 | use foo::bar::baz; | ||
681 | use foo::{baz::{qux, quux}, bar}; | ||
682 | ", | ||
683 | ImportGranularityGuess::Module, | ||
684 | ); | ||
685 | } | ||
686 | |||
687 | #[test] | ||
688 | fn guess_crate_or_module() { | ||
689 | check_guess( | ||
690 | r" | ||
691 | use foo::bar::baz; | ||
692 | use oof::bar::{qux, quux}; | ||
693 | ", | ||
694 | ImportGranularityGuess::CrateOrModule, | ||
695 | ); | ||
696 | } | ||
697 | |||
698 | #[test] | ||
699 | fn guess_crate() { | ||
700 | check_guess( | ||
701 | r" | ||
702 | use frob::bar::baz; | ||
703 | use foo::{baz::{qux, quux}, bar}; | ||
704 | ", | ||
705 | ImportGranularityGuess::Crate, | ||
706 | ); | ||
707 | } | ||
708 | |||
709 | #[test] | ||
710 | fn guess_skips_differing_vis() { | ||
711 | check_guess( | ||
712 | r" | ||
713 | use foo::bar::baz; | ||
714 | pub use foo::bar::qux; | ||
715 | ", | ||
716 | ImportGranularityGuess::Unknown, | ||
717 | ); | ||
718 | } | ||
719 | |||
720 | #[test] | ||
721 | fn guess_grouping_matters() { | ||
722 | check_guess( | ||
723 | r" | ||
724 | use foo::bar::baz; | ||
725 | use oof::bar::baz; | ||
726 | use foo::bar::qux; | ||
727 | ", | ||
728 | ImportGranularityGuess::Unknown, | ||
729 | ); | ||
730 | } | ||
731 | |||
634 | fn check( | 732 | fn 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 | |||
797 | fn 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. |
184 | fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { | 184 | pub 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 | ||
292 | fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool { | 292 | pub 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`. |
34 | config_data! { | 34 | config_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")] |
722 | enum ImportGranularityDef { | 724 | enum 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 | -- |
4 | The strategy to use when inserting new imports or merging imports. | 4 | How imports should be grouped into use statements. |
5 | -- | ||
6 | [[rust-analyzer.assist.importEnforceGranularity]]rust-analyzer.assist.importEnforceGranularity (default: `false`):: | ||
7 | + | ||
8 | -- | ||
9 | 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. | ||
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", |