Skip to content

Commit a5d7073

Browse files
dawirstejecknrc
dawirstejeck
authored andcommitted
Split impl at 'for' if a line break is needed (#1148)
* Split impl at 'for' if a line break is needed * Fix formatting * Improve comments * Skip second try if there is no 'for' * Restore intentional trailing whitespace * Change test source to be incorrectly formatted * Restore more missing trailing whitespace * Remove too much whitespace... Really should learn how to use git revert.
1 parent df173c2 commit a5d7073

File tree

3 files changed

+87
-47
lines changed

3 files changed

+87
-47
lines changed

src/items.rs

+80-47
Original file line numberDiff line numberDiff line change
@@ -446,58 +446,21 @@ impl<'a> FmtVisitor<'a> {
446446
}
447447

448448
pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
449-
if let ast::ItemKind::Impl(unsafety,
450-
polarity,
451-
ref generics,
452-
ref trait_ref,
453-
ref self_ty,
454-
ref items) = item.node {
449+
if let ast::ItemKind::Impl(_, _, ref generics, ref trait_ref, _, ref items) = item.node {
455450
let mut result = String::new();
456451

457-
result.push_str(&*format_visibility(&item.vis));
458-
result.push_str(format_unsafety(unsafety));
459-
result.push_str("impl");
460-
461-
let lo = context.codemap.span_after(item.span, "impl");
462-
let hi = match *trait_ref {
463-
Some(ref tr) => tr.path.span.lo,
464-
None => self_ty.span.lo,
465-
};
466-
let generics_str = try_opt!(rewrite_generics(context,
467-
generics,
468-
offset,
469-
context.config.max_width,
470-
offset + result.len(),
471-
mk_sp(lo, hi)));
472-
result.push_str(&generics_str);
473-
474-
// FIXME might need to linebreak in the impl header, here would be a
475-
// good place.
476-
result.push(' ');
477-
if polarity == ast::ImplPolarity::Negative {
478-
result.push_str("!");
479-
}
480-
if let Some(ref trait_ref) = *trait_ref {
481-
let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
482-
let indent = offset + result.len();
483-
result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent)));
484-
result.push_str(" for ");
485-
}
452+
// First try to format the ref and type without a split at the 'for'.
453+
let mut ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, false));
486454

487-
let mut used_space = result.len();
488-
if generics.where_clause.predicates.is_empty() {
489-
// If there is no where clause adapt budget for type formatting to take space and curly
490-
// brace into account.
491-
match context.config.item_brace_style {
492-
BraceStyle::AlwaysNextLine => {}
493-
BraceStyle::PreferSameLine => used_space += 2,
494-
BraceStyle::SameLineWhere => used_space += 2,
455+
// If there is a line break present in the first result format it again
456+
// with a split at the 'for'. Skip this if there is no trait ref and
457+
// therefore no 'for'.
458+
if let Some(_) = *trait_ref {
459+
if ref_and_type.contains('\n') {
460+
ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, true));
495461
}
496462
}
497-
498-
let budget = try_opt!(context.config.max_width.checked_sub(used_space));
499-
let indent = offset + result.len();
500-
result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent)));
463+
result.push_str(&ref_and_type);
501464

502465
let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
503466
let where_clause_str = try_opt!(rewrite_where_clause(context,
@@ -594,6 +557,76 @@ fn is_impl_single_line(context: &RewriteContext,
594557
!contains_comment(&snippet[open_pos..]))
595558
}
596559

560+
fn format_impl_ref_and_type(context: &RewriteContext,
561+
item: &ast::Item,
562+
offset: Indent,
563+
split_at_for: bool)
564+
-> Option<String> {
565+
if let ast::ItemKind::Impl(unsafety, polarity, ref generics, ref trait_ref, ref self_ty, _) =
566+
item.node {
567+
let mut result = String::new();
568+
569+
result.push_str(&*format_visibility(&item.vis));
570+
result.push_str(format_unsafety(unsafety));
571+
result.push_str("impl");
572+
573+
let lo = context.codemap.span_after(item.span, "impl");
574+
let hi = match *trait_ref {
575+
Some(ref tr) => tr.path.span.lo,
576+
None => self_ty.span.lo,
577+
};
578+
let generics_str = try_opt!(rewrite_generics(context,
579+
generics,
580+
offset,
581+
context.config.max_width,
582+
offset + result.len(),
583+
mk_sp(lo, hi)));
584+
result.push_str(&generics_str);
585+
586+
result.push(' ');
587+
if polarity == ast::ImplPolarity::Negative {
588+
result.push('!');
589+
}
590+
if let Some(ref trait_ref) = *trait_ref {
591+
let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
592+
let indent = offset + result.len();
593+
result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent)));
594+
595+
if split_at_for {
596+
result.push('\n');
597+
598+
// Add indentation of one additional tab.
599+
let width = context.block_indent.width() + context.config.tab_spaces;
600+
let for_indent = Indent::new(0, width);
601+
result.push_str(&for_indent.to_string(context.config));
602+
603+
result.push_str("for ");
604+
} else {
605+
result.push_str(" for ");
606+
}
607+
}
608+
609+
let mut used_space = last_line_width(&result);
610+
if generics.where_clause.predicates.is_empty() {
611+
// If there is no where clause adapt budget for type formatting to take space and curly
612+
// brace into account.
613+
match context.config.item_brace_style {
614+
BraceStyle::AlwaysNextLine => {}
615+
BraceStyle::PreferSameLine => used_space += 2,
616+
BraceStyle::SameLineWhere => used_space += 2,
617+
}
618+
}
619+
620+
let budget = try_opt!(context.config.max_width.checked_sub(used_space));
621+
let indent = offset + result.len();
622+
result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent)));
623+
624+
Some(result)
625+
} else {
626+
unreachable!();
627+
}
628+
}
629+
597630
pub fn format_struct(context: &RewriteContext,
598631
item_name: &str,
599632
ident: ast::Ident,

tests/source/impls.rs

+3
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,6 @@ mod m {
100100

101101
impl<BorrowType, K, V, NodeType, HandleType> Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> {
102102
}
103+
104+
impl<BorrowType, K, V, NodeType, HandleType> PartialEq for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> {
105+
}

tests/target/impls.rs

+4
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,7 @@ mod m {
128128
impl<BorrowType, K, V, NodeType, HandleType> Handle<NodeRef<BorrowType, K, V, NodeType>,
129129
HandleType> {
130130
}
131+
132+
impl<BorrowType, K, V, NodeType, HandleType> PartialEq
133+
for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> {
134+
}

0 commit comments

Comments
 (0)