Skip to content

Commit c4101de

Browse files
committed
Refactor some things; add extra tests.
1 parent 2fa6220 commit c4101de

15 files changed

+292
-88
lines changed

src/config.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,18 @@ use {NewlineStyle, BraceStyle, ReturnIndent, StructLitStyle};
1414
use lists::SeparatorTactic;
1515
use issues::ReportTactic;
1616

17+
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
18+
pub enum BlockIndentStyle {
19+
// Same level as parent.
20+
Inherit,
21+
// One level deeper than parent.
22+
Tabbed,
23+
// Aligned with block open.
24+
Visual,
25+
}
26+
27+
impl_enum_decodable!(BlockIndentStyle, Inherit, Tabbed, Visual);
28+
1729
#[derive(RustcDecodable, Clone)]
1830
pub struct Config {
1931
pub max_width: usize,
@@ -31,6 +43,7 @@ pub struct Config {
3143
pub report_todo: ReportTactic,
3244
pub report_fixme: ReportTactic,
3345
pub reorder_imports: bool, // Alphabetically, case sensitive.
46+
pub expr_indent_style: BlockIndentStyle,
3447
}
3548

3649
impl Config {

src/default.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ enum_trailing_comma = true
1313
report_todo = "Always"
1414
report_fixme = "Never"
1515
reorder_imports = false
16+
expr_indent_style = "Tabbed"

src/expr.rs

Lines changed: 139 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use string::{StringFormat, rewrite_string};
1414
use StructLitStyle;
1515
use utils::{span_after, make_indent};
1616
use visitor::FmtVisitor;
17+
use config::BlockIndentStyle;
1718

1819
use syntax::{ast, ptr};
1920
use syntax::codemap::{Pos, Span, BytePos, mk_sp};
@@ -57,48 +58,16 @@ impl Rewrite for ast::Expr {
5758
rewrite_tuple_lit(context, items, self.span, width, offset)
5859
}
5960
ast::Expr_::ExprWhile(ref cond, ref block, label) => {
60-
rewrite_loop(context,
61-
cond,
62-
block,
63-
label,
64-
None,
65-
"while ",
66-
"let ",
67-
" = ",
68-
width,
69-
offset)
61+
Loop::new_while(None, cond, block, label).rewrite(context, width, offset)
7062
}
7163
ast::Expr_::ExprWhileLet(ref pat, ref cond, ref block, label) => {
72-
rewrite_loop(context,
73-
cond,
74-
block,
75-
label,
76-
Some(pat),
77-
"while ",
78-
"let ",
79-
" = ",
80-
width,
81-
offset)
64+
Loop::new_while(Some(pat), cond, block, label).rewrite(context, width, offset)
8265
}
8366
ast::Expr_::ExprForLoop(ref pat, ref cond, ref block, label) => {
84-
rewrite_loop(context,
85-
cond,
86-
block,
87-
label,
88-
Some(pat),
89-
"for ",
90-
"",
91-
" in ",
92-
width,
93-
offset)
67+
Loop::new_for(pat, cond, block, label).rewrite(context, width, offset)
9468
}
9569
ast::Expr_::ExprLoop(ref block, label) => {
96-
// Of all the loops, this is the only one that does not use
97-
// rewrite_loop!
98-
// FIXME: this drops any comment between "loop" and the block.
99-
block.rewrite(context, width, offset).map(|result| {
100-
format!("{}loop {}", rewrite_label(label), result)
101-
})
70+
Loop::new_loop(block, label).rewrite(context, width, offset)
10271
}
10372
ast::Expr_::ExprBlock(ref block) => {
10473
block.rewrite(context, width, offset)
@@ -121,7 +90,8 @@ impl Rewrite for ast::Expr {
12190
width,
12291
offset)
12392
}
124-
// We reformat it ourselves because rustc gives us a bad span for ranges
93+
// We reformat it ourselves because rustc gives us a bad span
94+
// for ranges, see rust#27162
12595
ast::Expr_::ExprRange(ref left, ref right) => {
12696
rewrite_range(context,
12797
left.as_ref().map(|e| &**e),
@@ -161,6 +131,91 @@ impl Rewrite for ast::Pat {
161131
}
162132
}
163133

134+
// Abstraction over for, while and loop expressions
135+
struct Loop<'a> {
136+
cond: Option<&'a ast::Expr>,
137+
block: &'a ast::Block,
138+
label: Option<ast::Ident>,
139+
pat: Option<&'a ast::Pat>,
140+
keyword: &'a str,
141+
matcher: &'a str,
142+
connector: &'a str,
143+
}
144+
145+
impl<'a> Loop<'a> {
146+
fn new_loop(block: &'a ast::Block, label: Option<ast::Ident>) -> Loop<'a> {
147+
Loop {
148+
cond: None,
149+
block: block,
150+
label: label,
151+
pat: None,
152+
keyword: "loop",
153+
matcher: "",
154+
connector: "",
155+
}
156+
}
157+
158+
fn new_while(pat: Option<&'a ast::Pat>,
159+
cond: &'a ast::Expr,
160+
block: &'a ast::Block,
161+
label: Option<ast::Ident>)
162+
-> Loop<'a> {
163+
Loop {
164+
cond: Some(cond),
165+
block: block,
166+
label: label,
167+
pat: pat,
168+
keyword: "while ",
169+
matcher: match pat {
170+
Some(..) => "let ",
171+
None => ""
172+
},
173+
connector: " =",
174+
}
175+
}
176+
177+
fn new_for(pat: &'a ast::Pat,
178+
cond: &'a ast::Expr,
179+
block: &'a ast::Block,
180+
label: Option<ast::Ident>)
181+
-> Loop<'a> {
182+
Loop {
183+
cond: Some(cond),
184+
block: block,
185+
label: label,
186+
pat: Some(pat),
187+
keyword: "for ",
188+
matcher: "",
189+
connector: " in",
190+
}
191+
}
192+
}
193+
194+
impl<'a> Rewrite for Loop<'a> {
195+
fn rewrite(&self, context: &RewriteContext, width: usize, offset: usize) -> Option<String> {
196+
let label_string = rewrite_label(self.label);
197+
// 2 = " {".len()
198+
let inner_width = width - self.keyword.len() - 2 - label_string.len();
199+
let inner_offset = offset + self.keyword.len() + label_string.len();
200+
201+
let pat_expr_string = match self.cond {
202+
Some(cond) => try_opt!(rewrite_pat_expr(context,
203+
self.pat,
204+
cond,
205+
self.matcher,
206+
self.connector,
207+
inner_width,
208+
inner_offset)),
209+
None => String::new()
210+
};
211+
212+
// FIXME: this drops any comment between "loop" and the block.
213+
self.block.rewrite(context, width, offset).map(|result| {
214+
format!("{}{}{} {}", label_string, self.keyword, pat_expr_string, result)
215+
})
216+
}
217+
}
218+
164219
fn rewrite_label(label: Option<ast::Ident>) -> String {
165220
match label {
166221
Some(ident) => format!("{}: ", ident),
@@ -193,36 +248,8 @@ fn rewrite_range(context: &RewriteContext,
193248
Some(format!("{}..{}", left_string, right_string))
194249
}
195250

196-
fn rewrite_loop(context: &RewriteContext,
197-
cond: &ast::Expr,
198-
block: &ast::Block,
199-
label: Option<ast::Ident>,
200-
pat: Option<&ast::Pat>,
201-
keyword: &str,
202-
matcher: &str, // FIXME: think of better identifiers
203-
connector: &str,
204-
width: usize,
205-
offset: usize)
206-
-> Option<String> {
207-
let label_string = rewrite_label(label);
208-
// 2 = " {"
209-
let inner_width = width - keyword.len() - 2 - label_string.len();
210-
let inner_offset = offset + keyword.len() + label_string.len();
211-
212-
let pat_expr_string = try_opt!(rewrite_pat_expr(context,
213-
pat,
214-
cond,
215-
matcher,
216-
connector,
217-
inner_width,
218-
inner_offset));
219-
220-
// FIXME: this drops any comment between "loop" and the block.
221-
block.rewrite(context, width, offset).map(|result| {
222-
format!("{}{}{} {}", label_string, keyword, pat_expr_string, result)
223-
})
224-
}
225-
251+
// Rewrites if-else blocks. If let Some(_) = pat, the expression is
252+
// treated as an if-let-else expression.
226253
fn rewrite_if_else(context: &RewriteContext,
227254
cond: &ast::Expr,
228255
if_block: &ast::Block,
@@ -236,7 +263,7 @@ fn rewrite_if_else(context: &RewriteContext,
236263
pat,
237264
cond,
238265
"let ",
239-
" = ",
266+
" =",
240267
width - 3 - 2,
241268
offset + 3));
242269

@@ -261,28 +288,49 @@ fn rewrite_pat_expr(context: &RewriteContext,
261288
width: usize,
262289
offset: usize)
263290
-> Option<String> {
291+
let pat_offset = offset + matcher.len();
264292
let mut result = match pat {
265293
Some(pat) => {
266294
let pat_string = try_opt!(pat.rewrite(context,
267295
width - connector.len() - matcher.len(),
268-
offset + matcher.len()));
296+
pat_offset));
269297
format!("{}{}{}", matcher, pat_string, connector)
270298
}
271299
None => String::new()
272300
};
273301

274-
// Consider only the last line of the pat string
302+
// Consider only the last line of the pat string.
275303
let extra_offset = match result.rfind('\n') {
276304
// 1 for newline character
277305
Some(idx) => result.len() - idx - 1 - offset,
278306
None => result.len()
279307
};
280308

281-
let expr_string = try_opt!(expr.rewrite(context,
282-
width - extra_offset,
283-
offset + extra_offset));
309+
// The expression may (partionally) fit on the current line.
310+
if width > extra_offset + 1 {
311+
let mut corrected_offset = extra_offset;
284312

285-
result.push_str(&expr_string);
313+
if pat.is_some() {
314+
result.push(' ');
315+
corrected_offset += 1;
316+
}
317+
318+
let expr_rewrite = expr.rewrite(context,
319+
width - corrected_offset,
320+
offset + corrected_offset);
321+
322+
if let Some(expr_string) = expr_rewrite {
323+
result.push_str(&expr_string);
324+
return Some(result);
325+
}
326+
}
327+
328+
// The expression won't fit on the current line, jump to next.
329+
result.push('\n');
330+
result.push_str(&make_indent(pat_offset));
331+
332+
let expr_rewrite = expr.rewrite(context, context.config.max_width - pat_offset, pat_offset);
333+
result.push_str(&&try_opt!(expr_rewrite));
286334

287335
Some(result)
288336
}
@@ -333,6 +381,8 @@ fn rewrite_call(context: &RewriteContext,
333381
// 2 is for parens.
334382
let remaining_width = width - callee_str.len() - 2;
335383
let offset = callee_str.len() + 1 + offset;
384+
let block_indent = expr_block_indent(context, offset);
385+
let inner_context = &RewriteContext { block_indent: block_indent, ..*context };
336386

337387
let items = itemize_list(context.codemap,
338388
Vec::new(),
@@ -342,7 +392,7 @@ fn rewrite_call(context: &RewriteContext,
342392
|item| item.span.lo,
343393
|item| item.span.hi,
344394
// Take old span when rewrite fails.
345-
|item| item.rewrite(context, remaining_width, offset)
395+
|item| item.rewrite(inner_context, remaining_width, offset)
346396
.unwrap_or(context.codemap.span_to_snippet(item.span)
347397
.unwrap()),
348398
callee.span.hi + BytePos(1),
@@ -361,6 +411,14 @@ fn rewrite_call(context: &RewriteContext,
361411
Some(format!("{}({})", callee_str, write_list(&items, &fmt)))
362412
}
363413

414+
fn expr_block_indent(context: &RewriteContext, offset: usize) -> usize {
415+
match context.config.expr_indent_style {
416+
BlockIndentStyle::Inherit => context.block_indent,
417+
BlockIndentStyle::Tabbed => context.block_indent + context.config.tab_spaces,
418+
BlockIndentStyle::Visual => offset,
419+
}
420+
}
421+
364422
fn rewrite_paren(context: &RewriteContext,
365423
subexpr: &ast::Expr,
366424
width: usize,
@@ -391,17 +449,18 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
391449
}
392450

393451
let path_str = pprust::path_to_string(path);
394-
let (indent, h_budget, v_budget) = match context.config.struct_lit_style {
452+
// Foo { a: Foo } - indent is +3, width is -5.
453+
let h_budget = width.checked_sub(path_str.len() + 5).unwrap_or(0);
454+
let (indent, v_budget) = match context.config.struct_lit_style {
395455
StructLitStyle::VisualIndent => {
396-
// Foo { a: Foo } - indent is +3, width is -5.
397-
let budget = width - (path_str.len() + 5);
398-
(offset + path_str.len() + 3, budget, budget)
456+
(offset + path_str.len() + 3, h_budget)
399457
}
400458
StructLitStyle::BlockIndent => {
401459
// If we are all on one line, then we'll ignore the indent, and we
402460
// have a smaller budget.
403461
let indent = context.block_indent + context.config.tab_spaces;
404-
(indent, width - (path_str.len() + 5), width - indent)
462+
let v_budget = context.config.max_width.checked_sub(indent).unwrap_or(0);
463+
(indent, v_budget)
405464
}
406465
};
407466

src/imports.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ impl<'a> FmtVisitor<'a> {
123123
let list = write_list(&items[first_index..], &fmt);
124124

125125
Some(if path_str.len() == 0 {
126-
format!("{}use {{{}}};", vis, list)
127-
} else {
128-
format!("{}use {}::{{{}}};", vis, path_str, list)
129-
})
126+
format!("{}use {{{}}};", vis, list)
127+
} else {
128+
format!("{}use {}::{{{}}};", vis, path_str, list)
129+
})
130130
}
131131
}
132132

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,9 @@ use changes::ChangeSet;
4949
use visitor::FmtVisitor;
5050
use config::Config;
5151

52-
#[macro_use]
53-
mod config;
5452
#[macro_use]
5553
mod utils;
54+
pub mod config;
5655
mod changes;
5756
mod visitor;
5857
mod items;

tests/config/expr_visual_indent.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
max_width = 100
2+
ideal_width = 80
3+
leeway = 5
4+
tab_spaces = 4
5+
newline_style = "Unix"
6+
fn_brace_style = "SameLineWhere"
7+
fn_return_indent = "WithArgs"
8+
fn_args_paren_newline = true
9+
struct_trailing_comma = "Vertical"
10+
struct_lit_style = "BlockIndent"
11+
struct_lit_trailing_comma = "Vertical"
12+
enum_trailing_comma = true
13+
report_todo = "Always"
14+
report_fixme = "Never"
15+
reorder_imports = false
16+
expr_indent_style = "Visual"

0 commit comments

Comments
 (0)