Merge pull request #1692 from topecongiro/chain/last-item

Allow overflowing the last item of chain only if it is multi-lined
This commit is contained in:
Nick Cameron 2017-06-16 13:24:03 +12:00 committed by GitHub
commit c5538d2a58
17 changed files with 188 additions and 160 deletions

View File

@ -167,9 +167,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
let child_shape_iter = Some(first_child_shape).into_iter().chain(
::std::iter::repeat(
other_child_shape,
).take(
subexpr_list.len() - 1,
),
).take(subexpr_list.len() - 1),
);
let iter = subexpr_list.iter().rev().zip(child_shape_iter);
let mut rewrites = try_opt!(
@ -180,9 +178,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
// Total of all items excluding the last.
let last_non_try_index = rewrites.len() - (1 + trailing_try_num);
let almost_total = rewrites[..last_non_try_index].iter().fold(0, |a, b| {
a + first_line_width(b)
}) + parent_rewrite.len();
let almost_total = rewrites[..last_non_try_index]
.iter()
.fold(0, |a, b| a + first_line_width(b)) + parent_rewrite.len();
let one_line_len = rewrites.iter().fold(0, |a, r| a + first_line_width(r)) +
parent_rewrite.len();
@ -320,9 +318,9 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
fn is_extendable_parent(context: &RewriteContext, parent_str: &str) -> bool {
context.config.chain_indent() == IndentStyle::Block &&
parent_str.lines().last().map_or(false, |s| {
s.trim().chars().all(|c| {
c == ')' || c == ']' || c == '}' || c == '?'
})
s.trim()
.chars()
.all(|c| c == ')' || c == ']' || c == '}' || c == '?')
})
}
@ -348,7 +346,7 @@ fn rewrite_last_child_with_overflow(
) -> bool {
if let Some(shape) = shape.shrink_left(almost_total) {
if let Some(ref mut rw) = rewrite_chain_subexpr(expr, span, context, shape) {
if almost_total + first_line_width(rw) <= one_line_budget {
if almost_total + first_line_width(rw) <= one_line_budget && rw.lines().count() > 3 {
::std::mem::swap(last_child, rw);
return true;
}

View File

@ -45,9 +45,9 @@ pub enum CommentStyle<'a> {
fn custom_opener(s: &str) -> &str {
s.lines().next().map_or("", |first_line| {
first_line.find(' ').map_or(first_line, |space_index| {
&first_line[0..space_index + 1]
})
first_line
.find(' ')
.map_or(first_line, |space_index| &first_line[0..space_index + 1])
})
}

View File

@ -360,9 +360,8 @@ where
// This is needed in case of line break not caused by a
// shortage of space, but by end-of-line comments, for example.
if !rhs_result.contains('\n') {
let lhs_shape = try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width(
infix.len(),
));
let lhs_shape =
try_opt!(try_opt!(shape.offset_left(prefix.len())).sub_width(infix.len()));
let lhs_result = lhs.rewrite(context, lhs_shape);
if let Some(lhs_result) = lhs_result {
let mut result = format!("{}{}{}", prefix, lhs_result, infix);
@ -451,9 +450,11 @@ where
let nested_shape = match context.config.array_layout() {
IndentStyle::Block => shape.block().block_indent(context.config.tab_spaces()),
IndentStyle::Visual => {
try_opt!(shape.visual_indent(bracket_size).sub_width(
bracket_size * 2,
))
try_opt!(
shape
.visual_indent(bracket_size)
.sub_width(bracket_size * 2)
)
}
};
@ -476,9 +477,9 @@ where
}
}
let has_long_item = items.iter().any(|li| {
li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false)
});
let has_long_item = items
.iter()
.any(|li| li.item.as_ref().map(|s| s.len() > 10).unwrap_or(false));
let tactic = match context.config.array_layout() {
IndentStyle::Block => {
@ -1699,9 +1700,10 @@ impl Rewrite for ast::Arm {
body.rewrite(context, body_shape),
body_shape.width,
));
let indent_str = shape.indent.block_indent(context.config).to_string(
context.config,
);
let indent_str = shape
.indent
.block_indent(context.config)
.to_string(context.config);
let (body_prefix, body_suffix) = if context.config.wrap_match_arms() {
if context.config.match_block_trailing_comma() {
("{", "},")
@ -1763,13 +1765,13 @@ fn rewrite_guard(
if let Some(ref guard) = *guard {
// First try to fit the guard string on the same line as the pattern.
// 4 = ` if `, 5 = ` => {`
if let Some(cond_shape) = shape.shrink_left(pattern_width + 4).and_then(
|s| s.sub_width(5),
)
if let Some(cond_shape) = shape
.shrink_left(pattern_width + 4)
.and_then(|s| s.sub_width(5))
{
if let Some(cond_str) = guard.rewrite(context, cond_shape).and_then(|s| {
s.rewrite(context, cond_shape)
})
if let Some(cond_str) = guard
.rewrite(context, cond_shape)
.and_then(|s| s.rewrite(context, cond_shape))
{
if !cond_str.contains('\n') {
return Some(format!(" if {}", cond_str));
@ -1787,9 +1789,10 @@ fn rewrite_guard(
if let Some(cond_str) = guard.rewrite(context, cond_shape) {
return Some(format!(
"\n{}if {}",
shape.indent.block_indent(context.config).to_string(
context.config,
),
shape
.indent
.block_indent(context.config)
.to_string(context.config),
cond_str
));
}
@ -1821,9 +1824,8 @@ fn rewrite_pat_expr(
} else {
format!("{} ", matcher)
};
let pat_shape = try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width(
connector.len(),
));
let pat_shape =
try_opt!(try_opt!(shape.offset_left(matcher.len())).sub_width(connector.len()));
pat_string = try_opt!(pat.rewrite(context, pat_shape));
format!("{}{}{}", matcher, pat_string, connector)
}
@ -1936,9 +1938,9 @@ where
width: callee_max_width,
..shape
};
let callee_str = callee.rewrite(context, callee_shape).ok_or(
Ordering::Greater,
)?;
let callee_str = callee
.rewrite(context, callee_shape)
.ok_or(Ordering::Greater)?;
rewrite_call_inner(
context,
@ -2046,9 +2048,9 @@ where
);
}
let args_shape = shape.sub_width(last_line_width(&callee_str)).ok_or(
Ordering::Less,
)?;
let args_shape = shape
.sub_width(last_line_width(&callee_str))
.ok_or(Ordering::Less)?;
Ok(format!(
"{}{}",
callee_str,
@ -2064,9 +2066,8 @@ where
fn need_block_indent(s: &str, shape: Shape) -> bool {
s.lines().skip(1).any(|s| {
s.find(|c| !char::is_whitespace(c)).map_or(false, |w| {
w + 1 < shape.indent.width()
})
s.find(|c| !char::is_whitespace(c))
.map_or(false, |w| w + 1 < shape.indent.width())
})
}
@ -2434,9 +2435,10 @@ fn rewrite_struct_lit<'a>(
return Some(format!("{} {{}}", path_str));
}
let field_iter = fields.into_iter().map(StructLitField::Regular).chain(
base.into_iter().map(StructLitField::Base),
);
let field_iter = fields
.into_iter()
.map(StructLitField::Regular)
.chain(base.into_iter().map(StructLitField::Base));
// Foo { a: Foo } - indent is +3, width is -5.
let (h_shape, v_shape) = try_opt!(struct_lit_shape(shape, context, path_str.len() + 3, 2));

View File

@ -213,9 +213,8 @@ struct JsonSpan {
impl JsonSpan {
fn into_tuple(self) -> Result<(String, Range), String> {
let (lo, hi) = self.range;
let canonical = canonicalize_path_string(&self.file).ok_or_else(|| {
format!("Can't canonicalize {}", &self.file)
})?;
let canonical = canonicalize_path_string(&self.file)
.ok_or_else(|| format!("Can't canonicalize {}", &self.file))?;
Ok((canonical, Range::new(lo, hi)))
}
}

View File

@ -196,9 +196,11 @@ impl<'a> FmtVisitor<'a> {
.map(|p_i| {
cmp::max(
self.last_pos,
p_i.attrs.iter().map(|attr| attr.span.lo).min().unwrap_or(
p_i.span.lo,
),
p_i.attrs
.iter()
.map(|attr| attr.span.lo)
.min()
.unwrap_or(p_i.span.lo),
)
})
.unwrap_or(self.last_pos);
@ -399,9 +401,9 @@ pub fn rewrite_use_list(
// Returns true when self item was found.
fn move_self_to_front(items: &mut Vec<ListItem>) -> bool {
match items.iter().position(|item| {
item.item.as_ref().map(|x| &x[..]) == Some("self")
}) {
match items
.iter()
.position(|item| item.item.as_ref().map(|x| &x[..]) == Some("self")) {
Some(pos) => {
items[0] = items.remove(pos);
true

View File

@ -149,9 +149,8 @@ impl<'a> FmtVisitor<'a> {
self.format_missing_no_indent(item.span.hi - BytePos(1));
self.block_indent = self.block_indent.block_unindent(self.config);
self.buffer.push_str(
&self.block_indent.to_string(self.config),
);
self.buffer
.push_str(&self.block_indent.to_string(self.config));
} else {
for item in &item.body {
self.format_body_element(item);
@ -424,9 +423,8 @@ impl<'a> FmtVisitor<'a> {
self.block_indent = self.block_indent.block_unindent(self.config);
if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
self.buffer.push_str(
&self.block_indent.to_string(self.config),
);
self.buffer
.push_str(&self.block_indent.to_string(self.config));
}
self.buffer.push_str("}");
self.last_pos = span.hi;
@ -955,9 +953,12 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
Density::Tall
};
let where_budget = try_opt!(context.config.max_width().checked_sub(
last_line_width(&result),
));
let where_budget = try_opt!(
context
.config
.max_width()
.checked_sub(last_line_width(&result))
);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
@ -1100,9 +1101,12 @@ fn format_struct_struct(
let item_indent = offset.block_indent(context.config);
// 1 = ","
let item_budget = try_opt!(context.config.max_width().checked_sub(
item_indent.width() + 1,
));
let item_budget = try_opt!(
context
.config
.max_width()
.checked_sub(item_indent.width() + 1)
);
let items = itemize_list(
context.codemap,
@ -1144,9 +1148,9 @@ fn format_struct_struct(
Some(format!(
"{}\n{}{}\n{}}}",
result,
offset.block_indent(context.config).to_string(
context.config,
),
offset
.block_indent(context.config)
.to_string(context.config),
items_str,
offset.to_string(context.config)
))
@ -1181,9 +1185,12 @@ fn format_tuple_struct(
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
let where_budget = try_opt!(context.config.max_width().checked_sub(
last_line_width(&result),
));
let where_budget = try_opt!(
context
.config
.max_width()
.checked_sub(last_line_width(&result))
);
try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
@ -1229,9 +1236,12 @@ fn format_tuple_struct(
}
};
// 3 = `();`
let item_budget = try_opt!(context.config.max_width().checked_sub(
item_indent.width() + 3,
));
let item_budget = try_opt!(
context
.config
.max_width()
.checked_sub(item_indent.width() + 3)
);
let items = itemize_list(
context.codemap,
@ -1321,9 +1331,12 @@ pub fn rewrite_type_alias(
let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
result.push_str(&generics_str);
let where_budget = try_opt!(context.config.max_width().checked_sub(
last_line_width(&result),
));
let where_budget = try_opt!(
context
.config
.max_width()
.checked_sub(last_line_width(&result))
);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,
@ -1358,9 +1371,12 @@ pub fn rewrite_type_alias(
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(),
));
let budget = try_opt!(
context
.config
.max_width()
.checked_sub(type_indent.width() + ";".len())
);
ty.rewrite(context, Shape::legacy(budget, type_indent))
})
);
@ -1963,9 +1979,10 @@ fn rewrite_fn_base(
}
// If the last line of args contains comment, we cannot put the closing paren
// on the same line.
if arg_str.lines().last().map_or(false, |last_line| {
last_line.contains("//")
})
if arg_str
.lines()
.last()
.map_or(false, |last_line| last_line.contains("//"))
{
args_last_line_contains_comment = true;
result.push('\n');
@ -2038,12 +2055,13 @@ fn rewrite_fn_base(
let snippet_hi = span.hi;
let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
// Try to preserve the layout of the original snippet.
let original_starts_with_newline = snippet.find(|c| c != ' ').map_or(false, |i| {
snippet[i..].starts_with('\n')
});
let original_ends_with_newline = snippet.rfind(|c| c != ' ').map_or(false, |i| {
snippet[i..].ends_with('\n')
});
let original_starts_with_newline =
snippet
.find(|c| c != ' ')
.map_or(false, |i| snippet[i..].starts_with('\n'));
let original_ends_with_newline = snippet
.rfind(|c| c != ' ')
.map_or(false, |i| snippet[i..].ends_with('\n'));
let snippet = snippet.trim();
if !snippet.is_empty() {
result.push(if original_starts_with_newline {
@ -2070,9 +2088,12 @@ fn rewrite_fn_base(
} || (put_args_in_block && ret_str.is_empty());
if where_clause.predicates.len() == 1 && should_compress_where {
let budget = try_opt!(context.config.max_width().checked_sub(
last_line_width(&result),
));
let budget = try_opt!(
context
.config
.max_width()
.checked_sub(last_line_width(&result))
);
if let Some(where_clause_str) =
rewrite_where_clause(
context,
@ -2463,9 +2484,9 @@ pub fn wrap_generics_with_angle_brackets(
"<\n{}{}\n{}>",
list_offset.to_string(context.config),
list_str,
list_offset.block_unindent(context.config).to_string(
context.config,
)
list_offset
.block_unindent(context.config)
.to_string(context.config)
)
} else if context.config.spaces_within_angle_brackets() {
format!("< {} >", list_str)
@ -2672,9 +2693,12 @@ fn format_generics(
let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
let budget = try_opt!(context.config.max_width().checked_sub(
last_line_width(&result),
));
let budget = try_opt!(
context
.config
.max_width()
.checked_sub(last_line_width(&result))
);
let where_clause_str = try_opt!(rewrite_where_clause(
context,
&generics.where_clause,

View File

@ -132,9 +132,9 @@ impl ListItem {
}
pub fn has_line_pre_comment(&self) -> bool {
self.pre_comment.as_ref().map_or(false, |comment| {
comment.starts_with("//")
})
self.pre_comment
.as_ref()
.map_or(false, |comment| comment.starts_with("//"))
}
pub fn from_str<S: Into<String>>(s: S) -> ListItem {
@ -160,9 +160,10 @@ where
I: IntoIterator<Item = T> + Clone,
T: AsRef<ListItem>,
{
let pre_line_comments = items.clone().into_iter().any(|item| {
item.as_ref().has_line_pre_comment()
});
let pre_line_comments = items
.clone()
.into_iter()
.any(|item| item.as_ref().has_line_pre_comment());
let limit = match tactic {
_ if pre_line_comments => return DefinitiveListTactic::Vertical,

View File

@ -160,9 +160,8 @@ impl<'a> FmtVisitor<'a> {
if let Some('{') = last_char {
self.buffer.push_str("\n");
}
self.buffer.push_str(
&self.block_indent.to_string(self.config),
);
self.buffer
.push_str(&self.block_indent.to_string(self.config));
} else {
self.buffer.push_str(" ");
}
@ -184,9 +183,10 @@ impl<'a> FmtVisitor<'a> {
if let Some('/') = subslice.chars().skip(1).next() {
// check that there are no contained block comments
if !subslice.split('\n').map(|s| s.trim_left()).any(|s| {
s.len() >= 2 && &s[0..2] == "/*"
})
if !subslice
.split('\n')
.map(|s| s.trim_left())
.any(|s| s.len() >= 2 && &s[0..2] == "/*")
{
// Add a newline after line comments
self.buffer.push_str("\n");

View File

@ -38,9 +38,11 @@ impl Rewrite for Pat {
let sub_pat = match *sub_pat {
Some(ref p) => {
// 3 - ` @ `.
let width = try_opt!(shape.width.checked_sub(
prefix.len() + mut_infix.len() + id_str.len() + 3,
));
let width = try_opt!(
shape
.width
.checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 3)
);
format!(
" @ {}",
try_opt!(p.rewrite(context, Shape::legacy(width, shape.indent)))

View File

@ -42,10 +42,12 @@ 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(),
));
let mut result = String::with_capacity(
stripped_str
.len()
.checked_next_power_of_two()
.unwrap_or(usize::max_value()),
);
result.push_str(fmt.opener);
let ender_length = fmt.line_end.len();

View File

@ -311,9 +311,9 @@ where
context.codemap,
// 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,
),
inputs
.map(|i| ArgumentKind::Regular(Box::new(i)))
.chain(variadic_arg),
")",
|arg| match *arg {
ArgumentKind::Regular(ref ty) => ty.span().lo,
@ -718,9 +718,8 @@ impl Rewrite for ast::Ty {
ast::TyKind::Mac(..) => None,
ast::TyKind::ImplicitSelf => Some(String::from("")),
ast::TyKind::ImplTrait(ref it) => {
it.rewrite(context, shape).map(|it_str| {
format!("impl {}", it_str)
})
it.rewrite(context, shape)
.map(|it_str| format!("impl {}", it_str))
}
ast::TyKind::Err |
ast::TyKind::Typeof(..) => unreachable!(),

View File

@ -44,9 +44,9 @@ pub fn format_visibility(vis: &Visibility) -> Cow<'static, str> {
let Path { ref segments, .. } = **path;
let mut segments_iter = segments.iter().map(|seg| seg.identifier.name.to_string());
if path.is_global() {
segments_iter.next().expect(
"Non-global path in pub(restricted)?",
);
segments_iter
.next()
.expect("Non-global path in pub(restricted)?");
}
let is_keyword = |s: &str| s == "self" || s == "super";
let path = segments_iter.collect::<Vec<_>>().join("::");
@ -129,9 +129,9 @@ fn is_skip_nested(meta_item: &NestedMetaItem) -> bool {
#[inline]
pub fn contains_skip(attrs: &[Attribute]) -> bool {
attrs.iter().any(
|a| a.meta().map_or(false, |a| is_skip(&a)),
)
attrs
.iter()
.any(|a| a.meta().map_or(false, |a| is_skip(&a)))
}
// Find the end of a TyParam

View File

@ -69,11 +69,9 @@ impl<'a> FmtVisitor<'a> {
);
// FIXME(#434): Move this check to somewhere more central, eg Rewrite.
if !self.config.file_lines().intersects(
&self.codemap.lookup_line_range(
stmt.span,
),
)
if !self.config
.file_lines()
.intersects(&self.codemap.lookup_line_range(stmt.span))
{
return;
}
@ -292,9 +290,10 @@ impl<'a> FmtVisitor<'a> {
ast::ItemKind::Impl(..) => {
self.format_missing_with_indent(source!(self, item.span).lo);
let snippet = self.get_context().snippet(item.span);
let where_span_end = snippet.find_uncommented("{").map(|x| {
(BytePos(x as u32)) + source!(self, item.span).lo
});
let where_span_end =
snippet
.find_uncommented("{")
.map(|x| (BytePos(x as u32)) + source!(self, item.span).lo);
if let Some(impl_str) = format_impl(
&self.get_context(),
item,
@ -727,9 +726,11 @@ impl Rewrite for ast::MetaItem {
ast::MetaItemKind::List(ref list) => {
let name = self.name.as_str();
// 3 = `#[` and `(`, 2 = `]` and `)`
let item_shape = try_opt!(shape.shrink_left(name.len() + 3).and_then(
|s| s.sub_width(2),
));
let item_shape = try_opt!(
shape
.shrink_left(name.len() + 3)
.and_then(|s| s.sub_width(2))
);
let hi = self.span.hi +
BytePos(count_missing_closing_parens(&context.snippet(self.span)));
let items = itemize_list(

View File

@ -84,9 +84,9 @@ 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",
);
expected_file
.read_to_string(&mut expected_text)
.expect("Failed reading target");
let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
if compare.len() > 0 {
@ -285,9 +285,9 @@ fn get_config(config_file: Option<&str>) -> Config {
let mut def_config_file = fs::File::open(config_file_name).expect("Couldn't open config");
let mut def_config = String::new();
def_config_file.read_to_string(&mut def_config).expect(
"Couldn't read config",
);
def_config_file
.read_to_string(&mut def_config)
.expect("Couldn't read config");
Config::from_toml(&def_config).expect("Invalid toml")
}

View File

@ -1,7 +1,6 @@
// rustfmt-chain_split_single_child: true
fn main() {
let files = fs::read_dir("tests/source").expect(
"Couldn't read source dir",
);
let files = fs::read_dir("tests/source")
.expect("Couldn't read source dir");
}

View File

@ -353,8 +353,8 @@ fn issue1106() {
{}
}
for entry in WalkDir::new(path).into_iter().filter_entry(|entry| {
exclusions.filter_entry(entry)
})
for entry in WalkDir::new(path)
.into_iter()
.filter_entry(|entry| exclusions.filter_entry(entry))
{}
}

View File

@ -389,9 +389,8 @@ fn issue1395() {
fn issue1456() {
Ok(Recording {
artists: match reader.evaluate(
".//mb:recording/mb:artist-credit/mb:name-credit",
)? {
artists: match reader
.evaluate(".//mb:recording/mb:artist-credit/mb:name-credit")? {
Nodeset(nodeset) => {
let res: Result<Vec<ArtistRef>, ReadError> = nodeset
.iter()