From 428339fdc3c572b0b4a4e86ce1fc2ab048cccac0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 31 Jan 2017 08:28:48 +1300 Subject: [PATCH] Refactor indent and width into Shape struct --- src/chains.rs | 84 +++--- src/comment.rs | 40 +-- src/expr.rs | 663 ++++++++++++++++++++------------------------ src/imports.rs | 31 ++- src/items.rs | 302 ++++++++++---------- src/lib.rs | 44 +++ src/lists.rs | 62 ++--- src/macros.rs | 19 +- src/missed_spans.rs | 5 +- src/patterns.rs | 123 ++++---- src/rewrite.rs | 12 +- src/string.rs | 14 +- src/types.rs | 305 ++++++++++---------- src/utils.rs | 16 +- src/visitor.rs | 30 +- 15 files changed, 865 insertions(+), 885 deletions(-) diff --git a/src/chains.rs b/src/chains.rs index 1220d43356e8..38f6fad1166d 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -81,7 +81,7 @@ /// true, then we allow the last method call to spill over multiple lines without /// forcing the rest of the chain to be split. -use Indent; +use {Indent, Shape}; use rewrite::{Rewrite, RewriteContext}; use utils::{wrap_str, first_line_width}; use expr::rewrite_call; @@ -92,24 +92,20 @@ use std::iter; use syntax::{ast, ptr}; use syntax::codemap::{mk_sp, Span}; -pub fn rewrite_chain(expr: &ast::Expr, - context: &RewriteContext, - width: usize, - offset: Indent) - -> Option { +pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option { let total_span = expr.span; let (parent, subexpr_list) = make_subexpr_list(expr, context); // Bail out if the chain is just try sugar, i.e., an expression followed by // any number of `?`s. if chain_only_try(&subexpr_list) { - return rewrite_try(&parent, subexpr_list.len(), context, width, offset); + return rewrite_try(&parent, subexpr_list.len(), context, shape); } // Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`. - let parent_block_indent = chain_base_indent(context, offset); + let parent_block_indent = chain_base_indent(context, shape.indent); let parent_context = &RewriteContext { block_indent: parent_block_indent, ..*context }; - let parent_rewrite = try_opt!(parent.rewrite(parent_context, width, offset)); + let parent_rewrite = try_opt!(parent.rewrite(parent_context, shape)); // Decide how to layout the rest of the chain. `extend` is true if we can // put the first non-parent item on the same line as the parent. @@ -119,7 +115,7 @@ pub fn rewrite_chain(expr: &ast::Expr, let indent = if let ast::ExprKind::Try(..) = subexpr_list.last().unwrap().node { parent_block_indent.block_indent(context.config) } else { - chain_indent(context, offset + Indent::new(0, parent_rewrite.len())) + chain_indent(context, shape.indent + Indent::new(0, parent_rewrite.len())) }; (indent, true) } else if is_block_expr(&parent, &parent_rewrite) { @@ -129,13 +125,13 @@ pub fn rewrite_chain(expr: &ast::Expr, } else if parent_rewrite.contains('\n') { (chain_indent(context, parent_block_indent.block_indent(context.config)), false) } else { - (chain_indent_newline(context, offset + Indent::new(0, parent_rewrite.len())), false) + (chain_indent_newline(context, shape.indent + Indent::new(0, parent_rewrite.len())), false) }; - let max_width = try_opt!((width + offset.width()).checked_sub(indent.width())); + let max_width = try_opt!((shape.width + shape.indent.width()).checked_sub(indent.width())); let mut rewrites = try_opt!(subexpr_list.iter() .rev() - .map(|e| rewrite_chain_subexpr(e, total_span, context, max_width, indent)) + .map(|e| rewrite_chain_subexpr(e, total_span, context, Shape::legacy(max_width, indent))) .collect::>>()); // Total of all items excluding the last. @@ -156,7 +152,7 @@ pub fn rewrite_chain(expr: &ast::Expr, false }; - let mut fits_single_line = !veto_single_line && total_width <= width; + let mut fits_single_line = !veto_single_line && total_width <= shape.width; if fits_single_line { let len = rewrites.len(); let (init, last) = rewrites.split_at_mut(len - 1); @@ -168,10 +164,9 @@ pub fn rewrite_chain(expr: &ast::Expr, rewrite_method_call_with_overflow(e, &mut last[0], almost_total, - width, total_span, context, - offset) + shape) } _ => !last[0].contains('\n'), } @@ -199,8 +194,7 @@ pub fn rewrite_chain(expr: &ast::Expr, first_connector, join_rewrites(&rewrites, &subexpr_list, &connector)), context.config.max_width, - width, - offset) + shape) } // True if the chain is only `?`s. @@ -215,10 +209,9 @@ fn chain_only_try(exprs: &[ast::Expr]) -> bool { pub fn rewrite_try(expr: &ast::Expr, try_count: usize, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { - let sub_expr = try_opt!(expr.rewrite(context, width - try_count, offset)); + let sub_expr = try_opt!(expr.rewrite(context, shape.sub_width(try_count))); Some(format!("{}{}", sub_expr, iter::repeat("?").take(try_count).collect::())) @@ -305,13 +298,12 @@ fn chain_indent_newline(context: &RewriteContext, _offset: Indent) -> Indent { fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind, last: &mut String, almost_total: usize, - width: usize, total_span: Span, context: &RewriteContext, - offset: Indent) + shape: Shape) -> bool { if let &ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) = expr_kind { - let budget = match width.checked_sub(almost_total) { + let budget = match shape.width.checked_sub(almost_total) { Some(b) => b, None => return false, }; @@ -320,8 +312,8 @@ fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind, expressions, total_span, context, - budget, - offset + almost_total); + Shape::legacy(budget, + shape.indent + almost_total)); if let Some(ref mut s) = last_rewrite { ::std::mem::swap(s, last); @@ -366,29 +358,36 @@ fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr { fn rewrite_chain_subexpr(expr: &ast::Expr, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { match expr.node { ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) => { - let inner = &RewriteContext { block_indent: offset, ..*context }; - rewrite_method_call(method_name.node, - types, - expressions, - span, - inner, - width, - offset) + let inner = &RewriteContext { block_indent: shape.indent, ..*context }; + rewrite_method_call(method_name.node, types, expressions, span, inner, shape) } ast::ExprKind::Field(_, ref field) => { let s = format!(".{}", field.node); - if s.len() <= width { Some(s) } else { None } + if s.len() <= shape.width { + Some(s) + } else { + None + } } ast::ExprKind::TupField(_, ref field) => { let s = format!(".{}", field.node); - if s.len() <= width { Some(s) } else { None } + if s.len() <= shape.width { + Some(s) + } else { + None + } + } + ast::ExprKind::Try(_) => { + if shape.width >= 1 { + Some("?".into()) + } else { + None + } } - ast::ExprKind::Try(_) => if width >= 1 { Some("?".into()) } else { None }, _ => unreachable!(), } } @@ -406,14 +405,13 @@ fn rewrite_method_call(method_name: ast::Ident, args: &[ptr::P], span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let (lo, type_str) = if types.is_empty() { (args[0].span.hi, String::new()) } else { let type_list: Vec<_> = try_opt!(types.iter() - .map(|ty| ty.rewrite(context, width, offset)) + .map(|ty| ty.rewrite(context, shape)) .collect()); let type_str = if context.config.spaces_within_angle_brackets && type_list.len() > 0 { @@ -428,5 +426,5 @@ fn rewrite_method_call(method_name: ast::Ident, let callee_str = format!(".{}{}", method_name, type_str); let span = mk_sp(lo, span.hi); - rewrite_call(context, &callee_str, &args[1..], span, width, offset) + rewrite_call(context, &callee_str, &args[1..], span, shape) } diff --git a/src/comment.rs b/src/comment.rs index 8eaf2b2fb4fd..b7549f10c2de 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -14,7 +14,7 @@ use std::{self, iter}; use syntax::codemap::Span; -use Indent; +use {Indent, Shape}; use config::Config; use rewrite::RewriteContext; use string::{StringFormat, rewrite_string}; @@ -34,8 +34,7 @@ fn is_custom_comment(comment: &str) -> bool { pub fn rewrite_comment(orig: &str, block_style: bool, - width: usize, - offset: Indent, + shape: Shape, config: &Config) -> Option { // If there are lines without a starting sigil, we won't format them correctly @@ -50,7 +49,7 @@ pub fn rewrite_comment(orig: &str, } if !config.normalize_comments && !config.wrap_comments { - return light_rewrite_comment(orig, offset, config); + return light_rewrite_comment(orig, shape.indent, config); } let (opener, closer, line_start) = @@ -85,15 +84,14 @@ pub fn rewrite_comment(orig: &str, ("// ", "", "// ") }; - let max_chars = width.checked_sub(closer.len() + opener.len()).unwrap_or(1); - let indent_str = offset.to_string(config); + let max_chars = shape.width.checked_sub(closer.len() + opener.len()).unwrap_or(1); + let indent_str = shape.indent.to_string(config); let fmt = StringFormat { opener: "", closer: "", line_start: line_start, line_end: "", - width: max_chars, - offset: offset + (opener.len() - line_start.len()), + shape: Shape::legacy(max_chars, shape.indent + (opener.len() - line_start.len())), trim_end: true, config: config, }; @@ -574,14 +572,13 @@ impl<'a> Iterator for CommentCodeSlices<'a> { pub fn recover_comment_removed(new: String, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let snippet = context.snippet(span); if changed_comment_content(&snippet, &new) { // We missed some comments // Keep previous formatting if it satisfies the constrains - wrap_str(snippet, context.config.max_width, width, offset) + wrap_str(snippet, context.config.max_width, shape) } else { Some(new) } @@ -678,7 +675,7 @@ fn remove_comment_header(comment: &str) -> &str { mod test { use super::{CharClasses, CodeCharKind, FullCodeCharKind, contains_comment, rewrite_comment, FindUncommented, CommentCodeSlices}; - use Indent; + use {Indent, Shape}; #[test] fn char_classes() { @@ -735,33 +732,36 @@ mod test { config.wrap_comments = true; config.normalize_comments = true; - let comment = rewrite_comment(" //test", true, 100, Indent::new(0, 100), &config).unwrap(); + let comment = rewrite_comment(" //test", + true, + Shape::legacy(100, Indent::new(0, 100)), + &config).unwrap(); assert_eq!("/* test */", comment); let comment = rewrite_comment("// comment on a", false, - 10, - Indent::empty(), + Shape::legacy(10, Indent::empty()), &config).unwrap(); assert_eq!("// comment\n// on a", comment); let comment = rewrite_comment("// A multi line comment\n // between args.", false, - 60, - Indent::new(0, 12), + Shape::legacy(60, Indent::new(0, 12)), &config).unwrap(); assert_eq!("// A multi line comment\n // between args.", comment); let input = "// comment"; let expected = "/* comment */"; - let comment = rewrite_comment(input, true, 9, Indent::new(0, 69), &config).unwrap(); + let comment = rewrite_comment(input, + true, + Shape::legacy(9, Indent::new(0, 69)), + &config).unwrap(); assert_eq!(expected, comment); let comment = rewrite_comment("/* trimmed */", true, - 100, - Indent::new(0, 100), + Shape::legacy(100, Indent::new(0, 100)), &config).unwrap(); assert_eq!("/* trimmed */", comment); } diff --git a/src/expr.rs b/src/expr.rs index 80937d76da73..ba7c05b65285 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -15,7 +15,7 @@ use std::ops::Deref; use std::iter::ExactSizeIterator; use std::fmt::Write; -use {Indent, Spanned}; +use {Indent, Shape, Spanned}; use codemap::SpanUtils; use rewrite::{Rewrite, RewriteContext}; use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic, @@ -36,8 +36,8 @@ use syntax::codemap::{CodeMap, Span, BytePos, mk_sp}; use syntax::parse::classify; impl Rewrite for ast::Expr { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - format_expr(self, ExprType::SubExpression, context, width, offset) + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + format_expr(self, ExprType::SubExpression, context, shape) } } @@ -50,35 +50,28 @@ enum ExprType { fn format_expr(expr: &ast::Expr, expr_type: ExprType, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let result = match expr.node { ast::ExprKind::Array(ref expr_vec) => { rewrite_array(expr_vec.iter().map(|e| &**e), mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi), context, - width, - offset) + shape) } ast::ExprKind::Lit(ref l) => { match l.node { ast::LitKind::Str(_, ast::StrStyle::Cooked) => { - rewrite_string_lit(context, l.span, width, offset) - } - _ => { - wrap_str(context.snippet(expr.span), - context.config.max_width, - width, - offset) + rewrite_string_lit(context, l.span, shape) } + _ => wrap_str(context.snippet(expr.span), context.config.max_width, shape), } } ast::ExprKind::Call(ref callee, ref args) => { let inner_span = mk_sp(callee.span.hi, expr.span.hi); - rewrite_call(context, &**callee, args, inner_span, width, offset) + rewrite_call(context, &**callee, args, inner_span, shape) } - ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, width, offset), + ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape), ast::ExprKind::Binary(ref op, ref lhs, ref rhs) => { // FIXME: format comments between operands and operator rewrite_pair(&**lhs, @@ -87,43 +80,33 @@ fn format_expr(expr: &ast::Expr, &format!(" {} ", context.snippet(op.span)), "", context, - width, - offset) - } - ast::ExprKind::Unary(ref op, ref subexpr) => { - rewrite_unary_op(context, op, subexpr, width, offset) + shape) } + ast::ExprKind::Unary(ref op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape), ast::ExprKind::Struct(ref path, ref fields, ref base) => { rewrite_struct_lit(context, path, fields, base.as_ref().map(|e| &**e), expr.span, - width, - offset) + shape) } ast::ExprKind::Tup(ref items) => { - rewrite_tuple(context, - items.iter().map(|x| &**x), - expr.span, - width, - offset) + rewrite_tuple(context, items.iter().map(|x| &**x), expr.span, shape) } ast::ExprKind::While(ref cond, ref block, label) => { - ControlFlow::new_while(None, cond, block, label, expr.span) - .rewrite(context, width, offset) + ControlFlow::new_while(None, cond, block, label, expr.span).rewrite(context, shape) } ast::ExprKind::WhileLet(ref pat, ref cond, ref block, label) => { - ControlFlow::new_while(Some(pat), cond, block, label, expr.span) - .rewrite(context, width, offset) + ControlFlow::new_while(Some(pat), cond, block, label, expr.span).rewrite(context, shape) } ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => { - ControlFlow::new_for(pat, cond, block, label, expr.span).rewrite(context, width, offset) + ControlFlow::new_for(pat, cond, block, label, expr.span).rewrite(context, shape) } ast::ExprKind::Loop(ref block, label) => { - ControlFlow::new_loop(block, label, expr.span).rewrite(context, width, offset) + ControlFlow::new_loop(block, label, expr.span).rewrite(context, shape) } - ast::ExprKind::Block(ref block) => block.rewrite(context, width, offset), + ast::ExprKind::Block(ref block) => block.rewrite(context, shape), ast::ExprKind::If(ref cond, ref if_block, ref else_block) => { ControlFlow::new_if(cond, None, @@ -132,7 +115,7 @@ fn format_expr(expr: &ast::Expr, expr_type == ExprType::SubExpression, false, expr.span) - .rewrite(context, width, offset) + .rewrite(context, shape) } ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => { ControlFlow::new_if(cond, @@ -142,24 +125,19 @@ fn format_expr(expr: &ast::Expr, expr_type == ExprType::SubExpression, false, expr.span) - .rewrite(context, width, offset) + .rewrite(context, shape) } ast::ExprKind::Match(ref cond, ref arms) => { - rewrite_match(context, cond, arms, width, offset, expr.span) + rewrite_match(context, cond, arms, shape, expr.span) } ast::ExprKind::Path(ref qself, ref path) => { - rewrite_path(context, - PathContext::Expr, - qself.as_ref(), - path, - width, - offset) + rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape) } ast::ExprKind::Assign(ref lhs, ref rhs) => { - rewrite_assignment(context, lhs, rhs, None, width, offset) + rewrite_assignment(context, lhs, rhs, None, shape) } ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => { - rewrite_assignment(context, lhs, rhs, Some(op), width, offset) + rewrite_assignment(context, lhs, rhs, Some(op), shape) } ast::ExprKind::Continue(ref opt_ident) => { let id_str = match *opt_ident { @@ -168,8 +146,7 @@ fn format_expr(expr: &ast::Expr, }; wrap_str(format!("continue{}", id_str), context.config.max_width, - width, - offset) + shape) } ast::ExprKind::Break(ref opt_ident, ref opt_expr) => { let id_str = match *opt_ident { @@ -178,56 +155,40 @@ fn format_expr(expr: &ast::Expr, }; if let Some(ref expr) = *opt_expr { - rewrite_unary_prefix(context, - &format!("break{} ", id_str), - &**expr, - width, - offset) + rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape) } else { - wrap_str(format!("break{}", id_str), - context.config.max_width, - width, - offset) + wrap_str(format!("break{}", id_str), context.config.max_width, shape) } } ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => { - rewrite_closure(capture, fn_decl, body, expr.span, context, width, offset) + rewrite_closure(capture, fn_decl, body, expr.span, context, shape) } ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::TupField(..) | - ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, width, offset), + ast::ExprKind::MethodCall(..) => rewrite_chain(expr, context, shape), ast::ExprKind::Mac(ref mac) => { // Failure to rewrite a marco should not imply failure to // rewrite the expression. - rewrite_macro(mac, None, context, width, offset, MacroPosition::Expression) - .or_else(|| { - wrap_str(context.snippet(expr.span), - context.config.max_width, - width, - offset) - }) - } - ast::ExprKind::Ret(None) => { - wrap_str("return".to_owned(), context.config.max_width, width, offset) + rewrite_macro(mac, None, context, shape, MacroPosition::Expression) + .or_else(|| wrap_str(context.snippet(expr.span), context.config.max_width, shape)) } + ast::ExprKind::Ret(None) => wrap_str("return".to_owned(), context.config.max_width, shape), ast::ExprKind::Ret(Some(ref expr)) => { - rewrite_unary_prefix(context, "return ", &**expr, width, offset) - } - ast::ExprKind::Box(ref expr) => { - rewrite_unary_prefix(context, "box ", &**expr, width, offset) + rewrite_unary_prefix(context, "return ", &**expr, shape) } + ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape), ast::ExprKind::AddrOf(mutability, ref expr) => { - rewrite_expr_addrof(context, mutability, expr, width, offset) + rewrite_expr_addrof(context, mutability, expr, shape) } ast::ExprKind::Cast(ref expr, ref ty) => { - rewrite_pair(&**expr, &**ty, "", " as ", "", context, width, offset) + rewrite_pair(&**expr, &**ty, "", " as ", "", context, shape) } ast::ExprKind::Type(ref expr, ref ty) => { - rewrite_pair(&**expr, &**ty, "", ": ", "", context, width, offset) + rewrite_pair(&**expr, &**ty, "", ": ", "", context, shape) } ast::ExprKind::Index(ref expr, ref index) => { - rewrite_index(&**expr, &**index, context, width, offset) + rewrite_index(&**expr, &**index, context, shape) } ast::ExprKind::Repeat(ref expr, ref repeats) => { let (lbr, rbr) = if context.config.spaces_within_square_brackets { @@ -235,7 +196,7 @@ fn format_expr(expr: &ast::Expr, } else { ("[", "]") }; - rewrite_pair(&**expr, &**repeats, lbr, "; ", rbr, context, width, offset) + rewrite_pair(&**expr, &**repeats, lbr, "; ", rbr, context, shape) } ast::ExprKind::Range(ref lhs, ref rhs, limits) => { let delim = match limits { @@ -250,7 +211,7 @@ fn format_expr(expr: &ast::Expr, } else { delim.into() }; - rewrite_pair(&**lhs, &**rhs, "", &sp_delim, "", context, width, offset) + rewrite_pair(&**lhs, &**rhs, "", &sp_delim, "", context, shape) } (None, Some(ref rhs)) => { let sp_delim = if context.config.spaces_around_ranges { @@ -258,7 +219,7 @@ fn format_expr(expr: &ast::Expr, } else { delim.into() }; - rewrite_unary_prefix(context, &sp_delim, &**rhs, width, offset) + rewrite_unary_prefix(context, &sp_delim, &**rhs, shape) } (Some(ref lhs), None) => { let sp_delim = if context.config.spaces_around_ranges { @@ -266,22 +227,19 @@ fn format_expr(expr: &ast::Expr, } else { delim.into() }; - rewrite_unary_suffix(context, &sp_delim, &**lhs, width, offset) + rewrite_unary_suffix(context, &sp_delim, &**lhs, shape) } - (None, None) => wrap_str(delim.into(), context.config.max_width, width, offset), + (None, None) => wrap_str(delim.into(), context.config.max_width, shape), } } // We do not format these expressions yet, but they should still // satisfy our width restrictions. ast::ExprKind::InPlace(..) | ast::ExprKind::InlineAsm(..) => { - wrap_str(context.snippet(expr.span), - context.config.max_width, - width, - offset) + wrap_str(context.snippet(expr.span), context.config.max_width, shape) } }; - result.and_then(|res| recover_comment_removed(res, expr.span, context, width, offset)) + result.and_then(|res| recover_comment_removed(res, expr.span, context, shape)) } pub fn rewrite_pair(lhs: &LHS, @@ -290,31 +248,31 @@ pub fn rewrite_pair(lhs: &LHS, infix: &str, suffix: &str, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option where LHS: Rewrite, RHS: Rewrite { - let lhs_budget = try_opt!(width.checked_sub(prefix.len() + infix.len())); - let rhs_budget = try_opt!(width.checked_sub(suffix.len())); + let lhs_budget = try_opt!(shape.width.checked_sub(prefix.len() + infix.len())); + let rhs_budget = try_opt!(shape.width.checked_sub(suffix.len())); // Get "full width" rhs and see if it fits on the current line. This // usually works fairly well since it tends to place operands of // operations with high precendence close together. // Note that this is non-conservative, but its just to see if it's even // worth trying to put everything on one line. - let rhs_result = rhs.rewrite(context, rhs_budget, offset); + let rhs_result = rhs.rewrite(context, Shape::legacy(rhs_budget, shape.indent)); if let Some(rhs_result) = rhs_result { // This is needed in case of line break not caused by a // shortage of space, but by end-of-line comments, for example. if !rhs_result.contains('\n') { - let lhs_result = lhs.rewrite(context, lhs_budget, offset); + let lhs_result = lhs.rewrite(context, Shape::legacy(lhs_budget, shape.indent)); if let Some(lhs_result) = lhs_result { let mut result = format!("{}{}{}", prefix, lhs_result, infix); - let remaining_width = width.checked_sub(last_line_width(&result)).unwrap_or(0); + let remaining_width = + shape.width.checked_sub(last_line_width(&result)).unwrap_or(0); if rhs_result.len() <= remaining_width { result.push_str(&rhs_result); @@ -324,7 +282,9 @@ pub fn rewrite_pair(lhs: &LHS, // Try rewriting the rhs into the remaining space. let rhs_budget = try_opt!(remaining_width.checked_sub(suffix.len())); - if let Some(rhs_result) = rhs.rewrite(context, rhs_budget, offset + result.len()) { + if let Some(rhs_result) = rhs.rewrite(context, + Shape::legacy(rhs_budget, + shape.indent + result.len())) { if rhs_result.len() <= remaining_width { result.push_str(&rhs_result); result.push_str(suffix); @@ -339,13 +299,14 @@ pub fn rewrite_pair(lhs: &LHS, // Re-evaluate the rhs because we have more space now: let infix = infix.trim_right(); - let lhs_budget = - try_opt!(context.config.max_width.checked_sub(offset.width() + prefix.len() + infix.len())); + let lhs_budget = try_opt!(context.config + .max_width + .checked_sub(shape.indent.width() + prefix.len() + infix.len())); let rhs_budget = try_opt!(rhs_budget.checked_sub(prefix.len())); - let rhs_offset = offset + prefix.len(); + let rhs_offset = shape.indent + prefix.len(); - let rhs_result = try_opt!(rhs.rewrite(context, rhs_budget, rhs_offset)); - let lhs_result = try_opt!(lhs.rewrite(context, lhs_budget, offset)); + let rhs_result = try_opt!(rhs.rewrite(context, Shape::legacy(rhs_budget, rhs_offset))); + let lhs_result = try_opt!(lhs.rewrite(context, Shape::legacy(lhs_budget, shape.indent))); Some(format!("{}{}{}\n{}{}{}", prefix, lhs_result, @@ -358,8 +319,7 @@ pub fn rewrite_pair(lhs: &LHS, pub fn rewrite_array<'a, I>(expr_iter: I, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option where I: Iterator { @@ -368,18 +328,19 @@ pub fn rewrite_array<'a, I>(expr_iter: I, } else { 1 // "[" }; - let offset = offset + bracket_size; + let offset = shape.indent + bracket_size; let inner_context = &RewriteContext { block_indent: offset, ..*context }; - let max_item_width = try_opt!(width.checked_sub(bracket_size * 2)); - let items = itemize_list(context.codemap, - expr_iter, - "]", - |item| item.span.lo, - |item| item.span.hi, - |item| item.rewrite(inner_context, max_item_width, offset), - span.lo, - span.hi) - .collect::>(); + let max_item_width = try_opt!(shape.width.checked_sub(bracket_size * 2)); + let items = + itemize_list(context.codemap, + expr_iter, + "]", + |item| item.span.lo, + |item| item.span.hi, + |item| item.rewrite(inner_context, Shape::legacy(max_item_width, offset)), + span.lo, + span.hi) + .collect::>(); let has_long_item = try_opt!(items.iter() .map(|li| li.item.as_ref().map(|s| s.len() > 10)) @@ -395,8 +356,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: offset, - width: max_item_width, + shape: Shape::legacy(max_item_width, offset), ends_with_newline: false, config: context.config, }; @@ -410,7 +370,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I, } // This functions is pretty messy because of the rules around closures and blocks: -// TODO +// FIXME - the below is probably no longer true in full. // * if there is a return type, then there must be braces, // * given a closure with braces, whether that is parsed to give an inner block // or not depends on if there is a return type and if there are statements @@ -423,34 +383,34 @@ fn rewrite_closure(capture: ast::CaptureBy, body: &ast::Expr, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let mover = if capture == ast::CaptureBy::Value { "move " } else { "" }; - let offset = offset + mover.len(); + let offset = shape.indent + mover.len(); // 4 = "|| {".len(), which is overconservative when the closure consists of // a single expression. - let budget = try_opt!(width.checked_sub(4 + mover.len())); + let budget = try_opt!(shape.width.checked_sub(4 + mover.len())); // 1 = | let argument_offset = offset + 1; - let ret_str = try_opt!(fn_decl.output.rewrite(context, budget, argument_offset)); + let ret_str = try_opt!(fn_decl.output.rewrite(context, Shape::legacy(budget, argument_offset))); // 1 = space between arguments and return type. let horizontal_budget = budget.checked_sub(ret_str.len() + 1).unwrap_or(0); - let arg_items = itemize_list(context.codemap, - fn_decl.inputs.iter(), - "|", - |arg| span_lo_for_arg(arg), - |arg| span_hi_for_arg(arg), - |arg| arg.rewrite(context, budget, argument_offset), - context.codemap.span_after(span, "|"), - body.span.lo); + let arg_items = + itemize_list(context.codemap, + fn_decl.inputs.iter(), + "|", + |arg| span_lo_for_arg(arg), + |arg| span_hi_for_arg(arg), + |arg| arg.rewrite(context, Shape::legacy(budget, argument_offset)), + context.codemap.span_after(span, "|"), + body.span.lo); let item_vec = arg_items.collect::>(); let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, horizontal_budget); let budget = match tactic { @@ -462,8 +422,7 @@ fn rewrite_closure(capture: ast::CaptureBy, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: argument_offset, - width: budget, + shape: Shape::legacy(budget, argument_offset), ends_with_newline: false, config: context.config, }; @@ -482,7 +441,7 @@ fn rewrite_closure(capture: ast::CaptureBy, // 1 = space between `|...|` and body. let extra_offset = extra_offset(&prefix, offset) + 1; - let budget = try_opt!(width.checked_sub(extra_offset)); + let budget = try_opt!(shape.width.checked_sub(extra_offset)); let total_offset = offset + extra_offset; if let ast::ExprKind::Block(ref block) = body.node { @@ -502,8 +461,7 @@ fn rewrite_closure(capture: ast::CaptureBy, if let Some(rw) = rewrite_closure_expr(expr, &prefix, context, - budget, - total_offset) { + Shape::legacy(budget, total_offset)) { return Some(rw); } } @@ -513,7 +471,9 @@ fn rewrite_closure(capture: ast::CaptureBy, // We need braces, but we might still prefer a one-liner. let stmt = &block.stmts[0]; // 4 = braces and spaces. - let mut rewrite = stmt.rewrite(context, try_opt!(budget.checked_sub(4)), total_offset); + let mut rewrite = stmt.rewrite(context, + Shape::legacy(try_opt!(budget.checked_sub(4)), + total_offset)); // Checks if rewrite succeeded and fits on a single line. rewrite = and_one_line(rewrite); @@ -527,7 +487,10 @@ fn rewrite_closure(capture: ast::CaptureBy, return rewrite_closure_block(&block, prefix, context, budget); } - if let Some(rw) = rewrite_closure_expr(body, &prefix, context, budget, total_offset) { + if let Some(rw) = rewrite_closure_expr(body, + &prefix, + context, + Shape::legacy(budget, total_offset)) { return Some(rw); } @@ -548,10 +511,9 @@ fn rewrite_closure(capture: ast::CaptureBy, fn rewrite_closure_expr(expr: &ast::Expr, prefix: &str, context: &RewriteContext, - budget: usize, - offset: Indent) + shape: Shape) -> Option { - let mut rewrite = expr.rewrite(context, budget, offset); + let mut rewrite = expr.rewrite(context, shape); if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) { rewrite = and_one_line(rewrite); } @@ -565,7 +527,7 @@ fn rewrite_closure(capture: ast::CaptureBy, -> Option { // Start with visual indent, then fall back to block indent if the // closure is large. - let rewrite = try_opt!(block.rewrite(&context, budget, Indent::empty())); + let rewrite = try_opt!(block.rewrite(&context, Shape::legacy(budget, Indent::empty()))); let block_threshold = context.config.closure_block_indent_threshold; if block_threshold < 0 || rewrite.matches('\n').count() <= block_threshold as usize { @@ -576,7 +538,7 @@ fn rewrite_closure(capture: ast::CaptureBy, // means we must re-format. let mut context = context.clone(); context.block_indent.alignment = 0; - let rewrite = try_opt!(block.rewrite(&context, budget, Indent::empty())); + let rewrite = try_opt!(block.rewrite(&context, Shape::legacy(budget, Indent::empty()))); Some(format!("{} {}", prefix, rewrite)) } } @@ -597,11 +559,12 @@ fn nop_block_collapse(block_str: Option, budget: usize) -> Option Option { - // width is used only for the single line case: either the empty block `{}`, + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + // shape.width is used only for the single line case: either the empty block `{}`, // or an unsafe expression `unsafe { e }`. - if self.stmts.is_empty() && !block_contains_comment(self, context.codemap) && width >= 2 { + if self.stmts.is_empty() && !block_contains_comment(self, context.codemap) && + shape.width >= 2 { return Some("{}".to_owned()); } @@ -611,7 +574,8 @@ impl Rewrite for ast::Block { if user_str.starts_with('{') && user_str.ends_with('}') { let comment_str = user_str[1..user_str.len() - 1].trim(); if self.stmts.is_empty() && !comment_str.contains('\n') && - !comment_str.starts_with("//") && comment_str.len() + 4 <= width { + !comment_str.starts_with("//") && + comment_str.len() + 4 <= shape.width { return Some(format!("{{ {} }}", comment_str)); } } @@ -630,22 +594,23 @@ impl Rewrite for ast::Block { let prefix = if !trimmed.is_empty() { // 9 = "unsafe {".len(), 7 = "unsafe ".len() - let budget = try_opt!(width.checked_sub(9)); + let budget = try_opt!(shape.width.checked_sub(9)); format!("unsafe {} ", try_opt!(rewrite_comment(trimmed, true, - budget, - offset + 7, + Shape::legacy(budget, shape.indent + 7), context.config))) } else { "unsafe ".to_owned() }; - if is_simple_block(self, context.codemap) && prefix.len() < width { - let expr_str = self.stmts[0].rewrite(context, width - prefix.len(), offset); + if is_simple_block(self, context.codemap) && prefix.len() < shape.width { + let expr_str = self.stmts[0].rewrite(context, + Shape::legacy(shape.width - prefix.len(), + shape.indent)); let expr_str = try_opt!(expr_str); let result = format!("{}{{ {} }}", prefix, expr_str); - if result.len() <= width && !result.contains('\n') { + if result.len() <= shape.width && !result.contains('\n') { return Some(result); } } @@ -666,10 +631,11 @@ impl Rewrite for ast::Block { } impl Rewrite for ast::Stmt { - fn rewrite(&self, context: &RewriteContext, _width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let result = match self.node { ast::StmtKind::Local(ref local) => { - local.rewrite(context, context.config.max_width, offset) + local.rewrite(context, + Shape::legacy(context.config.max_width, shape.indent)) } ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => { @@ -682,14 +648,15 @@ impl Rewrite for ast::Stmt { _ => unreachable!(), }, context, - context.config.max_width - offset.width() - suffix.len(), - offset) + Shape::legacy(context.config.max_width - shape.indent.width() - + suffix.len(), + shape.indent)) .map(|s| s + suffix) } ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None, }; - result.and_then(|res| recover_comment_removed(res, self.span, context, _width, offset)) + result.and_then(|res| recover_comment_removed(res, self.span, context, shape)) } } @@ -819,11 +786,12 @@ impl<'a> ControlFlow<'a> { let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost)); let expr = &self.block.stmts[0]; - let if_str = try_opt!(expr.rewrite(context, new_width, Indent::empty())); + let if_str = try_opt!(expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))); 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, 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; @@ -845,14 +813,14 @@ impl<'a> ControlFlow<'a> { } impl<'a> Rewrite for ControlFlow<'a> { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - debug!("ControlFlow::rewrite {:?} {} {:?}", self, width, offset); + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + debug!("ControlFlow::rewrite {:?} {:?}", self, shape); let (budget, indent) = if self.nested_if { // We are part of an if-elseif-else chain. Our constraints are tightened. // 7 = "} else " .len() - (try_opt!(width.checked_sub(7)), offset + 7) + (try_opt!(shape.width.checked_sub(7)), shape.indent + 7) } else { - (width, offset) + (shape.width, shape.indent) }; let label_string = rewrite_label(self.label); @@ -872,15 +840,14 @@ impl<'a> Rewrite for ControlFlow<'a> { cond, self.matcher, self.connector, - inner_width, - inner_offset)) + Shape::legacy(inner_width, inner_offset))) } None => String::new(), }; // Try to format if-else on single line. if self.allow_single_line && context.config.single_line_if_else_max_width > 0 { - let trial = self.rewrite_single_line(&pat_expr_string, context, width); + let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width); if trial.is_some() && trial.as_ref().unwrap().len() <= context.config.single_line_if_else_max_width { @@ -891,16 +858,18 @@ impl<'a> Rewrite for ControlFlow<'a> { // This is used only for the empty block case: `{}`. So, we use 1 if we know // we should avoid the single line case. // 2 = spaces after keyword and condition. - let block_width = try_opt!(width.checked_sub(label_string.len() + self.keyword.len() + - extra_offset(&pat_expr_string, inner_offset) + - 2)); + let block_width = try_opt!(shape.width + .checked_sub(label_string.len() + self.keyword.len() + + extra_offset(&pat_expr_string, inner_offset) + + 2)); let block_width = if self.else_block.is_some() || self.nested_if { min(1, block_width) } else { block_width }; - let block_str = try_opt!(self.block.rewrite(context, block_width, offset)); + let block_str = try_opt!(self.block + .rewrite(context, Shape::legacy(block_width, shape.indent))); let cond_span = if let Some(cond) = self.cond { cond.span @@ -917,12 +886,10 @@ impl<'a> Rewrite for ControlFlow<'a> { context.codemap.span_before(self.span, self.matcher.trim()) })); - let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, offset, width); + let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape); - let after_cond_comment = extract_comment(mk_sp(cond_span.hi, self.block.span.lo), - context, - offset, - width); + let after_cond_comment = + extract_comment(mk_sp(cond_span.hi, self.block.span.lo), context, shape); let alt_block_sep = String::from("\n") + &context.block_indent.to_string(context.config); let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() { @@ -949,7 +916,7 @@ impl<'a> Rewrite for ControlFlow<'a> { let rewrite = match else_block.node { // If the else expression is another if-else expression, prevent it // from being formatted on a single line. - // Note how we're passing the original width and offset, as the + // Note how we're passing the original shape, as the // cost of "else" should not cascade. ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref next_else_block) => { ControlFlow::new_if(cond, @@ -959,7 +926,7 @@ impl<'a> Rewrite for ControlFlow<'a> { false, true, mk_sp(else_block.span.lo, self.span.hi)) - .rewrite(context, width, offset) + .rewrite(context, shape) } ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => { ControlFlow::new_if(cond, @@ -969,13 +936,13 @@ impl<'a> Rewrite for ControlFlow<'a> { false, true, mk_sp(else_block.span.lo, self.span.hi)) - .rewrite(context, width, offset) + .rewrite(context, shape) } _ => { last_in_chain = true; // When rewriting a block, the width is only used for single line // blocks, passing 1 lets us avoid that. - else_block.rewrite(context, min(1, width), offset) + else_block.rewrite(context, Shape::legacy(min(1, shape.width), shape.indent)) } }; @@ -984,13 +951,13 @@ impl<'a> Rewrite for ControlFlow<'a> { 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, offset, width); + 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"), else_block.span.lo); - let after_else_comment = extract_comment(after_else, context, offset, width); + let after_else_comment = extract_comment(after_else, context, shape); let between_sep = match context.config.control_brace_style { ControlBraceStyle::AlwaysNextLine | @@ -1021,18 +988,13 @@ fn rewrite_label(label: Option) -> String { } } -fn extract_comment(span: Span, - context: &RewriteContext, - offset: Indent, - width: usize) - -> Option { +fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option { let comment_str = context.snippet(span); if contains_comment(&comment_str) { - let comment = - try_opt!(rewrite_comment(comment_str.trim(), false, width, offset, context.config)); + let comment = try_opt!(rewrite_comment(comment_str.trim(), false, shape, context.config)); Some(format!("\n{indent}{}\n{indent}", comment, - indent = offset.to_string(context.config))) + indent = shape.indent.to_string(context.config))) } else { None } @@ -1081,8 +1043,7 @@ fn is_unsafe_block(block: &ast::Block) -> bool { // are about the second arm fn rewrite_match_arm_comment(context: &RewriteContext, missed_str: &str, - width: usize, - arm_indent: Indent, + shape: Shape, arm_indent_str: &str) -> Option { // The leading "," is not part of the arm-comment @@ -1105,8 +1066,7 @@ fn rewrite_match_arm_comment(context: &RewriteContext, } let missed_str = missed_str[first..].trim(); if !missed_str.is_empty() { - let comment = - try_opt!(rewrite_comment(&missed_str, false, width, arm_indent, context.config)); + let comment = try_opt!(rewrite_comment(&missed_str, false, shape, context.config)); result.push('\n'); result.push_str(arm_indent_str); result.push_str(&comment); @@ -1118,8 +1078,7 @@ fn rewrite_match_arm_comment(context: &RewriteContext, fn rewrite_match(context: &RewriteContext, cond: &ast::Expr, arms: &[ast::Arm], - width: usize, - offset: Indent, + shape: Shape, span: Span) -> Option { if arms.is_empty() { @@ -1127,8 +1086,8 @@ fn rewrite_match(context: &RewriteContext, } // `match `cond` {` - let cond_budget = try_opt!(width.checked_sub(8)); - let cond_str = try_opt!(cond.rewrite(context, cond_budget, offset + 6)); + let cond_budget = try_opt!(shape.width.checked_sub(8)); + let cond_str = try_opt!(cond.rewrite(context, Shape::legacy(cond_budget, shape.indent + 6))); let alt_block_sep = String::from("\n") + &context.block_indent.to_string(context.config); let block_sep = match context.config.control_brace_style { ControlBraceStyle::AlwaysSameLine => " ", @@ -1152,16 +1111,15 @@ fn rewrite_match(context: &RewriteContext, }; let comment = try_opt!(rewrite_match_arm_comment(context, &missed_str, - width, - arm_indent, + Shape::legacy(shape.width, arm_indent), &arm_indent_str)); result.push_str(&comment); result.push('\n'); result.push_str(&arm_indent_str); let arm_str = arm.rewrite(&nested_context, - context.config.max_width - arm_indent.width(), - arm_indent); + Shape::legacy(context.config.max_width - arm_indent.width(), + arm_indent)); if let Some(ref arm_str) = arm_str { result.push_str(arm_str); } else { @@ -1176,8 +1134,7 @@ fn rewrite_match(context: &RewriteContext, let last_comment = context.snippet(last_span); let comment = try_opt!(rewrite_match_arm_comment(context, &last_comment, - width, - arm_indent, + Shape::legacy(shape.width, arm_indent), &arm_indent_str)); result.push_str(&comment); result.push('\n'); @@ -1221,8 +1178,8 @@ fn arm_comma(config: &Config, arm: &ast::Arm, body: &ast::Expr) -> &'static str // Match arms. impl Rewrite for ast::Arm { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - debug!("Arm::rewrite {:?} {} {:?}", self, width, offset); + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + debug!("Arm::rewrite {:?} {:?}", self, shape); let &ast::Arm { ref attrs, ref pats, ref guard, ref body } = self; // FIXME this is all a bit grotty, would be nice to abstract out the @@ -1245,9 +1202,9 @@ impl Rewrite for ast::Arm { // Patterns // 5 = ` => {` - let pat_budget = try_opt!(width.checked_sub(5)); + let pat_budget = try_opt!(shape.width.checked_sub(5)); let pat_strs = try_opt!(pats.iter() - .map(|p| p.rewrite(context, pat_budget, offset)) + .map(|p| p.rewrite(context, Shape::legacy(pat_budget, shape.indent))) .collect::>>()); let all_simple = pat_strs.iter().all(|p| pat_is_simple(p)); @@ -1260,30 +1217,28 @@ impl Rewrite for ast::Arm { }, separator: " |", trailing_separator: SeparatorTactic::Never, - indent: offset, - width: pat_budget, + shape: Shape::legacy(pat_budget, shape.indent), ends_with_newline: false, config: context.config, }; let pats_str = try_opt!(write_list(items, &fmt)); let budget = if pats_str.contains('\n') { - context.config.max_width - offset.width() + context.config.max_width - shape.indent.width() } else { - width + shape.width }; let guard_str = try_opt!(rewrite_guard(context, guard, - budget, - offset, + Shape::legacy(budget, shape.indent), trimmed_last_line_width(&pats_str))); let pats_str = format!("{}{}", pats_str, guard_str); // Where the next text can start. let mut line_start = last_line_width(&pats_str); if !pats_str.contains('\n') { - line_start += offset.width(); + line_start += shape.indent.width(); } let body = match body.node { @@ -1306,8 +1261,10 @@ impl Rewrite for ast::Arm { // 4 = ` => `.len() if context.config.max_width > line_start + comma.len() + 4 { let budget = context.config.max_width - line_start - comma.len() - 4; - let offset = Indent::new(offset.block_indent, line_start + 4 - offset.block_indent); - let rewrite = nop_block_collapse(body.rewrite(context, budget, offset), budget); + let offset = Indent::new(shape.indent.block_indent, + line_start + 4 - shape.indent.block_indent); + let rewrite = nop_block_collapse(body.rewrite(context, Shape::legacy(budget, offset)), + budget); let is_block = if let ast::ExprKind::Block(..) = body.node { true } else { @@ -1335,13 +1292,14 @@ impl Rewrite for ast::Arm { // FIXME: we're doing a second rewrite of the expr; This may not be // necessary. - let body_budget = try_opt!(width.checked_sub(context.config.tab_spaces)); + let body_budget = try_opt!(shape.width.checked_sub(context.config.tab_spaces)); let indent = context.block_indent.block_indent(context.config); let inner_context = &RewriteContext { block_indent: indent, ..*context }; - let next_line_body = - try_opt!(nop_block_collapse(body.rewrite(inner_context, body_budget, indent), - body_budget)); - let indent_str = offset.block_indent(context.config).to_string(context.config); + let next_line_body = try_opt!(nop_block_collapse(body.rewrite(inner_context, + Shape::legacy(body_budget, + indent)), + body_budget)); + let indent_str = shape.indent.block_indent(context.config).to_string(context.config); let (body_prefix, body_suffix) = if context.config.wrap_match_arms { if context.config.match_block_trailing_comma { ("{", "},") @@ -1362,7 +1320,7 @@ impl Rewrite for ast::Arm { block_sep, indent_str, next_line_body, - offset.to_string(context.config), + shape.indent.to_string(context.config), body_suffix)) } } @@ -1377,8 +1335,7 @@ fn pat_is_simple(pat_str: &str) -> bool { // The `if ...` guard on a match arm. fn rewrite_guard(context: &RewriteContext, guard: &Option>, - width: usize, - offset: Indent, + shape: Shape, // The amount of space used up on this line for the pattern in // the arm (excludes offset). pattern_width: usize) @@ -1387,23 +1344,28 @@ fn rewrite_guard(context: &RewriteContext, // First try to fit the guard string on the same line as the pattern. // 4 = ` if `, 5 = ` => {` let overhead = pattern_width + 4 + 5; - if overhead < width { - let cond_str = guard.rewrite(context, width - overhead, offset + pattern_width + 4); + if overhead < shape.width { + let cond_str = guard.rewrite(context, + Shape::legacy(shape.width - overhead, + shape.indent + pattern_width + 4)); if let Some(cond_str) = cond_str { return Some(format!(" if {}", cond_str)); } } // Not enough space to put the guard after the pattern, try a newline. - let overhead = offset.block_indent(context.config).width() + 4 + 5; - if overhead < width { + let overhead = shape.indent.block_indent(context.config).width() + 4 + 5; + if overhead < shape.width { let cond_str = guard.rewrite(context, - width - overhead, - // 3 == `if ` - offset.block_indent(context.config) + 3); + Shape::legacy(shape.width - overhead, + // 3 == `if ` + shape.indent.block_indent(context.config) + + 3)); if let Some(cond_str) = cond_str { return Some(format!("\n{}if {}", - offset.block_indent(context.config).to_string(context.config), + shape.indent + .block_indent(context.config) + .to_string(context.config), cond_str)); } } @@ -1421,8 +1383,7 @@ fn rewrite_pat_expr(context: &RewriteContext, // Connecting piece between pattern and expression, // *without* trailing space. connector: &str, - width: usize, - offset: Indent) + shape: Shape) -> Option { let mut result = match pat { Some(pat) => { @@ -1431,29 +1392,33 @@ fn rewrite_pat_expr(context: &RewriteContext, } else { format!("{} ", matcher) }; - let pat_budget = try_opt!(width.checked_sub(connector.len() + matcher.len())); - let pat_offset = offset + matcher.len(); - let pat_string = try_opt!(pat.rewrite(context, pat_budget, pat_offset)); + let pat_budget = try_opt!(shape.width.checked_sub(connector.len() + matcher.len())); + let pat_offset = shape.indent + matcher.len(); + let pat_string = try_opt!(pat.rewrite(context, Shape::legacy(pat_budget, pat_offset))); format!("{}{}{}", matcher, pat_string, connector) } None => String::new(), }; // Consider only the last line of the pat string. - let extra_offset = extra_offset(&result, offset); + let extra_offset = extra_offset(&result, shape.indent); // The expression may (partionally) fit on the current line. - if width > extra_offset + 1 { + if shape.width > extra_offset + 1 { let spacer = if pat.is_some() { " " } else { "" }; let expr_rewrite = expr.rewrite(context, - try_opt!(width.checked_sub(extra_offset + spacer.len())), - offset + extra_offset + spacer.len()); + Shape::legacy(try_opt!(shape.width + .checked_sub(extra_offset + + spacer.len())), + shape.indent + extra_offset + spacer.len())); if let Some(expr_string) = expr_rewrite { - let pat_simple = - pat.and_then(|p| p.rewrite(context, context.config.max_width, Indent::empty())) - .map(|s| pat_is_simple(&s)); + let pat_simple = pat.and_then(|p| { + p.rewrite(context, + Shape::legacy(context.config.max_width, Indent::empty())) + }) + .map(|s| pat_is_simple(&s)); if pat.is_none() || pat_simple.unwrap_or(false) || !expr_string.contains('\n') { result.push_str(spacer); @@ -1469,20 +1434,17 @@ fn rewrite_pat_expr(context: &RewriteContext, result.push('\n'); result.push_str(&nested.block_indent.to_string(context.config)); - let expr_rewrite = - expr.rewrite(&nested, - try_opt!(context.config.max_width.checked_sub(nested.block_indent.width())), - nested.block_indent); + let expr_rewrite = expr.rewrite(&nested, + Shape::legacy(try_opt!(context.config + .max_width + .checked_sub(nested.block_indent.width())), + nested.block_indent)); result.push_str(&try_opt!(expr_rewrite)); Some(result) } -fn rewrite_string_lit(context: &RewriteContext, - span: Span, - width: usize, - offset: Indent) - -> Option { +fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Option { let string_lit = context.snippet(span); if !context.config.format_strings && !context.config.force_format_strings { @@ -1490,7 +1452,7 @@ fn rewrite_string_lit(context: &RewriteContext, } if !context.config.force_format_strings && - !string_requires_rewrite(context, span, &string_lit, width, offset) { + !string_requires_rewrite(context, span, &string_lit, shape) { return Some(string_lit); } @@ -1499,8 +1461,7 @@ fn rewrite_string_lit(context: &RewriteContext, closer: "\"", line_start: " ", line_end: "\\", - width: width, - offset: offset, + shape: shape, trim_end: false, config: context.config, }; @@ -1514,20 +1475,19 @@ fn rewrite_string_lit(context: &RewriteContext, fn string_requires_rewrite(context: &RewriteContext, span: Span, string: &str, - width: usize, - offset: Indent) + shape: Shape) -> bool { - if context.codemap.lookup_char_pos(span.lo).col.0 != offset.width() { + if context.codemap.lookup_char_pos(span.lo).col.0 != shape.indent.width() { return true; } for (i, line) in string.lines().enumerate() { if i == 0 { - if line.len() > width { + if line.len() > shape.width { return true; } } else { - if line.len() > width + offset.width() { + if line.len() > shape.width + shape.indent.width() { return true; } } @@ -1540,17 +1500,15 @@ pub fn rewrite_call(context: &RewriteContext, callee: &R, args: &[ptr::P], span: Span, - width: usize, - offset: Indent) + shape: Shape) -> Option where R: Rewrite { - let closure = |callee_max_width| { - rewrite_call_inner(context, callee, callee_max_width, args, span, width, offset) - }; + let closure = + |callee_max_width| rewrite_call_inner(context, callee, callee_max_width, args, span, shape); // 2 is for parens - let max_width = try_opt!(width.checked_sub(2)); + let max_width = try_opt!(shape.width.checked_sub(2)); binary_search(1, max_width, closure) } @@ -1559,15 +1517,14 @@ fn rewrite_call_inner(context: &RewriteContext, max_callee_width: usize, args: &[ptr::P], span: Span, - width: usize, - offset: Indent) + shape: Shape) -> Result where R: Rewrite { let callee = callee.borrow(); // FIXME using byte lens instead of char lens (and probably all over the // place too) - let callee_str = match callee.rewrite(context, max_callee_width, offset) { + let callee_str = match callee.rewrite(context, Shape::legacy(max_callee_width, shape.indent)) { Some(string) => { if !string.contains('\n') && string.len() > max_callee_width { panic!("{:?} {}", string, max_callee_width); @@ -1581,13 +1538,13 @@ fn rewrite_call_inner(context: &RewriteContext, let span_lo = context.codemap.span_after(span, "("); let span = mk_sp(span_lo, span.hi); - let extra_offset = extra_offset(&callee_str, offset); + let extra_offset = extra_offset(&callee_str, shape.indent); // 2 is for parens. - let remaining_width = match width.checked_sub(extra_offset + 2) { + let remaining_width = match shape.width.checked_sub(extra_offset + 2) { Some(str) => str, None => return Err(Ordering::Greater), }; - let offset = offset + extra_offset + 1; + let offset = shape.indent + extra_offset + 1; let arg_count = args.len(); let block_indent = if arg_count == 1 { context.block_indent @@ -1596,14 +1553,15 @@ fn rewrite_call_inner(context: &RewriteContext, }; let inner_context = &RewriteContext { block_indent: block_indent, ..*context }; - let items = itemize_list(context.codemap, - args.iter(), - ")", - |item| item.span.lo, - |item| item.span.hi, - |item| item.rewrite(inner_context, remaining_width, offset), - span.lo, - span.hi); + let items = + itemize_list(context.codemap, + args.iter(), + ")", + |item| item.span.lo, + |item| item.span.hi, + |item| item.rewrite(inner_context, Shape::legacy(remaining_width, offset)), + span.lo, + span.hi); let mut item_vec: Vec<_> = items.collect(); // Try letting the last argument overflow to the next line with block @@ -1622,7 +1580,8 @@ fn rewrite_call_inner(context: &RewriteContext, // first arguments. if overflow_last { let inner_context = &RewriteContext { block_indent: context.block_indent, ..*context }; - let rewrite = args.last().unwrap().rewrite(inner_context, remaining_width, offset); + let rewrite = + args.last().unwrap().rewrite(inner_context, Shape::legacy(remaining_width, offset)); if let Some(rewrite) = rewrite { let rewrite_first_line = Some(rewrite[..first_line_width(&rewrite)].to_owned()); @@ -1654,8 +1613,7 @@ fn rewrite_call_inner(context: &RewriteContext, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: offset, - width: width, + shape: Shape::legacy(shape.width, offset), ends_with_newline: false, config: context.config, }; @@ -1672,15 +1630,13 @@ fn rewrite_call_inner(context: &RewriteContext, }) } -fn rewrite_paren(context: &RewriteContext, - subexpr: &ast::Expr, - width: usize, - offset: Indent) - -> Option { - debug!("rewrite_paren, width: {}, offset: {:?}", width, offset); +fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, shape: Shape) -> Option { + debug!("rewrite_paren, shape: {:?}", shape); // 1 is for opening paren, 2 is for opening+closing, we want to keep the closing // paren on the same line as the subexpr. - let subexpr_str = subexpr.rewrite(context, try_opt!(width.checked_sub(2)), offset + 1); + let subexpr_str = subexpr.rewrite(context, + Shape::legacy(try_opt!(shape.width.checked_sub(2)), + shape.indent + 1)); debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str); subexpr_str.map(|s| if context.config.spaces_within_parens && s.len() > 0 { @@ -1693,10 +1649,9 @@ fn rewrite_paren(context: &RewriteContext, fn rewrite_index(expr: &ast::Expr, index: &ast::Expr, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { - let expr_str = try_opt!(expr.rewrite(context, width, offset)); + let expr_str = try_opt!(expr.rewrite(context, shape)); let (lbr, rbr) = if context.config.spaces_within_square_brackets { ("[ ", " ]") @@ -1704,19 +1659,19 @@ fn rewrite_index(expr: &ast::Expr, ("[", "]") }; - let budget = width.checked_sub(expr_str.len() + lbr.len() + rbr.len()).unwrap_or(0); - let index_str = index.rewrite(context, budget, offset); + let budget = shape.width.checked_sub(expr_str.len() + lbr.len() + rbr.len()).unwrap_or(0); + let index_str = index.rewrite(context, Shape::legacy(budget, shape.indent)); if let Some(index_str) = index_str { return Some(format!("{}{}{}{}", expr_str, lbr, index_str, rbr)); } - let indent = offset.block_indent(&context.config); + let indent = shape.indent.block_indent(&context.config); let indent = indent.to_string(&context.config); - // FIXME this is not right, since we don't take into account that width + // FIXME this is not right, since we don't take into account that shape.width // might be reduced from max_width by something on the right. let budget = try_opt!(context.config.max_width.checked_sub(indent.len() + lbr.len() + rbr.len())); - let index_str = try_opt!(index.rewrite(context, budget, offset)); + let index_str = try_opt!(index.rewrite(context, Shape::legacy(budget, shape.indent))); Some(format!("{}\n{}{}{}{}", expr_str, indent, lbr, index_str, rbr)) } @@ -1725,10 +1680,9 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, fields: &'a [ast::Field], base: Option<&'a ast::Expr>, span: Span, - width: usize, - offset: Indent) + shape: Shape) -> Option { - debug!("rewrite_struct_lit: width {}, offset {:?}", width, offset); + debug!("rewrite_struct_lit: shape {:?}", shape); enum StructLitField<'a> { Regular(&'a ast::Field), @@ -1736,15 +1690,18 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, } // 2 = " {".len() - let path_budget = try_opt!(width.checked_sub(2)); - let path_str = - try_opt!(rewrite_path(context, PathContext::Expr, None, path, path_budget, offset)); + let path_budget = try_opt!(shape.width.checked_sub(2)); + let path_str = try_opt!(rewrite_path(context, + PathContext::Expr, + None, + path, + Shape::legacy(path_budget, shape.indent))); // Foo { a: Foo } - indent is +3, width is -5. - let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0); + let h_budget = shape.width.checked_sub(path_str.len() + 5).unwrap_or(0); // The 1 taken from the v_budget is for the comma. let (indent, v_budget) = match context.config.struct_lit_style { - StructLitStyle::Visual => (offset + path_str.len() + 3, h_budget), + StructLitStyle::Visual => (shape.indent + path_str.len() + 3, h_budget), StructLitStyle::Block => { // If we are all on one line, then we'll ignore the indent, and we // have a smaller budget. @@ -1783,12 +1740,12 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, StructLitField::Regular(field) => { rewrite_field(inner_context, field, - v_budget.checked_sub(1).unwrap_or(0), - indent) + Shape::legacy(v_budget.checked_sub(1).unwrap_or(0), indent)) } StructLitField::Base(expr) => { // 2 = .. - expr.rewrite(inner_context, try_opt!(v_budget.checked_sub(2)), indent + 2) + expr.rewrite(inner_context, + Shape::legacy(try_opt!(v_budget.checked_sub(2)), indent + 2)) .map(|s| format!("..{}", s)) } } @@ -1826,8 +1783,7 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, } else { context.config.struct_lit_trailing_comma }, - indent: indent, - width: budget, + shape: Shape::legacy(budget, indent), ends_with_newline: ends_with_newline, config: context.config, }; @@ -1870,27 +1826,23 @@ pub fn type_annotation_separator(config: &Config) -> &str { } } -fn rewrite_field(context: &RewriteContext, - field: &ast::Field, - width: usize, - offset: Indent) - -> Option { +fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) -> Option { let name = &field.ident.node.to_string(); let separator = type_annotation_separator(context.config); let overhead = name.len() + separator.len(); let expr = field.expr.rewrite(context, - try_opt!(width.checked_sub(overhead)), - offset + overhead); + Shape::legacy(try_opt!(shape.width.checked_sub(overhead)), + shape.indent + overhead)); match expr { Some(e) => Some(format!("{}{}{}", name, separator, e)), None => { - let expr_offset = offset.block_indent(context.config); + let expr_offset = shape.indent.block_indent(context.config); let expr = field.expr.rewrite(context, - try_opt!(context.config - .max_width - .checked_sub(expr_offset.width())), - expr_offset); + Shape::legacy(try_opt!(context.config + .max_width + .checked_sub(expr_offset.width())), + expr_offset)); expr.map(|s| format!("{}:\n{}{}", name, expr_offset.to_string(&context.config), s)) } } @@ -1899,23 +1851,22 @@ fn rewrite_field(context: &RewriteContext, pub fn rewrite_tuple<'a, I>(context: &RewriteContext, mut items: I, span: Span, - width: usize, - offset: Indent) + shape: Shape) -> Option where I: ExactSizeIterator, ::Item: Deref, ::Target: Rewrite + Spanned + 'a { - let indent = offset + 1; + let indent = shape.indent + 1; let aligned = RewriteContext { block_indent: indent, ..context.clone() }; // In case of length 1, need a trailing comma if items.len() == 1 { // 3 = "(" + ",)" - let budget = try_opt!(width.checked_sub(3)); + let budget = try_opt!(shape.width.checked_sub(3)); return items.next() .unwrap() - .rewrite(&aligned, budget, indent) + .rewrite(&aligned, Shape::legacy(budget, indent)) .map(|s| if context.config.spaces_within_parens { format!("( {}, )", s) } else { @@ -1924,16 +1875,16 @@ pub fn rewrite_tuple<'a, I>(context: &RewriteContext, } let list_lo = context.codemap.span_after(span, "("); - let budget = try_opt!(width.checked_sub(2)); + let budget = try_opt!(shape.width.checked_sub(2)); let items = itemize_list(context.codemap, items, ")", |item| item.span().lo, |item| item.span().hi, - |item| item.rewrite(&aligned, budget, indent), + |item| item.rewrite(&aligned, Shape::legacy(budget, indent)), list_lo, span.hi - BytePos(1)); - let list_str = try_opt!(format_item_list(items, budget, indent, context.config)); + let list_str = try_opt!(format_item_list(items, Shape::legacy(budget, indent), context.config)); if context.config.spaces_within_parens && list_str.len() > 0 { Some(format!("( {} )", list_str)) @@ -1945,12 +1896,11 @@ pub fn rewrite_tuple<'a, I>(context: &RewriteContext, pub fn rewrite_unary_prefix(context: &RewriteContext, prefix: &str, rewrite: &R, - width: usize, - offset: Indent) + shape: Shape) -> Option { rewrite.rewrite(context, - try_opt!(width.checked_sub(prefix.len())), - offset + prefix.len()) + Shape::legacy(try_opt!(shape.width.checked_sub(prefix.len())), + shape.indent + prefix.len())) .map(|r| format!("{}{}", prefix, r)) } @@ -1959,10 +1909,11 @@ pub fn rewrite_unary_prefix(context: &RewriteContext, pub fn rewrite_unary_suffix(context: &RewriteContext, suffix: &str, rewrite: &R, - width: usize, - offset: Indent) + shape: Shape) -> Option { - rewrite.rewrite(context, try_opt!(width.checked_sub(suffix.len())), offset) + rewrite.rewrite(context, + Shape::legacy(try_opt!(shape.width.checked_sub(suffix.len())), + shape.indent)) .map(|mut r| { r.push_str(suffix); r @@ -1972,8 +1923,7 @@ pub fn rewrite_unary_suffix(context: &RewriteContext, fn rewrite_unary_op(context: &RewriteContext, op: &ast::UnOp, expr: &ast::Expr, - width: usize, - offset: Indent) + shape: Shape) -> Option { // For some reason, an UnOp is not spanned like BinOp! let operator_str = match *op { @@ -1981,15 +1931,14 @@ fn rewrite_unary_op(context: &RewriteContext, ast::UnOp::Not => "!", ast::UnOp::Neg => "-", }; - rewrite_unary_prefix(context, operator_str, expr, width, offset) + rewrite_unary_prefix(context, operator_str, expr, shape) } fn rewrite_assignment(context: &RewriteContext, lhs: &ast::Expr, rhs: &ast::Expr, op: Option<&ast::BinOp>, - width: usize, - offset: Indent) + shape: Shape) -> Option { let operator_str = match op { Some(op) => context.snippet(op.span), @@ -1997,12 +1946,12 @@ fn rewrite_assignment(context: &RewriteContext, }; // 1 = space between lhs and operator. - let max_width = try_opt!(width.checked_sub(operator_str.len() + 1)); + let max_width = try_opt!(shape.width.checked_sub(operator_str.len() + 1)); let lhs_str = format!("{} {}", - try_opt!(lhs.rewrite(context, max_width, offset)), + try_opt!(lhs.rewrite(context, Shape::legacy(max_width, shape.indent))), operator_str); - rewrite_assign_rhs(context, lhs_str, rhs, width, offset) + rewrite_assign_rhs(context, lhs_str, rhs, shape) } // The left hand side must contain everything up to, and including, the @@ -2010,19 +1959,19 @@ fn rewrite_assignment(context: &RewriteContext, pub fn rewrite_assign_rhs>(context: &RewriteContext, lhs: S, ex: &ast::Expr, - width: usize, - offset: Indent) + shape: Shape) -> Option { let mut result = lhs.into(); let last_line_width = last_line_width(&result) - if result.contains('\n') { - offset.width() + shape.indent.width() } else { 0 }; // 1 = space between operator and rhs. - let max_width = try_opt!(width.checked_sub(last_line_width + 1)); - let rhs = ex.rewrite(context, max_width, offset + last_line_width + 1); + let max_width = try_opt!(shape.width.checked_sub(last_line_width + 1)); + let rhs = ex.rewrite(context, + Shape::legacy(max_width, shape.indent + last_line_width + 1)); fn count_line_breaks(src: &str) -> usize { src.chars().filter(|&x| x == '\n').count() @@ -2037,10 +1986,11 @@ pub fn rewrite_assign_rhs>(context: &RewriteContext, // Expression did not fit on the same line as the identifier or is // at least three lines big. Try splitting the line and see // if that works better. - let new_offset = offset.block_indent(context.config); - let max_width = try_opt!((width + offset.width()).checked_sub(new_offset.width())); + let new_offset = shape.indent.block_indent(context.config); + let max_width = try_opt!((shape.width + shape.indent.width()) + .checked_sub(new_offset.width())); let inner_context = context.nested_context(); - let new_rhs = ex.rewrite(&inner_context, max_width, new_offset); + let new_rhs = ex.rewrite(&inner_context, Shape::legacy(max_width, new_offset)); // FIXME: DRY! match (rhs, new_rhs) { @@ -2069,12 +2019,11 @@ pub fn rewrite_assign_rhs>(context: &RewriteContext, fn rewrite_expr_addrof(context: &RewriteContext, mutability: ast::Mutability, expr: &ast::Expr, - width: usize, - offset: Indent) + shape: Shape) -> Option { let operator_str = match mutability { ast::Mutability::Immutable => "&", ast::Mutability::Mutable => "&mut ", }; - rewrite_unary_prefix(context, operator_str, expr, width, offset) + rewrite_unary_prefix(context, operator_str, expr, shape) } diff --git a/src/imports.rs b/src/imports.rs index a75a571c553f..6e7c2d0f7e2d 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use Indent; +use Shape; use utils; use syntax::codemap::{self, BytePos, Span}; use codemap::SpanUtils; @@ -125,19 +125,19 @@ fn compare_use_items(a: &ast::Item, b: &ast::Item) -> Option { impl Rewrite for ast::ViewPath { // Returns an empty string when the ViewPath is empty (like foo::bar::{}) - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match self.node { ast::ViewPath_::ViewPathList(_, ref path_list) if path_list.is_empty() => { Some(String::new()) } ast::ViewPath_::ViewPathList(ref path, ref path_list) => { - rewrite_use_list(width, offset, path, path_list, self.span, context) + rewrite_use_list(shape, path, path_list, self.span, context) } ast::ViewPath_::ViewPathGlob(_) => None, ast::ViewPath_::ViewPathSimple(ident, ref path) => { let ident_str = ident.to_string(); // 4 = " as ".len() - let budget = try_opt!(width.checked_sub(ident_str.len() + 4)); + let budget = try_opt!(shape.width.checked_sub(ident_str.len() + 4)); let path_str = if path.segments.last().unwrap().identifier.to_string() == "self" && path.segments.len() > 1 { @@ -149,10 +149,13 @@ impl Rewrite for ast::ViewPath { PathContext::Import, None, &path, - budget, - offset)) + Shape::legacy(budget, shape.indent))) } else { - try_opt!(rewrite_path(context, PathContext::Import, None, path, budget, offset)) + try_opt!(rewrite_path(context, + PathContext::Import, + None, + path, + Shape::legacy(budget, shape.indent))) }; Some(if path.segments.last().unwrap().identifier == ident { @@ -225,8 +228,7 @@ impl<'a> FmtVisitor<'a> { offset.alignment += vis.len() + "use ".len(); // 1 = ";" match vp.rewrite(&self.get_context(), - self.config.max_width - offset.width() - 1, - offset) { + Shape::legacy(self.config.max_width - offset.width() - 1, offset)) { Some(ref s) if s.is_empty() => { // Format up to last newline let prev_span = codemap::mk_sp(self.last_pos, source!(self, span).lo); @@ -283,15 +285,14 @@ fn append_alias(path_item_str: String, vpi: &ast::PathListItem) -> String { // Pretty prints a multi-item import. // Assumes that path_list.len() > 0. -pub fn rewrite_use_list(width: usize, - offset: Indent, +pub fn rewrite_use_list(shape: Shape, path: &ast::Path, path_list: &[ast::PathListItem], span: Span, context: &RewriteContext) -> Option { // Returns a different option to distinguish `::foo` and `foo` - let path_str = try_opt!(rewrite_path(context, PathContext::Import, None, path, width, offset)); + let path_str = try_opt!(rewrite_path(context, PathContext::Import, None, path, shape)); match path_list.len() { 0 => unreachable!(), @@ -300,7 +301,7 @@ pub fn rewrite_use_list(width: usize, } // 2 = {} - let remaining_width = width.checked_sub(path_str.len() + 2).unwrap_or(0); + let remaining_width = shape.width.checked_sub(path_str.len() + 2).unwrap_or(0); let mut items = { // Dummy value, see explanation below. @@ -336,11 +337,11 @@ pub fn rewrite_use_list(width: usize, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: offset + path_str.len() + 1 + colons_offset, // FIXME This is too conservative, and will not use all width // available // (loose 1 column (";")) - width: remaining_width, + shape: Shape::legacy(remaining_width, + shape.indent + path_str.len() + 1 + colons_offset), ends_with_newline: false, config: context.config, }; diff --git a/src/items.rs b/src/items.rs index 8270a52ce766..3c5bf3ce6cee 100644 --- a/src/items.rs +++ b/src/items.rs @@ -10,7 +10,7 @@ // Formatting top-level items - functions, structs, enums, traits, impls. -use Indent; +use {Indent, Shape}; use codemap::SpanUtils; use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str, last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr}; @@ -30,14 +30,18 @@ use syntax::ast::ImplItem; // Statements of the form // let pat: ty = init; impl Rewrite for ast::Local { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - debug!("Local::rewrite {:?} {} {:?}", self, width, offset); + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + debug!("Local::rewrite {:?} {} {:?}", + self, + shape.width, + shape.indent); let mut result = "let ".to_owned(); - let pattern_offset = offset + result.len(); + let pattern_offset = shape.indent + result.len(); // 1 = ; - let pattern_width = try_opt!(width.checked_sub(pattern_offset.width() + 1)); + let pattern_width = try_opt!(shape.width.checked_sub(pattern_offset.width() + 1)); - let pat_str = try_opt!(self.pat.rewrite(&context, pattern_width, pattern_offset)); + let pat_str = try_opt!(self.pat + .rewrite(&context, Shape::legacy(pattern_width, pattern_offset))); result.push_str(&pat_str); // String that is placed within the assignment pattern and expression. @@ -46,10 +50,10 @@ impl Rewrite for ast::Local { if let Some(ref ty) = self.ty { let separator = type_annotation_separator(context.config); - let indent = offset + last_line_width(&result) + separator.len(); + let indent = shape.indent + last_line_width(&result) + separator.len(); // 1 = ; - let budget = try_opt!(width.checked_sub(indent.width() + 1)); - let rewrite = try_opt!(ty.rewrite(context, budget, indent)); + let budget = try_opt!(shape.width.checked_sub(indent.width() + 1)); + let rewrite = try_opt!(ty.rewrite(context, Shape::legacy(budget, indent))); infix.push_str(separator); infix.push_str(&rewrite); @@ -66,10 +70,12 @@ impl Rewrite for ast::Local { if let Some(ref ex) = self.init { // 1 = trailing semicolon; - let budget = try_opt!(width.checked_sub(context.block_indent.width() + 1)); + let budget = try_opt!(shape.width.checked_sub(context.block_indent.width() + 1)); - result = - try_opt!(rewrite_assign_rhs(&context, result, ex, budget, context.block_indent)); + result = try_opt!(rewrite_assign_rhs(&context, + result, + ex, + Shape::legacy(budget, context.block_indent))); } result.push(';'); @@ -200,7 +206,7 @@ impl<'a> FmtVisitor<'a> { let offset = self.block_indent + prefix.len(); // 1 = ; let width = self.config.max_width - offset.width() - 1; - let rewrite = ty.rewrite(&self.get_context(), width, offset); + let rewrite = ty.rewrite(&self.get_context(), Shape::legacy(width, offset)); match rewrite { Some(result) => { @@ -321,15 +327,17 @@ impl<'a> FmtVisitor<'a> { let suffix = if semicolon_for_expr(e) { ";" } else { "" }; e.rewrite(&self.get_context(), - self.config.max_width - self.block_indent.width(), - self.block_indent) + Shape::legacy(self.config.max_width - + self.block_indent.width(), + self.block_indent)) .map(|s| s + suffix) .or_else(|| Some(self.snippet(e.span))) } None => { stmt.rewrite(&self.get_context(), - self.config.max_width - self.block_indent.width(), - self.block_indent) + Shape::legacy(self.config.max_width - + self.block_indent.width(), + self.block_indent)) } } } else { @@ -426,8 +434,7 @@ impl<'a> FmtVisitor<'a> { tactic: DefinitiveListTactic::Vertical, separator: ",", trailing_separator: SeparatorTactic::from_bool(self.config.enum_trailing_comma), - indent: self.block_indent, - width: budget, + shape: Shape::legacy(budget, self.block_indent), ends_with_newline: true, config: self.config, }; @@ -450,8 +457,7 @@ impl<'a> FmtVisitor<'a> { let mut result = try_opt!(field.node .attrs .rewrite(&self.get_context(), - self.config.max_width - indent.width(), - indent)); + Shape::legacy(self.config.max_width - indent.width(), indent))); if !result.is_empty() { result.push('\n'); result.push_str(&indent.to_string(self.config)); @@ -481,8 +487,7 @@ impl<'a> FmtVisitor<'a> { wrap_str(tag, self.config.max_width, - self.config.max_width - indent.width(), - indent) + Shape::legacy(self.config.max_width - indent.width(), indent)) } }; @@ -514,8 +519,8 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) - &generics.where_clause, context.config, context.config.item_brace_style, - context.block_indent, - where_budget, + Shape::legacy(where_budget, + context.block_indent), context.config.where_density, "{", true, @@ -628,8 +633,8 @@ fn format_impl_ref_and_type(context: &RewriteContext, }; let generics_str = try_opt!(rewrite_generics(context, generics, - offset, - context.config.max_width, + Shape::legacy(context.config.max_width, + offset), offset + result.len(), mk_sp(lo, hi))); result.push_str(&generics_str); @@ -643,7 +648,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, } let budget = try_opt!(context.config.max_width.checked_sub(result.len())); let indent = offset + result.len(); - result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent))); + result.push_str(&*try_opt!(trait_ref.rewrite(context, Shape::legacy(budget, indent)))); if split_at_for { result.push('\n'); @@ -673,7 +678,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, // 1 = space before the type. let budget = try_opt!(context.config.max_width.checked_sub(used_space + 1)); let indent = offset + result.len() + 1; - let self_ty_str = self_ty.rewrite(context, budget, indent); + let self_ty_str = self_ty.rewrite(context, Shape::legacy(budget, indent)); if let Some(self_ty_str) = self_ty_str { result.push_str(" "); result.push_str(&self_ty_str); @@ -684,7 +689,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, let indent = offset.block_indent(context.config); result.push_str(&format!("\n{}", indent.to_string(context.config))); let budget = try_opt!(context.config.max_width.checked_sub(indent.width())); - result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent))); + result.push_str(&*try_opt!(self_ty.rewrite(context, Shape::legacy(budget, indent)))); Some(result) } else { unreachable!(); @@ -742,16 +747,16 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) let generics_str = try_opt!(rewrite_generics(context, generics, - offset, - context.config.max_width, + Shape::legacy(context.config.max_width, + offset), offset + result.len(), mk_sp(item.span.lo, body_lo))); result.push_str(&generics_str); - let trait_bound_str = try_opt!(rewrite_trait_bounds(context, - type_param_bounds, - offset, - context.config.max_width)); + let trait_bound_str = + try_opt!(rewrite_trait_bounds(context, + type_param_bounds, + Shape::legacy(context.config.max_width, offset))); // If the trait, generics, and trait bound cannot fit on the same line, // put the trait bounds on an indented new line if offset.width() + last_line_width(&result) + trait_bound_str.len() > @@ -783,8 +788,8 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) &generics.where_clause, context.config, context.config.item_brace_style, - context.block_indent, - where_budget, + Shape::legacy(where_budget, + context.block_indent), where_density, "{", has_body, @@ -916,22 +921,23 @@ fn format_struct_struct(context: &RewriteContext, // 1 = "," let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 1)); - let items = itemize_list(context.codemap, - fields.iter(), - "}", - |field| { - // Include attributes and doc comments, if present - if !field.attrs.is_empty() { - field.attrs[0].span.lo - } else { - field.span.lo - } - }, - |field| field.ty.span.hi, - |field| field.rewrite(context, item_budget, item_indent), - context.codemap.span_after(span, "{"), - span.hi) - .collect::>(); + let items = + itemize_list(context.codemap, + fields.iter(), + "}", + |field| { + // Include attributes and doc comments, if present + if !field.attrs.is_empty() { + field.attrs[0].span.lo + } else { + field.span.lo + } + }, + |field| field.ty.span.hi, + |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)), + context.codemap.span_after(span, "{"), + span.hi) + .collect::>(); // 1 = , let budget = context.config.max_width - offset.width() + context.config.tab_spaces - 1; @@ -944,8 +950,7 @@ fn format_struct_struct(context: &RewriteContext, tactic: tactic, separator: ",", trailing_separator: context.config.struct_trailing_comma, - indent: item_indent, - width: budget, + shape: Shape::legacy(budget, item_indent), ends_with_newline: true, config: context.config, }; @@ -986,8 +991,8 @@ fn format_tuple_struct(context: &RewriteContext, Some(generics) => { let generics_str = try_opt!(rewrite_generics(context, generics, - offset, - context.config.max_width, + Shape::legacy(context.config.max_width, + offset), offset + header_str.len(), mk_sp(span.lo, body_lo))); result.push_str(&generics_str); @@ -999,8 +1004,7 @@ fn format_tuple_struct(context: &RewriteContext, &generics.where_clause, context.config, context.config.item_brace_style, - context.block_indent, - where_budget, + Shape::legacy(where_budget, context.block_indent), Density::Compressed, ";", false, @@ -1014,22 +1018,25 @@ fn format_tuple_struct(context: &RewriteContext, // 2 = ");" let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2)); - let items = itemize_list(context.codemap, - fields.iter(), - ")", - |field| { - // Include attributes and doc comments, if present - if !field.attrs.is_empty() { - field.attrs[0].span.lo - } else { - field.span.lo - } - }, - |field| field.ty.span.hi, - |field| field.rewrite(context, item_budget, item_indent), - context.codemap.span_after(span, "("), - span.hi); - let body = try_opt!(format_item_list(items, item_budget, item_indent, context.config)); + let items = + itemize_list(context.codemap, + fields.iter(), + ")", + |field| { + // Include attributes and doc comments, if present + if !field.attrs.is_empty() { + field.attrs[0].span.lo + } else { + field.span.lo + } + }, + |field| field.ty.span.hi, + |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)), + context.codemap.span_after(span, "("), + span.hi); + let body = try_opt!(format_item_list(items, + Shape::legacy(item_budget, item_indent), + context.config)); if context.config.spaces_within_parens && body.len() > 0 { result.push(' '); @@ -1077,8 +1084,7 @@ pub fn rewrite_type_alias(context: &RewriteContext, let generics_width = context.config.max_width - " =".len(); let generics_str = try_opt!(rewrite_generics(context, generics, - indent, - generics_width, + Shape::legacy(generics_width, indent), generics_indent, generics_span)); @@ -1091,8 +1097,7 @@ pub fn rewrite_type_alias(context: &RewriteContext, &generics.where_clause, context.config, context.config.item_brace_style, - indent, - where_budget, + Shape::legacy(where_budget, indent), context.config.where_density, "=", false, @@ -1109,7 +1114,7 @@ pub fn rewrite_type_alias(context: &RewriteContext, .unwrap_or(0); let type_indent = indent + line_width; // Try to fit the type on the same line - let ty_str = try_opt!(ty.rewrite(context, budget, type_indent) + let ty_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, type_indent)) .or_else(|| { // The line was too short, try to put the type on the next line @@ -1121,7 +1126,7 @@ pub fn rewrite_type_alias(context: &RewriteContext, let budget = try_opt!(context.config .max_width .checked_sub(type_indent.width() + ";".len())); - ty.rewrite(context, budget, type_indent) + ty.rewrite(context, Shape::legacy(budget, type_indent)) })); result.push_str(&ty_str); result.push_str(";"); @@ -1142,19 +1147,21 @@ fn type_annotation_spacing(config: &Config) -> (&str, &str) { } impl Rewrite for ast::StructField { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { if contains_skip(&self.attrs) { let span = context.snippet(mk_sp(self.attrs[0].span.lo, self.span.hi)); - return wrap_str(span, context.config.max_width, width, offset); + return wrap_str(span, context.config.max_width, shape); } let name = self.ident; let vis = format_visibility(&self.vis); let mut attr_str = try_opt!(self.attrs - .rewrite(context, context.config.max_width - offset.width(), offset)); + .rewrite(context, + Shape::legacy(context.config.max_width - shape.indent.width(), + shape.indent))); if !attr_str.is_empty() { attr_str.push('\n'); - attr_str.push_str(&offset.to_string(context.config)); + attr_str.push_str(&shape.indent.to_string(context.config)); } let type_annotation_spacing = type_annotation_spacing(context.config); @@ -1171,8 +1178,10 @@ impl Rewrite for ast::StructField { }; let last_line_width = last_line_width(&result); - let budget = try_opt!(width.checked_sub(last_line_width)); - let rewrite = try_opt!(self.ty.rewrite(context, budget, offset + last_line_width)); + let budget = try_opt!(shape.width.checked_sub(last_line_width)); + let rewrite = try_opt!(self.ty.rewrite(context, + Shape::legacy(budget, + shape.indent + last_line_width))); Some(result + &rewrite) } } @@ -1195,15 +1204,20 @@ pub fn rewrite_static(prefix: &str, type_annotation_spacing.1); // 2 = " =".len() let ty_str = try_opt!(ty.rewrite(context, - context.config.max_width - context.block_indent.width() - - prefix.len() - 2, - context.block_indent)); + Shape::legacy(context.config.max_width - + context.block_indent.width() - + prefix.len() - + 2, + context.block_indent))); if let Some(expr) = expr_opt { let lhs = format!("{}{} =", prefix, ty_str); // 1 = ; let remaining_width = context.config.max_width - context.block_indent.width() - 1; - rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent) + rewrite_assign_rhs(context, + lhs, + expr, + Shape::legacy(remaining_width, context.block_indent)) .map(|s| s + ";") } else { let lhs = format!("{}{};", prefix, ty_str); @@ -1222,7 +1236,9 @@ pub fn rewrite_associated_type(ident: ast::Ident, let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt { let bounds: &[_] = ty_param_bounds; let bound_str = try_opt!(bounds.iter() - .map(|ty_bound| ty_bound.rewrite(context, context.config.max_width, indent)) + .map(|ty_bound| { + ty_bound.rewrite(context, Shape::legacy(context.config.max_width, indent)) + }) .intersperse(Some(" + ".to_string())) .collect::>()); if bounds.len() > 0 { @@ -1236,10 +1252,11 @@ pub fn rewrite_associated_type(ident: ast::Ident, if let Some(ty) = ty_opt { let ty_str = try_opt!(ty.rewrite(context, - context.config.max_width - context.block_indent.width() - - prefix.len() - - 2, - context.block_indent)); + Shape::legacy(context.config.max_width - + context.block_indent.width() - + prefix.len() - + 2, + context.block_indent))); Some(format!("{} = {};", prefix, ty_str)) } else { Some(format!("{}{};", prefix, type_bounds_str)) @@ -1247,21 +1264,23 @@ pub fn rewrite_associated_type(ident: ast::Ident, } impl Rewrite for ast::FunctionRetTy { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match *self { ast::FunctionRetTy::Default(_) => Some(String::new()), ast::FunctionRetTy::Ty(ref ty) => { - let inner_width = try_opt!(width.checked_sub(3)); - ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r)) + let inner_width = try_opt!(shape.width.checked_sub(3)); + ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3)) + .map(|r| format!("-> {}", r)) } } } } impl Rewrite for ast::Arg { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { if is_named_arg(self) { - let mut result = try_opt!(self.pat.rewrite(context, width, offset)); + let mut result = try_opt!(self.pat + .rewrite(context, Shape::legacy(shape.width, shape.indent))); if self.ty.node != ast::TyKind::Infer { if context.config.space_before_type_annotation { @@ -1271,14 +1290,16 @@ impl Rewrite for ast::Arg { if context.config.space_after_type_annotation_colon { result.push_str(" "); } - let max_width = try_opt!(width.checked_sub(result.len())); - let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len())); + let max_width = try_opt!(shape.width.checked_sub(result.len())); + let ty_str = try_opt!(self.ty.rewrite(context, + Shape::legacy(max_width, + shape.indent + result.len()))); result.push_str(&ty_str); } Some(result) } else { - self.ty.rewrite(context, width, offset) + self.ty.rewrite(context, shape) } } } @@ -1292,8 +1313,8 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf, let mut_str = format_mutability(m); match lt { Some(ref l) => { - let lifetime_str = - try_opt!(l.rewrite(context, usize::max_value(), Indent::empty())); + let lifetime_str = try_opt!(l.rewrite(context, + Shape::legacy(usize::max_value(), Indent::empty()))); Some(format!("&{} {}self", lifetime_str, mut_str)) } None => Some(format!("&{}self", mut_str)), @@ -1303,7 +1324,8 @@ fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf, assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty."); let mutability = explicit_self_mutability(&args[0]); - let type_str = try_opt!(ty.rewrite(context, usize::max_value(), Indent::empty())); + let type_str = + try_opt!(ty.rewrite(context, Shape::legacy(usize::max_value(), Indent::empty()))); Some(format!("{}self: {}", format_mutability(mutability), type_str)) } @@ -1427,8 +1449,7 @@ fn rewrite_fn_base(context: &RewriteContext, let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo); let generics_str = try_opt!(rewrite_generics(context, generics, - indent, - context.config.max_width, + Shape::legacy(context.config.max_width, indent), generics_indent, generics_span)); result.push_str(&generics_str); @@ -1436,7 +1457,8 @@ fn rewrite_fn_base(context: &RewriteContext, // Note that if the width and indent really matter, we'll re-layout the // return type later anyway. let ret_str = try_opt!(fd.output - .rewrite(&context, context.config.max_width - indent.width(), indent)); + .rewrite(&context, + Shape::legacy(context.config.max_width - indent.width(), indent))); let multi_line_ret_str = ret_str.contains('\n'); let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() }; @@ -1571,7 +1593,7 @@ fn rewrite_fn_base(context: &RewriteContext, // Now that we know the proper indent and width, we need to // re-layout the return type. let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width())); - let ret_str = try_opt!(fd.output.rewrite(context, budget, ret_indent)); + let ret_str = try_opt!(fd.output.rewrite(context, Shape::legacy(budget, ret_indent))); result.push_str(&ret_str); } else { result.push_str(&ret_str); @@ -1612,8 +1634,7 @@ fn rewrite_fn_base(context: &RewriteContext, where_clause, context.config, context.config.fn_brace_style, - indent, - where_budget, + Shape::legacy(where_budget, indent), where_density, "{", has_body, @@ -1640,7 +1661,7 @@ fn rewrite_args(context: &RewriteContext, variadic: bool) -> Option { let mut arg_item_strs = try_opt!(args.iter() - .map(|arg| arg.rewrite(&context, multi_line_budget, arg_indent)) + .map(|arg| arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))) .collect::>>()); // Account for sugary self. @@ -1744,8 +1765,7 @@ fn rewrite_args(context: &RewriteContext, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: indent, - width: budget, + shape: Shape::legacy(budget, indent), ends_with_newline: end_with_newline, config: context.config, }; @@ -1812,8 +1832,8 @@ fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool { fn rewrite_generics(context: &RewriteContext, generics: &ast::Generics, - offset: Indent, - width: usize, + shape: Shape, + // TODO shouldn't need this generics_offset: Indent, span: Span) -> Option { @@ -1826,18 +1846,19 @@ fn rewrite_generics(context: &RewriteContext, } let offset = match context.config.generics_indent { - BlockIndentStyle::Inherit => offset, - BlockIndentStyle::Tabbed => offset.block_indent(context.config), + BlockIndentStyle::Inherit => shape.indent, + BlockIndentStyle::Tabbed => shape.indent.block_indent(context.config), // 1 = < BlockIndentStyle::Visual => generics_offset + 1, }; - let h_budget = try_opt!(width.checked_sub(generics_offset.width() + 2)); + let h_budget = try_opt!(shape.width.checked_sub(generics_offset.width() + 2)); // FIXME: might need to insert a newline if the generics are really long. // Strings for the generics. - let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, h_budget, offset)); - let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, h_budget, offset)); + let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, Shape::legacy(h_budget, offset))); + let ty_strs = tys.iter() + .map(|ty_param| ty_param.rewrite(context, Shape::legacy(h_budget, offset))); // Extract comments between generics. let lt_spans = lifetimes.iter().map(|l| { @@ -1859,7 +1880,8 @@ fn rewrite_generics(context: &RewriteContext, |&(_, ref str)| str.clone(), context.codemap.span_after(span, "<"), span.hi); - let list_str = try_opt!(format_item_list(items, h_budget, offset, context.config)); + let list_str = + try_opt!(format_item_list(items, Shape::legacy(h_budget, offset), context.config)); Some(if context.config.spaces_within_angle_brackets { format!("< {} >", list_str) @@ -1870,8 +1892,7 @@ fn rewrite_generics(context: &RewriteContext, fn rewrite_trait_bounds(context: &RewriteContext, type_param_bounds: &ast::TyParamBounds, - indent: Indent, - width: usize) + shape: Shape) -> Option { let bounds: &[_] = type_param_bounds; @@ -1880,7 +1901,7 @@ fn rewrite_trait_bounds(context: &RewriteContext, } let bound_str = try_opt!(bounds.iter() - .map(|ty_bound| ty_bound.rewrite(&context, width, indent)) + .map(|ty_bound| ty_bound.rewrite(&context, shape)) .intersperse(Some(" + ".to_string())) .collect::>()); @@ -1894,8 +1915,7 @@ fn rewrite_where_clause(context: &RewriteContext, where_clause: &ast::WhereClause, config: &Config, brace_style: BraceStyle, - indent: Indent, - width: usize, + shape: Shape, density: Density, terminator: &str, allow_trailing_comma: bool, @@ -1911,10 +1931,10 @@ fn rewrite_where_clause(context: &RewriteContext, }; let offset = match context.config.where_pred_indent { - BlockIndentStyle::Inherit => indent + extra_indent, - BlockIndentStyle::Tabbed => indent + extra_indent.block_indent(config), + BlockIndentStyle::Inherit => shape.indent + extra_indent, + BlockIndentStyle::Tabbed => shape.indent + extra_indent.block_indent(config), // 6 = "where ".len() - BlockIndentStyle::Visual => indent + extra_indent + 6, + BlockIndentStyle::Visual => shape.indent + extra_indent + 6, }; // FIXME: if where_pred_indent != Visual, then the budgets below might // be out by a char or two. @@ -1931,7 +1951,7 @@ fn rewrite_where_clause(context: &RewriteContext, terminator, |pred| span_for_where_pred(pred).lo, |pred| span_for_where_pred(pred).hi, - |pred| pred.rewrite(context, budget, offset), + |pred| pred.rewrite(context, Shape::legacy(budget, offset)), span_start, span_end); let item_vec = items.collect::>(); @@ -1944,8 +1964,7 @@ fn rewrite_where_clause(context: &RewriteContext, tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::from_bool(use_trailing_comma), - indent: offset, - width: budget, + shape: Shape::legacy(budget, offset), ends_with_newline: true, config: context.config, }; @@ -1965,9 +1984,9 @@ fn rewrite_where_clause(context: &RewriteContext, terminator.len() }; if density == Density::Tall || preds_str.contains('\n') || - indent.width() + " where ".len() + preds_str.len() + end_length > width { + shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width { Some(format!("\n{}where {}", - (indent + extra_indent).to_string(context.config), + (shape.indent + extra_indent).to_string(context.config), preds_str)) } else { Some(format!(" where {}", preds_str)) @@ -1990,8 +2009,7 @@ fn format_generics(context: &RewriteContext, -> Option { let mut result = try_opt!(rewrite_generics(context, generics, - offset, - context.config.max_width, + Shape::legacy(context.config.max_width, offset), generics_offset, span)); @@ -2001,8 +2019,8 @@ fn format_generics(context: &RewriteContext, &generics.where_clause, context.config, brace_style, - context.block_indent, - budget, + Shape::legacy(budget, + context.block_indent), Density::Tall, terminator, true, diff --git a/src/lib.rs b/src/lib.rs index 9e80e8f1b6b7..3caeaf92ebb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -201,6 +201,50 @@ impl Sub for Indent { } } +#[derive(Copy, Clone, Debug)] +pub struct Shape { + pub width: usize, + pub indent: Indent, +} + +impl Shape { + pub fn indented(indent: Indent, config: &Config) -> Shape { + Shape { + width: config.max_width, + indent: indent, + } + } + + /// `indent` is the indentation of the first line. The next lines + /// should begin with at least `indent` spaces (except backwards + /// indentation). The first line should not begin with indentation. + /// `width` is the maximum number of characters on the last line + /// (excluding `indent`). The width of other lines is not limited by + /// `width`. + /// Note that in reality, we sometimes use width for lines other than the + /// last (i.e., we are conservative). + // .......*-------* + // | | + // | *-* + // *-----| + // |<------------>| max width + // |<---->| indent + // |<--->| width + pub fn legacy(width: usize, indent: Indent) -> Shape { + Shape { + width: width, + indent: indent, + } + } + + pub fn sub_width(self, width: usize) -> Shape { + Shape { + width: self.width - width, + indent: self.indent, + } + } +} + pub enum ErrorKind { // Line has exceeded character limit (found, maximum) LineOverflow(usize, usize), diff --git a/src/lists.rs b/src/lists.rs index 9af4fc238d6d..2c78a1040c86 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -13,7 +13,7 @@ use std::iter::Peekable; use syntax::codemap::{self, CodeMap, BytePos}; -use Indent; +use {Indent, Shape}; use comment::{FindUncommented, rewrite_comment, find_comment_end}; use config::Config; @@ -59,50 +59,38 @@ pub struct ListFormatting<'a> { pub tactic: DefinitiveListTactic, pub separator: &'a str, pub trailing_separator: SeparatorTactic, - pub indent: Indent, - pub width: usize, + pub shape: Shape, // Non-expressions, e.g. items, will have a new line at the end of the list. // Important for comment styles. pub ends_with_newline: bool, pub config: &'a Config, } -pub fn format_fn_args(items: I, width: usize, offset: Indent, config: &Config) -> Option +pub fn format_fn_args(items: I, shape: Shape, config: &Config) -> Option where I: Iterator { list_helper(items, - width, - offset, + shape, config, ListTactic::LimitedHorizontalVertical(config.fn_call_width)) } -pub fn format_item_list(items: I, - width: usize, - offset: Indent, - config: &Config) - -> Option +pub fn format_item_list(items: I, shape: Shape, config: &Config) -> Option where I: Iterator { - list_helper(items, width, offset, config, ListTactic::HorizontalVertical) + list_helper(items, shape, config, ListTactic::HorizontalVertical) } -pub fn list_helper(items: I, - width: usize, - offset: Indent, - config: &Config, - tactic: ListTactic) - -> Option +pub fn list_helper(items: I, shape: Shape, config: &Config, tactic: ListTactic) -> Option where I: Iterator { let item_vec: Vec<_> = items.collect(); - let tactic = definitive_tactic(&item_vec, tactic, width); + let tactic = definitive_tactic(&item_vec, tactic, shape.width); let fmt = ListFormatting { tactic: tactic, separator: ",", trailing_separator: SeparatorTactic::Never, - indent: offset, - width: width, + shape: shape, ends_with_newline: false, config: config, }; @@ -201,7 +189,7 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option let mut iter = items.into_iter().enumerate().peekable(); let mut line_len = 0; - let indent_str = &formatting.indent.to_string(formatting.config); + let indent_str = &formatting.shape.indent.to_string(formatting.config); while let Some((i, item)) = iter.next() { let item = item.as_ref(); let inner_item = try_opt!(item.item.as_ref()); @@ -234,7 +222,7 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option let total_width = total_item_width(item) + item_sep_len; // 1 is space between separator and item. - if line_len > 0 && line_len + 1 + total_width > formatting.width { + if line_len > 0 && line_len + 1 + total_width > formatting.shape.width { result.push('\n'); result.push_str(indent_str); line_len = 0; @@ -255,12 +243,8 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option // Block style in non-vertical mode. let block_mode = tactic != DefinitiveListTactic::Vertical; // Width restriction is only relevant in vertical mode. - let max_width = formatting.width; - let comment = try_opt!(rewrite_comment(comment, - block_mode, - max_width, - formatting.indent, - formatting.config)); + let comment = + try_opt!(rewrite_comment(comment, block_mode, formatting.shape, formatting.config)); result.push_str(&comment); if tactic == DefinitiveListTactic::Vertical { @@ -276,11 +260,11 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option // Post-comments if tactic != DefinitiveListTactic::Vertical && item.post_comment.is_some() { let comment = item.post_comment.as_ref().unwrap(); - let formatted_comment = try_opt!(rewrite_comment(comment, - true, - formatting.width, - Indent::empty(), - formatting.config)); + let formatted_comment = + try_opt!(rewrite_comment(comment, + true, + Shape::legacy(formatting.shape.width, Indent::empty()), + formatting.config)); result.push(' '); result.push_str(&formatted_comment); @@ -292,8 +276,8 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option if tactic == DefinitiveListTactic::Vertical && item.post_comment.is_some() { // 1 = space between item and comment. - let width = formatting.width.checked_sub(item_last_line_width + 1).unwrap_or(1); - let mut offset = formatting.indent; + let width = formatting.shape.width.checked_sub(item_last_line_width + 1).unwrap_or(1); + let mut offset = formatting.shape.indent; offset.alignment += item_last_line_width + 1; let comment = item.post_comment.as_ref().unwrap(); @@ -303,8 +287,10 @@ pub fn write_list(items: I, formatting: &ListFormatting) -> Option comment.trim().contains('\n') || comment.trim().len() > width; - let formatted_comment = - try_opt!(rewrite_comment(comment, block_style, width, offset, formatting.config)); + let formatted_comment = try_opt!(rewrite_comment(comment, + block_style, + Shape::legacy(width, offset), + formatting.config)); result.push(' '); result.push_str(&formatted_comment); diff --git a/src/macros.rs b/src/macros.rs index 412fb15cede1..3a184d242ef5 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -26,7 +26,7 @@ use syntax::parse::tts_to_parser; use syntax::symbol; use syntax::util::ThinVec; -use Indent; +use Shape; use codemap::SpanUtils; use rewrite::{Rewrite, RewriteContext}; use expr::{rewrite_call, rewrite_array}; @@ -62,13 +62,12 @@ impl MacroStyle { pub fn rewrite_macro(mac: &ast::Mac, extra_ident: Option, context: &RewriteContext, - width: usize, - offset: Indent, + shape: Shape, position: MacroPosition) -> Option { if context.config.use_try_shorthand { if let Some(expr) = convert_try_mac(mac, context) { - return expr.rewrite(context, width, offset); + return expr.rewrite(context, shape); } } @@ -146,11 +145,12 @@ pub fn rewrite_macro(mac: &ast::Mac, match style { MacroStyle::Parens => { // Format macro invocation as function call. - rewrite_call(context, ¯o_name, &expr_vec, mac.span, width, offset) - .map(|rw| match position { + rewrite_call(context, ¯o_name, &expr_vec, mac.span, shape).map(|rw| { + match position { MacroPosition::Item => format!("{};", rw), _ => rw, - }) + } + }) } MacroStyle::Brackets => { // Format macro invocation as array literal. @@ -161,8 +161,9 @@ pub fn rewrite_macro(mac: &ast::Mac, original_style.opener()), mac.span.hi - BytePos(1)), context, - try_opt!(width.checked_sub(extra_offset)), - offset + extra_offset)); + Shape::legacy(try_opt!(shape.width + .checked_sub(extra_offset)), + shape.indent + extra_offset))); Some(format!("{}{}", macro_name, rewrite)) } diff --git a/src/missed_spans.rs b/src/missed_spans.rs index eff3fd6c573a..9967a8a4ab86 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -12,6 +12,7 @@ use config::WriteMode; use visitor::FmtVisitor; use syntax::codemap::{self, BytePos, Span, Pos}; use comment::{CodeCharKind, CommentCodeSlices, rewrite_comment}; +use Shape; impl<'a> FmtVisitor<'a> { fn output_at_start(&self) -> bool { @@ -143,8 +144,8 @@ impl<'a> FmtVisitor<'a> { self.buffer.push_str(&rewrite_comment(subslice, false, - comment_width, - self.block_indent, + Shape::legacy(comment_width, + self.block_indent), self.config) .unwrap()); diff --git a/src/patterns.rs b/src/patterns.rs index 03598a1971b7..7346dc08010c 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use Indent; +use Shape; use codemap::SpanUtils; use rewrite::{Rewrite, RewriteContext}; use utils::{wrap_str, format_mutability}; @@ -23,9 +23,9 @@ use syntax::ptr; use syntax::codemap::{self, BytePos, Span}; impl Rewrite for Pat { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match self.node { - PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, width, offset), + PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape), PatKind::Ident(binding_mode, ident, ref sub_pat) => { let (prefix, mutability) = match binding_mode { BindingMode::ByRef(mutability) => ("ref ", mutability), @@ -36,60 +36,54 @@ impl Rewrite for Pat { let sub_pat = match *sub_pat { Some(ref p) => { // 3 - ` @ `. - let width = try_opt!(width.checked_sub(prefix.len() + mut_infix.len() + - id_str.len() + - 3)); - format!(" @ {}", try_opt!(p.rewrite(context, width, offset))) + let width = try_opt!(shape.width + .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 3)); + format!(" @ {}", + try_opt!(p.rewrite(context, Shape::legacy(width, shape.indent)))) } None => "".to_owned(), }; let result = format!("{}{}{}{}", prefix, mut_infix, id_str, sub_pat); - wrap_str(result, context.config.max_width, width, offset) + wrap_str(result, context.config.max_width, shape) } PatKind::Wild => { - if 1 <= width { + if 1 <= shape.width { Some("_".to_owned()) } else { None } } PatKind::Range(ref lhs, ref rhs) => { - rewrite_pair(&**lhs, &**rhs, "", "...", "", context, width, offset) + rewrite_pair(&**lhs, &**rhs, "", "...", "", context, shape) } PatKind::Ref(ref pat, mutability) => { let prefix = format!("&{}", format_mutability(mutability)); - rewrite_unary_prefix(context, &prefix, &**pat, width, offset) + rewrite_unary_prefix(context, &prefix, &**pat, shape) } PatKind::Tuple(ref items, dotdot_pos) => { - rewrite_tuple_pat(items, dotdot_pos, None, self.span, context, width, offset) + rewrite_tuple_pat(items, dotdot_pos, None, self.span, context, shape) } PatKind::Path(ref q_self, ref path) => { - rewrite_path(context, - PathContext::Expr, - q_self.as_ref(), - path, - width, - offset) + rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape) } PatKind::TupleStruct(ref path, ref pat_vec, dotdot_pos) => { let path_str = - try_opt!(rewrite_path(context, PathContext::Expr, None, path, width, offset)); + try_opt!(rewrite_path(context, PathContext::Expr, None, path, shape)); rewrite_tuple_pat(pat_vec, dotdot_pos, Some(path_str), self.span, context, - width, - offset) + shape) } - PatKind::Lit(ref expr) => expr.rewrite(context, width, offset), + PatKind::Lit(ref expr) => expr.rewrite(context, shape), PatKind::Slice(ref prefix, ref slice_pat, ref suffix) => { // Rewrite all the sub-patterns. - let prefix = prefix.iter().map(|p| p.rewrite(context, width, offset)); + let prefix = prefix.iter().map(|p| p.rewrite(context, shape)); let slice_pat = slice_pat.as_ref() - .map(|p| Some(format!("{}..", try_opt!(p.rewrite(context, width, offset))))); - let suffix = suffix.iter().map(|p| p.rewrite(context, width, offset)); + .map(|p| Some(format!("{}..", try_opt!(p.rewrite(context, shape))))); + let suffix = suffix.iter().map(|p| p.rewrite(context, shape)); // Munge them together. let pats: Option> = prefix.chain(slice_pat.into_iter()) @@ -105,32 +99,33 @@ impl Rewrite for Pat { } else { format!("[{}]", pats.join(", ")) }; - wrap_str(result, context.config.max_width, width, offset) + wrap_str(result, context.config.max_width, shape) } PatKind::Struct(ref path, ref fields, elipses) => { - let path = - try_opt!(rewrite_path(context, PathContext::Expr, None, path, width, offset)); + let path = try_opt!(rewrite_path(context, PathContext::Expr, None, path, shape)); let (elipses_str, terminator) = if elipses { (", ..", "..") } else { ("", "}") }; // 5 = `{` plus space before and after plus `}` plus space before. - let budget = try_opt!(width.checked_sub(path.len() + 5 + elipses_str.len())); + let budget = try_opt!(shape.width.checked_sub(path.len() + 5 + elipses_str.len())); // FIXME Using visual indenting, should use block or visual to match // struct lit preference (however, in practice I think it is rare // for struct patterns to be multi-line). // 3 = `{` plus space before and after. - let offset = offset + path.len() + 3; + let offset = shape.indent + path.len() + 3; - let items = itemize_list(context.codemap, - fields.iter(), - terminator, - |f| f.span.lo, - |f| f.span.hi, - |f| f.node.rewrite(context, budget, offset), - context.codemap.span_after(self.span, "{"), - self.span.hi); - let mut field_string = - try_opt!(format_item_list(items, budget, offset, context.config)); + let items = + itemize_list(context.codemap, + fields.iter(), + terminator, + |f| f.span.lo, + |f| f.span.hi, + |f| f.node.rewrite(context, Shape::legacy(budget, offset)), + context.codemap.span_after(self.span, "{"), + self.span.hi); + let mut field_string = try_opt!(format_item_list(items, + Shape::legacy(budget, offset), + context.config)); if elipses { if field_string.contains('\n') { field_string.push_str(",\n"); @@ -152,25 +147,21 @@ impl Rewrite for Pat { } // FIXME(#819) format pattern macros. PatKind::Mac(..) => { - wrap_str(context.snippet(self.span), - context.config.max_width, - width, - offset) + wrap_str(context.snippet(self.span), context.config.max_width, shape) } } } } impl Rewrite for FieldPat { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - let pat = self.pat.rewrite(context, width, offset); + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + let pat = self.pat.rewrite(context, shape); if self.is_shorthand { pat } else { wrap_str(format!("{}: {}", self.ident.to_string(), try_opt!(pat)), context.config.max_width, - width, - offset) + shape) } } } @@ -182,9 +173,9 @@ enum TuplePatField<'a> { } impl<'a> Rewrite for TuplePatField<'a> { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match *self { - TuplePatField::Pat(ref p) => p.rewrite(context, width, offset), + TuplePatField::Pat(ref p) => p.rewrite(context, shape), TuplePatField::Dotdot(_) => Some("..".to_string()), } } @@ -204,8 +195,7 @@ fn rewrite_tuple_pat(pats: &[ptr::P], path_str: Option, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let mut pat_vec: Vec<_> = pats.into_iter().map(|x| TuplePatField::Pat(x)).collect(); @@ -230,18 +220,19 @@ fn rewrite_tuple_pat(pats: &[ptr::P], let path_len = path_str.as_ref().map(|p| p.len()).unwrap_or(0); // 2 = "()".len(), 3 = "(,)".len() - let width = try_opt!(width.checked_sub(path_len + if add_comma { 3 } else { 2 })); + let width = try_opt!(shape.width.checked_sub(path_len + if add_comma { 3 } else { 2 })); // 1 = "(".len() - let offset = offset + path_len + 1; - let mut items: Vec<_> = itemize_list(context.codemap, - pat_vec.iter(), - if add_comma { ",)" } else { ")" }, - |item| item.span().lo, - |item| item.span().hi, - |item| item.rewrite(context, width, offset), - context.codemap.span_after(span, "("), - span.hi - BytePos(1)) - .collect(); + let offset = shape.indent + path_len + 1; + let mut items: Vec<_> = + itemize_list(context.codemap, + pat_vec.iter(), + if add_comma { ",)" } else { ")" }, + |item| item.span().lo, + |item| item.span().hi, + |item| item.rewrite(context, Shape::legacy(width, offset)), + context.codemap.span_after(span, "("), + span.hi - BytePos(1)) + .collect(); // Condense wildcard string suffix into a single .. let wildcard_suffix_len = count_wildcard_suffix_len(&items); @@ -251,9 +242,11 @@ fn rewrite_tuple_pat(pats: &[ptr::P], items[new_item_count - 1].item = Some("..".to_owned()); let da_iter = items.into_iter().take(new_item_count); - try_opt!(format_item_list(da_iter, width, offset, context.config)) + try_opt!(format_item_list(da_iter, Shape::legacy(width, offset), context.config)) } else { - try_opt!(format_item_list(items.into_iter(), width, offset, context.config)) + try_opt!(format_item_list(items.into_iter(), + Shape::legacy(width, offset), + context.config)) }; match path_str { diff --git a/src/rewrite.rs b/src/rewrite.rs index 247b1df1c3fa..3c69e2c3c451 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -13,18 +13,12 @@ use syntax::codemap::{CodeMap, Span}; use syntax::parse::ParseSess; -use Indent; +use {Indent, Shape}; use config::Config; pub trait Rewrite { - /// Rewrite self into offset and width. - /// `offset` is the indentation of the first line. The next lines - /// should begin with a least `offset` spaces (except backwards - /// indentation). The first line should not begin with indentation. - /// `width` is the maximum number of characters on the last line - /// (excluding offset). The width of other lines is not limited by - /// `width`. - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option; + /// Rewrite self into shape. + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option; } #[derive(Clone)] diff --git a/src/string.rs b/src/string.rs index 71d8f8415f0c..014830a9155a 100644 --- a/src/string.rs +++ b/src/string.rs @@ -13,7 +13,7 @@ use unicode_segmentation::UnicodeSegmentation; use regex::Regex; -use Indent; +use Shape; use config::Config; use utils::wrap_str; @@ -24,8 +24,7 @@ pub struct StringFormat<'a> { pub closer: &'a str, pub line_start: &'a str, pub line_end: &'a str, - pub width: usize, - pub offset: Indent, + pub shape: Shape, pub trim_end: bool, pub config: &'a Config, } @@ -37,7 +36,7 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option let stripped_str = re.replace_all(orig, "$1"); let graphemes = UnicodeSegmentation::graphemes(&*stripped_str, false).collect::>(); - let indent = fmt.offset.to_string(fmt.config); + let indent = fmt.shape.indent.to_string(fmt.config); let punctuation = ":,;."; // `cur_start` is the position in `orig` of the start of the current line. @@ -50,7 +49,7 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option let ender_length = fmt.line_end.len(); // If we cannot put at least a single character per line, the rewrite won't // succeed. - let max_chars = try_opt!(fmt.width.checked_sub(fmt.opener.len() + ender_length + 1)) + 1; + let max_chars = try_opt!(fmt.shape.width.checked_sub(fmt.opener.len() + ender_length + 1)) + 1; // Snip a line at a time from `orig` until it is used up. Push the snippet // onto result. @@ -118,7 +117,7 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option } result.push_str(fmt.closer); - wrap_str(result, fmt.config.max_width, fmt.width, fmt.offset) + wrap_str(result, fmt.config.max_width, fmt.shape) } #[cfg(test)] @@ -133,8 +132,7 @@ mod test { closer: "\"", line_start: " ", line_end: "\\", - width: 2, - offset: ::Indent::empty(), + shape: ::Shape::legacy(2, ::Indent::empty()), trim_end: false, config: &config, }; diff --git a/src/types.rs b/src/types.rs index acc9c7c6cb51..cce487cb2ea8 100644 --- a/src/types.rs +++ b/src/types.rs @@ -17,7 +17,7 @@ use syntax::codemap::{self, Span, BytePos}; use syntax::print::pprust; use syntax::symbol::keywords; -use {Indent, Spanned}; +use {Shape, Spanned}; use codemap::SpanUtils; use lists::{format_item_list, itemize_list, format_fn_args}; use rewrite::{Rewrite, RewriteContext}; @@ -38,8 +38,7 @@ pub fn rewrite_path(context: &RewriteContext, path_context: PathContext, qself: Option<&ast::QSelf>, path: &ast::Path, - width: usize, - offset: Indent) + shape: Shape) -> Option { let skip_count = qself.map_or(0, |x| x.position); @@ -58,7 +57,7 @@ pub fn rewrite_path(context: &RewriteContext, result.push_str(" ") } - let fmt_ty = try_opt!(qself.ty.rewrite(context, width, offset)); + let fmt_ty = try_opt!(qself.ty.rewrite(context, shape)); result.push_str(&fmt_ty); if skip_count > 0 { @@ -67,9 +66,9 @@ pub fn rewrite_path(context: &RewriteContext, result.push_str("::"); } - let extra_offset = extra_offset(&result, offset); + let extra_offset = extra_offset(&result, shape.indent); // 3 = ">::".len() - let budget = try_opt!(width.checked_sub(extra_offset + 3)); + let budget = try_opt!(shape.width.checked_sub(extra_offset + 3)); result = try_opt!(rewrite_path_segments(PathContext::Type, result, @@ -77,8 +76,8 @@ pub fn rewrite_path(context: &RewriteContext, span_lo, path.span.hi, context, - budget, - offset + extra_offset)); + Shape::legacy(budget, + shape.indent + extra_offset))); } if context.config.spaces_within_angle_brackets { @@ -89,16 +88,15 @@ pub fn rewrite_path(context: &RewriteContext, span_lo = qself.ty.span.hi + BytePos(1); } - let extra_offset = extra_offset(&result, offset); - let budget = try_opt!(width.checked_sub(extra_offset)); + let extra_offset = extra_offset(&result, shape.indent); + let budget = try_opt!(shape.width.checked_sub(extra_offset)); rewrite_path_segments(path_context, result, path.segments.iter().skip(skip_count), span_lo, path.span.hi, context, - budget, - offset + extra_offset) + Shape::legacy(budget, shape.indent + extra_offset)) } fn rewrite_path_segments<'a, I>(path_context: PathContext, @@ -107,8 +105,7 @@ fn rewrite_path_segments<'a, I>(path_context: PathContext, mut span_lo: BytePos, span_hi: BytePos, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option where I: Iterator { @@ -125,16 +122,15 @@ fn rewrite_path_segments<'a, I>(path_context: PathContext, buffer.push_str("::"); } - let extra_offset = extra_offset(&buffer, offset); - let remaining_width = try_opt!(width.checked_sub(extra_offset)); - let new_offset = offset + extra_offset; + let extra_offset = extra_offset(&buffer, shape.indent); + let remaining_width = try_opt!(shape.width.checked_sub(extra_offset)); + let new_offset = shape.indent + extra_offset; let segment_string = try_opt!(rewrite_segment(path_context, segment, &mut span_lo, span_hi, context, - remaining_width, - new_offset)); + Shape::legacy(remaining_width, new_offset))); buffer.push_str(&segment_string); } @@ -160,14 +156,15 @@ impl<'a> SegmentParam<'a> { } impl<'a> Rewrite for SegmentParam<'a> { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match *self { - SegmentParam::LifeTime(lt) => lt.rewrite(context, width, offset), - SegmentParam::Type(ty) => ty.rewrite(context, width, offset), + SegmentParam::LifeTime(lt) => lt.rewrite(context, shape), + SegmentParam::Type(ty) => ty.rewrite(context, shape), SegmentParam::Binding(binding) => { let mut result = format!("{} = ", binding.ident); - let budget = try_opt!(width.checked_sub(result.len())); - let rewrite = try_opt!(binding.ty.rewrite(context, budget, offset + result.len())); + 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()))); result.push_str(&rewrite); Some(result) } @@ -190,12 +187,11 @@ fn rewrite_segment(path_context: PathContext, span_lo: &mut BytePos, span_hi: BytePos, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let ident_len = segment.identifier.to_string().len(); - let width = try_opt!(width.checked_sub(ident_len)); - let offset = offset + ident_len; + let width = try_opt!(shape.width.checked_sub(ident_len)); + let offset = shape.indent + ident_len; let params = if let Some(ref params) = segment.parameters { match **params { @@ -222,18 +218,21 @@ fn rewrite_segment(path_context: PathContext, // 1 for > let list_width = try_opt!(width.checked_sub(extra_offset + 1)); - let items = - itemize_list(context.codemap, - param_list.into_iter(), - ">", - |param| param.get_span().lo, - |param| param.get_span().hi, - |seg| seg.rewrite(context, list_width, offset + extra_offset), - list_lo, - span_hi); + let items = itemize_list(context.codemap, + param_list.into_iter(), + ">", + |param| param.get_span().lo, + |param| param.get_span().hi, + |seg| { + seg.rewrite(context, + Shape::legacy(list_width, + offset + extra_offset)) + }, + list_lo, + span_hi); let list_str = try_opt!(format_item_list(items, - list_width, - offset + extra_offset, + Shape::legacy(list_width, + offset + extra_offset), context.config)); // Update position of last bracket. @@ -255,8 +254,7 @@ fn rewrite_segment(path_context: PathContext, false, data.span, context, - width, - offset)) + Shape::legacy(width, offset))) } _ => String::new(), } @@ -272,8 +270,7 @@ fn format_function_type<'a, I>(inputs: I, variadic: bool, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option where I: ExactSizeIterator, ::Item: Deref, @@ -297,44 +294,45 @@ fn format_function_type<'a, I>(inputs: I, }; // 2 for () - let budget = try_opt!(width.checked_sub(2)); + let budget = try_opt!(shape.width.checked_sub(2)); // 1 for ( - let offset = offset + 1; + let offset = shape.indent + 1; let list_lo = context.codemap.span_after(span, "("); - let items = - itemize_list(context.codemap, - // FIXME Would be nice to avoid this allocation, - // but I couldn't get the types to work out. - inputs.map(|i| ArgumentKind::Regular(Box::new(i))) - .chain(variadic_arg), - ")", - |arg| match *arg { - ArgumentKind::Regular(ref ty) => ty.span().lo, - ArgumentKind::Variadic(start) => start, - }, - |arg| match *arg { - ArgumentKind::Regular(ref ty) => ty.span().hi, - ArgumentKind::Variadic(start) => start + BytePos(3), - }, - |arg| match *arg { - ArgumentKind::Regular(ref ty) => ty.rewrite(context, budget, offset), - ArgumentKind::Variadic(_) => Some("...".to_owned()), - }, - list_lo, - span.hi); + let items = itemize_list(context.codemap, + // FIXME Would be nice to avoid this allocation, + // but I couldn't get the types to work out. + inputs.map(|i| ArgumentKind::Regular(Box::new(i))) + .chain(variadic_arg), + ")", + |arg| match *arg { + ArgumentKind::Regular(ref ty) => ty.span().lo, + ArgumentKind::Variadic(start) => start, + }, + |arg| match *arg { + ArgumentKind::Regular(ref ty) => ty.span().hi, + ArgumentKind::Variadic(start) => start + BytePos(3), + }, + |arg| match *arg { + ArgumentKind::Regular(ref ty) => { + ty.rewrite(context, Shape::legacy(budget, offset)) + } + ArgumentKind::Variadic(_) => Some("...".to_owned()), + }, + list_lo, + span.hi); - let list_str = try_opt!(format_fn_args(items, budget, offset, context.config)); + let list_str = try_opt!(format_fn_args(items, Shape::legacy(budget, offset), context.config)); let output = match *output { FunctionRetTy::Ty(ref ty) => { - let budget = try_opt!(width.checked_sub(4)); - let type_str = try_opt!(ty.rewrite(context, budget, offset + 4)); + let budget = try_opt!(shape.width.checked_sub(4)); + let type_str = try_opt!(ty.rewrite(context, Shape::legacy(budget, offset + 4))); format!(" -> {}", type_str) } FunctionRetTy::Default(..) => String::new(), }; - let infix = if !output.is_empty() && output.len() + list_str.len() > width { + let infix = if !output.is_empty() && output.len() + list_str.len() > shape.width { format!("\n{}", (offset - 1).to_string(context.config)) } else { String::new() @@ -357,35 +355,33 @@ fn type_bound_colon(context: &RewriteContext) -> &'static str { } impl Rewrite for ast::WherePredicate { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { // TODO: dead spans? let result = match *self { ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { ref bound_lifetimes, ref bounded_ty, ref bounds, .. }) => { - let type_str = try_opt!(bounded_ty.rewrite(context, width, offset)); + let type_str = try_opt!(bounded_ty.rewrite(context, shape)); let colon = type_bound_colon(context); if !bound_lifetimes.is_empty() { let lifetime_str: String = try_opt!(bound_lifetimes.iter() .map(|lt| { - lt.rewrite(context, - width, - offset) + lt.rewrite(context, shape) }) .intersperse(Some(", ".to_string())) .collect()); // 6 = "for<> ".len() let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6; - let budget = try_opt!(width.checked_sub(used_width)); + let budget = try_opt!(shape.width.checked_sub(used_width)); let bounds_str: String = try_opt!(bounds.iter() .map(|ty_bound| { ty_bound.rewrite(context, - budget, - offset + used_width) + Shape::legacy(budget, + shape.indent + used_width)) }) .intersperse(Some(" + ".to_string())) .collect()); @@ -397,12 +393,12 @@ impl Rewrite for ast::WherePredicate { } } else { let used_width = type_str.len() + colon.len(); - let budget = try_opt!(width.checked_sub(used_width)); + let budget = try_opt!(shape.width.checked_sub(used_width)); let bounds_str: String = try_opt!(bounds.iter() .map(|ty_bound| { ty_bound.rewrite(context, - budget, - offset + used_width) + Shape::legacy(budget, + shape.indent + used_width)) }) .intersperse(Some(" + ".to_string())) .collect()); @@ -413,91 +409,92 @@ impl Rewrite for ast::WherePredicate { ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate { ref lifetime, ref bounds, .. }) => { - try_opt!(rewrite_bounded_lifetime(lifetime, bounds.iter(), context, width, offset)) + try_opt!(rewrite_bounded_lifetime(lifetime, bounds.iter(), context, shape)) } ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { ref lhs_ty, ref rhs_ty, .. }) => { - let lhs_ty_str = try_opt!(lhs_ty.rewrite(context, width, offset)); + let lhs_ty_str = try_opt!(lhs_ty.rewrite(context, shape)); // 3 = " = ".len() let used_width = 3 + lhs_ty_str.len(); - let budget = try_opt!(width.checked_sub(used_width)); - let rhs_ty_str = try_opt!(rhs_ty.rewrite(context, budget, offset + used_width)); + 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))); format!("{} = {}", lhs_ty_str, rhs_ty_str) } }; - wrap_str(result, context.config.max_width, width, offset) + wrap_str(result, context.config.max_width, shape) } } impl Rewrite for ast::LifetimeDef { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, width, offset) + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, shape) } } fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime, bounds: I, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option where I: ExactSizeIterator { - let result = try_opt!(lt.rewrite(context, width, offset)); + let result = try_opt!(lt.rewrite(context, shape)); if bounds.len() == 0 { Some(result) } else { let appendix: Vec<_> = try_opt!(bounds.into_iter() - .map(|b| b.rewrite(context, width, offset)) + .map(|b| b.rewrite(context, shape)) .collect()); let colon = type_bound_colon(context); let result = format!("{}{}{}", result, colon, appendix.join(" + ")); - wrap_str(result, context.config.max_width, width, offset) + wrap_str(result, context.config.max_width, shape) } } impl Rewrite for ast::TyParamBound { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match *self { ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => { - tref.rewrite(context, width, offset) + tref.rewrite(context, shape) } ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::Maybe) => { - let budget = try_opt!(width.checked_sub(1)); - Some(format!("?{}", try_opt!(tref.rewrite(context, budget, offset + 1)))) + let budget = try_opt!(shape.width.checked_sub(1)); + Some(format!("?{}", + try_opt!(tref.rewrite(context, + Shape::legacy(budget, shape.indent + 1))))) } - ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, width, offset), + ast::TyParamBound::RegionTyParamBound(ref l) => l.rewrite(context, shape), } } } impl Rewrite for ast::Lifetime { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { wrap_str(pprust::lifetime_to_string(self), context.config.max_width, - width, - offset) + shape) } } impl Rewrite for ast::TyParamBounds { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let joiner = match context.config.type_punctuation_density { TypeDensity::Compressed => "+", TypeDensity::Wide => " + ", }; let strs: Vec<_> = try_opt!(self.iter() - .map(|b| b.rewrite(context, width, offset)) + .map(|b| b.rewrite(context, shape)) .collect()); - wrap_str(strs.join(joiner), context.config.max_width, width, offset) + wrap_str(strs.join(joiner), context.config.max_width, shape) } } impl Rewrite for ast::TyParam { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let mut result = String::with_capacity(128); result.push_str(&self.ident.to_string()); if !self.bounds.is_empty() { @@ -511,7 +508,7 @@ impl Rewrite for ast::TyParam { let bounds: String = try_opt!(self.bounds .iter() - .map(|ty_bound| ty_bound.rewrite(context, width, offset)) + .map(|ty_bound| ty_bound.rewrite(context, shape)) .intersperse(Some(" + ".to_string())) .collect()); @@ -524,29 +521,31 @@ impl Rewrite for ast::TyParam { TypeDensity::Wide => " = ", }; result.push_str(eq_str); - let budget = try_opt!(width.checked_sub(result.len())); - let rewrite = try_opt!(def.rewrite(context, budget, offset + result.len())); + let budget = try_opt!(shape.width.checked_sub(result.len())); + let rewrite = + try_opt!(def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))); result.push_str(&rewrite); } - wrap_str(result, context.config.max_width, width, offset) + wrap_str(result, context.config.max_width, shape) } } impl Rewrite for ast::PolyTraitRef { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { if !self.bound_lifetimes.is_empty() { let lifetime_str: String = try_opt!(self.bound_lifetimes .iter() - .map(|lt| lt.rewrite(context, width, offset)) + .map(|lt| lt.rewrite(context, shape)) .intersperse(Some(", ".to_string())) .collect()); // 6 is "for<> ".len() let extra_offset = lifetime_str.len() + 6; - let max_path_width = try_opt!(width.checked_sub(extra_offset)); + let max_path_width = try_opt!(shape.width.checked_sub(extra_offset)); let path_str = try_opt!(self.trait_ref - .rewrite(context, max_path_width, offset + extra_offset)); + .rewrite(context, + Shape::legacy(max_path_width, shape.indent + extra_offset))); Some(if context.config.spaces_within_angle_brackets && lifetime_str.len() > 0 { format!("for< {} > {}", lifetime_str, path_str) @@ -554,58 +553,64 @@ impl Rewrite for ast::PolyTraitRef { format!("for<{}> {}", lifetime_str, path_str) }) } else { - self.trait_ref.rewrite(context, width, offset) + self.trait_ref.rewrite(context, shape) } } } impl Rewrite for ast::TraitRef { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - rewrite_path(context, PathContext::Type, None, &self.path, width, offset) + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + rewrite_path(context, PathContext::Type, None, &self.path, shape) } } impl Rewrite for ast::Ty { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { match self.node { - ast::TyKind::TraitObject(ref bounds) => bounds.rewrite(context, width, offset), + ast::TyKind::TraitObject(ref bounds) => bounds.rewrite(context, shape), ast::TyKind::Ptr(ref mt) => { let prefix = match mt.mutbl { Mutability::Mutable => "*mut ", Mutability::Immutable => "*const ", }; - rewrite_unary_prefix(context, prefix, &*mt.ty, width, offset) + rewrite_unary_prefix(context, prefix, &*mt.ty, shape) } ast::TyKind::Rptr(ref lifetime, ref mt) => { let mut_str = format_mutability(mt.mutbl); let mut_len = mut_str.len(); Some(match *lifetime { Some(ref lifetime) => { - let lt_budget = try_opt!(width.checked_sub(2 + mut_len)); - let lt_str = - try_opt!(lifetime.rewrite(context, lt_budget, offset + 2 + mut_len)); + let lt_budget = try_opt!(shape.width.checked_sub(2 + mut_len)); + let lt_str = try_opt!(lifetime.rewrite(context, + Shape::legacy(lt_budget, + shape.indent + 2 + + mut_len))); let lt_len = lt_str.len(); - let budget = try_opt!(width.checked_sub(2 + mut_len + lt_len)); + let budget = try_opt!(shape.width.checked_sub(2 + mut_len + lt_len)); format!("&{} {}{}", lt_str, mut_str, try_opt!(mt.ty - .rewrite(context, budget, offset + 2 + mut_len + lt_len))) + .rewrite(context, + Shape::legacy(budget, + shape.indent + 2 + mut_len + lt_len)))) } None => { - let budget = try_opt!(width.checked_sub(1 + mut_len)); + let budget = try_opt!(shape.width.checked_sub(1 + mut_len)); format!("&{}{}", mut_str, - try_opt!(mt.ty.rewrite(context, budget, offset + 1 + mut_len))) + try_opt!(mt.ty.rewrite(context, + Shape::legacy(budget, + shape.indent + 1 + mut_len)))) } }) } // FIXME: we drop any comments here, even though it's a silly place to put // comments. ast::TyKind::Paren(ref ty) => { - let budget = try_opt!(width.checked_sub(2)); - ty.rewrite(context, budget, offset + 1) + let budget = try_opt!(shape.width.checked_sub(2)); + ty.rewrite(context, Shape::legacy(budget, shape.indent + 1)) .map(|ty_str| if context.config.spaces_within_parens { format!("( {} )", ty_str) } else { @@ -614,11 +619,11 @@ impl Rewrite for ast::Ty { } ast::TyKind::Slice(ref ty) => { let budget = if context.config.spaces_within_square_brackets { - try_opt!(width.checked_sub(4)) + try_opt!(shape.width.checked_sub(4)) } else { - try_opt!(width.checked_sub(2)) + try_opt!(shape.width.checked_sub(2)) }; - ty.rewrite(context, budget, offset + 1) + ty.rewrite(context, Shape::legacy(budget, shape.indent + 1)) .map(|ty_str| if context.config.spaces_within_square_brackets { format!("[ {} ]", ty_str) } else { @@ -626,41 +631,30 @@ impl Rewrite for ast::Ty { }) } ast::TyKind::Tup(ref items) => { - rewrite_tuple(context, - items.iter().map(|x| &**x), - self.span, - width, - offset) + rewrite_tuple(context, items.iter().map(|x| &**x), self.span, shape) } ast::TyKind::Path(ref q_self, ref path) => { - rewrite_path(context, - PathContext::Type, - q_self.as_ref(), - path, - width, - offset) + rewrite_path(context, PathContext::Type, q_self.as_ref(), path, shape) } ast::TyKind::Array(ref ty, ref repeats) => { let use_spaces = context.config.spaces_within_square_brackets; let lbr = if use_spaces { "[ " } else { "[" }; let rbr = if use_spaces { " ]" } else { "]" }; - rewrite_pair(&**ty, &**repeats, lbr, "; ", rbr, context, width, offset) + rewrite_pair(&**ty, &**repeats, lbr, "; ", rbr, context, shape) } ast::TyKind::Infer => { - if width >= 1 { + if shape.width >= 1 { Some("_".to_owned()) } else { None } } - ast::TyKind::BareFn(ref bare_fn) => { - rewrite_bare_fn(bare_fn, self.span, context, width, offset) - } + ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape), ast::TyKind::Never => Some(String::from("!")), ast::TyKind::Mac(..) => None, ast::TyKind::ImplicitSelf => Some(String::from("")), ast::TyKind::ImplTrait(ref it) => { - it.rewrite(context, width, offset).map(|it_str| format!("impl {}", it_str)) + it.rewrite(context, shape).map(|it_str| format!("impl {}", it_str)) } ast::TyKind::Typeof(..) => unreachable!(), } @@ -670,8 +664,7 @@ impl Rewrite for ast::Ty { fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, span: Span, context: &RewriteContext, - width: usize, - offset: Indent) + shape: Shape) -> Option { let mut result = String::with_capacity(128); @@ -682,7 +675,10 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, // rightward drift. If that is a problem, we could use the list stuff. result.push_str(&try_opt!(bare_fn.lifetimes .iter() - .map(|l| l.rewrite(context, try_opt!(width.checked_sub(6)), offset + 4)) + .map(|l| { + l.rewrite(context, + Shape::legacy(try_opt!(shape.width.checked_sub(6)), shape.indent + 4)) + }) .intersperse(Some(", ".to_string())) .collect::>())); result.push_str("> "); @@ -696,16 +692,15 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, result.push_str("fn"); - let budget = try_opt!(width.checked_sub(result.len())); - let indent = offset + result.len(); + let budget = try_opt!(shape.width.checked_sub(result.len())); + let indent = shape.indent + result.len(); let rewrite = try_opt!(format_function_type(bare_fn.decl.inputs.iter(), &bare_fn.decl.output, bare_fn.decl.variadic, span, context, - budget, - indent)); + Shape::legacy(budget, indent))); result.push_str(&rewrite); diff --git a/src/utils.rs b/src/utils.rs index 2f8c5db82e16..c90175710251 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -18,7 +18,7 @@ use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItemKind, NestedMet use syntax::codemap::BytePos; use syntax::abi; -use Indent; +use {Indent, Shape}; use rewrite::{Rewrite, RewriteContext}; use SKIP_ANNOTATION; @@ -253,18 +253,18 @@ macro_rules! source { // Wraps string-like values in an Option. Returns Some when the string adheres // to the Rewrite constraints defined for the Rewrite trait and else otherwise. -pub fn wrap_str>(s: S, max_width: usize, width: usize, offset: Indent) -> Option { +pub fn wrap_str>(s: S, max_width: usize, shape: Shape) -> Option { { let snippet = s.as_ref(); - if !snippet.contains('\n') && snippet.len() > width { + if !snippet.contains('\n') && snippet.len() > shape.width { return None; } else { let mut lines = snippet.lines(); - // The caller of this function has already placed `offset` + // 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(offset.width())); + let first_line_max_len = try_opt!(max_width.checked_sub(shape.indent.width())); if lines.next().unwrap().len() > first_line_max_len { return None; } @@ -278,7 +278,7 @@ pub fn wrap_str>(s: S, max_width: usize, width: usize, offset: Ind // 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() > offset.width() + width { + if snippet.lines().rev().next().unwrap().len() > shape.indent.width() + shape.width { return None; } } @@ -288,8 +288,8 @@ pub fn wrap_str>(s: S, max_width: usize, width: usize, offset: Ind } impl Rewrite for String { - fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { - wrap_str(self, context.config.max_width, width, offset).map(ToOwned::to_owned) + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { + wrap_str(self, context.config.max_width, shape).map(ToOwned::to_owned) } } diff --git a/src/visitor.rs b/src/visitor.rs index 95ec54e89eed..fd0a1f1ed21e 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -14,7 +14,7 @@ use syntax::parse::ParseSess; use strings::string_buffer::StringBuffer; -use Indent; +use {Indent, Shape}; use utils; use codemap::{LineRangeUtils, SpanUtils}; use config::Config; @@ -59,8 +59,9 @@ impl<'a> FmtVisitor<'a> { ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => { let rewrite = stmt.rewrite(&self.get_context(), - self.config.max_width - self.block_indent.width(), - self.block_indent); + Shape::legacy(self.config.max_width - + self.block_indent.width(), + self.block_indent)); self.push_rewrite(stmt.span, rewrite); } ast::StmtKind::Mac(ref mac) => { @@ -425,8 +426,7 @@ impl<'a> FmtVisitor<'a> { let rewrite = rewrite_macro(mac, ident, &self.get_context(), - width, - self.block_indent, + Shape::legacy(width, self.block_indent), pos); self.push_rewrite(mac.span, rewrite); } @@ -482,8 +482,8 @@ impl<'a> FmtVisitor<'a> { self.format_missing_with_indent(source!(self, first.span).lo); let rewrite = outers.rewrite(&self.get_context(), - self.config.max_width - self.block_indent.width(), - self.block_indent) + Shape::legacy(self.config.max_width - self.block_indent.width(), + self.block_indent)) .unwrap(); self.buffer.push_str(&rewrite); let last = outers.last().unwrap(); @@ -566,12 +566,12 @@ impl<'a> FmtVisitor<'a> { } impl<'a> Rewrite for [ast::Attribute] { - fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option { + fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { let mut result = String::new(); if self.is_empty() { return Some(result); } - let indent = offset.to_string(context.config); + let indent = shape.indent.to_string(context.config); for (i, a) in self.iter().enumerate() { let mut a_str = context.snippet(a.span); @@ -587,9 +587,10 @@ impl<'a> Rewrite for [ast::Attribute] { if !comment.is_empty() { let comment = try_opt!(rewrite_comment(comment, false, - context.config.ideal_width - - offset.width(), - offset, + Shape::legacy(context.config + .ideal_width - + shape.indent.width(), + shape.indent), context.config)); result.push_str(&indent); result.push_str(&comment); @@ -603,8 +604,9 @@ impl<'a> Rewrite for [ast::Attribute] { if a_str.starts_with("//") { a_str = try_opt!(rewrite_comment(&a_str, false, - context.config.ideal_width - offset.width(), - offset, + Shape::legacy(context.config.ideal_width - + shape.indent.width(), + shape.indent), context.config)); }