diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 00000000000..c84b66340a8 --- /dev/null +++ b/bootstrap.sh @@ -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 diff --git a/src/bin/cargo-fmt.rs b/src/bin/cargo-fmt.rs index c033851f98a..909d62b20f8 100644 --- a/src/bin/cargo-fmt.rs +++ b/src/bin/cargo-fmt.rs @@ -98,14 +98,14 @@ fn format_crate(verbosity: Verbosity) -> Result { // 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, 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() } diff --git a/src/bin/rustfmt.rs b/src/bin/rustfmt.rs index 472098f59eb..2105a962997 100644 --- a/src/bin/rustfmt.rs +++ b/src/bin/rustfmt.rs @@ -191,7 +191,7 @@ fn execute(opts: &Options) -> FmtResult { 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 { // 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 { // 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 { // Read the config_path and convert to parent dir if a file is provided. let config_path: Option = 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() { diff --git a/src/chains.rs b/src/chains.rs index c535287df24..aa6034aa687 100644 --- a/src/chains.rs +++ b/src/chains.rs @@ -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 { let total_span = expr.span; - let mut subexpr_list = vec![expr]; - - while let Some(subexpr) = pop_expr_chain(expr) { - subexpr_list.push(subexpr); - expr = subexpr; - } + let (parent, subexpr_list) = make_subexpr_list(expr); - 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::>>()); + .rev() + .map(|e| rewrite_chain_subexpr(e, total_span, context, max_width, indent)) + .collect::>>()); // 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]; - - 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, + 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 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 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!(); } } -fn rewrite_chain_expr(expr: &ast::Expr, - span: Span, - context: &RewriteContext, - width: usize, - offset: Indent) - -> Option { +// 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 { 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(", "))) }; diff --git a/src/comment.rs b/src/comment.rs index 9b64e3f1345..991faa3c9c8 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -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)]; - } - - line.trim_right() - }) - .map(left_trim_comment_line) - .map(|line| { - if line_breaks == 0 { - line.trim_left() - } else { - line - } - }); + .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 + } + }); 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: {}", diff --git a/src/config.rs b/src/config.rs index 5632e9a925c..333835b66cd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -188,6 +188,12 @@ impl ConfigType for usize { } } +impl ConfigType for isize { + fn doc_hint() -> String { + String::from("") + } +} + impl ConfigType for String { fn doc_hint() -> String { String::from("") @@ -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"; } diff --git a/src/expr.rs b/src/expr.rs index 248cc7e090a..c2d5115ba75 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -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::>(); + .collect::>(); 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) -> Option { @@ -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::>>()); + .map(|p| p.rewrite(context, pat_budget, offset)) + .collect::>>()); 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(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::>(); @@ -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(context: &RewriteContext, offset: Indent) -> Option { 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, diff --git a/src/items.rs b/src/items.rs index 2566d9a436b..5ded7c2c5e8 100644 --- a/src/items.rs +++ b/src/items.rs @@ -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 - - // 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) - })); + .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) + })); 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::>() - .join(" + "); + .filter_map(|ty_bound| ty_bound.rewrite(context, context.config.max_width, indent)) + .collect::>() + .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 { let mut arg_item_strs = try_opt!(args.iter() - .map(|arg| { - arg.rewrite(&context, multi_line_budget, arg_indent) - }) - .collect::>>()); + .map(|arg| arg.rewrite(&context, multi_line_budget, arg_indent)) + .collect::>>()); // 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::>() - .join(" + "); + .filter_map(|ty_bound| ty_bound.rewrite(&context, width, indent)) + .collect::>() + .join(" + "); let mut result = String::new(); result.push_str(": "); diff --git a/src/lists.rs b/src/lists.rs index b251a8ee255..f966e41ce99 100644 --- a/src/lists.rs +++ b/src/lists.rs @@ -160,8 +160,8 @@ pub fn definitive_tactic(items: I, tactic: ListTactic, width: usize) -> De T: AsRef { 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(items: I) -> (usize, usize) T: AsRef { 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 { diff --git a/src/macros.rs b/src/macros.rs index 2be271e140b..13e1164487a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -112,8 +112,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)), diff --git a/src/missed_spans.rs b/src/missed_spans.rs index 092cc0093f1..2191a7812b1 100644 --- a/src/missed_spans.rs +++ b/src/missed_spans.rs @@ -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(); diff --git a/src/patterns.rs b/src/patterns.rs index 3cec98bb93a..ba3621fc6d5 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -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> = 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); diff --git a/src/rewrite.rs b/src/rewrite.rs index 5ca8d2e8241..247b1df1c3f 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -27,6 +27,7 @@ pub trait Rewrite { fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option; } +#[derive(Clone)] pub struct RewriteContext<'a> { pub parse_session: &'a ParseSess, pub codemap: &'a CodeMap, diff --git a/src/string.rs b/src/string.rs index bccf39deb92..e90e24f7af2 100644 --- a/src/string.rs +++ b/src/string.rs @@ -42,8 +42,8 @@ pub fn rewrite_string<'a>(orig: &str, fmt: &StringFormat<'a>) -> Option // `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(); diff --git a/src/types.rs b/src/types.rs index 22b518d2463..a1d449f3249 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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::>(); + .iter() + .map(SegmentParam::LifeTime) + .chain(data.types.iter().map(|x| SegmentParam::Type(&*x))) + .chain(data.bindings.iter().map(|x| SegmentParam::Binding(&*x))) + .collect::>(); 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 { 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::>>()) - .join(" + "); + .iter() + .map(|ty_bound| ty_bound.rewrite(context, width, offset)) + .collect::>>()) + .join(" + "); result.push_str(&bounds); } @@ -483,15 +481,15 @@ impl Rewrite for ast::PolyTraitRef { fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option { if !self.bound_lifetimes.is_empty() { let lifetime_str = try_opt!(self.bound_lifetimes - .iter() - .map(|lt| lt.rewrite(context, width, offset)) - .collect::>>()) - .join(", "); + .iter() + .map(|lt| lt.rewrite(context, width, offset)) + .collect::>>()) + .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)); diff --git a/src/utils.rs b/src/utils.rs index 667c9cd7efd..da690f1e8ea 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -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] diff --git a/src/visitor.rs b/src/visitor.rs index d52a167cb5e..8fba02de2d1 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -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; diff --git a/tests/source/chains-visual.rs b/tests/source/chains-visual.rs new file mode 100644 index 00000000000..a62ec4f492e --- /dev/null +++ b/tests/source/chains-visual.rs @@ -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()) +} diff --git a/tests/system.rs b/tests/system.rs index 2a6b1a9e19c..1af9c0f3462 100644 --- a/tests/system.rs +++ b/tests/system.rs @@ -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 { // 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. diff --git a/tests/target/chains-indent-visual.rs b/tests/target/chains-indent-visual.rs index e91317bd5de..e3ab320c6e1 100644 --- a/tests/target/chains-indent-visual.rs +++ b/tests/target/chains-indent-visual.rs @@ -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(); } diff --git a/tests/target/chains-no-overflow.rs b/tests/target/chains-no-overflow.rs index 2479157bb4f..2c78fbd9121 100644 --- a/tests/target/chains-no-overflow.rs +++ b/tests/target/chains-no-overflow.rs @@ -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) } diff --git a/tests/target/chains-no-overlow-2.rs b/tests/target/chains-no-overlow-2.rs index 815620234b5..c11070913d9 100644 --- a/tests/target/chains-no-overlow-2.rs +++ b/tests/target/chains-no-overlow-2.rs @@ -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(); } diff --git a/tests/target/chains-visual.rs b/tests/target/chains-visual.rs new file mode 100644 index 00000000000..d17a98e2ada --- /dev/null +++ b/tests/target/chains-visual.rs @@ -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()) +} diff --git a/tests/target/chains.rs b/tests/target/chains.rs index 392ff355b86..aacdb8e93e1 100644 --- a/tests/target/chains.rs +++ b/tests/target/chains.rs @@ -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() { diff --git a/tests/target/hard-tabs.rs b/tests/target/hard-tabs.rs index cd694099d95..0914959ceb1 100644 --- a/tests/target/hard-tabs.rs +++ b/tests/target/hard-tabs.rs @@ -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() { diff --git a/tests/target/long_field_access.rs b/tests/target/long_field_access.rs index 349d2c2f639..e4efd86b7f9 100644 --- a/tests/target/long_field_access.rs +++ b/tests/target/long_field_access.rs @@ -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; }