diff --git a/src/expr.rs b/src/expr.rs index aa5913e5f0fa..04778b6ddcab 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -2063,12 +2063,12 @@ fn rewrite_struct_lit<'a>(context: &RewriteContext, // FIXME if context.config.struct_lit_style() == Visual, but we run out // of space, we should fall back to BlockIndent. } + pub fn struct_lit_field_separator(config: &Config) -> &str { colon_spaces(config.space_before_struct_lit_field_colon(), config.space_after_struct_lit_field_colon()) } - fn rewrite_field(context: &RewriteContext, field: &ast::Field, shape: Shape) -> Option { let name = &field.ident.node.to_string(); if field.is_shorthand { diff --git a/src/items.rs b/src/items.rs index 10ab6fe72dfe..78226624c4f0 100644 --- a/src/items.rs +++ b/src/items.rs @@ -21,7 +21,8 @@ use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs}; use comment::{FindUncommented, contains_comment, rewrite_comment, recover_comment_removed}; use visitor::FmtVisitor; use rewrite::{Rewrite, RewriteContext}; -use config::{Config, IndentStyle, Density, ReturnIndent, BraceStyle, Style, TypeDensity}; +use config::{Config, IndentStyle, Density, ReturnIndent, BraceStyle, Style}; +use types::join_bounds; use syntax::{ast, abi, ptr, symbol}; use syntax::codemap::{Span, BytePos}; @@ -666,7 +667,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, context.config), 0); let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, mk_sp(lo, hi))); + try_opt!(rewrite_generics_inner(context, generics, shape, shape.width, mk_sp(lo, hi))); let polarity_str = if polarity == ast::ImplPolarity::Negative { "!" @@ -684,7 +685,7 @@ fn format_impl_ref_and_type(context: &RewriteContext, &mut result); if !success { let generics_str = - try_opt!(rewrite_generics(context, generics, shape, 0, mk_sp(lo, hi))); + try_opt!(rewrite_generics_inner(context, generics, shape, 0, mk_sp(lo, hi))); if !format_trait_ref_then_update_result(context, &trait_ref, offset, @@ -839,15 +840,9 @@ pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) let body_lo = context.codemap.span_after(item.span, "{"); - let generics_indent = offset + last_line_width(&result); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, context.config), - 0); - let generics_str = try_opt!(rewrite_generics(context, - generics, - shape, - shape.width, - mk_sp(item.span.lo, body_lo))); + let shape = Shape::indented(offset + last_line_width(&result), context.config); + let generics_str = + try_opt!(rewrite_generics(context, generics, shape, mk_sp(item.span.lo, body_lo))); result.push_str(&generics_str); let trait_bound_str = @@ -1091,16 +1086,9 @@ fn format_tuple_struct(context: &RewriteContext, let where_clause_str = match generics { Some(generics) => { - let generics_indent = offset + last_line_width(&header_str); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, - context.config), - 0); - let generics_str = try_opt!(rewrite_generics(context, - generics, - shape, - shape.width, - mk_sp(span.lo, body_lo))); + let shape = Shape::indented(offset + last_line_width(&header_str), context.config); + let g_span = mk_sp(span.lo, body_lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let where_budget = try_opt!(context @@ -1227,16 +1215,10 @@ pub fn rewrite_type_alias(context: &RewriteContext, result.push_str("type "); result.push_str(&ident.to_string()); - let generics_indent = indent + result.len(); - let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo); - let shape = generics_shape_from_config(context.config, - try_opt!(Shape::indented(generics_indent, - context.config) - .sub_width(" =".len())), - 0); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); - + // 2 = `= ` + let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2)); + let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let where_budget = try_opt!(context @@ -1470,23 +1452,14 @@ pub fn rewrite_associated_type(ident: ast::Ident, let prefix = format!("type {}", ident); let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; + let shape = Shape::legacy(context.config.max_width(), indent); let bounds: &[_] = ty_param_bounds; - let bound_str = - try_opt!(bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(context.config.max_width(), - indent)) - }) - .collect::>>()) - .join(joiner); + let bound_str = try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, shape)) + .collect::>>()); if bounds.len() > 0 { - format!(": {}", bound_str) + format!(": {}", join_bounds(context, shape, &bound_str)) } else { String::new() } @@ -1711,13 +1684,9 @@ fn rewrite_fn_base(context: &RewriteContext, result.push_str(&ident.to_string()); // Generics. - let generics_indent = indent + last_line_width(&result); - let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo); - let shape = generics_shape_from_config(context.config, - Shape::indented(generics_indent, context.config), - 0); - let generics_str = - try_opt!(rewrite_generics(context, generics, shape, shape.width, generics_span)); + let shape = Shape::indented(indent + last_line_width(&result), context.config); + let g_span = mk_sp(span.lo, span_for_return(&fd.output).lo); + let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span)); result.push_str(&generics_str); let snuggle_angle_bracket = generics_str @@ -2182,9 +2151,19 @@ fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool { fn rewrite_generics(context: &RewriteContext, generics: &ast::Generics, shape: Shape, - one_line_width: usize, span: Span) -> Option { + let shape = generics_shape_from_config(context.config, shape, 0); + rewrite_generics_inner(context, generics, shape, shape.width, span) + .or_else(|| rewrite_generics_inner(context, generics, shape, 0, span)) +} + +fn rewrite_generics_inner(context: &RewriteContext, + generics: &ast::Generics, + shape: Shape, + one_line_width: usize, + span: Span) + -> Option { // FIXME: convert bounds to where clauses where they get too big or if // there is a where clause at all. let lifetimes: &[_] = &generics.lifetimes; @@ -2286,20 +2265,11 @@ fn rewrite_trait_bounds(context: &RewriteContext, if bounds.is_empty() { return Some(String::new()); } - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let bound_str = try_opt!(bounds .iter() .map(|ty_bound| ty_bound.rewrite(&context, shape)) - .collect::>>()) - .join(joiner); - - let mut result = String::new(); - result.push_str(": "); - result.push_str(&bound_str); - Some(result) + .collect::>>()); + Some(format!(": {}", join_bounds(context, shape, &bound_str))) } fn rewrite_where_clause_rfc_style(context: &RewriteContext, @@ -2463,9 +2433,8 @@ fn format_generics(context: &RewriteContext, offset: Indent, span: Span) -> Option { - let shape = - generics_shape_from_config(context.config, Shape::indented(offset, context.config), 0); - let mut result = try_opt!(rewrite_generics(context, generics, shape, shape.width, span)); + let shape = Shape::indented(offset, context.config); + let mut result = try_opt!(rewrite_generics(context, generics, shape, span)); if !generics.where_clause.predicates.is_empty() || result.contains('\n') { let budget = try_opt!(context diff --git a/src/types.rs b/src/types.rs index 4e74ea8213f1..d2405f390f1d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -22,7 +22,7 @@ use codemap::SpanUtils; use items::{format_generics_item_list, generics_shape_from_config}; use lists::{itemize_list, format_fn_args}; use rewrite::{Rewrite, RewriteContext}; -use utils::{extra_offset, format_mutability, colon_spaces, wrap_str, mk_sp}; +use utils::{extra_offset, format_mutability, colon_spaces, wrap_str, mk_sp, last_line_width}; use expr::{rewrite_unary_prefix, rewrite_pair, rewrite_tuple_type}; use config::TypeDensity; @@ -362,22 +362,15 @@ impl Rewrite for ast::WherePredicate { .collect::>>()) .join(", "); - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; // 6 = "for<> ".len() let used_width = lifetime_str.len() + type_str.len() + colon.len() + 6; - let budget = try_opt!(shape.width.checked_sub(used_width)); - let bounds_str: String = try_opt!( - bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(budget, shape.indent + used_width)) - }) - .collect::>>() - ).join(joiner); + let ty_shape = try_opt!(shape.block_left(used_width)); + let bounds: Vec<_> = + try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, ty_shape)) + .collect()); + let bounds_str = join_bounds(context, ty_shape, &bounds); if context.config.spaces_within_angle_brackets() && lifetime_str.len() > 0 { format!("for< {} > {}{}{}", @@ -389,21 +382,14 @@ impl Rewrite for ast::WherePredicate { format!("for<{}> {}{}{}", lifetime_str, type_str, colon, bounds_str) } } else { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let used_width = type_str.len() + colon.len(); - let budget = try_opt!(shape.width.checked_sub(used_width)); - let bounds_str: String = try_opt!( - bounds - .iter() - .map(|ty_bound| { - ty_bound.rewrite(context, - Shape::legacy(budget, shape.indent + used_width)) - }) - .collect::>>() - ).join(joiner); + let ty_shape = try_opt!(shape.block_left(used_width)); + let bounds: Vec<_> = + try_opt!(bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, ty_shape)) + .collect()); + let bounds_str = join_bounds(context, ty_shape, &bounds); format!("{}{}{}", type_str, colon, bounds_str) } @@ -458,11 +444,11 @@ fn rewrite_bounded_lifetime<'b, I>(lt: &ast::Lifetime, .map(|b| b.rewrite(context, shape)) .collect()); let colon = type_bound_colon(context); - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; - let result = format!("{}{}{}", result, colon, appendix.join(joiner)); + let overhead = last_line_width(&result) + colon.len(); + let result = format!("{}{}{}", + result, + colon, + join_bounds(context, try_opt!(shape.sub_width(overhead)), &appendix)); wrap_str(result, context.config.max_width(), shape) } } @@ -494,12 +480,8 @@ impl Rewrite for ast::Lifetime { impl Rewrite for ast::TyParamBounds { fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option { - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; let strs: Vec<_> = try_opt!(self.iter().map(|b| b.rewrite(context, shape)).collect()); - wrap_str(strs.join(joiner), context.config.max_width(), shape) + join_bounds(context, shape, &strs).rewrite(context, shape) } } @@ -514,24 +496,12 @@ impl Rewrite for ast::TyParam { result.push_str(&attr_str); result.push_str(&self.ident.to_string()); if !self.bounds.is_empty() { - if context.config.space_before_bound() { - result.push_str(" "); - } - result.push_str(":"); - if context.config.space_after_bound_colon() { - result.push_str(" "); - } - let joiner = match context.config.type_punctuation_density() { - TypeDensity::Compressed => "+", - TypeDensity::Wide => " + ", - }; - let bounds: String = try_opt!(self.bounds - .iter() - .map(|ty_bound| ty_bound.rewrite(context, shape)) - .collect::>>()) - .join(joiner); - - result.push_str(&bounds); + result.push_str(type_bound_colon(context)); + let strs: Vec<_> = try_opt!(self.bounds + .iter() + .map(|ty_bound| ty_bound.rewrite(context, shape)) + .collect()); + result.push_str(&join_bounds(context, shape, &strs)); } if let Some(ref def) = self.default { @@ -732,3 +702,19 @@ fn rewrite_bare_fn(bare_fn: &ast::BareFnTy, Some(result) } + +pub fn join_bounds(context: &RewriteContext, shape: Shape, type_strs: &Vec) -> String { + // Try to join types in a single line + let joiner = match context.config.type_punctuation_density() { + TypeDensity::Compressed => "+", + TypeDensity::Wide => " + ", + }; + let result = type_strs.join(joiner); + if result.contains('\n') || result.len() > shape.width { + let joiner_indent = shape.indent.block_indent(context.config); + let joiner = format!("\n{}+ ", joiner_indent.to_string(context.config)); + type_strs.join(&joiner) + } else { + result + } +}