diff --git a/Configurations.md b/Configurations.md index 78545c6187a..e2b374ec32b 100644 --- a/Configurations.md +++ b/Configurations.md @@ -768,6 +768,29 @@ 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) + +## `enable_fn_param_limit` + +Switch to enable the unstable feature `fn_param_limit`. + +- **Default value**: `false` +- **Possible values**: `true`, `false` +- **Stable**: No + +See also [`fn_param_limit`](#fn_param_limit) + + +## `fn_param_limit` + +Maximum parameters in the declaration of a function signature before falling back to formatting chosen with `fn_param_layout`. + +- **Default value**: `4` +- **Possible values**: any non-negative integer +- **Stable**: No + +See also [`enable_fn_param_limit`](#enable_fn_param_limit) and [`fn_params_layout`](#fn_params_layout) + + ## `fn_params_layout` Control the layout of parameters in function signatures. diff --git a/src/config/mod.rs b/src/config/mod.rs index 9484b2e5829..e7366a10981 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -87,6 +87,9 @@ create_config! { "Put small struct literals on a single line"; fn_single_line: bool, false, false, "Put single-expression functions on a single line"; where_single_line: bool, false, false, "Force where-clauses to be on a single line"; + enable_fn_param_limit: bool, false, false, "Switch to enable `fn_param_limit`"; + fn_param_limit: usize, 4, false, "How many parameters in a function declaration before \ + falling back to formatting chosen with `fn_param_layout`"; // Imports imports_indent: IndentStyle, IndentStyle::Block, false, "Indent of imports"; @@ -649,6 +652,8 @@ empty_item_single_line = true struct_lit_single_line = true fn_single_line = false where_single_line = false +enable_fn_param_limit = false +fn_param_limit = 4 imports_indent = "Block" imports_layout = "Mixed" imports_granularity = "Preserve" diff --git a/src/items.rs b/src/items.rs index 8669bdda32b..7d845fc2a4e 100644 --- a/src/items.rs +++ b/src/items.rs @@ -2390,6 +2390,7 @@ fn rewrite_fn_base( ret_str_len, fn_brace_style, multi_line_ret_str, + fd.inputs.len(), )?; debug!( @@ -2779,6 +2780,7 @@ fn compute_budgets_for_params( ret_str_len: usize, fn_brace_style: FnBraceStyle, force_vertical_layout: bool, + param_count: usize, ) -> Option<(usize, usize, Indent)> { debug!( "compute_budgets_for_params {} {:?}, {}, {:?}", @@ -2787,8 +2789,10 @@ fn compute_budgets_for_params( ret_str_len, fn_brace_style, ); + let over_param_limit = + context.config.enable_fn_param_limit() && param_count > context.config.fn_param_limit(); // Try keeping everything on the same line. - if !result.contains('\n') && !force_vertical_layout { + if !result.contains('\n') && !force_vertical_layout && !over_param_limit { // 2 = `()`, 3 = `() `, space is before ret_string. let overhead = if ret_str_len == 0 { 2 } else { 3 }; let mut used_space = indent.width() + result.len() + ret_str_len + overhead; diff --git a/tests/source/fn_param_limit/0.rs b/tests/source/fn_param_limit/0.rs new file mode 100644 index 00000000000..520a98fc910 --- /dev/null +++ b/tests/source/fn_param_limit/0.rs @@ -0,0 +1,95 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 0 +// rustfmt-edition: 2018 + +fn lorem(mut commands: Commands) { + // block +} +fn lorem(mut commands: Commands, icons: Res) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>, mut materials: ResMut>) { + // block +} + +fn comments(mut commands: Commands, /**/ icons: Res) { + // block +} + +fn comments(mut commands: Commands, /* really loooooong intermission */ icons: Res) { + // block +} + +fn generic(query: Query, query2: Query) { + // block +} + +fn lorem(query: Query) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(query: Query, mut commands: Commands, icons: Res) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(mut commands: Commands, icons: Res) -> bool { + // block +} + +pub fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(crate) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(super) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +async fn lorem(mut commands: Commands, icons: Res) { + // block +} + +unsafe fn lorem(mut commands: Commands, icons: Res) { + // block +} + +extern "C" { + fn lorem(mut commands: Commands, icons: Res) { + // block + } +} + +impl Trait { + fn lorem(mut commands: Commands); + fn lorem(mut commands: Commands, icons: Res); + fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + + fn inner(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } +} + +mod example { + fn mod_func(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + fn nested(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } + } +} diff --git a/tests/source/fn_param_limit/1.rs b/tests/source/fn_param_limit/1.rs new file mode 100644 index 00000000000..008239c51bd --- /dev/null +++ b/tests/source/fn_param_limit/1.rs @@ -0,0 +1,95 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 1 +// rustfmt-edition: 2018 + +fn lorem(mut commands: Commands) { + // block +} +fn lorem(mut commands: Commands, icons: Res) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>, mut materials: ResMut>) { + // block +} + +fn comments(mut commands: Commands, /**/ icons: Res) { + // block +} + +fn comments(mut commands: Commands, /* really loooooong intermission */ icons: Res) { + // block +} + +fn generic(query: Query, query2: Query) { + // block +} + +fn lorem(query: Query) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(query: Query, mut commands: Commands, icons: Res) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(mut commands: Commands, icons: Res) -> bool { + // block +} + +pub fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(crate) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(super) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +async fn lorem(mut commands: Commands, icons: Res) { + // block +} + +unsafe fn lorem(mut commands: Commands, icons: Res) { + // block +} + +extern "C" { + fn lorem(mut commands: Commands, icons: Res) { + // block + } +} + +impl Trait { + fn lorem(mut commands: Commands); + fn lorem(mut commands: Commands, icons: Res); + fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + + fn inner(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } +} + +mod example { + fn mod_func(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + fn nested(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } + } +} diff --git a/tests/source/fn_param_limit/2.rs b/tests/source/fn_param_limit/2.rs new file mode 100644 index 00000000000..3343f22fd8b --- /dev/null +++ b/tests/source/fn_param_limit/2.rs @@ -0,0 +1,95 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 2 +// rustfmt-edition: 2018 + +fn lorem(mut commands: Commands) { + // block +} +fn lorem(mut commands: Commands, icons: Res) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block +} +fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>, mut materials: ResMut>) { + // block +} + +fn comments(mut commands: Commands, /**/ icons: Res) { + // block +} + +fn comments(mut commands: Commands, /* really really loooooooong intermission */ icons: Res) { + // block +} + +fn generic(query: Query, query2: Query) { + // block +} + +fn lorem(query: Query) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(query: Query, mut commands: Commands, icons: Res) where C: Add + Sub + Mul + Div { + // body +} + +fn lorem(mut commands: Commands, icons: Res) -> bool { + // block +} + +pub fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(crate) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(super) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +async fn lorem(mut commands: Commands, icons: Res) { + // block +} + +unsafe fn lorem(mut commands: Commands, icons: Res) { + // block +} + +extern "C" { + fn lorem(mut commands: Commands, icons: Res) { + // block + } +} + +impl Trait { + fn lorem(mut commands: Commands); + fn lorem(mut commands: Commands, icons: Res); + fn lorem(mut commands: Commands, icons: Res, mut meshes: ResMut>); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + + fn inner(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } +} + +mod example { + fn mod_func(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + fn nested(mut commands: Commands, icons: Res, mut meshes: ResMut>) { + // block + } + } +} diff --git a/tests/target/fn_param_limit/0.rs b/tests/target/fn_param_limit/0.rs new file mode 100644 index 00000000000..fcb2fea368a --- /dev/null +++ b/tests/target/fn_param_limit/0.rs @@ -0,0 +1,174 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 0 +// rustfmt-edition: 2018 + +fn lorem( + mut commands: Commands, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // block +} + +fn comments( + mut commands: Commands, + /**/ icons: Res, +) { + // block +} + +fn comments( + mut commands: Commands, + /* really loooooong intermission */ icons: Res, +) { + // block +} + +fn generic( + query: Query, + query2: Query, +) { + // block +} + +fn lorem( + query: Query, +) where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem( + query: Query, + mut commands: Commands, + icons: Res, +) where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem( + mut commands: Commands, + icons: Res, +) -> bool { + // block +} + +pub fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +pub(crate) fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +pub(super) fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +async fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +unsafe fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +extern "C" { + fn lorem( + mut commands: Commands, + icons: Res, + ) { + // block + } +} + +impl Trait { + fn lorem( + mut commands: Commands, + ); + fn lorem( + mut commands: Commands, + icons: Res, + ); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block + + fn inner( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } +} + +mod example { + fn mod_func( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + fn nested( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } + } +} diff --git a/tests/target/fn_param_limit/1.rs b/tests/target/fn_param_limit/1.rs new file mode 100644 index 00000000000..48d36ae0694 --- /dev/null +++ b/tests/target/fn_param_limit/1.rs @@ -0,0 +1,169 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 1 +// rustfmt-edition: 2018 + +fn lorem(mut commands: Commands) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // block +} + +fn comments( + mut commands: Commands, + /**/ icons: Res, +) { + // block +} + +fn comments( + mut commands: Commands, + /* really loooooong intermission */ icons: Res, +) { + // block +} + +fn generic( + query: Query, + query2: Query, +) { + // block +} + +fn lorem(query: Query) +where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem( + query: Query, + mut commands: Commands, + icons: Res, +) where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem( + mut commands: Commands, + icons: Res, +) -> bool { + // block +} + +pub fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +pub(crate) fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +pub(super) fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +async fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +unsafe fn lorem( + mut commands: Commands, + icons: Res, +) { + // block +} + +extern "C" { + fn lorem( + mut commands: Commands, + icons: Res, + ) { + // block + } +} + +impl Trait { + fn lorem(mut commands: Commands); + fn lorem( + mut commands: Commands, + icons: Res, + ); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block + + fn inner( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } +} + +mod example { + fn mod_func( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + fn nested( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } + } +} diff --git a/tests/target/fn_param_limit/2.rs b/tests/target/fn_param_limit/2.rs new file mode 100644 index 00000000000..15be800b665 --- /dev/null +++ b/tests/target/fn_param_limit/2.rs @@ -0,0 +1,136 @@ +// rustfmt-enable_fn_param_limit: true +// rustfmt-fn_param_limit: 2 +// rustfmt-edition: 2018 + +fn lorem(mut commands: Commands) { + // block +} +fn lorem(mut commands: Commands, icons: Res) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block +} +fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // block +} + +fn comments(mut commands: Commands, /**/ icons: Res) { + // block +} + +fn comments( + mut commands: Commands, + /* really really loooooooong intermission */ icons: Res, +) { + // block +} + +fn generic(query: Query, query2: Query) { + // block +} + +fn lorem(query: Query) +where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem( + query: Query, + mut commands: Commands, + icons: Res, +) where + C: Add + Sub + Mul + Div, +{ + // body +} + +fn lorem(mut commands: Commands, icons: Res) -> bool { + // block +} + +pub fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(crate) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +pub(super) fn lorem(mut commands: Commands, icons: Res) { + // block +} + +async fn lorem(mut commands: Commands, icons: Res) { + // block +} + +unsafe fn lorem(mut commands: Commands, icons: Res) { + // block +} + +extern "C" { + fn lorem(mut commands: Commands, icons: Res) { + // block + } +} + +impl Trait { + fn lorem(mut commands: Commands); + fn lorem(mut commands: Commands, icons: Res); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ); + fn lorem( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + mut materials: ResMut>, + ); +} + +fn outer( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, +) { + // block + + fn inner( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } +} + +mod example { + fn mod_func( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + fn nested( + mut commands: Commands, + icons: Res, + mut meshes: ResMut>, + ) { + // block + } + } +}