Avoid trial and error in rewrite_chain whenever possible
This commit is contained in:
parent
7268a50e36
commit
04a6d16c7b
1 changed files with 48 additions and 154 deletions
198
src/chains.rs
198
src/chains.rs
|
@ -105,7 +105,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
let parent_shape = if is_block_expr(context, &parent, "\n") {
|
let parent_shape = if is_block_expr(context, &parent, "\n") {
|
||||||
match context.config.chain_indent() {
|
match context.config.chain_indent() {
|
||||||
IndentStyle::Visual => shape.visual_indent(0),
|
IndentStyle::Visual => shape.visual_indent(0),
|
||||||
IndentStyle::Block => shape.block(),
|
IndentStyle::Block => shape,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shape
|
shape
|
||||||
|
@ -133,13 +133,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
// brace.
|
// brace.
|
||||||
IndentStyle::Visual => (parent_shape, false),
|
IndentStyle::Visual => (parent_shape, false),
|
||||||
}
|
}
|
||||||
} else if parent_rewrite_contains_newline {
|
|
||||||
(chain_indent(context, parent_shape), false)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
shape
|
chain_indent(context, shape.add_offset(parent_rewrite.len())),
|
||||||
.block_indent(context.config.tab_spaces())
|
|
||||||
.with_max_width(context.config),
|
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -166,8 +162,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.chain(iter::repeat(other_child_shape));
|
.chain(iter::repeat(other_child_shape));
|
||||||
let subexpr_num = subexpr_list.len();
|
let subexpr_num = subexpr_list.len();
|
||||||
|
let last_subexpr = &subexpr_list[suffix_try_num];
|
||||||
let subexpr_list = &subexpr_list[suffix_try_num..subexpr_num - prefix_try_num];
|
let subexpr_list = &subexpr_list[suffix_try_num..subexpr_num - prefix_try_num];
|
||||||
let iter = subexpr_list.iter().rev().zip(child_shape_iter);
|
let iter = subexpr_list.iter().skip(1).rev().zip(child_shape_iter);
|
||||||
let mut rewrites = try_opt!(
|
let mut rewrites = try_opt!(
|
||||||
iter.map(|(e, shape)| {
|
iter.map(|(e, shape)| {
|
||||||
rewrite_chain_subexpr(e, total_span, context, shape)
|
rewrite_chain_subexpr(e, total_span, context, shape)
|
||||||
|
@ -175,85 +172,46 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
);
|
);
|
||||||
|
|
||||||
// Total of all items excluding the last.
|
// Total of all items excluding the last.
|
||||||
let rewrites_len = rewrites.len();
|
let extend_last_subexr = last_line_extendable(&parent_rewrite) && rewrites.is_empty();
|
||||||
let almost_total = rewrites[0..(rewrites_len - 1)]
|
let almost_total = if extend_last_subexr {
|
||||||
.iter()
|
last_line_width(&parent_rewrite)
|
||||||
.fold(0, |a, b| a + first_line_width(b)) + parent_rewrite.len();
|
|
||||||
let one_line_len =
|
|
||||||
rewrites.iter().fold(0, |a, r| a + first_line_width(r)) + parent_rewrite.len();
|
|
||||||
|
|
||||||
let one_line_budget = min(shape.width, context.config.chain_one_line_max());
|
|
||||||
let veto_single_line = if one_line_len > one_line_budget {
|
|
||||||
if rewrites.len() > 1 {
|
|
||||||
true
|
|
||||||
} else if rewrites.len() == 1 {
|
|
||||||
context.config.chain_split_single_child() || one_line_len > shape.width
|
|
||||||
} else {
|
} else {
|
||||||
false
|
rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len()
|
||||||
}
|
|
||||||
} else if context.config.take_source_hints() && rewrites.len() > 1 {
|
|
||||||
// Look at the source code. Unless all chain elements start on the same
|
|
||||||
// line, we won't consider putting them on a single line either.
|
|
||||||
let last_span = context.snippet(mk_sp(subexpr_list[1].span.hi, total_span.hi));
|
|
||||||
let first_span = context.snippet(subexpr_list[1].span);
|
|
||||||
let last_iter = last_span.chars().take_while(|c| c.is_whitespace());
|
|
||||||
|
|
||||||
first_span.chars().chain(last_iter).any(|c| c == '\n')
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
};
|
||||||
|
let one_line_budget = if rewrites.is_empty() && !context.config.chain_split_single_child() {
|
||||||
let mut fits_single_line = !veto_single_line && almost_total <= shape.width;
|
shape.width
|
||||||
if fits_single_line {
|
|
||||||
let len = rewrites.len();
|
|
||||||
let (init, last) = rewrites.split_at_mut(len - 1);
|
|
||||||
fits_single_line = init.iter().all(|s| !s.contains('\n'));
|
|
||||||
|
|
||||||
if fits_single_line {
|
|
||||||
fits_single_line = match expr.node {
|
|
||||||
ref e @ ast::ExprKind::MethodCall(..) => {
|
|
||||||
if rewrite_method_call_with_overflow(
|
|
||||||
e,
|
|
||||||
&mut last[0],
|
|
||||||
almost_total,
|
|
||||||
total_span,
|
|
||||||
context,
|
|
||||||
shape,
|
|
||||||
) {
|
|
||||||
// If the first line of the last method does not fit into a single line
|
|
||||||
// after the others, allow new lines.
|
|
||||||
almost_total + first_line_width(&last[0]) < context.config.max_width()
|
|
||||||
} else {
|
} else {
|
||||||
false
|
min(shape.width, context.config.chain_one_line_max())
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => !last[0].contains('\n'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try overflowing the last element if we are using block indent and it goes multi line
|
|
||||||
// or it fits in a single line but goes over the max width.
|
|
||||||
if !fits_single_line && context.use_block_indent() {
|
|
||||||
let last_expr_index = rewrites.len() - 1;
|
|
||||||
let (init, last) = rewrites.split_at_mut(last_expr_index);
|
|
||||||
let almost_single_line = init.iter().all(|s| !s.contains('\n'));
|
|
||||||
if almost_single_line && last[0].contains('\n') {
|
|
||||||
let overflow_shape = Shape {
|
|
||||||
width: one_line_budget,
|
|
||||||
..parent_shape
|
|
||||||
};
|
};
|
||||||
fits_single_line = rewrite_last_child_with_overflow(
|
let all_in_one_line = !parent_rewrite_contains_newline &&
|
||||||
context,
|
rewrites.iter().all(|s| !s.contains('\n')) &&
|
||||||
&subexpr_list[0],
|
almost_total < one_line_budget;
|
||||||
overflow_shape,
|
let rewrite_last = || rewrite_chain_subexpr(last_subexpr, total_span, context, nested_shape);
|
||||||
total_span,
|
let (last_subexpr_str, fits_single_line) = try_opt!(if all_in_one_line || extend_last_subexr {
|
||||||
almost_total,
|
parent_shape.offset_left(almost_total).map(|shape| {
|
||||||
one_line_budget,
|
if let Some(rw) = rewrite_chain_subexpr(last_subexpr, total_span, context, shape) {
|
||||||
&mut last[0],
|
let line_count = rw.lines().count();
|
||||||
);
|
let fits_single_line = almost_total + first_line_width(&rw) <= one_line_budget;
|
||||||
|
if (line_count >= 5 && fits_single_line) || extend_last_subexr {
|
||||||
|
(Some(rw), true)
|
||||||
|
} else {
|
||||||
|
match rewrite_last() {
|
||||||
|
Some(ref new_rw) if !fits_single_line => (Some(new_rw.clone()), false),
|
||||||
|
Some(ref new_rw) if new_rw.lines().count() >= line_count => {
|
||||||
|
(Some(rw), fits_single_line)
|
||||||
|
}
|
||||||
|
new_rw @ Some(..) => (new_rw, false),
|
||||||
|
_ => (Some(rw), fits_single_line),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
(rewrite_last(), false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Some((rewrite_last(), false))
|
||||||
|
});
|
||||||
|
rewrites.push(try_opt!(last_subexpr_str));
|
||||||
|
|
||||||
let connector = if fits_single_line && !parent_rewrite_contains_newline {
|
let connector = if fits_single_line && !parent_rewrite_contains_newline {
|
||||||
// Yay, we can put everything on one line.
|
// Yay, we can put everything on one line.
|
||||||
|
@ -266,14 +224,14 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
format!("\n{}", nested_shape.indent.to_string(context.config))
|
format!("\n{}", nested_shape.indent.to_string(context.config))
|
||||||
};
|
};
|
||||||
|
|
||||||
let first_connector = choose_first_connector(
|
let first_connector = if is_small_parent || fits_single_line ||
|
||||||
context,
|
last_line_extendable(&parent_rewrite) ||
|
||||||
&parent_rewrite,
|
context.config.chain_indent() == IndentStyle::Visual
|
||||||
&rewrites[0],
|
{
|
||||||
&connector,
|
""
|
||||||
&subexpr_list,
|
} else {
|
||||||
extend,
|
connector.as_str()
|
||||||
);
|
};
|
||||||
|
|
||||||
let result = if is_small_parent && rewrites.len() > 1 {
|
let result = if is_small_parent && rewrites.len() > 1 {
|
||||||
let second_connector = choose_first_connector(
|
let second_connector = choose_first_connector(
|
||||||
|
@ -301,11 +259,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let result = format!("{}{}", result, repeat_try(suffix_try_num));
|
let result = format!("{}{}", result, repeat_try(suffix_try_num));
|
||||||
if context.config.chain_indent() == IndentStyle::Block {
|
|
||||||
Some(result)
|
|
||||||
} else {
|
|
||||||
wrap_str(result, context.config.max_width(), shape)
|
wrap_str(result, context.config.max_width(), shape)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_extendable_parent(context: &RewriteContext, parent_str: &str) -> bool {
|
fn is_extendable_parent(context: &RewriteContext, parent_str: &str) -> bool {
|
||||||
|
@ -323,26 +277,6 @@ fn chain_only_try(exprs: &[ast::Expr]) -> bool {
|
||||||
|
|
||||||
// Try to rewrite and replace the last non-try child. Return `true` if
|
// Try to rewrite and replace the last non-try child. Return `true` if
|
||||||
// replacing succeeds.
|
// replacing succeeds.
|
||||||
fn rewrite_last_child_with_overflow(
|
|
||||||
context: &RewriteContext,
|
|
||||||
expr: &ast::Expr,
|
|
||||||
shape: Shape,
|
|
||||||
span: Span,
|
|
||||||
almost_total: usize,
|
|
||||||
one_line_budget: usize,
|
|
||||||
last_child: &mut String,
|
|
||||||
) -> bool {
|
|
||||||
if let Some(shape) = shape.shrink_left(almost_total) {
|
|
||||||
if let Some(ref mut rw) = rewrite_chain_subexpr(expr, span, context, shape) {
|
|
||||||
if almost_total + first_line_width(rw) <= one_line_budget && rw.lines().count() > 3 {
|
|
||||||
::std::mem::swap(last_child, rw);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn repeat_try(try_count: usize) -> String {
|
fn repeat_try(try_count: usize) -> String {
|
||||||
iter::repeat("?").take(try_count).collect::<String>()
|
iter::repeat("?").take(try_count).collect::<String>()
|
||||||
}
|
}
|
||||||
|
@ -420,46 +354,6 @@ fn chain_indent(context: &RewriteContext, shape: Shape) -> Shape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rewrite_method_call_with_overflow(
|
|
||||||
expr_kind: &ast::ExprKind,
|
|
||||||
last: &mut String,
|
|
||||||
almost_total: usize,
|
|
||||||
total_span: Span,
|
|
||||||
context: &RewriteContext,
|
|
||||||
shape: Shape,
|
|
||||||
) -> bool {
|
|
||||||
if let &ast::ExprKind::MethodCall(ref segment, ref expressions) = expr_kind {
|
|
||||||
let shape = match shape.shrink_left(almost_total) {
|
|
||||||
Some(b) => b,
|
|
||||||
None => return false,
|
|
||||||
};
|
|
||||||
let types = match segment.parameters {
|
|
||||||
Some(ref params) => match **params {
|
|
||||||
ast::PathParameters::AngleBracketed(ref data) => &data.types[..],
|
|
||||||
_ => &[],
|
|
||||||
},
|
|
||||||
_ => &[],
|
|
||||||
};
|
|
||||||
let mut last_rewrite = rewrite_method_call(
|
|
||||||
segment.identifier,
|
|
||||||
types,
|
|
||||||
expressions,
|
|
||||||
total_span,
|
|
||||||
context,
|
|
||||||
shape,
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Some(ref mut s) = last_rewrite {
|
|
||||||
::std::mem::swap(s, last);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the expression's subexpression, if it exists. When the subexpr
|
// Returns the expression's subexpression, if it exists. When the subexpr
|
||||||
// is a try! macro, we'll convert it to shorthand when the option is set.
|
// is a try! macro, we'll convert it to shorthand when the option is set.
|
||||||
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option<ast::Expr> {
|
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option<ast::Expr> {
|
||||||
|
|
Loading…
Reference in a new issue