mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
Merge pull request #960 from rust-lang-nursery/big-closures
Block indent large closures and field/method chains
This commit is contained in:
commit
de2b8d98ea
18
bootstrap.sh
Executable file
18
bootstrap.sh
Executable 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
|
@ -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()
|
||||
}
|
||||
|
@ -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() {
|
||||
|
293
src/chains.rs
293
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<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(", ")))
|
||||
};
|
||||
|
@ -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: {}",
|
||||
|
@ -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";
|
||||
}
|
||||
|
134
src/expr.rs
134
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::<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,
|
||||
|
150
src/items.rs
150
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
|
||||
.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(": ");
|
||||
|
20
src/lists.rs
20
src/lists.rs
@ -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 {
|
||||
|
@ -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)),
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
|
55
src/types.rs
55
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::<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));
|
||||
|
16
src/utils.rs
16
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]
|
||||
|
@ -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;
|
||||
|
116
tests/source/chains-visual.rs
Normal file
116
tests/source/chains-visual.rs
Normal 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())
|
||||
}
|
@ -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.
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
138
tests/target/chains-visual.rs
Normal file
138
tests/target/chains-visual.rs
Normal 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())
|
||||
}
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user