use std::cmp::{min, Ordering};
use std::fmt::Write;
-use std::iter::ExactSizeIterator;
+use std::iter::{repeat, ExactSizeIterator};
use syntax::{ast, ptr};
use syntax::codemap::{BytePos, CodeMap, Span};
use {Indent, Shape, Spanned};
use chains::rewrite_chain;
-use codemap::SpanUtils;
-use comment::{contains_comment, recover_comment_removed, rewrite_comment, FindUncommented};
+use codemap::{LineRangeUtils, SpanUtils};
+use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
+ rewrite_comment, rewrite_missing_comment, FindUncommented};
use config::{Config, ControlBraceStyle, IndentStyle, MultilineStyle, Style};
use items::{span_hi_for_arg, span_lo_for_arg};
use lists::{definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting,
struct_lit_shape, struct_lit_tactic, write_list, DefinitiveListTactic, ListFormatting,
- ListItem, ListTactic, SeparatorTactic};
-use macros::{rewrite_macro, MacroPosition};
+ ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
+use macros::{rewrite_macro, MacroArg, MacroPosition};
use patterns::{can_be_overflowed_pat, TuplePatField};
use rewrite::{Rewrite, RewriteContext};
use string::{rewrite_string, StringFormat};
use types::{can_be_overflowed_type, rewrite_path, PathContext};
use utils::{binary_search, colon_spaces, contains_skip, extra_offset, first_line_width,
- last_line_extendable, last_line_width, left_most_sub_expr, mk_sp, paren_overhead,
- semicolon_for_stmt, stmt_expr, trimmed_last_line_width, wrap_str};
+ inner_attributes, last_line_extendable, last_line_width, left_most_sub_expr, mk_sp,
+ outer_attributes, paren_overhead, semicolon_for_stmt, stmt_expr,
+ trimmed_last_line_width, wrap_str};
use vertical::rewrite_with_alignment;
use visitor::FmtVisitor;
}
}
-#[derive(PartialEq)]
+#[derive(Copy, Clone, PartialEq)]
pub enum ExprType {
Statement,
SubExpression,
}
-fn combine_attr_and_expr(
- context: &RewriteContext,
- shape: Shape,
- attr_str: &str,
- expr_str: &str,
-) -> String {
- let separator = if attr_str.is_empty() {
- String::new()
- } else {
- if expr_str.contains('\n') || attr_str.contains('\n') ||
- attr_str.len() + expr_str.len() > shape.width
- {
- format!("\n{}", shape.indent.to_string(context.config))
- } else {
- String::from(" ")
- }
- };
- format!("{}{}{}", attr_str, separator, expr_str)
-}
-
pub fn format_expr(
expr: &ast::Expr,
expr_type: ExprType,
context: &RewriteContext,
shape: Shape,
) -> Option<String> {
- let attr_rw = (&*expr.attrs).rewrite(context, shape);
+ skip_out_of_file_lines_range!(context, expr.span);
+
if contains_skip(&*expr.attrs) {
- if let Some(attr_str) = attr_rw {
- return Some(combine_attr_and_expr(
- context,
- shape,
- &attr_str,
- &context.snippet(expr.span),
- ));
- } else {
- return Some(context.snippet(expr.span));
- }
+ return Some(context.snippet(expr.span()));
}
+
let expr_rw = match expr.node {
ast::ExprKind::Array(ref expr_vec) => rewrite_array(
expr_vec.iter().map(|e| &**e),
- mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi),
+ mk_sp(context.codemap.span_after(expr.span, "["), expr.span.hi()),
context,
shape,
false,
),
},
ast::ExprKind::Call(ref callee, ref args) => {
- let inner_span = mk_sp(callee.span.hi, expr.span.hi);
+ let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
rewrite_call_with_binary_search(
context,
&**callee,
ExprType::Statement => {
if is_unsafe_block(block) {
block.rewrite(context, shape)
- } else {
+ } else if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
// Rewrite block without trying to put it in a single line.
- if let rw @ Some(_) = rewrite_empty_block(context, block, shape) {
- return rw;
- }
+ rw
+ } else {
let prefix = try_opt!(block_prefix(context, block, shape));
rewrite_block_with_visitor(context, &prefix, block, shape)
}
}
}
ast::ExprKind::Match(ref cond, ref arms) => {
- rewrite_match(context, cond, arms, shape, expr.span)
+ rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
}
ast::ExprKind::Path(ref qself, ref path) => {
rewrite_path(context, PathContext::Expr, qself.as_ref(), path, shape)
)
}
}
+ ast::ExprKind::Yield(ref opt_expr) => if let Some(ref expr) = *opt_expr {
+ rewrite_unary_prefix(context, "yield ", &**expr, shape)
+ } else {
+ wrap_str("yield".to_string(), context.config.max_width(), shape)
+ },
ast::ExprKind::Closure(capture, ref fn_decl, ref body, _) => {
rewrite_closure(capture, fn_decl, body, expr.span, context, shape)
}
}
match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
- (Some(ref lhs), Some(ref rhs)) => {
+ (Some(lhs), Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {} ", delim)
} else if needs_space_before_range(context, lhs) {
} else {
delim.into()
};
- rewrite_pair(&**lhs, &**rhs, "", &sp_delim, "", context, shape)
+ rewrite_pair(&*lhs, &*rhs, "", &sp_delim, "", context, shape)
}
- (None, Some(ref rhs)) => {
+ (None, Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!("{} ", delim)
} else {
delim.into()
};
- rewrite_unary_prefix(context, &sp_delim, &**rhs, shape)
+ rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
}
- (Some(ref lhs), None) => {
+ (Some(lhs), None) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {}", delim)
} else {
delim.into()
};
- rewrite_unary_suffix(context, &sp_delim, &**lhs, shape)
+ rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
}
(None, None) => wrap_str(delim.into(), context.config.max_width(), shape),
}
shape,
),
ast::ExprKind::Catch(ref block) => {
- if let rewrite @ Some(_) =
- rewrite_single_line_block(context, "do catch ", block, shape)
- {
- return rewrite;
+ if let rw @ Some(_) = rewrite_single_line_block(context, "do catch ", block, shape) {
+ rw
+ } else {
+ // 9 = `do catch `
+ let budget = shape.width.checked_sub(9).unwrap_or(0);
+ Some(format!(
+ "{}{}",
+ "do catch ",
+ try_opt!(block.rewrite(&context, Shape::legacy(budget, shape.indent)))
+ ))
}
- // 9 = `do catch `
- let budget = shape.width.checked_sub(9).unwrap_or(0);
- Some(format!(
- "{}{}",
- "do catch ",
- try_opt!(block.rewrite(&context, Shape::legacy(budget, shape.indent)))
- ))
}
};
- match (attr_rw, expr_rw) {
- (Some(attr_str), Some(expr_str)) => recover_comment_removed(
- combine_attr_and_expr(context, shape, &attr_str, &expr_str),
- expr.span,
- context,
- shape,
- ),
- _ => None,
- }
+
+ expr_rw
+ .and_then(|expr_str| {
+ recover_comment_removed(expr_str, expr.span, context, shape)
+ })
+ .and_then(|expr_str| {
+ let attrs = outer_attributes(&expr.attrs);
+ let attrs_str = try_opt!(attrs.rewrite(context, shape));
+ let span = mk_sp(
+ attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
+ expr.span.lo(),
+ );
+ combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
+ })
}
pub fn rewrite_pair<LHS, RHS>(
LHS: Rewrite,
RHS: Rewrite,
{
- // 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_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_shape =
- try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width(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);
-
- let remaining_width = shape
- .width
- .checked_sub(last_line_width(&result) + suffix.len())
- .unwrap_or(0);
-
- if rhs_result.len() <= remaining_width {
- result.push_str(&rhs_result);
- result.push_str(suffix);
- return Some(result);
- }
+ let sep = if infix.ends_with(' ') { " " } else { "" };
+ let infix = infix.trim_right();
+ let lhs_overhead = shape.used_width() + prefix.len() + infix.len();
+ let lhs_shape = Shape {
+ width: try_opt!(context.config.max_width().checked_sub(lhs_overhead)),
+ ..shape
+ };
+ let lhs_result = try_opt!(
+ lhs.rewrite(context, lhs_shape)
+ .map(|lhs_str| format!("{}{}{}", prefix, lhs_str, infix))
+ );
- // Try rewriting the rhs into the remaining space.
- 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);
- }
- }
- }
- }
+ // Try to the both lhs and rhs on the same line.
+ let rhs_orig_result = shape
+ .offset_left(last_line_width(&lhs_result) + suffix.len() + sep.len())
+ .and_then(|rhs_shape| rhs.rewrite(context, rhs_shape));
+ if let Some(ref rhs_result) = rhs_orig_result {
+ // If the rhs looks like block expression, we allow it to stay on the same line
+ // with the lhs even if it is multi-lined.
+ let allow_same_line = rhs_result
+ .lines()
+ .next()
+ .map(|first_line| first_line.ends_with('{'))
+ .unwrap_or(false);
+ if !rhs_result.contains('\n') || allow_same_line {
+ return Some(format!("{}{}{}{}", lhs_result, sep, rhs_result, suffix));
}
}
// We have to use multiple lines.
-
// Re-evaluate the rhs because we have more space now:
- let infix = infix.trim_right();
let rhs_shape = match context.config.control_style() {
Style::Legacy => {
try_opt!(shape.sub_width(suffix.len() + prefix.len())).visual_indent(prefix.len())
}
};
let rhs_result = try_opt!(rhs.rewrite(context, rhs_shape));
- let lhs_overhead = shape.used_width() + prefix.len() + infix.len();
- let lhs_shape = Shape {
- width: try_opt!(context.config.max_width().checked_sub(lhs_overhead)),
- ..shape
- };
- let lhs_result = try_opt!(lhs.rewrite(context, lhs_shape));
Some(format!(
- "{}{}{}\n{}{}{}",
- prefix,
+ "{}\n{}{}{}",
lhs_result,
- infix,
rhs_shape.indent.to_string(context.config),
rhs_result,
suffix
1 // "["
};
- let mut nested_shape = match context.config.array_layout() {
+ let nested_shape = match context.config.array_layout() {
IndentStyle::Block => try_opt!(
shape
.block()
context.codemap,
expr_iter,
"]",
- |item| item.span.lo,
- |item| item.span.hi,
+ |item| item.span.lo(),
+ |item| item.span.hi(),
|item| item.rewrite(context, nested_shape),
- span.lo,
- span.hi,
+ span.lo(),
+ span.hi(),
+ false,
).collect::<Vec<_>>();
if items.is_empty() {
Some(width) => {
let tactic =
ListTactic::LimitedHorizontalVertical(context.config.array_width());
- definitive_tactic(&items, tactic, width)
+ definitive_tactic(&items, tactic, Separator::Comma, width)
}
None => DefinitiveListTactic::Vertical,
}
definitive_tactic(
&items,
ListTactic::LimitedHorizontalVertical(context.config.array_width()),
+ Separator::Comma,
nested_shape.width,
)
} else {
DefinitiveListTactic::Mixed
},
};
- let mut ends_with_newline = tactic.ends_with_newline(context.config.array_layout());
+ let ends_with_newline = tactic.ends_with_newline(context.config.array_layout());
if context.config.array_horizontal_layout_threshold() > 0 &&
items.len() > context.config.array_horizontal_layout_threshold()
{
tactic = DefinitiveListTactic::Mixed;
- ends_with_newline = false;
- if context.config.array_layout() == IndentStyle::Block {
- nested_shape = try_opt!(
- shape
- .visual_indent(bracket_size)
- .sub_width(bracket_size * 2)
- );
- }
}
let fmt = ListFormatting {
} else {
SeparatorTactic::Vertical
},
+ separator_place: SeparatorPlace::Back,
shape: nested_shape,
ends_with_newline: ends_with_newline,
+ preserve_newline: false,
config: context.config,
};
let list_str = try_opt!(write_list(&items, &fmt));
let result = if context.config.array_layout() == IndentStyle::Visual ||
- tactic != DefinitiveListTactic::Vertical
+ tactic == DefinitiveListTactic::Horizontal
{
- if context.config.spaces_within_square_brackets() && list_str.len() > 0 {
+ if context.config.spaces_within_square_brackets() && !list_str.is_empty() {
format!("[ {} ]", list_str)
} else {
format!("[{}]", list_str)
// 1 = |
let argument_offset = nested_shape.indent + 1;
- let arg_shape = try_opt!(nested_shape.shrink_left(1)).visual_indent(0);
+ let arg_shape = try_opt!(nested_shape.offset_left(1)).visual_indent(0);
let ret_str = try_opt!(fn_decl.output.rewrite(context, arg_shape));
let arg_items = itemize_list(
|arg| span_hi_for_arg(context, arg),
|arg| arg.rewrite(context, arg_shape),
context.codemap.span_after(span, "|"),
- body.span.lo,
+ body.span.lo(),
+ false,
);
let item_vec = arg_items.collect::<Vec<_>>();
// 1 = space between arguments and return type.
.width
.checked_sub(ret_str.len() + 1)
.unwrap_or(0);
- let tactic = definitive_tactic(&item_vec, ListTactic::HorizontalVertical, horizontal_budget);
+ let tactic = definitive_tactic(
+ &item_vec,
+ ListTactic::HorizontalVertical,
+ Separator::Comma,
+ horizontal_budget,
+ );
let arg_shape = match tactic {
DefinitiveListTactic::Horizontal => try_opt!(arg_shape.sub_width(ret_str.len() + 1)),
_ => arg_shape,
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
shape: arg_shape,
ends_with_newline: false,
+ preserve_newline: true,
config: context.config,
};
let list_str = try_opt!(write_list(&item_vec, &fmt));
}
// Figure out if the block is necessary.
- let needs_block = block.rules != ast::BlockCheckMode::Default ||
- block.stmts.len() > 1 || context.inside_macro ||
+ let needs_block = block.rules != ast::BlockCheckMode::Default || block.stmts.len() > 1 ||
+ context.inside_macro ||
block_contains_comment(block, context.codemap) ||
prefix.contains('\n');
};
if no_return_type && !needs_block {
// lock.stmts.len() == 1
- if let Some(ref expr) = stmt_expr(&block.stmts[0]) {
+ if let Some(expr) = stmt_expr(&block.stmts[0]) {
if let Some(rw) = rewrite_closure_expr(expr, &prefix, context, body_shape) {
return Some(rw);
}
}
// Either we require a block, or tried without and failed.
- rewrite_closure_block(&block, &prefix, context, body_shape)
+ rewrite_closure_block(block, &prefix, context, body_shape)
} else {
rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
// The closure originally had a non-block expression, but we can't fit on
if classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(expr)) {
rewrite = and_one_line(rewrite);
}
+ rewrite = rewrite.and_then(|rw| {
+ if context.config.multiline_closure_forces_block() && rw.contains('\n') {
+ None
+ } else {
+ Some(rw)
+ }
+ });
rewrite.map(|rw| format!("{} {}", prefix, rw))
}
// closure is large.
let block_threshold = context.config.closure_block_indent_threshold();
if block_threshold >= 0 {
- if let Some(block_str) = block.rewrite(&context, shape) {
+ if let Some(block_str) = block.rewrite(context, shape) {
if block_str.matches('\n').count() <= block_threshold as usize &&
!need_block_indent(&block_str, shape)
{
// The body of the closure is big enough to be block indented, that
// means we must re-format.
let block_shape = shape.block();
- let block_str = try_opt!(block.rewrite(&context, block_shape));
+ let block_str = try_opt!(block.rewrite(context, block_shape));
Some(format!("{} {}", prefix, block_str))
}
block: &ast::Block,
shape: Shape,
) -> Option<String> {
- if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) &&
- shape.width >= 2
+ if block.stmts.is_empty() && !block_contains_comment(block, context.codemap) && shape.width >= 2
{
return Some("{}".to_owned());
}
ast::BlockCheckMode::Unsafe(..) => {
let snippet = context.snippet(block.span);
let open_pos = try_opt!(snippet.find_uncommented("{"));
- visitor.last_pos = block.span.lo + BytePos(open_pos as u32)
+ visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
}
- ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo,
+ ast::BlockCheckMode::Default => visitor.last_pos = block.span.lo(),
}
- visitor.visit_block(block);
- if visitor.failed && shape.indent.alignment != 0 {
- block.rewrite(
- context,
- Shape::indented(shape.indent.block_only(), context.config),
- )
- } else {
- Some(format!("{}{}", prefix, visitor.buffer))
- }
+ visitor.visit_block(block, None);
+ Some(format!("{}{}", prefix, visitor.buffer))
}
impl Rewrite for ast::Block {
impl Rewrite for ast::Stmt {
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+ skip_out_of_file_lines_range!(context, self.span());
+
let result = match self.node {
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
""
};
- format_expr(
- ex,
- match self.node {
- ast::StmtKind::Expr(_) => ExprType::SubExpression,
- ast::StmtKind::Semi(_) => ExprType::Statement,
- _ => unreachable!(),
- },
- context,
- try_opt!(shape.sub_width(suffix.len())),
- ).map(|s| s + suffix)
+ let shape = try_opt!(shape.sub_width(suffix.len()));
+ format_expr(ex, ExprType::Statement, context, shape).map(|s| s + suffix)
}
ast::StmtKind::Mac(..) | ast::StmtKind::Item(..) => None,
};
result.and_then(|res| {
- recover_comment_removed(res, self.span, context, shape)
+ recover_comment_removed(res, self.span(), context, shape)
})
}
}
let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost));
let expr = &self.block.stmts[0];
- let if_str = try_opt!(expr.rewrite(
- context,
- Shape::legacy(new_width, Indent::empty()),
- ));
+ let if_str = try_opt!(expr.rewrite(context, Shape::legacy(new_width, Indent::empty())));
let new_width = try_opt!(new_width.checked_sub(if_str.len()));
let else_expr = &else_node.stmts[0];
shape: Shape,
alt_block_sep: &str,
) -> Option<(String, usize)> {
+ // Do not take the rhs overhead from the upper expressions into account
+ // when rewriting pattern.
+ let new_width = context
+ .config
+ .max_width()
+ .checked_sub(shape.used_width())
+ .unwrap_or(0);
+ let fresh_shape = Shape {
+ width: new_width,
+ ..shape
+ };
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.shrink_left(7))
+ try_opt!(fresh_shape.offset_left(7))
} else {
- shape
+ fresh_shape
};
let label_string = rewrite_label(self.label);
let pat_expr_string = match self.cond {
Some(cond) => {
- let mut cond_shape = match context.config.control_style() {
+ let cond_shape = match context.config.control_style() {
Style::Legacy => try_opt!(constr_shape.shrink_left(offset)),
Style::Rfc => try_opt!(constr_shape.offset_left(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,
None => String::new(),
};
+ let brace_overhead =
+ if context.config.control_brace_style() != ControlBraceStyle::AlwaysNextLine {
+ // 2 = ` {`
+ 2
+ } else {
+ 0
+ };
+ let one_line_budget = context
+ .config
+ .max_width()
+ .checked_sub(constr_shape.used_width() + offset + brace_overhead)
+ .unwrap_or(0);
let force_newline_brace = context.config.control_style() == Style::Rfc &&
- pat_expr_string.contains('\n') &&
+ (pat_expr_string.contains('\n') || pat_expr_string.len() > one_line_budget) &&
!last_line_extendable(&pat_expr_string);
// Try to format if-else on single line.
let cond_span = if let Some(cond) = self.cond {
cond.span
} else {
- mk_sp(self.block.span.lo, self.block.span.lo)
+ mk_sp(self.block.span.lo(), self.block.span.lo())
};
- // for event in event
+ // `for event in event`
+ // Do not include label in the span.
+ let lo = self.label.map_or(self.span.lo(), |label| label.span.hi());
let between_kwd_cond = mk_sp(
- context.codemap.span_after(self.span, self.keyword.trim()),
- self.pat.map_or(
- cond_span.lo,
- |p| if self.matcher.is_empty() {
- p.span.lo
+ context
+ .codemap
+ .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
+ self.pat
+ .map_or(cond_span.lo(), |p| if self.matcher.is_empty() {
+ p.span.lo()
} else {
context.codemap.span_before(self.span, self.matcher.trim())
- },
- ),
+ }),
);
let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
let after_cond_comment =
- extract_comment(mk_sp(cond_span.hi, self.block.span.lo), context, shape);
+ extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
""
} else if context.config.control_brace_style() == ControlBraceStyle::AlwaysNextLine ||
- force_newline_brace
+ force_newline_brace
{
alt_block_sep
} else {
next_else_block.as_ref().map(|e| &**e),
false,
true,
- mk_sp(else_block.span.lo, self.span.hi),
+ mk_sp(else_block.span.lo(), self.span.hi()),
).rewrite(context, shape)
}
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
next_else_block.as_ref().map(|e| &**e),
false,
true,
- mk_sp(else_block.span.lo, self.span.hi),
+ mk_sp(else_block.span.lo(), self.span.hi()),
).rewrite(context, shape)
}
_ => {
};
let between_kwd_else_block = mk_sp(
- self.block.span.hi,
+ self.block.span.hi(),
context
.codemap
- .span_before(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
+ .span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
);
let between_kwd_else_block_comment =
extract_comment(between_kwd_else_block, context, shape);
let after_else = mk_sp(
context
.codemap
- .span_after(mk_sp(self.block.span.hi, else_block.span.lo), "else"),
- else_block.span.lo,
+ .span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
+ else_block.span.lo(),
);
let after_else_comment = extract_comment(after_else, context, shape);
}
fn extract_comment(span: Span, context: &RewriteContext, shape: Shape) -> Option<String> {
- let comment_str = context.snippet(span);
- if contains_comment(&comment_str) {
- let comment = try_opt!(rewrite_comment(
- comment_str.trim(),
- false,
- shape,
- context.config,
- ));
- Some(format!(
+ match rewrite_missing_comment(span, shape, context) {
+ Some(ref comment) if !comment.is_empty() => Some(format!(
"\n{indent}{}\n{indent}",
comment,
indent = shape.indent.to_string(context.config)
- ))
- } else {
- None
+ )),
+ _ => None,
}
}
// the expression.
pub fn is_simple_block(block: &ast::Block, codemap: &CodeMap) -> bool {
(block.stmts.len() == 1 && stmt_is_expr(&block.stmts[0]) &&
- !block_contains_comment(block, codemap))
+ !block_contains_comment(block, codemap))
}
/// Checks whether a block contains at most one statement or expression, and no comments.
}
}
-// inter-match-arm-comment-rules:
-// - all comments following a match arm before the start of the next arm
-// are about the second arm
-fn rewrite_match_arm_comment(
- context: &RewriteContext,
- missed_str: &str,
- shape: Shape,
- arm_indent_str: &str,
-) -> Option<String> {
- // The leading "," is not part of the arm-comment
- let missed_str = match missed_str.find_uncommented(",") {
- Some(n) => &missed_str[n + 1..],
- None => &missed_str[..],
- };
-
- let mut result = String::new();
- // any text not preceeded by a newline is pushed unmodified to the block
- let first_brk = missed_str.find(|c: char| c == '\n').unwrap_or(0);
- result.push_str(&missed_str[..first_brk]);
- let missed_str = &missed_str[first_brk..]; // If missed_str had one newline, it starts with it
+// A simple wrapper type against ast::Arm. Used inside write_list().
+struct ArmWrapper<'a> {
+ pub arm: &'a ast::Arm,
+ // True if the arm is the last one in match expression. Used to decide on whether we should add
+ // trailing comma to the match arm when `config.trailing_comma() == Never`.
+ pub is_last: bool,
+}
- let first = missed_str
- .find(|c: char| !c.is_whitespace())
- .unwrap_or(missed_str.len());
- if missed_str[..first].chars().filter(|c| c == &'\n').count() >= 2 {
- // Excessive vertical whitespace before comment should be preserved
- // FIXME handle vertical whitespace better
- result.push('\n');
- }
- let missed_str = missed_str[first..].trim();
- if !missed_str.is_empty() {
- let comment = try_opt!(rewrite_comment(&missed_str, false, shape, context.config));
- result.push('\n');
- result.push_str(arm_indent_str);
- result.push_str(&comment);
+impl<'a> ArmWrapper<'a> {
+ pub fn new(arm: &'a ast::Arm, is_last: bool) -> ArmWrapper<'a> {
+ ArmWrapper { arm, is_last }
}
+}
- Some(result)
+impl<'a> Rewrite for ArmWrapper<'a> {
+ fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
+ rewrite_match_arm(context, self.arm, shape, self.is_last)
+ }
}
fn rewrite_match(
arms: &[ast::Arm],
shape: Shape,
span: Span,
+ attrs: &[ast::Attribute],
) -> Option<String> {
if arms.is_empty() {
return None;
}
- // `match `cond` {`
+ // Do not take the rhs overhead from the upper expressions into account
+ // when rewriting match condition.
+ let new_width = try_opt!(context.config.max_width().checked_sub(shape.used_width()));
+ let cond_shape = Shape {
+ width: new_width,
+ ..shape
+ };
+ // 6 = `match `
let cond_shape = match context.config.control_style() {
- Style::Legacy => try_opt!(shape.shrink_left(6).and_then(|s| s.sub_width(2))),
- Style::Rfc => try_opt!(shape.offset_left(8)),
+ Style::Legacy => try_opt!(cond_shape.shrink_left(6)),
+ Style::Rfc => try_opt!(cond_shape.offset_left(6)),
};
let cond_str = try_opt!(cond.rewrite(context, cond_shape));
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::AlwaysNextLine => alt_block_sep.as_str(),
+ ControlBraceStyle::AlwaysNextLine => &alt_block_sep,
+ _ if last_line_extendable(&cond_str) => " ",
+ // 2 = ` {`
+ _ if cond_str.contains('\n') || cond_str.len() + 2 > cond_shape.width => &alt_block_sep,
_ => " ",
};
+ let nested_indent_str = shape
+ .indent
+ .block_indent(context.config)
+ .to_string(context.config);
+ // Inner attributes.
+ let inner_attrs = &inner_attributes(attrs);
+ let inner_attrs_str = if inner_attrs.is_empty() {
+ String::new()
+ } else {
+ try_opt!(
+ inner_attrs
+ .rewrite(context, shape)
+ .map(|s| format!("{}{}\n", nested_indent_str, s))
+ )
+ };
+
+ let open_brace_pos = if inner_attrs.is_empty() {
+ context
+ .codemap
+ .span_after(mk_sp(cond.span.hi(), arms[0].span().lo()), "{")
+ } else {
+ inner_attrs[inner_attrs.len() - 1].span().hi()
+ };
+
+ let arm_indent_str = if context.config.indent_match_arms() {
+ nested_indent_str
+ } else {
+ shape.indent.to_string(context.config)
+ };
+
Some(format!(
- "match {}{}{{{}\n{}}}",
+ "match {}{}{{\n{}{}{}\n{}}}",
cond_str,
block_sep,
- try_opt!(rewrite_match_arms(context, arms, shape, span, cond.span.hi)),
+ inner_attrs_str,
+ arm_indent_str,
+ try_opt!(rewrite_match_arms(
+ context,
+ arms,
+ shape,
+ span,
+ open_brace_pos,
+ )),
shape.indent.to_string(context.config),
))
}
-fn arm_comma(config: &Config, body: &ast::Expr) -> &'static str {
- if config.match_block_trailing_comma() {
+fn arm_comma(config: &Config, body: &ast::Expr, is_last: bool) -> &'static str {
+ if is_last && config.trailing_comma() == SeparatorTactic::Never {
+ ""
+ } else if config.match_block_trailing_comma() {
","
} else if let ast::ExprKind::Block(ref block) = body.node {
if let ast::BlockCheckMode::Default = block.rules {
}
}
+fn rewrite_match_arms(
+ context: &RewriteContext,
+ arms: &[ast::Arm],
+ shape: Shape,
+ span: Span,
+ open_brace_pos: BytePos,
+) -> Option<String> {
+ let arm_shape = if context.config.indent_match_arms() {
+ shape.block_indent(context.config.tab_spaces())
+ } else {
+ shape.block_indent(0)
+ }.with_max_width(context.config);
+
+ let arm_len = arms.len();
+ let is_last_iter = repeat(false)
+ .take(arm_len.checked_sub(1).unwrap_or(0))
+ .chain(repeat(true));
+ let items = itemize_list(
+ context.codemap,
+ arms.iter()
+ .zip(is_last_iter)
+ .map(|(arm, is_last)| ArmWrapper::new(arm, is_last)),
+ "}",
+ |arm| arm.arm.span().lo(),
+ |arm| arm.arm.span().hi(),
+ |arm| arm.rewrite(context, arm_shape),
+ open_brace_pos,
+ span.hi(),
+ false,
+ );
+ let arms_vec: Vec<_> = items.collect();
+ let fmt = ListFormatting {
+ tactic: DefinitiveListTactic::Vertical,
+ // We will add/remove commas inside `arm.rewrite()`, and hence no separator here.
+ separator: "",
+ trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
+ shape: arm_shape,
+ ends_with_newline: true,
+ preserve_newline: true,
+ config: context.config,
+ };
+
+ write_list(&arms_vec, &fmt)
+}
+
+fn rewrite_match_arm(
+ context: &RewriteContext,
+ arm: &ast::Arm,
+ shape: Shape,
+ is_last: bool,
+) -> Option<String> {
+ let (missing_span, attrs_str) = if !arm.attrs.is_empty() {
+ if contains_skip(&arm.attrs) {
+ let (_, body) = flatten_arm_body(context, &arm.body);
+ // `arm.span()` does not include trailing comma, add it manually.
+ return Some(format!(
+ "{}{}",
+ context.snippet(arm.span()),
+ arm_comma(context.config, body, is_last),
+ ));
+ }
+ (
+ mk_sp(
+ arm.attrs[arm.attrs.len() - 1].span.hi(),
+ arm.pats[0].span.lo(),
+ ),
+ try_opt!(arm.attrs.rewrite(context, shape)),
+ )
+ } else {
+ (mk_sp(arm.span().lo(), arm.span().lo()), String::new())
+ };
+ let pats_str = try_opt!(
+ rewrite_match_pattern(context, &arm.pats, &arm.guard, shape).and_then(|pats_str| {
+ combine_strs_with_missing_comments(
+ context,
+ &attrs_str,
+ &pats_str,
+ missing_span,
+ shape,
+ false,
+ )
+ })
+ );
+ rewrite_match_body(
+ context,
+ &arm.body,
+ &pats_str,
+ shape,
+ arm.guard.is_some(),
+ is_last,
+ )
+}
+
fn rewrite_match_pattern(
context: &RewriteContext,
- pats: &Vec<ptr::P<ast::Pat>>,
+ pats: &[ptr::P<ast::Pat>],
guard: &Option<ptr::P<ast::Expr>>,
shape: Shape,
) -> Option<String> {
);
let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
- let tactic = definitive_tactic(&items, ListTactic::HorizontalVertical, pat_shape.width);
+ let tactic = definitive_tactic(
+ &items,
+ ListTactic::HorizontalVertical,
+ Separator::VerticalBar,
+ pat_shape.width,
+ );
let fmt = ListFormatting {
tactic: tactic,
separator: " |",
trailing_separator: SeparatorTactic::Never,
+ separator_place: context.config.match_pattern_separator_break_point(),
shape: pat_shape,
ends_with_newline: false,
+ preserve_newline: false,
config: context.config,
};
let pats_str = try_opt!(write_list(&items, &fmt));
Some(format!("{}{}", pats_str, guard_str))
}
-fn rewrite_match_arms(
- context: &RewriteContext,
- arms: &[ast::Arm],
- shape: Shape,
- span: Span,
- cond_end_pos: BytePos,
-) -> Option<String> {
- let mut result = String::new();
-
- let arm_shape = if context.config.indent_match_arms() {
- shape.block_indent(context.config.tab_spaces())
- } else {
- shape.block_indent(0)
- }.with_max_width(context.config);
- let arm_indent_str = arm_shape.indent.to_string(context.config);
-
- let open_brace_pos = context
- .codemap
- .span_after(mk_sp(cond_end_pos, arms[0].span().lo), "{");
-
- let arm_num = arms.len();
- for (i, arm) in arms.iter().enumerate() {
- // Make sure we get the stuff between arms.
- let missed_str = if i == 0 {
- context.snippet(mk_sp(open_brace_pos, arm.span().lo))
- } else {
- context.snippet(mk_sp(arms[i - 1].span().hi, arm.span().lo))
- };
- let comment = try_opt!(rewrite_match_arm_comment(
- context,
- &missed_str,
- arm_shape,
- &arm_indent_str,
- ));
- result.push_str(&comment);
- result.push('\n');
- result.push_str(&arm_indent_str);
-
- let arm_str = rewrite_match_arm(context, arm, arm_shape);
- if let Some(ref arm_str) = arm_str {
- // Trim the trailing comma if necessary.
- if i == arm_num - 1 && context.config.trailing_comma() == SeparatorTactic::Never &&
- arm_str.ends_with(',')
- {
- result.push_str(&arm_str[0..arm_str.len() - 1])
+// (extend, body)
+// @extend: true if the arm body can be put next to `=>`
+// @body: flattened body, if the body is block with a single expression
+fn flatten_arm_body<'a>(context: &'a RewriteContext, body: &'a ast::Expr) -> (bool, &'a ast::Expr) {
+ match body.node {
+ ast::ExprKind::Block(ref block)
+ if !is_unsafe_block(block) && is_simple_block(block, context.codemap) =>
+ {
+ if let ast::StmtKind::Expr(ref expr) = block.stmts[0].node {
+ (
+ !context.config.multiline_match_arm_forces_block() &&
+ expr.can_be_overflowed(context, 1),
+ &**expr,
+ )
} else {
- result.push_str(arm_str)
- }
- } else {
- // We couldn't format the arm, just reproduce the source.
- let snippet = context.snippet(arm.span());
- result.push_str(&snippet);
- if context.config.trailing_comma() != SeparatorTactic::Never {
- result.push_str(arm_comma(context.config, &arm.body))
+ (false, &*body)
}
}
+ _ => (
+ !context.config.multiline_match_arm_forces_block() &&
+ body.can_be_overflowed(context, 1),
+ &*body,
+ ),
}
- // BytePos(1) = closing match brace.
- let last_span = mk_sp(arms[arms.len() - 1].span().hi, span.hi - BytePos(1));
- let last_comment = context.snippet(last_span);
- let comment = try_opt!(rewrite_match_arm_comment(
- context,
- &last_comment,
- arm_shape,
- &arm_indent_str,
- ));
- result.push_str(&comment);
-
- Some(result)
-}
-
-fn rewrite_match_arm(context: &RewriteContext, arm: &ast::Arm, shape: Shape) -> Option<String> {
- let attr_str = if !arm.attrs.is_empty() {
- if contains_skip(&arm.attrs) {
- return None;
- }
- format!(
- "{}\n{}",
- try_opt!(arm.attrs.rewrite(context, shape)),
- shape.indent.to_string(context.config)
- )
- } else {
- String::new()
- };
- let pats_str = try_opt!(rewrite_match_pattern(context, &arm.pats, &arm.guard, shape));
- let pats_str = attr_str + &pats_str;
- rewrite_match_body(context, &arm.body, &pats_str, shape, arm.guard.is_some())
}
fn rewrite_match_body(
pats_str: &str,
shape: Shape,
has_guard: bool,
+ is_last: bool,
) -> Option<String> {
- let (extend, body) = match body.node {
- ast::ExprKind::Block(ref block)
- if !is_unsafe_block(block) && is_simple_block(block, context.codemap) => {
- if let ast::StmtKind::Expr(ref expr) = block.stmts[0].node {
- (expr.can_be_overflowed(context, 1), &**expr)
- } else {
- (false, &**body)
- }
- }
- _ => (body.can_be_overflowed(context, 1), &**body),
- };
+ let (extend, body) = flatten_arm_body(context, body);
- let comma = arm_comma(&context.config, body);
+ let comma = arm_comma(context.config, body, is_last);
let alt_block_sep = String::from("\n") + &shape.indent.block_only().to_string(context.config);
let alt_block_sep = alt_block_sep.as_str();
- let is_block = if let ast::ExprKind::Block(..) = body.node {
- true
+ let (is_block, is_empty_block) = if let ast::ExprKind::Block(ref block) = body.node {
+ (true, is_empty_block(block, context.codemap))
} else {
- false
+ (false, false)
};
let combine_orig_body = |body_str: &str| {
let block_sep = match context.config.control_brace_style() {
ControlBraceStyle::AlwaysNextLine if is_block => alt_block_sep,
- _ if has_guard && pats_str.contains('\n') && is_block && body_str != "{}" => {
- alt_block_sep
- }
_ => " ",
};
Some(format!("{} =>{}{}{}", pats_str, block_sep, body_str, comma))
};
+ let forbid_same_line = has_guard && pats_str.contains('\n') && !is_empty_block;
+ let next_line_indent = if is_block {
+ shape.indent
+ } else {
+ shape.indent.block_indent(context.config)
+ };
let combine_next_line_body = |body_str: &str| {
- let indent_str = shape
- .indent
- .block_indent(context.config)
- .to_string(context.config);
+ if is_block {
+ return Some(format!(
+ "{} =>\n{}{}",
+ pats_str,
+ next_line_indent.to_string(context.config),
+ body_str
+ ));
+ }
+
+ let indent_str = shape.indent.to_string(context.config);
+ let nested_indent_str = next_line_indent.to_string(context.config);
let (body_prefix, body_suffix) = if context.config.wrap_match_arms() {
let comma = if context.config.match_block_trailing_comma() {
","
} else {
""
};
- (
- "{",
- format!("\n{}}}{}", shape.indent.to_string(context.config), comma),
- )
+ ("{", format!("\n{}}}{}", indent_str, comma))
} else {
("", String::from(","))
};
let block_sep = match context.config.control_brace_style() {
ControlBraceStyle::AlwaysNextLine => format!("{}{}\n", alt_block_sep, body_prefix),
_ if body_prefix.is_empty() => "\n".to_owned(),
- _ => " ".to_owned() + body_prefix + "\n",
- } + &indent_str;
+ _ if forbid_same_line => format!("{}{}\n", alt_block_sep, body_prefix),
+ _ => format!(" {}\n", body_prefix),
+ } + &nested_indent_str;
Some(format!(
"{} =>{}{}{}",
// Let's try and get the arm body on the same line as the condition.
// 4 = ` => `.len()
- let orig_arm_shape = shape
- .offset_left(extra_offset(&pats_str, shape) + 4)
+ let orig_body_shape = shape
+ .offset_left(extra_offset(pats_str, shape) + 4)
.and_then(|shape| shape.sub_width(comma.len()));
- let orig_body = if let Some(arm_shape) = orig_arm_shape {
+ let orig_body = if let Some(body_shape) = orig_body_shape {
let rewrite = nop_block_collapse(
- format_expr(body, ExprType::Statement, context, arm_shape),
- arm_shape.width,
+ format_expr(body, ExprType::Statement, context, body_shape),
+ body_shape.width,
);
match rewrite {
Some(ref body_str)
- if ((!body_str.contains('\n')) && first_line_width(body_str) <= arm_shape.width) ||
- is_block =>
+ if !forbid_same_line &&
+ (is_block ||
+ (!body_str.contains('\n') && body_str.len() <= body_shape.width)) =>
{
return combine_orig_body(body_str);
}
} else {
None
};
- let orig_budget = orig_arm_shape.map_or(0, |shape| shape.width);
+ let orig_budget = orig_body_shape.map_or(0, |shape| shape.width);
// Try putting body on the next line and see if it looks better.
- let next_line_body_shape =
- Shape::indented(shape.indent.block_indent(context.config), context.config);
+ let next_line_body_shape = Shape::indented(next_line_indent, context.config);
let next_line_body = nop_block_collapse(
format_expr(body, ExprType::Statement, context, next_line_body_shape),
next_line_body_shape.width,
);
match (orig_body, next_line_body) {
(Some(ref orig_str), Some(ref next_line_str))
- if prefer_next_line(orig_str, next_line_str) => combine_next_line_body(next_line_str),
+ if forbid_same_line || prefer_next_line(orig_str, next_line_str) =>
+ {
+ combine_next_line_body(next_line_str)
+ }
(Some(ref orig_str), _) if extend && first_line_width(orig_str) <= orig_budget => {
combine_orig_body(orig_str)
}
string: &str,
shape: Shape,
) -> bool {
- if context.codemap.lookup_char_pos(span.lo).col.0 != shape.indent.width() {
+ if context.codemap.lookup_char_pos(span.lo()).col.0 != shape.indent.width() {
return true;
}
if line.len() > shape.width {
return true;
}
- } else {
- if line.len() > shape.width + shape.indent.width() {
- return true;
- }
+ } else if line.len() > shape.width + shape.indent.width() {
+ return true;
}
}
};
rewrite_call_inner(
context,
- &callee,
+ callee,
&args.iter().map(|x| &**x).collect::<Vec<_>>(),
span,
shape,
} else {
1
};
- let used_width = extra_offset(&callee_str, shape);
+ let used_width = extra_offset(callee_str, shape);
let one_line_width = shape
.width
.checked_sub(used_width + 2 * paren_overhead)
).ok_or(Ordering::Greater)?;
let span_lo = context.codemap.span_after(span, "(");
- let args_span = mk_sp(span_lo, span.hi);
+ let args_span = mk_sp(span_lo, span.hi());
let (extendable, list_str) = rewrite_call_args(
context,
one_line_width,
args_max_width,
force_trailing_comma,
- ).or_else(|| if context.use_block_indent() {
- rewrite_call_args(
- context,
- args,
- args_span,
- Shape::indented(
- shape.block().indent.block_indent(context.config),
- context.config,
- ),
- 0,
- 0,
- force_trailing_comma,
- )
- } else {
- None
- })
- .ok_or(Ordering::Less)?;
+ ).ok_or(Ordering::Less)?;
if !context.use_block_indent() && need_block_indent(&list_str, nested_shape) && !extendable {
let mut new_context = context.clone();
}
let args_shape = shape
- .sub_width(last_line_width(&callee_str))
+ .sub_width(last_line_width(callee_str))
.ok_or(Ordering::Less)?;
Ok(format!(
"{}{}",
context.codemap,
args.iter(),
")",
- |item| item.span().lo,
- |item| item.span().hi,
+ |item| item.span().lo(),
+ |item| item.span().hi(),
|item| item.rewrite(context, shape),
- span.lo,
- span.hi,
+ span.lo(),
+ span.hi(),
+ true,
);
let mut item_vec: Vec<_> = items.collect();
} else {
context.config.trailing_comma()
},
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: context.use_block_indent() && tactic == DefinitiveListTactic::Vertical,
+ preserve_newline: false,
config: context.config,
};
where
T: Rewrite + Spanned + ToExpr + 'a,
{
- let overflow_last = can_be_overflowed(&context, args);
+ let overflow_last = can_be_overflowed(context, args);
// Replace the last item with its first line to see if it fits with
// first arguments.
- let (orig_last, placeholder) = if overflow_last {
+ let placeholder = if overflow_last {
let mut context = context.clone();
if let Some(expr) = args[args.len() - 1].to_expr() {
- match expr.node {
- ast::ExprKind::MethodCall(..) => context.force_one_line_chain = true,
- _ => (),
+ if let ast::ExprKind::MethodCall(..) = expr.node {
+ context.force_one_line_chain = true;
}
}
- last_arg_shape(&context, &item_vec, shape, args_max_width)
- .map_or((None, None), |arg_shape| {
- rewrite_last_arg_with_overflow(
- &context,
- args,
- &mut item_vec[args.len() - 1],
- arg_shape,
- )
- })
+ last_arg_shape(&context, item_vec, shape, args_max_width).and_then(|arg_shape| {
+ rewrite_last_arg_with_overflow(&context, args, &mut item_vec[args.len() - 1], arg_shape)
+ })
} else {
- (None, None)
+ None
};
- let tactic = definitive_tactic(
+ let mut tactic = definitive_tactic(
&*item_vec,
ListTactic::LimitedHorizontalVertical(args_max_width),
+ Separator::Comma,
one_line_width,
);
(true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => {
item_vec[args.len() - 1].item = placeholder;
}
- (true, _, _) => {
- item_vec[args.len() - 1].item = orig_last;
+ _ if args.len() >= 1 => {
+ item_vec[args.len() - 1].item = args.last()
+ .and_then(|last_arg| last_arg.rewrite(context, shape));
+ tactic = definitive_tactic(
+ &*item_vec,
+ ListTactic::LimitedHorizontalVertical(args_max_width),
+ Separator::Comma,
+ one_line_width,
+ );
}
- (false, _, _) => {}
+ _ => (),
}
tactic
fn last_arg_shape(
context: &RewriteContext,
- items: &Vec<ListItem>,
+ items: &[ListItem],
shape: Shape,
args_max_width: usize,
) -> Option<Shape> {
let overhead = items.iter().rev().skip(1).fold(0, |acc, i| {
- acc + i.item.as_ref().map_or(0, |s| first_line_width(&s))
+ acc + i.item.as_ref().map_or(0, |s| first_line_width(s))
});
let max_width = min(args_max_width, shape.width);
let arg_indent = if context.use_block_indent() {
let body_shape = try_opt!(shape.offset_left(extra_offset));
// When overflowing the closure which consists of a single control flow expression,
// force to use block if its condition uses multi line.
- if rewrite_cond(context, body, body_shape)
- .map(|cond| cond.contains('\n'))
- .unwrap_or(false)
- {
+ let is_multi_lined_cond = rewrite_cond(context, body, body_shape)
+ .map(|cond| cond.contains('\n') || cond.len() > body_shape.width)
+ .unwrap_or(false);
+ if is_multi_lined_cond {
return rewrite_closure_with_block(context, body_shape, &prefix, body);
}
args: &[&T],
last_item: &mut ListItem,
shape: Shape,
-) -> (Option<String>, Option<String>)
+) -> Option<String>
where
T: Rewrite + Spanned + ToExpr + 'a,
{
} else {
last_arg.rewrite(context, shape)
};
- let orig_last = last_item.item.clone();
if let Some(rewrite) = rewrite {
let rewrite_first_line = Some(rewrite[..first_line_width(&rewrite)].to_owned());
last_item.item = rewrite_first_line;
- (orig_last, Some(rewrite))
+ Some(rewrite)
} else {
- (orig_last, None)
+ None
}
}
) -> String {
if !context.use_block_indent() ||
(context.inside_macro && !args_str.contains('\n') &&
- args_str.len() + paren_overhead(context) <= shape.width) || is_extendable
+ args_str.len() + paren_overhead(context) <= shape.width) || is_extendable
{
- if context.config.spaces_within_parens() && args_str.len() > 0 {
+ if context.config.spaces_within_parens() && !args_str.is_empty() {
format!("( {} )", args_str)
} else {
format!("({})", args_str)
fn rewrite_paren(context: &RewriteContext, subexpr: &ast::Expr, shape: Shape) -> Option<String> {
debug!("rewrite_paren, shape: {:?}", shape);
- let paren_overhead = paren_overhead(context);
- let sub_shape = try_opt!(shape.sub_width(paren_overhead / 2)).visual_indent(paren_overhead / 2);
+ let total_paren_overhead = paren_overhead(context);
+ let paren_overhead = total_paren_overhead / 2;
+ let sub_shape = try_opt!(
+ shape
+ .offset_left(paren_overhead)
+ .and_then(|s| s.sub_width(paren_overhead))
+ );
- let paren_wrapper = |s: &str| if context.config.spaces_within_parens() && s.len() > 0 {
+ let paren_wrapper = |s: &str| if context.config.spaces_within_parens() && !s.is_empty() {
format!("( {} )", s)
} else {
format!("({})", s)
let subexpr_str = try_opt!(subexpr.rewrite(context, sub_shape));
debug!("rewrite_paren, subexpr_str: `{:?}`", subexpr_str);
- if subexpr_str.contains('\n') {
+ if subexpr_str.contains('\n') ||
+ first_line_width(&subexpr_str) + total_paren_overhead <= shape.width
+ {
Some(paren_wrapper(&subexpr_str))
} else {
- if subexpr_str.len() + paren_overhead <= shape.width {
- Some(paren_wrapper(&subexpr_str))
- } else {
- let sub_shape = try_opt!(shape.offset_left(2));
- let subexpr_str = try_opt!(subexpr.rewrite(context, sub_shape));
- Some(paren_wrapper(&subexpr_str))
- }
+ None
}
}
(_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!(
"{}\n{}{}{}{}",
expr_str,
- indent.to_string(&context.config),
+ indent.to_string(context.config),
lbr,
new_index_str,
rbr
(None, Some(ref new_index_str)) => Some(format!(
"{}\n{}{}{}{}",
expr_str,
- indent.to_string(&context.config),
+ indent.to_string(context.config),
lbr,
new_index_str,
rbr
path_shape,
));
- if fields.len() == 0 && base.is_none() {
+ if fields.is_empty() && base.is_none() {
return Some(format!("{} {{}}", path_str));
}
fields,
context,
shape,
- mk_sp(body_lo, span.hi),
+ mk_sp(body_lo, span.hi()),
one_line_width,
))
} else {
.chain(base.into_iter().map(StructLitField::Base));
let span_lo = |item: &StructLitField| match *item {
- StructLitField::Regular(field) => field.span().lo,
+ StructLitField::Regular(field) => field.span().lo(),
StructLitField::Base(expr) => {
- let last_field_hi = fields.last().map_or(span.lo, |field| field.span.hi);
- let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo));
+ let last_field_hi = fields.last().map_or(span.lo(), |field| field.span.hi());
+ let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo()));
let pos = snippet.find_uncommented("..").unwrap();
last_field_hi + BytePos(pos as u32)
}
};
let span_hi = |item: &StructLitField| match *item {
- StructLitField::Regular(field) => field.span().hi,
- StructLitField::Base(expr) => expr.span.hi,
+ StructLitField::Regular(field) => field.span().hi(),
+ StructLitField::Base(expr) => expr.span.hi(),
};
let rewrite = |item: &StructLitField| match *item {
StructLitField::Regular(field) => {
}
StructLitField::Base(expr) => {
// 2 = ..
- expr.rewrite(context, try_opt!(v_shape.shrink_left(2)))
+ expr.rewrite(context, try_opt!(v_shape.offset_left(2)))
.map(|s| format!("..{}", s))
}
};
span_hi,
rewrite,
body_lo,
- span.hi,
+ span.hi(),
+ false,
);
let item_vec = items.collect::<Vec<_>>();
) -> String {
if context.config.struct_lit_style() == IndentStyle::Block &&
(fields_str.contains('\n') ||
- context.config.struct_lit_multiline_style() == MultilineStyle::ForceMulti ||
- fields_str.len() > one_line_width)
+ context.config.struct_lit_multiline_style() == MultilineStyle::ForceMulti ||
+ fields_str.len() > one_line_width)
{
format!(
"\n{}{}\n{}",
"{}{}:\n{}{}",
attrs_str,
name,
- expr_offset.to_string(&context.config),
+ expr_offset.to_string(context.config),
s
)
})
context.codemap,
items,
")",
- |item| item.span().lo,
- |item| item.span().hi,
+ |item| item.span().lo(),
+ |item| item.span().hi(),
|item| item.rewrite(context, nested_shape),
list_lo,
- span.hi - BytePos(1),
+ span.hi() - BytePos(1),
+ false,
);
let item_vec: Vec<_> = items.collect();
let tactic = definitive_tactic(
&item_vec,
ListTactic::HorizontalVertical,
+ Separator::Comma,
nested_shape.width,
);
let fmt = ListFormatting {
tactic: tactic,
separator: ",",
trailing_separator: SeparatorTactic::Never,
+ separator_place: SeparatorPlace::Back,
shape: shape,
ends_with_newline: false,
+ preserve_newline: false,
config: context.config,
};
let list_str = try_opt!(write_list(&item_vec, &fmt));
- if context.config.spaces_within_parens() && list_str.len() > 0 {
+ if context.config.spaces_within_parens() && !list_str.is_empty() {
Some(format!("( {} )", list_str))
} else {
Some(format!("({})", list_str))
{
debug!("rewrite_tuple {:?}", shape);
if context.use_block_indent() {
- // We use the same rule as funcation call for rewriting tuple.
+ // We use the same rule as function calls for rewriting tuples.
let force_trailing_comma = if context.inside_macro {
span_ends_with_comma(context, span)
} else {
shape: Shape,
) -> Option<String> {
let lhs = lhs.into();
- let last_line_width = last_line_width(&lhs) -
- if lhs.contains('\n') {
- shape.indent.width()
- } else {
- 0
- };
+ let last_line_width = last_line_width(&lhs) - if lhs.contains('\n') {
+ shape.indent.width()
+ } else {
+ 0
+ };
// 1 = space between operator and rhs.
let orig_shape = try_opt!(shape.offset_left(last_line_width + 1));
let rhs = try_opt!(choose_rhs(
}
fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str) -> bool {
-
fn count_line_breaks(src: &str) -> usize {
src.chars().filter(|&x| x == '\n').count()
}
false
}
}
+
+impl<'a> ToExpr for MacroArg {
+ fn to_expr(&self) -> Option<&ast::Expr> {
+ match self {
+ &MacroArg::Expr(ref expr) => Some(expr),
+ _ => None,
+ }
+ }
+
+ fn can_be_overflowed(&self, context: &RewriteContext, len: usize) -> bool {
+ match self {
+ &MacroArg::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
+ &MacroArg::Ty(ref ty) => can_be_overflowed_type(context, ty, len),
+ &MacroArg::Pat(..) => false,
+ }
+ }
+}