Align dots in chained expressions
This commit is contained in:
parent
95ef9dedb4
commit
a9814149c9
8 changed files with 134 additions and 130 deletions
|
@ -20,61 +20,58 @@
|
||||||
// argument function argument strategy.
|
// argument function argument strategy.
|
||||||
|
|
||||||
use rewrite::{Rewrite, RewriteContext};
|
use rewrite::{Rewrite, RewriteContext};
|
||||||
use utils::{make_indent, extra_offset};
|
use utils::make_indent;
|
||||||
use expr::rewrite_call;
|
use expr::rewrite_call;
|
||||||
|
|
||||||
use syntax::{ast, ptr};
|
use syntax::{ast, ptr};
|
||||||
use syntax::codemap::{mk_sp, Span};
|
use syntax::codemap::{mk_sp, Span};
|
||||||
use syntax::print::pprust;
|
use syntax::print::pprust;
|
||||||
|
|
||||||
pub fn rewrite_chain(orig_expr: &ast::Expr,
|
pub fn rewrite_chain(mut expr: &ast::Expr,
|
||||||
context: &RewriteContext,
|
context: &RewriteContext,
|
||||||
width: usize,
|
width: usize,
|
||||||
offset: usize)
|
offset: usize)
|
||||||
-> Option<String> {
|
-> Option<String> {
|
||||||
let mut expr = orig_expr;
|
let total_span = expr.span;
|
||||||
let mut rewrites = Vec::new();
|
let mut subexpr_list = vec![expr];
|
||||||
let indent = offset + context.config.tab_spaces;
|
|
||||||
let max_width = try_opt!(context.config.max_width.checked_sub(indent));
|
|
||||||
|
|
||||||
while let Some(pair) = pop_expr_chain(expr, orig_expr.span, context, max_width, indent) {
|
while let Some(subexpr) = pop_expr_chain(expr) {
|
||||||
let (rewrite, parent_expr) = pair;
|
subexpr_list.push(subexpr);
|
||||||
|
expr = subexpr;
|
||||||
rewrites.push(try_opt!(rewrite));
|
|
||||||
expr = parent_expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parent = subexpr_list.pop().unwrap();
|
||||||
let parent_rewrite = try_opt!(expr.rewrite(context, width, offset));
|
let parent_rewrite = try_opt!(expr.rewrite(context, width, offset));
|
||||||
|
let (extra_indent, extend) = if !parent_rewrite.contains('\n') && is_continuable(parent) ||
|
||||||
|
parent_rewrite.len() <= context.config.tab_spaces {
|
||||||
|
(parent_rewrite.len(), true)
|
||||||
|
} else {
|
||||||
|
(context.config.tab_spaces, false)
|
||||||
|
};
|
||||||
|
let indent = offset + extra_indent;
|
||||||
|
|
||||||
|
let max_width = try_opt!(width.checked_sub(extra_indent));
|
||||||
|
let rewrites = try_opt!(subexpr_list.into_iter()
|
||||||
|
.rev()
|
||||||
|
.map(|e| {
|
||||||
|
rewrite_chain_expr(e,
|
||||||
|
total_span,
|
||||||
|
context,
|
||||||
|
max_width,
|
||||||
|
indent)
|
||||||
|
})
|
||||||
|
.collect::<Option<Vec<_>>>());
|
||||||
|
|
||||||
let total_width = rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len();
|
let total_width = rewrites.iter().fold(0, |a, b| a + b.len()) + parent_rewrite.len();
|
||||||
let fits_single_line = total_width <= width && rewrites.iter().all(|s| !s.contains('\n'));
|
let fits_single_line = total_width <= width && rewrites.iter().all(|s| !s.contains('\n'));
|
||||||
|
|
||||||
if rewrites.len() == 1 && !fits_single_line &&
|
|
||||||
(is_continuable(expr) || parent_rewrite.len() <= context.config.tab_spaces) {
|
|
||||||
let extra_offset = extra_offset(&parent_rewrite, offset);
|
|
||||||
let offset = offset + extra_offset;
|
|
||||||
let max_width = try_opt!(width.checked_sub(extra_offset));
|
|
||||||
|
|
||||||
let rerewrite = pop_expr_chain(orig_expr, orig_expr.span, context, max_width, offset)
|
|
||||||
.unwrap()
|
|
||||||
.0;
|
|
||||||
|
|
||||||
return Some(format!("{}{}", parent_rewrite, try_opt!(rerewrite)));
|
|
||||||
}
|
|
||||||
|
|
||||||
let connector = if fits_single_line {
|
let connector = if fits_single_line {
|
||||||
String::new()
|
String::new()
|
||||||
} else {
|
} else {
|
||||||
format!("\n{}", make_indent(indent))
|
format!("\n{}", make_indent(indent))
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: don't do this. There's a more efficient way. VecDeque?
|
let first_connector = if extend {
|
||||||
rewrites.reverse();
|
|
||||||
|
|
||||||
// Put the first link on the same line as parent, if it fits.
|
|
||||||
let first_connector = if parent_rewrite.len() + rewrites[0].len() <= width &&
|
|
||||||
is_continuable(expr) &&
|
|
||||||
!rewrites[0].contains('\n') ||
|
|
||||||
parent_rewrite.len() <= context.config.tab_spaces {
|
|
||||||
""
|
""
|
||||||
} else {
|
} else {
|
||||||
&connector[..]
|
&connector[..]
|
||||||
|
@ -83,32 +80,36 @@ pub fn rewrite_chain(orig_expr: &ast::Expr,
|
||||||
Some(format!("{}{}{}", parent_rewrite, first_connector, rewrites.join(&connector)))
|
Some(format!("{}{}{}", parent_rewrite, first_connector, rewrites.join(&connector)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns None when the expression is not a chainable. Otherwise, rewrites the
|
fn pop_expr_chain<'a>(expr: &'a ast::Expr) -> Option<&'a ast::Expr> {
|
||||||
// outermost chain element and returns the remaining chain.
|
match expr.node {
|
||||||
fn pop_expr_chain<'a>(expr: &'a ast::Expr,
|
ast::Expr_::ExprMethodCall(_, _, ref expressions) => {
|
||||||
|
Some(&expressions[0])
|
||||||
|
}
|
||||||
|
ast::Expr_::ExprTupField(ref subexpr, _) |
|
||||||
|
ast::Expr_::ExprField(ref subexpr, _) => {
|
||||||
|
Some(subexpr)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rewrite_chain_expr(expr: &ast::Expr,
|
||||||
span: Span,
|
span: Span,
|
||||||
context: &RewriteContext,
|
context: &RewriteContext,
|
||||||
width: usize,
|
width: usize,
|
||||||
offset: usize)
|
offset: usize)
|
||||||
-> Option<(Option<String>, &'a ast::Expr)> {
|
-> Option<String> {
|
||||||
match expr.node {
|
match expr.node {
|
||||||
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
|
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
|
||||||
Some((rewrite_method_call(method_name.node,
|
rewrite_method_call(method_name.node, types, expressions, span, context, width, offset)
|
||||||
types,
|
|
||||||
expressions,
|
|
||||||
span,
|
|
||||||
context,
|
|
||||||
width,
|
|
||||||
offset),
|
|
||||||
&expressions[0]))
|
|
||||||
}
|
}
|
||||||
ast::Expr_::ExprField(ref subexpr, ref field) => {
|
ast::Expr_::ExprField(_, ref field) => {
|
||||||
Some((Some(format!(".{}", field.node)), subexpr))
|
Some(format!(".{}", field.node))
|
||||||
}
|
}
|
||||||
ast::Expr_::ExprTupField(ref subexpr, ref field) => {
|
ast::Expr_::ExprTupField(_, ref field) => {
|
||||||
Some((Some(format!(".{}", field.node)), subexpr))
|
Some(format!(".{}", field.node))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/expr.rs
12
src/expr.rs
|
@ -1017,8 +1017,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||||
};
|
};
|
||||||
|
|
||||||
let field_iter = fields.into_iter()
|
let field_iter = fields.into_iter()
|
||||||
.map(StructLitField::Regular)
|
.map(StructLitField::Regular)
|
||||||
.chain(base.into_iter().map(StructLitField::Base));
|
.chain(base.into_iter().map(StructLitField::Base));
|
||||||
|
|
||||||
let inner_context = &RewriteContext { block_indent: indent, ..*context };
|
let inner_context = &RewriteContext { block_indent: indent, ..*context };
|
||||||
|
|
||||||
|
@ -1030,8 +1030,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||||
StructLitField::Regular(ref field) => field.span.lo,
|
StructLitField::Regular(ref field) => field.span.lo,
|
||||||
StructLitField::Base(ref expr) => {
|
StructLitField::Base(ref expr) => {
|
||||||
let last_field_hi = fields.last()
|
let last_field_hi = fields.last()
|
||||||
.map_or(span.lo,
|
.map_or(span.lo,
|
||||||
|field| field.span.hi);
|
|field| field.span.hi);
|
||||||
let snippet = context.snippet(mk_sp(last_field_hi,
|
let snippet = context.snippet(mk_sp(last_field_hi,
|
||||||
expr.span.lo));
|
expr.span.lo));
|
||||||
let pos = snippet.find_uncommented("..").unwrap();
|
let pos = snippet.find_uncommented("..").unwrap();
|
||||||
|
@ -1104,8 +1104,8 @@ fn rewrite_field(context: &RewriteContext,
|
||||||
-> Option<String> {
|
-> Option<String> {
|
||||||
let name = &field.ident.node.to_string();
|
let name = &field.ident.node.to_string();
|
||||||
let overhead = name.len() + 2;
|
let overhead = name.len() + 2;
|
||||||
let expr =
|
let expr = field.expr
|
||||||
field.expr.rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead);
|
.rewrite(context, try_opt!(width.checked_sub(overhead)), offset + overhead);
|
||||||
expr.map(|s| format!("{}: {}", name, s))
|
expr.map(|s| format!("{}: {}", name, s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
41
src/items.rs
41
src/items.rs
|
@ -332,13 +332,14 @@ impl<'a> FmtVisitor<'a> {
|
||||||
// Account for sugary self.
|
// Account for sugary self.
|
||||||
// FIXME: the comment for the self argument is dropped. This is blocked
|
// FIXME: the comment for the self argument is dropped. This is blocked
|
||||||
// on rust issue #27522.
|
// on rust issue #27522.
|
||||||
let min_args = explicit_self
|
let min_args = explicit_self.and_then(|explicit_self| {
|
||||||
.and_then(|explicit_self| rewrite_explicit_self(explicit_self, args))
|
rewrite_explicit_self(explicit_self, args)
|
||||||
.map(|self_str| {
|
})
|
||||||
arg_item_strs[0] = self_str;
|
.map(|self_str| {
|
||||||
2
|
arg_item_strs[0] = self_str;
|
||||||
})
|
2
|
||||||
.unwrap_or(1);
|
})
|
||||||
|
.unwrap_or(1);
|
||||||
|
|
||||||
// Comments between args
|
// Comments between args
|
||||||
let mut arg_items = Vec::new();
|
let mut arg_items = Vec::new();
|
||||||
|
@ -761,9 +762,11 @@ impl<'a> FmtVisitor<'a> {
|
||||||
|
|
||||||
let indent = self.block_indent + self.config.tab_spaces;
|
let indent = self.block_indent + self.config.tab_spaces;
|
||||||
let mut attr_str = field.node
|
let mut attr_str = field.node
|
||||||
.attrs
|
.attrs
|
||||||
.rewrite(&self.get_context(), self.config.max_width - indent, indent)
|
.rewrite(&self.get_context(),
|
||||||
.unwrap();
|
self.config.max_width - indent,
|
||||||
|
indent)
|
||||||
|
.unwrap();
|
||||||
if !attr_str.is_empty() {
|
if !attr_str.is_empty() {
|
||||||
attr_str.push('\n');
|
attr_str.push('\n');
|
||||||
attr_str.push_str(&make_indent(indent));
|
attr_str.push_str(&make_indent(indent));
|
||||||
|
@ -804,18 +807,18 @@ impl<'a> FmtVisitor<'a> {
|
||||||
// FIXME: don't unwrap
|
// FIXME: don't unwrap
|
||||||
let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset).unwrap());
|
let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(&context, h_budget, offset).unwrap());
|
||||||
let ty_strs = tys.iter()
|
let ty_strs = tys.iter()
|
||||||
.map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap());
|
.map(|ty_param| ty_param.rewrite(&context, h_budget, offset).unwrap());
|
||||||
|
|
||||||
// Extract comments between generics.
|
// Extract comments between generics.
|
||||||
let lt_spans = lifetimes.iter()
|
let lt_spans = lifetimes.iter()
|
||||||
.map(|l| {
|
.map(|l| {
|
||||||
let hi = if l.bounds.is_empty() {
|
let hi = if l.bounds.is_empty() {
|
||||||
l.lifetime.span.hi
|
l.lifetime.span.hi
|
||||||
} else {
|
} else {
|
||||||
l.bounds[l.bounds.len() - 1].span.hi
|
l.bounds[l.bounds.len() - 1].span.hi
|
||||||
};
|
};
|
||||||
codemap::mk_sp(l.lifetime.span.lo, hi)
|
codemap::mk_sp(l.lifetime.span.lo, hi)
|
||||||
});
|
});
|
||||||
let ty_spans = tys.iter().map(span_for_ty_param);
|
let ty_spans = tys.iter().map(span_for_ty_param);
|
||||||
|
|
||||||
let items = itemize_list(self.codemap,
|
let items = itemize_list(self.codemap,
|
||||||
|
|
43
src/types.rs
43
src/types.rs
|
@ -279,22 +279,24 @@ impl Rewrite for ast::WherePredicate {
|
||||||
.. }) => {
|
.. }) => {
|
||||||
if !bound_lifetimes.is_empty() {
|
if !bound_lifetimes.is_empty() {
|
||||||
let lifetime_str = bound_lifetimes.iter()
|
let lifetime_str = bound_lifetimes.iter()
|
||||||
.map(|lt| lt.rewrite(context, width, offset).unwrap())
|
.map(|lt| {
|
||||||
.collect::<Vec<_>>()
|
lt.rewrite(context, width, offset)
|
||||||
.join(", ");
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ");
|
||||||
let type_str = pprust::ty_to_string(bounded_ty);
|
let type_str = pprust::ty_to_string(bounded_ty);
|
||||||
// 8 = "for<> : ".len()
|
// 8 = "for<> : ".len()
|
||||||
let used_width = lifetime_str.len() + type_str.len() + 8;
|
let used_width = lifetime_str.len() + type_str.len() + 8;
|
||||||
let bounds_str = bounds.iter()
|
let bounds_str = bounds.iter()
|
||||||
.map(|ty_bound| {
|
.map(|ty_bound| {
|
||||||
ty_bound
|
ty_bound.rewrite(context,
|
||||||
.rewrite(context,
|
width - used_width,
|
||||||
width - used_width,
|
offset + used_width)
|
||||||
offset + used_width)
|
.unwrap()
|
||||||
.unwrap()
|
})
|
||||||
})
|
.collect::<Vec<_>>()
|
||||||
.collect::<Vec<_>>()
|
.join(" + ");
|
||||||
.join(" + ");
|
|
||||||
|
|
||||||
format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str)
|
format!("for<{}> {}: {}", lifetime_str, type_str, bounds_str)
|
||||||
} else {
|
} else {
|
||||||
|
@ -302,15 +304,14 @@ impl Rewrite for ast::WherePredicate {
|
||||||
// 2 = ": ".len()
|
// 2 = ": ".len()
|
||||||
let used_width = type_str.len() + 2;
|
let used_width = type_str.len() + 2;
|
||||||
let bounds_str = bounds.iter()
|
let bounds_str = bounds.iter()
|
||||||
.map(|ty_bound| {
|
.map(|ty_bound| {
|
||||||
ty_bound
|
ty_bound.rewrite(context,
|
||||||
.rewrite(context,
|
width - used_width,
|
||||||
width - used_width,
|
offset + used_width)
|
||||||
offset + used_width)
|
.unwrap()
|
||||||
.unwrap()
|
})
|
||||||
})
|
.collect::<Vec<_>>()
|
||||||
.collect::<Vec<_>>()
|
.join(" + ");
|
||||||
.join(" + ");
|
|
||||||
|
|
||||||
format!("{}: {}", type_str, bounds_str)
|
format!("{}: {}", type_str, bounds_str)
|
||||||
}
|
}
|
||||||
|
|
18
src/utils.rs
18
src/utils.rs
|
@ -95,15 +95,15 @@ pub fn contains_skip(attrs: &[Attribute]) -> bool {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
|
pub fn end_typaram(typaram: &ast::TyParam) -> BytePos {
|
||||||
typaram.bounds
|
typaram.bounds
|
||||||
.last()
|
.last()
|
||||||
.map(|bound| {
|
.map(|bound| {
|
||||||
match *bound {
|
match *bound {
|
||||||
ast::RegionTyParamBound(ref lt) => lt.span,
|
ast::RegionTyParamBound(ref lt) => lt.span,
|
||||||
ast::TraitTyParamBound(ref prt, _) => prt.span,
|
ast::TraitTyParamBound(ref prt, _) => prt.span,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or(typaram.span)
|
.unwrap_or(typaram.span)
|
||||||
.hi
|
.hi
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
|
@ -288,11 +288,10 @@ impl<'a> FmtVisitor<'a> {
|
||||||
if utils::contains_skip(attrs) {
|
if utils::contains_skip(attrs) {
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
let rewrite = attrs
|
let rewrite = attrs.rewrite(&self.get_context(),
|
||||||
.rewrite(&self.get_context(),
|
self.config.max_width - self.block_indent,
|
||||||
self.config.max_width - self.block_indent,
|
self.block_indent)
|
||||||
self.block_indent)
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
self.buffer.push_str(&rewrite);
|
self.buffer.push_str(&rewrite);
|
||||||
let last = attrs.last().unwrap();
|
let last = attrs.last().unwrap();
|
||||||
self.last_pos = last.span.hi;
|
self.last_pos = last.span.hi;
|
||||||
|
|
|
@ -162,17 +162,17 @@ fn read_significant_comments(file_name: &str) -> HashMap<String, String> {
|
||||||
.expect("Failed creating pattern 2.");
|
.expect("Failed creating pattern 2.");
|
||||||
|
|
||||||
reader.lines()
|
reader.lines()
|
||||||
.map(|line| line.ok().expect("Failed getting line."))
|
.map(|line| line.ok().expect("Failed getting line."))
|
||||||
.take_while(|line| line_regex.is_match(&line))
|
.take_while(|line| line_regex.is_match(&line))
|
||||||
.filter_map(|line| {
|
.filter_map(|line| {
|
||||||
regex.captures_iter(&line)
|
regex.captures_iter(&line)
|
||||||
.next()
|
.next()
|
||||||
.map(|capture| {
|
.map(|capture| {
|
||||||
(capture.at(1).expect("Couldn\'t unwrap capture.").to_owned(),
|
(capture.at(1).expect("Couldn\'t unwrap capture.").to_owned(),
|
||||||
capture.at(2).expect("Couldn\'t unwrap capture.").to_owned())
|
capture.at(2).expect("Couldn\'t unwrap capture.").to_owned())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare output to input.
|
// Compare output to input.
|
||||||
|
|
|
@ -6,8 +6,8 @@ fn main() {
|
||||||
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddd();
|
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc.ddddddddddddddddddddddddddd();
|
||||||
|
|
||||||
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
|
bbbbbbbbbbbbbbbbbbb.ccccccccccccccccccccccccccccccccccccc
|
||||||
.ddddddddddddddddddddddddddd
|
.ddddddddddddddddddddddddddd
|
||||||
.eeeeeeee();
|
.eeeeeeee();
|
||||||
|
|
||||||
x().y(|| {
|
x().y(|| {
|
||||||
match cond() {
|
match cond() {
|
||||||
|
@ -34,13 +34,13 @@ fn main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
|
let suuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuum = xxxxxxx.map(|x| x + 5)
|
||||||
.map(|x| x / 2)
|
.map(|x| x / 2)
|
||||||
.fold(0, |acc, x| acc + x);
|
.fold(0,
|
||||||
|
|acc, x| acc + x);
|
||||||
|
|
||||||
aaaaaaaaaaaaaaaa
|
aaaaaaaaaaaaaaaa.map(|x| {
|
||||||
.map(|x| {
|
x += 1;
|
||||||
x += 1;
|
x
|
||||||
x
|
})
|
||||||
})
|
.filter(some_mod::some_filter)
|
||||||
.filter(some_mod::some_filter)
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue