From e47e91013ed69e967bb3a07145e86a789c28a1b4 Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Thu, 16 Jul 2015 16:29:28 +0200
Subject: [PATCH 1/5] Format while loops, including labels

---
 src/expr.rs          | 26 +++++++++++++++++++++++---
 tests/source/loop.rs |  7 ++++++-
 tests/target/loop.rs |  9 ++++++++-
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/src/expr.rs b/src/expr.rs
index 8dbe5c6d1dd..e0a76308b44 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -56,11 +56,24 @@ impl Rewrite for ast::Expr {
             ast::Expr_::ExprTup(ref items) => {
                 rewrite_tuple_lit(context, items, self.span, width, offset)
             }
-            ast::Expr_::ExprLoop(ref block, _) => {
+            ast::Expr_::ExprWhile(ref subexpr, ref block, label) => {
+                let label_string = rewrite_label(label);
+                // 6 = "while "
+                // 2 = " {"
+                let expr_width = width - 6 - 2 - label_string.len();
+                let expr_offset = offset + 6 + label_string.len();
+
+                subexpr.rewrite(context, expr_width, expr_offset).and_then(|expr_string| {
+                    // FIXME: this drops any comment between "loop" and the block.
+                    block.rewrite(context, width, offset).map(|result| {
+                        format!("{}while {} {}", rewrite_label(label), expr_string, result)
+                    })
+                })
+            }
+            ast::Expr_::ExprLoop(ref block, label) => {
                 // FIXME: this drops any comment between "loop" and the block.
-                // TODO: format label
                 block.rewrite(context, width, offset).map(|result| {
-                    format!("loop {}", result)
+                    format!("{}loop {}", rewrite_label(label), result)
                 })
             }
             _ => context.codemap.span_to_snippet(self.span).ok()
@@ -88,6 +101,13 @@ impl Rewrite for ast::Block {
     }
 }
 
+fn rewrite_label(label: Option<ast::Ident>) -> String {
+    match label {
+        Some(ident) => format!("{}: ", ident.as_str()),
+        None => "".to_owned()
+    }
+}
+
 fn rewrite_string_lit(context: &RewriteContext,
                       s: &str,
                       span: Span,
diff --git a/tests/source/loop.rs b/tests/source/loop.rs
index ad5ef93521d..143a3a23760 100644
--- a/tests/source/loop.rs
+++ b/tests/source/loop.rs
@@ -5,7 +5,12 @@ 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 {
+   }
 }
diff --git a/tests/target/loop.rs b/tests/target/loop.rs
index 3eb506eb6ed..cec8b2bff61 100644
--- a/tests/target/loop.rs
+++ b/tests/target/loop.rs
@@ -8,7 +8,14 @@ fn main() {
         do_forever();
     };
 
-    loop {
+    'label: loop {
         // Just comments
     }
+
+    'a: while loooooooooooooooooooooooooooooooooong_variable_name + another_value >
+              some_other_value {
+    }
+
+    while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {
+    }
 }

From b161815fe0aace4baa7007386b783a88547d7548 Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Sun, 19 Jul 2015 23:42:54 +0200
Subject: [PATCH 2/5] Format if-else expressions

---
 src/comment.rs                     |  8 +++---
 src/expr.rs                        | 40 ++++++++++++++++++++++++++++--
 src/imports.rs                     | 12 +++++++--
 src/issues.rs                      |  8 ++++--
 src/items.rs                       | 18 +++++++++++---
 src/utils.rs                       |  8 ++++--
 tests/source/expr.rs               | 13 +++++++++-
 tests/source/struct_lits_visual.rs |  2 ++
 tests/target/expr.rs               | 19 +++++++++++++-
 tests/target/struct_lits_visual.rs |  5 ++++
 10 files changed, 117 insertions(+), 16 deletions(-)

diff --git a/src/comment.rs b/src/comment.rs
index 7e4119880c3..6d453bd5c88 100644
--- a/src/comment.rs
+++ b/src/comment.rs
@@ -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);
diff --git a/src/expr.rs b/src/expr.rs
index e0a76308b44..89846527cff 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -76,6 +76,17 @@ impl Rewrite for ast::Expr {
                     format!("{}loop {}", rewrite_label(label), result)
                 })
             }
+            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),
+                                width,
+                                offset)
+            }
             _ => context.codemap.span_to_snippet(self.span).ok()
         }
     }
@@ -108,6 +119,29 @@ fn rewrite_label(label: Option<ast::Ident>) -> String {
     }
 }
 
+fn rewrite_if_else(context: &RewriteContext,
+                   cond: &ast::Expr,
+                   if_block: &ast::Block,
+                   else_block: Option<&ast::Expr>,
+                   width: usize,
+                   offset: usize)
+                   -> Option<String> {
+    // FIXME: missing comments between control statements and blocks
+    let cond_string = try_opt!(cond.rewrite(context, width - 3 - 2, offset + 3));
+    let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
+
+    match else_block {
+        Some(else_block) => {
+            else_block.rewrite(context, width, offset).map(|else_block_string| {
+                format!("if {} {} else {}", cond_string, if_block_string, else_block_string)
+            })
+        }
+        None => {
+            Some(format!("if {} {}", cond_string, if_block_string))
+        }
+    }
+}
+
 fn rewrite_string_lit(context: &RewriteContext,
                       s: &str,
                       span: Span,
@@ -229,6 +263,8 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext,
     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,
@@ -250,13 +286,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())
diff --git a/src/imports.rs b/src/imports.rs
index 1973115cd43..66bf26b041d 100644
--- a/src/imports.rs
+++ b/src/imports.rs
@@ -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));
diff --git a/src/issues.rs b/src/issues.rs
index 31f544605b5..34d5b8ab2c4 100644
--- a/src/issues.rs
+++ b/src/issues.rs
@@ -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 {
diff --git a/src/items.rs b/src/items.rs
index b3f4a0a63a4..3c35b20fb3f 100644
--- a/src/items.rs
+++ b/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;
diff --git a/src/utils.rs b/src/utils.rs
index 47203a0754f..246f7cb2dc3 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -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;
diff --git a/tests/source/expr.rs b/tests/source/expr.rs
index 373e42d67c5..d26c57ebbd0 100644
--- a/tests/source/expr.rs
+++ b/tests/source/expr.rs
@@ -12,5 +12,16 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
                                                      - 50000 * sqrt(-1),
                                                      trivial_value);
     (((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + a +
-             aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))))
+             aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))));
+
+     if  1  + 2 > 0  { let result = 5; result } else { 4};
+
+    if cond() {
+        something();
+    } else  if different_cond() {
+        something_else();
+    } else {
+        // Check subformatting
+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    }
 }
diff --git a/tests/source/struct_lits_visual.rs b/tests/source/struct_lits_visual.rs
index b629ffa1263..f14a56397ec 100644
--- a/tests/source/struct_lits_visual.rs
+++ b/tests/source/struct_lits_visual.rs
@@ -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(),
diff --git a/tests/target/expr.rs b/tests/target/expr.rs
index 25c84511c41..3a8605b7c42 100644
--- a/tests/target/expr.rs
+++ b/tests/target/expr.rs
@@ -13,5 +13,22 @@ fn foo() -> bool {
                                                          trivial_value);
     (((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
              a + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
-             aaaaa)))))))))
+             aaaaa)))))))));
+
+    if 1 + 2 > 0 {
+        let result = 5;
+        result
+    } else {
+        4
+    };
+
+    if cond() {
+        something();
+    } else if different_cond() {
+        something_else();
+    } else {
+        // Check subformatting
+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
+        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    }
 }
diff --git a/tests/target/struct_lits_visual.rs b/tests/target/struct_lits_visual.rs
index 651cd2b883b..248839cb869 100644
--- a/tests/target/struct_lits_visual.rs
+++ b/tests/target/struct_lits_visual.rs
@@ -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.

From 2fda8dd883f5de6989280884a37e408981dfc2ee Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Sun, 19 Jul 2015 22:25:44 +0200
Subject: [PATCH 3/5] Format if-let-else expressions

---
 src/expr.rs          | 61 +++++++++++++++++++++++++++++++++++---------
 tests/source/expr.rs | 14 ++++++++++
 tests/target/expr.rs | 17 ++++++++++++
 3 files changed, 80 insertions(+), 12 deletions(-)

diff --git a/src/expr.rs b/src/expr.rs
index 89846527cff..68b780b414a 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -84,6 +84,16 @@ impl Rewrite for ast::Expr {
                                 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)
             }
@@ -112,9 +122,16 @@ 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()
+    }
+}
+
 fn rewrite_label(label: Option<ast::Ident>) -> String {
     match label {
-        Some(ident) => format!("{}: ", ident.as_str()),
+        Some(ident) => format!("{}: ", ident),
         None => "".to_owned()
     }
 }
@@ -123,23 +140,43 @@ 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> {
     // FIXME: missing comments between control statements and blocks
-    let cond_string = try_opt!(cond.rewrite(context, width - 3 - 2, offset + 3));
-    let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
+    // 3 = "if ", 2 = " {"
+    let pat_string = match pat {
+        Some(pat) => {
+            // 7 = "let ".len() + " = ".len()
+            // 4 = "let ".len()
+            let pat_string = try_opt!(pat.rewrite(context, width - 3 - 2 - 7, offset + 3 + 4));
+            format!("let {} = ", pat_string)
+        }
+        None => String::new()
+    };
 
-    match else_block {
-        Some(else_block) => {
-            else_block.rewrite(context, width, offset).map(|else_block_string| {
-                format!("if {} {} else {}", cond_string, if_block_string, else_block_string)
-            })
-        }
-        None => {
-            Some(format!("if {} {}", cond_string, if_block_string))
-        }
+    // Consider only the last line of the pat string
+    let extra_offset = match pat_string.rfind('\n') {
+        // 1 for newline character
+        Some(idx) => pat_string.len() - idx - 1 - offset,
+        None => 3 + pat_string.len()
+    };
+
+    let cond_string = try_opt!(cond.rewrite(context,
+                                            width - extra_offset - 2,
+                                            offset + extra_offset));
+    let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
+    let mut result = format!("if {}{} {}", pat_string, cond_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_string_lit(context: &RewriteContext,
diff --git a/tests/source/expr.rs b/tests/source/expr.rs
index d26c57ebbd0..19baa90ace2 100644
--- a/tests/source/expr.rs
+++ b/tests/source/expr.rs
@@ -16,6 +16,20 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
 
      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 cond() {
         something();
     } else  if different_cond() {
diff --git a/tests/target/expr.rs b/tests/target/expr.rs
index 3a8605b7c42..86ad2dd406d 100644
--- a/tests/target/expr.rs
+++ b/tests/target/expr.rs
@@ -22,6 +22,23 @@ fn foo() -> bool {
         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 cond() {
         something();
     } else if different_cond() {

From 2fa6220f57228d149f99272a4b3f97b560359738 Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Sun, 19 Jul 2015 23:39:48 +0200
Subject: [PATCH 4/5] Format all the loops!

---
 src/expr.rs          | 176 ++++++++++++++++++++++++++++++++++---------
 src/lib.rs           |   7 +-
 src/lists.rs         |   9 ++-
 src/visitor.rs       |   2 +-
 tests/source/loop.rs |   9 +++
 tests/target/loop.rs |   9 +++
 6 files changed, 171 insertions(+), 41 deletions(-)

diff --git a/src/expr.rs b/src/expr.rs
index 68b780b414a..35bd90f5f32 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -56,21 +56,45 @@ impl Rewrite for ast::Expr {
             ast::Expr_::ExprTup(ref items) => {
                 rewrite_tuple_lit(context, items, self.span, width, offset)
             }
-            ast::Expr_::ExprWhile(ref subexpr, ref block, label) => {
-                let label_string = rewrite_label(label);
-                // 6 = "while "
-                // 2 = " {"
-                let expr_width = width - 6 - 2 - label_string.len();
-                let expr_offset = offset + 6 + label_string.len();
-
-                subexpr.rewrite(context, expr_width, expr_offset).and_then(|expr_string| {
-                    // FIXME: this drops any comment between "loop" and the block.
-                    block.rewrite(context, width, offset).map(|result| {
-                        format!("{}while {} {}", rewrite_label(label), expr_string, result)
-                    })
-                })
+            ast::Expr_::ExprWhile(ref cond, ref block, label) => {
+                rewrite_loop(context,
+                             cond,
+                             block,
+                             label,
+                             None,
+                             "while ",
+                             "let ",
+                             " = ",
+                             width,
+                             offset)
+            }
+            ast::Expr_::ExprWhileLet(ref pat, ref cond, ref block, label) => {
+                rewrite_loop(context,
+                             cond,
+                             block,
+                             label,
+                             Some(pat),
+                             "while ",
+                             "let ",
+                             " = ",
+                             width,
+                             offset)
+            }
+            ast::Expr_::ExprForLoop(ref pat, ref cond, ref block, label) => {
+                rewrite_loop(context,
+                             cond,
+                             block,
+                             label,
+                             Some(pat),
+                             "for ",
+                             "",
+                             " in ",
+                             width,
+                             offset)
             }
             ast::Expr_::ExprLoop(ref block, label) => {
+                // Of all the loops, this is the only one that does not use
+                // rewrite_loop!
                 // FIXME: this drops any comment between "loop" and the block.
                 block.rewrite(context, width, offset).map(|result| {
                     format!("{}loop {}", rewrite_label(label), result)
@@ -97,6 +121,14 @@ impl Rewrite for ast::Expr {
                                 width,
                                 offset)
             }
+            // We reformat it ourselves because rustc gives us a bad span for ranges
+            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()
         }
     }
@@ -136,6 +168,61 @@ fn rewrite_label(label: Option<ast::Ident>) -> String {
     }
 }
 
+// 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))
+}
+
+fn rewrite_loop(context: &RewriteContext,
+                cond: &ast::Expr,
+                block: &ast::Block,
+                label: Option<ast::Ident>,
+                pat: Option<&ast::Pat>,
+                keyword: &str,
+                matcher: &str, // FIXME: think of better identifiers
+                connector: &str,
+                width: usize,
+                offset: usize)
+                -> Option<String> {
+    let label_string = rewrite_label(label);
+    // 2 = " {"
+    let inner_width = width - keyword.len() - 2 - label_string.len();
+    let inner_offset = offset + keyword.len() + label_string.len();
+
+    let pat_expr_string = try_opt!(rewrite_pat_expr(context,
+                                                    pat,
+                                                    cond,
+                                                    matcher,
+                                                    connector,
+                                                    inner_width,
+                                                    inner_offset));
+
+    // FIXME: this drops any comment between "loop" and the block.
+    block.rewrite(context, width, offset).map(|result| {
+        format!("{}{}{} {}", label_string, keyword, pat_expr_string, result)
+    })
+}
+
 fn rewrite_if_else(context: &RewriteContext,
                    cond: &ast::Expr,
                    if_block: &ast::Block,
@@ -144,30 +231,17 @@ fn rewrite_if_else(context: &RewriteContext,
                    width: usize,
                    offset: usize)
                    -> Option<String> {
-    // FIXME: missing comments between control statements and blocks
     // 3 = "if ", 2 = " {"
-    let pat_string = match pat {
-        Some(pat) => {
-            // 7 = "let ".len() + " = ".len()
-            // 4 = "let ".len()
-            let pat_string = try_opt!(pat.rewrite(context, width - 3 - 2 - 7, offset + 3 + 4));
-            format!("let {} = ", pat_string)
-        }
-        None => String::new()
-    };
+    let pat_expr_string = try_opt!(rewrite_pat_expr(context,
+                                                    pat,
+                                                    cond,
+                                                    "let ",
+                                                    " = ",
+                                                    width - 3 - 2,
+                                                    offset + 3));
 
-    // Consider only the last line of the pat string
-    let extra_offset = match pat_string.rfind('\n') {
-        // 1 for newline character
-        Some(idx) => pat_string.len() - idx - 1 - offset,
-        None => 3 + pat_string.len()
-    };
-
-    let cond_string = try_opt!(cond.rewrite(context,
-                                            width - extra_offset - 2,
-                                            offset + extra_offset));
     let if_block_string = try_opt!(if_block.rewrite(context, width, offset));
-    let mut result = format!("if {}{} {}", pat_string, cond_string, if_block_string);
+    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));
@@ -179,6 +253,40 @@ fn rewrite_if_else(context: &RewriteContext,
     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 mut result = match pat {
+        Some(pat) => {
+            let pat_string = try_opt!(pat.rewrite(context,
+                                                  width - connector.len() - matcher.len(),
+                                                  offset + matcher.len()));
+            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()
+    };
+
+    let expr_string = try_opt!(expr.rewrite(context,
+                                            width - extra_offset,
+                                            offset + extra_offset));
+
+    result.push_str(&expr_string);
+
+    Some(result)
+}
+
 fn rewrite_string_lit(context: &RewriteContext,
                       s: &str,
                       span: Span,
diff --git a/src/lib.rs b/src/lib.rs
index a3a0659c292..5ea4812e144 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -218,11 +218,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) {
diff --git a/src/lists.rs b/src/lists.rs
index 155c8ab08cb..13c0cf763e3 100644
--- a/src/lists.rs
+++ b/src/lists.rs
@@ -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);
 
diff --git a/src/visitor.rs b/src/visitor.rs
index ae5b2083ccc..ee5688c14a1 100644
--- a/src/visitor.rs
+++ b/src/visitor.rs
@@ -353,7 +353,7 @@ impl<'a> FmtVisitor<'a> {
 
             result.push_str(&a_str);
 
-            if i < attrs.len() -1 {
+            if i < attrs.len() - 1 {
                 result.push('\n');
             }
         }
diff --git a/tests/source/loop.rs b/tests/source/loop.rs
index 143a3a23760..36e6ab43de8 100644
--- a/tests/source/loop.rs
+++ b/tests/source/loop.rs
@@ -13,4 +13,13 @@ let x = loop { do_forever(); };
 
    while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {
    }
+
+    'b: for xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx in some_iter(arg1, arg2) {
+        // do smth
+    }
+
+    while let  Some(i) =     x.find('s')
+    {
+        x.update();
+    }
 }
diff --git a/tests/target/loop.rs b/tests/target/loop.rs
index cec8b2bff61..e1f2ccc91a4 100644
--- a/tests/target/loop.rs
+++ b/tests/target/loop.rs
@@ -18,4 +18,13 @@ fn main() {
 
     while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa > bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {
     }
+
+    'b: for xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx in some_iter(arg1,
+                                                                                        arg2) {
+        // do smth
+    }
+
+    while let Some(i) = x.find('s') {
+        x.update();
+    }
 }

From c4101de53d8a0707907cb03c67a9224ab9943d37 Mon Sep 17 00:00:00 2001
From: Marcus Klaas <mail@marcusklaas.nl>
Date: Mon, 20 Jul 2015 23:29:25 +0200
Subject: [PATCH 5/5] Refactor some things; add extra tests.

---
 src/config.rs                        |  13 ++
 src/default.toml                     |   1 +
 src/expr.rs                          | 219 +++++++++++++++++----------
 src/imports.rs                       |   8 +-
 src/lib.rs                           |   3 +-
 tests/config/expr_visual_indent.toml |  16 ++
 tests/config/reorder_imports.toml    |   1 +
 tests/config/small_tabs.toml         |   1 +
 tests/config/visual_struct_lits.toml |   1 +
 tests/source/expr-visual-indent.rs   |   9 ++
 tests/source/expr.rs                 |  24 +++
 tests/source/struct_lits.rs          |  11 ++
 tests/target/expr-visual-indent.rs   |   9 ++
 tests/target/expr.rs                 |  44 ++++++
 tests/target/struct_lits.rs          |  20 ++-
 15 files changed, 292 insertions(+), 88 deletions(-)
 create mode 100644 tests/config/expr_visual_indent.toml
 create mode 100644 tests/source/expr-visual-indent.rs
 create mode 100644 tests/target/expr-visual-indent.rs

diff --git a/src/config.rs b/src/config.rs
index a01d3e64689..3d41b51661e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -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 {
diff --git a/src/default.toml b/src/default.toml
index e31a0f257e9..035fa21e917 100644
--- a/src/default.toml
+++ b/src/default.toml
@@ -13,3 +13,4 @@ enum_trailing_comma = true
 report_todo = "Always"
 report_fixme = "Never"
 reorder_imports = false
+expr_indent_style = "Tabbed"
diff --git a/src/expr.rs b/src/expr.rs
index 35bd90f5f32..e81314eba79 100644
--- a/src/expr.rs
+++ b/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};
@@ -57,48 +58,16 @@ impl Rewrite for ast::Expr {
                 rewrite_tuple_lit(context, items, self.span, width, offset)
             }
             ast::Expr_::ExprWhile(ref cond, ref block, label) => {
-                rewrite_loop(context,
-                             cond,
-                             block,
-                             label,
-                             None,
-                             "while ",
-                             "let ",
-                             " = ",
-                             width,
-                             offset)
+                Loop::new_while(None, cond, block, label).rewrite(context, width, offset)
             }
             ast::Expr_::ExprWhileLet(ref pat, ref cond, ref block, label) => {
-                rewrite_loop(context,
-                             cond,
-                             block,
-                             label,
-                             Some(pat),
-                             "while ",
-                             "let ",
-                             " = ",
-                             width,
-                             offset)
+                Loop::new_while(Some(pat), cond, block, label).rewrite(context, width, offset)
             }
             ast::Expr_::ExprForLoop(ref pat, ref cond, ref block, label) => {
-                rewrite_loop(context,
-                             cond,
-                             block,
-                             label,
-                             Some(pat),
-                             "for ",
-                             "",
-                             " in ",
-                             width,
-                             offset)
+                Loop::new_for(pat, cond, block, label).rewrite(context, width, offset)
             }
             ast::Expr_::ExprLoop(ref block, label) => {
-                // Of all the loops, this is the only one that does not use
-                // rewrite_loop!
-                // FIXME: this drops any comment between "loop" and the block.
-                block.rewrite(context, width, offset).map(|result| {
-                    format!("{}loop {}", rewrite_label(label), result)
-                })
+                Loop::new_loop(block, label).rewrite(context, width, offset)
             }
             ast::Expr_::ExprBlock(ref block) => {
                 block.rewrite(context, width, offset)
@@ -121,7 +90,8 @@ impl Rewrite for ast::Expr {
                                 width,
                                 offset)
             }
-            // We reformat it ourselves because rustc gives us a bad span for ranges
+            // 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),
@@ -161,6 +131,91 @@ impl Rewrite for ast::Pat {
     }
 }
 
+// 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),
@@ -193,36 +248,8 @@ fn rewrite_range(context: &RewriteContext,
     Some(format!("{}..{}", left_string, right_string))
 }
 
-fn rewrite_loop(context: &RewriteContext,
-                cond: &ast::Expr,
-                block: &ast::Block,
-                label: Option<ast::Ident>,
-                pat: Option<&ast::Pat>,
-                keyword: &str,
-                matcher: &str, // FIXME: think of better identifiers
-                connector: &str,
-                width: usize,
-                offset: usize)
-                -> Option<String> {
-    let label_string = rewrite_label(label);
-    // 2 = " {"
-    let inner_width = width - keyword.len() - 2 - label_string.len();
-    let inner_offset = offset + keyword.len() + label_string.len();
-
-    let pat_expr_string = try_opt!(rewrite_pat_expr(context,
-                                                    pat,
-                                                    cond,
-                                                    matcher,
-                                                    connector,
-                                                    inner_width,
-                                                    inner_offset));
-
-    // FIXME: this drops any comment between "loop" and the block.
-    block.rewrite(context, width, offset).map(|result| {
-        format!("{}{}{} {}", label_string, keyword, pat_expr_string, result)
-    })
-}
-
+// 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,
@@ -236,7 +263,7 @@ fn rewrite_if_else(context: &RewriteContext,
                                                     pat,
                                                     cond,
                                                     "let ",
-                                                    " = ",
+                                                    " =",
                                                     width - 3 - 2,
                                                     offset + 3));
 
@@ -261,28 +288,49 @@ fn rewrite_pat_expr(context: &RewriteContext,
                     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(),
-                                                  offset + matcher.len()));
+                                                  pat_offset));
             format!("{}{}{}", matcher, pat_string, connector)
         }
         None => String::new()
     };
 
-    // Consider only the last line of the pat string
+    // 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()
     };
 
-    let expr_string = try_opt!(expr.rewrite(context,
-                                            width - extra_offset,
-                                            offset + extra_offset));
+    // The expression may (partionally) fit on the current line.
+    if width > extra_offset + 1 {
+        let mut corrected_offset = extra_offset;
 
-    result.push_str(&expr_string);
+        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)
 }
@@ -333,6 +381,8 @@ fn rewrite_call(context: &RewriteContext,
     // 2 is for parens.
     let remaining_width = width - 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(),
@@ -342,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),
@@ -361,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,
@@ -391,17 +449,18 @@ 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)
         }
     };
 
diff --git a/src/imports.rs b/src/imports.rs
index 66bf26b041d..12ce3368eb3 100644
--- a/src/imports.rs
+++ b/src/imports.rs
@@ -123,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)
+            })
     }
 }
 
diff --git a/src/lib.rs b/src/lib.rs
index 5ea4812e144..7c36229e774 100644
--- a/src/lib.rs
+++ b/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;
diff --git a/tests/config/expr_visual_indent.toml b/tests/config/expr_visual_indent.toml
new file mode 100644
index 00000000000..38a099e3bed
--- /dev/null
+++ b/tests/config/expr_visual_indent.toml
@@ -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"
diff --git a/tests/config/reorder_imports.toml b/tests/config/reorder_imports.toml
index ddab2479f2c..5b1ce49a2f2 100644
--- a/tests/config/reorder_imports.toml
+++ b/tests/config/reorder_imports.toml
@@ -13,3 +13,4 @@ enum_trailing_comma = true
 report_todo = "Always"
 report_fixme = "Never"
 reorder_imports = true
+expr_indent_style = "Tabbed"
diff --git a/tests/config/small_tabs.toml b/tests/config/small_tabs.toml
index 303433dbcc1..b2c7f5fc43f 100644
--- a/tests/config/small_tabs.toml
+++ b/tests/config/small_tabs.toml
@@ -13,3 +13,4 @@ enum_trailing_comma = true
 report_todo = "Always"
 report_fixme = "Never"
 reorder_imports = false
+expr_indent_style = "Tabbed"
diff --git a/tests/config/visual_struct_lits.toml b/tests/config/visual_struct_lits.toml
index cf601303e9b..61bf4b0aee5 100644
--- a/tests/config/visual_struct_lits.toml
+++ b/tests/config/visual_struct_lits.toml
@@ -13,3 +13,4 @@ enum_trailing_comma = true
 report_todo = "Always"
 report_fixme = "Never"
 reorder_imports = false
+expr_indent_style = "Tabbed"
diff --git a/tests/source/expr-visual-indent.rs b/tests/source/expr-visual-indent.rs
new file mode 100644
index 00000000000..c173d7bd7c4
--- /dev/null
+++ b/tests/source/expr-visual-indent.rs
@@ -0,0 +1,9 @@
+// rustfmt-config: expr_visual_indent.toml
+
+// Visual level block indentation.
+
+fn matcher() {
+    Some(while true {
+        test();
+    })
+}
\ No newline at end of file
diff --git a/tests/source/expr.rs b/tests/source/expr.rs
index 19baa90ace2..1c063cf7f9d 100644
--- a/tests/source/expr.rs
+++ b/tests/source/expr.rs
@@ -14,6 +14,10 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
     (((((((((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + a +
              aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + aaaaa)))))))));
 
+    { for _ in 0..10 {} }
+
+    {{{{}}}}
+
      if  1  + 2 > 0  { let result = 5; result } else { 4};
 
     if  let   Some(x)  =  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {
@@ -30,6 +34,10 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
     if let (some_very_large,
             tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1111 + 2222 {}
 
+    if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) = 1
+ + 2 + 3 {
+    }
+
     if cond() {
         something();
     } else  if different_cond() {
@@ -39,3 +47,19 @@ some_ridiculously_loooooooooooooooooooooong_function(10000 * 30000000000 + 40000
         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);
+}
diff --git a/tests/source/struct_lits.rs b/tests/source/struct_lits.rs
index f2726821e55..54f2ea5441b 100644
--- a/tests/source/struct_lits.rs
+++ b/tests/source/struct_lits.rs
@@ -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",
+    },
+    };
+}
diff --git a/tests/target/expr-visual-indent.rs b/tests/target/expr-visual-indent.rs
new file mode 100644
index 00000000000..3488e8c93c0
--- /dev/null
+++ b/tests/target/expr-visual-indent.rs
@@ -0,0 +1,9 @@
+// rustfmt-config: expr_visual_indent.toml
+
+// Visual level block indentation.
+
+fn matcher() {
+    Some(while true {
+             test();
+         })
+}
diff --git a/tests/target/expr.rs b/tests/target/expr.rs
index 86ad2dd406d..9fa32048e3f 100644
--- a/tests/target/expr.rs
+++ b/tests/target/expr.rs
@@ -15,6 +15,20 @@ fn foo() -> bool {
              a + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
              aaaaa)))))))));
 
+    {
+        for _ in 0..10 {
+        }
+    }
+
+    {
+        {
+            {
+                {
+                }
+            }
+        }
+    }
+
     if 1 + 2 > 0 {
         let result = 5;
         result
@@ -39,6 +53,10 @@ fn foo() -> bool {
                                                                                          2222 {
     }
 
+    if let (some_very_large, tuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuple) =
+           1 + 2 + 3 {
+    }
+
     if cond() {
         something();
     } else if different_cond() {
@@ -49,3 +67,29 @@ fn foo() -> bool {
         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);
+}
diff --git a/tests/target/struct_lits.rs b/tests/target/struct_lits.rs
index 293a2a97b7a..9f7ab5cb428 100644
--- a/tests/target/struct_lits.rs
+++ b/tests/target/struct_lits.rs
@@ -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",
+        },
+    };
+}