Merge pull request #2838 from nrc/chains
Refactor chain formatting and fix some bugs
This commit is contained in:
commit
a24df1397e
31 changed files with 714 additions and 468 deletions
|
@ -422,8 +422,7 @@ fn determine_operation(matches: &Matches) -> Result<Operation, ErrorKind> {
|
|||
// we will do comparison later, so here tries to canonicalize first
|
||||
// to get the expected behavior.
|
||||
p.canonicalize().unwrap_or(p)
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
|
||||
Ok(Operation::Format {
|
||||
files,
|
||||
|
|
|
@ -163,8 +163,7 @@ fn format_crate(
|
|||
if verbosity == Verbosity::Verbose {
|
||||
println!("[{}] {:?}", t.kind, t.path)
|
||||
}
|
||||
})
|
||||
.map(|t| t.path)
|
||||
}).map(|t| t.path)
|
||||
.collect();
|
||||
|
||||
run_rustfmt(&files, &rustfmt_args, verbosity)
|
||||
|
|
884
src/chains.rs
884
src/chains.rs
|
@ -84,107 +84,277 @@ use syntax::codemap::Span;
|
|||
use syntax::{ast, ptr};
|
||||
|
||||
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);
|
||||
let chain = Chain::from_ast(expr, context);
|
||||
debug!("rewrite_chain {:?} {:?}", chain, shape);
|
||||
|
||||
// Bail out if the chain is just try sugar, i.e., an expression followed by
|
||||
// any number of `?`s.
|
||||
if chain_only_try(&subexpr_list) {
|
||||
return rewrite_try(&parent, subexpr_list.len(), context, shape);
|
||||
// If this is just an expression with some `?`s, then format it trivially and
|
||||
// return early.
|
||||
if chain.children.is_empty() {
|
||||
return chain.parent.rewrite(context, shape);
|
||||
}
|
||||
let suffix_try_num = subexpr_list.iter().take_while(|e| is_try(e)).count();
|
||||
let prefix_try_num = subexpr_list.iter().rev().take_while(|e| is_try(e)).count();
|
||||
|
||||
chain.rewrite(context, shape)
|
||||
}
|
||||
|
||||
// An expression plus trailing `?`s to be formatted together.
|
||||
#[derive(Debug)]
|
||||
struct ChainItem {
|
||||
// FIXME: we can't use a reference here because to convert `try!` to `?` we
|
||||
// synthesise the AST node. However, I think we could use `Cow` and that
|
||||
// would remove a lot of cloning.
|
||||
expr: ast::Expr,
|
||||
tries: usize,
|
||||
}
|
||||
|
||||
impl Rewrite for ChainItem {
|
||||
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
||||
let rewrite = self.expr.rewrite(context, shape.sub_width(self.tries)?)?;
|
||||
Some(format!("{}{}", rewrite, "?".repeat(self.tries)))
|
||||
}
|
||||
}
|
||||
|
||||
impl ChainItem {
|
||||
// Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite
|
||||
// `.c` and any trailing `?`s.
|
||||
fn rewrite_postfix(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
||||
let shape = shape.sub_width(self.tries)?;
|
||||
let mut rewrite = match self.expr.node {
|
||||
ast::ExprKind::MethodCall(ref segment, ref expressions) => {
|
||||
let types = match segment.args {
|
||||
Some(ref params) => match **params {
|
||||
ast::GenericArgs::AngleBracketed(ref data) => &data.args[..],
|
||||
_ => &[],
|
||||
},
|
||||
_ => &[],
|
||||
};
|
||||
Self::rewrite_method_call(
|
||||
segment.ident,
|
||||
types,
|
||||
expressions,
|
||||
self.expr.span,
|
||||
context,
|
||||
shape,
|
||||
)?
|
||||
}
|
||||
ast::ExprKind::Field(ref nested, ref field) => {
|
||||
let space =
|
||||
if Self::is_tup_field_access(&self.expr) && Self::is_tup_field_access(nested) {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let result = format!("{}.{}", space, field.name);
|
||||
if result.len() <= shape.width {
|
||||
result
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
rewrite.push_str(&"?".repeat(self.tries));
|
||||
Some(rewrite)
|
||||
}
|
||||
|
||||
fn is_tup_field_access(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprKind::Field(_, ref field) => {
|
||||
field.name.to_string().chars().all(|c| c.is_digit(10))
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_method_call(
|
||||
method_name: ast::Ident,
|
||||
types: &[ast::GenericArg],
|
||||
args: &[ptr::P<ast::Expr>],
|
||||
span: Span,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
let (lo, type_str) = if types.is_empty() {
|
||||
(args[0].span.hi(), String::new())
|
||||
} else {
|
||||
let type_list = types
|
||||
.iter()
|
||||
.map(|ty| ty.rewrite(context, shape))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
|
||||
let type_str = format!("::<{}>", type_list.join(", "));
|
||||
|
||||
(types.last().unwrap().span().hi(), type_str)
|
||||
};
|
||||
|
||||
let callee_str = format!(".{}{}", method_name, type_str);
|
||||
let span = mk_sp(lo, span.hi());
|
||||
|
||||
rewrite_call(context, &callee_str, &args[1..], span, shape)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Chain {
|
||||
parent: ChainItem,
|
||||
children: Vec<ChainItem>,
|
||||
}
|
||||
|
||||
impl Chain {
|
||||
fn from_ast(expr: &ast::Expr, context: &RewriteContext) -> Chain {
|
||||
let subexpr_list = Self::make_subexpr_list(expr, context);
|
||||
|
||||
// Un-parse the expression tree into ChainItems
|
||||
let mut children = vec![];
|
||||
let mut sub_tries = 0;
|
||||
for subexpr in subexpr_list {
|
||||
match subexpr.node {
|
||||
ast::ExprKind::Try(_) => sub_tries += 1,
|
||||
_ => {
|
||||
children.push(ChainItem {
|
||||
expr: subexpr,
|
||||
tries: sub_tries,
|
||||
});
|
||||
sub_tries = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Chain {
|
||||
parent: children.pop().unwrap(),
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a Vec of the prefixes of the chain.
|
||||
// E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
|
||||
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> Vec<ast::Expr> {
|
||||
let mut subexpr_list = vec![expr.clone()];
|
||||
|
||||
while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
|
||||
subexpr_list.push(subexpr.clone());
|
||||
}
|
||||
|
||||
subexpr_list
|
||||
}
|
||||
|
||||
// Returns the expression's subexpression, if it exists. When the subexpr
|
||||
// is a try! macro, we'll convert it to shorthand when the option is set.
|
||||
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option<ast::Expr> {
|
||||
match expr.node {
|
||||
ast::ExprKind::MethodCall(_, ref expressions) => {
|
||||
Some(Self::convert_try(&expressions[0], context))
|
||||
}
|
||||
ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) => {
|
||||
Some(Self::convert_try(subexpr, context))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr {
|
||||
match expr.node {
|
||||
ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand() => {
|
||||
if let Some(subexpr) = convert_try_mac(mac, context) {
|
||||
subexpr
|
||||
} else {
|
||||
expr.clone()
|
||||
}
|
||||
}
|
||||
_ => expr.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rewrite for Chain {
|
||||
fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
|
||||
debug!("rewrite chain {:?} {:?}", self, shape);
|
||||
|
||||
let mut formatter = match context.config.indent_style() {
|
||||
IndentStyle::Block => Box::new(ChainFormatterBlock::new(self)) as Box<ChainFormatter>,
|
||||
IndentStyle::Visual => Box::new(ChainFormatterVisual::new(self)) as Box<ChainFormatter>,
|
||||
};
|
||||
|
||||
formatter.format_root(&self.parent, context, shape)?;
|
||||
if let Some(result) = formatter.pure_root() {
|
||||
return wrap_str(result, context.config.max_width(), shape);
|
||||
}
|
||||
|
||||
// Decide how to layout the rest of the chain.
|
||||
let child_shape = formatter.child_shape(context, shape)?;
|
||||
|
||||
formatter.format_children(context, child_shape)?;
|
||||
formatter.format_last_child(context, shape, child_shape)?;
|
||||
|
||||
let result = formatter.join_rewrites(context, child_shape)?;
|
||||
wrap_str(result, context.config.max_width(), shape)
|
||||
}
|
||||
}
|
||||
|
||||
// There are a few types for formatting chains. This is because there is a lot
|
||||
// in common between formatting with block vs visual indent, but they are
|
||||
// different enough that branching on the indent all over the place gets ugly.
|
||||
// Anything that can format a chain is a ChainFormatter.
|
||||
trait ChainFormatter {
|
||||
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
|
||||
let parent_shape = if is_block_expr(context, &parent, "\n") {
|
||||
match context.config.indent_style() {
|
||||
IndentStyle::Visual => shape.visual_indent(0),
|
||||
IndentStyle::Block => shape,
|
||||
// Root is the parent plus any other chain items placed on the first line to
|
||||
// avoid an orphan. E.g.,
|
||||
// ```
|
||||
// foo.bar
|
||||
// .baz()
|
||||
// ```
|
||||
// If `bar` were not part of the root, then foo would be orphaned and 'float'.
|
||||
fn format_root(
|
||||
&mut self,
|
||||
parent: &ChainItem,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<()>;
|
||||
fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option<Shape>;
|
||||
fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()>;
|
||||
fn format_last_child(
|
||||
&mut self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
child_shape: Shape,
|
||||
) -> Option<()>;
|
||||
fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option<String>;
|
||||
// Returns `Some` if the chain is only a root, None otherwise.
|
||||
fn pure_root(&mut self) -> Option<String>;
|
||||
}
|
||||
|
||||
// Data and behaviour that is shared by both chain formatters. The concrete
|
||||
// formatters can delegate much behaviour to `ChainFormatterShared`.
|
||||
struct ChainFormatterShared<'a> {
|
||||
// The current working set of child items.
|
||||
children: &'a [ChainItem],
|
||||
// The current rewrites of items (includes trailing `?`s, but not any way to
|
||||
// connect the rewrites together).
|
||||
rewrites: Vec<String>,
|
||||
// Whether the chain can fit on one line.
|
||||
fits_single_line: bool,
|
||||
// The number of children in the chain. This is not equal to `self.children.len()`
|
||||
// because `self.children` will change size as we process the chain.
|
||||
child_count: usize,
|
||||
}
|
||||
|
||||
impl<'a> ChainFormatterShared<'a> {
|
||||
fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
|
||||
ChainFormatterShared {
|
||||
children: &chain.children,
|
||||
rewrites: Vec::with_capacity(chain.children.len() + 1),
|
||||
fits_single_line: false,
|
||||
child_count: chain.children.len(),
|
||||
}
|
||||
} else {
|
||||
shape
|
||||
};
|
||||
let parent_rewrite = parent
|
||||
.rewrite(context, parent_shape)
|
||||
.map(|parent_rw| parent_rw + &"?".repeat(prefix_try_num))?;
|
||||
let parent_rewrite_contains_newline = parent_rewrite.contains('\n');
|
||||
let is_small_parent = shape.offset + parent_rewrite.len() <= context.config.tab_spaces();
|
||||
}
|
||||
|
||||
// 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 (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
|
||||
(
|
||||
chain_indent(context, shape.add_offset(parent_rewrite.len())),
|
||||
context.config.indent_style() == IndentStyle::Visual || is_small_parent,
|
||||
)
|
||||
} else if is_block_expr(context, &parent, &parent_rewrite) {
|
||||
match context.config.indent_style() {
|
||||
// Try to put the first child on the same line with parent's last line
|
||||
IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true),
|
||||
// The parent is a block, so align the rest of the chain with the closing
|
||||
// brace.
|
||||
IndentStyle::Visual => (parent_shape, false),
|
||||
fn pure_root(&mut self) -> Option<String> {
|
||||
if self.children.is_empty() {
|
||||
assert_eq!(self.rewrites.len(), 1);
|
||||
Some(self.rewrites.pop().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
(
|
||||
chain_indent(context, shape.add_offset(parent_rewrite.len())),
|
||||
false,
|
||||
)
|
||||
};
|
||||
|
||||
let other_child_shape = nested_shape.with_max_width(context.config);
|
||||
|
||||
let first_child_shape = if extend {
|
||||
let overhead = last_line_width(&parent_rewrite);
|
||||
let offset = trimmed_last_line_width(&parent_rewrite) + prefix_try_num;
|
||||
match context.config.indent_style() {
|
||||
IndentStyle::Visual => parent_shape.offset_left(overhead)?,
|
||||
IndentStyle::Block => parent_shape.offset_left(offset)?,
|
||||
}
|
||||
} else {
|
||||
other_child_shape
|
||||
};
|
||||
debug!(
|
||||
"child_shapes {:?} {:?}",
|
||||
first_child_shape, other_child_shape
|
||||
);
|
||||
|
||||
let child_shape_iter = Some(first_child_shape)
|
||||
.into_iter()
|
||||
.chain(iter::repeat(other_child_shape));
|
||||
let subexpr_num = subexpr_list.len();
|
||||
let last_subexpr = &subexpr_list[suffix_try_num];
|
||||
let subexpr_list = &subexpr_list[suffix_try_num..subexpr_num - prefix_try_num];
|
||||
let iter = subexpr_list.iter().skip(1).rev().zip(child_shape_iter);
|
||||
let mut rewrites = iter
|
||||
.map(|(e, shape)| rewrite_chain_subexpr(e, total_span, context, shape))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
|
||||
// Total of all items excluding the last.
|
||||
let extend_last_subexpr = if is_small_parent {
|
||||
rewrites.len() == 1 && last_line_extendable(&rewrites[0])
|
||||
} else {
|
||||
rewrites.is_empty() && last_line_extendable(&parent_rewrite)
|
||||
};
|
||||
let almost_total = if extend_last_subexpr {
|
||||
last_line_width(&parent_rewrite)
|
||||
} else {
|
||||
rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len()
|
||||
} + suffix_try_num;
|
||||
let one_line_budget = if rewrites.is_empty() {
|
||||
shape.width
|
||||
} else {
|
||||
min(shape.width, context.config.width_heuristics().chain_width)
|
||||
};
|
||||
let all_in_one_line = !parent_rewrite_contains_newline
|
||||
&& rewrites.iter().all(|s| !s.contains('\n'))
|
||||
&& almost_total < one_line_budget;
|
||||
let last_shape = if rewrites.is_empty() {
|
||||
first_child_shape
|
||||
} else {
|
||||
other_child_shape
|
||||
}.sub_width(shape.rhs_overhead(context.config) + suffix_try_num)?;
|
||||
}
|
||||
|
||||
// Rewrite the last child. The last child of a chain requires special treatment. We need to
|
||||
// know whether 'overflowing' the last child make a better formatting:
|
||||
|
@ -218,142 +388,305 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
|
|||
// result
|
||||
// })
|
||||
// ```
|
||||
fn format_last_child(
|
||||
&mut self,
|
||||
may_extend: bool,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
child_shape: Shape,
|
||||
) -> Option<()> {
|
||||
let last = &self.children[0];
|
||||
let extendable =
|
||||
may_extend && last_line_extendable(&self.rewrites[self.rewrites.len() - 1]);
|
||||
let prev_last_line_width = last_line_width(&self.rewrites[self.rewrites.len() - 1]);
|
||||
|
||||
// `rewrite_last` rewrites the last child on its own line. We use a closure here instead of
|
||||
// directly calling `rewrite_chain_subexpr()` to avoid exponential blowup.
|
||||
let rewrite_last = || rewrite_chain_subexpr(last_subexpr, total_span, context, last_shape);
|
||||
let (last_subexpr_str, fits_single_line) = if all_in_one_line || extend_last_subexpr {
|
||||
// First we try to 'overflow' the last child and see if it looks better than using
|
||||
// vertical layout.
|
||||
parent_shape.offset_left(almost_total).map(|shape| {
|
||||
if let Some(rw) = rewrite_chain_subexpr(last_subexpr, total_span, context, shape) {
|
||||
// We allow overflowing here only if both of the following conditions match:
|
||||
// 1. The entire chain fits in a single line expect the last child.
|
||||
// 2. `last_child_str.lines().count() >= 5`.
|
||||
let line_count = rw.lines().count();
|
||||
let fits_single_line = almost_total + first_line_width(&rw) <= one_line_budget;
|
||||
if fits_single_line && line_count >= 5 {
|
||||
(Some(rw), true)
|
||||
} else {
|
||||
// We could not know whether overflowing is better than using vertical layout,
|
||||
// just by looking at the overflowed rewrite. Now we rewrite the last child
|
||||
// on its own line, and compare two rewrites to choose which is better.
|
||||
match rewrite_last() {
|
||||
Some(ref new_rw) if !fits_single_line => (Some(new_rw.clone()), false),
|
||||
Some(ref new_rw) if new_rw.lines().count() >= line_count => {
|
||||
(Some(rw), fits_single_line)
|
||||
// Total of all items excluding the last.
|
||||
let almost_total = if extendable {
|
||||
prev_last_line_width
|
||||
} else {
|
||||
self.rewrites.iter().fold(0, |a, b| a + b.len())
|
||||
} + last.tries;
|
||||
let one_line_budget = if self.child_count == 1 {
|
||||
shape.width
|
||||
} else {
|
||||
min(shape.width, context.config.width_heuristics().chain_width)
|
||||
}.saturating_sub(almost_total);
|
||||
|
||||
let all_in_one_line =
|
||||
self.rewrites.iter().all(|s| !s.contains('\n')) && one_line_budget > 0;
|
||||
let last_shape = if all_in_one_line {
|
||||
shape.sub_width(last.tries)?
|
||||
} else if extendable {
|
||||
child_shape.sub_width(last.tries)?
|
||||
} else {
|
||||
child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)?
|
||||
};
|
||||
|
||||
let mut last_subexpr_str = None;
|
||||
if all_in_one_line || extendable {
|
||||
// First we try to 'overflow' the last child and see if it looks better than using
|
||||
// vertical layout.
|
||||
if let Some(one_line_shape) = last_shape.offset_left(almost_total) {
|
||||
if let Some(rw) = last.rewrite_postfix(context, one_line_shape) {
|
||||
// We allow overflowing here only if both of the following conditions match:
|
||||
// 1. The entire chain fits in a single line except the last child.
|
||||
// 2. `last_child_str.lines().count() >= 5`.
|
||||
let line_count = rw.lines().count();
|
||||
let could_fit_single_line = first_line_width(&rw) <= one_line_budget;
|
||||
if could_fit_single_line && line_count >= 5 {
|
||||
last_subexpr_str = Some(rw);
|
||||
self.fits_single_line = all_in_one_line;
|
||||
} else {
|
||||
// We could not know whether overflowing is better than using vertical
|
||||
// layout, just by looking at the overflowed rewrite. Now we rewrite the
|
||||
// last child on its own line, and compare two rewrites to choose which is
|
||||
// better.
|
||||
let last_shape = child_shape
|
||||
.sub_width(shape.rhs_overhead(context.config) + last.tries)?;
|
||||
match last.rewrite_postfix(context, last_shape) {
|
||||
Some(ref new_rw) if !could_fit_single_line => {
|
||||
last_subexpr_str = Some(new_rw.clone());
|
||||
}
|
||||
Some(ref new_rw) if new_rw.lines().count() >= line_count => {
|
||||
last_subexpr_str = Some(rw);
|
||||
self.fits_single_line = could_fit_single_line && all_in_one_line;
|
||||
}
|
||||
new_rw @ Some(..) => {
|
||||
last_subexpr_str = new_rw;
|
||||
}
|
||||
_ => {
|
||||
last_subexpr_str = Some(rw);
|
||||
self.fits_single_line = could_fit_single_line && all_in_one_line;
|
||||
}
|
||||
}
|
||||
new_rw @ Some(..) => (new_rw, false),
|
||||
_ => (Some(rw), fits_single_line),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
(rewrite_last(), false)
|
||||
}
|
||||
})?
|
||||
} else {
|
||||
(rewrite_last(), false)
|
||||
};
|
||||
rewrites.push(last_subexpr_str?);
|
||||
|
||||
let connector = if fits_single_line && !parent_rewrite_contains_newline {
|
||||
// Yay, we can put everything on one line.
|
||||
Cow::from("")
|
||||
} else {
|
||||
// Use new lines.
|
||||
if *context.force_one_line_chain.borrow() {
|
||||
return None;
|
||||
}
|
||||
nested_shape.indent.to_string_with_newline(context.config)
|
||||
};
|
||||
|
||||
let first_connector = if is_small_parent
|
||||
|| fits_single_line
|
||||
|| last_line_extendable(&parent_rewrite)
|
||||
|| context.config.indent_style() == IndentStyle::Visual
|
||||
{
|
||||
""
|
||||
} else {
|
||||
&connector
|
||||
};
|
||||
last_subexpr_str = last_subexpr_str.or_else(|| last.rewrite_postfix(context, last_shape));
|
||||
self.rewrites.push(last_subexpr_str?);
|
||||
Some(())
|
||||
}
|
||||
|
||||
let result = if is_small_parent && rewrites.len() > 1 {
|
||||
let second_connector = if fits_single_line
|
||||
|| rewrites[1] == "?"
|
||||
|| last_line_extendable(&rewrites[0])
|
||||
|| context.config.indent_style() == IndentStyle::Visual
|
||||
{
|
||||
""
|
||||
fn join_rewrites(
|
||||
&self,
|
||||
context: &RewriteContext,
|
||||
child_shape: Shape,
|
||||
block_like_iter: impl Iterator<Item = bool>,
|
||||
) -> Option<String> {
|
||||
let connector = if self.fits_single_line {
|
||||
// Yay, we can put everything on one line.
|
||||
Cow::from("")
|
||||
} else {
|
||||
&connector
|
||||
// Use new lines.
|
||||
if *context.force_one_line_chain.borrow() {
|
||||
return None;
|
||||
}
|
||||
child_shape.to_string_with_newline(context.config)
|
||||
};
|
||||
format!(
|
||||
"{}{}{}{}{}",
|
||||
parent_rewrite,
|
||||
first_connector,
|
||||
rewrites[0],
|
||||
second_connector,
|
||||
join_rewrites(&rewrites[1..], &connector)
|
||||
)
|
||||
} else {
|
||||
format!(
|
||||
"{}{}{}",
|
||||
parent_rewrite,
|
||||
first_connector,
|
||||
join_rewrites(&rewrites, &connector)
|
||||
)
|
||||
};
|
||||
let result = format!("{}{}", result, "?".repeat(suffix_try_num));
|
||||
if context.config.indent_style() == IndentStyle::Visual {
|
||||
wrap_str(result, context.config.max_width(), shape)
|
||||
} else {
|
||||
|
||||
let mut rewrite_iter = self.rewrites.iter();
|
||||
let mut result = rewrite_iter.next().unwrap().clone();
|
||||
|
||||
for (rewrite, prev_is_block_like) in rewrite_iter.zip(block_like_iter) {
|
||||
if !prev_is_block_like {
|
||||
result.push_str(&connector);
|
||||
}
|
||||
result.push_str(&rewrite);
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
|
||||
// True if the chain is only `?`s.
|
||||
fn chain_only_try(exprs: &[ast::Expr]) -> bool {
|
||||
exprs.iter().all(|e| {
|
||||
if let ast::ExprKind::Try(_) = e.node {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
// Formats a chain using block indent.
|
||||
struct ChainFormatterBlock<'a> {
|
||||
shared: ChainFormatterShared<'a>,
|
||||
// For each rewrite, whether the corresponding item is block-like.
|
||||
is_block_like: Vec<bool>,
|
||||
}
|
||||
|
||||
fn rewrite_try(
|
||||
expr: &ast::Expr,
|
||||
try_count: usize,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
let sub_expr = expr.rewrite(context, shape.sub_width(try_count)?)?;
|
||||
Some(format!("{}{}", sub_expr, "?".repeat(try_count)))
|
||||
impl<'a> ChainFormatterBlock<'a> {
|
||||
fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> {
|
||||
ChainFormatterBlock {
|
||||
shared: ChainFormatterShared::new(chain),
|
||||
is_block_like: Vec::with_capacity(chain.children.len() + 1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn join_rewrites(rewrites: &[String], connector: &str) -> String {
|
||||
let mut rewrite_iter = rewrites.iter();
|
||||
let mut result = rewrite_iter.next().unwrap().clone();
|
||||
impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
|
||||
fn format_root(
|
||||
&mut self,
|
||||
parent: &ChainItem,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<()> {
|
||||
let mut root_rewrite: String = parent.rewrite(context, shape)?;
|
||||
|
||||
for rewrite in rewrite_iter {
|
||||
if rewrite != "?" {
|
||||
result.push_str(connector);
|
||||
let mut root_ends_with_block = is_block_expr(context, &parent.expr, &root_rewrite);
|
||||
let tab_width = context.config.tab_spaces().saturating_sub(shape.offset);
|
||||
|
||||
while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
|
||||
let item = &self.shared.children[self.shared.children.len() - 1];
|
||||
let shape = shape.offset_left(root_rewrite.len())?;
|
||||
match &item.rewrite_postfix(context, shape) {
|
||||
Some(rewrite) => root_rewrite.push_str(rewrite),
|
||||
None => break,
|
||||
}
|
||||
|
||||
root_ends_with_block = is_block_expr(context, &item.expr, &root_rewrite);
|
||||
|
||||
self.shared.children = &self.shared.children[..self.shared.children.len() - 1];
|
||||
if self.shared.children.is_empty() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result.push_str(&rewrite);
|
||||
self.is_block_like.push(root_ends_with_block);
|
||||
self.shared.rewrites.push(root_rewrite);
|
||||
Some(())
|
||||
}
|
||||
|
||||
result
|
||||
fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option<Shape> {
|
||||
Some(
|
||||
if self.is_block_like[0] {
|
||||
shape.block_indent(0)
|
||||
} else {
|
||||
shape.block_indent(context.config.tab_spaces())
|
||||
}.with_max_width(context.config),
|
||||
)
|
||||
}
|
||||
|
||||
fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> {
|
||||
for item in self.shared.children[1..].iter().rev() {
|
||||
let rewrite = item.rewrite_postfix(context, child_shape)?;
|
||||
self.is_block_like
|
||||
.push(is_block_expr(context, &item.expr, &rewrite));
|
||||
self.shared.rewrites.push(rewrite);
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn format_last_child(
|
||||
&mut self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
child_shape: Shape,
|
||||
) -> Option<()> {
|
||||
self.shared
|
||||
.format_last_child(true, context, shape, child_shape)
|
||||
}
|
||||
|
||||
fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option<String> {
|
||||
self.shared
|
||||
.join_rewrites(context, child_shape, self.is_block_like.iter().cloned())
|
||||
}
|
||||
|
||||
fn pure_root(&mut self) -> Option<String> {
|
||||
self.shared.pure_root()
|
||||
}
|
||||
}
|
||||
|
||||
// Format a chain using visual indent.
|
||||
struct ChainFormatterVisual<'a> {
|
||||
shared: ChainFormatterShared<'a>,
|
||||
// The extra offset from the chain's shape to the position of the `.`
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl<'a> ChainFormatterVisual<'a> {
|
||||
fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> {
|
||||
ChainFormatterVisual {
|
||||
shared: ChainFormatterShared::new(chain),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
|
||||
fn format_root(
|
||||
&mut self,
|
||||
parent: &ChainItem,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<()> {
|
||||
let parent_shape = shape.visual_indent(0);
|
||||
let mut root_rewrite = parent.rewrite(context, parent_shape)?;
|
||||
let multiline = root_rewrite.contains('\n');
|
||||
self.offset = if multiline {
|
||||
last_line_width(&root_rewrite).saturating_sub(shape.used_width())
|
||||
} else {
|
||||
trimmed_last_line_width(&root_rewrite)
|
||||
};
|
||||
|
||||
if !multiline || is_block_expr(context, &parent.expr, &root_rewrite) {
|
||||
let item = &self.shared.children[self.shared.children.len() - 1];
|
||||
let child_shape = parent_shape
|
||||
.visual_indent(self.offset)
|
||||
.sub_width(self.offset)?;
|
||||
let rewrite = item.rewrite_postfix(context, child_shape)?;
|
||||
match wrap_str(rewrite, context.config.max_width(), shape) {
|
||||
Some(rewrite) => root_rewrite.push_str(&rewrite),
|
||||
None => {
|
||||
// We couldn't fit in at the visual indent, try the last
|
||||
// indent.
|
||||
let rewrite = item.rewrite_postfix(context, parent_shape)?;
|
||||
root_rewrite.push_str(&rewrite);
|
||||
self.offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.shared.children = &self.shared.children[..self.shared.children.len() - 1];
|
||||
}
|
||||
|
||||
self.shared.rewrites.push(root_rewrite);
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn child_shape(&self, context: &RewriteContext, shape: Shape) -> Option<Shape> {
|
||||
shape
|
||||
.with_max_width(context.config)
|
||||
.offset_left(self.offset)
|
||||
.map(|s| s.visual_indent(0))
|
||||
}
|
||||
|
||||
fn format_children(&mut self, context: &RewriteContext, child_shape: Shape) -> Option<()> {
|
||||
for item in self.shared.children[1..].iter().rev() {
|
||||
let rewrite = item.rewrite_postfix(context, child_shape)?;
|
||||
self.shared.rewrites.push(rewrite);
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
|
||||
fn format_last_child(
|
||||
&mut self,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
child_shape: Shape,
|
||||
) -> Option<()> {
|
||||
self.shared
|
||||
.format_last_child(false, context, shape, child_shape)
|
||||
}
|
||||
|
||||
fn join_rewrites(&self, context: &RewriteContext, child_shape: Shape) -> Option<String> {
|
||||
self.shared
|
||||
.join_rewrites(context, child_shape, iter::repeat(false))
|
||||
}
|
||||
|
||||
fn pure_root(&mut self) -> Option<String> {
|
||||
self.shared.pure_root()
|
||||
}
|
||||
}
|
||||
|
||||
// States whether an expression's last line exclusively consists of closing
|
||||
// parens, braces, and brackets in its idiomatic formatting.
|
||||
fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprKind::Mac(..) | ast::ExprKind::Call(..) => {
|
||||
context.use_block_indent() && repr.contains('\n')
|
||||
}
|
||||
ast::ExprKind::Struct(..)
|
||||
ast::ExprKind::Mac(..)
|
||||
| ast::ExprKind::Call(..)
|
||||
| ast::ExprKind::MethodCall(..)
|
||||
| ast::ExprKind::Struct(..)
|
||||
| ast::ExprKind::While(..)
|
||||
| ast::ExprKind::WhileLet(..)
|
||||
| ast::ExprKind::If(..)
|
||||
|
@ -365,147 +698,14 @@ fn is_block_expr(context: &RewriteContext, expr: &ast::Expr, repr: &str) -> bool
|
|||
ast::ExprKind::Paren(ref expr)
|
||||
| ast::ExprKind::Binary(_, _, ref expr)
|
||||
| ast::ExprKind::Index(_, ref expr)
|
||||
| ast::ExprKind::Unary(_, ref expr) => is_block_expr(context, expr, repr),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the root of the chain and a Vec of the prefixes of the rest of the chain.
|
||||
// E.g., for input `a.b.c` we return (`a`, [`a.b.c`, `a.b`])
|
||||
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext) -> (ast::Expr, Vec<ast::Expr>) {
|
||||
let mut subexpr_list = vec![expr.clone()];
|
||||
|
||||
while let Some(subexpr) = pop_expr_chain(subexpr_list.last().unwrap(), context) {
|
||||
subexpr_list.push(subexpr.clone());
|
||||
}
|
||||
|
||||
let parent = subexpr_list.pop().unwrap();
|
||||
(parent, subexpr_list)
|
||||
}
|
||||
|
||||
fn chain_indent(context: &RewriteContext, shape: Shape) -> Shape {
|
||||
match context.config.indent_style() {
|
||||
IndentStyle::Visual => shape.visual_indent(0),
|
||||
IndentStyle::Block => shape
|
||||
.block_indent(context.config.tab_spaces())
|
||||
.with_max_width(context.config),
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the expression's subexpression, if it exists. When the subexpr
|
||||
// is a try! macro, we'll convert it to shorthand when the option is set.
|
||||
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext) -> Option<ast::Expr> {
|
||||
match expr.node {
|
||||
ast::ExprKind::MethodCall(_, ref expressions) => {
|
||||
Some(convert_try(&expressions[0], context))
|
||||
}
|
||||
ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) => {
|
||||
Some(convert_try(subexpr, context))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_try(expr: &ast::Expr, context: &RewriteContext) -> ast::Expr {
|
||||
match expr.node {
|
||||
ast::ExprKind::Mac(ref mac) if context.config.use_try_shorthand() => {
|
||||
if let Some(subexpr) = convert_try_mac(mac, context) {
|
||||
subexpr
|
||||
} else {
|
||||
expr.clone()
|
||||
}
|
||||
}
|
||||
_ => expr.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite the last element in the chain `expr`. E.g., given `a.b.c` we rewrite
|
||||
// `.c`.
|
||||
fn rewrite_chain_subexpr(
|
||||
expr: &ast::Expr,
|
||||
span: Span,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
let rewrite_element = |expr_str: String| {
|
||||
if expr_str.len() <= shape.width {
|
||||
Some(expr_str)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match expr.node {
|
||||
ast::ExprKind::MethodCall(ref segment, ref expressions) => {
|
||||
let types = match segment.args {
|
||||
Some(ref params) => match **params {
|
||||
ast::GenericArgs::AngleBracketed(ref data) => &data.args[..],
|
||||
_ => &[],
|
||||
},
|
||||
_ => &[],
|
||||
};
|
||||
rewrite_method_call(segment.ident, types, expressions, span, context, shape)
|
||||
}
|
||||
ast::ExprKind::Field(ref nested, ref field) => {
|
||||
let space = if is_tup_field_access(expr) && is_tup_field_access(nested) {
|
||||
" "
|
||||
} else {
|
||||
""
|
||||
};
|
||||
rewrite_element(format!("{}.{}", space, field.name))
|
||||
}
|
||||
ast::ExprKind::Try(_) => rewrite_element(String::from("?")),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_tup_field_access(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprKind::Field(_, ref field) => {
|
||||
field.name.to_string().chars().all(|c| c.is_digit(10))
|
||||
| ast::ExprKind::Unary(_, ref expr)
|
||||
| ast::ExprKind::Closure(_, _, _, _, ref expr, _)
|
||||
| ast::ExprKind::Try(ref expr)
|
||||
| ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
|
||||
// This can only be a string lit
|
||||
ast::ExprKind::Lit(_) => {
|
||||
repr.contains('\n') && trimmed_last_line_width(repr) <= context.config.tab_spaces()
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Determines if we can continue formatting a given expression on the same line.
|
||||
fn is_continuable(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprKind::Path(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_try(expr: &ast::Expr) -> bool {
|
||||
match expr.node {
|
||||
ast::ExprKind::Try(..) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_method_call(
|
||||
method_name: ast::Ident,
|
||||
types: &[ast::GenericArg],
|
||||
args: &[ptr::P<ast::Expr>],
|
||||
span: Span,
|
||||
context: &RewriteContext,
|
||||
shape: Shape,
|
||||
) -> Option<String> {
|
||||
let (lo, type_str) = if types.is_empty() {
|
||||
(args[0].span.hi(), String::new())
|
||||
} else {
|
||||
let type_list = types
|
||||
.iter()
|
||||
.map(|ty| ty.rewrite(context, shape))
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
|
||||
let type_str = format!("::<{}>", type_list.join(", "));
|
||||
|
||||
(types.last().unwrap().span().hi(), type_str)
|
||||
};
|
||||
|
||||
let callee_str = format!(".{}{}", method_name, type_str);
|
||||
let span = mk_sp(lo, span.hi());
|
||||
|
||||
rewrite_call(context, &callee_str, &args[1..], span, shape)
|
||||
}
|
||||
|
|
|
@ -198,8 +198,7 @@ fn rewrite_closure_expr(
|
|||
} else {
|
||||
Some(rw)
|
||||
}
|
||||
})
|
||||
.map(|rw| format!("{} {}", prefix, rw))
|
||||
}).map(|rw| format!("{} {}", prefix, rw))
|
||||
}
|
||||
|
||||
// Rewrite closure whose body is block.
|
||||
|
@ -376,10 +375,8 @@ where
|
|||
.map(|e| match e.node {
|
||||
ast::ExprKind::Closure(..) => true,
|
||||
_ => false,
|
||||
})
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.count()
|
||||
}).unwrap_or(false)
|
||||
}).count()
|
||||
> 1
|
||||
}
|
||||
|
||||
|
|
|
@ -348,8 +348,7 @@ fn rewrite_comment_inner(
|
|||
}
|
||||
|
||||
line
|
||||
})
|
||||
.map(|s| left_trim_comment_line(s, &style))
|
||||
}).map(|s| left_trim_comment_line(s, &style))
|
||||
.map(|(line, has_leading_whitespace)| {
|
||||
if orig.starts_with("/*") && line_breaks == 0 {
|
||||
(
|
||||
|
@ -517,8 +516,7 @@ fn trim_custom_comment_prefix(s: &str) -> String {
|
|||
} else {
|
||||
line
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}).collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
}
|
||||
|
||||
|
@ -606,8 +604,7 @@ fn light_rewrite_comment(
|
|||
};
|
||||
// Preserve markdown's double-space line break syntax in doc comment.
|
||||
trim_right_unless_two_whitespaces(left_trimmed, is_doc_comment)
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
Some(lines.join(&format!("\n{}", offset.to_string(config))))
|
||||
}
|
||||
|
||||
|
@ -1341,8 +1338,7 @@ mod test {
|
|||
.filter_map(|(s, c)| match s {
|
||||
FullCodeCharKind::Normal | FullCodeCharKind::InString => Some(c),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -322,8 +322,7 @@ impl IgnoreList {
|
|||
path.push(s);
|
||||
path
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
}
|
||||
|
||||
fn skip_file_inner(&self, file: &Path) -> bool {
|
||||
|
|
12
src/expr.rs
12
src/expr.rs
|
@ -39,9 +39,9 @@ use spanned::Spanned;
|
|||
use string::{rewrite_string, StringFormat};
|
||||
use types::{can_be_overflowed_type, rewrite_path, PathContext};
|
||||
use utils::{
|
||||
colon_spaces, contains_skip, count_newlines, first_line_width, inner_attributes,
|
||||
last_line_extendable, last_line_width, mk_sp, outer_attributes, ptr_vec_to_ref_vec,
|
||||
semicolon_for_stmt, wrap_str,
|
||||
colon_spaces, contains_skip, count_newlines, first_line_ends_with, first_line_width,
|
||||
inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes,
|
||||
ptr_vec_to_ref_vec, semicolon_for_stmt, wrap_str,
|
||||
};
|
||||
use vertical::rewrite_with_alignment;
|
||||
use visitor::FmtVisitor;
|
||||
|
@ -1212,8 +1212,7 @@ fn rewrite_string_lit(context: &RewriteContext, span: Span, shape: Shape) -> Opt
|
|||
new_indent.to_string(context.config),
|
||||
line.trim_left()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}).collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
.trim_left(),
|
||||
);
|
||||
|
@ -1953,6 +1952,9 @@ pub fn prefer_next_line(orig_rhs: &str, next_line_rhs: &str, rhs_tactics: RhsTac
|
|||
rhs_tactics == RhsTactics::ForceNextLineWithoutIndent
|
||||
|| !next_line_rhs.contains('\n')
|
||||
|| count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1
|
||||
|| first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(')
|
||||
|| first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{')
|
||||
|| first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[')
|
||||
}
|
||||
|
||||
fn rewrite_expr_addrof(
|
||||
|
|
|
@ -246,8 +246,7 @@ impl FormattingError {
|
|||
fl.file
|
||||
.get_line(fl.lines[0].line_index)
|
||||
.map(|l| l.into_owned())
|
||||
})
|
||||
.unwrap_or_else(|| String::new()),
|
||||
}).unwrap_or_else(|| String::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,7 @@ fn prune_files(files: Vec<&str>) -> Vec<&str> {
|
|||
return true;
|
||||
}
|
||||
pruned_prefixes.iter().all(|pp| !f.starts_with(pp))
|
||||
})
|
||||
.collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
fn git_diff(commits: &str) -> String {
|
||||
|
|
|
@ -344,8 +344,7 @@ impl UseTree {
|
|||
.zip(items.into_iter())
|
||||
.map(|(t, list_item)| {
|
||||
Self::from_ast(context, &t.0, Some(list_item), None, None, None)
|
||||
})
|
||||
.collect(),
|
||||
}).collect(),
|
||||
));
|
||||
}
|
||||
UseTreeKind::Simple(ref rename, ..) => {
|
||||
|
|
22
src/items.rs
22
src/items.rs
|
@ -1669,7 +1669,7 @@ fn rewrite_static(
|
|||
&**expr,
|
||||
Shape::legacy(remaining_width, offset.block_only()),
|
||||
).and_then(|res| recover_comment_removed(res, static_parts.span, context))
|
||||
.map(|s| if s.ends_with(';') { s } else { s + ";" })
|
||||
.map(|s| if s.ends_with(';') { s } else { s + ";" })
|
||||
} else {
|
||||
Some(format!("{}{};", prefix, ty_str))
|
||||
}
|
||||
|
@ -2783,17 +2783,15 @@ impl Rewrite for ast::ForeignItem {
|
|||
let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
|
||||
|
||||
let item_str = match self.node {
|
||||
ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
|
||||
rewrite_fn_base(
|
||||
context,
|
||||
shape.indent,
|
||||
self.ident,
|
||||
&FnSig::new(fn_decl, generics, self.vis.clone()),
|
||||
span,
|
||||
false,
|
||||
false,
|
||||
).map(|(s, _)| format!("{};", s))
|
||||
}
|
||||
ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => rewrite_fn_base(
|
||||
context,
|
||||
shape.indent,
|
||||
self.ident,
|
||||
&FnSig::new(fn_decl, generics, self.vis.clone()),
|
||||
span,
|
||||
false,
|
||||
false,
|
||||
).map(|(s, _)| format!("{};", s)),
|
||||
ast::ForeignItemKind::Static(ref ty, is_mutable) => {
|
||||
// FIXME(#21): we're dropping potential comments in between the
|
||||
// function keywords here.
|
||||
|
|
|
@ -1115,8 +1115,7 @@ fn indent_macro_snippet(
|
|||
};
|
||||
trimmed_lines.push((trimmed, line, prefix_space_width));
|
||||
prefix_space_width
|
||||
})
|
||||
.min()?;
|
||||
}).min()?;
|
||||
|
||||
Some(
|
||||
first_line + "\n" + &trimmed_lines
|
||||
|
@ -1132,8 +1131,7 @@ fn indent_macro_snippet(
|
|||
}
|
||||
None => String::new(),
|
||||
},
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
).collect::<Vec<_>>()
|
||||
.join("\n"),
|
||||
)
|
||||
}
|
||||
|
@ -1296,8 +1294,7 @@ impl MacroBranch {
|
|||
}
|
||||
(s + l + "\n", !kind.is_string() || l.ends_with('\\'))
|
||||
},
|
||||
)
|
||||
.0;
|
||||
).0;
|
||||
|
||||
// Undo our replacement of macro variables.
|
||||
// FIXME: this could be *much* more efficient.
|
||||
|
|
|
@ -125,7 +125,7 @@ fn rewrite_pairs_multiline<T: Rewrite>(
|
|||
IndentStyle::Visual => shape.visual_indent(0),
|
||||
IndentStyle::Block => shape.block_indent(context.config.tab_spaces()),
|
||||
}).with_max_width(&context.config)
|
||||
.sub_width(rhs_offset)?;
|
||||
.sub_width(rhs_offset)?;
|
||||
|
||||
let indent_str = nested_shape.indent.to_string_with_newline(context.config);
|
||||
let mut result = String::new();
|
||||
|
|
|
@ -151,8 +151,7 @@ fn rewrite_reorderable_items(
|
|||
.map(|use_tree| ListItem {
|
||||
item: use_tree.rewrite_top_level(context, nested_shape),
|
||||
..use_tree.list_item.unwrap_or_else(ListItem::empty)
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
|
||||
wrap_reorderable_items(context, &item_vec, nested_shape)
|
||||
}
|
||||
|
@ -249,8 +248,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
|
|||
last = current;
|
||||
in_same_group
|
||||
})
|
||||
})
|
||||
.count();
|
||||
}).count();
|
||||
let items = &items[..item_length];
|
||||
|
||||
let at_least_one_in_file_lines = items
|
||||
|
|
|
@ -193,13 +193,15 @@ where
|
|||
W: Write,
|
||||
{
|
||||
for mismatch in diff {
|
||||
let (num_removed, num_added) = mismatch.lines.iter().fold((0, 0), |(rem, add), line| {
|
||||
match *line {
|
||||
DiffLine::Context(_) => panic!("No Context expected"),
|
||||
DiffLine::Expected(_) => (rem, add + 1),
|
||||
DiffLine::Resulting(_) => (rem + 1, add),
|
||||
}
|
||||
});
|
||||
let (num_removed, num_added) =
|
||||
mismatch
|
||||
.lines
|
||||
.iter()
|
||||
.fold((0, 0), |(rem, add), line| match *line {
|
||||
DiffLine::Context(_) => panic!("No Context expected"),
|
||||
DiffLine::Expected(_) => (rem, add + 1),
|
||||
DiffLine::Resulting(_) => (rem + 1, add),
|
||||
});
|
||||
// Write a header with enough information to separate the modified lines.
|
||||
writeln!(
|
||||
out,
|
||||
|
|
|
@ -274,6 +274,12 @@ impl Shape {
|
|||
);
|
||||
Shape { width, ..*self }
|
||||
}
|
||||
|
||||
pub fn to_string_with_newline(&self, config: &Config) -> Cow<'static, str> {
|
||||
let mut offset_indent = self.indent;
|
||||
offset_indent.alignment = self.offset;
|
||||
offset_indent.to_string_inner(config, 0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -514,8 +514,7 @@ fn read_significant_comments(file_name: &Path) -> HashMap<String, String> {
|
|||
.to_owned(),
|
||||
)
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}).collect()
|
||||
}
|
||||
|
||||
// Compare output to input.
|
||||
|
@ -884,8 +883,8 @@ fn configuration_snippet_tests() {
|
|||
fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
|
||||
.expect(&format!("Couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
|
||||
).lines()
|
||||
.map(|l| l.unwrap())
|
||||
.enumerate();
|
||||
.map(|l| l.unwrap())
|
||||
.enumerate();
|
||||
let mut code_blocks: Vec<ConfigCodeBlock> = Vec::new();
|
||||
let mut hash_set = Config::hash_set();
|
||||
|
||||
|
@ -961,5 +960,5 @@ fn verify_check_works() {
|
|||
"--check",
|
||||
temp_file.path.to_str().unwrap(),
|
||||
]).succeeds()
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
}
|
||||
|
|
|
@ -548,7 +548,8 @@ impl Rewrite for ast::GenericParam {
|
|||
};
|
||||
result.push_str(eq_str);
|
||||
let budget = shape.width.checked_sub(result.len())?;
|
||||
let rewrite = def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
|
||||
let rewrite =
|
||||
def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
|
||||
result.push_str(&rewrite);
|
||||
}
|
||||
|
||||
|
@ -793,8 +794,7 @@ fn rewrite_lifetime_param(
|
|||
.filter(|p| match p.kind {
|
||||
ast::GenericParamKind::Lifetime => true,
|
||||
_ => false,
|
||||
})
|
||||
.map(|lt| lt.rewrite(context, shape))
|
||||
}).map(|lt| lt.rewrite(context, shape))
|
||||
.collect::<Option<Vec<_>>>()?
|
||||
.join(", ");
|
||||
if result.is_empty() {
|
||||
|
|
|
@ -382,6 +382,7 @@ pub fn colon_spaces(before: bool, after: bool) -> &'static str {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr {
|
||||
match e.node {
|
||||
ast::ExprKind::Call(ref e, _)
|
||||
|
@ -398,6 +399,12 @@ pub fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn starts_with_newline(s: &str) -> bool {
|
||||
s.starts_with('\n') || s.starts_with("\r\n")
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn first_line_ends_with(s: &str, c: char) -> bool {
|
||||
s.lines().next().map_or(false, |l| l.ends_with(c))
|
||||
}
|
||||
|
|
|
@ -200,14 +200,12 @@ fn struct_field_prefix_max_min_width<T: AlignedItem>(
|
|||
Some(field_str.len())
|
||||
}
|
||||
})
|
||||
})
|
||||
.fold(Some((0, ::std::usize::MAX)), |acc, len| match (acc, len) {
|
||||
}).fold(Some((0, ::std::usize::MAX)), |acc, len| match (acc, len) {
|
||||
(Some((max_len, min_len)), Some(len)) => {
|
||||
Some((cmp::max(max_len, len), cmp::min(min_len, len)))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or((0, 0))
|
||||
}).unwrap_or((0, 0))
|
||||
}
|
||||
|
||||
fn rewrite_aligned_items_inner<T: AlignedItem>(
|
||||
|
|
|
@ -228,3 +228,34 @@ fn issue2415() {
|
|||
})()
|
||||
.unwrap_or_else(|_: Box<::std::error::Error>| String::from(""));
|
||||
}
|
||||
|
||||
impl issue_2786 {
|
||||
fn thing(&self) {
|
||||
foo(|a| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
}).bar(|c| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
})
|
||||
.baz(|c| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_2773() {
|
||||
let bar = Some(0);
|
||||
bar.or_else(|| {
|
||||
// do stuff
|
||||
None
|
||||
}).or_else(|| {
|
||||
// do other stuff
|
||||
None
|
||||
})
|
||||
.and_then(|val| {
|
||||
// do this stuff
|
||||
None
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,16 +15,16 @@ fn main() {
|
|||
// Test case where first chain element isn't a path, but is shorter than
|
||||
// the size of a tab.
|
||||
x().y(|| match cond() {
|
||||
true => (),
|
||||
false => (),
|
||||
});
|
||||
true => (),
|
||||
false => (),
|
||||
});
|
||||
|
||||
loong_func().quux(move || if true { 1 } else { 2 });
|
||||
|
||||
some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
|
||||
let x = c;
|
||||
x
|
||||
});
|
||||
let x = c;
|
||||
x
|
||||
});
|
||||
|
||||
some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
|
||||
let x = c;
|
||||
|
@ -59,7 +59,7 @@ fn floaters() {
|
|||
|
||||
let x = Foo { field1: val1,
|
||||
field2: val2, }.method_call()
|
||||
.method_call();
|
||||
.method_call();
|
||||
|
||||
let y = if cond { val1 } else { val2 }.method_call();
|
||||
|
||||
|
@ -80,7 +80,7 @@ fn floaters() {
|
|||
} else {
|
||||
none();
|
||||
}.bar()
|
||||
.baz();
|
||||
.baz();
|
||||
|
||||
Foo { x: val }.baz(|| {
|
||||
force();
|
||||
|
@ -90,10 +90,10 @@ fn floaters() {
|
|||
|
||||
Foo { y: i_am_multi_line,
|
||||
z: ok, }.baz(|| {
|
||||
force();
|
||||
multiline();
|
||||
})
|
||||
.quux();
|
||||
force();
|
||||
multiline();
|
||||
})
|
||||
.quux();
|
||||
|
||||
a + match x {
|
||||
true => "yay!",
|
||||
|
@ -137,9 +137,9 @@ fn issue1434() {
|
|||
for _ in 0..100 {
|
||||
let prototype_id =
|
||||
PrototypeIdData::from_reader::<_, B>(&mut self.file_cursor).chain_err(|| {
|
||||
format!("could not read prototype ID at offset {:#010x}",
|
||||
current_offset)
|
||||
})?;
|
||||
format!("could not read prototype ID at offset {:#010x}",
|
||||
current_offset)
|
||||
})?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ fn main() {
|
|||
.method_call_a(aaaaa, bbbbb, |c| {
|
||||
let x = c;
|
||||
x
|
||||
})
|
||||
.method_call_b(aaaaa, bbbbb, |c| {
|
||||
}).method_call_b(aaaaa, bbbbb, |c| {
|
||||
let x = c;
|
||||
x
|
||||
});
|
||||
|
@ -65,8 +64,7 @@ fn main() {
|
|||
.map(|x| {
|
||||
x += 1;
|
||||
x
|
||||
})
|
||||
.filter(some_mod::some_filter)
|
||||
}).filter(some_mod::some_filter)
|
||||
}
|
||||
|
||||
fn floaters() {
|
||||
|
@ -79,7 +77,7 @@ fn floaters() {
|
|||
field1: val1,
|
||||
field2: val2,
|
||||
}.method_call()
|
||||
.method_call();
|
||||
.method_call();
|
||||
|
||||
let y = if cond {
|
||||
val1
|
||||
|
@ -106,15 +104,14 @@ fn floaters() {
|
|||
} else {
|
||||
none();
|
||||
}.bar()
|
||||
.baz();
|
||||
.baz();
|
||||
|
||||
Foo {
|
||||
x: val,
|
||||
}.baz(|| {
|
||||
force();
|
||||
multiline();
|
||||
})
|
||||
.quux();
|
||||
}).quux();
|
||||
|
||||
Foo {
|
||||
y: i_am_multi_line,
|
||||
|
@ -122,8 +119,7 @@ fn floaters() {
|
|||
}.baz(|| {
|
||||
force();
|
||||
multiline();
|
||||
})
|
||||
.quux();
|
||||
}).quux();
|
||||
|
||||
a + match x {
|
||||
true => "yay!",
|
||||
|
@ -238,8 +234,7 @@ impl Foo {
|
|||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,3 +250,32 @@ fn issue2415() {
|
|||
})().ok_or("")?)
|
||||
})().unwrap_or_else(|_: Box<::std::error::Error>| String::from(""));
|
||||
}
|
||||
|
||||
impl issue_2786 {
|
||||
fn thing(&self) {
|
||||
foo(|a| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
}).bar(|c| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
}).baz(|c| {
|
||||
println!("a");
|
||||
println!("b");
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn issue_2773() {
|
||||
let bar = Some(0);
|
||||
bar.or_else(|| {
|
||||
// do stuff
|
||||
None
|
||||
}).or_else(|| {
|
||||
// do other stuff
|
||||
None
|
||||
}).and_then(|val| {
|
||||
// do this stuff
|
||||
None
|
||||
});
|
||||
}
|
||||
|
|
|
@ -138,18 +138,20 @@ fn issue470() {
|
|||
{
|
||||
{
|
||||
{
|
||||
let explicit_arg_decls = explicit_arguments.into_iter().enumerate().map(
|
||||
|(index, (ty, pattern))| {
|
||||
let lvalue = Lvalue::Arg(index as u32);
|
||||
block = this.pattern(
|
||||
block,
|
||||
argument_extent,
|
||||
hair::PatternRef::Hair(pattern),
|
||||
&lvalue,
|
||||
);
|
||||
ArgDecl { ty: ty }
|
||||
},
|
||||
);
|
||||
let explicit_arg_decls =
|
||||
explicit_arguments
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, (ty, pattern))| {
|
||||
let lvalue = Lvalue::Arg(index as u32);
|
||||
block = this.pattern(
|
||||
block,
|
||||
argument_extent,
|
||||
hair::PatternRef::Hair(pattern),
|
||||
&lvalue,
|
||||
);
|
||||
ArgDecl { ty: ty }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -169,8 +171,7 @@ fn issue1329() {
|
|||
.map(|x| {
|
||||
x += 1;
|
||||
x
|
||||
})
|
||||
.filter
|
||||
}).filter
|
||||
}
|
||||
|
||||
fn issue325() {
|
||||
|
|
|
@ -117,8 +117,7 @@ impl Cursor {
|
|||
debug_assert_eq!(n, -1);
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| {
|
||||
}).or_else(|| {
|
||||
let canonical = self.canonical();
|
||||
if canonical != *self {
|
||||
canonical.num_template_args()
|
||||
|
|
|
@ -141,8 +141,7 @@ fn issue_1450() {
|
|||
Relaxed,
|
||||
Release,
|
||||
Relaxed,
|
||||
)
|
||||
.is_ok()
|
||||
).is_ok()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ fn floaters() {
|
|||
field1: val1,
|
||||
field2: val2,
|
||||
}.method_call()
|
||||
.method_call();
|
||||
.method_call();
|
||||
|
||||
let y = if cond {
|
||||
val1
|
||||
|
|
|
@ -5,7 +5,7 @@ fn floaters() {
|
|||
field1: val1,
|
||||
field2: val2,
|
||||
}.method_call()
|
||||
.method_call();
|
||||
.method_call();
|
||||
|
||||
let y = if cond { val1 } else { val2 }.method_call();
|
||||
|
||||
|
|
|
@ -56,8 +56,8 @@ fn bar() {}
|
|||
/// .boxed(),
|
||||
/// ]
|
||||
/// }).bind("127.0.0.1:8080")
|
||||
/// .unwrap()
|
||||
/// .run()
|
||||
/// .unwrap()
|
||||
/// .run()
|
||||
/// # });
|
||||
/// }
|
||||
/// ```
|
||||
|
|
|
@ -183,8 +183,7 @@ fn issue_1885() {
|
|||
chan_select! {
|
||||
rx.recv() => {}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
}).collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
fn issue_1917() {
|
||||
|
|
|
@ -381,8 +381,7 @@ fn issue1456() {
|
|||
.iter()
|
||||
.map(|node| {
|
||||
XPathNodeReader::new(node, &context).and_then(|r| ArtistRef::from_xml(&r))
|
||||
})
|
||||
.collect();
|
||||
}).collect();
|
||||
res?
|
||||
}
|
||||
_ => Vec::new(),
|
||||
|
|
Loading…
Reference in a new issue