Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions crates/config/src/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ pub struct FormatterConfig {
pub prefer_compact: PreferCompact,
/// Keep single imports on a single line even if they exceed line length.
pub single_line_imports: bool,
/// Style of condition formatting in if statements
pub format_conditions: ConditionFormatStyle,
}

/// Style of integer types.
Expand Down Expand Up @@ -223,6 +225,17 @@ impl PreferCompact {
}
}

/// Style of condition formatting in if statements
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ConditionFormatStyle {
/// Inline all conditions on a single line
#[default]
Inline,
/// Place each condition on a separate line
Multi,
}

/// Style of indent
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
Expand Down Expand Up @@ -254,6 +267,7 @@ impl Default for FormatterConfig {
prefer_compact: PreferCompact::default(),
docs_style: DocCommentStyle::default(),
single_line_imports: false,
format_conditions: ConditionFormatStyle::default(),
}
}
}
3 changes: 3 additions & 0 deletions crates/fmt/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ pub(super) struct State<'sess, 'ast> {
emit_or_revert: bool,
// Whether inside a variable initialization expression, or not.
var_init: bool,
// Whether inside an if condition expression, or not.
in_if_condition: bool,
}

impl std::ops::Deref for State<'_, '_> {
Expand Down Expand Up @@ -226,6 +228,7 @@ impl<'sess> State<'sess, '_> {
return_bin_expr: false,
emit_or_revert: false,
var_init: false,
in_if_condition: false,
block_depth: 0,
call_stack: CallStack::default(),
}
Expand Down
48 changes: 45 additions & 3 deletions crates/fmt/src/state/sol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1424,6 +1424,11 @@ impl<'ast> State<'_, 'ast> {
let prev_chain = self.binary_expr;
let is_chain = prev_chain.is_some_and(|prev| prev == bin_op.kind.group());

// Check if we should use multi-line formatting for if conditions
let use_multi_line_conditions = self.in_if_condition
&& matches!(self.config.format_conditions, config::ConditionFormatStyle::Multi)
&& matches!(bin_op.kind.group(), BinOpGroup::Logical);

// Opening box if starting a new operator chain.
if !is_chain {
self.binary_expr = Some(bin_op.kind.group());
Expand All @@ -1437,7 +1442,21 @@ impl<'ast> State<'_, 'ast> {
} else {
self.ind
};
self.s.ibox(indent);
// Use consistent box for multi-line condition formatting to ensure all breaks happen
// together
if use_multi_line_conditions {
self.s.cbox(indent);
} else {
self.s.ibox(indent);
}
}

// For multi-line condition formatting, break before the operator (except the first one)
if use_multi_line_conditions && is_chain {
// Break before the operator to start each condition on its own line
if !self.is_bol_or_only_ind() {
self.hardbreak();
}
}

// Print LHS.
Expand Down Expand Up @@ -1469,7 +1488,14 @@ impl<'ast> State<'_, 'ast> {

self.word(bin_op.kind.to_str());

if !self.config.pow_no_space || !matches!(bin_op.kind, ast::BinOpKind::Pow) {
// For multi-line condition formatting, break after logical operators in if conditions
if use_multi_line_conditions {
// Force a hard break after logical operators in multi-line mode
if !self.is_bol_or_only_ind() {
self.hardbreak();
}
self.s.offset(self.ind);
} else if !self.config.pow_no_space || !matches!(bin_op.kind, ast::BinOpKind::Pow) {
self.nbsp();
}
}
Expand Down Expand Up @@ -2301,14 +2327,30 @@ impl<'ast> State<'_, 'ast> {
fn print_if_cond(&mut self, kw: &'static str, cond: &'ast ast::Expr<'ast>, pos_hi: BytePos) {
self.print_word(kw);
self.print_sep_unhandled(Separator::Nbsp);

// Set flag for if condition formatting
let was_in_if_condition = self.in_if_condition;
self.in_if_condition = true;

// Choose ListFormat based on config
let list_format =
if matches!(self.config.format_conditions, config::ConditionFormatStyle::Multi) {
ListFormat::consistent().break_cmnts().break_single(true)
} else {
ListFormat::compact().break_cmnts().break_single(is_binary_expr(&cond.kind))
};

self.print_tuple(
std::slice::from_ref(cond),
cond.span.lo(),
pos_hi,
Self::print_expr,
get_span!(),
ListFormat::compact().break_cmnts().break_single(is_binary_expr(&cond.kind)),
list_format,
);

// Reset flag
self.in_if_condition = was_in_if_condition;
}

fn print_emit_or_revert(
Expand Down
4 changes: 3 additions & 1 deletion crates/forge/tests/cli/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ sort_imports = false
pow_no_space = false
prefer_compact = "all"
single_line_imports = false
format_conditions = "inline"

[lint]
severity = []
Expand Down Expand Up @@ -1332,7 +1333,8 @@ forgetest_init!(test_default_config, |prj, cmd| {
"sort_imports": false,
"pow_no_space": false,
"prefer_compact": "all",
"single_line_imports": false
"single_line_imports": false,
"format_conditions": "inline"
},
"lint": {
"severity": [],
Expand Down