Refactor indent and width into Shape struct

This commit is contained in:
Nick Cameron 2017-01-31 08:28:48 +13:00
parent 6054f28bd2
commit 428339fdc3
15 changed files with 865 additions and 885 deletions

View file

@ -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<String> {
pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option<String> {
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::<Option<Vec<_>>>());
// 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<String> {
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::<String>()))
@ -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<String> {
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<ast::Expr>],
span: Span,
context: &RewriteContext,
width: usize,
offset: Indent)
shape: Shape)
-> Option<String> {
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)
}

View file

@ -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<String> {
// 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<String> {
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);
}

File diff suppressed because it is too large Load diff

View file

@ -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<Ordering> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
// 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,
};

View file

@ -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<String> {
debug!("Local::rewrite {:?} {} {:?}", self, width, offset);
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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::<Vec<_>>();
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::<Vec<_>>();
// 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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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::<Option<String>>());
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
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::<Option<Vec<_>>>());
// 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<String> {
@ -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<String> {
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::<Option<String>>());
@ -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::<Vec<_>>();
@ -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<String> {
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,

View file

@ -201,6 +201,50 @@ impl Sub<usize> 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),

View file

@ -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<I>(items: I, width: usize, offset: Indent, config: &Config) -> Option<String>
pub fn format_fn_args<I>(items: I, shape: Shape, config: &Config) -> Option<String>
where I: Iterator<Item = ListItem>
{
list_helper(items,
width,
offset,
shape,
config,
ListTactic::LimitedHorizontalVertical(config.fn_call_width))
}
pub fn format_item_list<I>(items: I,
width: usize,
offset: Indent,
config: &Config)
-> Option<String>
pub fn format_item_list<I>(items: I, shape: Shape, config: &Config) -> Option<String>
where I: Iterator<Item = ListItem>
{
list_helper(items, width, offset, config, ListTactic::HorizontalVertical)
list_helper(items, shape, config, ListTactic::HorizontalVertical)
}
pub fn list_helper<I>(items: I,
width: usize,
offset: Indent,
config: &Config,
tactic: ListTactic)
-> Option<String>
pub fn list_helper<I>(items: I, shape: Shape, config: &Config, tactic: ListTactic) -> Option<String>
where I: Iterator<Item = ListItem>
{
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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
// 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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
// 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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
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<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
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);

View file

@ -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<ast::Ident>,
context: &RewriteContext,
width: usize,
offset: Indent,
shape: Shape,
position: MacroPosition)
-> Option<String> {
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, &macro_name, &expr_vec, mac.span, width, offset)
.map(|rw| match position {
rewrite_call(context, &macro_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))
}

View file

@ -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());

View file

@ -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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<Vec<String>> = 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<String> {
let pat = self.pat.rewrite(context, width, offset);
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<ast::Pat>],
path_str: Option<String>,
span: Span,
context: &RewriteContext,
width: usize,
offset: Indent)
shape: Shape)
-> Option<String> {
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<ast::Pat>],
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<ast::Pat>],
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 {

View file

@ -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<String>;
/// Rewrite self into shape.
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String>;
}
#[derive(Clone)]

View file

@ -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<String>
let stripped_str = re.replace_all(orig, "$1");
let graphemes = UnicodeSegmentation::graphemes(&*stripped_str, false).collect::<Vec<&str>>();
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<String>
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<String>
}
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,
};

View file

@ -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<String> {
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<String>
where I: Iterator<Item = &'a ast::PathSegment>
{
@ -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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
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<String>
where I: ExactSizeIterator,
<I as Iterator>::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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// 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<String> {
rewrite_bounded_lifetime(&self.lifetime, self.bounds.iter(), context, width, offset)
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String>
where I: ExactSizeIterator<Item = &'b ast::Lifetime>
{
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
rewrite_path(context, PathContext::Type, None, &self.path, width, offset)
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
rewrite_path(context, PathContext::Type, None, &self.path, shape)
}
}
impl Rewrite for ast::Ty {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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<String> {
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::<Option<String>>()));
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);

View file

@ -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: AsRef<str>>(s: S, max_width: usize, width: usize, offset: Indent) -> Option<S> {
pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, shape: Shape) -> Option<S> {
{
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: AsRef<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: AsRef<str>>(s: S, max_width: usize, width: usize, offset: Ind
}
impl Rewrite for String {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
wrap_str(self, context.config.max_width, width, offset).map(ToOwned::to_owned)
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
wrap_str(self, context.config.max_width, shape).map(ToOwned::to_owned)
}
}

View file

@ -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<String> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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));
}