Merge pull request #147 from marcusklaas/even-more-expr
Format if expressions & loops
This commit is contained in:
commit
8461e8a0a8
@ -17,9 +17,11 @@ pub fn rewrite_comment(orig: &str, block_style: bool, width: usize, offset: usiz
|
||||
let s = orig.trim();
|
||||
|
||||
// Edge case: block comments. Let's not trim their lines (for now).
|
||||
let opener = if block_style { "/* " } else { "// " };
|
||||
let closer = if block_style { " */" } else { "" };
|
||||
let line_start = if block_style { " * " } else { "// " };
|
||||
let (opener, closer, line_start) = if block_style {
|
||||
("/* ", " */", " * ")
|
||||
} else {
|
||||
("// ", "", "// ")
|
||||
};
|
||||
|
||||
let max_chars = width.checked_sub(closer.len()).unwrap_or(1)
|
||||
.checked_sub(opener.len()).unwrap_or(1);
|
||||
|
@ -14,6 +14,18 @@ use {NewlineStyle, BraceStyle, ReturnIndent, StructLitStyle};
|
||||
use lists::SeparatorTactic;
|
||||
use issues::ReportTactic;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum BlockIndentStyle {
|
||||
// Same level as parent.
|
||||
Inherit,
|
||||
// One level deeper than parent.
|
||||
Tabbed,
|
||||
// Aligned with block open.
|
||||
Visual,
|
||||
}
|
||||
|
||||
impl_enum_decodable!(BlockIndentStyle, Inherit, Tabbed, Visual);
|
||||
|
||||
#[derive(RustcDecodable, Clone)]
|
||||
pub struct Config {
|
||||
pub max_width: usize,
|
||||
@ -31,6 +43,7 @@ pub struct Config {
|
||||
pub report_todo: ReportTactic,
|
||||
pub report_fixme: ReportTactic,
|
||||
pub reorder_imports: bool, // Alphabetically, case sensitive.
|
||||
pub expr_indent_style: BlockIndentStyle,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
@ -13,3 +13,4 @@ enum_trailing_comma = true
|
||||
report_todo = "Always"
|
||||
report_fixme = "Never"
|
||||
reorder_imports = false
|
||||
expr_indent_style = "Tabbed"
|
||||
|
288
src/expr.rs
288
src/expr.rs
@ -14,6 +14,7 @@ use string::{StringFormat, rewrite_string};
|
||||
use StructLitStyle;
|
||||
use utils::{span_after, make_indent};
|
||||
use visitor::FmtVisitor;
|
||||
use config::BlockIndentStyle;
|
||||
|
||||
use syntax::{ast, ptr};
|
||||
use syntax::codemap::{Pos, Span, BytePos, mk_sp};
|
||||
@ -56,12 +57,47 @@ impl Rewrite for ast::Expr {
|
||||
ast::Expr_::ExprTup(ref items) => {
|
||||
rewrite_tuple_lit(context, items, self.span, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprLoop(ref block, _) => {
|
||||
// FIXME: this drops any comment between "loop" and the block.
|
||||
// TODO: format label
|
||||
block.rewrite(context, width, offset).map(|result| {
|
||||
format!("loop {}", result)
|
||||
})
|
||||
ast::Expr_::ExprWhile(ref cond, ref block, label) => {
|
||||
Loop::new_while(None, cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprWhileLet(ref pat, ref cond, ref block, label) => {
|
||||
Loop::new_while(Some(pat), cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprForLoop(ref pat, ref cond, ref block, label) => {
|
||||
Loop::new_for(pat, cond, block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprLoop(ref block, label) => {
|
||||
Loop::new_loop(block, label).rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprBlock(ref block) => {
|
||||
block.rewrite(context, width, offset)
|
||||
}
|
||||
ast::Expr_::ExprIf(ref cond, ref if_block, ref else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
None,
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
ast::Expr_::ExprIfLet(ref pat, ref cond, ref if_block, ref else_block) => {
|
||||
rewrite_if_else(context,
|
||||
cond,
|
||||
if_block,
|
||||
else_block.as_ref().map(|e| &**e),
|
||||
Some(pat),
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
// We reformat it ourselves because rustc gives us a bad span
|
||||
// for ranges, see rust#27162
|
||||
ast::Expr_::ExprRange(ref left, ref right) => {
|
||||
rewrite_range(context,
|
||||
left.as_ref().map(|e| &**e),
|
||||
right.as_ref().map(|e| &**e),
|
||||
width,
|
||||
offset)
|
||||
}
|
||||
_ => context.codemap.span_to_snippet(self.span).ok()
|
||||
}
|
||||
@ -88,6 +124,217 @@ impl Rewrite for ast::Block {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#18): implement pattern formatting
|
||||
impl Rewrite for ast::Pat {
|
||||
fn rewrite(&self, context: &RewriteContext, _: usize, _: usize) -> Option<String> {
|
||||
context.codemap.span_to_snippet(self.span).ok()
|
||||
}
|
||||
}
|
||||
|
||||
// Abstraction over for, while and loop expressions
|
||||
struct Loop<'a> {
|
||||
cond: Option<&'a ast::Expr>,
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::Ident>,
|
||||
pat: Option<&'a ast::Pat>,
|
||||
keyword: &'a str,
|
||||
matcher: &'a str,
|
||||
connector: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> Loop<'a> {
|
||||
fn new_loop(block: &'a ast::Block, label: Option<ast::Ident>) -> Loop<'a> {
|
||||
Loop {
|
||||
cond: None,
|
||||
block: block,
|
||||
label: label,
|
||||
pat: None,
|
||||
keyword: "loop",
|
||||
matcher: "",
|
||||
connector: "",
|
||||
}
|
||||
}
|
||||
|
||||
fn new_while(pat: Option<&'a ast::Pat>,
|
||||
cond: &'a ast::Expr,
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::Ident>)
|
||||
-> Loop<'a> {
|
||||
Loop {
|
||||
cond: Some(cond),
|
||||
block: block,
|
||||
label: label,
|
||||
pat: pat,
|
||||
keyword: "while ",
|
||||
matcher: match pat {
|
||||
Some(..) => "let ",
|
||||
None => ""
|
||||
},
|
||||
connector: " =",
|
||||
}
|
||||
}
|
||||
|
||||
fn new_for(pat: &'a ast::Pat,
|
||||
cond: &'a ast::Expr,
|
||||
block: &'a ast::Block,
|
||||
label: Option<ast::Ident>)
|
||||
-> Loop<'a> {
|
||||
Loop {
|
||||
cond: Some(cond),
|
||||
block: block,
|
||||
label: label,
|
||||
pat: Some(pat),
|
||||
keyword: "for ",
|
||||
matcher: "",
|
||||
connector: " in",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Rewrite for Loop<'a> {
|
||||
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
|
||||
let label_string = rewrite_label(self.label);
|
||||
// 2 = " {".len()
|
||||
let inner_width = width - self.keyword.len() - 2 - label_string.len();
|
||||
let inner_offset = offset + self.keyword.len() + label_string.len();
|
||||
|
||||
let pat_expr_string = match self.cond {
|
||||
Some(cond) => try_opt!(rewrite_pat_expr(context,
|
||||
self.pat,
|
||||
cond,
|
||||
self.matcher,
|
||||
self.connector,
|
||||
inner_width,
|
||||
inner_offset)),
|
||||
None => String::new()
|
||||
};
|
||||
|
||||
// FIXME: this drops any comment between "loop" and the block.
|
||||
self.block.rewrite(context, width, offset).map(|result| {
|
||||
format!("{}{}{} {}", label_string, self.keyword, pat_expr_string, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_label(label: Option<ast::Ident>) -> String {
|
||||
match label {
|
||||
Some(ident) => format!("{}: ", ident),
|
||||
None => "".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: this doesn't play well with line breaks
|
||||
fn rewrite_range(context: &RewriteContext,
|
||||
left: Option<&ast::Expr>,
|
||||
right: Option<&ast::Expr>,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
let left_string = match left {
|
||||
// 2 = ..
|
||||
Some(expr) => try_opt!(expr.rewrite(context, width - 2, offset)),
|
||||
None => String::new()
|
||||
};
|
||||
|
||||
let right_string = match right {
|
||||
Some(expr) => {
|
||||
// 2 = ..
|
||||
let max_width = (width - 2).checked_sub(left_string.len()).unwrap_or(0);
|
||||
try_opt!(expr.rewrite(context, max_width, offset + 2 + left_string.len()))
|
||||
}
|
||||
None => String::new()
|
||||
};
|
||||
|
||||
Some(format!("{}..{}", left_string, right_string))
|
||||
}
|
||||
|
||||
// Rewrites if-else blocks. If let Some(_) = pat, the expression is
|
||||
// treated as an if-let-else expression.
|
||||
fn rewrite_if_else(context: &RewriteContext,
|
||||
cond: &ast::Expr,
|
||||
if_block: &ast::Block,
|
||||
else_block: Option<&ast::Expr>,
|
||||
pat: Option<&ast::Pat>,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
// 3 = "if ", 2 = " {"
|
||||
let pat_expr_string = try_opt!(rewrite_pat_expr(context,
|
||||
pat,
|
||||
cond,
|
||||
"let ",
|
||||
" =",
|
||||
width - 3 - 2,
|
||||
offset + 3));
|
||||
|
||||
let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
|
||||
let mut result = format!("if {} {}", pat_expr_string, if_block_string);
|
||||
|
||||
if let Some(else_block) = else_block {
|
||||
let else_block_string = try_opt!(else_block.rewrite(context, width, offset));
|
||||
|
||||
result.push_str(" else ");
|
||||
result.push_str(&else_block_string);
|
||||
}
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn rewrite_pat_expr(context: &RewriteContext,
|
||||
pat: Option<&ast::Pat>,
|
||||
expr: &ast::Expr,
|
||||
matcher: &str,
|
||||
connector: &str,
|
||||
width: usize,
|
||||
offset: usize)
|
||||
-> Option<String> {
|
||||
let pat_offset = offset + matcher.len();
|
||||
let mut result = match pat {
|
||||
Some(pat) => {
|
||||
let pat_string = try_opt!(pat.rewrite(context,
|
||||
width - connector.len() - matcher.len(),
|
||||
pat_offset));
|
||||
format!("{}{}{}", matcher, pat_string, connector)
|
||||
}
|
||||
None => String::new()
|
||||
};
|
||||
|
||||
// Consider only the last line of the pat string.
|
||||
let extra_offset = match result.rfind('\n') {
|
||||
// 1 for newline character
|
||||
Some(idx) => result.len() - idx - 1 - offset,
|
||||
None => result.len()
|
||||
};
|
||||
|
||||
// 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 expr_rewrite = expr.rewrite(context,
|
||||
width - corrected_offset,
|
||||
offset + corrected_offset);
|
||||
|
||||
if let Some(expr_string) = expr_rewrite {
|
||||
result.push_str(&expr_string);
|
||||
return Some(result);
|
||||
}
|
||||
}
|
||||
|
||||
// The expression won't fit on the current line, jump to next.
|
||||
result.push('\n');
|
||||
result.push_str(&make_indent(pat_offset));
|
||||
|
||||
let expr_rewrite = expr.rewrite(context, context.config.max_width - pat_offset, pat_offset);
|
||||
result.push_str(&&try_opt!(expr_rewrite));
|
||||
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn rewrite_string_lit(context: &RewriteContext,
|
||||
s: &str,
|
||||
span: Span,
|
||||
@ -134,6 +381,8 @@ fn rewrite_call(context: &RewriteContext,
|
||||
// 2 is for parens.
|
||||
let remaining_width = try_opt!(width.checked_sub(callee_str.len() + 2));
|
||||
let offset = callee_str.len() + 1 + offset;
|
||||
let block_indent = expr_block_indent(context, offset);
|
||||
let inner_context = &RewriteContext { block_indent: block_indent, ..*context };
|
||||
|
||||
let items = itemize_list(context.codemap,
|
||||
Vec::new(),
|
||||
@ -143,7 +392,7 @@ fn rewrite_call(context: &RewriteContext,
|
||||
|item| item.span.lo,
|
||||
|item| item.span.hi,
|
||||
// Take old span when rewrite fails.
|
||||
|item| item.rewrite(context, remaining_width, offset)
|
||||
|item| item.rewrite(inner_context, remaining_width, offset)
|
||||
.unwrap_or(context.codemap.span_to_snippet(item.span)
|
||||
.unwrap()),
|
||||
callee.span.hi + BytePos(1),
|
||||
@ -162,6 +411,14 @@ fn rewrite_call(context: &RewriteContext,
|
||||
Some(format!("{}({})", callee_str, write_list(&items, &fmt)))
|
||||
}
|
||||
|
||||
fn expr_block_indent(context: &RewriteContext, offset: usize) -> usize {
|
||||
match context.config.expr_indent_style {
|
||||
BlockIndentStyle::Inherit => context.block_indent,
|
||||
BlockIndentStyle::Tabbed => context.block_indent + context.config.tab_spaces,
|
||||
BlockIndentStyle::Visual => offset,
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_paren(context: &RewriteContext,
|
||||
subexpr: &ast::Expr,
|
||||
width: usize,
|
||||
@ -192,23 +449,26 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
}
|
||||
|
||||
let path_str = pprust::path_to_string(path);
|
||||
let (indent, h_budget, v_budget) = match context.config.struct_lit_style {
|
||||
// Foo { a: Foo } - indent is +3, width is -5.
|
||||
let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0);
|
||||
let (indent, v_budget) = match context.config.struct_lit_style {
|
||||
StructLitStyle::VisualIndent => {
|
||||
// Foo { a: Foo } - indent is +3, width is -5.
|
||||
let budget = width - (path_str.len() + 5);
|
||||
(offset + path_str.len() + 3, budget, budget)
|
||||
(offset + path_str.len() + 3, h_budget)
|
||||
}
|
||||
StructLitStyle::BlockIndent => {
|
||||
// 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;
|
||||
(indent, width - (path_str.len() + 5), width - indent)
|
||||
let v_budget = context.config.max_width.checked_sub(indent).unwrap_or(0);
|
||||
(indent, v_budget)
|
||||
}
|
||||
};
|
||||
|
||||
let field_iter = fields.into_iter().map(StructLitField::Regular)
|
||||
.chain(base.into_iter().map(StructLitField::Base));
|
||||
|
||||
let inner_context = &RewriteContext { block_indent: indent, ..*context };
|
||||
|
||||
let items = itemize_list(context.codemap,
|
||||
Vec::new(),
|
||||
field_iter,
|
||||
@ -230,13 +490,13 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
|
||||
|item| {
|
||||
match *item {
|
||||
StructLitField::Regular(ref field) => {
|
||||
rewrite_field(context, &field, h_budget, indent)
|
||||
rewrite_field(inner_context, &field, h_budget, indent)
|
||||
.unwrap_or(context.codemap.span_to_snippet(field.span)
|
||||
.unwrap())
|
||||
},
|
||||
StructLitField::Base(ref expr) => {
|
||||
// 2 = ..
|
||||
expr.rewrite(context, h_budget - 2, indent + 2)
|
||||
expr.rewrite(inner_context, h_budget - 2, indent + 2)
|
||||
.map(|s| format!("..{}", s))
|
||||
.unwrap_or(context.codemap.span_to_snippet(expr.span)
|
||||
.unwrap())
|
||||
|
@ -60,7 +60,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
}
|
||||
|
||||
// 2 = ::
|
||||
let path_separation_w = if path_str.len() > 0 { 2 } else { 0 };
|
||||
let path_separation_w = if path_str.len() > 0 {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
};
|
||||
// 5 = "use " + {
|
||||
let indent = path_str.len() + 5 + path_separation_w + vis.len();
|
||||
|
||||
@ -106,7 +110,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
// FIXME: Make more efficient by using a linked list? That would
|
||||
// require changes to the signatures of itemize_list and write_list.
|
||||
let has_self = move_self_to_front(&mut items);
|
||||
let first_index = if has_self { 0 } else { 1 };
|
||||
let first_index = if has_self {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
if self.config.reorder_imports {
|
||||
items[1..].sort_by(|a, b| a.item.cmp(&b.item));
|
||||
@ -115,10 +123,10 @@ impl<'a> FmtVisitor<'a> {
|
||||
let list = write_list(&items[first_index..], &fmt);
|
||||
|
||||
Some(if path_str.len() == 0 {
|
||||
format!("{}use {{{}}};", vis, list)
|
||||
} else {
|
||||
format!("{}use {}::{{{}}};", vis, path_str, list)
|
||||
})
|
||||
format!("{}use {{{}}};", vis, list)
|
||||
} else {
|
||||
format!("{}use {}::{{{}}};", vis, path_str, list)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,11 @@ impl fmt::Display for Issue {
|
||||
IssueType::Todo => "TODO",
|
||||
IssueType::Fixme => "FIXME",
|
||||
};
|
||||
let details = if self.missing_number { " without issue number" } else { "" };
|
||||
let details = if self.missing_number {
|
||||
" without issue number"
|
||||
} else {
|
||||
""
|
||||
};
|
||||
|
||||
write!(fmt, "{}{}", msg, details)
|
||||
}
|
||||
@ -177,7 +181,7 @@ impl BadIssueSeeker {
|
||||
issue: Issue,
|
||||
mut part: NumberPart)
|
||||
-> IssueClassification {
|
||||
if ! issue.missing_number || c == '\n' {
|
||||
if !issue.missing_number || c == '\n' {
|
||||
return IssueClassification::Bad(issue);
|
||||
} else if c == ')' {
|
||||
return if let NumberPart::CloseParen = part {
|
||||
|
18
src/items.rs
18
src/items.rs
@ -446,7 +446,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
+ field.node.name.to_string().len()
|
||||
+ 1; // Open paren
|
||||
|
||||
let comma_cost = if self.config.enum_trailing_comma { 1 } else { 0 };
|
||||
let comma_cost = if self.config.enum_trailing_comma {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let budget = self.config.ideal_width - indent - comma_cost - 1; // 1 = )
|
||||
|
||||
let fmt = ListFormatting {
|
||||
@ -520,7 +524,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
ast::StructFieldKind::UnnamedField(..) => true
|
||||
};
|
||||
|
||||
let (opener, terminator) = if is_tuple { ("(", ")") } else { (" {", "}") };
|
||||
let (opener, terminator) = if is_tuple {
|
||||
("(", ")")
|
||||
} else {
|
||||
(" {", "}")
|
||||
};
|
||||
|
||||
let generics_str = match generics {
|
||||
Some(g) => self.format_generics(g,
|
||||
@ -565,7 +573,11 @@ impl<'a> FmtVisitor<'a> {
|
||||
result.push_str(&indentation);
|
||||
}
|
||||
|
||||
let tactic = if break_line { ListTactic::Vertical } else { ListTactic::Horizontal };
|
||||
let tactic = if break_line {
|
||||
ListTactic::Vertical
|
||||
} else {
|
||||
ListTactic::Horizontal
|
||||
};
|
||||
|
||||
// 1 = ,
|
||||
let budget = self.config.ideal_width - offset + self.config.tab_spaces - 1;
|
||||
|
10
src/lib.rs
10
src/lib.rs
@ -49,10 +49,9 @@ use changes::ChangeSet;
|
||||
use visitor::FmtVisitor;
|
||||
use config::Config;
|
||||
|
||||
#[macro_use]
|
||||
mod config;
|
||||
#[macro_use]
|
||||
mod utils;
|
||||
pub mod config;
|
||||
mod changes;
|
||||
mod visitor;
|
||||
mod items;
|
||||
@ -218,11 +217,12 @@ fn fmt_lines(changes: &mut ChangeSet, config: &Config) -> FormatReport {
|
||||
let mut cur_line = 1;
|
||||
let mut newline_count = 0;
|
||||
let mut errors = vec![];
|
||||
let mut issue_seeker = BadIssueSeeker::new(config.report_todo,
|
||||
config.report_fixme);
|
||||
let mut issue_seeker = BadIssueSeeker::new(config.report_todo, config.report_fixme);
|
||||
|
||||
for (c, b) in text.chars() {
|
||||
if c == '\r' { continue; }
|
||||
if c == '\r' {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add warnings for bad todos/ fixmes
|
||||
if let Some(issue) = issue_seeker.inspect(c) {
|
||||
|
@ -136,7 +136,11 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> St
|
||||
let first = i == 0;
|
||||
let last = i == items.len() - 1;
|
||||
let separate = !last || trailing_separator;
|
||||
let item_sep_len = if separate { sep_len } else { 0 };
|
||||
let item_sep_len = if separate {
|
||||
sep_len
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let item_width = item.item.len() + item_sep_len;
|
||||
|
||||
match tactic {
|
||||
@ -208,8 +212,7 @@ pub fn write_list<'b>(items: &[ListItem], formatting: &ListFormatting<'b>) -> St
|
||||
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;
|
||||
comment.trim().contains('\n') || comment.trim().len() > width;
|
||||
|
||||
let formatted_comment = rewrite_comment(comment, block_style, width, offset);
|
||||
|
||||
|
@ -24,7 +24,9 @@ pub fn span_after(original: Span, needle: &str, codemap: &CodeMap) -> BytePos {
|
||||
|
||||
#[inline]
|
||||
pub fn prev_char(s: &str, mut i: usize) -> usize {
|
||||
if i == 0 { return 0; }
|
||||
if i == 0 {
|
||||
return 0;
|
||||
}
|
||||
|
||||
i -= 1;
|
||||
while !s.is_char_boundary(i) {
|
||||
@ -35,7 +37,9 @@ pub fn prev_char(s: &str, mut i: usize) -> usize {
|
||||
|
||||
#[inline]
|
||||
pub fn next_char(s: &str, mut i: usize) -> usize {
|
||||
if i >= s.len() { return s.len(); }
|
||||
if i >= s.len() {
|
||||
return s.len();
|
||||
}
|
||||
|
||||
while !s.is_char_boundary(i) {
|
||||
i += 1;
|
||||
|
@ -351,7 +351,7 @@ impl<'a> FmtVisitor<'a> {
|
||||
|
||||
result.push_str(&a_str);
|
||||
|
||||
if i < attrs.len() -1 {
|
||||
if i < attrs.len() - 1 {
|
||||
result.push('\n');
|
||||
}
|
||||
}
|
||||
|
16
tests/config/expr_visual_indent.toml
Normal file
16
tests/config/expr_visual_indent.toml
Normal file
@ -0,0 +1,16 @@
|
||||
max_width = 100
|
||||
ideal_width = 80
|
||||
leeway = 5
|
||||
tab_spaces = 4
|
||||
newline_style = "Unix"
|
||||
fn_brace_style = "SameLineWhere"
|
||||
fn_return_indent = "WithArgs"
|
||||
fn_args_paren_newline = true
|
||||
struct_trailing_comma = "Vertical"
|
||||
struct_lit_style = "BlockIndent"
|
||||
struct_lit_trailing_comma = "Vertical"
|
||||
enum_trailing_comma = true
|
||||
report_todo = "Always"
|
||||
report_fixme = "Never"
|
||||
reorder_imports = false
|
||||
expr_indent_style = "Visual"
|
@ -13,3 +13,4 @@ enum_trailing_comma = true
|
||||
report_todo = "Always"
|
||||
report_fixme = "Never"
|
||||
reorder_imports = true
|
||||
expr_indent_style = "Tabbed"
|
||||
|
@ -13,3 +13,4 @@ enum_trailing_comma = true
|
||||
report_todo = "Always"
|
||||
report_fixme = "Never"
|
||||
reorder_imports = false
|
||||
expr_indent_style = "Tabbed"
|
||||
|
@ -13,3 +13,4 @@ enum_trailing_comma = true
|
||||
report_todo = "Always"
|
||||
report_fixme = "Never"
|
||||
reorder_imports = false
|
||||
expr_indent_style = "Tabbed"
|
||||
|
9
tests/source/expr-visual-indent.rs
Normal file
9
tests/source/expr-visual-indent.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// rustfmt-config: expr_visual_indent.toml
|
||||
|
||||
// Visual level block indentation.
|
||||
|
||||
fn matcher() {
|
||||
Some(while true {
|
||||
test();
|
||||
})
|
||||
}
|
@ -17,5 +17,54 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
|
||||
- 50000 * sqrt(-1),
|
||||
trivial_value);
|
||||
(((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + a +
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))))
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))));
|
||||
|
||||
{ for _ in 0..10 {} }
|
||||
|
||||
{{{{}}}}
|
||||
|
||||
if 1 + 2 > 0 { let result = 5; result } else { 4};
|
||||
|
||||
if let Some(x) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
if let Some(x) = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {}
|
||||
|
||||
if let (some_very_large,
|
||||
tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1
|
||||
+ 2 + 3 {
|
||||
}
|
||||
|
||||
if let (some_very_large,
|
||||
tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1111 + 2222 {}
|
||||
|
||||
if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1
|
||||
+ 2 + 3 {
|
||||
}
|
||||
|
||||
if cond() {
|
||||
something();
|
||||
} else if different_cond() {
|
||||
something_else();
|
||||
} else {
|
||||
// Check subformatting
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let range = ( 111111111 + 333333333333333333 + 1111 + 400000000000000000) .. (2222 + 2333333333333333);
|
||||
|
||||
let another_range = 5..some_func( a , b /* comment */);
|
||||
|
||||
for _ in 1 ..{ call_forever(); }
|
||||
|
||||
syntactically_correct(loop { sup( '?'); }, if cond { 0 } else { 1 });
|
||||
|
||||
let third = ..10;
|
||||
let infi_range = ..;
|
||||
let foo = 1..;
|
||||
let bar = 5;
|
||||
let nonsense = (10 .. 0)..(0..10);
|
||||
}
|
||||
|
@ -5,7 +5,21 @@ fn main() {
|
||||
|
||||
let x = loop { do_forever(); };
|
||||
|
||||
loop {
|
||||
'label : loop {
|
||||
// Just comments
|
||||
}
|
||||
|
||||
'a: while loooooooooooooooooooooooooooooooooong_variable_name + another_value > some_other_value{}
|
||||
|
||||
while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {
|
||||
}
|
||||
|
||||
'b: for xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx in some_iter(arg1, arg2) {
|
||||
// do smth
|
||||
}
|
||||
|
||||
while let Some(i) = x.find('s')
|
||||
{
|
||||
x.update();
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ fn main() {
|
||||
Foo { a:Bar,
|
||||
b:foo() };
|
||||
|
||||
Quux { x: if cond { bar(); }, y: baz() };
|
||||
|
||||
A {
|
||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor.
|
||||
first: item(),
|
||||
@ -37,3 +39,12 @@ fn main() {
|
||||
* o o o o */
|
||||
graph: G, }
|
||||
}
|
||||
|
||||
fn matcher() {
|
||||
TagTerminatedByteMatcher {
|
||||
matcher: ByteMatcher {
|
||||
pattern: b"<HTML",
|
||||
mask: b"\xFF\xDF\xDF\xDF\xDF\xFF",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ fn main() {
|
||||
Foo { a:Bar,
|
||||
b:foo() };
|
||||
|
||||
Quux { x: if cond { bar(); }, y: baz() };
|
||||
|
||||
A {
|
||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor.
|
||||
first: item(),
|
||||
|
9
tests/target/expr-visual-indent.rs
Normal file
9
tests/target/expr-visual-indent.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// rustfmt-config: expr_visual_indent.toml
|
||||
|
||||
// Visual level block indentation.
|
||||
|
||||
fn matcher() {
|
||||
Some(while true {
|
||||
test();
|
||||
})
|
||||
}
|
@ -19,5 +19,83 @@ fn foo() -> bool {
|
||||
trivial_value);
|
||||
(((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
|
||||
a + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
|
||||
aaaaa)))))))))
|
||||
aaaaa)))))))));
|
||||
|
||||
{
|
||||
for _ in 0..10 {
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
{
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if 1 + 2 > 0 {
|
||||
let result = 5;
|
||||
result
|
||||
} else {
|
||||
4
|
||||
};
|
||||
|
||||
if let Some(x) = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
if let Some(x) = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {
|
||||
}
|
||||
|
||||
if let (some_very_large,
|
||||
tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1 + 2 + 3 {
|
||||
}
|
||||
|
||||
if let (some_very_large,
|
||||
tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1111 +
|
||||
2222 {
|
||||
}
|
||||
|
||||
if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) =
|
||||
1 + 2 + 3 {
|
||||
}
|
||||
|
||||
if cond() {
|
||||
something();
|
||||
} else if different_cond() {
|
||||
something_else();
|
||||
} else {
|
||||
// Check subformatting
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
|
||||
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
||||
}
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
let range = (111111111 + 333333333333333333 + 1111 + 400000000000000000)..(2222 +
|
||||
2333333333333333);
|
||||
|
||||
let another_range = 5..some_func(a, b /* comment */);
|
||||
|
||||
for _ in 1.. {
|
||||
call_forever();
|
||||
}
|
||||
|
||||
syntactically_correct(loop {
|
||||
sup('?');
|
||||
},
|
||||
if cond {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
});
|
||||
|
||||
let third = ..10;
|
||||
let infi_range = ..;
|
||||
let foo = 1..;
|
||||
let bar = 5;
|
||||
let nonsense = (10..0)..(0..10);
|
||||
}
|
||||
|
@ -8,7 +8,23 @@ fn main() {
|
||||
do_forever();
|
||||
};
|
||||
|
||||
loop {
|
||||
'label: loop {
|
||||
// Just comments
|
||||
}
|
||||
|
||||
'a: while loooooooooooooooooooooooooooooooooong_variable_name + another_value >
|
||||
some_other_value {
|
||||
}
|
||||
|
||||
while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {
|
||||
}
|
||||
|
||||
'b: for xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx in some_iter(arg1,
|
||||
arg2) {
|
||||
// do smth
|
||||
}
|
||||
|
||||
while let Some(i) = x.find('s') {
|
||||
x.update();
|
||||
}
|
||||
}
|
||||
|
@ -29,9 +29,16 @@ fn main() {
|
||||
|
||||
Foo { a: Bar, b: foo() };
|
||||
|
||||
Quux {
|
||||
x: if cond {
|
||||
bar();
|
||||
},
|
||||
y: baz(),
|
||||
};
|
||||
|
||||
A {
|
||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed
|
||||
// sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante
|
||||
// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit
|
||||
// amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante
|
||||
// hendrerit. Donec et mollis dolor.
|
||||
first: item(),
|
||||
// Praesent et diam eget libero egestas mattis sit amet vitae augue.
|
||||
@ -48,3 +55,12 @@ fn main() {
|
||||
graph: G,
|
||||
}
|
||||
}
|
||||
|
||||
fn matcher() {
|
||||
TagTerminatedByteMatcher {
|
||||
matcher: ByteMatcher {
|
||||
pattern: b"<HTML",
|
||||
mask: b"\xFF\xDF\xDF\xDF\xDF\xFF",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -35,6 +35,11 @@ fn main() {
|
||||
|
||||
Foo { a: Bar, b: foo() };
|
||||
|
||||
Quux { x: if cond {
|
||||
bar();
|
||||
},
|
||||
y: baz(), };
|
||||
|
||||
A { // Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit
|
||||
// amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante
|
||||
// hendrerit. Donec et mollis dolor.
|
||||
|
Loading…
x
Reference in New Issue
Block a user