Merge pull request #1565 from topecongiro/issue-1563

Implement vec![expr; expr] and avoid unnecessary indent in chain
This commit is contained in:
Seiichi Uchida 2017-05-23 12:44:47 +09:00 committed by GitHub
commit eb8d67196c
15 changed files with 218 additions and 83 deletions

View File

@ -16,11 +16,11 @@ fn main() {
writeln!(f,
"const COMMIT_HASH: Option<&'static str> = {:?};",
git_head_sha1())
.unwrap();
.unwrap();
writeln!(f,
"const WORKTREE_CLEAN: Option<bool> = {:?};",
git_tree_is_clean())
.unwrap();
.unwrap();
// cargo:rerun-if-changed requires one entry per individual file.
for entry in WalkDir::new("src") {

View File

@ -126,9 +126,7 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
// brace.
(parent_shape, false)
} else if parent_rewrite_contains_newline {
(chain_indent(context,
parent_shape.block_indent(context.config.tab_spaces())),
false)
(chain_indent(context, parent_shape), false)
} else {
(shape.block_indent(context.config.tab_spaces()), false)
};
@ -142,17 +140,11 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
..nested_shape
};
let first_child_shape = if extend {
let mut shape = try_opt!(parent_shape.offset_left(last_line_width(&parent_rewrite)));
let first_child_shape = try_opt!(parent_shape
.offset_left(last_line_width(&parent_rewrite)));
match context.config.chain_indent() {
IndentStyle::Visual => shape,
IndentStyle::Block => {
shape.offset = shape
.offset
.checked_sub(context.config.tab_spaces())
.unwrap_or(0);
shape.indent.block_indent += context.config.tab_spaces();
shape
}
IndentStyle::Visual => first_child_shape,
IndentStyle::Block => first_child_shape.block(),
}
} else {
other_child_shape
@ -181,7 +173,6 @@ pub fn rewrite_chain(expr: &ast::Expr, context: &RewriteContext, shape: Shape) -
if rewrites.len() > 1 {
true
} else if rewrites.len() == 1 {
let one_line_len = parent_rewrite.len() + first_line_width(&rewrites[0]);
one_line_len > shape.width
} else {
false

View File

@ -120,7 +120,7 @@ fn format_expr(expr: &ast::Expr,
expr_type == ExprType::SubExpression,
false,
expr.span)
.rewrite(context, shape)
.rewrite(context, shape)
}
ast::ExprKind::IfLet(ref pat, ref cond, ref if_block, ref else_block) => {
ControlFlow::new_if(cond,
@ -130,7 +130,7 @@ fn format_expr(expr: &ast::Expr,
expr_type == ExprType::SubExpression,
false,
expr.span)
.rewrite(context, shape)
.rewrite(context, shape)
}
ast::ExprKind::Match(ref cond, ref arms) => {
rewrite_match(context, cond, arms, shape, expr.span)
@ -286,7 +286,7 @@ pub fn rewrite_pair<LHS, RHS>(lhs: &LHS,
let remaining_width = shape
.width
.checked_sub(last_line_width(&result))
.checked_sub(last_line_width(&result) + suffix.len())
.unwrap_or(0);
if rhs_result.len() <= remaining_width {
@ -372,7 +372,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
|item| item.rewrite(context, nested_shape),
span.lo,
span.hi)
.collect::<Vec<_>>();
.collect::<Vec<_>>();
if items.is_empty() {
if context.config.spaces_within_square_brackets() {
@ -716,7 +716,7 @@ impl Rewrite for ast::Stmt {
},
context,
try_opt!(shape.sub_width(suffix.len())))
.map(|s| s + suffix)
.map(|s| s + suffix)
}
ast::StmtKind::Mac(..) |
ast::StmtKind::Item(..) => None,
@ -1012,7 +1012,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
false,
true,
mk_sp(else_block.span.lo, self.span.hi))
.rewrite(context, shape)
.rewrite(context, shape)
}
ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
ControlFlow::new_if(cond,
@ -1022,7 +1022,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
false,
true,
mk_sp(else_block.span.lo, self.span.hi))
.rewrite(context, shape)
.rewrite(context, shape)
}
_ => {
last_in_chain = true;
@ -1065,7 +1065,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
.as_ref()
.map_or(between_sep, |s| &**s),
after_else_comment.as_ref().map_or(after_sep, |s| &**s))
.ok());
.ok());
result.push_str(&try_opt!(rewrite));
}
@ -2080,11 +2080,18 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
0
};
// 1 = space between operator and rhs.
let max_width = try_opt!(shape.width.checked_sub(last_line_width + 1));
let rhs = ex.rewrite(context,
Shape::offset(max_width,
shape.indent,
shape.indent.alignment + last_line_width + 1));
let orig_shape = try_opt!(shape.block_indent(0).offset_left(last_line_width + 1));
let rhs = match ex.node {
ast::ExprKind::Mac(ref mac) => {
match rewrite_macro(mac, None, context, orig_shape, MacroPosition::Expression) {
None if !context.snippet(ex.span).contains("\n") => {
context.snippet(ex.span).rewrite(context, orig_shape)
}
rhs @ _ => rhs,
}
}
_ => ex.rewrite(context, orig_shape),
};
fn count_line_breaks(src: &str) -> usize {
src.chars().filter(|&x| x == '\n').count()
@ -2099,10 +2106,7 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
// Expression did not fit on the same line as the identifier or is
// at least three lines big. Try splitting the line and see
// if that works better.
let new_offset = shape.indent.block_indent(context.config);
let max_width = try_opt!((shape.width + shape.indent.width())
.checked_sub(new_offset.width()));
let new_shape = Shape::legacy(max_width, new_offset);
let new_shape = try_opt!(shape.block_left(context.config.tab_spaces()));
let new_rhs = ex.rewrite(context, new_shape);
// FIXME: DRY!
@ -2111,11 +2115,11 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
if count_line_breaks(orig_rhs) > count_line_breaks(replacement_rhs) + 1 ||
(orig_rhs.rewrite(context, shape).is_none() &&
replacement_rhs.rewrite(context, new_shape).is_some()) => {
result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
result.push_str(&format!("\n{}", new_shape.indent.to_string(context.config)));
result.push_str(replacement_rhs);
}
(None, Some(ref final_rhs)) => {
result.push_str(&format!("\n{}", new_offset.to_string(context.config)));
result.push_str(&format!("\n{}", new_shape.indent.to_string(context.config)));
result.push_str(final_rhs);
}
(None, None) => return None,

View File

@ -332,7 +332,7 @@ impl<'a> FmtVisitor<'a> {
let suffix = if semicolon_for_expr(e) { ";" } else { "" };
e.rewrite(&self.get_context(),
Shape::indented(self.block_indent, self.config))
Shape::indented(self.block_indent, self.config))
.map(|s| s + suffix)
.or_else(|| Some(self.snippet(e.span)))
}
@ -376,7 +376,7 @@ impl<'a> FmtVisitor<'a> {
enum_def.variants.is_empty(),
self.block_indent,
mk_sp(span.lo, body_start))
.unwrap();
.unwrap();
self.buffer.push_str(&generics_str);
self.last_pos = body_start;
@ -941,7 +941,7 @@ fn format_struct_struct(context: &RewriteContext,
|field| field.rewrite(context, Shape::legacy(item_budget, item_indent)),
context.codemap.span_after(span, "{"),
span.hi)
.collect::<Vec<_>>();
.collect::<Vec<_>>();
// 1 = ,
let budget = context.config.max_width() - offset.width() + context.config.tab_spaces() - 1;
@ -1295,7 +1295,7 @@ pub fn rewrite_static(prefix: &str,
lhs,
expr,
Shape::legacy(remaining_width, offset.block_only()))
.map(|s| s + ";")
.map(|s| s + ";")
} else {
let lhs = format!("{}{};", prefix, ty_str);
Some(lhs)

View File

@ -266,7 +266,8 @@ pub fn write_list<I, T>(items: I, formatting: &ListFormatting) -> Option<String>
// Post-comments
if tactic != DefinitiveListTactic::Vertical && item.post_comment.is_some() {
let comment = item.post_comment.as_ref().unwrap();
let formatted_comment = try_opt!(rewrite_comment(comment,
let formatted_comment =
try_opt!(rewrite_comment(comment,
true,
Shape::legacy(formatting.shape.width, Indent::empty()),
formatting.config));

View File

@ -29,7 +29,7 @@ use syntax::util::ThinVec;
use Shape;
use codemap::SpanUtils;
use rewrite::{Rewrite, RewriteContext};
use expr::{rewrite_call, rewrite_array};
use expr::{rewrite_call, rewrite_array, rewrite_pair};
use comment::{FindUncommented, contains_comment};
const FORCED_BRACKET_MACROS: &'static [&'static str] = &["vec!"];
@ -105,6 +105,7 @@ pub fn rewrite_macro(mac: &ast::Mac,
let mut parser = tts_to_parser(context.parse_session, mac.node.tts.clone());
let mut expr_vec = Vec::new();
let mut vec_with_semi = false;
if MacroStyle::Braces != style {
loop {
@ -128,6 +129,29 @@ pub fn rewrite_macro(mac: &ast::Mac,
match parser.token {
Token::Eof => break,
Token::Comma => (),
Token::Semi => {
// Try to parse `vec![expr; expr]`
if FORCED_BRACKET_MACROS.contains(&&macro_name[..]) {
parser.bump();
if parser.token != Token::Eof {
match parser.parse_expr() {
Ok(expr) => {
if context.parse_session.span_diagnostic.has_errors() {
return None;
}
expr_vec.push(expr);
parser.bump();
if parser.token == Token::Eof && expr_vec.len() == 2 {
vec_with_semi = true;
break;
}
}
Err(mut e) => e.cancel(),
}
}
}
return None;
}
_ => return None,
}
@ -156,18 +180,35 @@ pub fn rewrite_macro(mac: &ast::Mac,
})
}
MacroStyle::Brackets => {
// Format macro invocation as array literal.
let extra_offset = macro_name.len();
let shape = try_opt!(shape.shrink_left(extra_offset));
let rewrite =
try_opt!(rewrite_array(expr_vec.iter().map(|x| &**x),
mk_sp(context.codemap.span_after(mac.span,
original_style.opener()),
mac.span.hi - BytePos(1)),
context,
shape));
let mac_shape = try_opt!(shape.shrink_left(macro_name.len()));
// Handle special case: `vec![expr; expr]`
if vec_with_semi {
let (lbr, rbr) = if context.config.spaces_within_square_brackets() {
("[ ", " ]")
} else {
("[", "]")
};
rewrite_pair(&*expr_vec[0],
&*expr_vec[1],
lbr,
"; ",
rbr,
context,
mac_shape)
.map(|s| format!("{}{}", macro_name, s))
} else {
// Format macro invocation as array literal.
let rewrite =
try_opt!(rewrite_array(expr_vec.iter().map(|x| &**x),
mk_sp(context.codemap.span_after(mac.span,
original_style
.opener()),
mac.span.hi - BytePos(1)),
context,
mac_shape));
Some(format!("{}{}", macro_name, rewrite))
Some(format!("{}{}", macro_name, rewrite))
}
}
MacroStyle::Braces => {
// Skip macro invocations with braces, for now.

View File

@ -163,7 +163,7 @@ impl<'a> FmtVisitor<'a> {
Shape::legacy(comment_width,
self.block_indent),
self.config)
.unwrap());
.unwrap());
last_wspace = None;
line_start = offset + subslice.len();

View File

@ -293,7 +293,7 @@ fn rewrite_tuple_pat(pats: &[ptr::P<ast::Pat>],
|item| item.rewrite(context, nested_shape),
context.codemap.span_after(span, "("),
span.hi - BytePos(1))
.collect();
.collect();
// Condense wildcard string suffix into a single ..
let wildcard_suffix_len = count_wildcard_suffix_len(&items);

View File

@ -364,7 +364,9 @@ impl Rewrite for ast::WherePredicate {
let colon = type_bound_colon(context);
if !bound_lifetimes.is_empty() {
let lifetime_str: String = try_opt!(bound_lifetimes.iter()
let lifetime_str: String =
try_opt!(bound_lifetimes
.iter()
.map(|lt| lt.rewrite(context, shape))
.intersperse(Some(", ".to_string()))
.collect());
@ -376,14 +378,17 @@ impl Rewrite for ast::WherePredicate {
// 6 = "for<> ".len()
let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6;
let budget = try_opt!(shape.width.checked_sub(used_width));
let bounds_str: String = try_opt!(bounds.iter()
.map(|ty_bound| {
ty_bound.rewrite(context,
Shape::legacy(budget,
shape.indent + used_width))
})
.intersperse(Some(joiner.to_string()))
.collect());
let bounds_str: String =
try_opt!(bounds
.iter()
.map(|ty_bound| {
ty_bound.rewrite(context,
Shape::legacy(budget,
shape.indent +
used_width))
})
.intersperse(Some(joiner.to_string()))
.collect());
if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 {
format!("for< {} > {}{}{}",
@ -401,14 +406,17 @@ impl Rewrite for ast::WherePredicate {
};
let used_width = type_str.len() + colon.len();
let budget = try_opt!(shape.width.checked_sub(used_width));
let bounds_str: String = try_opt!(bounds.iter()
.map(|ty_bound| {
ty_bound.rewrite(context,
Shape::legacy(budget,
shape.indent + used_width))
})
.intersperse(Some(joiner.to_string()))
.collect());
let bounds_str: String =
try_opt!(bounds
.iter()
.map(|ty_bound| {
ty_bound.rewrite(context,
Shape::legacy(budget,
shape.indent +
used_width))
})
.intersperse(Some(joiner.to_string()))
.collect());
format!("{}{}{}", type_str, colon, bounds_str)
}

View File

@ -282,10 +282,10 @@ impl<'a> FmtVisitor<'a> {
item.span,
indent,
None)
.map(|s| match *def {
ast::VariantData::Tuple(..) => s + ";",
_ => s,
})
.map(|s| match *def {
ast::VariantData::Tuple(..) => s + ";",
_ => s,
})
};
self.push_rewrite(item.span, rewrite);
}

View File

@ -15,3 +15,33 @@ impl Foo {
}
}
}
fn issue1420() {
given(
r#"
# Getting started
...
"#,
)
.running(waltz)
}
// #1563
fn query(conn: &Connection) -> Result<()> {
conn.query_row(
r#"
SELECT title, date
FROM posts,
WHERE DATE(date) = $1
"#,
&[],
|row| {
Post {
title: row.get(0),
date: row.get(1),
}
},
)?;
Ok(())
}

View File

@ -34,6 +34,19 @@ fn main() {
a,
];
vec![a; b];
vec!(a; b);
vec!{a; b};
vec![a, b; c];
vec![a; b, c];
vec![a; (|x| { let y = x + 1; let z = y + 1; z })(2)];
vec![a; xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx];
vec![a; unsafe {
x + 1
}];
unknown_bracket_macro__comma_should_not_be_stripped![
a,
];

View File

@ -28,3 +28,33 @@ impl Foo {
}
}
}
fn issue1420() {
given(
r#"
# Getting started
...
"#
)
.running(waltz)
}
// #1563
fn query(conn: &Connection) -> Result<()> {
conn.query_row(
r#"
SELECT title, date
FROM posts,
WHERE DATE(date) = $1
"#,
&[],
|row| {
Post {
title: row.get(0),
date: row.get(1),
}
},
)?;
Ok(())
}

View File

@ -38,6 +38,23 @@ fn main() {
// Trailing spaces after a comma
vec![a];
vec![a; b];
vec![a; b];
vec![a; b];
vec![a, b; c];
vec![a; b, c];
vec![a;
(|x| {
let y = x + 1;
let z = y + 1;
z
})(2)];
vec![a;
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx];
vec![a; unsafe { x + 1 }];
unknown_bracket_macro__comma_should_not_be_stripped![
a,
];

View File

@ -158,19 +158,19 @@ fn issue355() {
match mac {
a => println!("a", b),
b => vec![1, 2],
c => vec!(3; 4),
c => vec![3; 4],
d => println!("a", b),
e => vec![1, 2],
f => vec!(3; 4),
f => vec![3; 4],
h => println!("a", b), // h comment
i => vec![1, 2], // i comment
j => vec!(3; 4), // j comment
j => vec![3; 4], // j comment
// k comment
k => println!("a", b),
// l comment
l => vec![1, 2],
// m comment
m => vec!(3; 4),
m => vec![3; 4],
// Rewrite splits macro
nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn => {
println!("a", b)
@ -182,7 +182,7 @@ fn issue355() {
// Macro support fails to recognise this macro as splitable
// We push the whole expr to a new line, TODO split this macro as well
pppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppp => {
vec!(3; 4)
vec![3; 4]
}
// q, r and s: Rewrite splits match arm
qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq => {
@ -192,19 +192,19 @@ fn issue355() {
vec![1, 2]
}
ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss => {
vec!(3; 4)
vec![3; 4]
}
// Funky bracketing styles
t => println!{"a", b},
u => vec![1, 2],
v => vec!{3; 4},
v => vec![3; 4],
w => println!["a", b],
x => vec![1, 2],
y => vec![3; 4],
// Brackets with comments
tc => println!{"a", b}, // comment
uc => vec![1, 2], // comment
vc => vec!{3; 4}, // comment
vc => vec![3; 4], // comment
wc => println!["a", b], // comment
xc => vec![1, 2], // comment
yc => vec![3; 4], // comment