]> git.lizzy.rs Git - rust.git/blobdiff - src/items.rs
Remove BlockIndentStyle::Inherit
[rust.git] / src / items.rs
index 91fd91ef958d079e83655799b12d2dd39e4eab35..445959f63b0a004f65b1b20b4bae1655e3edb911 100644 (file)
 use {Indent, Shape};
 use codemap::SpanUtils;
 use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
-            last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr};
-use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
+            last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr,
+            trimmed_last_line_width};
+use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic, list_helper,
             DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, type_annotation_separator};
 use comment::{FindUncommented, contains_comment};
 use visitor::FmtVisitor;
 use rewrite::{Rewrite, RewriteContext};
-use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle};
+use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle, Style};
 use itertools::Itertools;
 
 use syntax::{ast, abi, codemap, ptr, symbol};
@@ -190,6 +191,7 @@ fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
                                               &item.vis,
                                               span,
                                               false,
+                                              false,
                                               false);
 
                 match rewrite {
@@ -257,7 +259,8 @@ pub fn rewrite_fn(&mut self,
                                                                          vis,
                                                                          span,
                                                                          newline_brace,
-                                                                         has_body));
+                                                                         has_body,
+                                                                         true));
 
         if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
             newline_brace = false;
@@ -302,6 +305,7 @@ pub fn rewrite_required_fn(&mut self,
                                                        &ast::Visibility::Inherited,
                                                        span,
                                                        false,
+                                                       false,
                                                        false));
 
         // Re-attach semicolon
@@ -520,13 +524,13 @@ pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -
         let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
         let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                              &generics.where_clause,
-                                                             context.config,
                                                              context.config.item_brace_style,
                                                              Shape::legacy(where_budget,
                                                                            offset.block_only()),
                                                              context.config.where_density,
                                                              "{",
                                                              false,
+                                                             last_line_width(&ref_and_type) == 1,
                                                              None));
 
         if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
@@ -625,7 +629,7 @@ fn format_impl_ref_and_type(context: &RewriteContext,
         item.node {
         let mut result = String::new();
 
-        result.push_str(&*format_visibility(&item.vis));
+        result.push_str(&format_visibility(&item.vis));
         result.push_str(format_unsafety(unsafety));
         result.push_str("impl");
 
@@ -649,8 +653,9 @@ fn format_impl_ref_and_type(context: &RewriteContext,
             if polarity != ast::ImplPolarity::Negative {
                 result.push_str(" ");
             }
-            let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
-            let indent = offset + result.len();
+            let used_space = last_line_width(&result);
+            let budget = try_opt!(context.config.max_width.checked_sub(used_space));
+            let indent = offset + used_space;
             result.push_str(&*try_opt!(trait_ref.rewrite(context, Shape::legacy(budget, indent))));
 
             if split_at_for {
@@ -763,7 +768,7 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         // If the trait, generics, and trait bound cannot fit on the same line,
         // put the trait bounds on an indented new line
         if offset.width() + last_line_width(&result) + trait_bound_str.len() >
-           context.config.ideal_width {
+           context.config.comment_width {
             result.push('\n');
             let trait_indent = offset.block_only().block_indent(context.config);
             result.push_str(&trait_indent.to_string(context.config));
@@ -787,19 +792,20 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent)
         let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
         let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                              &generics.where_clause,
-                                                             context.config,
                                                              context.config.item_brace_style,
                                                              Shape::legacy(where_budget,
                                                                            offset.block_only()),
                                                              where_density,
                                                              "{",
                                                              !has_body,
+                                                             trait_bound_str.is_empty() &&
+                                                             last_line_width(&generics_str) == 1,
                                                              None));
         // If the where clause cannot fit on the same line,
         // put the where clause on a new line
         if !where_clause_str.contains('\n') &&
            last_line_width(&result) + where_clause_str.len() + offset.width() >
-           context.config.ideal_width {
+           context.config.comment_width {
             result.push('\n');
             let width = offset.block_indent + context.config.tab_spaces - 1;
             let where_indent = Indent::new(0, width);
@@ -1002,21 +1008,29 @@ fn format_tuple_struct(context: &RewriteContext,
                 try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
             try_opt!(rewrite_where_clause(context,
                                           &generics.where_clause,
-                                          context.config,
                                           context.config.item_brace_style,
                                           Shape::legacy(where_budget, offset.block_only()),
                                           Density::Compressed,
                                           ";",
                                           true,
+                                          false,
                                           None))
         }
         None => "".to_owned(),
     };
-    result.push('(');
 
-    let item_indent = offset.block_only() + result.len();
-    // 2 = ");"
-    let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
+    let (tactic, item_indent) = match context.config.fn_args_layout {
+        FnArgLayoutStyle::Visual => {
+            // 1 = `(`
+            (ListTactic::HorizontalVertical, offset.block_only() + result.len() + 1)
+        }
+        FnArgLayoutStyle::Block |
+        FnArgLayoutStyle::BlockAlways => {
+            (ListTactic::HorizontalVertical, offset.block_only().block_indent(&context.config))
+        }
+    };
+    // 3 = `();`
+    let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 3));
 
     let items =
         itemize_list(context.codemap,
@@ -1034,27 +1048,41 @@ fn format_tuple_struct(context: &RewriteContext,
                      |field| field.rewrite(context, Shape::legacy(item_budget, item_indent)),
                      context.codemap.span_after(span, "("),
                      span.hi);
-    let body = try_opt!(format_item_list(items,
-                                         Shape::legacy(item_budget, item_indent),
-                                         context.config));
-
-    if context.config.spaces_within_parens && body.len() > 0 {
-        result.push(' ');
-    }
+    let body_budget = try_opt!(context.config.max_width.checked_sub(offset.block_only().width() +
+                                                                    result.len() +
+                                                                    3));
+    let body = try_opt!(list_helper(items,
+                                    // TODO budget is wrong in block case
+                                    Shape::legacy(body_budget, item_indent),
+                                    context.config,
+                                    tactic));
+
+    if context.config.fn_args_layout == FnArgLayoutStyle::Visual || !body.contains('\n') {
+        result.push('(');
+        if context.config.spaces_within_parens && body.len() > 0 {
+            result.push(' ');
+        }
 
-    result.push_str(&body);
+        result.push_str(&body);
 
-    if context.config.spaces_within_parens && body.len() > 0 {
-        result.push(' ');
+        if context.config.spaces_within_parens && body.len() > 0 {
+            result.push(' ');
+        }
+        result.push(')');
+    } else {
+        result.push_str("(\n");
+        result.push_str(&item_indent.to_string(&context.config));
+        result.push_str(&body);
+        result.push('\n');
+        result.push_str(&offset.block_only().to_string(&context.config));
+        result.push(')');
     }
 
-    result.push(')');
-
     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
        (result.contains('\n') ||
         offset.block_indent + result.len() + where_clause_str.len() + 1 >
         context.config.max_width) {
-        // We need to put the where clause on a new line, but we didn'to_string
+        // We need to put the where clause on a new line, but we didn't
         // know that earlier, so the where clause will not be indented properly.
         result.push('\n');
         result.push_str(&(offset.block_only() + (context.config.tab_spaces - 1))
@@ -1093,12 +1121,12 @@ pub fn rewrite_type_alias(context: &RewriteContext,
     let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
     let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                          &generics.where_clause,
-                                                         context.config,
                                                          context.config.item_brace_style,
                                                          Shape::legacy(where_budget, indent),
                                                          context.config.where_density,
                                                          "=",
                                                          true,
+                                                         true,
                                                          Some(span.hi)));
     result.push_str(&where_clause_str);
     result.push_str(" = ");
@@ -1430,7 +1458,8 @@ fn rewrite_fn_base(context: &RewriteContext,
                    vis: &ast::Visibility,
                    span: Span,
                    newline_brace: bool,
-                   has_body: bool)
+                   has_body: bool,
+                   has_braces: bool)
                    -> Option<(String, bool)> {
     let mut force_new_line_for_brace = false;
 
@@ -1468,7 +1497,9 @@ fn rewrite_fn_base(context: &RewriteContext,
                                                  generics_span));
     result.push_str(&generics_str);
 
-    // Note that if the width and indent really matter, we'll re-layout the
+    let snuggle_angle_bracket = last_line_width(&generics_str) == 1;
+
+    // Note that the width and indent don't really matter, we'll re-layout the
     // return type later anyway.
     let ret_str = try_opt!(fd.output.rewrite(&context,
                                              Shape::legacy(context.config.max_width -
@@ -1495,7 +1526,9 @@ fn rewrite_fn_base(context: &RewriteContext,
 
     // Check if vertical layout was forced.
     if one_line_budget == 0 {
-        if context.config.fn_args_paren_newline {
+        if snuggle_angle_bracket {
+            result.push_str("(");
+        } else if context.config.fn_args_paren_newline {
             result.push('\n');
             result.push_str(&arg_indent.to_string(context.config));
             arg_indent = arg_indent + 1; // extra space for `(`
@@ -1535,7 +1568,7 @@ fn rewrite_fn_base(context: &RewriteContext,
     let multi_line_arg_str = arg_str.contains('\n');
 
     let put_args_in_block = match context.config.fn_args_layout {
-        FnArgLayoutStyle::Block => multi_line_arg_str,
+        FnArgLayoutStyle::Block => multi_line_arg_str || generics_str.contains('\n'),
         FnArgLayoutStyle::BlockAlways => true,
         _ => false,
     } && !fd.inputs.is_empty();
@@ -1602,7 +1635,7 @@ fn rewrite_fn_base(context: &RewriteContext,
             Indent::new(indent.width(), result.len())
         };
 
-        if multi_line_ret_str {
+        if multi_line_ret_str || ret_should_indent {
             // Now that we know the proper indent and width, we need to
             // re-layout the return type.
             let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
@@ -1635,29 +1668,41 @@ fn rewrite_fn_base(context: &RewriteContext,
         _ => false,
     } || (put_args_in_block && ret_str.is_empty());
 
-    let where_density = if should_compress_where {
-        Density::Compressed
-    } else {
-        Density::Tall
-    };
+    if where_clause.predicates.len() == 1 && should_compress_where {
+        let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
+        if let Some(where_clause_str) =
+            rewrite_where_clause(context,
+                                 where_clause,
+                                 context.config.fn_brace_style,
+                                 Shape::legacy(budget, indent),
+                                 Density::Compressed,
+                                 "{",
+                                 !has_braces,
+                                 put_args_in_block && ret_str.is_empty(),
+                                 Some(span.hi)) {
+            if !where_clause_str.contains('\n') {
+                if last_line_width(&result) + where_clause_str.len() > context.config.max_width {
+                    result.push('\n');
+                }
 
-    // Where clause.
-    let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
+                result.push_str(&where_clause_str);
+
+                return Some((result, force_new_line_for_brace));
+            }
+        }
+    }
+
+    let budget = try_opt!(context.config.max_width.checked_sub(indent.block_indent));
     let where_clause_str = try_opt!(rewrite_where_clause(context,
                                                          where_clause,
-                                                         context.config,
                                                          context.config.fn_brace_style,
-                                                         Shape::legacy(where_budget, indent),
-                                                         where_density,
+                                                         Shape::legacy(budget, indent),
+                                                         Density::Tall,
                                                          "{",
-                                                         !has_body,
+                                                         !has_braces,
+                                                         put_args_in_block && ret_str.is_empty(),
                                                          Some(span.hi)));
 
-    if last_line_width(&result) + where_clause_str.len() > context.config.max_width &&
-       !where_clause_str.contains('\n') {
-        result.push('\n');
-    }
-
     result.push_str(&where_clause_str);
 
     Some((result, force_new_line_for_brace))
@@ -1761,7 +1806,6 @@ enum ArgumentKind<'a> {
     }
 
     let indent = match context.config.fn_arg_indent {
-        BlockIndentStyle::Inherit => indent,
         BlockIndentStyle::Tabbed => indent.block_indent(context.config),
         BlockIndentStyle::Visual => arg_indent,
     };
@@ -1776,16 +1820,16 @@ enum ArgumentKind<'a> {
 
     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
 
-    let end_with_newline = match context.config.fn_args_layout {
-        FnArgLayoutStyle::Block |
-        FnArgLayoutStyle::BlockAlways => true,
-        _ => false,
+    let (trailing_comma, end_with_newline) = match context.config.fn_args_layout {
+        FnArgLayoutStyle::Block => (SeparatorTactic::Vertical, true),
+        FnArgLayoutStyle::BlockAlways => (SeparatorTactic::Always, true),
+        _ => (SeparatorTactic::Never, false),
     };
 
     let fmt = ListFormatting {
         tactic: tactic,
         separator: ",",
-        trailing_separator: SeparatorTactic::Never,
+        trailing_separator: trailing_comma,
         shape: Shape::legacy(budget, indent),
         ends_with_newline: end_with_newline,
         config: context.config,
@@ -1870,7 +1914,6 @@ fn rewrite_generics(context: &RewriteContext,
     }
 
     let offset = match context.config.generics_indent {
-        BlockIndentStyle::Inherit => shape.indent,
         BlockIndentStyle::Tabbed => shape.indent.block_indent(context.config),
         // 1 = <
         BlockIndentStyle::Visual => generics_offset + 1,
@@ -1907,11 +1950,18 @@ fn rewrite_generics(context: &RewriteContext,
     let list_str =
         try_opt!(format_item_list(items, Shape::legacy(h_budget, offset), context.config));
 
-    Some(if context.config.spaces_within_angle_brackets {
-             format!("< {} >", list_str)
-         } else {
-             format!("<{}>", list_str)
-         })
+    let result = if context.config.generics_indent != BlockIndentStyle::Visual &&
+                    list_str.contains('\n') {
+        format!("<\n{}{}\n{}>",
+                offset.to_string(context.config),
+                list_str,
+                shape.indent.to_string(context.config))
+    } else if context.config.spaces_within_angle_brackets {
+        format!("< {} >", list_str)
+    } else {
+        format!("<{}>", list_str)
+    };
+    Some(result)
 }
 
 fn rewrite_trait_bounds(context: &RewriteContext,
@@ -1935,28 +1985,101 @@ fn rewrite_trait_bounds(context: &RewriteContext,
     Some(result)
 }
 
+//   fn reflow_list_node_with_rule(
+//        &self,
+//        node: &CompoundNode,
+//        rule: &Rule,
+//        args: &[Arg],
+//        shape: &Shape
+//    ) -> Result<String, ()>
+//    where
+//        T: Foo,
+//    {
+
+
+fn rewrite_where_clause_rfc_style(context: &RewriteContext,
+                                  where_clause: &ast::WhereClause,
+                                  shape: Shape,
+                                  terminator: &str,
+                                  suppress_comma: bool,
+                                  // where clause can be kept on the current line.
+                                  snuggle: bool,
+                                  span_end: Option<BytePos>)
+                                  -> Option<String> {
+    let block_shape = shape.block();
+
+    let starting_newline = if snuggle {
+        " ".to_owned()
+    } else {
+        "\n".to_owned() + &block_shape.indent.to_string(context.config)
+    };
+
+    let clause_shape = block_shape.block_indent(context.config.tab_spaces);
+    // each clause on one line, trailing comma (except if suppress_comma)
+    let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
+    // If we don't have the start of the next span, then use the end of the
+    // predicates, but that means we miss comments.
+    let len = where_clause.predicates.len();
+    let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
+    let span_end = span_end.unwrap_or(end_of_preds);
+    let items = itemize_list(context.codemap,
+                             where_clause.predicates.iter(),
+                             terminator,
+                             |pred| span_for_where_pred(pred).lo,
+                             |pred| span_for_where_pred(pred).hi,
+                             |pred| pred.rewrite(context, clause_shape),
+                             span_start,
+                             span_end);
+    let comma_tactic = if suppress_comma {
+        SeparatorTactic::Never
+    } else {
+        SeparatorTactic::Always
+    };
+
+    let fmt = ListFormatting {
+        tactic: DefinitiveListTactic::Vertical,
+        separator: ",",
+        trailing_separator: comma_tactic,
+        shape: clause_shape,
+        ends_with_newline: true,
+        config: context.config,
+    };
+    let preds_str = try_opt!(write_list(items, &fmt));
+
+    Some(format!("{}where\n{}{}",
+                 starting_newline,
+                 clause_shape.indent.to_string(context.config),
+                 preds_str))
+}
+
 fn rewrite_where_clause(context: &RewriteContext,
                         where_clause: &ast::WhereClause,
-                        config: &Config,
                         brace_style: BraceStyle,
                         shape: Shape,
                         density: Density,
                         terminator: &str,
                         suppress_comma: bool,
+                        snuggle: bool,
                         span_end: Option<BytePos>)
                         -> Option<String> {
     if where_clause.predicates.is_empty() {
         return Some(String::new());
     }
 
-    let extra_indent = match context.config.where_indent {
-        BlockIndentStyle::Inherit => Indent::empty(),
-        BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces, 0),
-    };
+    if context.config.where_style == Style::Rfc {
+        return rewrite_where_clause_rfc_style(context,
+                                              where_clause,
+                                              shape,
+                                              terminator,
+                                              suppress_comma,
+                                              snuggle,
+                                              span_end);
+    }
+
+    let extra_indent = Indent::new(context.config.tab_spaces, 0);
 
     let offset = match context.config.where_pred_indent {
-        BlockIndentStyle::Inherit => shape.indent + extra_indent,
-        BlockIndentStyle::Tabbed => shape.indent + extra_indent.block_indent(config),
+        BlockIndentStyle::Tabbed => shape.indent + extra_indent.block_indent(context.config),
         // 6 = "where ".len()
         BlockIndentStyle::Visual => shape.indent + extra_indent + 6,
     };
@@ -2044,18 +2167,21 @@ fn format_generics(context: &RewriteContext,
 
     if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
         let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
-        let where_clause_str = try_opt!(rewrite_where_clause(context,
-                                                             &generics.where_clause,
-                                                             context.config,
-                                                             brace_style,
-                                                             Shape::legacy(budget,
-                                                                           offset.block_only()),
-                                                             Density::Tall,
-                                                             terminator,
-                                                             false,
-                                                             Some(span.hi)));
+        let where_clause_str =
+            try_opt!(rewrite_where_clause(context,
+                                          &generics.where_clause,
+                                          brace_style,
+                                          Shape::legacy(budget, offset.block_only()),
+                                          Density::Tall,
+                                          terminator,
+                                          false,
+                                          trimmed_last_line_width(&result) == 1,
+                                          Some(span.hi)));
         result.push_str(&where_clause_str);
-        if !force_same_line_brace &&
+        let same_line_brace = force_same_line_brace ||
+                              (generics.where_clause.predicates.is_empty() &&
+                               trimmed_last_line_width(&result) == 1);
+        if !same_line_brace &&
            (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
             result.push('\n');
             result.push_str(&offset.block_only().to_string(context.config));
@@ -2064,11 +2190,12 @@ fn format_generics(context: &RewriteContext,
         }
         result.push_str(opener);
     } else {
-        if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
+        if force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
+           brace_style != BraceStyle::AlwaysNextLine {
+            result.push(' ');
+        } else {
             result.push('\n');
             result.push_str(&offset.block_only().to_string(context.config));
-        } else {
-            result.push(' ');
         }
         result.push_str(opener);
     }