From 7046624522ec3932b93b65765b54544eaae0452e Mon Sep 17 00:00:00 2001 From: Mateo Carreras Date: Sun, 21 Aug 2022 01:31:25 -0700 Subject: [PATCH] Added new option "chain_count" to limit number of chained functions per line. * Default value of '0' (disabled) * Does not override `chain_width` --- Configurations.md | 52 ++++++++++++++++++++++++++++++++++++ src/chains.rs | 5 +++- src/config/mod.rs | 2 ++ tests/config/issue-2263.toml | 1 + tests/source/chains.rs | 8 ++++++ tests/source/issue-2263.rs | 10 +++++++ tests/target/chains.rs | 8 ++++++ tests/target/issue-2263.rs | 11 ++++++++ 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/config/issue-2263.toml create mode 100644 tests/source/issue-2263.rs create mode 100644 tests/target/issue-2263.rs diff --git a/Configurations.md b/Configurations.md index e066553dc63..6cf0c9e5c0d 100644 --- a/Configurations.md +++ b/Configurations.md @@ -307,6 +307,58 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics) +## `chain_count` + +Maximum number of chained function calls to fit on one line. + +- **Default value**: `0` +- **Possible values**: any positive integer less than `4294967296`, although anything larger than one quarter the value of [`chain_width`](#chain_width) will have no effect as the minimum size of a function chain is 4 (e.g. `.a()`). +- **Stable**: No (tracking issue: [#2263](https://github.com/rust-lang/rustfmt/issues/2263)) + +This option co-exists with [`chain_width`](#chain_width) and chained +method calls will be wrapped if either option is triggered. Any line +with more method chains than defined in this option will have every +chained call put on a new line. + +Setting this option to `0` disables this rule, and `1` puts every single +chained call onto a newline. + +#### `0` (default): + +```rust +fn main() { + a.foo().bar().baz(); +} +``` + +#### `1`: + +```rust +fn main() { + a.foo() + .bar() + .baz(); +} +``` + +#### `2`: + +```rust +fn main() { + a.foo() + .bar() + .baz(); +} +``` + +#### `3`: + +```rust +fn main() { + a.foo().bar().baz(); +} +``` + ## `color` Whether to use colored output or not. diff --git a/src/chains.rs b/src/chains.rs index a2976bbe92a..2b012aa73a8 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -717,7 +717,10 @@ impl<'a> ChainFormatterShared<'a> { } fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option { - let connector = if self.fits_single_line { + let force_multiline = + self.child_count > context.config.chain_count() && context.config.chain_count() != 0; + + let connector = if self.fits_single_line && !force_multiline { // Yay, we can put everything on one line. Cow::from("") } else { diff --git a/src/config/mod.rs b/src/config/mod.rs index 14f27f3f8b6..04eea71f46b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -56,6 +56,7 @@ create_config! { array_width: usize, 60, true, "Maximum width of an array literal before falling \ back to vertical formatting."; chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line."; + chain_count: usize, 0, false, "Maximum number of chained method calls to fit on a single line."; single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \ expressions. A value of zero means always break if-else expressions."; @@ -618,6 +619,7 @@ struct_lit_width = 18 struct_variant_width = 35 array_width = 60 chain_width = 60 +chain_count = 0 single_line_if_else_max_width = 50 wrap_comments = false format_code_in_doc_comments = false diff --git a/tests/config/issue-2263.toml b/tests/config/issue-2263.toml new file mode 100644 index 00000000000..5b0484c048f --- /dev/null +++ b/tests/config/issue-2263.toml @@ -0,0 +1 @@ +chain_count = 3 diff --git a/tests/source/chains.rs b/tests/source/chains.rs index c77f5bac4cb..ae8d9895096 100644 --- a/tests/source/chains.rs +++ b/tests/source/chains.rs @@ -214,6 +214,14 @@ impl Foo { } } +// #2263 +// Limit chain functions per line. +fn issue2263() { + let a = "test"; + + a.to_string().to_string().to_string(); +} + // #2415 // Avoid orphan in chain fn issue2415() { diff --git a/tests/source/issue-2263.rs b/tests/source/issue-2263.rs new file mode 100644 index 00000000000..406e5f1e82a --- /dev/null +++ b/tests/source/issue-2263.rs @@ -0,0 +1,10 @@ +fn main() { + let foo = "foo"; + + foo.to_string().to_string(); + foo.to_string().to_string().to_string(); + foo.to_string() + .to_string() + .to_string(); + foo.to_string().to_string().to_string().to_string(); +} diff --git a/tests/target/chains.rs b/tests/target/chains.rs index 292da298195..e3c1a69303c 100644 --- a/tests/target/chains.rs +++ b/tests/target/chains.rs @@ -252,6 +252,14 @@ impl Foo { } } +// #2263 +// Limit chain functions per line. +fn issue2263() { + let a = "test"; + + a.to_string().to_string().to_string(); +} + // #2415 // Avoid orphan in chain fn issue2415() { diff --git a/tests/target/issue-2263.rs b/tests/target/issue-2263.rs new file mode 100644 index 00000000000..682569cb9c2 --- /dev/null +++ b/tests/target/issue-2263.rs @@ -0,0 +1,11 @@ +fn main() { + let foo = "foo"; + + foo.to_string().to_string(); + foo.to_string().to_string().to_string(); + foo.to_string().to_string().to_string(); + foo.to_string() + .to_string() + .to_string() + .to_string(); +}