Merge pull request #1708 from topecongiro/chain-overflow

Allow overflowing the last element of chain if it is originally multi-lined
This commit is contained in:
Nick Cameron 2017-06-18 15:29:52 +12:00 committed by GitHub
commit 2061f101c7
15 changed files with 130 additions and 152 deletions

View file

@ -124,7 +124,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
let first_subexpr_is_try = subexpr_list.last().map_or(false, is_try);
let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
let nested_shape = if first_subexpr_is_try {
parent_shape.block_indent(context.config.tab_spaces())
parent_shape
.block_indent(context.config.tab_spaces())
.with_max_width(context.config)
} else {
chain_indent(context, shape.add_offset(parent_rewrite.len()))
};
@ -143,7 +145,12 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
} else if parent_rewrite_contains_newline {
(chain_indent(context, parent_shape), false)
} else {
(shape.block_indent(context.config.tab_spaces()), false)
(
shape
.block_indent(context.config.tab_spaces())
.with_max_width(context.config),
false,
)
};
let other_child_shape = nested_shape.with_max_width(context.config);
@ -176,10 +183,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
// Total of all items excluding the last.
let last_non_try_index = rewrites.len() - (1 + trailing_try_num);
let almost_total = rewrites[..last_non_try_index].iter().fold(
0,
|a, b| a + first_line_width(b),
) + parent_rewrite.len();
let almost_total = rewrites[..last_non_try_index]
.iter()
.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();
@ -234,11 +240,12 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
}
}
// Try overflowing the last element if we are using block indent.
// 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 (init, last) = rewrites.split_at_mut(last_non_try_index);
let almost_single_line = init.iter().all(|s| !s.contains('\n'));
if almost_single_line {
if almost_single_line && last[0].contains('\n') {
let overflow_shape = Shape {
width: one_line_budget,
..parent_shape

View file

@ -45,10 +45,9 @@ pub enum CommentStyle<'a> {
fn custom_opener(s: &str) -> &str {
s.lines().next().map_or("", |first_line| {
first_line.find(' ').map_or(
first_line,
|space_index| &first_line[0..space_index + 1],
)
first_line
.find(' ')
.map_or(first_line, |space_index| &first_line[0..space_index + 1])
})
}

View file

@ -1077,10 +1077,8 @@ impl<'a> ControlFlow<'a> {
let new_width = try_opt!(new_width.checked_sub(if_str.len()));
let else_expr = &else_node.stmts[0];
let else_str = try_opt!(else_expr.rewrite(
context,
Shape::legacy(new_width, Indent::empty()),
));
let else_str =
try_opt!(else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty())));
if if_str.contains('\n') || else_str.contains('\n') {
return None;
@ -1298,19 +1296,17 @@ impl<'a> Rewrite for ControlFlow<'a> {
let between_kwd_else_block = mk_sp(
self.block.span.hi,
context.codemap.span_before(
mk_sp(self.block.span.hi, else_block.span.lo),
"else",
),
context
.codemap
.span_before(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
);
let between_kwd_else_block_comment =
extract_comment(between_kwd_else_block, context, shape);
let after_else = mk_sp(
context.codemap.span_after(
mk_sp(self.block.span.hi, else_block.span.lo),
"else",
),
context
.codemap
.span_after(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
else_block.span.lo,
);
let after_else_comment = extract_comment(after_else, context, shape);
@ -1328,10 +1324,9 @@ impl<'a> Rewrite for ControlFlow<'a> {
write!(
&mut result,
"{}else{}",
between_kwd_else_block_comment.as_ref().map_or(
between_sep,
|s| &**s,
),
between_kwd_else_block_comment
.as_ref()
.map_or(between_sep, |s| &**s),
after_else_comment.as_ref().map_or(after_sep, |s| &**s)
).ok()
);
@ -1478,10 +1473,9 @@ fn rewrite_match(
let arm_indent_str = arm_shape.indent.to_string(context.config);
let open_brace_pos = context.codemap.span_after(
mk_sp(cond.span.hi, arm_start_pos(&arms[0])),
"{",
);
let open_brace_pos = context
.codemap
.span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{");
for (i, arm) in arms.iter().enumerate() {
// Make sure we get the stuff between arms.
@ -2051,10 +2045,8 @@ where
fn need_block_indent(s: &str, shape: Shape) -> bool {
s.lines().skip(1).any(|s| {
s.find(|c| !char::is_whitespace(c)).map_or(
false,
|w| w + 1 < shape.indent.width(),
)
s.find(|c| !char::is_whitespace(c))
.map_or(false, |w| w + 1 < shape.indent.width())
})
}
@ -2271,10 +2263,8 @@ fn can_be_overflowed<'a, T>(context: &RewriteContext, args: &[&T]) -> bool
where
T: Rewrite + Spanned + ToExpr + 'a,
{
args.last().map_or(
false,
|x| x.can_be_overflowed(context, args.len()),
)
args.last()
.map_or(false, |x| x.can_be_overflowed(context, args.len()))
}
pub fn can_be_overflowed_expr(context: &RewriteContext, expr: &ast::Expr, args_len: usize) -> bool {
@ -2541,10 +2531,9 @@ fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) ->
Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
None => {
let expr_offset = shape.indent.block_indent(context.config);
let expr = field.expr.rewrite(
context,
Shape::indented(expr_offset, context.config),
);
let expr = field
.expr
.rewrite(context, Shape::indented(expr_offset, context.config));
expr.map(|s| {
format!(
"{}{}:\n{}{}",
@ -2729,7 +2718,7 @@ pub fn rewrite_assign_rhs<S: Into<String>>(
0
};
// 1 = space between operator and rhs.
let orig_shape = try_opt!(shape.block_indent(0).offset_left(last_line_width + 1));
let orig_shape = try_opt!(shape.offset_left(last_line_width + 1));
let rhs = match ex.node {
ast::ExprKind::Mac(ref mac) => {
match rewrite_macro(mac, None, context, orig_shape, MacroPosition::Expression) {
@ -2761,9 +2750,7 @@ pub fn rewrite_assign_rhs<S: Into<String>>(
// FIXME: DRY!
match (rhs, new_rhs) {
(Some(ref orig_rhs), Some(ref replacement_rhs))
if count_line_breaks(orig_rhs) > count_line_breaks(replacement_rhs) + 1 ||
(orig_rhs.rewrite(context, shape).is_none() &&
replacement_rhs.rewrite(context, new_shape).is_some()) => {
if count_line_breaks(orig_rhs) > count_line_breaks(replacement_rhs) + 1 => {
result.push_str(&format!("\n{}", new_shape.indent.to_string(context.config)));
result.push_str(replacement_rhs);
}

View file

@ -488,10 +488,12 @@ impl<'a> FmtVisitor<'a> {
let context = self.get_context();
let indent = self.block_indent;
let mut result = try_opt!(field.node.attrs.rewrite(
&context,
Shape::indented(indent, self.config),
));
let mut result = try_opt!(
field
.node
.attrs
.rewrite(&context, Shape::indented(indent, self.config))
);
if !result.is_empty() {
let shape = Shape {
width: context.config.max_width(),
@ -1436,10 +1438,10 @@ impl Rewrite for ast::StructField {
let name = self.ident;
let vis = format_visibility(&self.vis);
let mut attr_str = try_opt!(self.attrs.rewrite(
context,
Shape::indented(shape.indent, context.config),
));
let mut attr_str = try_opt!(
self.attrs
.rewrite(context, Shape::indented(shape.indent, context.config))
);
// Try format missing comments after attributes
let missing_comment = if !self.attrs.is_empty() {
rewrite_missing_comment_on_field(
@ -1470,10 +1472,8 @@ impl Rewrite for ast::StructField {
let type_offset = shape.indent.block_indent(context.config);
let rewrite_type_in_next_line = || {
self.ty.rewrite(
context,
Shape::indented(type_offset, context.config),
)
self.ty
.rewrite(context, Shape::indented(type_offset, context.config))
};
let last_line_width = last_line_width(&result) + type_annotation_spacing.1.len();
@ -1670,10 +1670,10 @@ fn is_empty_infer(context: &RewriteContext, ty: &ast::Ty) -> bool {
impl Rewrite for ast::Arg {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
if is_named_arg(self) {
let mut result = try_opt!(self.pat.rewrite(
context,
Shape::legacy(shape.width, shape.indent),
));
let mut result = try_opt!(
self.pat
.rewrite(context, Shape::legacy(shape.width, shape.indent))
);
if !is_empty_infer(context, &*self.ty) {
if context.config.space_before_type_annotation() {
@ -1872,17 +1872,17 @@ fn rewrite_fn_base(
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
let snuggle_angle_bracket = generics_str.lines().last().map_or(
false,
|l| l.trim_left().len() == 1,
);
let snuggle_angle_bracket = generics_str
.lines()
.last()
.map_or(false, |l| l.trim_left().len() == 1);
// Note that the width and indent don't really matter, we'll re-layout the
// return type later anyway.
let ret_str = try_opt!(fd.output.rewrite(
&context,
Shape::indented(indent, context.config),
));
let ret_str = try_opt!(
fd.output
.rewrite(&context, Shape::indented(indent, context.config))
);
let multi_line_ret_str = ret_str.contains('\n');
let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
@ -1942,10 +1942,10 @@ fn rewrite_fn_base(
}
// A conservative estimation, to goal is to be over all parens in generics
let args_start = generics.ty_params.last().map_or(
span.lo,
|tp| end_typaram(tp),
);
let args_start = generics
.ty_params
.last()
.map_or(span.lo, |tp| end_typaram(tp));
let args_span = mk_sp(
context.codemap.span_after(mk_sp(args_start, span.hi), "("),
span_for_return(&fd.output).lo,
@ -1987,10 +1987,10 @@ fn rewrite_fn_base(
}
// If the last line of args contains comment, we cannot put the closing paren
// on the same line.
if arg_str.lines().last().map_or(
false,
|last_line| last_line.contains("//"),
)
if arg_str
.lines()
.last()
.map_or(false, |last_line| last_line.contains("//"))
{
args_last_line_contains_comment = true;
result.push('\n');
@ -2048,10 +2048,10 @@ fn rewrite_fn_base(
if multi_line_ret_str || ret_should_indent {
// Now that we know the proper indent and width, we need to
// re-layout the return type.
let ret_str = try_opt!(fd.output.rewrite(
context,
Shape::indented(ret_indent, context.config),
));
let ret_str = try_opt!(
fd.output
.rewrite(context, Shape::indented(ret_indent, context.config))
);
result.push_str(&ret_str);
} else {
result.push_str(&ret_str);
@ -2063,14 +2063,12 @@ fn rewrite_fn_base(
let snippet_hi = span.hi;
let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
// Try to preserve the layout of the original snippet.
let original_starts_with_newline = snippet.find(|c| c != ' ').map_or(
false,
|i| snippet[i..].starts_with('\n'),
);
let original_ends_with_newline = snippet.rfind(|c| c != ' ').map_or(
false,
|i| snippet[i..].ends_with('\n'),
);
let original_starts_with_newline = snippet
.find(|c| c != ' ')
.map_or(false, |i| snippet[i..].starts_with('\n'));
let original_ends_with_newline = snippet
.rfind(|c| c != ' ')
.map_or(false, |i| snippet[i..].ends_with('\n'));
let snippet = snippet.trim();
if !snippet.is_empty() {
result.push(if original_starts_with_newline {

View file

@ -125,17 +125,15 @@ pub struct ListItem {
impl ListItem {
pub fn is_multiline(&self) -> bool {
self.item.as_ref().map_or(false, |s| s.contains('\n')) || self.pre_comment.is_some() ||
self.post_comment.as_ref().map_or(
false,
|s| s.contains('\n'),
)
self.post_comment
.as_ref()
.map_or(false, |s| s.contains('\n'))
}
pub fn has_line_pre_comment(&self) -> bool {
self.pre_comment.as_ref().map_or(
false,
|comment| comment.starts_with("//"),
)
self.pre_comment
.as_ref()
.map_or(false, |comment| comment.starts_with("//"))
}
pub fn from_str<S: Into<String>>(s: S) -> ListItem {

View file

@ -219,10 +219,9 @@ pub fn rewrite_macro(
let rewrite = try_opt!(rewrite_array(
expr_vec.iter().map(|x| &**x),
mk_sp(
context.codemap.span_after(
mac.span,
original_style.opener(),
),
context
.codemap
.span_after(mac.span, original_style.opener()),
mac.span.hi - BytePos(1),
),
context,

View file

@ -146,11 +146,9 @@ impl<'a> FmtVisitor<'a> {
let subslice_num_lines = subslice.chars().filter(|c| *c == '\n').count();
if rewrite_next_comment &&
!self.config.file_lines().intersects_range(
file_name,
cur_line,
cur_line + subslice_num_lines,
)
!self.config
.file_lines()
.intersects_range(file_name, cur_line, cur_line + subslice_num_lines)
{
rewrite_next_comment = false;
}

View file

@ -172,10 +172,11 @@ impl<'a> Rewrite for SegmentParam<'a> {
TypeDensity::Compressed => format!("{}=", binding.ident),
};
let budget = try_opt!(shape.width.checked_sub(result.len()));
let rewrite = try_opt!(binding.ty.rewrite(
context,
Shape::legacy(budget, shape.indent + result.len()),
));
let rewrite = try_opt!(
binding
.ty
.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))
);
result.push_str(&rewrite);
Some(result)
}
@ -448,10 +449,9 @@ impl Rewrite for ast::WherePredicate {
// 3 = " = ".len()
let used_width = 3 + lhs_ty_str.len();
let budget = try_opt!(shape.width.checked_sub(used_width));
let rhs_ty_str = try_opt!(rhs_ty.rewrite(
context,
Shape::legacy(budget, shape.indent + used_width),
));
let rhs_ty_str = try_opt!(
rhs_ty.rewrite(context, Shape::legacy(budget, shape.indent + used_width))
);
format!("{} = {}", lhs_ty_str, rhs_ty_str)
}
};
@ -651,10 +651,12 @@ impl Rewrite for ast::Ty {
format!(
"&{}{}",
mut_str,
try_opt!(mt.ty.rewrite(
context,
Shape::legacy(budget, shape.indent + 1 + mut_len),
))
try_opt!(
mt.ty.rewrite(
context,
Shape::legacy(budget, shape.indent + 1 + mut_len),
)
)
)
}
})

View file

@ -317,10 +317,7 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, shape: Shape) -> Option<S
} else {
let mut lines = snippet.lines();
// The caller of this function has already placed `shape.offset`
// characters on the first line.
let first_line_max_len = try_opt!(max_width.checked_sub(shape.indent.width()));
if lines.next().unwrap().len() > first_line_max_len {
if lines.next().unwrap().len() > shape.width {
return None;
}
@ -333,9 +330,7 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, shape: Shape) -> Option<S
// indentation.
// A special check for the last line, since the caller may
// place trailing characters on this line.
if snippet.lines().rev().next().unwrap().len() >
shape.indent.width() + shape.width
{
if snippet.lines().rev().next().unwrap().len() > shape.used_width() + shape.width {
return None;
}
}

View file

@ -290,10 +290,9 @@ impl<'a> FmtVisitor<'a> {
ast::ItemKind::Impl(..) => {
self.format_missing_with_indent(source!(self, item.span).lo);
let snippet = self.get_context().snippet(item.span);
let where_span_end =
snippet
.find_uncommented("{")
.map(|x| (BytePos(x as u32)) + source!(self, item.span).lo);
let where_span_end = snippet
.find_uncommented("{")
.map(|x| (BytePos(x as u32)) + source!(self, item.span).lo);
if let Some(impl_str) = format_impl(
&self.get_context(),
item,

View file

@ -47,10 +47,9 @@ fn main() {
});
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum =
xxxxxxx.map(|x| x + 5).map(|x| x / 2).fold(
0,
|acc, x| acc + x,
);
xxxxxxx.map(|x| x + 5)
.map(|x| x / 2)
.fold(0, |acc, x| acc + x);
aaaaaaaaaaaaaaaa.map(|x| {
x += 1;

View file

@ -18,18 +18,15 @@ fn main() {
));
// chain
let x = yooooooooooooo.fooooooooooooooo.baaaaaaaaaaaaar(
hello,
world,
);
let x = yooooooooooooo
.fooooooooooooooo
.baaaaaaaaaaaaar(hello, world);
// #1380
{
{
let creds = self.client.client_credentials(
&self.config.auth.oauth2.id,
&self.config.auth.oauth2.secret,
)?;
let creds = self.client
.client_credentials(&self.config.auth.oauth2.id, &self.config.auth.oauth2.secret)?;
}
}

View file

@ -4,7 +4,7 @@
// Force format strings
fn main() {
let lorem =
"ipsum dolor sit amet consectetur \
adipiscing elit lorem ipsum dolor sit";
let lorem = "ipsum dolor sit amet \
consectetur adipiscing elit \
lorem ipsum dolor sit";
}

View file

@ -3,7 +3,7 @@
// Force format strings
fn main() {
let lorem =
"ipsum dolor sit amet consectetur \
adipiscing elit lorem ipsum dolor sit";
let lorem = "ipsum dolor sit amet \
consectetur adipiscing elit \
lorem ipsum dolor sit";
}

View file

@ -1,4 +1,4 @@
fn f() {
block_flow.base.stacking_relative_position_of_display_port =
self.base.stacking_relative_position_of_display_port;
block_flow.base.stacking_relative_position_of_display_port = self.base
.stacking_relative_position_of_display_port;
}