Merge pull request #290 from SiegeLord/tabs
Initial implementation of hard tab indentation.
This commit is contained in:
commit
ce2c4f6be6
@ -19,8 +19,9 @@
|
||||
// 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 utils::first_line_width;
|
||||
use expr::rewrite_call;
|
||||
|
||||
use syntax::{ast, ptr};
|
||||
@ -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{}", indent.to_string(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()
|
||||
|
@ -12,10 +12,16 @@
|
||||
|
||||
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 +39,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 = offset.to_string(config);
|
||||
let line_breaks = s.chars().filter(|&c| c == '\n').count();
|
||||
|
||||
let (_, mut s) = s.lines()
|
||||
@ -288,27 +295,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::empty(), &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
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
135
src/expr.rs
135
src/expr.rs
@ -11,11 +11,11 @@
|
||||
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};
|
||||
use utils::{span_after, make_indent, extra_offset, first_line_width, last_line_width, wrap_str,
|
||||
binary_search};
|
||||
use utils::{span_after, extra_offset, first_line_width, last_line_width, wrap_str, binary_search};
|
||||
use visitor::FmtVisitor;
|
||||
use config::{StructLitStyle, MultilineStyle};
|
||||
use comment::{FindUncommented, rewrite_comment, contains_comment};
|
||||
@ -29,7 +29,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 +164,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 +201,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 +216,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 +259,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 +267,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(&argument_offset.to_string(context.config));
|
||||
} else {
|
||||
prefix.push(' ');
|
||||
}
|
||||
@ -308,18 +310,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::empty()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| body.rewrite(&context, 2, 0));
|
||||
.unwrap_or_else(|| body.rewrite(&context, 2, Indent::empty()));
|
||||
|
||||
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 +343,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 +384,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 +450,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 +486,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 +516,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 +591,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::empty()));
|
||||
|
||||
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::empty()));
|
||||
|
||||
// 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 +624,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 +637,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 = arm_indent.to_string(context.config);
|
||||
|
||||
let open_brace_pos = span_after(mk_sp(cond.span.hi, arm_start_pos(&arms[0])),
|
||||
"{",
|
||||
@ -669,7 +672,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 +687,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(&(context.block_indent + context.overflow_indent).to_string(context.config));
|
||||
result.push('}');
|
||||
Some(result)
|
||||
}
|
||||
@ -704,9 +707,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 = offset.to_string(context.config);
|
||||
|
||||
// FIXME this is all a bit grotty, would be nice to abstract out the
|
||||
// treatment of attributes.
|
||||
@ -734,7 +737,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))
|
||||
})
|
||||
.collect::<Option<Vec<_>>>());
|
||||
|
||||
@ -775,7 +778,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);
|
||||
}
|
||||
|
||||
let comma = if let ast::ExprBlock(_) = body.node {
|
||||
@ -788,7 +796,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 +818,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),
|
||||
offset.block_indent(context.config).to_string(context.config),
|
||||
body_str))
|
||||
}
|
||||
}
|
||||
@ -819,7 +827,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 +848,10 @@ 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));
|
||||
if let Some(cond_str) = cond_str {
|
||||
return Some(format!("\n{}if {}",
|
||||
make_indent(offset + context.config.tab_spaces),
|
||||
offset.block_indent(context.config).to_string(context.config),
|
||||
cond_str));
|
||||
}
|
||||
}
|
||||
@ -862,7 +870,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 +906,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(&pat_offset.to_string(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 +919,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 +933,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 +947,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 +966,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 +1014,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 +1026,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 +1042,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 +1065,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);
|
||||
let v_budget = context.config.max_width.checked_sub(indent.width()).unwrap_or(0);
|
||||
(indent, v_budget)
|
||||
}
|
||||
};
|
||||
@ -1121,12 +1132,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 = context.block_indent
|
||||
.block_indent(context.config)
|
||||
.to_string(context.config);
|
||||
let outer_indent = context.block_indent.to_string(context.config);
|
||||
Some(format!("{} {{\n{}{}\n{}}}", path_str, inner_indent, fields_str, outer_indent))
|
||||
};
|
||||
|
||||
@ -1143,7 +1157,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 +1170,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 +1187,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 +1195,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 +1206,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 +1247,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),
|
||||
offset.to_string(context.config),
|
||||
rhs_result))
|
||||
}
|
||||
|
||||
@ -1245,7 +1261,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 +1281,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 +1301,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 +1317,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);
|
||||
result.push_str(&format!("\n{}", new_offset.to_string(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));
|
||||
|
@ -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 = {
|
||||
|
130
src/items.rs
130
src/items.rs
@ -10,8 +10,8 @@
|
||||
|
||||
// Formatting top-level items - functions, structs, enums, traits, impls.
|
||||
|
||||
use utils::{format_mutability, format_visibility, make_indent, contains_skip, span_after,
|
||||
end_typaram, wrap_str};
|
||||
use Indent;
|
||||
use utils::{format_mutability, format_visibility, contains_skip, span_after, end_typaram, wrap_str};
|
||||
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
|
||||
use expr::rewrite_assign_rhs;
|
||||
use comment::FindUncommented;
|
||||
@ -34,8 +34,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::empty()).unwrap());
|
||||
}
|
||||
|
||||
if local.init.is_some() {
|
||||
@ -52,12 +51,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 +65,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 +89,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 +125,7 @@ pub fn rewrite_fn(&mut self,
|
||||
// this.
|
||||
if newline_brace {
|
||||
result.push('\n');
|
||||
result.push_str(&make_indent(indent));
|
||||
result.push_str(&indent.to_string(self.config));
|
||||
} else {
|
||||
result.push(' ');
|
||||
}
|
||||
@ -133,7 +134,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 +161,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 +208,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 +225,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(&arg_indent.to_string(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(&arg_indent.to_string(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);
|
||||
result.push_str("(\n");
|
||||
result.push_str(&make_indent(arg_indent));
|
||||
result.push_str(&arg_indent.to_string(self.config));
|
||||
} else {
|
||||
result.push('(');
|
||||
}
|
||||
@ -266,7 +269,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 +280,7 @@ fn rewrite_fn_base(&mut self,
|
||||
};
|
||||
|
||||
result.push('\n');
|
||||
result.push_str(&make_indent(indent));
|
||||
result.push_str(&indent.to_string(self.config));
|
||||
} else {
|
||||
result.push(' ');
|
||||
}
|
||||
@ -326,8 +329,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 +389,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),
|
||||
BlockIndentStyle::Visual => arg_indent,
|
||||
};
|
||||
|
||||
@ -398,6 +401,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 +409,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 +429,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 +443,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);
|
||||
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 +479,13 @@ 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),
|
||||
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);
|
||||
for (i, f) in enum_def.variants.iter().enumerate() {
|
||||
let next_span_start: BytePos = if i == enum_def.variants.len() - 1 {
|
||||
span.hi
|
||||
@ -491,7 +495,7 @@ 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);
|
||||
|
||||
self.format_missing_with_indent(span.lo + BytePos(enum_snippet.rfind('}').unwrap() as u32));
|
||||
self.buffer.push_str("}");
|
||||
@ -521,7 +525,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::empty())
|
||||
.unwrap()
|
||||
},
|
||||
span_after(field.span, "(", self.codemap),
|
||||
@ -536,7 +542,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 +552,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 +608,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 +661,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 +669,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 = offset.block_indent(self.config).to_string(self.config);
|
||||
result.push('\n');
|
||||
result.push_str(&indentation);
|
||||
|
||||
@ -672,15 +679,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),
|
||||
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 +696,7 @@ fn format_struct(&self,
|
||||
|
||||
if break_line {
|
||||
result.push('\n');
|
||||
result.push_str(&make_indent(offset));
|
||||
result.push_str(&offset.to_string(self.config));
|
||||
}
|
||||
|
||||
result.push_str(terminator);
|
||||
@ -727,8 +735,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 +748,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(&self.block_indent.to_string(self.config));
|
||||
result.push('\n');
|
||||
result.push_str(opener.trim());
|
||||
} else {
|
||||
@ -765,18 +773,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::empty()).unwrap();
|
||||
|
||||
let indent = self.block_indent + self.config.tab_spaces;
|
||||
let indent = self.block_indent.block_indent(self.config);
|
||||
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(&indent.to_string(self.config));
|
||||
}
|
||||
|
||||
match name {
|
||||
@ -787,8 +795,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 +809,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),
|
||||
// 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 +849,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 +858,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 +867,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::empty(),
|
||||
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),
|
||||
// 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 +905,14 @@ 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 {}", (indent + extra_indent).to_string(self.config), preds_str))
|
||||
} else {
|
||||
Some(format!(" where {}", preds_str))
|
||||
}
|
||||
@ -910,7 +920,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 +939,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)
|
||||
|
78
src/lib.rs
78
src/lib.rs
@ -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,83 @@
|
||||
// When we get scoped annotations, we should have rustfmt::skip.
|
||||
const SKIP_ANNOTATION: &'static str = "rustfmt_skip";
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Indent {
|
||||
// Width of the block indent, in characters. Must be a multiple of
|
||||
// Config::tab_spaces.
|
||||
block_indent: usize,
|
||||
// Alignment in characters.
|
||||
alignment: usize,
|
||||
}
|
||||
|
||||
impl Indent {
|
||||
pub fn new(block_indent: usize, alignment: usize) -> Indent {
|
||||
Indent { block_indent: block_indent, alignment: alignment }
|
||||
}
|
||||
|
||||
pub fn empty() -> Indent {
|
||||
Indent::new(0, 0)
|
||||
}
|
||||
|
||||
pub fn block_indent(mut self, config: &Config) -> Indent {
|
||||
self.block_indent += config.tab_spaces;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn block_unindent(mut self, config: &Config) -> Indent {
|
||||
self.block_indent -= config.tab_spaces;
|
||||
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::new(self.block_indent - rhs.block_indent, self.alignment - rhs.alignment)
|
||||
}
|
||||
}
|
||||
|
||||
impl Add<usize> for Indent {
|
||||
type Output = Indent;
|
||||
|
||||
fn add(self, rhs: usize) -> Indent {
|
||||
Indent::new(self.block_indent, self.alignment + rhs)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum WriteMode {
|
||||
// Backups the original file and overwrites the orignal.
|
||||
|
34
src/lists.rs
34
src/lists.rs
@ -13,8 +13,10 @@
|
||||
|
||||
use syntax::codemap::{self, CodeMap, BytePos};
|
||||
|
||||
use utils::{round_up_to_power_of_two, make_indent, wrap_str};
|
||||
use Indent;
|
||||
use utils::{round_up_to_power_of_two, 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 = &formatting.indent.to_string(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::empty(),
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -8,7 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use utils::make_indent;
|
||||
use visitor::FmtVisitor;
|
||||
|
||||
use syntax::codemap::{self, BytePos};
|
||||
@ -21,14 +20,15 @@ pub fn format_missing(&mut self, end: BytePos) {
|
||||
}
|
||||
|
||||
pub fn format_missing_with_indent(&mut self, end: BytePos) {
|
||||
let config = self.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 = this.block_indent.to_string(config);
|
||||
this.buffer.push_str(&indent);
|
||||
})
|
||||
}
|
||||
|
@ -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),
|
||||
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,
|
||||
|
@ -13,7 +13,9 @@
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use regex::Regex;
|
||||
|
||||
use utils::{make_indent, round_up_to_power_of_two};
|
||||
use Indent;
|
||||
use config::Config;
|
||||
use utils::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 = fmt.offset.to_string(fmt.config);
|
||||
let indent = &indent;
|
||||
|
||||
let mut cur_start = 0;
|
||||
|
29
src/types.rs
29
src/types.rs
@ -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)
|
||||
|
22
src/utils.rs
22
src/utils.rs
@ -13,6 +13,7 @@
|
||||
use syntax::ast::{self, Visibility, Attribute, MetaItem, MetaItem_};
|
||||
use syntax::codemap::{CodeMap, Span, BytePos};
|
||||
|
||||
use Indent;
|
||||
use comment::FindUncommented;
|
||||
use rewrite::{Rewrite, RewriteContext};
|
||||
|
||||
@ -20,10 +21,10 @@
|
||||
|
||||
// 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(),
|
||||
}
|
||||
}
|
||||
@ -35,15 +36,6 @@ pub fn span_after(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
|
||||
original.lo + BytePos(snippet.find_uncommented(needle).unwrap() as u32 + 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn make_indent(width: usize) -> String {
|
||||
let mut indent = String::with_capacity(width);
|
||||
for _ in 0..width {
|
||||
indent.push(' ')
|
||||
}
|
||||
indent
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn format_visibility(vis: Visibility) -> &'static str {
|
||||
match vis {
|
||||
@ -186,7 +178,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 +189,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 +203,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 +213,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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
@ -38,8 +39,9 @@ fn visit_expr(&mut self, ex: &'v ast::Expr) {
|
||||
self.codemap.lookup_char_pos(ex.span.hi));
|
||||
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);
|
||||
let rewrite = ex.rewrite(&self.get_context(),
|
||||
self.config.max_width - self.block_indent.width(),
|
||||
self.block_indent);
|
||||
|
||||
if let Some(new_str) = rewrite {
|
||||
self.buffer.push_str(&new_str);
|
||||
@ -65,7 +67,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 {
|
||||
@ -96,7 +99,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);
|
||||
self.buffer.push_str("{");
|
||||
|
||||
for stmt in &b.stmts {
|
||||
@ -111,8 +114,8 @@ fn visit_block(&mut self, b: &'v ast::Block) {
|
||||
None => {}
|
||||
}
|
||||
|
||||
self.block_indent -= self.config.tab_spaces;
|
||||
// TODO: we should compress any newlines here to just one.
|
||||
self.block_indent = self.block_indent.block_unindent(self.config);
|
||||
// TODO: we should compress any newlines here to just one
|
||||
self.format_missing_with_indent(b.span.hi - brace_compensation);
|
||||
self.buffer.push_str("}");
|
||||
self.last_pos = b.span.hi;
|
||||
@ -126,6 +129,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,
|
||||
@ -191,9 +195,9 @@ 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);
|
||||
visit::walk_item(self, item);
|
||||
self.block_indent -= self.config.tab_spaces;
|
||||
self.block_indent = self.block_indent.block_unindent(self.config);
|
||||
}
|
||||
ast::Item_::ItemExternCrate(_) => {
|
||||
self.format_missing_with_indent(item.span.lo);
|
||||
@ -256,7 +260,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 +276,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,
|
||||
}
|
||||
}
|
||||
@ -302,7 +306,7 @@ pub fn visit_attrs(&mut self, attrs: &[ast::Attribute]) -> bool {
|
||||
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 +327,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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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::empty();
|
||||
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::empty(),
|
||||
};
|
||||
// 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);
|
||||
@ -377,18 +382,18 @@ pub fn get_context(&self) -> RewriteContext {
|
||||
codemap: self.codemap,
|
||||
config: self.config,
|
||||
block_indent: self.block_indent,
|
||||
overflow_indent: 0,
|
||||
overflow_indent: Indent::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = offset.to_string(context.config);
|
||||
|
||||
for (i, a) in self.iter().enumerate() {
|
||||
let a_str = context.snippet(a.span);
|
||||
@ -403,8 +408,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');
|
||||
|
69
tests/source/hard-tabs.rs
Normal file
69
tests/source/hard-tabs.rs
Normal file
@ -0,0 +1,69 @@
|
||||
// rustfmt-hard_tabs: true
|
||||
|
||||
fn main() {
|
||||
let x = Bar;
|
||||
|
||||
let y = Foo {a: x };
|
||||
|
||||
Foo { a: foo() /* comment*/, /* comment*/ b: bar(), ..something };
|
||||
|
||||
fn foo(a: i32, a: i32, a: i32, a: i32, a: i32, a: i32, a: i32, a: i32, a: i32, a: i32, a: i32) {}
|
||||
|
||||
let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAa";
|
||||
|
||||
if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1
|
||||
+ 2 + 3 {
|
||||
}
|
||||
|
||||
if cond() {
|
||||
something();
|
||||
} else if different_cond() {
|
||||
something_else();
|
||||
} else {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}
|
||||
|
||||
unsafe /* very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong comment */ {}
|
||||
|
||||
unsafe // So this is a very long comment.
|
||||
// Multi-line, too.
|
||||
// Will it still format correctly?
|
||||
{
|
||||
}
|
||||
|
||||
let z = [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz, q];
|
||||
|
||||
fn generic<T>(arg: T) -> &SomeType
|
||||
where T: Fn(// First arg
|
||||
A,
|
||||
// Second argument
|
||||
B, C, D, /* pre comment */ E /* last comment */) -> &SomeType {
|
||||
arg(a, b, c, d, e)
|
||||
}
|
||||
|
||||
loong_func().quux(move || {
|
||||
if true {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
});
|
||||
|
||||
fffffffffffffffffffffffffffffffffff(a,
|
||||
{
|
||||
SCRIPT_TASK_ROOT
|
||||
.with(|root| {
|
||||
*root.borrow_mut() = Some(&script_task);
|
||||
});
|
||||
});
|
||||
a.b
|
||||
.c
|
||||
.d();
|
||||
|
||||
x().y(|| {
|
||||
match cond() {
|
||||
true => (),
|
||||
false => (),
|
||||
}
|
||||
});
|
||||
}
|
95
tests/target/hard-tabs.rs
Normal file
95
tests/target/hard-tabs.rs
Normal file
@ -0,0 +1,95 @@
|
||||
// rustfmt-hard_tabs: true
|
||||
|
||||
fn main() {
|
||||
let x = Bar;
|
||||
|
||||
let y = Foo { a: x };
|
||||
|
||||
Foo {
|
||||
a: foo(), // comment
|
||||
// comment
|
||||
b: bar(),
|
||||
..something
|
||||
};
|
||||
|
||||
fn foo(a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32,
|
||||
a: i32) {
|
||||
}
|
||||
|
||||
let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAA\
|
||||
AAAAAAAAAAAAaAa";
|
||||
|
||||
if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) =
|
||||
1 + 2 + 3 {
|
||||
}
|
||||
|
||||
if cond() {
|
||||
something();
|
||||
} else if different_cond() {
|
||||
something_else();
|
||||
} else {
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}
|
||||
|
||||
unsafe /* very looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
|
||||
* comment */ {
|
||||
}
|
||||
|
||||
unsafe /* So this is a very long comment.
|
||||
* Multi-line, too.
|
||||
* Will it still format correctly? */ {
|
||||
}
|
||||
|
||||
let z = [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
|
||||
yyyyyyyyyyyyyyyyyyyyyyyyyyy,
|
||||
zzzzzzzzzzzzzzzzzz,
|
||||
q];
|
||||
|
||||
fn generic<T>(arg: T) -> &SomeType
|
||||
where T: Fn(// First arg
|
||||
A,
|
||||
// Second argument
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
// pre comment
|
||||
E /* last comment */) -> &SomeType
|
||||
{
|
||||
arg(a, b, c, d, e)
|
||||
}
|
||||
|
||||
loong_func().quux(move || {
|
||||
if true {
|
||||
1
|
||||
} else {
|
||||
2
|
||||
}
|
||||
});
|
||||
|
||||
fffffffffffffffffffffffffffffffffff(a,
|
||||
{
|
||||
SCRIPT_TASK_ROOT.with(|root| {
|
||||
*root.borrow_mut() = Some(&script_task);
|
||||
});
|
||||
});
|
||||
a.b
|
||||
.c
|
||||
.d();
|
||||
|
||||
x().y(|| {
|
||||
match cond() {
|
||||
true => (),
|
||||
false => (),
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user