Merge pull request #960 from rust-lang-nursery/big-closures

Block indent large closures and field/method chains
This commit is contained in:
Nick Cameron 2016-04-28 09:49:08 +12:00
commit de2b8d98ea
26 changed files with 840 additions and 457 deletions

18
bootstrap.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
# Make sure you double check the diffs after running this script - with great
# power comes great responsibility.
# We deliberately avoid reformatting files with rustfmt comment directives.
cargo build
target/debug/rustfmt --write-mode=overwrite src/lib.rs
target/debug/rustfmt --write-mode=overwrite src/bin/rustfmt.rs
target/debug/rustfmt --write-mode=overwrite src/bin/cargo-fmt.rs
target/debug/rustfmt --write-mode=overwrite tests/system.rs
for filename in tests/target/*.rs; do
if ! grep -q "rustfmt-" "$filename"; then
target/debug/rustfmt --write-mode=overwrite $filename
fi
done

View File

@ -98,14 +98,14 @@ fn format_crate(verbosity: Verbosity) -> Result<ExitStatus, std::io::Error> {
// Currently only bin and lib files get formatted
let files: Vec<_> = targets.into_iter()
.filter(|t| t.kind.is_lib() | t.kind.is_bin())
.inspect(|t| {
if verbosity == Verbosity::Verbose {
println!("[{:?}] {:?}", t.kind, t.path)
}
})
.map(|t| t.path)
.collect();
.filter(|t| t.kind.is_lib() | t.kind.is_bin())
.inspect(|t| {
if verbosity == Verbosity::Verbose {
println!("[{:?}] {:?}", t.kind, t.path)
}
})
.map(|t| t.path)
.collect();
format_files(&files, &get_fmt_args(), verbosity)
}
@ -201,9 +201,9 @@ fn format_files(files: &Vec<PathBuf>,
println!("");
}
let mut command = try!(Command::new("rustfmt")
.stdout(stdout)
.args(files)
.args(fmt_args)
.spawn());
.stdout(stdout)
.args(files)
.args(fmt_args)
.spawn());
command.wait()
}

View File

@ -191,7 +191,7 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
Operation::Stdin { input, config_path } => {
// try to read config from local directory
let (mut config, _) = match_cli_path_or_file(config_path, &env::current_dir().unwrap())
.expect("Error resolving config");
.expect("Error resolving config");
// write_mode is always Plain for Stdin.
config.write_mode = WriteMode::Plain;
@ -205,8 +205,7 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
// Load the config path file if provided
if let Some(config_file) = config_path {
let (cfg_tmp, path_tmp) = resolve_config(config_file.as_ref())
.expect(&format!("Error resolving config for {:?}",
config_file));
.expect(&format!("Error resolving config for {:?}", config_file));
config = cfg_tmp;
path = path_tmp;
};
@ -219,9 +218,7 @@ fn execute(opts: &Options) -> FmtResult<Summary> {
// Check the file directory if the config-path could not be read or not provided
if path.is_none() {
let (config_tmp, path_tmp) = resolve_config(file.parent().unwrap())
.expect(&format!("Error resolving config \
for {}",
file.display()));
.expect(&format!("Error resolving config for {}", file.display()));
if let Some(path) = path_tmp.as_ref() {
println!("Using rustfmt config file {} for {}",
path.display(),
@ -301,13 +298,13 @@ fn determine_operation(matches: &Matches) -> FmtResult<Operation> {
// Read the config_path and convert to parent dir if a file is provided.
let config_path: Option<PathBuf> = matches.opt_str("config-path")
.map(PathBuf::from)
.and_then(|dir| {
if dir.is_file() {
return dir.parent().map(|v| v.into());
}
Some(dir)
});
.map(PathBuf::from)
.and_then(|dir| {
if dir.is_file() {
return dir.parent().map(|v| v.into());
}
Some(dir)
});
// if no file argument is supplied, read from stdin
if matches.free.is_empty() {

View File

@ -8,16 +8,79 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Formatting of chained expressions, i.e. expressions which are chained by
// dots: struct and enum field access and method calls.
//
// Instead of walking these subexpressions one-by-one, as is our usual strategy
// for expression formatting, we collect maximal sequences of these expressions
// and handle them simultaneously.
//
// Whenever possible, the entire chain is put on a single line. If that fails,
// we put each subexpression on a separate, much like the (default) function
// argument function argument strategy.
/// Formatting of chained expressions, i.e. expressions which are chained by
/// dots: struct and enum field access and method calls.
///
/// Instead of walking these subexpressions one-by-one, as is our usual strategy
/// for expression formatting, we collect maximal sequences of these expressions
/// and handle them simultaneously.
///
/// Whenever possible, the entire chain is put on a single line. If that fails,
/// we put each subexpression on a separate, much like the (default) function
/// argument function argument strategy.
///
/// Depends on config options: `chain_base_indent` is the indent to use for
/// blocks in the parent/root/base of the chain.
/// E.g., `let foo = { aaaa; bbb; ccc }.bar.baz();`, we would layout for the
/// following values of `chain_base_indent`:
/// Visual:
/// ```
/// let foo = {
/// aaaa;
/// bbb;
/// ccc
/// }
/// .bar
/// .baz();
/// ```
/// Inherit:
/// ```
/// let foo = {
/// aaaa;
/// bbb;
/// ccc
/// }
/// .bar
/// .baz();
/// ```
/// Tabbed:
/// ```
/// let foo = {
/// aaaa;
/// bbb;
/// ccc
/// }
/// .bar
/// .baz();
/// ```
///
/// `chain_indent` dictates how the rest of the chain is aligned.
/// If the first item in the chain is a block expression, we align the dots with
/// the braces.
/// Visual:
/// ```
/// let a = foo.bar
/// .baz()
/// .qux
/// ```
/// Inherit:
/// ```
/// let a = foo.bar
/// .baz()
/// .qux
/// ```
/// Tabbed:
/// ```
/// let a = foo.bar
/// .baz()
/// .qux
/// ```
/// `chains_overflow_last` applies only to chains where the last item is a
/// method call. Usually, any line break in a chain sub-expression causes the
/// whole chain to be split with newlines at each `.`. With `chains_overflow_last`
/// true, then we allow the last method call to spill over multiple lines without
/// forcing the rest of the chain to be split.
use Indent;
use rewrite::{Rewrite, RewriteContext};
@ -28,58 +91,48 @@ use config::BlockIndentStyle;
use syntax::{ast, ptr};
use syntax::codemap::{mk_sp, Span};
pub fn rewrite_chain(mut expr: &ast::Expr,
pub fn rewrite_chain(expr: &ast::Expr,
context: &RewriteContext,
width: usize,
offset: Indent)
-> Option<String> {
let total_span = expr.span;
let mut subexpr_list = vec![expr];
let (parent, subexpr_list) = make_subexpr_list(expr);
while let Some(subexpr) = pop_expr_chain(expr) {
subexpr_list.push(subexpr);
expr = subexpr;
}
let parent_block_indent = match context.config.chain_base_indent {
BlockIndentStyle::Visual => offset,
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Tabbed => context.block_indent.block_indent(context.config),
};
// Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
let parent_block_indent = chain_base_indent(context, offset);
let parent_context = &RewriteContext { block_indent: parent_block_indent, ..*context };
let parent = subexpr_list.pop().unwrap();
let parent_rewrite = try_opt!(expr.rewrite(parent_context, width, offset));
let parent_rewrite = try_opt!(parent.rewrite(parent_context, width, offset));
// Decide how to layout the rest of the chain. `extend` is true if we can
// put the first non-parent item on the same line as the parent.
let (indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(parent) ||
parent_rewrite.len() <= context.config.tab_spaces {
(offset + Indent::new(0, parent_rewrite.len()), true)
// Try and put at least the first two items on the same line.
(chain_indent(context, offset + Indent::new(0, parent_rewrite.len())), true)
} else if is_block_expr(parent, &parent_rewrite) {
// The parent is a block, so align the rest of the chain with the closing
// brace.
(parent_block_indent, false)
} else if parent_rewrite.contains('\n') {
(chain_indent(context, parent_block_indent.block_indent(context.config)), false)
} else {
match context.config.chain_indent {
BlockIndentStyle::Inherit => (context.block_indent, false),
BlockIndentStyle::Tabbed => (context.block_indent.block_indent(context.config), false),
BlockIndentStyle::Visual => (offset + Indent::new(context.config.tab_spaces, 0), false),
}
(chain_indent_newline(context, offset + Indent::new(0, parent_rewrite.len())), false)
};
let max_width = try_opt!((width + offset.width()).checked_sub(indent.width()));
let mut rewrites = try_opt!(subexpr_list.iter()
.rev()
.map(|e| {
rewrite_chain_expr(e,
total_span,
context,
max_width,
indent)
})
.collect::<Option<Vec<_>>>());
.rev()
.map(|e| rewrite_chain_subexpr(e, total_span, context, max_width, indent))
.collect::<Option<Vec<_>>>());
// Total of all items excluding the last.
let almost_total = rewrites[..rewrites.len() - 1]
.iter()
.fold(0, |a, b| a + first_line_width(b)) +
parent_rewrite.len();
.iter()
.fold(0, |a, b| a + first_line_width(b)) + parent_rewrite.len();
let total_width = almost_total + first_line_width(rewrites.last().unwrap());
let veto_single_line = if context.config.take_source_hints && subexpr_list.len() > 1 {
// Look at the source code. Unless all chain elements start on the same
// line, we won't consider putting them on a single line either.
@ -92,49 +145,40 @@ pub fn rewrite_chain(mut expr: &ast::Expr,
false
};
let fits_single_line = !veto_single_line &&
match subexpr_list[0].node {
ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions)
if context.config.chains_overflow_last => {
let len = rewrites.len();
let (init, last) = rewrites.split_at_mut(len - 1);
let last = &mut last[0];
let mut fits_single_line = !veto_single_line && total_width <= width;
if fits_single_line {
let len = rewrites.len();
let (init, last) = rewrites.split_at_mut(len - 1);
fits_single_line = init.iter().all(|s| !s.contains('\n'));
if init.iter().all(|s| !s.contains('\n')) && total_width <= width {
let last_rewrite = width.checked_sub(almost_total)
.and_then(|inner_width| {
rewrite_method_call(method_name.node,
types,
expressions,
total_span,
context,
inner_width,
offset + almost_total)
});
match last_rewrite {
Some(mut string) => {
::std::mem::swap(&mut string, last);
true
}
None => false,
if fits_single_line {
fits_single_line = match expr.node {
ref e @ ast::ExprKind::MethodCall(..) if context.config.chains_overflow_last => {
rewrite_method_call_with_overflow(e,
&mut last[0],
almost_total,
width,
total_span,
context,
offset)
}
} else {
false
_ => !last[0].contains('\n'),
}
}
_ => total_width <= width && rewrites.iter().all(|s| !s.contains('\n')),
};
}
let connector = if fits_single_line && !parent_rewrite.contains('\n') {
// Yay, we can put everything on one line.
String::new()
} else {
// Use new lines.
format!("\n{}", indent.to_string(context.config))
};
let first_connector = if extend {
""
} else {
&connector[..]
&*connector
};
wrap_str(format!("{}{}{}",
@ -147,7 +191,7 @@ pub fn rewrite_chain(mut expr: &ast::Expr,
}
// States whether an expression's last line exclusively consists of closing
// parens, braces and brackets in its idiomatic formatting.
// parens, braces, and brackets in its idiomatic formatting.
fn is_block_expr(expr: &ast::Expr, repr: &str) -> bool {
match expr.node {
ast::ExprKind::Struct(..) |
@ -167,21 +211,96 @@ fn is_block_expr(expr: &ast::Expr, repr: &str) -> bool {
}
}
fn pop_expr_chain(expr: &ast::Expr) -> Option<&ast::Expr> {
match expr.node {
ast::ExprKind::MethodCall(_, _, ref expressions) => Some(&expressions[0]),
ast::ExprKind::TupField(ref subexpr, _) |
ast::ExprKind::Field(ref subexpr, _) => Some(subexpr),
_ => None,
// 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(mut expr: &ast::Expr) -> (&ast::Expr, Vec<&ast::Expr>) {
fn pop_expr_chain(expr: &ast::Expr) -> Option<&ast::Expr> {
match expr.node {
ast::ExprKind::MethodCall(_, _, ref expressions) => Some(&expressions[0]),
ast::ExprKind::TupField(ref subexpr, _) |
ast::ExprKind::Field(ref subexpr, _) => Some(subexpr),
_ => None,
}
}
let mut subexpr_list = vec![expr];
while let Some(subexpr) = pop_expr_chain(expr) {
subexpr_list.push(subexpr);
expr = subexpr;
}
let parent = subexpr_list.pop().unwrap();
(parent, subexpr_list)
}
fn chain_base_indent(context: &RewriteContext, offset: Indent) -> Indent {
match context.config.chain_base_indent {
BlockIndentStyle::Visual => offset,
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Tabbed => context.block_indent.block_indent(context.config),
}
}
fn rewrite_chain_expr(expr: &ast::Expr,
span: Span,
context: &RewriteContext,
width: usize,
offset: Indent)
-> Option<String> {
fn chain_indent(context: &RewriteContext, offset: Indent) -> Indent {
match context.config.chain_indent {
BlockIndentStyle::Visual => offset,
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Tabbed => context.block_indent.block_indent(context.config),
}
}
// Ignores visual indenting because this function should be called where it is
// not possible to use visual indentation because we are starting on a newline.
fn chain_indent_newline(context: &RewriteContext, _offset: Indent) -> Indent {
match context.config.chain_indent {
BlockIndentStyle::Inherit => context.block_indent,
BlockIndentStyle::Visual | BlockIndentStyle::Tabbed => {
context.block_indent.block_indent(context.config)
}
}
}
fn rewrite_method_call_with_overflow(expr_kind: &ast::ExprKind,
last: &mut String,
almost_total: usize,
width: usize,
total_span: Span,
context: &RewriteContext,
offset: Indent)
-> bool {
if let &ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) = expr_kind {
let budget = match width.checked_sub(almost_total) {
Some(b) => b,
None => return false,
};
let mut last_rewrite = rewrite_method_call(method_name.node,
types,
expressions,
total_span,
context,
budget,
offset + almost_total);
if let Some(ref mut s) = last_rewrite {
::std::mem::swap(s, last);
true
} else {
false
}
} else {
unreachable!();
}
}
// 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,
width: usize,
offset: Indent)
-> Option<String> {
match expr.node {
ast::ExprKind::MethodCall(ref method_name, ref types, ref expressions) => {
let inner = &RewriteContext { block_indent: offset, ..*context };
@ -213,7 +332,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
}
}
// Determines we can continue formatting a given expression on the same line.
// 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,
@ -233,8 +352,8 @@ fn rewrite_method_call(method_name: ast::Ident,
(args[0].span.hi, String::new())
} else {
let type_list: Vec<_> = try_opt!(types.iter()
.map(|ty| ty.rewrite(context, width, offset))
.collect());
.map(|ty| ty.rewrite(context, width, offset))
.collect());
(types.last().unwrap().span.hi, format!("::<{}>", type_list.join(", ")))
};

View File

@ -70,24 +70,24 @@ pub fn rewrite_comment(orig: &str,
let line_breaks = s.chars().filter(|&c| c == '\n').count();
let lines = s.lines()
.enumerate()
.map(|(i, mut line)| {
line = line.trim();
// Drop old closer.
if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
line = &line[..(line.len() - 2)];
}
.enumerate()
.map(|(i, mut line)| {
line = line.trim();
// Drop old closer.
if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
line = &line[..(line.len() - 2)];
}
line.trim_right()
})
.map(left_trim_comment_line)
.map(|line| {
if line_breaks == 0 {
line.trim_left()
} else {
line
}
});
line.trim_right()
})
.map(left_trim_comment_line)
.map(|line| {
if line_breaks == 0 {
line.trim_left()
} else {
line
}
});
let mut result = opener.to_owned();
for line in lines {
@ -538,7 +538,7 @@ fn changed_comment_content(orig: &str, new: &str) -> bool {
let code_comment_content = |code| {
let slices = UngroupedCommentCodeSlices::new(code);
slices.filter(|&(ref kind, _, _)| *kind == CodeCharKind::Comment)
.flat_map(|(_, _, s)| CommentReducer::new(s))
.flat_map(|(_, _, s)| CommentReducer::new(s))
};
let res = code_comment_content(orig).ne(code_comment_content(new));
debug!("comment::changed_comment_content: {}\norig: '{}'\nnew: '{}'\nraw_old: {}\nraw_new: {}",

View File

@ -188,6 +188,12 @@ impl ConfigType for usize {
}
}
impl ConfigType for isize {
fn doc_hint() -> String {
String::from("<signed integer>")
}
}
impl ConfigType for String {
fn doc_hint() -> String {
String::from("<string>")
@ -369,13 +375,13 @@ create_config! {
"Report all, none or unnumbered occurrences of TODO in source file comments";
report_fixme: ReportTactic, ReportTactic::Never,
"Report all, none or unnumbered occurrences of FIXME in source file comments";
chain_base_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on chain base";
chain_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of chain";
chain_base_indent: BlockIndentStyle, BlockIndentStyle::Tabbed, "Indent on chain base";
chain_indent: BlockIndentStyle, BlockIndentStyle::Tabbed, "Indentation of chain";
chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
reorder_imports: bool, false, "Reorder import statements alphabetically";
single_line_if_else: bool, false, "Put else on same line as closing brace for if statements";
format_strings: bool, true, "Format string literals where necessary";
force_format_strings: bool, false, "Always format string literals";
chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
take_source_hints: bool, true, "Retain some formatting characteristics from the source code";
hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
wrap_comments: bool, false, "Break comments to fit on the line";
@ -384,6 +390,8 @@ create_config! {
match_block_trailing_comma: bool, false,
"Put a trailing comma after a block based match arm (non-block arms are not affected)";
match_wildcard_trailing_comma: bool, true, "Put a trailing comma after a wildcard arm";
closure_block_indent_threshold: isize, 5, "How many lines a closure must have before it is \
block indented. -1 means never use block indent.";
write_mode: WriteMode, WriteMode::Replace,
"What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
}

View File

@ -283,12 +283,11 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
|item| item.rewrite(&inner_context, max_item_width, offset),
span.lo,
span.hi)
.collect::<Vec<_>>();
.collect::<Vec<_>>();
let has_long_item = try_opt!(items.iter()
.map(|li| li.item.as_ref().map(|s| s.len() > 10))
.fold(Some(false),
|acc, x| acc.and_then(|y| x.map(|x| x || y))));
.map(|li| li.item.as_ref().map(|s| s.len() > 10))
.fold(Some(false), |acc, x| acc.and_then(|y| x.map(|x| x || y))));
let tactic = if has_long_item || items.iter().any(ListItem::is_multiline) {
definitive_tactic(&items, ListTactic::HorizontalVertical, max_item_width)
@ -410,8 +409,8 @@ fn rewrite_closure(capture: ast::CaptureBy,
if try_single_line && !force_block {
let must_preserve_braces =
!classify::expr_requires_semi_to_be_stmt(left_most_sub_expr(inner_block.expr
.as_ref()
.unwrap()));
.as_ref()
.unwrap()));
if !(must_preserve_braces && had_braces) &&
(must_preserve_braces || !prefix.contains('\n')) {
// If we got here, then we can try to format without braces.
@ -455,9 +454,19 @@ fn rewrite_closure(capture: ast::CaptureBy,
// We couldn't format the closure body as a single line expression; fall
// back to block formatting.
let body_rewrite = inner_block.rewrite(&context, budget, Indent::empty());
let body_rewrite = try_opt!(inner_block.rewrite(&context, budget, Indent::empty()));
Some(format!("{} {}", prefix, try_opt!(body_rewrite)))
let block_threshold = context.config.closure_block_indent_threshold;
if block_threshold < 0 || body_rewrite.matches('\n').count() <= block_threshold as usize {
return Some(format!("{} {}", prefix, body_rewrite));
}
// The body of the closure is big enough to be block indented, that means we
// must re-format.
let mut context = context.clone();
context.block_indent.alignment = 0;
let body_rewrite = try_opt!(inner_block.rewrite(&context, budget, Indent::empty()));
Some(format!("{} {}", prefix, body_rewrite))
}
fn and_one_line(x: Option<String>) -> Option<String> {
@ -513,9 +522,9 @@ impl Rewrite for ast::Block {
if is_simple_block(self, context.codemap) && prefix.len() < width {
let body = self.expr
.as_ref()
.unwrap()
.rewrite(context, width - prefix.len(), offset);
.as_ref()
.unwrap()
.rewrite(context, width - prefix.len(), offset);
if let Some(ref expr_str) = body {
let result = format!("{}{{ {} }}", prefix, expr_str);
if result.len() <= width && !result.contains('\n') {
@ -558,9 +567,9 @@ impl Rewrite for ast::Stmt {
};
ex.rewrite(context,
context.config.max_width - offset.width() - suffix.len(),
offset)
.map(|s| s + suffix)
context.config.max_width - offset.width() - suffix.len(),
offset)
.map(|s| s + suffix)
}
ast::StmtKind::Mac(..) => None,
};
@ -795,8 +804,8 @@ fn rewrite_if_else(context: &RewriteContext,
width);
let after_else = mk_sp(context.codemap
.span_after(mk_sp(if_block.span.hi, else_block.span.lo),
"else"),
.span_after(mk_sp(if_block.span.hi, else_block.span.lo),
"else"),
else_block.span.lo);
let after_else_comment = extract_comment(after_else, &context, offset, width);
@ -812,9 +821,9 @@ fn rewrite_if_else(context: &RewriteContext,
try_opt!(write!(&mut result,
"{}else{}",
between_if_else_block_comment.as_ref()
.map_or(between_sep, |str| &**str),
.map_or(between_sep, |str| &**str),
after_else_comment.as_ref().map_or(after_sep, |str| &**str))
.ok());
.ok());
result.push_str(&&try_opt!(rewrite));
}
@ -958,7 +967,7 @@ fn rewrite_match(context: &RewriteContext,
let arm_indent_str = arm_indent.to_string(context.config);
let open_brace_pos = context.codemap
.span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{");
.span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])), "{");
for (i, arm) in arms.iter().enumerate() {
// Make sure we get the stuff between arms.
@ -1063,8 +1072,8 @@ impl Rewrite for ast::Arm {
// 5 = ` => {`
let pat_budget = try_opt!(width.checked_sub(5));
let pat_strs = try_opt!(pats.iter()
.map(|p| p.rewrite(context, pat_budget, offset))
.collect::<Option<Vec<_>>>());
.map(|p| p.rewrite(context, pat_budget, offset))
.collect::<Option<Vec<_>>>());
let all_simple = pat_strs.iter().all(|p| pat_is_simple(&p));
let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
@ -1435,7 +1444,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
let tactic = definitive_tactic(&item_vec,
ListTactic::LimitedHorizontalVertical(context.config
.fn_call_width),
.fn_call_width),
remaining_width);
// Replace the stub with the full overflowing last argument if the rewrite
@ -1515,8 +1524,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
};
let field_iter = fields.into_iter()
.map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
.map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
let inner_context = &RewriteContext { block_indent: indent, ..*context };
@ -1524,20 +1533,16 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
field_iter,
"}",
|item| {
match *item {
StructLitField::Regular(ref field) => field.span.lo,
StructLitField::Base(ref 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 pos = snippet.find_uncommented("..").unwrap();
last_field_hi + BytePos(pos as u32)
}
}
},
match *item {
StructLitField::Regular(ref field) => field.span.lo,
StructLitField::Base(ref 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 pos = snippet.find_uncommented("..").unwrap();
last_field_hi + BytePos(pos as u32)
}
}
},
|item| {
match *item {
StructLitField::Regular(ref field) => field.span.hi,
@ -1545,22 +1550,20 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
}
},
|item| {
match *item {
StructLitField::Regular(ref field) => {
rewrite_field(inner_context,
&field,
v_budget.checked_sub(1).unwrap_or(0),
indent)
}
StructLitField::Base(ref expr) => {
// 2 = ..
expr.rewrite(inner_context,
try_opt!(v_budget.checked_sub(2)),
indent + 2)
.map(|s| format!("..{}", s))
}
}
},
match *item {
StructLitField::Regular(ref field) => {
rewrite_field(inner_context,
&field,
v_budget.checked_sub(1).unwrap_or(0),
indent)
}
StructLitField::Base(ref expr) => {
// 2 = ..
expr.rewrite(inner_context, try_opt!(v_budget.checked_sub(2)), indent + 2)
.map(|s| format!("..{}", s))
}
}
},
context.codemap.span_after(span, "{"),
span.hi);
let item_vec = items.collect::<Vec<_>>();
@ -1607,8 +1610,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
let format_on_newline = || {
let inner_indent = context.block_indent
.block_indent(context.config)
.to_string(context.config);
.block_indent(context.config)
.to_string(context.config);
let outer_indent = context.block_indent.to_string(context.config);
Some(format!("{} {{\n{}{}\n{}}}",
path_str,
@ -1646,8 +1649,8 @@ fn rewrite_field(context: &RewriteContext,
let expr_offset = offset.block_indent(&context.config);
let expr = field.expr.rewrite(context,
try_opt!(context.config
.max_width
.checked_sub(expr_offset.width())),
.max_width
.checked_sub(expr_offset.width())),
expr_offset);
expr.map(|s| format!("{}:\n{}{}", name, expr_offset.to_string(&context.config), s))
}
@ -1680,9 +1683,8 @@ pub fn rewrite_tuple<'a, I>(context: &RewriteContext,
|item| item.span().hi,
|item| {
let inner_width = try_opt!(context.config
.max_width
.checked_sub(indent.width() +
1));
.max_width
.checked_sub(indent.width() + 1));
item.rewrite(context, inner_width, indent)
},
list_lo,
@ -1740,8 +1742,8 @@ fn rewrite_binary_op(context: &RewriteContext,
// Re-evaluate the lhs because we have more space now:
let budget = try_opt!(context.config
.max_width
.checked_sub(offset.width() + 1 + operator_str.len()));
.max_width
.checked_sub(offset.width() + 1 + operator_str.len()));
Some(format!("{} {}\n{}{}",
try_opt!(lhs.rewrite(context, budget, offset)),
operator_str,
@ -1756,9 +1758,9 @@ pub fn rewrite_unary_prefix<R: Rewrite>(context: &RewriteContext,
offset: Indent)
-> Option<String> {
rewrite.rewrite(context,
try_opt!(width.checked_sub(prefix.len())),
offset + prefix.len())
.map(|r| format!("{}{}", prefix, r))
try_opt!(width.checked_sub(prefix.len())),
offset + prefix.len())
.map(|r| format!("{}{}", prefix, r))
}
fn rewrite_unary_op(context: &RewriteContext,

View File

@ -277,10 +277,10 @@ impl<'a> FmtVisitor<'a> {
};
e.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent)
.map(|s| s + suffix)
.or_else(|| Some(self.snippet(e.span)))
self.config.max_width - self.block_indent.width(),
self.block_indent)
.map(|s| s + suffix)
.or_else(|| Some(self.snippet(e.span)))
} else if let Some(ref stmt) = block.stmts.first() {
stmt.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
@ -321,7 +321,7 @@ impl<'a> FmtVisitor<'a> {
self.block_indent,
self.block_indent.block_indent(self.config),
mk_sp(span.lo, body_start))
.unwrap();
.unwrap();
self.buffer.push_str(&generics_str);
self.last_pos = body_start;
@ -359,12 +359,12 @@ impl<'a> FmtVisitor<'a> {
enum_def.variants.iter(),
"}",
|f| {
if !f.node.attrs.is_empty() {
f.node.attrs[0].span.lo
} else {
f.span.lo
}
},
if !f.node.attrs.is_empty() {
f.node.attrs[0].span.lo
} else {
f.span.lo
}
},
|f| f.span.hi,
|f| self.format_variant(f),
body_lo,
@ -397,10 +397,10 @@ impl<'a> FmtVisitor<'a> {
let indent = self.block_indent;
let mut result = try_opt!(field.node
.attrs
.rewrite(&self.get_context(),
self.config.max_width - indent.width(),
indent));
.attrs
.rewrite(&self.get_context(),
self.config.max_width - indent.width(),
indent));
if !result.is_empty() {
result.push('\n');
result.push_str(&indent.to_string(self.config));
@ -666,8 +666,8 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
};
let where_budget = try_opt!(context.config
.max_width
.checked_sub(last_line_width(&result)));
.max_width
.checked_sub(last_line_width(&result)));
let where_clause_str = try_opt!(rewrite_where_clause(context,
&generics.where_clause,
context.config,
@ -803,13 +803,13 @@ fn format_struct_struct(context: &RewriteContext,
fields.iter(),
"}",
|field| {
// Include attributes and doc comments, if present
if !field.node.attrs.is_empty() {
field.node.attrs[0].span.lo
} else {
field.span.lo
}
},
// Include attributes and doc comments, if present
if !field.node.attrs.is_empty() {
field.node.attrs[0].span.lo
} else {
field.span.lo
}
},
|field| field.node.ty.span.hi,
|field| field.rewrite(context, item_budget, item_indent),
context.codemap.span_after(span, "{"),
@ -864,8 +864,8 @@ fn format_tuple_struct(context: &RewriteContext,
result.push_str(&generics_str);
let where_budget = try_opt!(context.config
.max_width
.checked_sub(last_line_width(&result)));
.max_width
.checked_sub(last_line_width(&result)));
try_opt!(rewrite_where_clause(context,
&generics.where_clause,
context.config,
@ -889,13 +889,13 @@ fn format_tuple_struct(context: &RewriteContext,
fields.iter(),
")",
|field| {
// Include attributes and doc comments, if present
if !field.node.attrs.is_empty() {
field.node.attrs[0].span.lo
} else {
field.span.lo
}
},
// Include attributes and doc comments, if present
if !field.node.attrs.is_empty() {
field.node.attrs[0].span.lo
} else {
field.span.lo
}
},
|field| field.node.ty.span.hi,
|field| field.rewrite(context, item_budget, item_indent),
context.codemap.span_after(span, "("),
@ -912,7 +912,7 @@ fn format_tuple_struct(context: &RewriteContext,
// know that earlier, so the where clause will not be indented properly.
result.push('\n');
result.push_str(&(context.block_indent + (context.config.tab_spaces - 1))
.to_string(context.config));
.to_string(context.config));
}
result.push_str(&where_clause_str);
@ -946,8 +946,8 @@ pub fn rewrite_type_alias(context: &RewriteContext,
result.push_str(&generics_str);
let where_budget = try_opt!(context.config
.max_width
.checked_sub(last_line_width(&result)));
.max_width
.checked_sub(last_line_width(&result)));
let where_clause_str = try_opt!(rewrite_where_clause(context,
&generics.where_clause,
context.config,
@ -965,26 +965,25 @@ pub fn rewrite_type_alias(context: &RewriteContext,
// This checked_sub may fail as the extra space after '=' is not taken into account
// In that case the budget is set to 0 which will make ty.rewrite retry on a new line
let budget = context.config
.max_width
.checked_sub(indent.width() + line_width + ";".len())
.unwrap_or(0);
.max_width
.checked_sub(indent.width() + line_width + ";".len())
.unwrap_or(0);
let type_indent = indent + line_width;
// Try to fit the type on the same line
let ty_str = try_opt!(ty.rewrite(context, budget, type_indent)
.or_else(|| {
// The line was too short, try to put the type on the next line
.or_else(|| {
// The line was too short, try to put the type on the next line
// Remove the space after '='
result.pop();
let type_indent = indent.block_indent(context.config);
result.push('\n');
result.push_str(&type_indent.to_string(context.config));
let budget = try_opt!(context.config
.max_width
.checked_sub(type_indent.width() +
";".len()));
ty.rewrite(context, budget, type_indent)
}));
// Remove the space after '='
result.pop();
let type_indent = indent.block_indent(context.config);
result.push('\n');
result.push_str(&type_indent.to_string(context.config));
let budget = try_opt!(context.config
.max_width
.checked_sub(type_indent.width() + ";".len()));
ty.rewrite(context, budget, type_indent)
}));
result.push_str(&ty_str);
result.push_str(";");
Some(result)
@ -1006,10 +1005,8 @@ impl Rewrite for ast::StructField {
ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis),
};
let mut attr_str = try_opt!(self.node
.attrs
.rewrite(context,
context.config.max_width - offset.width(),
offset));
.attrs
.rewrite(context, context.config.max_width - offset.width(), offset));
if !attr_str.is_empty() {
attr_str.push('\n');
attr_str.push_str(&offset.to_string(context.config));
@ -1069,11 +1066,9 @@ pub fn rewrite_associated_type(ident: ast::Ident,
let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
let bounds: &[_] = &ty_param_bounds.as_slice();
let bound_str = bounds.iter()
.filter_map(|ty_bound| {
ty_bound.rewrite(context, context.config.max_width, indent)
})
.collect::<Vec<String>>()
.join(" + ");
.filter_map(|ty_bound| ty_bound.rewrite(context, context.config.max_width, indent))
.collect::<Vec<String>>()
.join(" + ");
if bounds.len() > 0 {
format!(": {}", bound_str)
} else {
@ -1287,7 +1282,7 @@ fn rewrite_fn_base(context: &RewriteContext,
// Note that if the width and indent really matter, we'll re-layout the
// return type later anyway.
let ret_str = try_opt!(fd.output
.rewrite(&context, context.config.max_width - indent.width(), indent));
.rewrite(&context, context.config.max_width - indent.width(), indent));
let multi_line_ret_str = ret_str.contains('\n');
let ret_str_len = if multi_line_ret_str {
@ -1332,8 +1327,8 @@ fn rewrite_fn_base(context: &RewriteContext,
// A conservative estimation, to goal is to be over all parens in generics
let args_start = generics.ty_params
.last()
.map_or(span.lo, |tp| end_typaram(tp));
.last()
.map_or(span.lo, |tp| end_typaram(tp));
let args_span = mk_sp(context.codemap.span_after(mk_sp(args_start, span.hi), "("),
span_for_return(&fd.output).lo);
let arg_str = try_opt!(rewrite_args(context,
@ -1408,7 +1403,7 @@ fn rewrite_fn_base(context: &RewriteContext,
let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
let ret_str = try_opt!(fd.output
.rewrite(context, budget, ret_indent));
.rewrite(context, budget, ret_indent));
result.push_str(&ret_str);
} else {
result.push_str(&ret_str);
@ -1477,21 +1472,18 @@ fn rewrite_args(context: &RewriteContext,
variadic: bool)
-> Option<String> {
let mut arg_item_strs = try_opt!(args.iter()
.map(|arg| {
arg.rewrite(&context, multi_line_budget, arg_indent)
})
.collect::<Option<Vec<_>>>());
.map(|arg| arg.rewrite(&context, multi_line_budget, arg_indent))
.collect::<Option<Vec<_>>>());
// Account for sugary self.
// FIXME: the comment for the self argument is dropped. This is blocked
// on rust issue #27522.
let min_args = explicit_self.and_then(|explicit_self| {
rewrite_explicit_self(explicit_self, args, context)
})
.map_or(1, |self_str| {
arg_item_strs[0] = self_str;
2
});
let min_args =
explicit_self.and_then(|explicit_self| rewrite_explicit_self(explicit_self, args, context))
.map_or(1, |self_str| {
arg_item_strs[0] = self_str;
2
});
// Comments between args.
let mut arg_items = Vec::new();
@ -1722,9 +1714,9 @@ fn rewrite_trait_bounds(context: &RewriteContext,
}
let bound_str = bounds.iter()
.filter_map(|ty_bound| ty_bound.rewrite(&context, width, indent))
.collect::<Vec<String>>()
.join(" + ");
.filter_map(|ty_bound| ty_bound.rewrite(&context, width, indent))
.collect::<Vec<String>>()
.join(" + ");
let mut result = String::new();
result.push_str(": ");

View File

@ -160,8 +160,8 @@ pub fn definitive_tactic<I, T>(items: I, tactic: ListTactic, width: usize) -> De
T: AsRef<ListItem>
{
let pre_line_comments = items.clone()
.into_iter()
.any(|item| item.as_ref().has_line_pre_comment());
.into_iter()
.any(|item| item.as_ref().has_line_pre_comment());
let limit = match tactic {
_ if pre_line_comments => return DefinitiveListTactic::Vertical,
@ -353,9 +353,8 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
let mut new_lines = false;
// Pre-comment
let pre_snippet = self.codemap
.span_to_snippet(codemap::mk_sp(self.prev_span_end,
(self.get_lo)(&item)))
.unwrap();
.span_to_snippet(codemap::mk_sp(self.prev_span_end, (self.get_lo)(&item)))
.unwrap();
let trimmed_pre_snippet = pre_snippet.trim();
let pre_comment = if !trimmed_pre_snippet.is_empty() {
Some(trimmed_pre_snippet.to_owned())
@ -369,9 +368,8 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
None => self.next_span_start,
};
let post_snippet = self.codemap
.span_to_snippet(codemap::mk_sp((self.get_hi)(&item),
next_start))
.unwrap();
.span_to_snippet(codemap::mk_sp((self.get_hi)(&item), next_start))
.unwrap();
let comment_end = match self.inner.peek() {
Some(..) => {
@ -413,7 +411,7 @@ impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
// From the end of the first line of comments.
let test_snippet = &test_snippet[first_newline..];
let first = test_snippet.find(|c: char| !c.is_whitespace())
.unwrap_or(test_snippet.len());
.unwrap_or(test_snippet.len());
// From the end of the first line of comments to the next non-whitespace char.
let test_snippet = &test_snippet[..first];
@ -494,8 +492,8 @@ fn calculate_width<I, T>(items: I) -> (usize, usize)
T: AsRef<ListItem>
{
items.into_iter()
.map(|item| total_item_width(item.as_ref()))
.fold((0, 0), |acc, l| (acc.0 + 1, acc.1 + l))
.map(|item| total_item_width(item.as_ref()))
.fold((0, 0), |acc, l| (acc.0 + 1, acc.1 + l))
}
fn total_item_width(item: &ListItem) -> usize {

View File

@ -121,8 +121,9 @@ pub fn rewrite_macro(mac: &ast::Mac,
// Format macro invocation as array literal.
let extra_offset = macro_name.len();
let rewrite = try_opt!(rewrite_array(expr_vec.iter().map(|x| &**x),
mk_sp(context.codemap.span_after(mac.span,
original_style.opener()),
mk_sp(context.codemap
.span_after(mac.span,
original_style.opener()),
mac.span.hi - BytePos(1)),
context,
try_opt!(width.checked_sub(extra_offset)),

View File

@ -93,14 +93,14 @@ impl<'a> FmtVisitor<'a> {
fn replace_chars(string: &str) -> String {
string.chars()
.map(|ch| {
if ch.is_whitespace() {
ch
} else {
'X'
}
})
.collect()
.map(|ch| {
if ch.is_whitespace() {
ch
} else {
'X'
}
})
.collect()
}
let replaced = match self.config.write_mode {
@ -112,10 +112,10 @@ impl<'a> FmtVisitor<'a> {
for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
if let CodeCharKind::Comment = kind {
let last_char = big_snippet[..(offset + big_diff)]
.chars()
.rev()
.skip_while(|rev_c| [' ', '\t'].contains(&rev_c))
.next();
.chars()
.rev()
.skip_while(|rev_c| [' ', '\t'].contains(&rev_c))
.next();
let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));
@ -134,7 +134,7 @@ impl<'a> FmtVisitor<'a> {
comment_width,
self.block_indent,
self.config)
.unwrap());
.unwrap());
last_wspace = None;
line_start = offset + subslice.len();

View File

@ -103,15 +103,14 @@ impl Rewrite for Pat {
PatKind::Vec(ref prefix, ref slice_pat, ref suffix) => {
// Rewrite all the sub-patterns.
let prefix = prefix.iter().map(|p| p.rewrite(context, width, offset));
let slice_pat = slice_pat.as_ref().map(|p| {
Some(format!("{}..", try_opt!(p.rewrite(context, width, offset))))
});
let slice_pat = slice_pat.as_ref()
.map(|p| Some(format!("{}..", try_opt!(p.rewrite(context, width, offset)))));
let suffix = suffix.iter().map(|p| p.rewrite(context, width, offset));
// Munge them together.
let pats: Option<Vec<String>> = prefix.chain(slice_pat.into_iter())
.chain(suffix)
.collect();
.chain(suffix)
.collect();
// Check that all the rewrites succeeded, and if not return None.
let pats = try_opt!(pats);

View File

@ -27,6 +27,7 @@ pub trait Rewrite {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String>;
}
#[derive(Clone)]
pub struct RewriteContext<'a> {
pub parse_session: &'a ParseSess,
pub codemap: &'a CodeMap,

View File

@ -42,8 +42,8 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option<String>
// `cur_start` is the position in `orig` of the start of the current line.
let mut cur_start = 0;
let mut result = String::with_capacity(stripped_str.len()
.checked_next_power_of_two()
.unwrap_or(usize::max_value()));
.checked_next_power_of_two()
.unwrap_or(usize::max_value()));
result.push_str(fmt.opener);
let ender_length = fmt.line_end.len();

View File

@ -176,11 +176,11 @@ fn rewrite_segment(expr_context: bool,
!data.types.is_empty() ||
!data.bindings.is_empty() => {
let param_list = data.lifetimes
.iter()
.map(SegmentParam::LifeTime)
.chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
.chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
.collect::<Vec<_>>();
.iter()
.map(SegmentParam::LifeTime)
.chain(data.types.iter().map(|x| SegmentParam::Type(&*x)))
.chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x)))
.collect::<Vec<_>>();
let next_span_lo = param_list.last().unwrap().get_span().hi + BytePos(1);
let list_lo = context.codemap.span_after(codemap::mk_sp(*span_lo, span_hi), "<");
@ -270,7 +270,7 @@ fn format_function_type<'a, I>(inputs: I,
// FIXME Would be nice to avoid this allocation,
// but I couldn't get the types to work out.
inputs.map(|i| ArgumentKind::Regular(Box::new(i)))
.chain(variadic_arg),
.chain(variadic_arg),
")",
|arg| {
match *arg {
@ -285,13 +285,11 @@ fn format_function_type<'a, I>(inputs: I,
}
},
|arg| {
match *arg {
ArgumentKind::Regular(ref ty) => {
ty.rewrite(context, budget, offset)
}
ArgumentKind::Variadic(_) => Some("...".to_owned()),
}
},
match *arg {
ArgumentKind::Regular(ref ty) => ty.rewrite(context, budget, offset),
ArgumentKind::Variadic(_) => Some("...".to_owned()),
}
},
list_lo,
span.hi);
@ -408,8 +406,8 @@ fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime,
Some(result)
} else {
let appendix: Vec<_> = try_opt!(bounds.into_iter()
.map(|b| b.rewrite(context, width, offset))
.collect());
.map(|b| b.rewrite(context, width, offset))
.collect());
let result = format!("{}: {}", result, appendix.join(" + "));
wrap_str(result, context.config.max_width, width, offset)
}
@ -442,8 +440,8 @@ impl Rewrite for ast::Lifetime {
impl Rewrite for ast::TyParamBounds {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let strs: Vec<_> = try_opt!(self.iter()
.map(|b| b.rewrite(context, width, offset))
.collect());
.map(|b| b.rewrite(context, width, offset))
.collect());
wrap_str(strs.join(" + "), context.config.max_width, width, offset)
}
}
@ -456,10 +454,10 @@ impl Rewrite for ast::TyParam {
result.push_str(": ");
let bounds = try_opt!(self.bounds
.iter()
.map(|ty_bound| ty_bound.rewrite(context, width, offset))
.collect::<Option<Vec<_>>>())
.join(" + ");
.iter()
.map(|ty_bound| ty_bound.rewrite(context, width, offset))
.collect::<Option<Vec<_>>>())
.join(" + ");
result.push_str(&bounds);
}
@ -483,15 +481,15 @@ impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
if !self.bound_lifetimes.is_empty() {
let lifetime_str = try_opt!(self.bound_lifetimes
.iter()
.map(|lt| lt.rewrite(context, width, offset))
.collect::<Option<Vec<_>>>())
.join(", ");
.iter()
.map(|lt| lt.rewrite(context, width, offset))
.collect::<Option<Vec<_>>>())
.join(", ");
// 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6;
let max_path_width = try_opt!(width.checked_sub(extra_offset));
let path_str = try_opt!(self.trait_ref
.rewrite(context, max_path_width, offset + extra_offset));
.rewrite(context, max_path_width, offset + extra_offset));
Some(format!("for<{}> {}", lifetime_str, path_str))
} else {
@ -545,9 +543,8 @@ impl Rewrite for ast::Ty {
format!("&{} {}{}",
lt_str,
mut_str,
try_opt!(mt.ty.rewrite(context,
budget,
offset + 2 + mut_len + lt_len)))
try_opt!(mt.ty
.rewrite(context, budget, offset + 2 + mut_len + lt_len)))
}
None => {
let budget = try_opt!(width.checked_sub(1 + mut_len));

View File

@ -142,14 +142,14 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool {
#[inline]
pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
typaram.bounds
.last()
.map_or(typaram.span, |bound| {
match *bound {
ast::RegionTyParamBound(ref lt) => lt.span,
ast::TraitTyParamBound(ref prt, _) => prt.span,
}
})
.hi
.last()
.map_or(typaram.span, |bound| {
match *bound {
ast::RegionTyParamBound(ref lt) => lt.span,
ast::TraitTyParamBound(ref prt, _) => prt.span,
}
})
.hi
}
#[inline]

View File

@ -86,9 +86,9 @@ impl<'a> FmtVisitor<'a> {
if let Some(ref e) = b.expr {
self.format_missing_with_indent(e.span.lo);
let rewrite = e.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent)
.unwrap_or_else(|| self.snippet(e.span));
self.config.max_width - self.block_indent.width(),
self.block_indent)
.unwrap_or_else(|| self.snippet(e.span));
self.buffer.push_str(&rewrite);
self.last_pos = e.span.hi;
@ -436,9 +436,9 @@ impl<'a> FmtVisitor<'a> {
}
let outers: Vec<_> = attrs.iter()
.filter(|a| a.node.style == ast::AttrStyle::Outer)
.cloned()
.collect();
.filter(|a| a.node.style == ast::AttrStyle::Outer)
.cloned()
.collect();
if outers.is_empty() {
return false;
}
@ -447,9 +447,9 @@ impl<'a> FmtVisitor<'a> {
self.format_missing_with_indent(first.span.lo);
let rewrite = outers.rewrite(&self.get_context(),
self.config.max_width - self.block_indent.width(),
self.block_indent)
.unwrap();
self.config.max_width - self.block_indent.width(),
self.block_indent)
.unwrap();
self.buffer.push_str(&rewrite);
let last = outers.last().unwrap();
self.last_pos = last.span.hi;

View File

@ -0,0 +1,116 @@
// rustfmt-chain_indent: Visual
// rustfmt-chain_base_indent: Visual
// Test chain formatting.
fn main() {
// Don't put chains on a single line if it wasn't so in source.
let a = b .c
.d.1
.foo(|x| x + 1);
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd();
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddd.eeeeeeee();
// 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 => () });
loong_func()
.quux(move || if true {
1
} else {
2
});
some_fuuuuuuuuunction()
.method_call_a(aaaaa, bbbbb, |c| {
let x = c;
x
});
some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
let x = c;
x
}).method_call_b(aaaaa, bbbbb, |c| {
let x = c;
x
});
fffffffffffffffffffffffffffffffffff(a,
{
SCRIPT_TASK_ROOT
.with(|root| {
*root.borrow_mut() = Some(&script_task);
});
});
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx
.map(|x| x + 5)
.map(|x| x / 2)
.fold(0, |acc, x| acc + x);
aaaaaaaaaaaaaaaa.map(|x| {
x += 1;
x
}).filter(some_mod::some_filter)
}
fn floaters() {
let z = Foo {
field1: val1,
field2: val2,
};
let x = Foo {
field1: val1,
field2: val2,
}.method_call().method_call();
let y = if cond {
val1
} else {
val2
}
.method_call();
{
match x {
PushParam => {
// params are 1-indexed
stack.push(mparams[match cur.to_digit(10) {
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned()),
}]
.clone());
}
}
}
if cond { some(); } else { none(); }
.bar()
.baz();
Foo { x: val } .baz(|| { /*force multiline */ }) .quux();
Foo { y: i_am_multi_line, z: ok }
.baz(|| {
// force multiline
})
.quux();
a + match x { true => "yay!", false => "boo!" }.bar()
}
fn is_replaced_content() -> bool {
constellat.send(ConstellationMsg::ViewportConstrained(
self.id, constraints)).unwrap();
}
fn issue587() {
a.b::<()>(c);
std::mem::transmute(dl.symbol::<()>("init").unwrap())
}

View File

@ -85,7 +85,7 @@ fn assert_output(source: &str, expected_filename: &str) {
let mut expected_file = fs::File::open(&expected_filename).expect("Couldn't open target");
let mut expected_text = String::new();
expected_file.read_to_string(&mut expected_text)
.expect("Failed reading target");
.expect("Failed reading target");
let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
if compare.len() > 0 {
@ -102,8 +102,8 @@ fn assert_output(source: &str, expected_filename: &str) {
fn idempotence_tests() {
// Get all files in the tests/target directory.
let files = fs::read_dir("tests/target")
.expect("Couldn't read target dir")
.map(get_path_string);
.expect("Couldn't read target dir")
.map(get_path_string);
let (_reports, count, fails) = check_files(files);
// Display results.
@ -116,9 +116,9 @@ fn idempotence_tests() {
#[test]
fn self_tests() {
let files = fs::read_dir("src/bin")
.expect("Couldn't read src dir")
.chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
.map(get_path_string);
.expect("Couldn't read src dir")
.chain(fs::read_dir("tests").expect("Couldn't read tests dir"))
.map(get_path_string);
// Hack because there's no `IntoIterator` impl for `[T; N]`.
let files = files.chain(Some("src/lib.rs".to_owned()).into_iter());
@ -264,18 +264,18 @@ fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
// Matches lines containing significant comments or whitespace.
let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
.expect("Failed creating pattern 2");
.expect("Failed creating pattern 2");
reader.lines()
.map(|line| line.expect("Failed getting line"))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line).next().map(|capture| {
(capture.at(1).expect("Couldn't unwrap capture").to_owned(),
capture.at(2).expect("Couldn't unwrap capture").to_owned())
})
})
.collect()
.map(|line| line.expect("Failed getting line"))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line).next().map(|capture| {
(capture.at(1).expect("Couldn't unwrap capture").to_owned(),
capture.at(2).expect("Couldn't unwrap capture").to_owned())
})
})
.collect()
}
// Compare output to input.

View File

@ -2,9 +2,9 @@
fn test() {
let x = my_long_function()
.my_even_longer_function()
.my_nested_function()
.some_random_name()
.another_function()
.do_it();
.my_even_longer_function()
.my_nested_function()
.some_random_name()
.another_function()
.do_it();
}

View File

@ -3,16 +3,16 @@
fn main() {
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd();
.ddddddddddddddddddddddddddd();
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd
.eeeeeeee();
.ddddddddddddddddddddddddddd
.eeeeeeee();
x().y(|| match cond() {
true => (),
false => (),
});
true => (),
false => (),
});
loong_func()
.quux(move || if true {
@ -24,19 +24,17 @@ fn main() {
fffffffffffffffffffffffffffffffffff(a,
{
SCRIPT_TASK_ROOT.with(|root| {
*root.borrow_mut() =
Some(&script_task);
});
*root.borrow_mut() = Some(&script_task);
});
});
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
.map(|x| x / 2)
.fold(0,
|acc, x| acc + x);
.map(|x| x / 2)
.fold(0, |acc, x| acc + x);
aaaaaaaaaaaaaaaa.map(|x| {
x += 1;
x
})
.filter(some_mod::some_filter)
x += 1;
x
})
.filter(some_mod::some_filter)
}

View File

@ -2,15 +2,15 @@
fn main() {
reader.lines()
.map(|line| line.expect("Failed getting line"))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line)
.next()
.map(|capture| {
(capture.at(1).expect("Couldn\'t unwrap capture").to_owned(),
capture.at(2).expect("Couldn\'t unwrap capture").to_owned())
})
})
.collect();
.map(|line| line.expect("Failed getting line"))
.take_while(|line| line_regex.is_match(&line))
.filter_map(|line| {
regex.captures_iter(&line)
.next()
.map(|capture| {
(capture.at(1).expect("Couldn\'t unwrap capture").to_owned(),
capture.at(2).expect("Couldn\'t unwrap capture").to_owned())
})
})
.collect();
}

View File

@ -0,0 +1,138 @@
// rustfmt-chain_indent: Visual
// rustfmt-chain_base_indent: Visual
// Test chain formatting.
fn main() {
// Don't put chains on a single line if it wasn't so in source.
let a = b.c
.d
.1
.foo(|x| x + 1);
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd();
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd
.eeeeeeee();
// 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 => (),
});
loong_func().quux(move || if true {
1
} else {
2
});
some_fuuuuuuuuunction().method_call_a(aaaaa, bbbbb, |c| {
let x = c;
x
});
some_fuuuuuuuuunction()
.method_call_a(aaaaa, bbbbb, |c| {
let x = c;
x
})
.method_call_b(aaaaa, bbbbb, |c| {
let x = c;
x
});
fffffffffffffffffffffffffffffffffff(a, {
SCRIPT_TASK_ROOT.with(|root| {
*root.borrow_mut() = Some(&script_task);
});
});
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
.map(|x| x / 2)
.fold(0,
|acc, x| acc + x);
aaaaaaaaaaaaaaaa.map(|x| {
x += 1;
x
})
.filter(some_mod::some_filter)
}
fn floaters() {
let z = Foo {
field1: val1,
field2: val2,
};
let x = Foo {
field1: val1,
field2: val2,
}
.method_call()
.method_call();
let y = if cond {
val1
} else {
val2
}
.method_call();
{
match x {
PushParam => {
// params are 1-indexed
stack.push(mparams[match cur.to_digit(10) {
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned()),
}]
.clone());
}
}
}
if cond {
some();
} else {
none();
}
.bar()
.baz();
Foo { x: val }
.baz(|| {
// force multiline
})
.quux();
Foo {
y: i_am_multi_line,
z: ok,
}
.baz(|| {
// force multiline
})
.quux();
a +
match x {
true => "yay!",
false => "boo!",
}
.bar()
}
fn is_replaced_content() -> bool {
constellat.send(ConstellationMsg::ViewportConstrained(self.id, constraints))
.unwrap();
}
fn issue587() {
a.b::<()>(c);
std::mem::transmute(dl.symbol::<()>("init").unwrap())
}

View File

@ -3,16 +3,16 @@
fn main() {
// Don't put chains on a single line if it wasn't so in source.
let a = b.c
.d
.1
.foo(|x| x + 1);
.d
.1
.foo(|x| x + 1);
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd();
.ddddddddddddddddddddddddddd();
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
.ddddddddddddddddddddddddddd
.eeeeeeee();
.ddddddddddddddddddddddddddd
.eeeeeeee();
// Test case where first chain element isn't a path, but is shorter than
// the size of a tab.
@ -49,15 +49,14 @@ fn main() {
});
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
.map(|x| x / 2)
.fold(0,
|acc, x| acc + x);
.map(|x| x / 2)
.fold(0, |acc, x| acc + x);
aaaaaaaaaaaaaaaa.map(|x| {
x += 1;
x
})
.filter(some_mod::some_filter)
x += 1;
x
})
.filter(some_mod::some_filter)
}
fn floaters() {
@ -67,39 +66,39 @@ fn floaters() {
};
let x = Foo {
field1: val1,
field2: val2,
}
.method_call()
.method_call();
field1: val1,
field2: val2,
}
.method_call()
.method_call();
let y = if cond {
val1
} else {
val2
}
.method_call();
val1
} else {
val2
}
.method_call();
{
match x {
PushParam => {
// params are 1-indexed
stack.push(mparams[match cur.to_digit(10) {
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned()),
}]
.clone());
Some(d) => d as usize - 1,
None => return Err("bad param number".to_owned()),
}]
.clone());
}
}
}
if cond {
some();
} else {
none();
}
.bar()
.baz();
some();
} else {
none();
}
.bar()
.baz();
Foo { x: val }
.baz(|| {
@ -108,25 +107,25 @@ fn floaters() {
.quux();
Foo {
y: i_am_multi_line,
z: ok,
}
.baz(|| {
// force multiline
})
.quux();
y: i_am_multi_line,
z: ok,
}
.baz(|| {
// force multiline
})
.quux();
a +
match x {
true => "yay!",
false => "boo!",
}
.bar()
true => "yay!",
false => "boo!",
}
.bar()
}
fn is_replaced_content() -> bool {
constellat.send(ConstellationMsg::ViewportConstrained(self.id, constraints))
.unwrap();
.unwrap();
}
fn issue587() {

View File

@ -51,9 +51,9 @@ fn main() {
}
let chain = funktion_kall()
.go_to_next_line_with_tab()
.go_to_next_line_with_tab()
.go_to_next_line_with_tab();
.go_to_next_line_with_tab()
.go_to_next_line_with_tab()
.go_to_next_line_with_tab();
let z = [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
yyyyyyyyyyyyyyyyyyyyyyyyyyy,
@ -88,8 +88,8 @@ fn main() {
});
});
a.b
.c
.d();
.c
.d();
x().y(|| {
match cond() {

View File

@ -1,4 +1,4 @@
fn f() {
block_flow.base.stacking_relative_position_of_display_port =
self.base.stacking_relative_position_of_display_port;
block_flow.base.stacking_relative_position_of_display_port = self.base
.stacking_relative_position_of_display_port;
}