diff --git a/swayfmt/src/formatter/shape.rs b/swayfmt/src/formatter/shape.rs index 743a537aac8..0630c73e851 100644 --- a/swayfmt/src/formatter/shape.rs +++ b/swayfmt/src/formatter/shape.rs @@ -112,6 +112,8 @@ pub(crate) struct CodeLine { pub(crate) expr_kind: ExprKind, /// Used in determining `SameLineWhere` formatting. pub(crate) has_where_clause: bool, + /// Expression is too long to fit in a single line + pub(crate) expr_new_line: bool, } impl CodeLine { @@ -121,6 +123,7 @@ impl CodeLine { line_style, expr_kind, has_where_clause: Default::default(), + expr_new_line: false, } } pub(crate) fn reset_width(&mut self) { @@ -147,6 +150,10 @@ impl CodeLine { pub(crate) fn update_where_clause(&mut self, has_where_clause: bool) { self.has_where_clause = has_where_clause; } + + pub(crate) fn update_expr_new_line(&mut self, expr_new_line: bool) { + self.expr_new_line = expr_new_line; + } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -300,10 +307,9 @@ impl Shape { } /// Create a new `Shape` with default `CodeLine`. pub(crate) fn with_default_code_line(self) -> Self { - Self { - code_line: CodeLine::default(), - ..self - } + let mut code_line = CodeLine::default(); + code_line.update_expr_new_line(self.code_line.expr_new_line); + Self { code_line, ..self } } } diff --git a/swayfmt/src/utils/language/expr/mod.rs b/swayfmt/src/utils/language/expr/mod.rs index 02e2b01a1a5..af23f9f2f2d 100644 --- a/swayfmt/src/utils/language/expr/mod.rs +++ b/swayfmt/src/utils/language/expr/mod.rs @@ -275,8 +275,20 @@ impl Format for Expr { name, } => { target.format(formatted_code, formatter)?; - write!(formatted_code, "{}", dot_token.span().as_str())?; - name.format(formatted_code, formatter)?; + if formatter.shape.code_line.expr_new_line { + formatter.indent(); + write!( + formatted_code, + "\n{}{}", + formatter.indent_to_str()?, + dot_token.span().as_str() + )?; + name.format(formatted_code, formatter)?; + formatter.unindent(); + } else { + write!(formatted_code, "{}", dot_token.span().as_str())?; + name.format(formatted_code, formatter)?; + } } Self::TupleFieldProjection { target, @@ -646,6 +658,13 @@ fn format_method_call( write!(formatted_code, "{}", formatter.indent_to_str()?)?; } target.format(formatted_code, formatter)?; + + if formatter.shape.code_line.expr_new_line { + formatter.indent(); + write!(formatted_code, "\n{}", formatter.indent_to_str()?)?; + formatter.unindent(); + } + write!(formatted_code, "{}", dot_token.span().as_str())?; path_seg.format(formatted_code, formatter)?; if let Some(contract_args) = &contract_args_opt { diff --git a/swayfmt/src/utils/language/statement.rs b/swayfmt/src/utils/language/statement.rs index 224b2684240..39a07c29075 100644 --- a/swayfmt/src/utils/language/statement.rs +++ b/swayfmt/src/utils/language/statement.rs @@ -31,7 +31,16 @@ fn format_statement( expr, semicolon_token_opt, } => { - expr.format(formatted_code, formatter)?; + let mut temp_expr = FormattedCode::new(); + expr.format(&mut temp_expr, formatter)?; + if temp_expr.len() > formatter.config.whitespace.max_width { + formatter.shape.code_line.expr_new_line = true; + // reformat the expression adding a break + expr.format(formatted_code, formatter)?; + formatter.shape.code_line.expr_new_line = false; + } else { + write!(formatted_code, "{}", temp_expr)?; + } if let Some(semicolon) = semicolon_token_opt { if formatter.shape.code_line.line_style == LineStyle::Inline { write!(formatted_code, "{}", semicolon.span().as_str())?; diff --git a/swayfmt/tests/mod.rs b/swayfmt/tests/mod.rs index a1eef88ae1a..37630aaece9 100644 --- a/swayfmt/tests/mod.rs +++ b/swayfmt/tests/mod.rs @@ -1716,3 +1716,51 @@ impl OrdEq for u256 {} "#, ); } + +#[test] +fn chained_methods() { + check( + r#" +library; + +fn test() { + fuelcoin.really_long_field.other_really_long_field.foo().bar().baz.quux().yet_another_call().to_go_above_max_line_length(); +} + "#, + r#"library; + +fn test() { + fuelcoin + .really_long_field + .other_really_long_field + .foo() + .bar() + .baz + .quux() + .yet_another_call() + .to_go_above_max_line_length(); +} +"#, + ); +} + +#[test] +fn comment_in_the_middle() { + check( + r#" + library; + + fn test() { + let number: /* this number is for counting */ u64 = 10; + + + + }"#, + r#"library; + +fn test() { + let number: /* this number is for counting */ u64 = 10; +} +"#, + ); +}