From f140778b3ddec4ebd6f5d8df43600419b68d611f Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Tue, 15 Dec 2020 17:19:54 -0800 Subject: [PATCH 1/4] Add an `unnest_imports` option to break apart nested import groups. --- Configurations.md | 26 +++++++++++++++++++++++ src/config.rs | 2 ++ src/formatting/imports.rs | 38 ++++++++++++++++++++++++++++++++++ src/formatting/reorder.rs | 5 ++++- tests/source/unnest_imports.rs | 6 ++++++ tests/target/unnest_imports.rs | 12 +++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 tests/source/unnest_imports.rs create mode 100644 tests/target/unnest_imports.rs diff --git a/Configurations.md b/Configurations.md index 7130e80bfdc..4a8a6d048cd 100644 --- a/Configurations.md +++ b/Configurations.md @@ -2548,6 +2548,32 @@ fn lorem() { } ``` +## `unnest_imports` + +Break apart nested import groups into separate `use` statements. +When used with `merge_imports`, imports will be merged together by module but +not merge into a single tree. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No + +#### `false` (default): + +```rust +use foo::{a::b, c}; +use foo::{d::{e, f}, g::{h, i}}; +``` + +#### `true`: + +```rust +use foo::a::b; +use foo::c; +use foo::d::{e, f}; +use foo::g::{h, i}; +``` + ## `unstable_features` Enable unstable features on stable and beta channels (unstable features are available by default on nightly). diff --git a/src/config.rs b/src/config.rs index 6a0c46f6275..f9a6b497959 100644 --- a/src/config.rs +++ b/src/config.rs @@ -78,6 +78,7 @@ create_config! { imports_indent: IndentStyle, IndentStyle::Block, false, "Indent of imports"; imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block"; merge_imports: bool, false, false, "Merge imports"; + unnest_imports: bool, false, false, "Break apart nested import groups"; group_imports: GroupImportsTactic, GroupImportsTactic::Preserve, false, "Controls the strategy for how imports are grouped together"; @@ -596,6 +597,7 @@ where_single_line = false imports_indent = "Block" imports_layout = "Mixed" merge_imports = false +unnest_imports = false group_imports = "Preserve" reorder_imports = true reorder_modules = true diff --git a/src/formatting/imports.rs b/src/formatting/imports.rs index 72aff70987a..4cd2b462756 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -179,6 +179,44 @@ pub(crate) fn merge_use_trees(use_trees: Vec) -> Vec { result } +pub(crate) fn unnest_use_trees(mut use_trees: Vec) -> Vec { + let mut result = Vec::with_capacity(use_trees.len()); + while let Some(mut use_tree) = use_trees.pop() { + if !use_tree.has_comment() && use_tree.attrs.is_none() { + if let Some((UseSegment::List(list), ref prefix)) = use_tree.path.split_last_mut() { + let span = use_tree.span; + let visibility = &use_tree.visibility; + list.retain(|nested_use_tree| { + if matches!( + nested_use_tree.path[..], + [UseSegment::Ident(..)] | [UseSegment::Slf(..)] | [UseSegment::Glob] + ) { + return true; + } + // nested item detected; flatten once, but process it again + // in case it has more nesting + use_trees.push(UseTree { + path: prefix + .iter() + .cloned() + .chain(nested_use_tree.path.iter().cloned()) + .collect(), + span, + list_item: None, + visibility: visibility.clone(), + attrs: None, + }); + // remove this item + false + }); + use_tree = use_tree.normalize(); + } + } + result.push(use_tree); + } + result +} + impl fmt::Debug for UseTree { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) diff --git a/src/formatting/reorder.rs b/src/formatting/reorder.rs index 379aa109b14..0ba37d29991 100644 --- a/src/formatting/reorder.rs +++ b/src/formatting/reorder.rs @@ -15,7 +15,7 @@ use crate::config::{Config, GroupImportsTactic}; use crate::formatting::imports::UseSegment; use crate::formatting::modules::{get_mod_inner_attrs, FileModMap}; use crate::formatting::{ - imports::{merge_use_trees, UseTree}, + imports::{merge_use_trees, unnest_use_trees, UseTree}, items::{is_mod_decl, rewrite_extern_crate, rewrite_mod}, lists::{itemize_list, write_list, ListFormatting, ListItem}, rewrite::RewriteContext, @@ -229,6 +229,9 @@ fn rewrite_reorderable_or_regroupable_items( if context.config.merge_imports() { normalized_items = merge_use_trees(normalized_items); } + if context.config.unnest_imports() { + normalized_items = unnest_use_trees(normalized_items); + } let mut regrouped_items = match context.config.group_imports() { GroupImportsTactic::Preserve => vec![normalized_items], diff --git a/tests/source/unnest_imports.rs b/tests/source/unnest_imports.rs new file mode 100644 index 00000000000..43d769ba561 --- /dev/null +++ b/tests/source/unnest_imports.rs @@ -0,0 +1,6 @@ +// rustfmt-unnest_imports: true + +use a::{b::c, d::e}; +use a::{f, g::{h, i}}; +use a::{j::{self, k::{self, l}, m}, n::{o::p, q}}; +pub use a::{r::s, t}; diff --git a/tests/target/unnest_imports.rs b/tests/target/unnest_imports.rs new file mode 100644 index 00000000000..e2f3812743e --- /dev/null +++ b/tests/target/unnest_imports.rs @@ -0,0 +1,12 @@ +// rustfmt-unnest_imports: true + +use a::b::c; +use a::d::e; +use a::f; +use a::g::{h, i}; +use a::j::k::{self, l}; +use a::j::{self, m}; +use a::n::o::p; +use a::n::q; +pub use a::r::s; +pub use a::t; From bdab80e4f7d30b67db8aa35a32339650a0463408 Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Wed, 16 Dec 2020 11:24:33 -0800 Subject: [PATCH 2/4] add a test case for merge+unnest_imports --- tests/source/merge_and_unnest_imports.rs | 9 +++++++++ tests/target/merge_and_unnest_imports.rs | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/source/merge_and_unnest_imports.rs create mode 100644 tests/target/merge_and_unnest_imports.rs diff --git a/tests/source/merge_and_unnest_imports.rs b/tests/source/merge_and_unnest_imports.rs new file mode 100644 index 00000000000..60bf06b47d6 --- /dev/null +++ b/tests/source/merge_and_unnest_imports.rs @@ -0,0 +1,9 @@ +// rustfmt-merge_imports: true +// rustfmt-unnest_imports: true + +use a::b; +use a::c; +use a::d::e; +use a::d::f; +use a::d::{g, h::{i, j::k, l}}; +pub use a::d::m; diff --git a/tests/target/merge_and_unnest_imports.rs b/tests/target/merge_and_unnest_imports.rs new file mode 100644 index 00000000000..2a240d9b4ac --- /dev/null +++ b/tests/target/merge_and_unnest_imports.rs @@ -0,0 +1,8 @@ +// rustfmt-merge_imports: true +// rustfmt-unnest_imports: true + +use a::d::h::j::k; +use a::d::h::{i, l}; +pub use a::d::m; +use a::d::{e, f, g}; +use a::{b, c}; From ca3e5160129fcdc8caa9358681a6ec50cd06e13b Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Wed, 16 Dec 2020 11:25:37 -0800 Subject: [PATCH 3/4] fix docs --- Configurations.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Configurations.md b/Configurations.md index 4a8a6d048cd..10565f84451 100644 --- a/Configurations.md +++ b/Configurations.md @@ -2562,7 +2562,10 @@ not merge into a single tree. ```rust use foo::{a::b, c}; -use foo::{d::{e, f}, g::{h, i}}; +use foo::{ + d::{e, f}, + g::{h, i}, +}; ``` #### `true`: From 781f7bc3df55d5df7b8e070b39338ef284d5784e Mon Sep 17 00:00:00 2001 From: Geoffry Song Date: Wed, 16 Dec 2020 13:55:22 -0800 Subject: [PATCH 4/4] try harder to preserve comments --- src/formatting/imports.rs | 3 +++ tests/source/unnest_imports.rs | 11 +++++++++++ tests/target/unnest_imports.rs | 11 +++++++++++ 3 files changed, 25 insertions(+) diff --git a/src/formatting/imports.rs b/src/formatting/imports.rs index 4cd2b462756..1b75ddf8668 100644 --- a/src/formatting/imports.rs +++ b/src/formatting/imports.rs @@ -193,6 +193,9 @@ pub(crate) fn unnest_use_trees(mut use_trees: Vec) -> Vec { ) { return true; } + if nested_use_tree.has_comment() { + return true; + } // nested item detected; flatten once, but process it again // in case it has more nesting use_trees.push(UseTree { diff --git a/tests/source/unnest_imports.rs b/tests/source/unnest_imports.rs index 43d769ba561..c4b2e95b64a 100644 --- a/tests/source/unnest_imports.rs +++ b/tests/source/unnest_imports.rs @@ -4,3 +4,14 @@ use a::{b::c, d::e}; use a::{f, g::{h, i}}; use a::{j::{self, k::{self, l}, m}, n::{o::p, q}}; pub use a::{r::s, t}; + +#[cfg(test)] +use foo::{a::b, c::d}; + +use bar::{ + // comment + a::b, + // more comment + c::d, + e::f, +}; diff --git a/tests/target/unnest_imports.rs b/tests/target/unnest_imports.rs index e2f3812743e..a3f33ac489a 100644 --- a/tests/target/unnest_imports.rs +++ b/tests/target/unnest_imports.rs @@ -10,3 +10,14 @@ use a::n::o::p; use a::n::q; pub use a::r::s; pub use a::t; + +#[cfg(test)] +use foo::{a::b, c::d}; + +use bar::e::f; +use bar::{ + // comment + a::b, + // more comment + c::d, +};