Implement single line if-else formatting
This commit is contained in:
parent
eff87a4a66
commit
b7a71250f4
8 changed files with 163 additions and 5 deletions
|
@ -79,4 +79,5 @@ create_config! {
|
||||||
reorder_imports: bool, // Alphabetically, case sensitive.
|
reorder_imports: bool, // Alphabetically, case sensitive.
|
||||||
expr_indent_style: BlockIndentStyle,
|
expr_indent_style: BlockIndentStyle,
|
||||||
closure_indent_style: BlockIndentStyle,
|
closure_indent_style: BlockIndentStyle,
|
||||||
|
single_line_if_else: bool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,3 +15,4 @@ report_fixme = "Never"
|
||||||
reorder_imports = false
|
reorder_imports = false
|
||||||
expr_indent_style = "Tabbed"
|
expr_indent_style = "Tabbed"
|
||||||
closure_indent_style = "Visual"
|
closure_indent_style = "Visual"
|
||||||
|
single_line_if_else = false
|
||||||
|
|
65
src/expr.rs
65
src/expr.rs
|
@ -20,7 +20,7 @@ use types::rewrite_path;
|
||||||
use items::{span_lo_for_arg, span_hi_for_arg, rewrite_fn_input};
|
use items::{span_lo_for_arg, span_hi_for_arg, rewrite_fn_input};
|
||||||
|
|
||||||
use syntax::{ast, ptr};
|
use syntax::{ast, ptr};
|
||||||
use syntax::codemap::{Pos, Span, BytePos, mk_sp};
|
use syntax::codemap::{CodeMap, Pos, Span, BytePos, mk_sp};
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
|
|
||||||
impl Rewrite for ast::Expr {
|
impl Rewrite for ast::Expr {
|
||||||
|
@ -412,7 +412,7 @@ fn rewrite_range(context: &RewriteContext,
|
||||||
fn rewrite_if_else(context: &RewriteContext,
|
fn rewrite_if_else(context: &RewriteContext,
|
||||||
cond: &ast::Expr,
|
cond: &ast::Expr,
|
||||||
if_block: &ast::Block,
|
if_block: &ast::Block,
|
||||||
else_block: Option<&ast::Expr>,
|
else_block_opt: Option<&ast::Expr>,
|
||||||
pat: Option<&ast::Pat>,
|
pat: Option<&ast::Pat>,
|
||||||
width: usize,
|
width: usize,
|
||||||
offset: usize)
|
offset: usize)
|
||||||
|
@ -423,13 +423,22 @@ fn rewrite_if_else(context: &RewriteContext,
|
||||||
cond,
|
cond,
|
||||||
"let ",
|
"let ",
|
||||||
" =",
|
" =",
|
||||||
width - 3 - 2,
|
try_opt!(width.checked_sub(3 + 2)),
|
||||||
offset + 3));
|
offset + 3));
|
||||||
|
|
||||||
|
// Try to format if-else on single line.
|
||||||
|
if context.config.single_line_if_else {
|
||||||
|
let trial = single_line_if_else(context, &pat_expr_string, if_block, else_block_opt, width);
|
||||||
|
|
||||||
|
if trial.is_some() {
|
||||||
|
return trial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
|
let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
|
||||||
let mut result = format!("if {} {}", pat_expr_string, if_block_string);
|
let mut result = format!("if {} {}", pat_expr_string, if_block_string);
|
||||||
|
|
||||||
if let Some(else_block) = else_block {
|
if let Some(else_block) = else_block_opt {
|
||||||
let else_block_string = try_opt!(else_block.rewrite(context, width, offset));
|
let else_block_string = try_opt!(else_block.rewrite(context, width, offset));
|
||||||
|
|
||||||
result.push_str(" else ");
|
result.push_str(" else ");
|
||||||
|
@ -439,6 +448,52 @@ fn rewrite_if_else(context: &RewriteContext,
|
||||||
Some(result)
|
Some(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn single_line_if_else(context: &RewriteContext,
|
||||||
|
pat_expr_str: &str,
|
||||||
|
if_node: &ast::Block,
|
||||||
|
else_block_opt: Option<&ast::Expr>,
|
||||||
|
width: usize)
|
||||||
|
-> Option<String> {
|
||||||
|
let else_block = try_opt!(else_block_opt);
|
||||||
|
let fixed_cost = "if { } else { }".len();
|
||||||
|
|
||||||
|
if let ast::ExprBlock(ref else_node) = else_block.node {
|
||||||
|
if !is_simple_block(if_node, context.codemap) ||
|
||||||
|
!is_simple_block(else_node, context.codemap) || pat_expr_str.contains('\n') {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost));
|
||||||
|
let if_expr = if_node.expr.as_ref().unwrap();
|
||||||
|
let if_str = try_opt!(if_expr.rewrite(context, new_width, 0));
|
||||||
|
|
||||||
|
let new_width = try_opt!(new_width.checked_sub(if_str.len()));
|
||||||
|
let else_expr = else_node.expr.as_ref().unwrap();
|
||||||
|
let else_str = try_opt!(else_expr.rewrite(context, new_width, 0));
|
||||||
|
|
||||||
|
// FIXME: this check shouldn't be necessary. Rewrites should either fail
|
||||||
|
// or wrap to a newline when the object does not fit the width.
|
||||||
|
let fits_line = fixed_cost + pat_expr_str.len() + if_str.len() + else_str.len() <= width;
|
||||||
|
|
||||||
|
if fits_line && !if_str.contains('\n') && !else_str.contains('\n') {
|
||||||
|
return Some(format!("if {} {{ {} }} else {{ {} }}", pat_expr_str, if_str, else_str));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks that a block contains no statements, an expression and no comments.
|
||||||
|
fn is_simple_block(block: &ast::Block, codemap: &CodeMap) -> bool {
|
||||||
|
if !block.stmts.is_empty() || block.expr.is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let snippet = codemap.span_to_snippet(block.span).unwrap();
|
||||||
|
|
||||||
|
!snippet.contains("//") && !snippet.contains("/*")
|
||||||
|
}
|
||||||
|
|
||||||
fn rewrite_match(context: &RewriteContext,
|
fn rewrite_match(context: &RewriteContext,
|
||||||
cond: &ast::Expr,
|
cond: &ast::Expr,
|
||||||
arms: &[ast::Arm],
|
arms: &[ast::Arm],
|
||||||
|
@ -830,7 +885,7 @@ fn rewrite_paren(context: &RewriteContext,
|
||||||
debug!("rewrite_paren, width: {}, offset: {}", width, offset);
|
debug!("rewrite_paren, width: {}, offset: {}", width, offset);
|
||||||
// 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
|
// 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
|
||||||
// paren on the same line as the subexpr.
|
// paren on the same line as the subexpr.
|
||||||
let subexpr_str = subexpr.rewrite(context, width-2, offset+1);
|
let subexpr_str = subexpr.rewrite(context, try_opt!(width.checked_sub(2)), offset + 1);
|
||||||
debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
|
debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
|
||||||
subexpr_str.map(|s| format!("({})", s))
|
subexpr_str.map(|s| format!("({})", s))
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,3 +15,4 @@ report_fixme = "Never"
|
||||||
reorder_imports = false
|
reorder_imports = false
|
||||||
expr_indent_style = "Tabbed"
|
expr_indent_style = "Tabbed"
|
||||||
closure_indent_style = "Visual"
|
closure_indent_style = "Visual"
|
||||||
|
single_line_if_else = false
|
||||||
|
|
|
@ -43,6 +43,8 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
|
||||||
+ 2 + 3 {
|
+ 2 + 3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let test = if true { 5 } else { 3 };
|
||||||
|
|
||||||
if cond() {
|
if cond() {
|
||||||
something();
|
something();
|
||||||
} else if different_cond() {
|
} else if different_cond() {
|
||||||
|
|
46
tests/source/single-line-if-else.rs
Normal file
46
tests/source/single-line-if-else.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// rustfmt-single_line_if_else: true
|
||||||
|
|
||||||
|
// Format if-else expressions on a single line, when possible.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = if 1 > 2 {
|
||||||
|
unreachable!()
|
||||||
|
} else {
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
let a = if x { 1 } else if y { 2 } else { 3 };
|
||||||
|
|
||||||
|
let b = if cond() {
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
// Brief comment.
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
let c = if cond() {
|
||||||
|
statement();
|
||||||
|
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
if cond() { statement(); } else { other_statement(); }
|
||||||
|
|
||||||
|
if true {
|
||||||
|
do_something()
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = if veeeeeeeeery_loooooong_condition() { aaaaaaaaaaaaaaaaaaaaaaaaaaa } else { bbbbbbbbbb };
|
||||||
|
|
||||||
|
let x = if veeeeeeeeery_loooooong_condition() { aaaaaaaaaaaaaaaaaaaaaaaaa } else {
|
||||||
|
bbbbbbbbbb };
|
||||||
|
|
||||||
|
funk(if test() {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
2
|
||||||
|
},
|
||||||
|
arg2);
|
||||||
|
}
|
|
@ -61,6 +61,12 @@ fn foo() -> bool {
|
||||||
1 + 2 + 3 {
|
1 + 2 + 3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let test = if true {
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
3
|
||||||
|
};
|
||||||
|
|
||||||
if cond() {
|
if cond() {
|
||||||
something();
|
something();
|
||||||
} else if different_cond() {
|
} else if different_cond() {
|
||||||
|
|
46
tests/target/single-line-if-else.rs
Normal file
46
tests/target/single-line-if-else.rs
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// rustfmt-single_line_if_else: true
|
||||||
|
|
||||||
|
// Format if-else expressions on a single line, when possible.
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let a = if 1 > 2 { unreachable!() } else { 10 };
|
||||||
|
|
||||||
|
let a = if x {
|
||||||
|
1
|
||||||
|
} else if y { 2 } else { 3 };
|
||||||
|
|
||||||
|
let b = if cond() {
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
// Brief comment.
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
let c = if cond() {
|
||||||
|
statement();
|
||||||
|
|
||||||
|
5
|
||||||
|
} else {
|
||||||
|
10
|
||||||
|
};
|
||||||
|
|
||||||
|
if cond() {
|
||||||
|
statement();
|
||||||
|
} else {
|
||||||
|
other_statement();
|
||||||
|
}
|
||||||
|
|
||||||
|
if true {
|
||||||
|
do_something()
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = if veeeeeeeeery_loooooong_condition() {
|
||||||
|
aaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||||
|
} else {
|
||||||
|
bbbbbbbbbb
|
||||||
|
};
|
||||||
|
|
||||||
|
let x = if veeeeeeeeery_loooooong_condition() { aaaaaaaaaaaaaaaaaaaaaaaaa } else { bbbbbbbbbb };
|
||||||
|
|
||||||
|
funk(if test() { 1 } else { 2 }, arg2);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue