Skip to content

Commit 62846f4

Browse files
refactor: add chain child indent options
1 parent e9acbb5 commit 62846f4

14 files changed

+318
-213
lines changed

Configurations.md

Lines changed: 109 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -392,39 +392,135 @@ fn example() {
392392
## `chains_block_parent_indent_children`
393393
Determines whether to indent the child chain items of a chain that beings with a block-like parent element when `indent_style` is `Block`.
394394

395-
- **Default value**: `false`
396-
- **Possible values**: `true`, `false`
395+
- **Default value**: `"OnlyWithParent"`
396+
- **Possible values**: `"Never"`, `"Always"`, `"OnlyWithParent"`
397397
- **Stable**: No (tracking issue: ...)
398398

399-
#### `false` (default):
399+
#### `OnlyWithParent` (default):
400+
Only indent the children chain elements of a block-like parent element if the parent's body was indented.
400401

401402
```rust
403+
// chains_block_parent_indent_parent_item: "OnlyTupleLitsAndSimpleCalls"
404+
#![rustfmt::skip]
402405
fn example() {
403-
StructA {
404-
test_test: some_value,
405-
}
406-
.foo()
406+
let all = very_very_very_very_very_long_fun_name(
407+
very_very_very_very_very_very_very_very_very_long_var_name,
408+
)
409+
.iter()
410+
.map(|x| x + very_very_very_very_very_very_long_var_name);
411+
412+
foo(|x| {
413+
// ....
414+
})
407415
.bar()
408416
.baz()
409-
.qux();
417+
.unwrap();
418+
419+
StructA {
420+
test_test: some_value,
421+
}
422+
.do_stuff(StructB {
423+
test_test_b: other_value,
424+
})
425+
.foo()
426+
.aaa_aaa();
427+
428+
let y = if some_condition {
429+
// foo
430+
val1
431+
} else {
432+
// bar
433+
val2
434+
}
435+
.method_call()
436+
.other_call()
437+
.another();
410438
}
411439
```
412440

413-
#### `true`:
441+
#### `Always`:
442+
Always indent the children chain elements of a block-like parent element, regardless of whether the parent element body was indented.
414443

415444
```rust
416445
fn example() {
446+
let all = very_very_very_very_very_long_fun_name(
447+
very_very_very_very_very_very_very_very_very_long_var_name,
448+
)
449+
.iter()
450+
.map(|x| x + very_very_very_very_very_very_long_var_name);
451+
452+
foo(|x| {
453+
// ....
454+
})
455+
.bar()
456+
.baz()
457+
.unwrap();
458+
417459
StructA {
418460
test_test: some_value,
419461
}
462+
.do_stuff(StructB {
463+
test_test_b: other_value,
464+
})
420465
.foo()
421-
.bar()
422-
.baz()
423-
.qux();
466+
.aaa_aaa();
467+
468+
let y = if some_condition {
469+
// foo
470+
val1
471+
} else {
472+
// bar
473+
val2
474+
}
475+
.method_call()
476+
.other_call()
477+
.another();
424478
}
425479
```
426480

427-
See also: [`indent_style`](#indent_style).
481+
#### `Never`:
482+
Never indent the children chain elements of a block-like parent element, regardless of whether the parent element body was indented.
483+
484+
```rust
485+
// chains_block_parent_indent_parent_item: "OnlyTupleLitsAndSimpleCalls"
486+
#![rustfmt::skip]
487+
fn example() {
488+
let all = very_very_very_very_very_long_fun_name(
489+
very_very_very_very_very_very_very_very_very_long_var_name,
490+
)
491+
.iter()
492+
.map(|x| x + very_very_very_very_very_very_long_var_name);
493+
494+
foo(|x| {
495+
// ....
496+
})
497+
.bar()
498+
.baz()
499+
.unwrap();
500+
501+
StructA {
502+
test_test: some_value,
503+
}
504+
.do_stuff(StructB {
505+
test_test_b: other_value,
506+
})
507+
.foo()
508+
.aaa_aaa();
509+
510+
let y = if some_condition {
511+
// foo
512+
val1
513+
} else {
514+
// bar
515+
val2
516+
}
517+
.method_call()
518+
.other_call()
519+
.another();
520+
}
521+
```
522+
523+
See also: [`indent_style`](#indent_style), [`chains_block_parent_indent_parent_item`](#chains_block_parent_indent_parent_item).
428524

429525
## `chains_block_parent_indent_parent_item`
430526
Determines whether block-like chain parents are indented when `indent_style` is `Block`.

src/chains.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use syntax::{ast, ptr};
6363

6464
use crate::closures::rewrite_closure;
6565
use crate::comment::{rewrite_comment, CharClasses, FullCodeCharKind, RichChar};
66-
use crate::config::{ChainsBlockParentElementIndent, IndentStyle};
66+
use crate::config::{ChainsBlockParentChildrenIndent, ChainsBlockParentElementIndent, IndentStyle};
6767
use crate::expr::rewrite_call;
6868
use crate::lists::extract_pre_comment;
6969
use crate::macros::convert_try_mac;
@@ -924,12 +924,17 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
924924
}
925925

926926
fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
927-
let always_indent_children = context.config.chains_block_parent_indent_children();
927+
let indent_style = context.config.chains_block_parent_indent_children();
928+
let use_indented = match indent_style {
929+
ChainsBlockParentChildrenIndent::Always => true,
930+
ChainsBlockParentChildrenIndent::Never => false,
931+
ChainsBlockParentChildrenIndent::OnlyWithParent if self.parent_body_forced_indent => {
932+
true
933+
}
934+
_ => false,
935+
};
928936
Some(
929-
if !self.root_ends_with_block
930-
|| always_indent_children
931-
|| self.parent_body_forced_indent
932-
{
937+
if !self.root_ends_with_block || use_indented {
933938
shape.block_indent(context.config.tab_spaces())
934939
} else {
935940
shape.block_indent(0)
@@ -974,7 +979,6 @@ impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
974979
Some(rewrite) => wrap_str(rewrite, context.config.max_width(), shape),
975980
None => None,
976981
}
977-
// self.shared.join_rewrites(context, child_shape)
978982
}
979983

980984
fn pure_root(&mut self) -> Option<String> {

src/config/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ create_config! {
6666
merge_imports: bool, false, false, "Merge imports";
6767

6868
// Chains
69-
chains_block_parent_indent_children: bool, false, false,
69+
chains_block_parent_indent_children:
70+
ChainsBlockParentChildrenIndent,
71+
ChainsBlockParentChildrenIndent::OnlyWithParent,
72+
false,
7073
"Determines whether to indent the child chain items of a chain that beings with/
7174
a block-like parent element";
7275
chains_block_parent_indent_parent_item:
@@ -519,7 +522,7 @@ where_single_line = false
519522
imports_indent = "Block"
520523
imports_layout = "Mixed"
521524
merge_imports = false
522-
chains_block_parent_indent_children = false
525+
chains_block_parent_indent_children = "OnlyWithParent"
523526
chains_block_parent_indent_parent_item = "Never"
524527
reorder_imports = true
525528
reorder_modules = true

src/config/options.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ pub enum ChainsBlockParentElementIndent {
187187
OnlyTupleLitsAndSimpleCalls,
188188
}
189189

190+
#[config_type]
191+
pub enum ChainsBlockParentChildrenIndent {
192+
/// Never indent the children chain elements of a block-like parent element.
193+
Never,
194+
/// Always indent the children chain elements of a block-like parent element.
195+
Always,
196+
/// Only indent the children chain elements if the block-like parent body is indented.
197+
OnlyWithParent,
198+
}
199+
190200
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
191201
pub struct WidthHeuristics {
192202
// Maximum width of the args of a function call before falling back

tests/source/chains_long_items_block.rs

Lines changed: 74 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,80 @@ fn issue_3863() {
55
foo("This text is under the max_width limit, and shouldn't cause any problems on its own.").long("But this line is extra long, and doesn't fit within 100 max_width. 1234567890123456789 aBcDeFgHiJ").baz().collect().unwrap();
66
}
77

8+
// https://github.com/rust-lang/rustup.rs/pull/2097
9+
fn deeply_nested() {
10+
let mut app = App::new("rustup")
11+
.version(common::version())
12+
.about("The Rust toolchain installer")
13+
.after_help(RUSTUP_HELP)
14+
.setting(AppSettings::VersionlessSubcommands)
15+
.setting(AppSettings::DeriveDisplayOrder)
16+
.setting(AppSettings::SubcommandRequiredElseHelp)
17+
.subcommand(
18+
SubCommand::with_name("run")
19+
.about("Run a command with an environment configured for a given toolchain")
20+
.after_help(RUN_HELP)
21+
.setting(AppSettings::TrailingVarArg)
22+
.arg(
23+
Arg::with_name("install")
24+
.help("Install the requested toolchain if needed")
25+
.long("install"),
26+
)
27+
.arg(
28+
Arg::with_name("toolchain")
29+
.help(TOOLCHAIN_ARG_HELP)
30+
.required(true),
31+
)
32+
.arg(
33+
Arg::with_name("command")
34+
.required(true)
35+
.multiple(true)
36+
.use_delimiter(false),
37+
),
38+
)
39+
.subcommand(
40+
SubCommand::with_name("which")
41+
.about("Display which binary will be run for a given command")
42+
.arg(Arg::with_name("command").required(true))
43+
.arg(
44+
Arg::with_name("toolchain")
45+
.help(TOOLCHAIN_ARG_HELP)
46+
.long("toolchain")
47+
.takes_value(true),
48+
),
49+
)
50+
.subcommand(
51+
SubCommand::with_name("doc")
52+
.alias("docs")
53+
.about("Open the documentation for the current toolchain")
54+
.after_help(DOC_HELP)
55+
.arg(
56+
Arg::with_name("path")
57+
.long("path")
58+
.help("Only print the path to the documentation"),
59+
)
60+
.args(
61+
&DOCS_DATA
62+
.iter()
63+
.map(|(name, help_msg, _)| Arg::with_name(name).long(name).help(help_msg))
64+
.collect::<Vec<_>>(),
65+
)
66+
.arg(Arg::with_name("toolchain")
67+
.help(TOOLCHAIN_ARG_HELP)
68+
.long("toolchain")
69+
.takes_value(true),
70+
).group(ArgGroup::with_name("page").args(
71+
&DOCS_DATA
72+
.iter()
73+
.map(|(name, _, _)| *name)
74+
.collect::<Vec<_>>(),
75+
),
76+
)
77+
.arg(Arg::with_name("topic").help("Topic such as 'core', 'fn', 'usize', 'eprintln!', 'core::arch', 'alloc::format!', 'std::fs', 'std::fs::read_dir', 'std::io::Bytes', 'std::iter::Sum', 'std::io::error::Result' etc..."),
78+
),
79+
);
80+
}
81+
882
fn long_parent() {
983
// Args that do not fit
1084
let bar = baz("ffffffffffffffffffffffffffffffffffffasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfadfasdfasdfasdfadfasdfasdf").foo().bar().baz();
@@ -77,80 +151,6 @@ fn raw_str_lit() {
77151
"#.trim().foo().bar.baz.qux().unwrap());
78152
}
79153

80-
// https://github.com/rust-lang/rustup.rs/pull/2097
81-
fn deeply_nested() {
82-
let mut app = App::new("rustup")
83-
.version(common::version())
84-
.about("The Rust toolchain installer")
85-
.after_help(RUSTUP_HELP)
86-
.setting(AppSettings::VersionlessSubcommands)
87-
.setting(AppSettings::DeriveDisplayOrder)
88-
.setting(AppSettings::SubcommandRequiredElseHelp)
89-
.subcommand(
90-
SubCommand::with_name("run")
91-
.about("Run a command with an environment configured for a given toolchain")
92-
.after_help(RUN_HELP)
93-
.setting(AppSettings::TrailingVarArg)
94-
.arg(
95-
Arg::with_name("install")
96-
.help("Install the requested toolchain if needed")
97-
.long("install"),
98-
)
99-
.arg(
100-
Arg::with_name("toolchain")
101-
.help(TOOLCHAIN_ARG_HELP)
102-
.required(true),
103-
)
104-
.arg(
105-
Arg::with_name("command")
106-
.required(true)
107-
.multiple(true)
108-
.use_delimiter(false),
109-
),
110-
)
111-
.subcommand(
112-
SubCommand::with_name("which")
113-
.about("Display which binary will be run for a given command")
114-
.arg(Arg::with_name("command").required(true))
115-
.arg(
116-
Arg::with_name("toolchain")
117-
.help(TOOLCHAIN_ARG_HELP)
118-
.long("toolchain")
119-
.takes_value(true),
120-
),
121-
)
122-
.subcommand(
123-
SubCommand::with_name("doc")
124-
.alias("docs")
125-
.about("Open the documentation for the current toolchain")
126-
.after_help(DOC_HELP)
127-
.arg(
128-
Arg::with_name("path")
129-
.long("path")
130-
.help("Only print the path to the documentation"),
131-
)
132-
.args(
133-
&DOCS_DATA
134-
.iter()
135-
.map(|(name, help_msg, _)| Arg::with_name(name).long(name).help(help_msg))
136-
.collect::<Vec<_>>(),
137-
)
138-
.arg(Arg::with_name("toolchain")
139-
.help(TOOLCHAIN_ARG_HELP)
140-
.long("toolchain")
141-
.takes_value(true),
142-
).group(ArgGroup::with_name("page").args(
143-
&DOCS_DATA
144-
.iter()
145-
.map(|(name, _, _)| *name)
146-
.collect::<Vec<_>>(),
147-
),
148-
)
149-
.arg(Arg::with_name("topic").help("Topic such as 'core', 'fn', 'usize', 'eprintln!', 'core::arch', 'alloc::format!', 'std::fs', 'std::fs::read_dir', 'std::io::Bytes', 'std::iter::Sum', 'std::io::error::Result' etc..."),
150-
),
151-
);
152-
}
153-
154154
fn comments() {
155155
foo // foo
156156
// comment after parent

tests/source/chains_multiline_parent_always.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// rustfmt-chains_block_parent_indent_children: true
21
// rustfmt-chains_block_parent_indent_parent_item: Always
32
// rustfmt-use_small_heuristics: Off
43

tests/source/chains_multiline_parent_never.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// rustfmt-chains_block_parent_indent_children: false
21
// rustfmt-chains_block_parent_indent_parent_item: Never
32

43
fn main() {

0 commit comments

Comments
 (0)