Initial implementation of hard tab indentation.

This commit is contained in:
Pavel Sountsov 2015-09-05 22:39:28 -07:00 committed by SiegeLord
parent 4e1fff8710
commit d4108a3029
15 changed files with 368 additions and 214 deletions

View File

@ -19,6 +19,7 @@
// we put each subexpression on a separate, much like the (default) function
// argument function argument strategy.
use Indent;
use rewrite::{Rewrite, RewriteContext};
use utils::{first_line_width, make_indent};
use expr::rewrite_call;
@ -30,7 +31,7 @@
pub fn rewrite_chain(mut expr: &ast::Expr,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let total_span = expr.span;
let mut subexpr_list = vec![expr];
@ -116,7 +117,7 @@ pub fn rewrite_chain(mut expr: &ast::Expr,
let connector = if fits_single_line {
String::new()
} else {
format!("\n{}", make_indent(indent))
format!("\n{}", make_indent(indent, context.config))
};
let first_connector = if extend {
@ -145,7 +146,7 @@ fn rewrite_chain_expr(expr: &ast::Expr,
span: Span,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
match expr.node {
ast::Expr_::ExprMethodCall(ref method_name, ref types, ref expressions) => {
@ -179,7 +180,7 @@ fn rewrite_method_call(method_name: ast::Ident,
span: Span,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let type_str = if types.is_empty() {
String::new()

View File

@ -12,10 +12,17 @@
use std::iter;
use Indent;
use config::Config;
use string::{StringFormat, rewrite_string};
use utils::make_indent;
pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usize) -> String {
pub fn rewrite_comment(orig: &str,
block_style: bool,
width: usize,
offset: Indent,
config: &Config)
-> String {
let s = orig.trim();
// Edge case: block comments. Let's not trim their lines (for now).
@ -33,11 +40,12 @@ pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usiz
line_start: line_start,
line_end: "",
width: max_chars,
offset: offset + opener.len() - line_start.len(),
offset: offset + (opener.len() - line_start.len()),
trim_end: true,
config: config,
};
let indent_str = make_indent(offset);
let indent_str = make_indent(offset, config);
let line_breaks = s.chars().filter(|&c| c == '\n').count();
let (_, mut s) = s.lines()
@ -288,27 +296,32 @@ fn next(&mut self) -> Option<(CodeCharKind, T::Item)> {
mod test {
use super::{CharClasses, CodeCharKind, contains_comment, rewrite_comment, FindUncommented};
// FIXME(#217): prevent string literal from going over the limit.
use Indent;
#[test]
#[rustfmt_skip]
fn format_comments() {
assert_eq!("/* test */", rewrite_comment(" //test", true, 100, 100));
assert_eq!("// comment\n// on a", rewrite_comment("// comment on a", false, 10, 0));
let config = Default::default();
assert_eq!("/* test */", rewrite_comment(" //test", true, 100, Indent::new(0, 100),
&config));
assert_eq!("// comment\n// on a", rewrite_comment("// comment on a", false, 10,
Indent::new(0, 0), &config));
assert_eq!("// A multi line comment\n // between args.",
rewrite_comment("// A multi line comment\n // between args.",
false,
60,
12));
Indent::new(0, 12),
&config));
let input = "// comment";
let expected =
"/* com\n \
* men\n \
* t */";
assert_eq!(expected, rewrite_comment(input, true, 9, 69));
assert_eq!(expected, rewrite_comment(input, true, 9, Indent::new(0, 69), &config));
assert_eq!("/* trimmed */", rewrite_comment("/* trimmed */", true, 100, 100));
assert_eq!("/* trimmed */", rewrite_comment("/* trimmed */", true, 100,
Indent::new(0, 100), &config));
}
// This is probably intended to be a non-test fn, but it is not used. I'm

View File

@ -246,6 +246,7 @@ pub fn get_docs() -> Vec<ConfigHelpItem> {
format_strings: bool, "Format string literals, or leave as is",
chains_overflow_last: bool, "Allow last call in method chain to break the line",
take_source_hints: bool, "Retain some formatting characteristics from the source code",
hard_tabs: bool, "Use tab characters for indentation, spaces for alignment",
}
impl Default for Config {
@ -279,6 +280,7 @@ fn default() -> Config {
format_strings: true,
chains_overflow_last: true,
take_source_hints: true,
hard_tabs: false,
}
}
}

View File

@ -11,6 +11,7 @@
use std::cmp::Ordering;
use std::borrow::Borrow;
use Indent;
use rewrite::{Rewrite, RewriteContext};
use lists::{write_list, itemize_list, ListFormatting, SeparatorTactic, ListTactic};
use string::{StringFormat, rewrite_string};
@ -29,7 +30,7 @@
use syntax::visit::Visitor;
impl Rewrite for ast::Expr {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
match self.node {
ast::Expr_::ExprVec(ref expr_vec) => {
rewrite_array(expr_vec.iter().map(|e| &**e), self.span, context, width, offset)
@ -164,7 +165,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
span: Span,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String>
where I: Iterator<Item = &'a ast::Expr>
{
@ -201,6 +202,7 @@ pub fn rewrite_array<'a, I>(expr_iter: I,
h_width: max_item_width,
v_width: max_item_width,
ends_with_newline: false,
config: context.config,
};
let list_str = try_opt!(write_list(&items, &fmt));
@ -215,7 +217,7 @@ fn rewrite_closure(capture: ast::CaptureClause,
span: Span,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let mover = if capture == ast::CaptureClause::CaptureByValue {
"move "
@ -258,6 +260,7 @@ fn rewrite_closure(capture: ast::CaptureClause,
h_width: horizontal_budget,
v_width: budget,
ends_with_newline: false,
config: context.config,
};
let list_str = try_opt!(write_list(&arg_items.collect::<Vec<_>>(), &fmt));
let mut prefix = format!("{}|{}|", mover, list_str);
@ -265,7 +268,7 @@ fn rewrite_closure(capture: ast::CaptureClause,
if !ret_str.is_empty() {
if prefix.contains('\n') {
prefix.push('\n');
prefix.push_str(&make_indent(argument_offset));
prefix.push_str(&make_indent(argument_offset, context.config));
} else {
prefix.push(' ');
}
@ -308,18 +311,18 @@ fn rewrite_closure(capture: ast::CaptureClause,
.as_ref()
.and_then(|body_expr| {
if let ast::Expr_::ExprBlock(ref inner) = body_expr.node {
Some(inner.rewrite(&context, 2, 0))
Some(inner.rewrite(&context, 2, Indent::new(0, 0)))
} else {
None
}
})
.unwrap_or_else(|| body.rewrite(&context, 2, 0));
.unwrap_or_else(|| body.rewrite(&context, 2, Indent::new(0, 0)));
Some(format!("{} {}", prefix, try_opt!(body_rewrite)))
}
impl Rewrite for ast::Block {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let user_str = context.snippet(self.span);
if user_str == "{}" && width >= 2 {
return Some(user_str);
@ -341,7 +344,8 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
let prefix = if !trimmed.is_empty() {
// 9 = "unsafe {".len(), 7 = "unsafe ".len()
let budget = try_opt!(width.checked_sub(9));
format!("unsafe {} ", rewrite_comment(trimmed, true, budget, offset + 7))
format!("unsafe {} ",
rewrite_comment(trimmed, true, budget, offset + 7, context.config))
} else {
"unsafe ".to_owned()
};
@ -381,7 +385,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
// FIXME(#18): implement pattern formatting
impl Rewrite for ast::Pat {
fn rewrite(&self, context: &RewriteContext, _: usize, _: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, _: usize, _: Indent) -> Option<String> {
Some(context.snippet(self.span))
}
}
@ -447,7 +451,7 @@ fn new_for(pat: &'a ast::Pat,
}
impl<'a> Rewrite for Loop<'a> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let label_string = rewrite_label(self.label);
// 2 = " {".len()
let inner_width = try_opt!(width.checked_sub(self.keyword.len() + 2 + label_string.len()));
@ -483,7 +487,7 @@ fn rewrite_range(context: &RewriteContext,
left: Option<&ast::Expr>,
right: Option<&ast::Expr>,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let left_string = match left {
Some(expr) => {
@ -513,7 +517,7 @@ fn rewrite_if_else(context: &RewriteContext,
else_block_opt: Option<&ast::Expr>,
pat: Option<&ast::Pat>,
width: usize,
offset: usize,
offset: Indent,
allow_single_line: bool)
-> Option<String> {
// 3 = "if ", 2 = " {"
@ -588,11 +592,11 @@ fn single_line_if_else(context: &RewriteContext,
let new_width = try_opt!(width.checked_sub(pat_expr_str.len() + fixed_cost));
let if_expr = if_node.expr.as_ref().unwrap();
let if_str = try_opt!(if_expr.rewrite(context, new_width, 0));
let if_str = try_opt!(if_expr.rewrite(context, new_width, Indent::new(0, 0)));
let new_width = try_opt!(new_width.checked_sub(if_str.len()));
let else_expr = else_node.expr.as_ref().unwrap();
let else_str = try_opt!(else_expr.rewrite(context, new_width, 0));
let else_str = try_opt!(else_expr.rewrite(context, new_width, Indent::new(0, 0)));
// FIXME: this check shouldn't be necessary. Rewrites should either fail
// or wrap to a newline when the object does not fit the width.
@ -621,7 +625,7 @@ fn rewrite_match(context: &RewriteContext,
cond: &ast::Expr,
arms: &[ast::Arm],
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
if arms.is_empty() {
return None;
@ -634,7 +638,7 @@ fn rewrite_match(context: &RewriteContext,
let nested_context = context.nested_context();
let arm_indent = nested_context.block_indent + context.overflow_indent;
let arm_indent_str = make_indent(arm_indent);
let arm_indent_str = make_indent(arm_indent, context.config);
let open_brace_pos = span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])),
"{",
@ -669,7 +673,7 @@ fn rewrite_match(context: &RewriteContext,
result.push_str(&arm_indent_str);
let arm_str = arm.rewrite(&nested_context,
context.config.max_width - arm_indent,
context.config.max_width - arm_indent.width(),
arm_indent);
if let Some(ref arm_str) = arm_str {
result.push_str(arm_str);
@ -684,7 +688,7 @@ fn rewrite_match(context: &RewriteContext,
// match expression, but meh.
result.push('\n');
result.push_str(&make_indent(context.block_indent + context.overflow_indent));
result.push_str(&make_indent(context.block_indent + context.overflow_indent, context.config));
result.push('}');
Some(result)
}
@ -704,9 +708,9 @@ fn arm_end_pos(arm: &ast::Arm) -> BytePos {
// Match arms.
impl Rewrite for ast::Arm {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let &ast::Arm { ref attrs, ref pats, ref guard, ref body } = self;
let indent_str = make_indent(offset);
let indent_str = make_indent(offset, context.config);
// FIXME this is all a bit grotty, would be nice to abstract out the
// treatment of attributes.
@ -734,7 +738,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
.map(|p| {
p.rewrite(context,
pat_budget,
offset + context.config.tab_spaces)
offset.block_indent(context.config.tab_spaces))
})
.collect::<Option<Vec<_>>>());
@ -775,7 +779,12 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
// Where the next text can start.
let mut line_start = last_line_width(&pats_str);
if pats_str.find('\n').is_none() {
line_start += offset;
line_start += offset.width();
}
let mut line_indent = offset + pats_width;
if vertical {
line_indent = line_indent.block_indent(context.config.tab_spaces);
}
let comma = if let ast::ExprBlock(_) = body.node {
@ -788,7 +797,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
// 4 = ` => `.len()
if context.config.max_width > line_start + comma.len() + 4 {
let budget = context.config.max_width - line_start - comma.len() - 4;
if let Some(ref body_str) = body.rewrite(context, budget, line_start + 4) {
if let Some(ref body_str) = body.rewrite(context, budget, line_indent + 4) {
if first_line_width(body_str) <= budget {
return Some(format!("{}{} => {}{}",
attr_str.trim_left(),
@ -810,7 +819,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
Some(format!("{}{} =>\n{}{},",
attr_str.trim_left(),
pats_str,
make_indent(offset + context.config.tab_spaces),
make_indent(offset.block_indent(context.config.tab_spaces), context.config),
body_str))
}
}
@ -819,7 +828,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
fn rewrite_guard(context: &RewriteContext,
guard: &Option<ptr::P<ast::Expr>>,
width: usize,
offset: usize,
offset: Indent,
// The amount of space used up on this line for the pattern in
// the arm (excludes offset).
pattern_width: usize)
@ -840,10 +849,11 @@ fn rewrite_guard(context: &RewriteContext,
if overhead < width {
let cond_str = guard.rewrite(context,
width - overhead,
offset + context.config.tab_spaces);
offset.block_indent(context.config.tab_spaces));
if let Some(cond_str) = cond_str {
return Some(format!("\n{}if {}",
make_indent(offset + context.config.tab_spaces),
make_indent(offset.block_indent(context.config.tab_spaces),
context.config),
cond_str));
}
}
@ -862,7 +872,7 @@ fn rewrite_pat_expr(context: &RewriteContext,
// *without* trailing space.
connector: &str,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let pat_offset = offset + matcher.len();
let mut result = match pat {
@ -898,9 +908,11 @@ fn rewrite_pat_expr(context: &RewriteContext,
// The expression won't fit on the current line, jump to next.
result.push('\n');
result.push_str(&make_indent(pat_offset));
result.push_str(&make_indent(pat_offset, context.config));
let expr_rewrite = expr.rewrite(context, context.config.max_width - pat_offset, pat_offset);
let expr_rewrite = expr.rewrite(context,
context.config.max_width - pat_offset.width(),
pat_offset);
result.push_str(&&try_opt!(expr_rewrite));
Some(result)
@ -909,7 +921,7 @@ fn rewrite_pat_expr(context: &RewriteContext,
fn rewrite_string_lit(context: &RewriteContext,
span: Span,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
if !context.config.format_strings {
return Some(context.snippet(span));
@ -923,6 +935,7 @@ fn rewrite_string_lit(context: &RewriteContext,
width: width,
offset: offset,
trim_end: false,
config: context.config,
};
let string_lit = context.snippet(span);
@ -936,7 +949,7 @@ pub fn rewrite_call<R>(context: &RewriteContext,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
offset: Indent)
-> Option<String>
where R: Rewrite
{
@ -955,7 +968,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
args: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
offset: Indent)
-> Result<String, Ordering>
where R: Rewrite
{
@ -1003,7 +1016,7 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
span.lo,
span.hi);
let fmt = ListFormatting::for_fn(remaining_width, offset);
let fmt = ListFormatting::for_fn(remaining_width, offset, context.config);
let list_str = match write_list(&items.collect::<Vec<_>>(), &fmt) {
Some(str) => str,
None => return Err(Ordering::Less),
@ -1015,9 +1028,9 @@ fn rewrite_call_inner<R>(context: &RewriteContext,
fn rewrite_paren(context: &RewriteContext,
subexpr: &ast::Expr,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
debug!("rewrite_paren, width: {}, offset: {}", width, offset);
debug!("rewrite_paren, width: {}, offset: {:?}", width, offset);
// 1 is for opening paren, 2 is for opening+closing, we want to keep the closing
// paren on the same line as the subexpr.
let subexpr_str = subexpr.rewrite(context, try_opt!(width.checked_sub(2)), offset + 1);
@ -1031,9 +1044,9 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
base: Option<&'a ast::Expr>,
span: Span,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
debug!("rewrite_struct_lit: width {}, offset {}", width, offset);
debug!("rewrite_struct_lit: width {}, offset {:?}", width, offset);
assert!(!fields.is_empty() || base.is_some());
enum StructLitField<'a> {
@ -1054,8 +1067,8 @@ enum StructLitField<'a> {
StructLitStyle::Block => {
// If we are all on one line, then we'll ignore the indent, and we
// have a smaller budget.
let indent = context.block_indent + context.config.tab_spaces;
let v_budget = context.config.max_width.checked_sub(indent).unwrap_or(0);
let indent = context.block_indent.block_indent(context.config.tab_spaces);
let v_budget = context.config.max_width.checked_sub(indent.width()).unwrap_or(0);
(indent, v_budget)
}
};
@ -1121,12 +1134,15 @@ enum StructLitField<'a> {
h_width: h_budget,
v_width: v_budget,
ends_with_newline: false,
config: context.config,
};
let fields_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
let format_on_newline = || {
let inner_indent = make_indent(context.block_indent + context.config.tab_spaces);
let outer_indent = make_indent(context.block_indent);
let inner_indent = make_indent(context.block_indent
.block_indent(context.config.tab_spaces),
context.config);
let outer_indent = make_indent(context.block_indent, context.config);
Some(format!("{} {{\n{}{}\n{}}}", path_str, inner_indent, fields_str, outer_indent))
};
@ -1143,7 +1159,7 @@ enum StructLitField<'a> {
fn rewrite_field(context: &RewriteContext,
field: &ast::Field,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let name = &field.ident.node.to_string();
let overhead = name.len() + 2;
@ -1156,9 +1172,9 @@ fn rewrite_tuple_lit(context: &RewriteContext,
items: &[ptr::P<ast::Expr>],
span: Span,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
debug!("rewrite_tuple_lit: width: {}, offset: {}", width, offset);
debug!("rewrite_tuple_lit: width: {}, offset: {:?}", width, offset);
let indent = offset + 1;
// In case of length 1, need a trailing comma
if items.len() == 1 {
@ -1173,7 +1189,7 @@ fn rewrite_tuple_lit(context: &RewriteContext,
|item| item.span.lo,
|item| item.span.hi,
|item| {
let inner_width = context.config.max_width - indent - 1;
let inner_width = context.config.max_width - indent.width() - 1;
item.rewrite(context, inner_width, indent)
.unwrap_or(context.snippet(item.span))
},
@ -1181,7 +1197,7 @@ fn rewrite_tuple_lit(context: &RewriteContext,
span.hi - BytePos(1));
let budget = try_opt!(width.checked_sub(2));
let fmt = ListFormatting::for_fn(budget, indent);
let fmt = ListFormatting::for_fn(budget, indent, context.config);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
Some(format!("({})", list_str))
@ -1192,7 +1208,7 @@ fn rewrite_binary_op(context: &RewriteContext,
lhs: &ast::Expr,
rhs: &ast::Expr,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
// FIXME: format comments between operands and operator
@ -1233,11 +1249,13 @@ fn rewrite_binary_op(context: &RewriteContext,
// We have to use multiple lines.
// Re-evaluate the lhs because we have more space now:
let budget = try_opt!(context.config.max_width.checked_sub(offset + 1 + operator_str.len()));
let budget = try_opt!(context.config
.max_width
.checked_sub(offset.width() + 1 + operator_str.len()));
Some(format!("{} {}\n{}{}",
try_opt!(lhs.rewrite(context, budget, offset)),
operator_str,
make_indent(offset),
make_indent(offset, context.config),
rhs_result))
}
@ -1245,7 +1263,7 @@ fn rewrite_unary_op(context: &RewriteContext,
op: &ast::UnOp,
expr: &ast::Expr,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
// For some reason, an UnOp is not spanned like BinOp!
let operator_str = match *op {
@ -1265,7 +1283,7 @@ fn rewrite_assignment(context: &RewriteContext,
rhs: &ast::Expr,
op: Option<&ast::BinOp>,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let operator_str = match op {
Some(op) => context.snippet(op.span),
@ -1285,7 +1303,7 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
lhs: S,
ex: &ast::Expr,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let mut result = lhs.into();
@ -1301,13 +1319,14 @@ pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
None => {
// Expression did not fit on the same line as the identifier. Retry
// on the next line.
let new_offset = offset + context.config.tab_spaces;
result.push_str(&format!("\n{}", make_indent(new_offset)));
let new_offset = offset.block_indent(context.config.tab_spaces);
result.push_str(&format!("\n{}", make_indent(new_offset, context.config)));
// FIXME: we probably should related max_width to width instead of config.max_width
// where is the 1 coming from anyway?
let max_width = try_opt!(context.config.max_width.checked_sub(new_offset + 1));
let overflow_context = context.overflow_context(context.config.tab_spaces);
let max_width = try_opt!(context.config.max_width.checked_sub(new_offset.width() + 1));
let rhs_indent = Indent::new(context.config.tab_spaces, 0);
let overflow_context = context.overflow_context(rhs_indent);
let rhs = ex.rewrite(&overflow_context, max_width, new_offset);
result.push_str(&&try_opt!(rhs));

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use Indent;
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
use utils::span_after;
use rewrite::{Rewrite, RewriteContext};
@ -20,7 +21,7 @@
impl Rewrite for ast::ViewPath {
// Returns an empty string when the ViewPath is empty (like foo::bar::{})
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
match self.node {
ast::ViewPath_::ViewPathList(_, ref path_list) if path_list.is_empty() => {
Some(String::new())
@ -68,7 +69,7 @@ fn rewrite_single_use_list(path_str: String, vpi: ast::PathListItem) -> String {
// Pretty prints a multi-item import.
// Assumes that path_list.len() > 0.
pub fn rewrite_use_list(width: usize,
offset: usize,
offset: Indent,
path: &ast::Path,
path_list: &[ast::PathListItem],
span: Span,
@ -105,6 +106,7 @@ pub fn rewrite_use_list(width: usize,
// (loose 1 column (";"))
v_width: remaining_width,
ends_with_newline: false,
config: context.config,
};
let mut items = {

View File

@ -10,6 +10,7 @@
// Formatting top-level items - functions, structs, enums, traits, impls.
use Indent;
use utils::{format_mutability, format_visibility, make_indent, contains_skip, span_after,
end_typaram, wrap_str};
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
@ -26,7 +27,7 @@
impl<'a> FmtVisitor<'a> {
pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
self.format_missing_with_indent(span.lo);
self.format_missing_with_indent(span.lo, self.config);
// String that is placed within the assignment pattern and expression.
let infix = {
@ -34,8 +35,7 @@ pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
if let Some(ref ty) = local.ty {
infix.push_str(": ");
// FIXME: silly width, indent
infix.push_str(&ty.rewrite(&self.get_context(), 1000, 0).unwrap());
infix.push_str(&ty.rewrite(&self.get_context(), 1000, Indent::new(0, 0)).unwrap());
}
if local.init.is_some() {
@ -52,12 +52,13 @@ pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
let mut result = "let ".to_owned();
let pattern_offset = self.block_indent + result.len() + infix.len();
// 1 = ;
let pattern_width = match self.config.max_width.checked_sub(pattern_offset + 1) {
let pattern_width = self.config.max_width.checked_sub(pattern_offset.width() + 1);
let pattern_width = match pattern_width {
Some(width) => width,
None => return,
};
match local.pat.rewrite(&context, pattern_offset, pattern_width) {
match local.pat.rewrite(&context, pattern_width, pattern_offset) {
Some(ref pat_string) => result.push_str(pat_string),
None => return,
}
@ -65,7 +66,8 @@ pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
result.push_str(&infix);
if let Some(ref ex) = local.init {
let max_width = match self.config.max_width.checked_sub(context.block_indent + 1) {
let max_width = self.config.max_width.checked_sub(context.block_indent.width() + 1);
let max_width = match max_width {
Some(width) => width,
None => return,
};
@ -88,7 +90,7 @@ pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
}
pub fn rewrite_fn(&mut self,
indent: usize,
indent: Indent,
ident: ast::Ident,
fd: &ast::FnDecl,
explicit_self: Option<&ast::ExplicitSelf>,
@ -124,7 +126,7 @@ pub fn rewrite_fn(&mut self,
// this.
if newline_brace {
result.push('\n');
result.push_str(&make_indent(indent));
result.push_str(&make_indent(indent, self.config));
} else {
result.push(' ');
}
@ -133,7 +135,7 @@ pub fn rewrite_fn(&mut self,
}
pub fn rewrite_required_fn(&mut self,
indent: usize,
indent: Indent,
ident: ast::Ident,
sig: &ast::MethodSig,
span: Span)
@ -160,7 +162,7 @@ pub fn rewrite_required_fn(&mut self,
}
fn rewrite_fn_base(&mut self,
indent: usize,
indent: Indent,
ident: ast::Ident,
fd: &ast::FnDecl,
explicit_self: Option<&ast::ExplicitSelf>,
@ -207,13 +209,15 @@ fn rewrite_fn_base(&mut self,
result.push_str(&generics_str);
let context = self.get_context();
let ret_str = fd.output.rewrite(&context, self.config.max_width - indent, indent).unwrap();
let ret_str = fd.output
.rewrite(&context, self.config.max_width - indent.width(), indent)
.unwrap();
// Args.
let (one_line_budget, multi_line_budget, mut arg_indent) =
self.compute_budgets_for_args(&result, indent, ret_str.len(), newline_brace);
debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {}",
debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
one_line_budget,
multi_line_budget,
arg_indent);
@ -222,17 +226,17 @@ fn rewrite_fn_base(&mut self,
if one_line_budget <= 0 {
if self.config.fn_args_paren_newline {
result.push('\n');
result.push_str(&make_indent(arg_indent));
result.push_str(&make_indent(arg_indent, self.config));
arg_indent = arg_indent + 1; // extra space for `(`
result.push('(');
} else {
result.push_str("(\n");
result.push_str(&make_indent(arg_indent));
result.push_str(&make_indent(arg_indent, self.config));
}
} else if self.config.fn_args_layout == StructLitStyle::Block {
arg_indent = indent + self.config.tab_spaces;
arg_indent = indent.block_indent(self.config.tab_spaces);
result.push_str("(\n");
result.push_str(&make_indent(arg_indent));
result.push_str(&make_indent(arg_indent, self.config));
} else {
result.push('(');
}
@ -266,7 +270,7 @@ fn rewrite_fn_base(&mut self,
// Unless we are formatting args like a block, in which case there
// should always be room for the return type.
if (result.contains("\n") ||
result.len() + indent + ret_str.len() > self.config.max_width) &&
result.len() + indent.width() + ret_str.len() > self.config.max_width) &&
self.config.fn_args_layout != StructLitStyle::Block {
let indent = match self.config.fn_return_indent {
ReturnIndent::WithWhereClause => indent + 4,
@ -277,7 +281,7 @@ fn rewrite_fn_base(&mut self,
};
result.push('\n');
result.push_str(&make_indent(indent));
result.push_str(&make_indent(indent, self.config));
} else {
result.push(' ');
}
@ -326,8 +330,8 @@ fn rewrite_args(&self,
explicit_self: Option<&ast::ExplicitSelf>,
one_line_budget: usize,
multi_line_budget: usize,
indent: usize,
arg_indent: usize,
indent: Indent,
arg_indent: Indent,
span: Span)
-> Option<String> {
let context = self.get_context();
@ -386,7 +390,7 @@ fn rewrite_args(&self,
let indent = match self.config.fn_arg_indent {
BlockIndentStyle::Inherit => indent,
BlockIndentStyle::Tabbed => indent + self.config.tab_spaces,
BlockIndentStyle::Tabbed => indent.block_indent(self.config.tab_spaces),
BlockIndentStyle::Visual => arg_indent,
};
@ -398,6 +402,7 @@ fn rewrite_args(&self,
h_width: one_line_budget,
v_width: multi_line_budget,
ends_with_newline: false,
config: self.config,
};
write_list(&arg_items, &fmt)
@ -405,16 +410,16 @@ fn rewrite_args(&self,
fn compute_budgets_for_args(&self,
result: &str,
indent: usize,
indent: Indent,
ret_str_len: usize,
newline_brace: bool)
-> (usize, usize, usize) {
-> (usize, usize, Indent) {
let mut budgets = None;
// Try keeping everything on the same line
if !result.contains("\n") {
// 3 = `() `, space is before ret_string
let mut used_space = indent + result.len() + ret_str_len + 3;
let mut used_space = indent.width() + result.len() + ret_str_len + 3;
if !newline_brace {
used_space += 2;
}
@ -425,7 +430,7 @@ fn compute_budgets_for_args(&self,
};
// 2 = `()`
let used_space = indent + result.len() + 2;
let used_space = indent.width() + result.len() + 2;
let max_space = self.config.ideal_width + self.config.leeway;
debug!("compute_budgets_for_args: used_space: {}, max_space: {}",
used_space,
@ -439,8 +444,8 @@ fn compute_budgets_for_args(&self,
// Didn't work. we must force vertical layout and put args on a newline.
if let None = budgets {
let new_indent = indent + self.config.tab_spaces;
let used_space = new_indent + 2; // account for `(` and `)`
let new_indent = indent.block_indent(self.config.tab_spaces);
let used_space = new_indent.width() + 2; // account for `(` and `)`
let max_space = self.config.ideal_width + self.config.leeway;
if used_space > max_space {
// Whoops! bankrupt.
@ -475,13 +480,14 @@ pub fn visit_enum(&mut self,
let generics_str = self.format_generics(generics,
" {",
self.block_indent,
self.block_indent + self.config.tab_spaces,
self.block_indent
.block_indent(self.config.tab_spaces),
codemap::mk_sp(span.lo, body_start))
.unwrap();
self.buffer.push_str(&generics_str);
self.last_pos = body_start;
self.block_indent += self.config.tab_spaces;
self.block_indent = self.block_indent.block_indent(self.config.tab_spaces);
for (i, f) in enum_def.variants.iter().enumerate() {
let next_span_start: BytePos = if i == enum_def.variants.len() - 1 {
span.hi
@ -491,9 +497,10 @@ pub fn visit_enum(&mut self,
self.visit_variant(f, i == enum_def.variants.len() - 1, next_span_start);
}
self.block_indent -= self.config.tab_spaces;
self.block_indent = self.block_indent.block_unindent(self.config.tab_spaces);
self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32));
self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32),
self.config);
self.buffer.push_str("}");
}
@ -503,7 +510,7 @@ fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_st
return;
}
self.format_missing_with_indent(field.span.lo);
self.format_missing_with_indent(field.span.lo, self.config);
let result = match field.node.kind {
ast::VariantKind::TupleVariantKind(ref types) => {
@ -521,7 +528,9 @@ fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_st
|arg| {
// FIXME silly width, indent
arg.ty
.rewrite(&self.get_context(), 1000, 0)
.rewrite(&self.get_context(),
1000,
Indent::new(0, 0))
.unwrap()
},
span_after(field.span, "(", self.codemap),
@ -536,7 +545,7 @@ fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_st
} else {
0
};
let budget = self.config.ideal_width - indent - comma_cost - 1; // 1 = )
let budget = self.config.ideal_width - indent.width() - comma_cost - 1; // 1 = )
let fmt = ListFormatting {
tactic: ListTactic::HorizontalVertical,
@ -546,6 +555,7 @@ fn visit_variant(&mut self, field: &ast::Variant, last_field: bool, next_span_st
h_width: budget,
v_width: budget,
ends_with_newline: true,
config: self.config,
};
let list_str = match write_list(&items.collect::<Vec<_>>(), &fmt) {
Some(list_str) => list_str,
@ -601,7 +611,7 @@ fn format_struct(&self,
struct_def: &ast::StructDef,
generics: Option<&ast::Generics>,
span: Span,
offset: usize)
offset: Indent)
-> Option<String> {
let mut result = String::with_capacity(1024);
@ -654,7 +664,7 @@ fn format_struct(&self,
span.hi);
// 2 terminators and a semicolon
let used_budget = offset + header_str.len() + generics_str.len() + 3;
let used_budget = offset.width() + header_str.len() + generics_str.len() + 3;
// Conservative approximation
let single_line_cost = (span.hi - struct_def.fields[0].span.lo).0;
@ -662,7 +672,7 @@ fn format_struct(&self,
single_line_cost as usize + used_budget > self.config.max_width;
let tactic = if break_line {
let indentation = make_indent(offset + self.config.tab_spaces);
let indentation = make_indent(offset.block_indent(self.config.tab_spaces), self.config);
result.push('\n');
result.push_str(&indentation);
@ -672,15 +682,16 @@ fn format_struct(&self,
};
// 1 = ,
let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1;
let budget = self.config.ideal_width - offset.width() + self.config.tab_spaces - 1;
let fmt = ListFormatting {
tactic: tactic,
separator: ",",
trailing_separator: self.config.struct_trailing_comma,
indent: offset + self.config.tab_spaces,
indent: offset.block_indent(self.config.tab_spaces),
h_width: self.config.max_width,
v_width: budget,
ends_with_newline: true,
config: self.config,
};
let list_str = write_list(&items.collect::<Vec<_>>(), &fmt).unwrap();
@ -688,7 +699,7 @@ fn format_struct(&self,
if break_line {
result.push('\n');
result.push_str(&make_indent(offset));
result.push_str(&make_indent(offset, self.config));
}
result.push_str(terminator);
@ -727,8 +738,8 @@ fn format_header(&self, item_name: &str, ident: ast::Ident, vis: ast::Visibility
fn format_generics(&self,
generics: &ast::Generics,
opener: &str,
offset: usize,
generics_offset: usize,
offset: Indent,
generics_offset: Indent,
span: Span)
-> Option<String> {
let mut result = try_opt!(self.rewrite_generics(generics, offset, generics_offset, span));
@ -740,7 +751,7 @@ fn format_generics(&self,
Density::Tall,
span.hi));
result.push_str(&where_clause_str);
result.push_str(&make_indent(self.block_indent));
result.push_str(&make_indent(self.block_indent, self.config));
result.push('\n');
result.push_str(opener.trim());
} else {
@ -765,18 +776,18 @@ fn format_field(&self, field: &ast::StructField) -> String {
ast::StructFieldKind::UnnamedField(vis) => format_visibility(vis),
};
// FIXME silly width, indent
let typ = field.node.ty.rewrite(&self.get_context(), 1000, 0).unwrap();
let typ = field.node.ty.rewrite(&self.get_context(), 1000, Indent::new(0, 0)).unwrap();
let indent = self.block_indent + self.config.tab_spaces;
let mut attr_str = field.node
.attrs
.rewrite(&self.get_context(),
self.config.max_width - indent,
self.config.max_width - indent.width(),
indent)
.unwrap();
if !attr_str.is_empty() {
attr_str.push('\n');
attr_str.push_str(&make_indent(indent));
attr_str.push_str(&make_indent(indent, self.config));
}
match name {
@ -787,8 +798,8 @@ fn format_field(&self, field: &ast::StructField) -> String {
fn rewrite_generics(&self,
generics: &ast::Generics,
offset: usize,
generics_offset: usize,
offset: Indent,
generics_offset: Indent,
span: Span)
-> Option<String> {
// FIXME: convert bounds to where clauses where they get too big or if
@ -801,12 +812,12 @@ fn rewrite_generics(&self,
let offset = match self.config.generics_indent {
BlockIndentStyle::Inherit => offset,
BlockIndentStyle::Tabbed => offset + self.config.tab_spaces,
BlockIndentStyle::Tabbed => offset.block_indent(self.config.tab_spaces),
// 1 = <
BlockIndentStyle::Visual => generics_offset + 1,
};
let h_budget = self.config.max_width - generics_offset - 2;
let h_budget = self.config.max_width - generics_offset.width() - 2;
// TODO: might need to insert a newline if the generics are really long.
// Strings for the generics.
@ -841,7 +852,7 @@ fn rewrite_generics(&self,
item.item = ty;
}
let fmt = ListFormatting::for_fn(h_budget, offset);
let fmt = ListFormatting::for_fn(h_budget, offset, self.config);
let list_str = try_opt!(write_list(&items, &fmt));
Some(format!("<{}>", list_str))
@ -850,7 +861,7 @@ fn rewrite_generics(&self,
fn rewrite_where_clause(&self,
where_clause: &ast::WhereClause,
config: &Config,
indent: usize,
indent: Indent,
density: Density,
span_end: BytePos)
-> Option<String> {
@ -859,22 +870,23 @@ fn rewrite_where_clause(&self,
}
let extra_indent = match self.config.where_indent {
BlockIndentStyle::Inherit => 0,
BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => config.tab_spaces,
BlockIndentStyle::Inherit => Indent::new(0, 0),
BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces,
0),
};
let context = self.get_context();
let offset = match self.config.where_pred_indent {
BlockIndentStyle::Inherit => indent + extra_indent,
BlockIndentStyle::Tabbed => indent + extra_indent + config.tab_spaces,
BlockIndentStyle::Tabbed => indent + extra_indent.block_indent(config.tab_spaces),
// 6 = "where ".len()
BlockIndentStyle::Visual => indent + extra_indent + 6,
};
// FIXME: if where_pred_indent != Visual, then the budgets below might
// be out by a char or two.
let budget = self.config.ideal_width + self.config.leeway - offset;
let budget = self.config.ideal_width + self.config.leeway - offset.width();
let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
let items = itemize_list(self.codemap,
where_clause.predicates.iter(),
@ -896,13 +908,16 @@ fn rewrite_where_clause(&self,
h_width: budget,
v_width: budget,
ends_with_newline: true,
config: self.config,
};
let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
// 9 = " where ".len() + " {".len()
if density == Density::Tall || preds_str.contains('\n') ||
indent + 9 + preds_str.len() > self.config.max_width {
Some(format!("\n{}where {}", make_indent(indent + extra_indent), preds_str))
indent.width() + 9 + preds_str.len() > self.config.max_width {
Some(format!("\n{}where {}",
make_indent(indent + extra_indent, self.config),
preds_str))
} else {
Some(format!(" where {}", preds_str))
}
@ -910,7 +925,7 @@ fn rewrite_where_clause(&self,
}
impl Rewrite for ast::FunctionRetTy {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
match *self {
ast::FunctionRetTy::DefaultReturn(_) => Some(String::new()),
ast::FunctionRetTy::NoReturn(_) => {
@ -929,7 +944,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
}
impl Rewrite for ast::Arg {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
if is_named_arg(self) {
if let ast::Ty_::TyInfer = self.ty.node {
wrap_str(pprust::pat_to_string(&self.pat), context.config.max_width, width, offset)

View File

@ -44,6 +44,7 @@
use syntax::codemap::CodeMap;
use syntax::diagnostics;
use std::ops::{Add, Sub};
use std::path::PathBuf;
use std::collections::HashMap;
use std::fmt;
@ -80,6 +81,79 @@
// When we get scoped annotations, we should have rustfmt::skip.
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";
#[derive(Copy, Clone, Debug)]
pub struct Indent {
block_indent: usize,
alignment: usize,
}
impl Indent {
pub fn new(block_indent: usize, alignment: usize) -> Indent {
Indent { block_indent: block_indent, alignment: alignment }
}
pub fn block_indent(mut self, block_indent: usize) -> Indent {
self.block_indent += block_indent;
self
}
pub fn block_unindent(mut self, block_indent: usize) -> Indent {
self.block_indent -= block_indent;
self
}
pub fn width(&self) -> usize {
self.block_indent + self.alignment
}
pub fn to_string(&self, config: &Config) -> String {
let (num_tabs, num_spaces) = if config.hard_tabs {
(self.block_indent / config.tab_spaces, self.alignment)
} else {
(0, self.block_indent + self.alignment)
};
let num_chars = num_tabs + num_spaces;
let mut indent = String::with_capacity(num_chars);
for _ in 0..num_tabs {
indent.push('\t')
}
for _ in 0..num_spaces {
indent.push(' ')
}
indent
}
}
impl Add for Indent {
type Output = Indent;
fn add(self, rhs: Indent) -> Indent {
Indent {
block_indent: self.block_indent + rhs.block_indent,
alignment: self.alignment + rhs.alignment,
}
}
}
impl Sub for Indent {
type Output = Indent;
fn sub(self, rhs: Indent) -> Indent {
Indent {
block_indent: self.block_indent - rhs.block_indent,
alignment: self.alignment - rhs.alignment,
}
}
}
impl Add<usize> for Indent {
type Output = Indent;
fn add(self, rhs: usize) -> Indent {
Indent { block_indent: self.block_indent, alignment: self.alignment + rhs }
}
}
#[derive(Copy, Clone)]
pub enum WriteMode {
// Backups the original file and overwrites the orignal.

View File

@ -13,8 +13,10 @@
use syntax::codemap::{self, CodeMap, BytePos};
use Indent;
use utils::{round_up_to_power_of_two, make_indent, wrap_str};
use comment::{FindUncommented, rewrite_comment, find_comment_end};
use config::Config;
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
pub enum ListTactic {
@ -44,7 +46,7 @@ pub struct ListFormatting<'a> {
pub tactic: ListTactic,
pub separator: &'a str,
pub trailing_separator: SeparatorTactic,
pub indent: usize,
pub indent: Indent,
// Available width if we layout horizontally.
pub h_width: usize,
// Available width if we layout vertically
@ -52,10 +54,11 @@ pub struct ListFormatting<'a> {
// Non-expressions, e.g. items, will have a new line at the end of the list.
// Important for comment styles.
pub ends_with_newline: bool,
pub config: &'a Config,
}
impl<'a> ListFormatting<'a> {
pub fn for_fn(width: usize, offset: usize) -> ListFormatting<'a> {
pub fn for_fn(width: usize, offset: Indent, config: &'a Config) -> ListFormatting<'a> {
ListFormatting {
tactic: ListTactic::HorizontalVertical,
separator: ",",
@ -64,6 +67,7 @@ pub fn for_fn(width: usize, offset: usize) -> ListFormatting<'a> {
h_width: width,
v_width: width,
ends_with_newline: false,
config: config,
}
}
}
@ -146,12 +150,12 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> Op
let alloc_width = if tactic == ListTactic::Horizontal {
total_width + total_sep_len
} else {
total_width + items.len() * (formatting.indent + 1)
total_width + items.len() * (formatting.indent.width() + 1)
};
let mut result = String::with_capacity(round_up_to_power_of_two(alloc_width));
let mut line_len = 0;
let indent_str = &make_indent(formatting.indent);
let indent_str = &make_indent(formatting.indent, formatting.config);
for (i, item) in items.iter().enumerate() {
let first = i == 0;
let last = i == items.len() - 1;
@ -196,7 +200,8 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> Op
let block_mode = tactic != ListTactic::Vertical;
// Width restriction is only relevant in vertical mode.
let max_width = formatting.v_width;
result.push_str(&rewrite_comment(comment, block_mode, max_width, formatting.indent));
result.push_str(&rewrite_comment(comment, block_mode, max_width, formatting.indent,
formatting.config));
if tactic == ListTactic::Vertical {
result.push('\n');
@ -206,14 +211,18 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> Op
}
}
let max_width = formatting.indent + formatting.v_width;
let max_width = formatting.indent.width() + formatting.v_width;
let item_str = wrap_str(&item.item[..], max_width, formatting.v_width, formatting.indent);
result.push_str(&&try_opt!(item_str));
// Post-comments
if tactic != ListTactic::Vertical && item.post_comment.is_some() {
let comment = item.post_comment.as_ref().unwrap();
let formatted_comment = rewrite_comment(comment, true, formatting.v_width, 0);
let formatted_comment = rewrite_comment(comment,
true,
formatting.v_width,
Indent::new(0, 0),
formatting.config);
result.push(' ');
result.push_str(&formatted_comment);
@ -226,14 +235,19 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> Op
if tactic == ListTactic::Vertical && item.post_comment.is_some() {
// 1 = space between item and comment.
let width = formatting.v_width.checked_sub(item_width + 1).unwrap_or(1);
let offset = formatting.indent + item_width + 1;
let mut offset = formatting.indent;
offset.alignment += item_width + 1;
let comment = item.post_comment.as_ref().unwrap();
// Use block-style only for the last item or multiline comments.
let block_style = !formatting.ends_with_newline && last ||
comment.trim().contains('\n') ||
comment.trim().len() > width;
let formatted_comment = rewrite_comment(comment, block_style, width, offset);
let formatted_comment = rewrite_comment(comment,
block_style,
width,
offset,
formatting.config);
result.push(' ');
result.push_str(&formatted_comment);

View File

@ -25,6 +25,7 @@
use syntax::parse::token::{Eof, Comma, Token};
use syntax::parse::{ParseSess, tts_to_parser};
use Indent;
use rewrite::RewriteContext;
use expr::{rewrite_call, rewrite_array};
use comment::FindUncommented;
@ -46,7 +47,7 @@ enum MacroStyle {
pub fn rewrite_macro(mac: &ast::Mac,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let ast::Mac_::MacInvocTT(ref path, ref tt_vec, _) = mac.node;
let style = macro_style(mac, context);

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use config::Config;
use utils::make_indent;
use visitor::FmtVisitor;
@ -20,15 +21,15 @@ pub fn format_missing(&mut self, end: BytePos) {
self.format_missing_inner(end, |this, last_snippet, _| this.buffer.push_str(last_snippet))
}
pub fn format_missing_with_indent(&mut self, end: BytePos) {
pub fn format_missing_with_indent(&mut self, end: BytePos, config: &Config) {
self.format_missing_inner(end,
|this, last_snippet, snippet| {
this.buffer.push_str(last_snippet.trim_right());
if last_snippet == snippet {
// No new lines in the snippet.
// No new lines in the snippet.
this.buffer.push_str("\n");
}
let indent = make_indent(this.block_indent);
let indent = make_indent(this.block_indent, config);
this.buffer.push_str(&indent);
})
}

View File

@ -12,6 +12,7 @@
use syntax::codemap::{CodeMap, Span};
use Indent;
use config::Config;
pub trait Rewrite {
@ -22,7 +23,7 @@ pub trait Rewrite {
/// `width` is the maximum number of characters on the last line
/// (excluding offset). The width of other lines is not limited by
/// `width`.
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String>;
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String>;
}
pub struct RewriteContext<'a> {
@ -30,12 +31,12 @@ pub struct RewriteContext<'a> {
pub config: &'a Config,
// Indentation due to nesting of blocks.
pub block_indent: usize,
pub block_indent: Indent,
// *Extra* indentation due to overflowing to the next line, e.g.,
// let foo =
// bar();
// The extra 4 spaces when formatting `bar()` is overflow_indent.
pub overflow_indent: usize,
pub overflow_indent: Indent,
}
impl<'a> RewriteContext<'a> {
@ -43,12 +44,12 @@ pub fn nested_context(&self) -> RewriteContext<'a> {
RewriteContext {
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent + self.config.tab_spaces,
block_indent: self.block_indent.block_indent(self.config.tab_spaces),
overflow_indent: self.overflow_indent,
}
}
pub fn overflow_context(&self, overflow: usize) -> RewriteContext<'a> {
pub fn overflow_context(&self, overflow: Indent) -> RewriteContext<'a> {
RewriteContext {
codemap: self.codemap,
config: self.config,

View File

@ -13,6 +13,8 @@
use unicode_segmentation::UnicodeSegmentation;
use regex::Regex;
use Indent;
use config::Config;
use utils::{make_indent, round_up_to_power_of_two};
use MIN_STRING;
@ -23,8 +25,9 @@ pub struct StringFormat<'a> {
pub line_start: &'a str,
pub line_end: &'a str,
pub width: usize,
pub offset: usize,
pub offset: Indent,
pub trim_end: bool,
pub config: &'a Config,
}
// TODO: simplify this!
@ -36,7 +39,7 @@ pub fn rewrite_string<'a>(s: &str, fmt: &StringFormat<'a>) -> String {
let graphemes = UnicodeSegmentation::graphemes(&*stripped_str, false).collect::<Vec<&str>>();
let indent = make_indent(fmt.offset);
let indent = make_indent(fmt.offset, fmt.config);
let indent = &indent;
let mut cur_start = 0;

View File

@ -12,12 +12,13 @@
use syntax::print::pprust;
use syntax::codemap::{self, Span, BytePos, CodeMap};
use Indent;
use lists::{itemize_list, write_list, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use utils::{extra_offset, span_after};
impl Rewrite for ast::Path {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
rewrite_path(context, None, self, width, offset)
}
}
@ -27,7 +28,7 @@ pub fn rewrite_path(context: &RewriteContext,
qself: Option<&ast::QSelf>,
path: &ast::Path,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let skip_count = qself.map(|x| x.position).unwrap_or(0);
@ -80,7 +81,7 @@ fn rewrite_path_segments<'a, I>(mut buffer: String,
span_hi: BytePos,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String>
where I: Iterator<Item = &'a ast::PathSegment>
{
@ -128,7 +129,7 @@ fn get_span(&self) -> Span {
impl<'a> Rewrite for SegmentParam<'a> {
// FIXME: doesn't always use width, offset.
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
Some(match *self {
SegmentParam::LifeTime(ref lt) => {
pprust::lifetime_to_string(lt)
@ -186,7 +187,7 @@ fn rewrite_segment(segment: &ast::PathSegment,
span_hi: BytePos,
context: &RewriteContext,
width: usize,
offset: usize)
offset: Indent)
-> Option<String> {
let ident_len = segment.identifier.to_string().len();
let width = try_opt!(width.checked_sub(ident_len));
@ -229,7 +230,7 @@ fn rewrite_segment(segment: &ast::PathSegment,
list_lo,
span_hi);
let fmt = ListFormatting::for_fn(list_width, offset + extra_offset);
let fmt = ListFormatting::for_fn(list_width, offset + extra_offset, context.config);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
// Update position of last bracket.
@ -257,7 +258,7 @@ fn rewrite_segment(segment: &ast::PathSegment,
let budget = try_opt!(width.checked_sub(output.len() + 2));
// 1 for (
let fmt = ListFormatting::for_fn(budget, offset + 1);
let fmt = ListFormatting::for_fn(budget, offset + 1, context.config);
let list_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
format!("({}){}", list_str, output)
@ -269,7 +270,7 @@ fn rewrite_segment(segment: &ast::PathSegment,
}
impl Rewrite for ast::WherePredicate {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
// TODO: dead spans?
// TODO: don't assume we'll always fit on one line...
Some(match *self {
@ -340,7 +341,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
}
impl Rewrite for ast::LifetimeDef {
fn rewrite(&self, _: &RewriteContext, _: usize, _: usize) -> Option<String> {
fn rewrite(&self, _: &RewriteContext, _: usize, _: Indent) -> Option<String> {
if self.bounds.is_empty() {
Some(pprust::lifetime_to_string(&self.lifetime))
} else {
@ -356,7 +357,7 @@ fn rewrite(&self, _: &RewriteContext, _: usize, _: usize) -> Option<String> {
}
impl Rewrite for ast::TyParamBound {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
match *self {
ast::TyParamBound::TraitTyParamBound(ref tref, ast::TraitBoundModifier::None) => {
tref.rewrite(context, width, offset)
@ -372,7 +373,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
}
impl Rewrite for ast::TyParamBounds {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let strs: Vec<_> = self.iter()
.map(|b| b.rewrite(context, width, offset).unwrap())
.collect();
@ -382,7 +383,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
// FIXME: this assumes everything will fit on one line
impl Rewrite for ast::TyParam {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
let mut result = String::with_capacity(128);
result.push_str(&self.ident.to_string());
if !self.bounds.is_empty() {
@ -407,7 +408,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
// FIXME: this assumes everything will fit on one line
impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
if !self.bound_lifetimes.is_empty() {
let lifetime_str = self.bound_lifetimes
.iter()
@ -430,7 +431,7 @@ fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Opti
impl Rewrite for ast::Ty {
// FIXME doesn't always use width, offset
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
match self.node {
ast::TyPath(None, ref p) => {
p.rewrite(context, width, offset)

View File

@ -13,17 +13,19 @@
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_};
use syntax::codemap::{CodeMap, Span, BytePos};
use Indent;
use comment::FindUncommented;
use config::Config;
use rewrite::{Rewrite, RewriteContext};
use SKIP_ANNOTATION;
// Computes the length of a string's last line, minus offset.
#[inline]
pub fn extra_offset(text: &str, offset: usize) -> usize {
pub fn extra_offset(text: &str, offset: Indent) -> usize {
match text.rfind('\n') {
// 1 for newline character
Some(idx) => text.len() - idx - 1 - offset,
Some(idx) => text.len() - idx - 1 - offset.width(),
None => text.len(),
}
}
@ -36,12 +38,8 @@ pub fn span_after(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
}
#[inline]
pub fn make_indent(width: usize) -> String {
let mut indent = String::with_capacity(width);
for _ in 0..width {
indent.push(' ')
}
indent
pub fn make_indent(indent: Indent, config: &Config) -> String {
indent.to_string(config)
}
#[inline]
@ -186,7 +184,7 @@ macro_rules! try_opt {
// Wraps string-like values in an Option. Returns Some when the string adheres
// to the Rewrite constraints defined for the Rewrite trait and else otherwise.
pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usize) -> Option<S> {
pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: Indent) -> Option<S> {
{
let snippet = s.as_ref();
@ -197,7 +195,7 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usi
// The caller of this function has already placed `offset`
// characters on the first line.
let first_line_max_len = try_opt!(max_width.checked_sub(offset));
let first_line_max_len = try_opt!(max_width.checked_sub(offset.width()));
if lines.next().unwrap().len() > first_line_max_len {
return None;
}
@ -211,7 +209,7 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usi
// indentation.
// A special check for the last line, since the caller may
// place trailing characters on this line.
if snippet.lines().rev().next().unwrap().len() > offset + width {
if snippet.lines().rev().next().unwrap().len() > offset.width() + width {
return None;
}
}
@ -221,7 +219,7 @@ pub fn wrap_str<S: AsRef<str>>(s: S, max_width: usize, width: usize, offset: usi
}
impl Rewrite for String {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
wrap_str(self, context.config.max_width, width, offset).map(ToOwned::to_owned)
}
}

View File

@ -14,6 +14,7 @@
use strings::string_buffer::StringBuffer;
use Indent;
use utils;
use config::Config;
use rewrite::{Rewrite, RewriteContext};
@ -25,7 +26,7 @@ pub struct FmtVisitor<'a> {
pub buffer: StringBuffer,
pub last_pos: BytePos,
// TODO: RAII util for indenting
pub block_indent: usize,
pub block_indent: Indent,
pub config: &'a Config,
}
@ -39,7 +40,11 @@ fn visit_expr(&mut self, ex: &'v ast::Expr) {
self.format_missing(ex.span.lo);
let offset = self.buffer.cur_offset();
let rewrite = ex.rewrite(&self.get_context(), self.config.max_width - offset, offset);
// FIXME: We put the entire offset into the block_indent, which might not be correct in all
// situations.
let rewrite = ex.rewrite(&self.get_context(),
self.config.max_width - offset,
Indent::new(offset, 0));
if let Some(new_str) = rewrite {
self.buffer.push_str(&new_str);
@ -56,7 +61,7 @@ fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
}
}
ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
self.format_missing_with_indent(stmt.span.lo);
self.format_missing_with_indent(stmt.span.lo, self.config);
let suffix = if let ast::Stmt_::StmtExpr(..) = stmt.node {
""
} else {
@ -65,7 +70,8 @@ fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
// 1 = trailing semicolon;
let rewrite = ex.rewrite(&self.get_context(),
self.config.max_width - self.block_indent - suffix.len(),
self.config.max_width - self.block_indent.width() -
suffix.len(),
self.block_indent);
if let Some(new_str) = rewrite {
@ -75,7 +81,7 @@ fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
}
}
ast::Stmt_::StmtMac(ref _mac, _macro_style) => {
self.format_missing_with_indent(stmt.span.lo);
self.format_missing_with_indent(stmt.span.lo, self.config);
visit::walk_stmt(self, stmt);
}
}
@ -96,7 +102,7 @@ fn visit_block(&mut self, b: &'v ast::Block) {
};
self.last_pos = self.last_pos + brace_compensation;
self.block_indent += self.config.tab_spaces;
self.block_indent = self.block_indent.block_indent(self.config.tab_spaces);
self.buffer.push_str("{");
for stmt in &b.stmts {
@ -105,15 +111,15 @@ fn visit_block(&mut self, b: &'v ast::Block) {
match b.expr {
Some(ref e) => {
self.format_missing_with_indent(e.span.lo);
self.format_missing_with_indent(e.span.lo, self.config);
self.visit_expr(e);
}
None => {}
}
self.block_indent -= self.config.tab_spaces;
// TODO: we should compress any newlines here to just one.
self.format_missing_with_indent(b.span.hi - brace_compensation);
self.block_indent = self.block_indent.block_unindent(self.config.tab_spaces);
// TODO: we should compress any newlines here to just one
self.format_missing_with_indent(b.span.hi - brace_compensation, self.config);
self.buffer.push_str("}");
self.last_pos = b.span.hi;
}
@ -126,6 +132,7 @@ fn visit_fn(&mut self,
b: &'v ast::Block,
s: Span,
_: ast::NodeId) {
let indent = self.block_indent;
let rewrite = match fk {
visit::FnKind::ItemFn(ident,
@ -161,7 +168,7 @@ fn visit_fn(&mut self,
};
if let Some(fn_str) = rewrite {
self.format_missing_with_indent(s.lo);
self.format_missing_with_indent(s.lo, self.config);
self.buffer.push_str(&fn_str);
} else {
self.format_missing(b.span.lo);
@ -191,31 +198,31 @@ fn visit_item(&mut self, item: &'v ast::Item) {
}
ast::Item_::ItemImpl(..) |
ast::Item_::ItemTrait(..) => {
self.block_indent += self.config.tab_spaces;
self.block_indent = self.block_indent.block_indent(self.config.tab_spaces);
visit::walk_item(self, item);
self.block_indent -= self.config.tab_spaces;
self.block_indent = self.block_indent.block_unindent(self.config.tab_spaces);
}
ast::Item_::ItemExternCrate(_) => {
self.format_missing_with_indent(item.span.lo);
self.format_missing_with_indent(item.span.lo, self.config);
let new_str = self.snippet(item.span);
self.buffer.push_str(&new_str);
self.last_pos = item.span.hi;
}
ast::Item_::ItemStruct(ref def, ref generics) => {
self.format_missing_with_indent(item.span.lo);
self.format_missing_with_indent(item.span.lo, self.config);
self.visit_struct(item.ident, item.vis, def, generics, item.span);
}
ast::Item_::ItemEnum(ref def, ref generics) => {
self.format_missing_with_indent(item.span.lo);
self.format_missing_with_indent(item.span.lo, self.config);
self.visit_enum(item.ident, item.vis, def, generics, item.span);
self.last_pos = item.span.hi;
}
ast::Item_::ItemMod(ref module) => {
self.format_missing_with_indent(item.span.lo);
self.format_missing_with_indent(item.span.lo, self.config);
self.format_mod(module, item.span, item.ident);
}
ast::Item_::ItemMac(..) => {
self.format_missing_with_indent(item.span.lo);
self.format_missing_with_indent(item.span.lo, self.config);
// TODO: we cannot format these yet, because of a bad span.
// See rust lang issue #28424.
// visit::walk_item(self, item);
@ -232,7 +239,7 @@ fn visit_trait_item(&mut self, ti: &'v ast::TraitItem) {
}
if let ast::TraitItem_::MethodTraitItem(ref sig, None) = ti.node {
self.format_missing_with_indent(ti.span.lo);
self.format_missing_with_indent(ti.span.lo, self.config);
let indent = self.block_indent;
let new_fn = self.rewrite_required_fn(indent, ti.ident, sig, ti.span);
@ -256,7 +263,7 @@ fn visit_impl_item(&mut self, ii: &'v ast::ImplItem) {
fn visit_mac(&mut self, mac: &'v ast::Mac) {
// 1 = ;
let width = self.config.max_width - self.block_indent - 1;
let width = self.config.max_width - self.block_indent.width() - 1;
let rewrite = rewrite_macro(mac, &self.get_context(), width, self.block_indent);
if let Some(res) = rewrite {
@ -272,7 +279,7 @@ pub fn from_codemap<'b>(codemap: &'b CodeMap, config: &'b Config) -> FmtVisitor<
codemap: codemap,
buffer: StringBuffer::new(),
last_pos: BytePos(0),
block_indent: 0,
block_indent: Indent { block_indent: 0, alignment: 0 },
config: config,
}
}
@ -296,13 +303,13 @@ pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
}
let first = &attrs[0];
self.format_missing_with_indent(first.span.lo);
self.format_missing_with_indent(first.span.lo, self.config);
if utils::contains_skip(attrs) {
true
} else {
let rewrite = attrs.rewrite(&self.get_context(),
self.config.max_width - self.block_indent,
self.config.max_width - self.block_indent.width(),
self.block_indent)
.unwrap();
self.buffer.push_str(&rewrite);
@ -323,32 +330,33 @@ fn format_mod(&mut self, m: &ast::Mod, s: Span, ident: ast::Ident) {
if is_internal {
debug!("FmtVisitor::format_mod: internal mod");
self.block_indent += self.config.tab_spaces;
self.block_indent = self.block_indent.block_indent(self.config.tab_spaces);
visit::walk_mod(self, m);
debug!("... last_pos after: {:?}", self.last_pos);
self.block_indent -= self.config.tab_spaces;
self.block_indent = self.block_indent.block_unindent(self.config.tab_spaces);
}
}
pub fn format_separate_mod(&mut self, m: &ast::Mod, filename: &str) {
let filemap = self.codemap.get_filemap(filename);
self.last_pos = filemap.start_pos;
self.block_indent = 0;
self.block_indent = Indent::new(0, 0);
visit::walk_mod(self, m);
self.format_missing(filemap.end_pos);
}
fn format_import(&mut self, vis: ast::Visibility, vp: &ast::ViewPath, span: Span) {
let vis = utils::format_visibility(vis);
let offset = self.block_indent + vis.len() + "use ".len();
let mut offset = self.block_indent;
offset.alignment += vis.len() + "use ".len();
let context = RewriteContext {
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent,
overflow_indent: 0,
overflow_indent: Indent::new(0, 0),
};
// 1 = ";"
match vp.rewrite(&context, self.config.max_width - offset - 1, offset) {
match vp.rewrite(&context, self.config.max_width - offset.width() - 1, offset) {
Some(ref s) if s.is_empty() => {
// Format up to last newline
let prev_span = codemap::mk_sp(self.last_pos, span.lo);
@ -361,12 +369,12 @@ fn format_import(&mut self, vis: ast::Visibility, vp: &ast::ViewPath, span: Span
}
Some(ref s) => {
let s = format!("{}use {};", vis, s);
self.format_missing_with_indent(span.lo);
self.format_missing_with_indent(span.lo, self.config);
self.buffer.push_str(&s);
self.last_pos = span.hi;
}
None => {
self.format_missing_with_indent(span.lo);
self.format_missing_with_indent(span.lo, self.config);
self.format_missing(span.hi);
}
}
@ -377,18 +385,18 @@ pub fn get_context(&self) -> RewriteContext {
codemap: self.codemap,
config: self.config,
block_indent: self.block_indent,
overflow_indent: 0,
overflow_indent: Indent::new(0, 0),
}
}
}
impl<'a> Rewrite for [ast::Attribute] {
fn rewrite(&self, context: &RewriteContext, _: usize, offset: usize) -> Option<String> {
fn rewrite(&self, context: &RewriteContext, _: usize, offset: Indent) -> Option<String> {
let mut result = String::new();
if self.is_empty() {
return Some(result);
}
let indent = utils::make_indent(offset);
let indent = utils::make_indent(offset, context.config);
for (i, a) in self.iter().enumerate() {
let a_str = context.snippet(a.span);
@ -403,8 +411,9 @@ fn rewrite(&self, context: &RewriteContext, _: usize, offset: usize) -> Option<S
if !comment.is_empty() {
let comment = rewrite_comment(comment,
false,
context.config.max_width - offset,
offset);
context.config.max_width - offset.width(),
offset,
context.config);
result.push_str(&indent);
result.push_str(&comment);
result.push('\n');