This commit is contained in:
Nick Cameron
2017-02-21 14:43:43 +13:00
parent 4f939ddf0c
commit b35906dbce
11 changed files with 382 additions and 336 deletions
+37 -35
View File
@@ -93,6 +93,7 @@
use syntax::codemap::{mk_sp, Span};
pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -> Option<String> {
debug!("rewrite_chain {:?}", shape);
let total_span = expr.span;
let (parent, subexpr_list) = make_subexpr_list(expr, context);
@@ -103,42 +104,45 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
}
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
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, shape));
let mut parent_shape = shape;
if is_block_expr(&parent, "\n") {
parent_shape = chain_base_indent(context, shape);
}
let parent_rewrite = try_opt!(parent.rewrite(context, parent_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.
let (indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(&parent) ||
parent_rewrite.len() <= context.config.tab_spaces {
let indent = if let ast::ExprKind::Try(..) = subexpr_list.last().unwrap().node {
parent_block_indent.block_indent(context.config)
let (nested_shape, extend) = if !parent_rewrite.contains('\n') && is_continuable(&parent) {
let nested_shape = if let ast::ExprKind::Try(..) = subexpr_list.last().unwrap().node {
parent_shape.block_indent(context.config.tab_spaces)
} else {
chain_indent(context, shape.indent + Indent::new(0, parent_rewrite.len()))
chain_indent(context, shape.add_offset(parent_rewrite.len()))
};
(indent, true)
(nested_shape, true)
} else if is_block_expr(&parent, &parent_rewrite) {
// The parent is a block, so align the rest of the chain with the closing
// brace.
(parent_block_indent, false)
(parent_shape, false)
} else if parent_rewrite.contains('\n') {
(chain_indent(context, parent_block_indent.block_indent(context.config)), false)
(chain_indent(context, parent_shape.block_indent(context.config.tab_spaces)), false)
} else {
(chain_indent_newline(context, shape.indent + Indent::new(0, parent_rewrite.len())), false)
(chain_indent_newline(context, shape.add_offset(parent_rewrite.len())), false)
};
let max_width = try_opt!((shape.width + shape.indent.width()).checked_sub(indent.width()));
let max_width = try_opt!((shape.width + shape.indent.width() + shape.offset).checked_sub(nested_shape.indent.width() + nested_shape.offset));
// The alignement in the shape is only used if we start the item on a new
// line, so we don't need to preserve the offset.
let child_shape = Shape { width: max_width, ..nested_shape };
debug!("child_shape {:?}", child_shape);
let mut rewrites = try_opt!(subexpr_list.iter()
.rev()
.map(|e| rewrite_chain_subexpr(e, total_span, context, Shape::legacy(max_width, indent)))
.map(|e| rewrite_chain_subexpr(e, total_span, context, child_shape))
.collect::<Option<Vec<_>>>());
// Total of all items excluding the last.
let almost_total = rewrites[..rewrites.len() - 1]
.iter()
.fold(0, |a, b| a + first_line_width(b)) + parent_rewrite.len();
let total_width = almost_total + first_line_width(rewrites.last().unwrap());
let veto_single_line = if context.config.take_source_hints && subexpr_list.len() > 1 {
// Look at the source code. Unless all chain elements start on the same
@@ -152,7 +156,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
false
};
let mut fits_single_line = !veto_single_line && total_width <= shape.width;
let mut fits_single_line = !veto_single_line && almost_total <= shape.width;
if fits_single_line {
let len = rewrites.len();
let (init, last) = rewrites.split_at_mut(len - 1);
@@ -178,7 +182,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
String::new()
} else {
// Use new lines.
format!("\n{}", indent.to_string(context.config))
format!("\n{}", nested_shape.indent.to_string(context.config))
};
let first_connector = if extend || subexpr_list.is_empty() {
@@ -211,7 +215,7 @@ pub fn rewrite_try(expr: &ast::Expr,
context: &RewriteContext,
shape: Shape)
-> Option<String> {
let sub_expr = try_opt!(expr.rewrite(context, shape.sub_width(try_count)));
let sub_expr = try_opt!(expr.rewrite(context, try_opt!(shape.sub_width(try_count))));
Some(format!("{}{}",
sub_expr,
iter::repeat("?").take(try_count).collect::<String>()))
@@ -268,29 +272,29 @@ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> (ast::Expr,
(parent, subexpr_list)
}
fn chain_base_indent(context: &RewriteContext, offset: Indent) -> Indent {
fn chain_base_indent(context: &RewriteContext, shape: Shape) -> Shape {
match context.config.chain_base_indent {
BlockIndentStyle::Visual => offset,
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Tabbed => context.block_indent.block_indent(context.config),
BlockIndentStyle::Visual => shape,
BlockIndentStyle::Inherit => shape.block_indent(0),
BlockIndentStyle::Tabbed => shape.block_indent(context.config.tab_spaces),
}
}
fn chain_indent(context: &RewriteContext, offset: Indent) -> Indent {
fn chain_indent(context: &RewriteContext, shape: Shape) -> Shape {
match context.config.chain_indent {
BlockIndentStyle::Visual => offset,
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Tabbed => context.block_indent.block_indent(context.config),
BlockIndentStyle::Visual => shape,
BlockIndentStyle::Inherit => shape.block_indent(0),
BlockIndentStyle::Tabbed => shape.block_indent(context.config.tab_spaces),
}
}
// Ignores visual indenting because this function should be called where it is
// not possible to use visual indentation because we are starting on a newline.
fn chain_indent_newline(context: &RewriteContext, _offset: Indent) -> Indent {
fn chain_indent_newline(context: &RewriteContext, shape: Shape) -> Shape {
match context.config.chain_indent {
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Inherit => shape.block_indent(0),
BlockIndentStyle::Visual | BlockIndentStyle::Tabbed => {
context.block_indent.block_indent(context.config)
shape.block_indent(context.config.tab_spaces)
}
}
}
@@ -303,7 +307,7 @@ fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind,
shape: Shape)
-> bool {
if let &ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) = expr_kind {
let budget = match shape.width.checked_sub(almost_total) {
let shape = match shape.shrink_left(almost_total) {
Some(b) => b,
None => return false,
};
@@ -312,8 +316,7 @@ fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind,
expressions,
total_span,
context,
Shape::legacy(budget,
shape.indent + almost_total));
shape);
if let Some(ref mut s) = last_rewrite {
::std::mem::swap(s, last);
@@ -362,8 +365,7 @@ fn rewrite_chain_subexpr(expr: &ast::Expr,
-> Option<String> {
match expr.node {
ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) => {
let inner = &RewriteContext { block_indent: shape.indent, ..*context };
rewrite_method_call(method_name.node, types, expressions, span, inner, shape)
rewrite_method_call(method_name.node, types, expressions, span, context, shape)
}
ast::ExprKind::Field(_, ref field) => {
let s = format!(".{}", field.node);
+190 -221
View File
@@ -253,21 +253,20 @@ pub fn rewrite_pair<LHS, RHS>(lhs: &LHS,
where LHS: Rewrite,
RHS: Rewrite
{
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, Shape::legacy(rhs_budget, shape.indent));
let rhs_shape = try_opt!(shape.sub_width(suffix.len()));
let rhs_result = rhs.rewrite(context, rhs_shape);
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, Shape::legacy(lhs_budget, shape.indent));
let lhs_shape = try_opt!(shape.sub_width(prefix.len() + infix.len()));
let lhs_result = lhs.rewrite(context, lhs_shape);
if let Some(lhs_result) = lhs_result {
let mut result = format!("{}{}{}", prefix, lhs_result, infix);
@@ -281,14 +280,15 @@ pub fn rewrite_pair<LHS, RHS>(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,
Shape::legacy(rhs_budget,
shape.indent + result.len())) {
if rhs_result.len() <= remaining_width {
result.push_str(&rhs_result);
result.push_str(suffix);
return Some(result);
let rhs_shape = shape.shrink_left(last_line_width(&result) + suffix.len());
if let Some(rhs_shape) = rhs_shape {
if let Some(rhs_result) = rhs.rewrite(context, rhs_shape) {
// FIXME this should always hold.
if rhs_result.len() <= remaining_width {
result.push_str(&rhs_result);
result.push_str(suffix);
return Some(result);
}
}
}
}
@@ -301,17 +301,16 @@ pub fn rewrite_pair<LHS, RHS>(lhs: &LHS,
let infix = infix.trim_right();
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 = shape.indent + prefix.len();
.checked_sub(shape.used_width() + prefix.len() + infix.len()));
let rhs_shape = try_opt!(shape.sub_width(suffix.len() + prefix.len())).visual_indent(prefix.len());
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)));
let rhs_result = try_opt!(rhs.rewrite(context, rhs_shape));
let lhs_result = try_opt!(lhs.rewrite(context, Shape { width: lhs_budget, ..shape }));
Some(format!("{}{}{}\n{}{}{}",
prefix,
lhs_result,
infix,
rhs_offset.to_string(context.config),
rhs_shape.indent.to_string(context.config),
rhs_result,
suffix))
}
@@ -328,16 +327,14 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
} else {
1 // "["
};
let offset = shape.indent + bracket_size;
let inner_context = &RewriteContext { block_indent: offset, ..*context };
let max_item_width = try_opt!(shape.width.checked_sub(bracket_size * 2));
let nested_shape = try_opt!(shape.visual_indent(bracket_size).sub_width(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)),
|item| item.rewrite(context, nested_shape),
span.lo,
span.hi)
.collect::<Vec<_>>();
@@ -347,7 +344,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
.fold(Some(false), |acc, x| acc.and_then(|y| x.map(|x| x || y))));
let tactic = if has_long_item || items.iter().any(ListItem::is_multiline) {
definitive_tactic(&items, ListTactic::HorizontalVertical, max_item_width)
definitive_tactic(&items, ListTactic::HorizontalVertical, nested_shape.width)
} else {
DefinitiveListTactic::Mixed
};
@@ -356,7 +353,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
shape: Shape::legacy(max_item_width, offset),
shape: nested_shape,
ends_with_newline: false,
config: context.config,
};
@@ -390,17 +387,14 @@ fn rewrite_closure(capture: ast::CaptureBy,
} else {
""
};
let offset = shape.indent + mover.len();
// 4 = "|| {".len(), which is overconservative when the closure consists of
// a single expression.
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, Shape::legacy(budget, argument_offset)));
let nested_shape = try_opt!(try_opt!(shape.shrink_left(mover.len())).sub_width(4));
// 1 = space between arguments and return type.
let horizontal_budget = budget.checked_sub(ret_str.len() + 1).unwrap_or(0);
// 1 = |
let argument_offset = nested_shape.indent + 1;
let arg_shape = try_opt!(nested_shape.shrink_left(1)).visual_indent(0);
let ret_str = try_opt!(fn_decl.output.rewrite(context, arg_shape));
let arg_items =
itemize_list(context.codemap,
@@ -408,21 +402,23 @@ fn rewrite_closure(capture: ast::CaptureBy,
"|",
|arg| span_lo_for_arg(arg),
|arg| span_hi_for_arg(arg),
|arg| arg.rewrite(context, Shape::legacy(budget, argument_offset)),
|arg| arg.rewrite(context, arg_shape),
context.codemap.span_after(span, "|"),
body.span.lo);
let item_vec = arg_items.collect::<Vec<_>>();
// 1 = space between arguments and return type.
let horizontal_budget = nested_shape.width.checked_sub(ret_str.len() + 1).unwrap_or(0);
let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, horizontal_budget);
let budget = match tactic {
DefinitiveListTactic::Horizontal => horizontal_budget,
_ => budget,
let arg_shape = match tactic {
DefinitiveListTactic::Horizontal => try_opt!(arg_shape.sub_width(ret_str.len() + 1)),
_ => arg_shape,
};
let fmt = ListFormatting {
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
shape: Shape::legacy(budget, argument_offset),
shape: arg_shape,
ends_with_newline: false,
config: context.config,
};
@@ -440,12 +436,11 @@ fn rewrite_closure(capture: ast::CaptureBy,
}
// 1 = space between `|...|` and body.
let extra_offset = extra_offset(&prefix, offset) + 1;
let budget = try_opt!(shape.width.checked_sub(extra_offset));
let total_offset = offset + extra_offset;
let extra_offset = extra_offset(&prefix, shape) + 1;
let body_shape = try_opt!(shape.sub_width(extra_offset)).add_offset(extra_offset);
if let ast::ExprKind::Block(ref block) = body.node {
// The body of the closure is a block.
// The body of the closure is an empty block.
if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) {
return Some(format!("{} {{}}", prefix));
}
@@ -461,7 +456,7 @@ fn rewrite_closure(capture: ast::CaptureBy,
if let Some(rw) = rewrite_closure_expr(expr,
&prefix,
context,
Shape::legacy(budget, total_offset)) {
body_shape) {
return Some(rw);
}
}
@@ -472,8 +467,7 @@ fn rewrite_closure(capture: ast::CaptureBy,
let stmt = &block.stmts[0];
// 4 = braces and spaces.
let mut rewrite = stmt.rewrite(context,
Shape::legacy(try_opt!(budget.checked_sub(4)),
total_offset));
try_opt!(body_shape.sub_width(4)));
// Checks if rewrite succeeded and fits on a single line.
rewrite = and_one_line(rewrite);
@@ -484,13 +478,14 @@ fn rewrite_closure(capture: ast::CaptureBy,
}
// Either we require a block, or tried without and failed.
return rewrite_closure_block(&block, prefix, context, budget);
let body_shape = shape.block();
return rewrite_closure_block(&block, prefix, context, body_shape);
}
if let Some(rw) = rewrite_closure_expr(body,
&prefix,
context,
Shape::legacy(budget, total_offset)) {
body_shape) {
return Some(rw);
}
@@ -506,7 +501,7 @@ fn rewrite_closure(capture: ast::CaptureBy,
rules: ast::BlockCheckMode::Default,
span: body.span,
};
return rewrite_closure_block(&block, prefix, context, budget);
return rewrite_closure_block(&block, prefix, context, body_shape.block());
fn rewrite_closure_expr(expr: &ast::Expr,
prefix: &str,
@@ -523,11 +518,11 @@ fn rewrite_closure_expr(expr: &ast::Expr,
fn rewrite_closure_block(block: &ast::Block,
prefix: String,
context: &RewriteContext,
budget: usize)
shape: Shape)
-> Option<String> {
// Start with visual indent, then fall back to block indent if the
// closure is large.
let rewrite = try_opt!(block.rewrite(&context, Shape::legacy(budget, Indent::empty())));
let rewrite = try_opt!(block.rewrite(&context, shape));
let block_threshold = context.config.closure_block_indent_threshold;
if block_threshold < 0 || rewrite.matches('\n').count() <= block_threshold as usize {
@@ -536,9 +531,8 @@ fn rewrite_closure_block(block: &ast::Block,
// The body of the closure is big enough to be block indented, that
// means we must re-format.
let mut context = context.clone();
context.block_indent.alignment = 0;
let rewrite = try_opt!(block.rewrite(&context, Shape::legacy(budget, Indent::empty())));
let block_shape = shape.block();
let rewrite = try_opt!(block.rewrite(&context, block_shape));
Some(format!("{} {}", prefix, rewrite))
}
}
@@ -581,7 +575,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
}
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = context.block_indent;
visitor.block_indent = shape.indent;
let prefix = match self.rules {
ast::BlockCheckMode::Unsafe(..) => {
@@ -648,9 +642,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
_ => unreachable!(),
},
context,
Shape::legacy(context.config.max_width - shape.indent.width() -
suffix.len(),
shape.indent))
try_opt!(shape.sub_width(suffix.len())))
.map(|s| s + suffix)
}
ast::StmtKind::Mac(..) |
@@ -815,32 +807,32 @@ fn rewrite_single_line(&self,
impl<'a> Rewrite for ControlFlow<'a> {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
let (budget, indent) = if self.nested_if {
let constr_shape = if self.nested_if {
// We are part of an if-elseif-else chain. Our constraints are tightened.
// 7 = "} else " .len()
(try_opt!(shape.width.checked_sub(7)), shape.indent + 7)
try_opt!(shape.shrink_left(7))
} else {
(shape.width, shape.indent)
shape
};
let label_string = rewrite_label(self.label);
// 1 = space after keyword.
let inner_offset = indent + self.keyword.len() + label_string.len() + 1;
let mut inner_width =
try_opt!(budget.checked_sub(self.keyword.len() + label_string.len() + 1));
if context.config.control_brace_style != ControlBraceStyle::AlwaysNextLine {
// 2 = " {".len()
inner_width = try_opt!(inner_width.checked_sub(2));
}
let add_offset = self.keyword.len() + label_string.len() + 1;
let pat_expr_string = match self.cond {
Some(cond) => {
let mut cond_shape = try_opt!(constr_shape.shrink_left(add_offset));
if context.config.control_brace_style != ControlBraceStyle::AlwaysNextLine {
// 2 = " {".len()
cond_shape = try_opt!(cond_shape.sub_width(2));
}
try_opt!(rewrite_pat_expr(context,
self.pat,
cond,
self.matcher,
self.connector,
Shape::legacy(inner_width, inner_offset)))
cond_shape))
}
None => String::new(),
};
@@ -855,21 +847,24 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
}
}
let used_width = if pat_expr_string.contains('\n') {
last_line_width(&pat_expr_string)
} else {
// 2 = spaces after keyword and condition.
label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
};
let block_width = try_opt!(shape.width.checked_sub(used_width));
// 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!(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, Shape::legacy(block_width, shape.indent)));
// TODO this .block() - not what we want if we are actually visually indented
let block_shape = Shape { width: block_width, ..shape };
let block_str = try_opt!(self.block.rewrite(context, block_shape));
let cond_span = if let Some(cond) = self.cond {
cond.span
@@ -891,7 +886,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
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 alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
""
} else if context.config.control_brace_style ==
@@ -913,14 +908,8 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
if let Some(else_block) = self.else_block {
// Since this is an else block, we should not indent for the assignment preceding
// the original if, so set shape.indent.alignment to 0.
let shape = Shape {
width: shape.width,
indent: Indent {
block_indent: shape.indent.block_indent,
alignment: 0,
},
};
// the original if, so set shape.offset to 0.
let shape = Shape { offset: 0, ..shape };
let mut last_in_chain = false;
let rewrite = match else_block.node {
// If the else expression is another if-else expression, prevent it
@@ -935,7 +924,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
false,
true,
mk_sp(else_block.span.lo, self.span.hi))
.rewrite(context, shape)
.rewrite(context, shape.visual_indent(0))
}
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
ControlFlow::new_if(cond,
@@ -945,13 +934,14 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
false,
true,
mk_sp(else_block.span.lo, self.span.hi))
.rewrite(context, shape)
.rewrite(context, shape.visual_indent(0))
}
_ => {
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, Shape::legacy(min(1, shape.width), shape.indent))
let else_shape = Shape { width: min(1, shape.width), ..shape };
else_block.rewrite(context, else_shape)
}
};
@@ -1097,16 +1087,15 @@ fn rewrite_match(context: &RewriteContext,
// `match `cond` {`
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 alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
let block_sep = match context.config.control_brace_style {
ControlBraceStyle::AlwaysSameLine => " ",
_ => alt_block_sep.as_str(),
};
let mut result = format!("match {}{}{{", cond_str, block_sep);
let nested_context = context.nested_context();
let arm_indent = nested_context.block_indent;
let arm_indent_str = arm_indent.to_string(context.config);
let arm_shape = shape.block_indent(context.config.tab_spaces);
let arm_indent_str = arm_shape.indent.to_string(context.config);
let open_brace_pos = context.codemap
.span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{");
@@ -1120,15 +1109,14 @@ fn rewrite_match(context: &RewriteContext,
};
let comment = try_opt!(rewrite_match_arm_comment(context,
&missed_str,
Shape::legacy(shape.width, arm_indent),
arm_shape,
&arm_indent_str));
result.push_str(&comment);
result.push('\n');
result.push_str(&arm_indent_str);
let arm_str = arm.rewrite(&nested_context,
Shape::legacy(context.config.max_width - arm_indent.width(),
arm_indent));
let arm_str = arm.rewrite(&context,
Shape { width: context.config.max_width - arm_shape.indent.width(), .. arm_shape });
if let Some(ref arm_str) = arm_str {
result.push_str(arm_str);
} else {
@@ -1143,11 +1131,11 @@ fn rewrite_match(context: &RewriteContext,
let last_comment = context.snippet(last_span);
let comment = try_opt!(rewrite_match_arm_comment(context,
&last_comment,
Shape::legacy(shape.width, arm_indent),
arm_shape,
&arm_indent_str));
result.push_str(&comment);
result.push('\n');
result.push_str(&context.block_indent.to_string(context.config));
result.push_str(&shape.indent.to_string(context.config));
result.push('}');
Some(result)
}
@@ -1197,7 +1185,7 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// We only use this visitor for the attributes, should we use it for
// more?
let mut attr_visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
attr_visitor.block_indent = context.block_indent;
attr_visitor.block_indent = shape.indent.block_only();
attr_visitor.last_pos = attrs[0].span.lo;
if attr_visitor.visit_attrs(attrs) {
// Attributes included a skip instruction.
@@ -1211,9 +1199,10 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// Patterns
// 5 = ` => {`
let pat_budget = try_opt!(shape.width.checked_sub(5));
let pat_shape = try_opt!(shape.sub_width(5));
let pat_strs = try_opt!(pats.iter()
.map(|p| p.rewrite(context, Shape::legacy(pat_budget, shape.indent)))
.map(|p| p.rewrite(context, pat_shape))
.collect::<Option<Vec<_>>>());
let all_simple = pat_strs.iter().all(|p| pat_is_simple(p));
@@ -1226,29 +1215,26 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
},
separator: " |",
trailing_separator: SeparatorTactic::Never,
shape: Shape::legacy(pat_budget, shape.indent),
shape: pat_shape,
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 - shape.indent.width()
let guard_shape = if pats_str.contains('\n') {
Shape { width: context.config.max_width - shape.indent.width(), ..shape }
} else {
shape.width
shape
};
let guard_str = try_opt!(rewrite_guard(context,
guard,
Shape::legacy(budget, shape.indent),
guard_shape,
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 += shape.indent.width();
}
let mut line_start = trimmed_last_line_width(&pats_str);
let body = match body.node {
ast::ExprKind::Block(ref block) if !is_unsafe_block(block) &&
@@ -1264,16 +1250,17 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
};
let comma = arm_comma(&context.config, self, body);
let alt_block_sep = String::from("\n") + &context.block_indent.to_string(context.config);
let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
// Let's try and get the arm body on the same line as the condition.
// 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(shape.indent.block_indent,
line_start + 4 - shape.indent.block_indent);
let rewrite = nop_block_collapse(body.rewrite(context, Shape::legacy(budget, offset)),
budget);
if shape.width > line_start + comma.len() + 4 {
let arm_shape = shape.shrink_left(line_start + 4).unwrap().sub_width(comma.len()).unwrap().block();
// TODO
// let offset = Indent::new(shape.indent.block_indent,
// line_start + 4 - shape.indent.block_indent);
let rewrite = nop_block_collapse(body.rewrite(context, arm_shape),
arm_shape.width);
let is_block = if let ast::ExprKind::Block(..) = body.node {
true
} else {
@@ -1301,13 +1288,12 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
// FIXME: we're doing a second rewrite of the expr; This may not be
// necessary.
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,
Shape::legacy(body_budget,
indent)),
body_budget));
// TODO
// let body_budget = try_opt!(shape.width.checked_sub(context.config.tab_spaces));
// let indent = shape.indent.block_only().block_indent(context.config);
let body_shape = try_opt!(shape.sub_width(context.config.tab_spaces)).block_indent(context.config.tab_spaces);
let next_line_body = try_opt!(nop_block_collapse(body.rewrite(context, body_shape),
body_shape.width));
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 {
@@ -1394,6 +1380,7 @@ fn rewrite_pat_expr(context: &RewriteContext,
connector: &str,
shape: Shape)
-> Option<String> {
debug!("rewrite_pat_expr {:?}", shape);
let mut result = match pat {
Some(pat) => {
let matcher = if matcher.is_empty() {
@@ -1401,26 +1388,22 @@ fn rewrite_pat_expr(context: &RewriteContext,
} else {
format!("{} ", matcher)
};
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)));
let pat_shape = try_opt!(try_opt!(shape.shrink_left(matcher.len())).sub_width(connector.len()));
let pat_string = try_opt!(pat.rewrite(context, pat_shape));
format!("{}{}{}", matcher, pat_string, connector)
}
None => String::new(),
};
// Consider only the last line of the pat string.
let extra_offset = extra_offset(&result, shape.indent);
let extra_offset = extra_offset(&result, shape);
// The expression may (partionally) fit on the current line.
// The expression may (partially) fit on the current line.
if shape.width > extra_offset + 1 {
let spacer = if pat.is_some() { " " } else { "" };
let expr_rewrite = expr.rewrite(context,
Shape::legacy(try_opt!(shape.width
.checked_sub(extra_offset +
spacer.len())),
shape.indent + extra_offset + spacer.len()));
let expr_shape = try_opt!(shape.sub_width(extra_offset + spacer.len())).add_offset(extra_offset + spacer.len());
let expr_rewrite = expr.rewrite(context, expr_shape);
if let Some(expr_string) = expr_rewrite {
let pat_simple = pat.and_then(|p| {
@@ -1437,17 +1420,17 @@ fn rewrite_pat_expr(context: &RewriteContext,
}
}
let nested = context.nested_context();
let nested_indent = shape.indent.block_only().block_indent(context.config);
// The expression won't fit on the current line, jump to next.
result.push('\n');
result.push_str(&nested.block_indent.to_string(context.config));
result.push_str(&nested_indent.to_string(context.config));
let expr_rewrite = expr.rewrite(&nested,
let expr_rewrite = expr.rewrite(&context,
Shape::legacy(try_opt!(context.config
.max_width
.checked_sub(nested.block_indent.width())),
nested.block_indent));
.checked_sub(nested_indent.width())),
nested_indent));
result.push_str(&try_opt!(expr_rewrite));
Some(result)
@@ -1533,7 +1516,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
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, Shape::legacy(max_callee_width, shape.indent)) {
let callee_str = match callee.rewrite(context, Shape { width: max_callee_width, ..shape }) {
Some(string) => {
if !string.contains('\n') && string.len() > max_callee_width {
panic!("{:?} {}", string, max_callee_width);
@@ -1547,20 +1530,15 @@ fn rewrite_call_inner<R>(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, shape.indent);
let used_width = extra_offset(&callee_str, shape);
// 2 is for parens.
let remaining_width = match shape.width.checked_sub(extra_offset + 2) {
Some(str) => str,
let remaining_width = match shape.width.checked_sub(used_width + 2) {
Some(s) => s,
None => return Err(Ordering::Greater),
};
let offset = shape.indent + extra_offset + 1;
// 1 = (
let nested_shape = shape.visual_indent(used_width + 1);
let arg_count = args.len();
let block_indent = if arg_count == 1 {
context.block_indent
} else {
offset
};
let inner_context = &RewriteContext { block_indent: block_indent, ..*context };
let items =
itemize_list(context.codemap,
@@ -1568,7 +1546,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
")",
|item| item.span.lo,
|item| item.span.hi,
|item| item.rewrite(inner_context, Shape::legacy(remaining_width, offset)),
|item| item.rewrite(context, Shape { width: remaining_width, ..nested_shape }),
span.lo,
span.hi);
let mut item_vec: Vec<_> = items.collect();
@@ -1588,9 +1566,12 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
// Replace the last item with its first line to see if it fits with
// first arguments.
if overflow_last {
let inner_context = &RewriteContext { block_indent: context.block_indent, ..*context };
let rewrite =
args.last().unwrap().rewrite(inner_context, Shape::legacy(remaining_width, offset));
let nested_shape = Shape {
width: remaining_width,
indent: nested_shape.indent.block_only(),
..nested_shape
};
let rewrite = args.last().unwrap().rewrite(context, nested_shape);
if let Some(rewrite) = rewrite {
let rewrite_first_line = Some(rewrite[..first_line_width(&rewrite)].to_owned());
@@ -1622,7 +1603,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
shape: Shape::legacy(shape.width, offset),
shape: nested_shape,
ends_with_newline: false,
config: context.config,
};
@@ -1643,9 +1624,8 @@ fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, shape: Shape) ->
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,
Shape::legacy(try_opt!(shape.width.checked_sub(2)),
shape.indent + 1));
let sub_shape = try_opt!(shape.sub_width(2)).visual_indent(1);
let subexpr_str = subexpr.rewrite(context, sub_shape);
debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
subexpr_str.map(|s| if context.config.spaces_within_parens && s.len() > 0 {
@@ -1699,24 +1679,20 @@ enum StructLitField<'a> {
}
// 2 = " {".len()
let path_budget = try_opt!(shape.width.checked_sub(2));
let path_shape = try_opt!(shape.sub_width(2));
let path_str = try_opt!(rewrite_path(context,
PathContext::Expr,
None,
path,
Shape::legacy(path_budget, shape.indent)));
path_shape));
// Foo { a: Foo } - indent is +3, width is -5.
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 => (shape.indent + path_str.len() + 3, h_budget),
let h_shape = shape.sub_width(path_str.len() + 5);
let v_shape = match context.config.struct_lit_style {
StructLitStyle::Visual => try_opt!(try_opt!(shape.shrink_left(path_str.len() + 3)).sub_width(2)),
StructLitStyle::Block => {
// If we are all on one line, then we'll ignore the indent, and we
// have a smaller budget.
let indent = context.block_indent.block_indent(context.config);
let v_budget = context.config.max_width.checked_sub(indent.width()).unwrap_or(0);
(indent, v_budget)
let shape = shape.block_indent(context.config.tab_spaces);
Shape { width: try_opt!(context.config.max_width.checked_sub(shape.indent.width())), ..shape }
}
};
@@ -1724,8 +1700,6 @@ enum StructLitField<'a> {
.map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
let inner_context = &RewriteContext { block_indent: indent, ..*context };
let items = itemize_list(context.codemap,
field_iter,
"}",
@@ -1747,14 +1721,15 @@ enum StructLitField<'a> {
|item| {
match *item {
StructLitField::Regular(field) => {
rewrite_field(inner_context,
// The 1 taken from the v_budget is for the comma.
rewrite_field(context,
field,
Shape::legacy(v_budget.checked_sub(1).unwrap_or(0), indent))
try_opt!(v_shape.sub_width(1)))
}
StructLitField::Base(expr) => {
// 2 = ..
expr.rewrite(inner_context,
Shape::legacy(try_opt!(v_budget.checked_sub(2)), indent + 2))
expr.rewrite(context,
try_opt!(v_shape.shrink_left(2)))
.map(|s| format!("..{}", s))
}
}
@@ -1763,7 +1738,7 @@ enum StructLitField<'a> {
span.hi);
let item_vec = items.collect::<Vec<_>>();
let tactic = {
let tactic = if let Some(h_shape) = h_shape {
let mut prelim_tactic = match (context.config.struct_lit_style, fields.len()) {
(StructLitStyle::Visual, 1) => ListTactic::HorizontalVertical,
_ => context.config.struct_lit_multiline_style.to_list_tactic(),
@@ -1773,12 +1748,14 @@ enum StructLitField<'a> {
prelim_tactic = ListTactic::LimitedHorizontalVertical(context.config.struct_lit_width);
}
definitive_tactic(&item_vec, prelim_tactic, h_budget)
definitive_tactic(&item_vec, prelim_tactic, h_shape.width)
} else {
DefinitiveListTactic::Vertical
};
let budget = match tactic {
DefinitiveListTactic::Horizontal => h_budget,
_ => v_budget,
let nested_shape = match tactic {
DefinitiveListTactic::Horizontal => h_shape.unwrap(),
_ => v_shape,
};
let ends_with_newline = context.config.struct_lit_style != StructLitStyle::Visual &&
@@ -1792,36 +1769,33 @@ enum StructLitField<'a> {
} else {
context.config.struct_lit_trailing_comma
},
shape: Shape::legacy(budget, indent),
shape: nested_shape,
ends_with_newline: ends_with_newline,
config: context.config,
};
let fields_str = try_opt!(write_list(&item_vec, &fmt));
// Empty struct.
if fields_str.is_empty() {
return Some(format!("{} {{}}", path_str));
}
let format_on_newline = || {
let inner_indent = context.block_indent
.block_indent(context.config)
.to_string(context.config);
let outer_indent = context.block_indent.to_string(context.config);
Some(format!("{} {{\n{}{}\n{}}}",
path_str,
inner_indent,
fields_str,
outer_indent))
};
match (context.config.struct_lit_style, context.config.struct_lit_multiline_style) {
(StructLitStyle::Block, _) if fields_str.contains('\n') || fields_str.len() > h_budget => {
format_on_newline()
}
(StructLitStyle::Block, MultilineStyle::ForceMulti) => format_on_newline(),
_ => Some(format!("{} {{ {} }}", path_str, fields_str)),
// One liner or visual indent.
if context.config.struct_lit_style == StructLitStyle::Visual ||
(context.config.struct_lit_multiline_style != MultilineStyle::ForceMulti &&
!fields_str.contains('\n') &&
fields_str.len() <= h_shape.map(|s| s.width).unwrap_or(0)) {
return Some(format!("{} {{ {} }}", path_str, fields_str));
}
// Multiple lines.
let inner_indent = v_shape.indent.to_string(context.config);
let outer_indent = shape.indent.to_string(context.config);
Some(format!("{} {{\n{}{}\n{}}}",
path_str,
inner_indent,
fields_str,
outer_indent))
// FIXME if context.config.struct_lit_style == Visual, but we run out
// of space, we should fall back to BlockIndent.
}
@@ -1842,9 +1816,9 @@ fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) ->
} else {
let separator = type_annotation_separator(context.config);
let overhead = name.len() + separator.len();
let expr = field.expr.rewrite(context,
Shape::legacy(try_opt!(shape.width.checked_sub(overhead)),
shape.indent + overhead));
let mut expr_shape = try_opt!(shape.sub_width(overhead));
expr_shape.offset += overhead;
let expr = field.expr.rewrite(context, expr_shape);
match expr {
Some(e) => Some(format!("{}{}{}", name, separator, e)),
@@ -1871,16 +1845,14 @@ pub fn rewrite_tuple<'a, I>(context: &RewriteContext,
<I as Iterator>::Item: Deref,
<I::Item as Deref>::Target: Rewrite + Spanned + 'a
{
let indent = shape.indent + 1;
let aligned = RewriteContext { block_indent: indent, ..context.clone() };
debug!("rewrite_tuple {:?}", shape);
// In case of length 1, need a trailing comma
if items.len() == 1 {
// 3 = "(" + ",)"
let budget = try_opt!(shape.width.checked_sub(3));
let nested_shape = try_opt!(shape.sub_width(3)).visual_indent(1);
return items.next()
.unwrap()
.rewrite(&aligned, Shape::legacy(budget, indent))
.rewrite(context, nested_shape)
.map(|s| if context.config.spaces_within_parens {
format!("( {}, )", s)
} else {
@@ -1889,16 +1861,16 @@ pub fn rewrite_tuple<'a, I>(context: &RewriteContext,
}
let list_lo = context.codemap.span_after(span, "(");
let budget = try_opt!(shape.width.checked_sub(2));
let nested_shape = try_opt!(shape.sub_width(2)).visual_indent(1);
let items = itemize_list(context.codemap,
items,
")",
|item| item.span().lo,
|item| item.span().hi,
|item| item.rewrite(&aligned, Shape::legacy(budget, indent)),
|item| item.rewrite(context, nested_shape),
list_lo,
span.hi - BytePos(1));
let list_str = try_opt!(format_item_list(items, Shape::legacy(budget, indent), context.config));
let list_str = try_opt!(format_item_list(items, nested_shape, context.config));
if context.config.spaces_within_parens && list_str.len() > 0 {
Some(format!("( {} )", list_str))
@@ -1912,10 +1884,8 @@ pub fn rewrite_unary_prefix<R: Rewrite>(context: &RewriteContext,
rewrite: &R,
shape: Shape)
-> Option<String> {
rewrite.rewrite(context,
Shape::legacy(try_opt!(shape.width.checked_sub(prefix.len())),
shape.indent + prefix.len()))
.map(|r| format!("{}{}", prefix, r))
let shape = try_opt!(shape.shrink_left(prefix.len())).visual_indent(0);
rewrite.rewrite(context, shape).map(|r| format!("{}{}", prefix, r))
}
// FIXME: this is probably not correct for multi-line Rewrites. we should
@@ -1925,9 +1895,7 @@ pub fn rewrite_unary_suffix<R: Rewrite>(context: &RewriteContext,
rewrite: &R,
shape: Shape)
-> Option<String> {
rewrite.rewrite(context,
Shape::legacy(try_opt!(shape.width.checked_sub(suffix.len())),
shape.indent))
rewrite.rewrite(context, try_opt!(shape.sub_width(suffix.len())))
.map(|mut r| {
r.push_str(suffix);
r
@@ -1960,9 +1928,9 @@ fn rewrite_assignment(context: &RewriteContext,
};
// 1 = space between lhs and operator.
let max_width = try_opt!(shape.width.checked_sub(operator_str.len() + 1));
let lhs_shape = try_opt!(shape.sub_width(operator_str.len() + 1));
let lhs_str = format!("{} {}",
try_opt!(lhs.rewrite(context, Shape::legacy(max_width, shape.indent))),
try_opt!(lhs.rewrite(context, lhs_shape)),
operator_str);
rewrite_assign_rhs(context, lhs_str, rhs, shape)
@@ -1985,7 +1953,9 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
// 1 = space between operator and rhs.
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));
Shape::offset(max_width,
shape.indent.block_only(),
shape.indent.alignment + last_line_width + 1));
fn count_line_breaks(src: &str) -> usize {
src.chars().filter(|&x| x == '\n').count()
@@ -2003,8 +1973,7 @@ fn count_line_breaks(src: &str) -> usize {
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, Shape::legacy(max_width, new_offset));
let new_rhs = ex.rewrite(context, Shape::legacy(max_width, new_offset));
// FIXME: DRY!
match (rhs, new_rhs) {
+28 -27
View File
@@ -70,12 +70,12 @@ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
if let Some(ref ex) = self.init {
// 1 = trailing semicolon;
let budget = try_opt!(shape.width.checked_sub(context.block_indent.width() + 1));
let budget = try_opt!(shape.width.checked_sub(shape.indent.block_only().width() + 1));
result = try_opt!(rewrite_assign_rhs(&context,
result,
ex,
Shape::legacy(budget, context.block_indent)));
Shape::legacy(budget, shape.indent.block_only())));
}
result.push(';');
@@ -520,7 +520,7 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
context.config,
context.config.item_brace_style,
Shape::legacy(where_budget,
context.block_indent),
offset.block_only()),
context.config.where_density,
"{",
true,
@@ -539,7 +539,7 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
result.push('\n');
let width = context.block_indent.width() + context.config.tab_spaces - 1;
let width = offset.block_indent + context.config.tab_spaces - 1;
let where_indent = Indent::new(0, width);
result.push_str(&where_indent.to_string(context.config));
}
@@ -568,7 +568,7 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = context.block_indent.block_indent(context.config);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
for item in items {
@@ -578,7 +578,7 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
visitor.format_missing(item.span.hi - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string(context.config);
let outer_indent_str = context.block_indent.to_string(context.config);
let outer_indent_str = offset.block_only().to_string(context.config);
result.push('\n');
result.push_str(&inner_indent_str);
@@ -654,7 +654,7 @@ fn format_impl_ref_and_type(context: &RewriteContext,
result.push('\n');
// Add indentation of one additional tab.
let width = context.block_indent.width() + context.config.tab_spaces;
let width = offset.block_indent + context.config.tab_spaces;
let for_indent = Indent::new(0, width);
result.push_str(&for_indent.to_string(context.config));
@@ -762,7 +762,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
if offset.width() + last_line_width(&result) + trait_bound_str.len() >
context.config.ideal_width {
result.push('\n');
let trait_indent = context.block_indent.block_indent(context.config);
let trait_indent = offset.block_only().block_indent(context.config);
result.push_str(&trait_indent.to_string(context.config));
}
result.push_str(&trait_bound_str);
@@ -789,7 +789,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
context.config,
context.config.item_brace_style,
Shape::legacy(where_budget,
context.block_indent),
offset.block_only()),
where_density,
"{",
has_body,
@@ -800,7 +800,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
last_line_width(&result) + where_clause_str.len() + offset.width() >
context.config.ideal_width {
result.push('\n');
let width = context.block_indent.width() + context.config.tab_spaces - 1;
let width = offset.block_indent + context.config.tab_spaces - 1;
let where_indent = Indent::new(0, width);
result.push_str(&where_indent.to_string(context.config));
}
@@ -829,7 +829,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
visitor.block_indent = context.block_indent.block_indent(context.config);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
for item in trait_items {
@@ -839,7 +839,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
visitor.format_missing(item.span.hi - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string(context.config);
let outer_indent_str = context.block_indent.to_string(context.config);
let outer_indent_str = offset.block_only().to_string(context.config);
result.push('\n');
result.push_str(&inner_indent_str);
@@ -892,7 +892,7 @@ fn format_struct_struct(context: &RewriteContext,
}
None => {
if context.config.item_brace_style == BraceStyle::AlwaysNextLine && !fields.is_empty() {
format!("\n{}{{", context.block_indent.to_string(context.config))
format!("\n{}{{", offset.block_only().to_string(context.config))
} else {
" {".to_owned()
}
@@ -1004,7 +1004,7 @@ fn format_tuple_struct(context: &RewriteContext,
&generics.where_clause,
context.config,
context.config.item_brace_style,
Shape::legacy(where_budget, context.block_indent),
Shape::legacy(where_budget, offset.block_only()),
Density::Compressed,
";",
false,
@@ -1014,7 +1014,7 @@ fn format_tuple_struct(context: &RewriteContext,
};
result.push('(');
let item_indent = context.block_indent + result.len();
let item_indent = offset.block_only() + result.len();
// 2 = ");"
let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
@@ -1052,12 +1052,12 @@ fn format_tuple_struct(context: &RewriteContext,
if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
(result.contains('\n') ||
context.block_indent.width() + result.len() + where_clause_str.len() + 1 >
offset.block_indent + result.len() + where_clause_str.len() + 1 >
context.config.max_width) {
// We need to put the where clause on a new line, but we didn'to_string
// know that earlier, so the where clause will not be indented properly.
result.push('\n');
result.push_str(&(context.block_indent + (context.config.tab_spaces - 1))
result.push_str(&(offset.block_only() + (context.config.tab_spaces - 1))
.to_string(context.config));
}
result.push_str(&where_clause_str);
@@ -1192,6 +1192,7 @@ pub fn rewrite_static(prefix: &str,
ty: &ast::Ty,
mutability: ast::Mutability,
expr_opt: Option<&ptr::P<ast::Expr>>,
offset: Indent,
context: &RewriteContext)
-> Option<String> {
let type_annotation_spacing = type_annotation_spacing(context.config);
@@ -1205,19 +1206,19 @@ pub fn rewrite_static(prefix: &str,
// 2 = " =".len()
let ty_str = try_opt!(ty.rewrite(context,
Shape::legacy(context.config.max_width -
context.block_indent.width() -
offset.block_indent -
prefix.len() -
2,
context.block_indent)));
offset.block_only())));
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;
let remaining_width = context.config.max_width - offset.block_indent - 1;
rewrite_assign_rhs(context,
lhs,
expr,
Shape::legacy(remaining_width, context.block_indent))
Shape::legacy(remaining_width, offset.block_only()))
.map(|s| s + ";")
} else {
let lhs = format!("{}{};", prefix, ty_str);
@@ -1253,10 +1254,10 @@ pub fn rewrite_associated_type(ident: ast::Ident,
if let Some(ty) = ty_opt {
let ty_str = try_opt!(ty.rewrite(context,
Shape::legacy(context.config.max_width -
context.block_indent.width() -
indent.block_indent -
prefix.len() -
2,
context.block_indent)));
indent.block_only())));
Some(format!("{} = {};", prefix, ty_str))
} else {
Some(format!("{}{};", prefix, type_bounds_str))
@@ -1473,7 +1474,7 @@ fn rewrite_fn_base(context: &RewriteContext,
multi_line_budget = context.config.max_width - arg_indent.width();
}
debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
debug!("rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
one_line_budget,
multi_line_budget,
arg_indent);
@@ -2020,7 +2021,7 @@ fn format_generics(context: &RewriteContext,
context.config,
brace_style,
Shape::legacy(budget,
context.block_indent),
offset.block_only()),
Density::Tall,
terminator,
true,
@@ -2029,7 +2030,7 @@ fn format_generics(context: &RewriteContext,
if !force_same_line_brace &&
(brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
result.push('\n');
result.push_str(&context.block_indent.to_string(context.config));
result.push_str(&offset.block_only().to_string(context.config));
} else {
result.push(' ');
}
@@ -2037,7 +2038,7 @@ fn format_generics(context: &RewriteContext,
} else {
if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
result.push('\n');
result.push_str(&context.block_indent.to_string(context.config));
result.push_str(&offset.block_only().to_string(context.config));
} else {
result.push(' ');
}
+93 -3
View File
@@ -133,6 +133,13 @@ pub fn empty() -> Indent {
Indent::new(0, 0)
}
pub fn block_only(&self) -> Indent {
Indent {
block_indent: self.block_indent,
alignment: 0,
}
}
pub fn block_indent(mut self, config: &Config) -> Indent {
self.block_indent += config.tab_spaces;
self
@@ -204,7 +211,11 @@ fn sub(self, rhs: usize) -> Indent {
#[derive(Copy, Clone, Debug)]
pub struct Shape {
pub width: usize,
// The current indentation of code.
pub indent: Indent,
// Indentation + any already emitted text on the first line of the current
// statement.
pub offset: usize,
}
impl Shape {
@@ -212,6 +223,7 @@ pub fn indented(indent: Indent, config: &Config) -> Shape {
Shape {
width: config.max_width,
indent: indent,
offset: indent.width(),
}
}
@@ -234,14 +246,92 @@ pub fn legacy(width: usize, indent: Indent) -> Shape {
Shape {
width: width,
indent: indent,
offset: indent.alignment,
}
}
pub fn sub_width(self, width: usize) -> Shape {
pub fn offset(width: usize, indent: Indent, offset: usize) -> Shape {
Shape {
width: self.width - width,
indent: self.indent,
width: width,
indent: indent,
offset: offset,
}
}
pub fn visual_indent(&self, extra_width: usize) -> Shape {
let alignment = self.offset + extra_width;
Shape {
width: self.width,
indent: Indent {
block_indent: self.indent.block_indent,
alignment: alignment,
},
offset: alignment,
}
}
pub fn block_indent(&self, extra_width: usize) -> Shape {
if self.indent.alignment == 0 {
Shape {
width: self.width,
indent: Indent {
block_indent: self.indent.block_indent + extra_width,
alignment: 0,
},
offset: 0,
}
} else {
Shape {
width: self.width,
indent: Indent {
block_indent: self.indent.block_indent,
alignment: self.indent.alignment + extra_width,
},
offset: self.indent.alignment + extra_width,
}
}
}
pub fn add_offset(&self, extra_width: usize) -> Shape {
Shape {
width: self.width,
indent: Indent {
block_indent: self.indent.block_indent,
alignment: self.indent.alignment,
},
offset: self.offset + extra_width,
}
}
pub fn block(&self) -> Shape {
Shape {
width: self.width,
indent: Indent {
block_indent: self.indent.block_indent,
alignment: 0,
},
offset: self.offset,
}
}
pub fn sub_width(&self, width: usize) -> Option<Shape> {
Some(Shape {
width: try_opt!(self.width.checked_sub(width)),
indent: self.indent,
offset: self.offset,
})
}
pub fn shrink_left(&self, width: usize) -> Option<Shape> {
Some(Shape {
width: try_opt!(self.width.checked_sub(width)),
indent: self.indent + width,
offset: self.offset + width,
})
}
pub fn used_width(&self) -> usize {
self.indent.block_indent + self.offset
}
}
+2 -3
View File
@@ -155,15 +155,14 @@ pub fn rewrite_macro(mac: &ast::Mac,
MacroStyle::Brackets => {
// Format macro invocation as array literal.
let extra_offset = macro_name.len();
let shape = try_opt!(shape.shrink_left(extra_offset));
let rewrite = try_opt!(rewrite_array(expr_vec.iter().map(|x| &**x),
mk_sp(context.codemap
.span_after(mac.span,
original_style.opener()),
mac.span.hi - BytePos(1)),
context,
Shape::legacy(try_opt!(shape.width
.checked_sub(extra_offset)),
shape.indent + extra_offset)));
shape));
Some(format!("{}{}", macro_name, rewrite))
}
+5 -5
View File
@@ -220,16 +220,16 @@ 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!(shape.width.checked_sub(path_len + if add_comma { 3 } else { 2 }));
let nested_shape = try_opt!(shape.sub_width(path_len + if add_comma { 3 } else { 2 }));
// 1 = "(".len()
let offset = shape.indent + path_len + 1;
let nested_shape = nested_shape.visual_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)),
|item| item.rewrite(context, nested_shape),
context.codemap.span_after(span, "("),
span.hi - BytePos(1))
.collect();
@@ -242,10 +242,10 @@ 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, Shape::legacy(width, offset), context.config))
try_opt!(format_item_list(da_iter, nested_shape, context.config))
} else {
try_opt!(format_item_list(items.into_iter(),
Shape::legacy(width, offset),
nested_shape,
context.config))
};
+1 -12
View File
@@ -13,7 +13,7 @@
use syntax::codemap::{CodeMap, Span};
use syntax::parse::ParseSess;
use {Indent, Shape};
use Shape;
use config::Config;
pub trait Rewrite {
@@ -26,20 +26,9 @@ pub struct RewriteContext<'a> {
pub parse_session: &'a ParseSess,
pub codemap: &'a CodeMap,
pub config: &'a Config,
// Indentation due to nesting of blocks.
pub block_indent: Indent,
}
impl<'a> RewriteContext<'a> {
pub fn nested_context(&self) -> RewriteContext<'a> {
RewriteContext {
parse_session: self.parse_session,
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent.block_indent(self.config),
}
}
pub fn snippet(&self, span: Span) -> String {
self.codemap.span_to_snippet(span).unwrap()
}
+3 -2
View File
@@ -36,7 +36,8 @@ 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.shape.indent.to_string(fmt.config);
let shape = fmt.shape.visual_indent(0);
let indent = shape.indent.to_string(fmt.config);
let punctuation = ":,;.";
// `cur_start` is the position in `orig` of the start of the current line.
@@ -49,7 +50,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.shape.width.checked_sub(fmt.opener.len() + ender_length + 1)) + 1;
let max_chars = try_opt!(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.
+16 -24
View File
@@ -66,9 +66,9 @@ pub fn rewrite_path(context: &RewriteContext,
result.push_str("::");
}
let extra_offset = extra_offset(&result, shape.indent);
let extra_offset = extra_offset(&result, shape);
// 3 = ">::".len()
let budget = try_opt!(shape.width.checked_sub(extra_offset + 3));
let shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(3));
result = try_opt!(rewrite_path_segments(PathContext::Type,
result,
@@ -76,8 +76,7 @@ pub fn rewrite_path(context: &RewriteContext,
span_lo,
path.span.hi,
context,
Shape::legacy(budget,
shape.indent + extra_offset)));
shape));
}
if context.config.spaces_within_angle_brackets {
@@ -88,15 +87,15 @@ pub fn rewrite_path(context: &RewriteContext,
span_lo = qself.ty.span.hi + BytePos(1);
}
let extra_offset = extra_offset(&result, shape.indent);
let budget = try_opt!(shape.width.checked_sub(extra_offset));
let extra_offset = extra_offset(&result, shape);
let shape = try_opt!(shape.shrink_left(extra_offset));
rewrite_path_segments(path_context,
result,
path.segments.iter().skip(skip_count),
span_lo,
path.span.hi,
context,
Shape::legacy(budget, shape.indent + extra_offset))
shape)
}
fn rewrite_path_segments<'a, I>(path_context: PathContext,
@@ -110,6 +109,7 @@ fn rewrite_path_segments<'a, I>(path_context: PathContext,
where I: Iterator<Item = &'a ast::PathSegment>
{
let mut first = true;
let shape = shape.visual_indent(0);
for segment in iter {
// Indicates a global path, shouldn't be rendered.
@@ -122,15 +122,14 @@ fn rewrite_path_segments<'a, I>(path_context: PathContext,
buffer.push_str("::");
}
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 extra_offset = extra_offset(&buffer, shape);
let new_shape = try_opt!(shape.shrink_left(extra_offset));
let segment_string = try_opt!(rewrite_segment(path_context,
segment,
&mut span_lo,
span_hi,
context,
Shape::legacy(remaining_width, new_offset)));
new_shape));
buffer.push_str(&segment_string);
}
@@ -190,8 +189,7 @@ fn rewrite_segment(path_context: PathContext,
shape: Shape)
-> Option<String> {
let ident_len = segment.identifier.to_string().len();
let width = try_opt!(shape.width.checked_sub(ident_len));
let offset = shape.indent + ident_len;
let shape = try_opt!(shape.shrink_left(ident_len));
let params = if let Some(ref params) = segment.parameters {
match **params {
@@ -216,24 +214,18 @@ fn rewrite_segment(path_context: PathContext,
// 1 for <
let extra_offset = 1 + separator.len();
// 1 for >
let list_width = try_opt!(width.checked_sub(extra_offset + 1));
// TODO bad visual indent
let list_shape = try_opt!(try_opt!(shape.shrink_left(extra_offset)).sub_width(1)).visual_indent(0);
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))
},
|seg| seg.rewrite(context, list_shape),
list_lo,
span_hi);
let list_str = try_opt!(format_item_list(items,
Shape::legacy(list_width,
offset + extra_offset),
context.config));
let list_str = try_opt!(format_item_list(items, list_shape, context.config));
// Update position of last bracket.
*span_lo = next_span_lo;
@@ -254,7 +246,7 @@ fn rewrite_segment(path_context: PathContext,
false,
data.span,
context,
Shape::legacy(width, offset)))
shape))
}
_ => String::new(),
}
+3 -3
View File
@@ -18,16 +18,16 @@
use syntax::codemap::BytePos;
use syntax::abi;
use {Indent, Shape};
use Shape;
use rewrite::{Rewrite, RewriteContext};
use SKIP_ANNOTATION;
// Computes the length of a string's last line, minus offset.
pub fn extra_offset(text: &str, offset: Indent) -> usize {
pub fn extra_offset(text: &str, shape: Shape) -> usize {
match text.rfind('\n') {
// 1 for newline character
Some(idx) => text.len().checked_sub(idx + 1 + offset.width()).unwrap_or(0),
Some(idx) => text.len().checked_sub(idx + 1 + shape.used_width()).unwrap_or(0),
None => text.len(),
}
}
+4 -1
View File
@@ -294,6 +294,7 @@ pub fn visit_item(&mut self, item: &ast::Item) {
ty,
mutability,
Some(expr),
self.block_indent,
&self.get_context());
self.push_rewrite(item.span, rewrite);
}
@@ -304,6 +305,7 @@ pub fn visit_item(&mut self, item: &ast::Item) {
ty,
ast::Mutability::Immutable,
Some(expr),
self.block_indent,
&self.get_context());
self.push_rewrite(item.span, rewrite);
}
@@ -353,6 +355,7 @@ pub fn visit_trait_item(&mut self, ti: &ast::TraitItem) {
ty,
ast::Mutability::Immutable,
expr_opt.as_ref(),
self.block_indent,
&self.get_context());
self.push_rewrite(ti.span, rewrite);
}
@@ -403,6 +406,7 @@ pub fn visit_impl_item(&mut self, ii: &ast::ImplItem) {
ty,
ast::Mutability::Immutable,
Some(expr),
self.block_indent,
&self.get_context());
self.push_rewrite(ii.span, rewrite);
}
@@ -560,7 +564,6 @@ pub fn get_context(&self) -> RewriteContext {
parse_session: self.parse_session,
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent,
}
}
}