diff --git a/src/chains.rs b/src/chains.rs index 4eaf0f5acb5..4556946649a 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -20,61 +20,58 @@ // argument function argument strategy. use rewrite::{Rewrite, RewriteContext}; -use utils::{make_indent, extra_offset}; +use utils::make_indent; use expr::rewrite_call; use syntax::{ast, ptr}; use syntax::codemap::{mk_sp, Span}; use syntax::print::pprust; -pub fn rewrite_chain(orig_expr: &ast::Expr, +pub fn rewrite_chain(mut expr: &ast::Expr, context: &RewriteContext, width: usize, offset: usize) -> Option { - let mut expr = orig_expr; - let mut rewrites = Vec::new(); - let indent = offset + context.config.tab_spaces; - let max_width = try_opt!(context.config.max_width.checked_sub(indent)); + let total_span = expr.span; + let mut subexpr_list = vec![expr]; - while let Some(pair) = pop_expr_chain(expr, orig_expr.span, context, max_width, indent) { - let (rewrite, parent_expr) = pair; - - rewrites.push(try_opt!(rewrite)); - expr = parent_expr; + while let Some(subexpr) = pop_expr_chain(expr) { + subexpr_list.push(subexpr); + expr = subexpr; } + let parent = subexpr_list.pop().unwrap(); let parent_rewrite = try_opt!(expr.rewrite(context, width, offset)); + let (extra_indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(parent) || + parent_rewrite.len() <= context.config.tab_spaces { + (parent_rewrite.len(), true) + } else { + (context.config.tab_spaces, false) + }; + let indent = offset + extra_indent; + + let max_width = try_opt!(width.checked_sub(extra_indent)); + let rewrites = try_opt!(subexpr_list.into_iter() + .rev() + .map(|e| { + rewrite_chain_expr(e, + total_span, + context, + max_width, + indent) + }) + .collect::>>()); + let total_width = rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len(); let fits_single_line = total_width <= width && rewrites.iter().all(|s| !s.contains('\n')); - if rewrites.len() == 1 && !fits_single_line && - (is_continuable(expr) || parent_rewrite.len() <= context.config.tab_spaces) { - let extra_offset = extra_offset(&parent_rewrite, offset); - let offset = offset + extra_offset; - let max_width = try_opt!(width.checked_sub(extra_offset)); - - let rerewrite = pop_expr_chain(orig_expr, orig_expr.span, context, max_width, offset) - .unwrap() - .0; - - return Some(format!("{}{}", parent_rewrite, try_opt!(rerewrite))); - } - let connector = if fits_single_line { String::new() } else { format!("\n{}", make_indent(indent)) }; - // FIXME: don't do this. There's a more efficient way. VecDeque? - rewrites.reverse(); - - // Put the first link on the same line as parent, if it fits. - let first_connector = if parent_rewrite.len() + rewrites[0].len() <= width && - is_continuable(expr) && - !rewrites[0].contains('\n') || - parent_rewrite.len() <= context.config.tab_spaces { + let first_connector = if extend { "" } else { &connector[..] @@ -83,32 +80,36 @@ pub fn rewrite_chain(orig_expr: &ast::Expr, Some(format!("{}{}{}", parent_rewrite, first_connector, rewrites.join(&connector))) } -// Returns None when the expression is not a chainable. Otherwise, rewrites the -// outermost chain element and returns the remaining chain. -fn pop_expr_chain<'a>(expr: &'a ast::Expr, +fn pop_expr_chain<'a>(expr: &'a ast::Expr) -> Option<&'a ast::Expr> { + match expr.node { + ast::Expr_::ExprMethodCall(_, _, ref expressions) => { + Some(&expressions[0]) + } + ast::Expr_::ExprTupField(ref subexpr, _) | + ast::Expr_::ExprField(ref subexpr, _) => { + Some(subexpr) + } + _ => None, + } +} + +fn rewrite_chain_expr(expr: &ast::Expr, span: Span, context: &RewriteContext, width: usize, offset: usize) - -> Option<(Option, &'a ast::Expr)> { + -> Option { match expr.node { ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => { - Some((rewrite_method_call(method_name.node, - types, - expressions, - span, - context, - width, - offset), - &expressions[0])) + rewrite_method_call(method_name.node, types, expressions, span, context, width, offset) } - ast::Expr_::ExprField(ref subexpr, ref field) => { - Some((Some(format!(".{}", field.node)), subexpr)) + ast::Expr_::ExprField(_, ref field) => { + Some(format!(".{}", field.node)) } - ast::Expr_::ExprTupField(ref subexpr, ref field) => { - Some((Some(format!(".{}", field.node)), subexpr)) + ast::Expr_::ExprTupField(_, ref field) => { + Some(format!(".{}", field.node)) } - _ => None, + _ => unreachable!(), } } diff --git a/src/expr.rs b/src/expr.rs index 69fea0e5927..986b5d50a1f 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1017,8 +1017,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, }; let field_iter = fields.into_iter() - .map(StructLitField::Regular) - .chain(base.into_iter().map(StructLitField::Base)); + .map(StructLitField::Regular) + .chain(base.into_iter().map(StructLitField::Base)); let inner_context = &RewriteContext { block_indent: indent, ..*context }; @@ -1030,8 +1030,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, StructLitField::Regular(ref field) => field.span.lo, StructLitField::Base(ref expr) => { let last_field_hi = fields.last() - .map_or(span.lo, - |field| field.span.hi); + .map_or(span.lo, + |field| field.span.hi); let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo)); let pos = snippet.find_uncommented("..").unwrap(); @@ -1104,8 +1104,8 @@ fn rewrite_field(context: &RewriteContext, -> Option { let name = &field.ident.node.to_string(); let overhead = name.len() + 2; - let expr = - field.expr.rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead); + let expr = field.expr + .rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead); expr.map(|s| format!("{}: {}", name, s)) } diff --git a/src/items.rs b/src/items.rs index ef8ad37b126..a2e562d9d26 100644 --- a/src/items.rs +++ b/src/items.rs @@ -332,13 +332,14 @@ impl<'a> FmtVisitor<'a> { // Account for sugary self. // FIXME: the comment for the self argument is dropped. This is blocked // on rust issue #27522. - let min_args = explicit_self - .and_then(|explicit_self| rewrite_explicit_self(explicit_self, args)) - .map(|self_str| { - arg_item_strs[0] = self_str; - 2 - }) - .unwrap_or(1); + let min_args = explicit_self.and_then(|explicit_self| { + rewrite_explicit_self(explicit_self, args) + }) + .map(|self_str| { + arg_item_strs[0] = self_str; + 2 + }) + .unwrap_or(1); // Comments between args let mut arg_items = Vec::new(); @@ -761,9 +762,11 @@ impl<'a> FmtVisitor<'a> { let indent = self.block_indent + self.config.tab_spaces; let mut attr_str = field.node - .attrs - .rewrite(&self.get_context(), self.config.max_width - indent, indent) - .unwrap(); + .attrs + .rewrite(&self.get_context(), + self.config.max_width - indent, + indent) + .unwrap(); if !attr_str.is_empty() { attr_str.push('\n'); attr_str.push_str(&make_indent(indent)); @@ -804,18 +807,18 @@ impl<'a> FmtVisitor<'a> { // FIXME: don't unwrap let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset).unwrap()); let ty_strs = tys.iter() - .map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap()); + .map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap()); // Extract comments between generics. let lt_spans = lifetimes.iter() - .map(|l| { - let hi = if l.bounds.is_empty() { - l.lifetime.span.hi - } else { - l.bounds[l.bounds.len() - 1].span.hi - }; - codemap::mk_sp(l.lifetime.span.lo, hi) - }); + .map(|l| { + let hi = if l.bounds.is_empty() { + l.lifetime.span.hi + } else { + l.bounds[l.bounds.len() - 1].span.hi + }; + codemap::mk_sp(l.lifetime.span.lo, hi) + }); let ty_spans = tys.iter().map(span_for_ty_param); let items = itemize_list(self.codemap, diff --git a/src/types.rs b/src/types.rs index 9f3cc17e4c7..83e92ff314b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -279,22 +279,24 @@ impl Rewrite for ast::WherePredicate { .. }) => { if !bound_lifetimes.is_empty() { let lifetime_str = bound_lifetimes.iter() - .map(|lt| lt.rewrite(context, width, offset).unwrap()) - .collect::>() - .join(", "); + .map(|lt| { + lt.rewrite(context, width, offset) + .unwrap() + }) + .collect::>() + .join(", "); let type_str = pprust::ty_to_string(bounded_ty); // 8 = "for<> : ".len() let used_width = lifetime_str.len() + type_str.len() + 8; let bounds_str = bounds.iter() - .map(|ty_bound| { - ty_bound - .rewrite(context, - width - used_width, - offset + used_width) - .unwrap() - }) - .collect::>() - .join(" + "); + .map(|ty_bound| { + ty_bound.rewrite(context, + width - used_width, + offset + used_width) + .unwrap() + }) + .collect::>() + .join(" + "); format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str) } else { @@ -302,15 +304,14 @@ impl Rewrite for ast::WherePredicate { // 2 = ": ".len() let used_width = type_str.len() + 2; let bounds_str = bounds.iter() - .map(|ty_bound| { - ty_bound - .rewrite(context, - width - used_width, - offset + used_width) - .unwrap() - }) - .collect::>() - .join(" + "); + .map(|ty_bound| { + ty_bound.rewrite(context, + width - used_width, + offset + used_width) + .unwrap() + }) + .collect::>() + .join(" + "); format!("{}: {}", type_str, bounds_str) } diff --git a/src/utils.rs b/src/utils.rs index faa953ebea3..cb1dd718375 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -95,15 +95,15 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool { #[inline] pub fn end_typaram(typaram: &ast::TyParam) -> BytePos { typaram.bounds - .last() - .map(|bound| { - match *bound { - ast::RegionTyParamBound(ref lt) => lt.span, - ast::TraitTyParamBound(ref prt, _) => prt.span, - } - }) - .unwrap_or(typaram.span) - .hi + .last() + .map(|bound| { + match *bound { + ast::RegionTyParamBound(ref lt) => lt.span, + ast::TraitTyParamBound(ref prt, _) => prt.span, + } + }) + .unwrap_or(typaram.span) + .hi } #[inline] diff --git a/src/visitor.rs b/src/visitor.rs index 1159116b010..54ada1b7455 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -288,11 +288,10 @@ impl<'a> FmtVisitor<'a> { if utils::contains_skip(attrs) { true } else { - let rewrite = attrs - .rewrite(&self.get_context(), - self.config.max_width - self.block_indent, - self.block_indent) - .unwrap(); + let rewrite = attrs.rewrite(&self.get_context(), + self.config.max_width - self.block_indent, + self.block_indent) + .unwrap(); self.buffer.push_str(&rewrite); let last = attrs.last().unwrap(); self.last_pos = last.span.hi; diff --git a/tests/system.rs b/tests/system.rs index ea98d94f412..4db15dbcfd1 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -162,17 +162,17 @@ fn read_significant_comments(file_name: &str) -> HashMap { .expect("Failed creating pattern 2."); reader.lines() - .map(|line| line.ok().expect("Failed getting line.")) - .take_while(|line| line_regex.is_match(&line)) - .filter_map(|line| { - regex.captures_iter(&line) - .next() - .map(|capture| { - (capture.at(1).expect("Couldn\'t unwrap capture.").to_owned(), - capture.at(2).expect("Couldn\'t unwrap capture.").to_owned()) - }) - }) - .collect() + .map(|line| line.ok().expect("Failed getting line.")) + .take_while(|line| line_regex.is_match(&line)) + .filter_map(|line| { + regex.captures_iter(&line) + .next() + .map(|capture| { + (capture.at(1).expect("Couldn\'t unwrap capture.").to_owned(), + capture.at(2).expect("Couldn\'t unwrap capture.").to_owned()) + }) + }) + .collect() } // Compare output to input. diff --git a/tests/target/chains.rs b/tests/target/chains.rs index daa60d09855..282dc58b492 100644 --- a/tests/target/chains.rs +++ b/tests/target/chains.rs @@ -6,8 +6,8 @@ fn main() { bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddd(); bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc - .ddddddddddddddddddddddddddd - .eeeeeeee(); + .ddddddddddddddddddddddddddd + .eeeeeeee(); x().y(|| { match cond() { @@ -34,13 +34,13 @@ fn main() { }); let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5) - .map(|x| x / 2) - .fold(0, |acc, x| acc + x); + .map(|x| x / 2) + .fold(0, + |acc, x| acc + x); - aaaaaaaaaaaaaaaa - .map(|x| { - x += 1; - x - }) - .filter(some_mod::some_filter) + aaaaaaaaaaaaaaaa.map(|x| { + x += 1; + x + }) + .filter(some_mod::some_filter) }