diff --git a/Configurations.md b/Configurations.md index 8c84614352c..3896de82a7a 100644 --- a/Configurations.md +++ b/Configurations.md @@ -753,6 +753,75 @@ trait Lorem { } ``` +## `fn_call_layout` + +Control the layout of arguments in function calls + +- **Default value**: `"Tall"` +- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"` +- **Stable**: No (tracking issue: N/A) + +#### `"Tall"` (default): + +```rust +fn main() { + lorem(ipsum, dolor, sit, amet); + ipsum( + dolor, + sit, + amet, + consectetur, + adipiscing, + elit, + vivamus, + ipsum, + orci, + rhoncus, + vel, + imperdiet, + ); +} +``` + +#### `"Compressed"`: + +```rust +fn main() { + lorem(ipsum, dolor, sit, amet); + ipsum( + dolor, sit, amet, consectetur, adipiscing, elit, vivamus, ipsum, orci, rhoncus, vel, + imperdiet, + ); +} +``` + +#### `"Vertical"`: + +```rust +fn main() { + lorem( + ipsum, + dolor, + sit, + amet, + ); + ipsum( + dolor, + sit, + amet, + consectetur, + adipiscing, + elit, + vivamus, + ipsum, + orci, + rhoncus, + vel, + imperdiet, + ); +} +``` + ## `fn_call_width` Maximum width of the args of a function call before falling back to vertical formatting. diff --git a/src/attr.rs b/src/attr.rs index 41ba9a847e6..4d20acfcb18 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -309,6 +309,7 @@ impl Rewrite for ast::MetaItem { } else { SeparatorTactic::Never }), + None, )? } ast::MetaItemKind::NameValue(ref literal) => { diff --git a/src/chains.rs b/src/chains.rs index e26e24ec55a..e7d1ec26c03 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -253,7 +253,7 @@ impl ChainItem { format!("::<{}>", type_list.join(", ")) }; let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str); - rewrite_call(context, &callee_str, &args[1..], span, shape) + rewrite_call(context, &callee_str, &args[1..], None, span, shape) } } diff --git a/src/config/mod.rs b/src/config/mod.rs index a5169528187..b65b44783c4 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -118,6 +118,8 @@ create_config! { "Force multiline closure bodies and match arms to be wrapped in a block"; fn_args_layout: Density, Density::Tall, true, "Control the layout of arguments in a function"; + fn_call_layout: Density, Density::Tall, false, + "Control the layout of arguments in a function call"; brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items"; control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false, "Brace style for control flow constructs"; @@ -565,6 +567,7 @@ match_arm_blocks = true match_arm_leading_pipes = "Never" force_multiline_blocks = false fn_args_layout = "Tall" +fn_call_layout = "Tall" brace_style = "SameLineWhere" control_brace_style = "AlwaysSameLine" trailing_semicolon = true diff --git a/src/expr.rs b/src/expr.rs index 4ccf1ca70c9..96ebe2f082a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -138,7 +138,19 @@ fn format_expr_inner( ast::ExprKind::Call(ref callee, ref args) => { let inner_span = mk_sp(callee.span.hi(), expr.span.hi()); let callee_str = callee.rewrite(context, shape)?; - rewrite_call(context, &callee_str, args, inner_span, shape) + let force_list_tactic = if context.config.was_set().fn_call_layout() { + Some(context.config.fn_call_layout().to_list_tactic(args.len())) + } else { + None + }; + rewrite_call( + context, + &callee_str, + args, + force_list_tactic, + inner_span, + shape, + ) } ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span), ast::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -1313,6 +1325,7 @@ pub(crate) fn rewrite_call( context: &RewriteContext<'_>, callee: &str, args: &[ptr::P], + force_list_tactic: Option, span: Span, shape: Shape, ) -> Option { @@ -1324,6 +1337,7 @@ pub(crate) fn rewrite_call( span, context.config.fn_call_width(), choose_separator_tactic(context, span), + force_list_tactic, ) } @@ -1861,6 +1875,7 @@ pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>( span, context.config.fn_call_width(), force_tactic, + None, ) } else { rewrite_tuple_in_visual_indent_style(context, items, span, shape, is_singleton_tuple) diff --git a/src/items.rs b/src/items.rs index bab881f4b4e..ccc3848ca58 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1484,6 +1484,7 @@ fn format_tuple_struct( mk_sp(lo, span.hi()), context.config.fn_call_width(), None, + None, )?; } diff --git a/src/macros.rs b/src/macros.rs index f4b2bcf2815..55a6304fb56 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -279,6 +279,7 @@ fn rewrite_macro_inner( } else { Some(SeparatorTactic::Never) }, + None, ) .map(|rw| match position { MacroPosition::Item => format!("{};", rw), diff --git a/src/overflow.rs b/src/overflow.rs index 6bf8cd0c70b..09cb0ce98de 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -252,6 +252,7 @@ pub(crate) fn rewrite_with_parens<'a, T: 'a + IntoOverflowableItem<'a>>( span: Span, item_max_width: usize, force_separator_tactic: Option, + force_list_tactic: Option, ) -> Option { Context::new( context, @@ -263,6 +264,7 @@ pub(crate) fn rewrite_with_parens<'a, T: 'a + IntoOverflowableItem<'a>>( ")", item_max_width, force_separator_tactic, + force_list_tactic, None, ) .rewrite(shape) @@ -286,6 +288,7 @@ pub(crate) fn rewrite_with_angle_brackets<'a, T: 'a + IntoOverflowableItem<'a>>( context.config.max_width(), None, None, + None, ) .rewrite(shape) } @@ -314,6 +317,7 @@ pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>> rhs, context.config.array_width(), force_separator_tactic, + None, Some(("[", "]")), ) .rewrite(shape) @@ -331,6 +335,7 @@ struct Context<'a> { item_max_width: usize, one_line_width: usize, force_separator_tactic: Option, + force_list_tactic: Option, custom_delims: Option<(&'a str, &'a str)>, } @@ -345,6 +350,7 @@ impl<'a> Context<'a> { suffix: &'static str, item_max_width: usize, force_separator_tactic: Option, + force_list_tactic: Option, custom_delims: Option<(&'a str, &'a str)>, ) -> Context<'a> { let used_width = extra_offset(ident, shape); @@ -369,6 +375,7 @@ impl<'a> Context<'a> { item_max_width, one_line_width, force_separator_tactic, + force_list_tactic, custom_delims, } } @@ -584,6 +591,25 @@ impl<'a> Context<'a> { _ => (), } + match self.force_list_tactic { + Some(list_tactic) if list_tactic == ListTactic::Mixed => { + if tactic != DefinitiveListTactic::Horizontal { + tactic = DefinitiveListTactic::Mixed + } + } + // If we need to force a tactic (like Vertical), we should only do it if there are + // at least 2 items for us to format. Otherwise, use the tactic already determined. + Some(list_tactic) if self.items.len() > 1 => { + tactic = definitive_tactic( + &*list_items, + list_tactic, + Separator::Comma, + self.one_line_width, + ) + } + _ => {} + }; + tactic } diff --git a/src/patterns.rs b/src/patterns.rs index 9b74b35f314..f323646c336 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -494,6 +494,7 @@ fn rewrite_tuple_pat( } else { None }, + None, ) } diff --git a/src/types.rs b/src/types.rs index 64a201e45dd..0f980323373 100644 --- a/src/types.rs +++ b/src/types.rs @@ -844,6 +844,7 @@ impl Rewrite for ast::Ty { context, "typeof", &[anon_const.value.clone()], + None, self.span, shape, ), diff --git a/tests/source/configs/fn_call_layout/compressed.rs b/tests/source/configs/fn_call_layout/compressed.rs new file mode 100644 index 00000000000..f4a07f1910f --- /dev/null +++ b/tests/source/configs/fn_call_layout/compressed.rs @@ -0,0 +1,58 @@ +// rustfmt-fn_call_layout:Compressed + +fn main() { + empty_args(); + single_arg(ipsum); + two_args(ipsum, dolor); + + lorem(ipsum, dolor, sit, amet); + lorem(ipsum, // some inine comment + dolor, sit, amet); + lorem(ipsum, /* some inine comment */ + dolor, sit, amet); + ipsum(dolor, sit, amet, consectetur, adipiscing, elit, vivamus, ipsum, orci, rhoncus, vel, imperdiet); + + // issue 2010 + let a = i8x32::new( + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32, + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32); + + // issue 4146 + return_monitor_err( + e, + channel_state, + chan, + order, + commitment_update.is_some(), + revoke_and_ack.is_some(), + ); + + + // other examples with more complex args + more_complex_args( + |a, b, c| {if a == 998765390 {- b * 3 } else {c} }, + std::ops::Range { start: 3, end: 5 }, + std::i8::MAX, String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), "another argument" + ) +} diff --git a/tests/source/configs/fn_call_layout/tall.rs b/tests/source/configs/fn_call_layout/tall.rs new file mode 100644 index 00000000000..1f02ad60e86 --- /dev/null +++ b/tests/source/configs/fn_call_layout/tall.rs @@ -0,0 +1,58 @@ +// rustfmt-fn_call_layout:Tall + +fn main() { + empty_args(); + single_arg(ipsum); + two_args(ipsum, dolor); + + lorem(ipsum, dolor, sit, amet); + lorem(ipsum, // some inine comment + dolor, sit, amet); + lorem(ipsum, /* some inine comment */ + dolor, sit, amet); + ipsum(dolor, sit, amet, consectetur, adipiscing, elit, vivamus, ipsum, orci, rhoncus, vel, imperdiet); + + // issue 2010 + let a = i8x32::new( + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32, + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32); + + // issue 4146 + return_monitor_err( + e, + channel_state, + chan, + order, + commitment_update.is_some(), + revoke_and_ack.is_some(), + ); + + + // other examples with more complex args + more_complex_args( + |a, b, c| {if a == 998765390 {- b * 3 } else {c} }, + std::ops::Range { start: 3, end: 5 }, + std::i8::MAX, String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), "another argument" + ) +} diff --git a/tests/source/configs/fn_call_layout/vertical.rs b/tests/source/configs/fn_call_layout/vertical.rs new file mode 100644 index 00000000000..7e25602784f --- /dev/null +++ b/tests/source/configs/fn_call_layout/vertical.rs @@ -0,0 +1,58 @@ +// rustfmt-fn_call_layout:Vertical + +fn main() { + empty_args(); + single_arg(ipsum); + two_args(ipsum, dolor); + + lorem(ipsum, dolor, sit, amet); + lorem(ipsum, // some inine comment + dolor, sit, amet); + lorem(ipsum, /* some inine comment */ + dolor, sit, amet); + ipsum(dolor, sit, amet, consectetur, adipiscing, elit, vivamus, ipsum, orci, rhoncus, vel, imperdiet); + + // issue 2010 + let a = i8x32::new( + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32, + 0, 1, -1, 2, + -2, 3, -3, 4, + -4, 5, -5, std::i8::MAX, + std::i8::MIN + 1, 100, -100, -32); + + // issue 4146 + return_monitor_err( + e, + channel_state, + chan, + order, + commitment_update.is_some(), + revoke_and_ack.is_some(), + ); + + + // other examples with more complex args + more_complex_args( + |a, b, c| {if a == 998765390 {- b * 3 } else {c} }, + std::ops::Range { start: 3, end: 5 }, + std::i8::MAX, String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), "another argument" + ) +} diff --git a/tests/target/configs/fn_call_layout/compressed.rs b/tests/target/configs/fn_call_layout/compressed.rs new file mode 100644 index 00000000000..0fe381e92e8 --- /dev/null +++ b/tests/target/configs/fn_call_layout/compressed.rs @@ -0,0 +1,58 @@ +// rustfmt-fn_call_layout:Compressed + +fn main() { + empty_args(); + single_arg(ipsum); + two_args(ipsum, dolor); + + lorem(ipsum, dolor, sit, amet); + lorem( + ipsum, // some inine comment + dolor, sit, amet, + ); + lorem(ipsum /* some inine comment */, dolor, sit, amet); + ipsum( + dolor, sit, amet, consectetur, adipiscing, elit, vivamus, ipsum, orci, rhoncus, vel, + imperdiet, + ); + + // issue 2010 + let a = i8x32::new( + 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, std::i8::MAX, std::i8::MIN + 1, 100, -100, -32, 0, 1, + -1, 2, -2, 3, -3, 4, -4, 5, -5, std::i8::MAX, std::i8::MIN + 1, 100, -100, -32, + ); + + // issue 4146 + return_monitor_err( + e, channel_state, chan, order, commitment_update.is_some(), revoke_and_ack.is_some(), + ); + + // other examples with more complex args + more_complex_args( + |a, b, c| { + if a == 998765390 { + -b * 3 + } else { + c + } + }, + std::ops::Range { start: 3, end: 5 }, std::i8::MAX, + String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), + "another argument", + ) +} diff --git a/tests/target/configs/fn_call_layout/tall.rs b/tests/target/configs/fn_call_layout/tall.rs new file mode 100644 index 00000000000..0f3473a037c --- /dev/null +++ b/tests/target/configs/fn_call_layout/tall.rs @@ -0,0 +1,106 @@ +// rustfmt-fn_call_layout:Tall + +fn main() { + empty_args(); + single_arg(ipsum); + two_args(ipsum, dolor); + + lorem(ipsum, dolor, sit, amet); + lorem( + ipsum, // some inine comment + dolor, + sit, + amet, + ); + lorem(ipsum /* some inine comment */, dolor, sit, amet); + ipsum( + dolor, + sit, + amet, + consectetur, + adipiscing, + elit, + vivamus, + ipsum, + orci, + rhoncus, + vel, + imperdiet, + ); + + // issue 2010 + let a = i8x32::new( + 0, + 1, + -1, + 2, + -2, + 3, + -3, + 4, + -4, + 5, + -5, + std::i8::MAX, + std::i8::MIN + 1, + 100, + -100, + -32, + 0, + 1, + -1, + 2, + -2, + 3, + -3, + 4, + -4, + 5, + -5, + std::i8::MAX, + std::i8::MIN + 1, + 100, + -100, + -32, + ); + + // issue 4146 + return_monitor_err( + e, + channel_state, + chan, + order, + commitment_update.is_some(), + revoke_and_ack.is_some(), + ); + + // other examples with more complex args + more_complex_args( + |a, b, c| { + if a == 998765390 { + -b * 3 + } else { + c + } + }, + std::ops::Range { start: 3, end: 5 }, + std::i8::MAX, + String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), + "another argument", + ) +} diff --git a/tests/target/configs/fn_call_layout/vertical.rs b/tests/target/configs/fn_call_layout/vertical.rs new file mode 100644 index 00000000000..4c97b7be24b --- /dev/null +++ b/tests/target/configs/fn_call_layout/vertical.rs @@ -0,0 +1,119 @@ +// rustfmt-fn_call_layout:Vertical + +fn main() { + empty_args(); + single_arg(ipsum); + two_args( + ipsum, + dolor, + ); + + lorem( + ipsum, + dolor, + sit, + amet, + ); + lorem( + ipsum, // some inine comment + dolor, + sit, + amet, + ); + lorem( + ipsum, /* some inine comment */ + dolor, + sit, + amet, + ); + ipsum( + dolor, + sit, + amet, + consectetur, + adipiscing, + elit, + vivamus, + ipsum, + orci, + rhoncus, + vel, + imperdiet, + ); + + // issue 2010 + let a = i8x32::new( + 0, + 1, + -1, + 2, + -2, + 3, + -3, + 4, + -4, + 5, + -5, + std::i8::MAX, + std::i8::MIN + 1, + 100, + -100, + -32, + 0, + 1, + -1, + 2, + -2, + 3, + -3, + 4, + -4, + 5, + -5, + std::i8::MAX, + std::i8::MIN + 1, + 100, + -100, + -32, + ); + + // issue 4146 + return_monitor_err( + e, + channel_state, + chan, + order, + commitment_update.is_some(), + revoke_and_ack.is_some(), + ); + + // other examples with more complex args + more_complex_args( + |a, b, c| { + if a == 998765390 { + -b * 3 + } else { + c + } + }, + std::ops::Range { start: 3, end: 5 }, + std::i8::MAX, + String::from(" hello world!!").as_bytes(), + thread::Builder::new() + .name("thread1".to_string()) + .spawn(move || { + use std::sync::Arc; + + let mut values = Arc::<[u32]>::new_uninit_slice(3); + + // Deferred initialization: + let data = Arc::get_mut(&mut values).unwrap(); + data[0].write(1); + data[1].write(2); + data[2].write(3); + + let values = unsafe { values.assume_init() }; + }), + "another argument", + ) +}