diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 625acce27bd64..eef530081abe3 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -42,7 +42,7 @@ pub struct UnsafetySpace(pub hir::Unsafety); #[derive(Copy, Clone)] pub struct ConstnessSpace(pub hir::Constness); /// Wrapper struct for properly emitting a method declaration. -pub struct Method<'a>(pub &'a clean::FnDecl, pub &'a str); +pub struct Method<'a>(pub &'a clean::FnDecl, pub usize); /// Similar to VisSpace, but used for mutability #[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); @@ -50,7 +50,7 @@ pub struct MutableSpace(pub clean::Mutability); #[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for emitting a where clause from Generics. -pub struct WhereClause<'a>(pub &'a clean::Generics); +pub struct WhereClause<'a>(pub &'a clean::Generics, pub usize); /// Wrapper struct for emitting type parameter bounds. pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]); /// Wrapper struct for emitting a comma-separated list of items @@ -157,52 +157,71 @@ impl fmt::Display for clean::Generics { impl<'a> fmt::Display for WhereClause<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let &WhereClause(gens) = self; + let &WhereClause(gens, pad) = self; if gens.where_predicates.is_empty() { return Ok(()); } + let mut clause = String::new(); if f.alternate() { - f.write_str(" ")?; + clause.push_str(" where "); } else { - f.write_str(" where ")?; + clause.push_str(" where "); } for (i, pred) in gens.where_predicates.iter().enumerate() { if i > 0 { - f.write_str(", ")?; + if f.alternate() { + clause.push_str(", "); + } else { + clause.push_str(",
"); + } } match pred { &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => { let bounds = bounds; if f.alternate() { - write!(f, "{:#}: {:#}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{:#}: {:#}", ty, TyParamBounds(bounds))); } else { - write!(f, "{}: {}", ty, TyParamBounds(bounds))?; + clause.push_str(&format!("{}: {}", ty, TyParamBounds(bounds))); } } &clean::WherePredicate::RegionPredicate { ref lifetime, ref bounds } => { - write!(f, "{}: ", lifetime)?; + clause.push_str(&format!("{}: ", lifetime)); for (i, lifetime) in bounds.iter().enumerate() { if i > 0 { - f.write_str(" + ")?; + clause.push_str(" + "); } - write!(f, "{}", lifetime)?; + clause.push_str(&format!("{}", lifetime)); } } &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => { if f.alternate() { - write!(f, "{:#} == {:#}", lhs, rhs)?; + clause.push_str(&format!("{:#} == {:#}", lhs, rhs)); } else { - write!(f, "{} == {}", lhs, rhs)?; + clause.push_str(&format!("{} == {}", lhs, rhs)); } } } } if !f.alternate() { - f.write_str("
")?; + clause.push_str("
"); + let plain = format!("{:#}", self); + if plain.len() > 80 { + //break it onto its own line regardless, but make sure method impls and trait + //blocks keep their fixed padding (2 and 9, respectively) + let padding = if pad > 10 { + clause = clause.replace("class='where'", "class='where fmt-newline'"); + repeat(" ").take(8).collect::() + } else { + repeat(" ").take(pad + 6).collect::() + }; + clause = clause.replace("
", &format!("
{}", padding)); + } else { + clause = clause.replace("
", " "); + } } - Ok(()) + write!(f, "{}", clause) } } @@ -718,30 +737,43 @@ impl fmt::Display for clean::Type { } fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result { + let mut plain = String::new(); + if f.alternate() { write!(f, "impl{:#} ", i.generics)?; } else { write!(f, "impl{} ", i.generics)?; } + plain.push_str(&format!("impl{:#} ", i.generics)); + if let Some(ref ty) = i.trait_ { - write!(f, "{}", - if i.polarity == Some(clean::ImplPolarity::Negative) { "!" } else { "" })?; + if i.polarity == Some(clean::ImplPolarity::Negative) { + write!(f, "!")?; + plain.push_str("!"); + } + if link_trait { fmt::Display::fmt(ty, f)?; + plain.push_str(&format!("{:#}", ty)); } else { match *ty { clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => { let last = path.segments.last().unwrap(); fmt::Display::fmt(&last.name, f)?; fmt::Display::fmt(&last.params, f)?; + plain.push_str(&format!("{:#}{:#}", last.name, last.params)); } _ => unreachable!(), } } write!(f, " for ")?; + plain.push_str(" for "); } + fmt::Display::fmt(&i.for_, f)?; - fmt::Display::fmt(&WhereClause(&i.generics), f)?; + plain.push_str(&format!("{:#}", i.for_)); + + fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), f)?; Ok(()) } @@ -870,24 +902,30 @@ impl<'a> fmt::Display for Method<'a> { let mut output: String; let plain: String; + let pad = repeat(" ").take(indent).collect::(); if arrow.is_empty() { output = format!("({})", args); - plain = format!("{}({})", indent.replace(" ", " "), args_plain); + plain = format!("{}({})", pad, args_plain); } else { output = format!("({args})
{arrow}", args = args, arrow = arrow); - plain = format!("{indent}({args}){arrow}", - indent = indent.replace(" ", " "), + plain = format!("{pad}({args}){arrow}", + pad = pad, args = args_plain, arrow = arrow_plain); } if plain.len() > 80 { - let pad = format!("
{}", indent); + let pad = repeat(" ").take(indent).collect::(); + let pad = format!("
{}", pad); output = output.replace("
", &pad); } else { output = output.replace("
", ""); } - write!(f, "{}", output) + if f.alternate() { + write!(f, "{}", output.replace("
", "\n")) + } else { + write!(f, "{}", output) + } } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2db771d771119..93827a01038f9 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1972,14 +1972,13 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, UnstableFeatures::Allow => f.constness, _ => hir::Constness::NotConst }; - let prefix = format!("{}{}{}{:#}fn {}{:#}", + let indent = format!("{}{}{}{:#}fn {}{:#}", VisSpace(&it.visibility), ConstnessSpace(vis_constness), UnsafetySpace(f.unsafety), AbiSpace(f.abi), it.name.as_ref().unwrap(), - f.generics); - let indent = repeat(" ").take(prefix.len()).collect::(); + f.generics).len(); write!(w, "
{vis}{constness}{unsafety}{abi}fn \
                {name}{generics}{decl}{where_clause}
", vis = VisSpace(&it.visibility), @@ -1988,22 +1987,29 @@ fn item_function(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, abi = AbiSpace(f.abi), name = it.name.as_ref().unwrap(), generics = f.generics, - where_clause = WhereClause(&f.generics), - decl = Method(&f.decl, &indent))?; + where_clause = WhereClause(&f.generics, 2), + decl = Method(&f.decl, indent))?; document(w, cx, it) } fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Trait) -> fmt::Result { let mut bounds = String::new(); + let mut bounds_plain = String::new(); if !t.bounds.is_empty() { if !bounds.is_empty() { bounds.push(' '); + bounds_plain.push(' '); } bounds.push_str(": "); + bounds_plain.push_str(": "); for (i, p) in t.bounds.iter().enumerate() { - if i > 0 { bounds.push_str(" + "); } + if i > 0 { + bounds.push_str(" + "); + bounds_plain.push_str(" + "); + } bounds.push_str(&format!("{}", *p)); + bounds_plain.push_str(&format!("{:#}", *p)); } } @@ -2014,7 +2020,8 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, it.name.as_ref().unwrap(), t.generics, bounds, - WhereClause(&t.generics))?; + // Where clauses in traits are indented nine spaces, per rustdoc.css + WhereClause(&t.generics, 9))?; let types = t.items.iter().filter(|m| m.is_associated_type()).collect::>(); let consts = t.items.iter().filter(|m| m.is_associated_const()).collect::>(); @@ -2028,7 +2035,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, write!(w, "{{\n")?; for t in &types { write!(w, " ")?; - render_assoc_item(w, t, AssocItemLink::Anchor(None))?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !types.is_empty() && !consts.is_empty() { @@ -2036,7 +2043,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for t in &consts { write!(w, " ")?; - render_assoc_item(w, t, AssocItemLink::Anchor(None))?; + render_assoc_item(w, t, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !consts.is_empty() && !required.is_empty() { @@ -2044,7 +2051,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &required { write!(w, " ")?; - render_assoc_item(w, m, AssocItemLink::Anchor(None))?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, ";\n")?; } if !required.is_empty() && !provided.is_empty() { @@ -2052,7 +2059,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, } for m in &provided { write!(w, " ")?; - render_assoc_item(w, m, AssocItemLink::Anchor(None))?; + render_assoc_item(w, m, AssocItemLink::Anchor(None), ItemType::Trait)?; write!(w, " {{ ... }}\n")?; } write!(w, "}}")?; @@ -2073,7 +2080,7 @@ fn item_trait(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, id = id, stab = m.stability_class(), ns_id = ns_id)?; - render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)))?; + render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl)?; write!(w, "")?; render_stability_since(w, m, t)?; write!(w, "")?; @@ -2227,7 +2234,8 @@ fn render_stability_since(w: &mut fmt::Formatter, fn render_assoc_item(w: &mut fmt::Formatter, item: &clean::Item, - link: AssocItemLink) -> fmt::Result { + link: AssocItemLink, + parent: ItemType) -> fmt::Result { fn method(w: &mut fmt::Formatter, meth: &clean::Item, unsafety: hir::Unsafety, @@ -2235,7 +2243,8 @@ fn render_assoc_item(w: &mut fmt::Formatter, abi: abi::Abi, g: &clean::Generics, d: &clean::FnDecl, - link: AssocItemLink) + link: AssocItemLink, + parent: ItemType) -> fmt::Result { let name = meth.name.as_ref().unwrap(); let anchor = format!("#{}.{}", meth.type_(), name); @@ -2265,7 +2274,16 @@ fn render_assoc_item(w: &mut fmt::Formatter, AbiSpace(abi), name, *g); - let indent = repeat(" ").take(prefix.len()).collect::(); + let mut indent = prefix.len(); + let where_indent = if parent == ItemType::Trait { + indent += 4; + 8 + } else if parent == ItemType::Impl { + 2 + } else { + let prefix = prefix + &format!("{:#}", Method(d, indent)); + prefix.lines().last().unwrap().len() + 1 + }; write!(w, "{}{}{}fn {name}\ {generics}{decl}{where_clause}", ConstnessSpace(vis_constness), @@ -2274,19 +2292,18 @@ fn render_assoc_item(w: &mut fmt::Formatter, href = href, name = name, generics = *g, - decl = Method(d, &indent), - where_clause = WhereClause(g)) + decl = Method(d, indent), + where_clause = WhereClause(g, where_indent)) } match item.inner { clean::StrippedItem(..) => Ok(()), clean::TyMethodItem(ref m) => { method(w, item, m.unsafety, hir::Constness::NotConst, - m.abi, &m.generics, &m.decl, link) + m.abi, &m.generics, &m.decl, link, parent) } clean::MethodItem(ref m) => { method(w, item, m.unsafety, m.constness, - m.abi, &m.generics, &m.decl, - link) + m.abi, &m.generics, &m.decl, link, parent) } clean::AssociatedConstItem(ref ty, ref default) => { assoc_const(w, item, ty, default.as_ref(), link) @@ -2383,11 +2400,15 @@ fn item_enum(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, e: &clean::Enum) -> fmt::Result { write!(w, "
")?;
     render_attributes(w, it)?;
+    let padding = format!("{}enum {}{:#} ",
+                          VisSpace(&it.visibility),
+                          it.name.as_ref().unwrap(),
+                          e.generics).len();
     write!(w, "{}enum {}{}{}",
            VisSpace(&it.visibility),
            it.name.as_ref().unwrap(),
            e.generics,
-           WhereClause(&e.generics))?;
+           WhereClause(&e.generics, padding))?;
     if e.variants.is_empty() && !e.variants_stripped {
         write!(w, " {{}}")?;
     } else {
@@ -2559,17 +2580,23 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
                  fields: &[clean::Item],
                  tab: &str,
                  structhead: bool) -> fmt::Result {
+    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"struct "} else {""},
            it.name.as_ref().unwrap())?;
+    plain.push_str(&format!("{}{}{}",
+                            VisSpace(&it.visibility),
+                            if structhead {"struct "} else {""},
+                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
+        plain.push_str(&format!("{:#}", g));
         write!(w, "{}", g)?
     }
     match ty {
         doctree::Plain => {
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             let mut has_visible_fields = false;
             write!(w, " {{")?;
@@ -2598,30 +2625,35 @@ fn render_struct(w: &mut fmt::Formatter, it: &clean::Item,
         }
         doctree::Tuple => {
             write!(w, "(")?;
+            plain.push_str("(");
             for (i, field) in fields.iter().enumerate() {
                 if i > 0 {
                     write!(w, ", ")?;
+                    plain.push_str(", ");
                 }
                 match field.inner {
                     clean::StrippedItem(box clean::StructFieldItem(..)) => {
+                        plain.push_str("_");
                         write!(w, "_")?
                     }
                     clean::StructFieldItem(ref ty) => {
+                        plain.push_str(&format!("{}{:#}", VisSpace(&field.visibility), *ty));
                         write!(w, "{}{}", VisSpace(&field.visibility), *ty)?
                     }
                     _ => unreachable!()
                 }
             }
             write!(w, ")")?;
+            plain.push_str(")");
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             write!(w, ";")?;
         }
         doctree::Unit => {
             // Needed for PhantomData.
             if let Some(g) = g {
-                write!(w, "{}", WhereClause(g))?
+                write!(w, "{}", WhereClause(g, plain.len() + 1))?
             }
             write!(w, ";")?;
         }
@@ -2634,13 +2666,19 @@ fn render_union(w: &mut fmt::Formatter, it: &clean::Item,
                 fields: &[clean::Item],
                 tab: &str,
                 structhead: bool) -> fmt::Result {
+    let mut plain = String::new();
     write!(w, "{}{}{}",
            VisSpace(&it.visibility),
            if structhead {"union "} else {""},
            it.name.as_ref().unwrap())?;
+    plain.push_str(&format!("{}{}{}",
+                            VisSpace(&it.visibility),
+                            if structhead {"union "} else {""},
+                            it.name.as_ref().unwrap()));
     if let Some(g) = g {
         write!(w, "{}", g)?;
-        write!(w, "{}", WhereClause(g))?;
+        plain.push_str(&format!("{:#}", g));
+        write!(w, "{}", WhereClause(g, plain.len() + 1))?;
     }
 
     write!(w, " {{\n{}", tab)?;
@@ -2831,7 +2869,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                     write!(w, "

", id, item_type)?; write!(w, "

\n")?; @@ -2941,10 +2979,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi fn item_typedef(w: &mut fmt::Formatter, cx: &Context, it: &clean::Item, t: &clean::Typedef) -> fmt::Result { + let indent = format!("type {}{:#} ", it.name.as_ref().unwrap(), t.generics).len(); write!(w, "
type {}{}{where_clause} = {type_};
", it.name.as_ref().unwrap(), t.generics, - where_clause = WhereClause(&t.generics), + where_clause = WhereClause(&t.generics, indent), type_ = t.type_)?; document(w, cx, it) diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 46b34b5a638b3..917b5f4fadc07 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -361,9 +361,17 @@ h4 > code, h3 > code, .invisible > code { position: relative; } /* Shift "where ..." part of method or fn definition down a line */ -.content .method .where, .content .fn .where { display: block; } +.content .method .where, +.content .fn .where, +.content .where.fmt-newline { + display: block; +} /* Bit of whitespace to indent it */ -.content .method .where::before, .content .fn .where::before { content: ' '; } +.content .method .where::before, +.content .fn .where::before, +.content .where.fmt-newline::before { + content: ' '; +} .content .methods > div { margin-left: 40px; } diff --git a/src/test/rustdoc/line-breaks.rs b/src/test/rustdoc/line-breaks.rs index cc608a2447574..a1eabb515a5ce 100644 --- a/src/test/rustdoc/line-breaks.rs +++ b/src/test/rustdoc/line-breaks.rs @@ -10,6 +10,9 @@ #![crate_name = "foo"] +use std::ops::Add; +use std::fmt::Display; + //@count foo/fn.function_with_a_really_long_name.html //pre/br 2 pub fn function_with_a_really_long_name(parameter_one: i32, parameter_two: i32) @@ -19,3 +22,19 @@ pub fn function_with_a_really_long_name(parameter_one: i32, //@count foo/fn.short_name.html //pre/br 0 pub fn short_name(param: i32) -> i32 { param + 1 } + +//@count foo/fn.where_clause.html //pre/br 4 +pub fn where_clause(param_one: T, + param_two: U) + where T: Add + Display + Copy, + U: Add + Display + Copy, + T::Output: Display + Add + Copy, + >::Output: Display, + U::Output: Display + Copy +{ + let x = param_one + param_two; + println!("{} + {} = {}", param_one, param_two, x); + let y = param_two + param_one; + println!("{} + {} = {}", param_two, param_one, y); + println!("{} + {} = {}", x, y, x + y); +}