Implement wrapping rules to force else on a newline in let-else

This commit is contained in:
Yacin Tmimi 2023-02-12 14:50:44 -05:00 committed by Caleb Cartwright
parent 7a3e4fca40
commit 00fef2d51d
4 changed files with 79 additions and 1 deletions

View File

@ -1027,12 +1027,14 @@ fn rewrite_cond(
/// Rewrite the `else` keyword with surrounding comments.
///
/// force_newline_else: whether or not to rewrite the `else` keyword on a newline.
/// is_last: true if this is an `else` and `false` if this is an `else if` block.
/// context: rewrite context
/// span: Span between the end of the last expression and the start of the else block,
/// which contains the `else` keyword
/// shape: Shape
pub(crate) fn rewrite_else_kw_with_comments(
force_newline_else: bool,
is_last: bool,
context: &RewriteContext<'_>,
span: Span,
@ -1048,6 +1050,7 @@ pub(crate) fn rewrite_else_kw_with_comments(
let newline_sep = &shape.indent.to_string_with_newline(context.config);
let before_sep = match context.config.control_brace_style() {
_ if force_newline_else => newline_sep.as_ref(),
ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
newline_sep.as_ref()
}
@ -1132,6 +1135,7 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
};
let else_kw = rewrite_else_kw_with_comments(
false,
last_in_chain,
context,
self.block.span.between(else_block.span),

View File

@ -126,10 +126,14 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
)?;
if let Some(block) = else_block {
let else_kw_span = init.span.between(block.span);
let force_newline_else =
!same_line_else_kw_and_brace(&result, context, else_kw_span, nested_shape);
let else_kw = rewrite_else_kw_with_comments(
force_newline_else,
true,
context,
init.span.between(block.span),
else_kw_span,
shape,
);
result.push_str(&else_kw);
@ -148,6 +152,47 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
}
}
/// When the initializer expression is multi-lined, then the else keyword and opening brace of the
/// block ( i.e. "else {") should be put on the same line as the end of the initializer expression
/// if all the following are true:
///
/// 1. The initializer expression ends with one or more closing parentheses, square brackets,
/// or braces
/// 2. There is nothing else on that line
/// 3. That line is not indented beyond the indent on the first line of the let keyword
fn same_line_else_kw_and_brace(
init_str: &str,
context: &RewriteContext<'_>,
else_kw_span: Span,
init_shape: Shape,
) -> bool {
if !init_str.contains('\n') {
// initializer expression is single lined so the "else {" should be placed on the same line
return true;
}
// 1. The initializer expression ends with one or more `)`, `]`, `}`.
if !init_str.ends_with([')', ']', '}']) {
return false;
}
// 2. There is nothing else on that line
// For example, there are no comments
let else_kw_snippet = context.snippet(else_kw_span).trim();
if else_kw_snippet != "else" {
return false;
}
// 3. The last line of the initializer expression is not indented beyond the `let` keyword
let indent = init_shape.indent.to_string(context.config);
init_str
.lines()
.last()
.expect("initializer expression is multi-lined")
.strip_prefix(indent.as_ref())
.map_or(false, |l| !l.starts_with(char::is_whitespace))
}
// FIXME convert to using rewrite style rather than visitor
// FIXME format modules in this style
#[allow(dead_code)]

View File

@ -7,4 +7,8 @@ fn main() {
// nope
return;
};
let Some(x) = y.foo("abc", fairly_long_identifier, "def", "123456", "string", "cheese") else { bar() };
let Some(x) = abcdef().foo("abc", some_really_really_really_long_ident, "ident", "123456").bar().baz().qux("fffffffffffffffff") else { foo_bar() };
}

View File

@ -9,4 +9,29 @@ fn main() {
// nope
return;
};
let Some(x) = y.foo(
"abc",
fairly_long_identifier,
"def",
"123456",
"string",
"cheese",
) else {
bar()
};
let Some(x) = abcdef()
.foo(
"abc",
some_really_really_really_long_ident,
"ident",
"123456",
)
.bar()
.baz()
.qux("fffffffffffffffff")
else {
foo_bar()
};
}