let input = "// comment";
let expected = "/* com\n \
- * men\n * \
- t */";
+ * men\n \
+ * t */";
assert_eq!(expected, rewrite_comment(input, true, 9, 69));
assert_eq!("/* trimmed */", rewrite_comment("/* trimmed */", true, 100, 100));
}
-
pub trait FindUncommented {
fn find_uncommented(&self, pat: &str) -> Option<usize>;
}
ast::Expr_::ExprPath(ref qself, ref path) => {
rewrite_path(context, qself.as_ref(), path, width, offset)
}
+ ast::Expr_::ExprAssign(ref lhs, ref rhs) => {
+ rewrite_assignment(context, lhs, rhs, None, width, offset)
+ }
+ ast::Expr_::ExprAssignOp(ref op, ref lhs, ref rhs) => {
+ rewrite_assignment(context, lhs, rhs, Some(op), width, offset)
+ }
// FIXME #184 Note that this formatting is broken due to a bad span
// from the parser.
// `continue`
};
Some(format!("continue{}", id_str))
}
+ ast::Expr_::ExprBreak(ref opt_ident) => {
+ let id_str = match *opt_ident {
+ Some(ident) => format!(" {}", ident),
+ None => String::new(),
+ };
+ Some(format!("break{}", id_str))
+ }
ast::Expr_::ExprClosure(capture, ref fn_decl, ref body) => {
rewrite_closure(capture, fn_decl, body, self.span, context, width, offset)
}
- _ => context.codemap.span_to_snippet(self.span).ok(),
+ _ => {
+ // We do not format these expressions yet, but they should still
+ // satisfy our width restrictions.
+ let snippet = context.codemap.span_to_snippet(self.span).unwrap();
+
+ {
+ let mut lines = snippet.lines();
+
+ // The caller of this function has already placed `offset`
+ // characters on the first line.
+ let first_line_max_len = try_opt!(context.config.max_width.checked_sub(offset));
+ if lines.next().unwrap().len() > first_line_max_len {
+ return None;
+ }
+
+ // The other lines must fit within the maximum width.
+ if lines.find(|line| line.len() > context.config.max_width).is_some() {
+ return None;
+ }
+
+ // `width` is the maximum length of the last line, excluding
+ // 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 {
+ return None;
+ }
+ }
+
+ Some(snippet)
+ }
}
}
}
width: usize,
offset: usize)
-> Option<String> {
- if arms.len() == 0 {
+ if arms.is_empty() {
return None;
}
result.push('\n');
}
let missed_str = missed_str.trim();
- if missed_str.len() > 0 {
+ if !missed_str.is_empty() {
result.push('\n');
result.push_str(&arm_indent_str);
result.push_str(missed_str);
fn arm_start_pos(arm: &ast::Arm) -> BytePos {
let &ast::Arm { ref attrs, ref pats, .. } = arm;
- if attrs.len() > 0 {
+ if !attrs.is_empty() {
return attrs[0].span.lo
}
// FIXME this is all a bit grotty, would be nice to abstract out the
// treatment of attributes.
- let attr_str = if attrs.len() > 0 {
+ let attr_str = if !attrs.is_empty() {
// We only use this visitor for the attributes, should we use it for
// more?
let mut attr_visitor = FmtVisitor::from_codemap(context.codemap, context.config);
let mut pats_str = String::new();
for p in pat_strs {
- if pats_str.len() > 0 {
+ if !pats_str.is_empty() {
if vertical {
pats_str.push_str(" |\n");
pats_str.push_str(&indent_str);
}
// We have to push the body to the next line.
- if comma.len() == 0 {
+ if comma.is_empty() {
// We're trying to fit a block in, but it still failed, give up.
return None;
}
pat: Option<&ast::Pat>,
expr: &ast::Expr,
matcher: &str,
+ // Connecting piece between pattern and expression,
+ // *without* trailing space.
connector: &str,
width: usize,
offset: usize)
// The expression may (partionally) fit on the current line.
if width > extra_offset + 1 {
- let mut corrected_offset = extra_offset;
-
- if pat.is_some() {
- result.push(' ');
- corrected_offset += 1;
- }
+ let spacer = if pat.is_some() {
+ " "
+ } else {
+ ""
+ };
let expr_rewrite = expr.rewrite(context,
- width - corrected_offset,
- offset + corrected_offset);
+ width - extra_offset - spacer.len(),
+ offset + extra_offset + spacer.len());
if let Some(expr_string) = expr_rewrite {
+ result.push_str(spacer);
result.push_str(&expr_string);
return Some(result);
}
let path_str = try_opt!(path.rewrite(context, width - 2, offset));
// Foo { a: Foo } - indent is +3, width is -5.
- let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0);
+ let h_budget = try_opt!(width.checked_sub(path_str.len() + 5));
let (indent, v_budget) = match context.config.struct_lit_style {
StructLitStyle::VisualIndent => {
(offset + path_str.len() + 3, h_budget)
ast::UnOp::UnNeg => "-",
};
- let subexpr = try_opt!(expr.rewrite(context, try_opt!(width.checked_sub(operator_str.len())), offset));
+ let subexpr =
+ try_opt!(expr.rewrite(context, try_opt!(width.checked_sub(operator_str.len())), offset));
Some(format!("{}{}", operator_str, subexpr))
}
+
+fn rewrite_assignment(context: &RewriteContext,
+ lhs: &ast::Expr,
+ rhs: &ast::Expr,
+ op: Option<&ast::BinOp>,
+ width: usize,
+ offset: usize)
+ -> Option<String> {
+ let operator_str = match op {
+ Some(op) => context.codemap.span_to_snippet(op.span).unwrap(),
+ None => "=".to_owned(),
+ };
+
+ // 1 = space between lhs and operator.
+ let max_width = try_opt!(width.checked_sub(operator_str.len() + 1));
+ let lhs_str = format!("{} {}", try_opt!(lhs.rewrite(context, max_width, offset)), operator_str);
+
+ rewrite_assign_rhs(&context, lhs_str, rhs, width, offset)
+}
+
+// The left hand side must contain everything up to, and including, the
+// assignment operator.
+pub fn rewrite_assign_rhs<S: Into<String>>(context: &RewriteContext,
+ lhs: S,
+ ex: &ast::Expr,
+ width: usize,
+ offset: usize)
+ -> Option<String> {
+ let mut result = lhs.into();
+
+ // 1 = space between operator and rhs.
+ let max_width = try_opt!(width.checked_sub(result.len() + 1));
+ let rhs = ex.rewrite(&context, max_width, offset + result.len() + 1);
+
+ match rhs {
+ Some(new_str) => {
+ result.push(' ');
+ result.push_str(&new_str)
+ }
+ 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 max_width = try_opt!(context.config.max_width.checked_sub(new_offset + 1));
+ let rhs = try_opt!(ex.rewrite(&context, max_width, new_offset));
+
+ result.push_str(&rhs);
+ }
+ }
+
+ Some(result)
+}
NumberPart::CloseParen => {}
}
- self.state = Seeking::Number {
- part: part,
- issue: issue
- };
+ self.state = Seeking::Number { part: part, issue: issue };
IssueClassification::None
}
use utils::{format_mutability, format_visibility, make_indent, contains_skip, span_after,
end_typaram};
use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, ListTactic};
+use expr::rewrite_assign_rhs;
use comment::FindUncommented;
use visitor::FmtVisitor;
+
use rewrite::Rewrite;
use config::Config;
use syntax::parse::token;
impl<'a> FmtVisitor<'a> {
+ pub fn visit_let(&mut self, local: &ast::Local, span: Span) {
+ self.format_missing_with_indent(span.lo);
+
+ // String that is placed within the assignment pattern and expression.
+ let infix = {
+ let mut infix = String::new();
+
+ if let Some(ref ty) = local.ty {
+ infix.push_str(": ");
+ infix.push_str(&pprust::ty_to_string(ty));
+ }
+
+ if local.init.is_some() {
+ infix.push_str(" =");
+ }
+
+ infix
+ };
+
+ // New scope so we drop the borrow of self (context) in time to mutably
+ // borrow self to mutate its buffer.
+ let result = {
+ let context = self.get_context();
+ 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) {
+ Some(width) => width,
+ None => return,
+ };
+
+ match local.pat.rewrite(&context, pattern_offset, pattern_width) {
+ Some(ref pat_string) => result.push_str(pat_string),
+ None => return,
+ }
+
+ 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) {
+ Some(width) => width,
+ None => return,
+ };
+
+ // 1 = trailing semicolon;
+ let rhs = rewrite_assign_rhs(&context, result, ex, max_width, context.block_indent);
+
+ match rhs {
+ Some(result) => result,
+ None => return,
+ }
+ } else {
+ result
+ }
+ };
+
+ self.buffer.push_str(&result);
+ self.buffer.push_str(";");
+ self.last_pos = span.hi;
+ }
+
pub fn rewrite_fn(&mut self,
indent: usize,
ident: ast::Ident,
span,
newline_brace);
- // Prepare for the function body by possibly adding a newline and indent.
- // FIXME we'll miss anything between the end of the signature and the start
- // of the body, but we need more spans from the compiler to solve this.
+ // Prepare for the function body by possibly adding a newline and
+ // indent.
+ // FIXME we'll miss anything between the end of the signature and the
+ // start of the body, but we need more spans from the compiler to solve
+ // this.
if newline_brace {
result.push('\n');
result.push_str(&make_indent(indent));
// this hacky solution caused by absence of `Mutability` in `SelfValue`.
let mut_str = {
- if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _) = args[0].pat.node {
+ if let ast::Pat_::PatIdent(ast::BindingMode::BindByValue(mutability), _, _) =
+ args[0].pat.node {
format_mutability(mutability)
} else {
panic!("there is a bug or change in structure of AST, aborting.");
panic!("No input supplied to RustFmt");
}
+ #[rustfmt_skip]
+ // FIXME(#195): closure is formatted poorly.
fn build_controller(&mut self, _: &Session) -> driver::CompileController<'a> {
let write_mode = self.write_mode;
let mut tactic = formatting.tactic;
// Conservatively overestimates because of the changing separator tactic.
- let sep_count = if formatting.trailing_separator != SeparatorTactic::Never {
+ let sep_count = if formatting.trailing_separator == SeparatorTactic::Always {
items.len()
} else {
items.len() - 1
if tactic == ListTactic::HorizontalVertical {
debug!("write_list: total_width: {}, total_sep_len: {}, h_width: {}",
total_width, total_sep_len, formatting.h_width);
- tactic = if fits_single &&
- !items.iter().any(ListItem::is_multiline) {
+ tactic = if fits_single && !items.iter().any(ListItem::is_multiline) {
ListTactic::Horizontal
} else {
ListTactic::Vertical
// Pre-comments
if let Some(ref comment) = item.pre_comment {
- result.push_str(&rewrite_comment(comment,
- // Block style in non-vertical mode
- tactic != ListTactic::Vertical,
- // Width restriction is only
- // relevant in vertical mode.
- formatting.v_width,
- formatting.indent));
+ // Block style in non-vertical mode.
+ 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));
if tactic == ListTactic::Vertical {
result.push('\n');
}
impl<'a, 'v> visit::Visitor<'v> for FmtVisitor<'a> {
+ // FIXME: We'd rather not format expressions here, as we have little
+ // context. How are we still reaching this?
fn visit_expr(&mut self, ex: &'v ast::Expr) {
debug!("visit_expr: {:?} {:?}",
self.codemap.lookup_char_pos(ex.span.lo),
}
fn visit_stmt(&mut self, stmt: &'v ast::Stmt) {
- // If the stmt is actually an item, then we'll handle any missing spans
- // there. This is important because of annotations.
- // Although it might make more sense for the statement span to include
- // any annotations on the item.
- let skip_missing = match stmt.node {
+ match stmt.node {
ast::Stmt_::StmtDecl(ref decl, _) => {
- match decl.node {
- ast::Decl_::DeclItem(_) => true,
- _ => false,
+ return match decl.node {
+ ast::Decl_::DeclLocal(ref local) => self.visit_let(local, stmt.span),
+ ast::Decl_::DeclItem(..) => visit::walk_stmt(self, stmt),
+ };
+ }
+ ast::Stmt_::StmtExpr(ref ex, _) | ast::Stmt_::StmtSemi(ref ex, _) => {
+ self.format_missing_with_indent(stmt.span.lo);
+ let suffix = if let ast::Stmt_::StmtExpr(..) = stmt.node {
+ ""
+ } else {
+ ";"
+ };
+
+ // 1 = trailing semicolon;
+ let rewrite = ex.rewrite(&self.get_context(),
+ self.config.max_width - self.block_indent - suffix.len(),
+ self.block_indent);
+
+ if let Some(new_str) = rewrite {
+ self.buffer.push_str(&new_str);
+ self.buffer.push_str(suffix);
+ self.last_pos = stmt.span.hi;
}
}
- _ => false,
- };
- if !skip_missing {
- self.format_missing_with_indent(stmt.span.lo);
+ ast::Stmt_::StmtMac(..) => {
+ self.format_missing_with_indent(stmt.span.lo);
+ visit::walk_stmt(self, stmt);
+ }
}
- visit::walk_stmt(self, stmt);
}
fn visit_block(&mut self, b: &'v ast::Block) {
--- /dev/null
+// Test assignment
+
+fn main() {
+ let some_var : Type ;
+
+ let mut mutable;
+
+ let variable = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::EEEEEE;
+
+ variable = LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG;
+
+ let single_line_fit =
+ DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
+
+ single_line_fit = 5;single_lit_fit >>= 10;
+}
fn foo() -> bool {
let boxed: Box<i32> = box 5;
- let referenced = &5;
+ let referenced = &5 ;
let very_long_variable_name = ( a + first + simple + test );
let very_long_variable_name = (a + first + simple + test + AAAAAAAAAAAAA + BBBBBBBBBBBBBBBBB + b + c);
- //FIXME this exceeds width limit. Needs assignments reformatting
let is_internalxxxx = self.codemap.span_to_filename(s) == self.codemap.span_to_filename(m.inner);
let some_val = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * bbbb / (bbbbbb -
function_call(x, *very_long_pointer, y))
- + 1000;
+ + 1000 ;
some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000 / 1002200000000
- 50000 * sqrt(-1),
trivial_value);
(((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + a +
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))));
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa))))))))) ;
{ for _ in 0..10 {} }
syntactically_correct(loop { sup( '?'); }, if cond { 0 } else { 1 });
let third = ..10;
- let infi_range = ..;
+ let infi_range = .. ;
let foo = 1..;
- let bar = 5;
+ let bar = 5 ;
let nonsense = (10 .. 0)..(0..10);
let x = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
Quux::<ParamOne, // Comment 1
ParamTwo, // Comment 2
>::some_func();
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::quux();
}
fn op(foo: Bar, key : &[u8], upd : Fn(Option<&memcache::Item> , Baz ) -> Result) -> MapResult {}
--- /dev/null
+// Test assignment
+
+fn main() {
+ let some_var: Type;
+
+ let mut mutable;
+
+ let variable =
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::EEEEEE;
+
+ variable =
+ LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG;
+
+ let single_line_fit = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD;
+
+ single_line_fit = 5;
+ single_lit_fit >>= 10;
+}
let very_long_variable_name = (a + first + simple + test + AAAAAAAAAAAAA +
BBBBBBBBBBBBBBBBB + b + c);
- //FIXME this exceeds width limit. Needs assignments reformatting
- let is_internalxxxx = self.codemap.span_to_filename(s) == self.codemap.span_to_filename(m.inner);
+ let is_internalxxxx = self.codemap.span_to_filename(s) ==
+ self.codemap.span_to_filename(m.inner);
let some_val = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa * bbbb /
(bbbbbb - function_call(x, *very_long_pointer, y)) + 1000;
42usize);
let rc = RefCell::new(42usize, remaining_width, remaining_width); // a comment
let x = "Hello!!!!!!!!! abcd abcd abcd abcd abcd abcd\n abcd abcd abcd abcd abcd abcd abcd \
- abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd \
+ abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd \
abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd abcd \
- abcd";
+ abcd abcd";
}
supports_clipboard);
Quux::<ParamOne /* Comment 1 */, ParamTwo /* Comment 2 */>::some_func();
-
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA::BBBBBBBBBBBBBBBBBBBBBBBBBBBB::CCCCCCCCCCCCCCCCCCCCCC::quux();
}
fn op(foo: Bar, key: &[u8], upd: Fn(Option<&memcache::Item>, Baz) -> Result) -> MapResult {
fn main() -> &'static str {
let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAaAA \
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAa";
- let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAA\
- AAAAAAAAAAAaAa";
+ let str = "AAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAAAAAAAAAAAAAAA\
+ AAAAAAAAAAAAaAa";
let str = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
let too_many_lines = "Hello";
// Make sure we don't break after an escape character.
- let odd_length_name = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
- \n\n";
+ let odd_length_name = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
+ \n\n\n";
let even_length_name = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\
\n\n\n";
- let really_long_variable_name = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
- AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
+ let really_long_variable_name = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\
+ AA";
let raw_string = r#"Do
not
b: bar(),
..something };
- Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo { a: foo(),
- b: bar(), };
+ Fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo { a: foo(), b: bar() };
- Foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo { // Comment
+ Foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo { // Commen
+ // t
a: foo(), /* C
* o
* m
* e
* n
* t */
- // Comment
+ // Commen
+ // t
b: bar(), /* C
* o
* m