]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
0323e2b1f522ee5b38d19081fb833779a8517bee
[rust.git] / src / librustdoc / html / format.rs
1 // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! HTML formatting module
12 //!
13 //! This module contains a large number of `fmt::Display` implementations for
14 //! various types in `rustdoc::clean`. These implementations all currently
15 //! assume that HTML output is desired, although it may be possible to redesign
16 //! them in the future to instead emit any format desired.
17
18 use std::fmt;
19 use std::iter::repeat;
20
21 use rustc::hir::def_id::DefId;
22 use rustc_target::spec::abi::Abi;
23 use rustc::hir;
24
25 use clean::{self, PrimitiveType};
26 use core::DocAccessLevels;
27 use html::item_type::ItemType;
28 use html::render::{self, cache, CURRENT_LOCATION_KEY};
29
30 /// Helper to render an optional visibility with a space after it (if the
31 /// visibility is preset)
32 #[derive(Copy, Clone)]
33 pub struct VisSpace<'a>(pub &'a Option<clean::Visibility>);
34 /// Similarly to VisSpace, this structure is used to render a function style with a
35 /// space after it.
36 #[derive(Copy, Clone)]
37 pub struct UnsafetySpace(pub hir::Unsafety);
38 /// Similarly to VisSpace, this structure is used to render a function constness
39 /// with a space after it.
40 #[derive(Copy, Clone)]
41 pub struct ConstnessSpace(pub hir::Constness);
42 /// Similar to VisSpace, but used for mutability
43 #[derive(Copy, Clone)]
44 pub struct MutableSpace(pub clean::Mutability);
45 /// Similar to VisSpace, but used for mutability
46 #[derive(Copy, Clone)]
47 pub struct RawMutableSpace(pub clean::Mutability);
48 /// Wrapper struct for emitting type parameter bounds.
49 pub struct TyParamBounds<'a>(pub &'a [clean::TyParamBound]);
50 /// Wrapper struct for emitting a comma-separated list of items
51 pub struct CommaSep<'a, T: 'a>(pub &'a [T]);
52 pub struct AbiSpace(pub Abi);
53
54 /// Wrapper struct for properly emitting a method declaration.
55 pub struct Method<'a> {
56     /// The declaration to emit.
57     pub decl: &'a clean::FnDecl,
58     /// The length of the function's "name", used to determine line-wrapping.
59     pub name_len: usize,
60     /// The number of spaces to indent each successive line with, if line-wrapping is necessary.
61     pub indent: usize,
62 }
63
64 /// Wrapper struct for emitting a where clause from Generics.
65 pub struct WhereClause<'a>{
66     /// The Generics from which to emit a where clause.
67     pub gens: &'a clean::Generics,
68     /// The number of spaces to indent each line with.
69     pub indent: usize,
70     /// Whether the where clause needs to add a comma and newline after the last bound.
71     pub end_newline: bool,
72 }
73
74 pub struct HRef<'a> {
75     pub did: DefId,
76     pub text: &'a str,
77 }
78
79 impl<'a> VisSpace<'a> {
80     pub fn get(self) -> &'a Option<clean::Visibility> {
81         let VisSpace(v) = self; v
82     }
83 }
84
85 impl UnsafetySpace {
86     pub fn get(&self) -> hir::Unsafety {
87         let UnsafetySpace(v) = *self; v
88     }
89 }
90
91 impl ConstnessSpace {
92     pub fn get(&self) -> hir::Constness {
93         let ConstnessSpace(v) = *self; v
94     }
95 }
96
97 impl<'a, T: fmt::Display> fmt::Display for CommaSep<'a, T> {
98     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99         for (i, item) in self.0.iter().enumerate() {
100             if i != 0 { write!(f, ", ")?; }
101             fmt::Display::fmt(item, f)?;
102         }
103         Ok(())
104     }
105 }
106
107 impl<'a> fmt::Display for TyParamBounds<'a> {
108     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109         let &TyParamBounds(bounds) = self;
110         for (i, bound) in bounds.iter().enumerate() {
111             if i > 0 {
112                 f.write_str(" + ")?;
113             }
114             fmt::Display::fmt(bound, f)?;
115         }
116         Ok(())
117     }
118 }
119
120 impl fmt::Display for clean::GenericParamDef {
121     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122         match *self {
123             clean::GenericParamDef::Lifetime(ref lp) => write!(f, "{}", lp),
124             clean::GenericParamDef::Type(ref tp) => {
125                 f.write_str(&tp.name)?;
126
127                 if !tp.bounds.is_empty() {
128                     if f.alternate() {
129                         write!(f, ": {:#}", TyParamBounds(&tp.bounds))?;
130                     } else {
131                         write!(f, ":&nbsp;{}", TyParamBounds(&tp.bounds))?;
132                     }
133                 }
134
135                 if let Some(ref ty) = tp.default {
136                     if f.alternate() {
137                         write!(f, " = {:#}", ty)?;
138                     } else {
139                         write!(f, "&nbsp;=&nbsp;{}", ty)?;
140                     }
141                 }
142
143                 Ok(())
144             }
145         }
146     }
147 }
148
149 impl fmt::Display for clean::Generics {
150     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151         let real_params = self.params
152             .iter()
153             .filter(|p| !p.is_synthetic_type_param())
154             .collect::<Vec<_>>();
155         if real_params.is_empty() {
156             return Ok(());
157         }
158         if f.alternate() {
159             write!(f, "<{:#}>", CommaSep(&real_params))
160         } else {
161             write!(f, "&lt;{}&gt;", CommaSep(&real_params))
162         }
163     }
164 }
165
166 impl<'a> fmt::Display for WhereClause<'a> {
167     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
168         let &WhereClause { gens, indent, end_newline } = self;
169         if gens.where_predicates.is_empty() {
170             return Ok(());
171         }
172         let mut clause = String::new();
173         if f.alternate() {
174             clause.push_str(" where");
175         } else {
176             if end_newline {
177                 clause.push_str(" <span class=\"where fmt-newline\">where");
178             } else {
179                 clause.push_str(" <span class=\"where\">where");
180             }
181         }
182         for (i, pred) in gens.where_predicates.iter().enumerate() {
183             if f.alternate() {
184                 clause.push(' ');
185             } else {
186                 clause.push_str("<br>");
187             }
188
189             match pred {
190                 &clean::WherePredicate::BoundPredicate { ref ty, ref bounds } => {
191                     let bounds = bounds;
192                     if f.alternate() {
193                         clause.push_str(&format!("{:#}: {:#}", ty, TyParamBounds(bounds)));
194                     } else {
195                         clause.push_str(&format!("{}: {}", ty, TyParamBounds(bounds)));
196                     }
197                 }
198                 &clean::WherePredicate::RegionPredicate { ref lifetime,
199                                                           ref bounds } => {
200                     clause.push_str(&format!("{}: ", lifetime));
201                     for (i, lifetime) in bounds.iter().enumerate() {
202                         if i > 0 {
203                             clause.push_str(" + ");
204                         }
205
206                         clause.push_str(&format!("{}", lifetime));
207                     }
208                 }
209                 &clean::WherePredicate::EqPredicate { ref lhs, ref rhs } => {
210                     if f.alternate() {
211                         clause.push_str(&format!("{:#} == {:#}", lhs, rhs));
212                     } else {
213                         clause.push_str(&format!("{} == {}", lhs, rhs));
214                     }
215                 }
216             }
217
218             if i < gens.where_predicates.len() - 1 || end_newline {
219                 clause.push(',');
220             }
221         }
222
223         if end_newline {
224             // add a space so stripping <br> tags and breaking spaces still renders properly
225             if f.alternate() {
226                 clause.push(' ');
227             } else {
228                 clause.push_str("&nbsp;");
229             }
230         }
231
232         if !f.alternate() {
233             clause.push_str("</span>");
234             let padding = repeat("&nbsp;").take(indent + 4).collect::<String>();
235             clause = clause.replace("<br>", &format!("<br>{}", padding));
236             clause.insert_str(0, &repeat("&nbsp;").take(indent.saturating_sub(1))
237                                                   .collect::<String>());
238             if !end_newline {
239                 clause.insert_str(0, "<br>");
240             }
241         }
242         write!(f, "{}", clause)
243     }
244 }
245
246 impl fmt::Display for clean::Lifetime {
247     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
248         f.write_str(self.get_ref())?;
249         Ok(())
250     }
251 }
252
253 impl fmt::Display for clean::PolyTrait {
254     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
255         if !self.generic_params.is_empty() {
256             if f.alternate() {
257                 write!(f, "for<{:#}> ", CommaSep(&self.generic_params))?;
258             } else {
259                 write!(f, "for&lt;{}&gt; ", CommaSep(&self.generic_params))?;
260             }
261         }
262         if f.alternate() {
263             write!(f, "{:#}", self.trait_)
264         } else {
265             write!(f, "{}", self.trait_)
266         }
267     }
268 }
269
270 impl fmt::Display for clean::TyParamBound {
271     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272         match *self {
273             clean::RegionBound(ref lt) => {
274                 write!(f, "{}", *lt)
275             }
276             clean::TraitBound(ref ty, modifier) => {
277                 let modifier_str = match modifier {
278                     hir::TraitBoundModifier::None => "",
279                     hir::TraitBoundModifier::Maybe => "?",
280                 };
281                 if f.alternate() {
282                     write!(f, "{}{:#}", modifier_str, *ty)
283                 } else {
284                     write!(f, "{}{}", modifier_str, *ty)
285                 }
286             }
287         }
288     }
289 }
290
291 impl fmt::Display for clean::PathParameters {
292     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293         match *self {
294             clean::PathParameters::AngleBracketed {
295                 ref lifetimes, ref types, ref bindings
296             } => {
297                 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
298                     if f.alternate() {
299                         f.write_str("<")?;
300                     } else {
301                         f.write_str("&lt;")?;
302                     }
303                     let mut comma = false;
304                     for lifetime in lifetimes {
305                         if comma {
306                             f.write_str(", ")?;
307                         }
308                         comma = true;
309                         write!(f, "{}", *lifetime)?;
310                     }
311                     for ty in types {
312                         if comma {
313                             f.write_str(", ")?;
314                         }
315                         comma = true;
316                         if f.alternate() {
317                             write!(f, "{:#}", *ty)?;
318                         } else {
319                             write!(f, "{}", *ty)?;
320                         }
321                     }
322                     for binding in bindings {
323                         if comma {
324                             f.write_str(", ")?;
325                         }
326                         comma = true;
327                         if f.alternate() {
328                             write!(f, "{:#}", *binding)?;
329                         } else {
330                             write!(f, "{}", *binding)?;
331                         }
332                     }
333                     if f.alternate() {
334                         f.write_str(">")?;
335                     } else {
336                         f.write_str("&gt;")?;
337                     }
338                 }
339             }
340             clean::PathParameters::Parenthesized { ref inputs, ref output } => {
341                 f.write_str("(")?;
342                 let mut comma = false;
343                 for ty in inputs {
344                     if comma {
345                         f.write_str(", ")?;
346                     }
347                     comma = true;
348                     if f.alternate() {
349                         write!(f, "{:#}", *ty)?;
350                     } else {
351                         write!(f, "{}", *ty)?;
352                     }
353                 }
354                 f.write_str(")")?;
355                 if let Some(ref ty) = *output {
356                     if f.alternate() {
357                         write!(f, " -> {:#}", ty)?;
358                     } else {
359                         write!(f, " -&gt; {}", ty)?;
360                     }
361                 }
362             }
363         }
364         Ok(())
365     }
366 }
367
368 impl fmt::Display for clean::PathSegment {
369     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
370         f.write_str(&self.name)?;
371         if f.alternate() {
372             write!(f, "{:#}", self.params)
373         } else {
374             write!(f, "{}", self.params)
375         }
376     }
377 }
378
379 impl fmt::Display for clean::Path {
380     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
381         if self.global {
382             f.write_str("::")?
383         }
384
385         for (i, seg) in self.segments.iter().enumerate() {
386             if i > 0 {
387                 f.write_str("::")?
388             }
389             if f.alternate() {
390                 write!(f, "{:#}", seg)?;
391             } else {
392                 write!(f, "{}", seg)?;
393             }
394         }
395         Ok(())
396     }
397 }
398
399 pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
400     let cache = cache();
401     if !did.is_local() && !cache.access_levels.is_doc_reachable(did) {
402         return None
403     }
404
405     let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
406     let (fqp, shortty, mut url) = match cache.paths.get(&did) {
407         Some(&(ref fqp, shortty)) => {
408             (fqp, shortty, repeat("../").take(loc.len()).collect())
409         }
410         None => {
411             let &(ref fqp, shortty) = cache.external_paths.get(&did)?;
412             (fqp, shortty, match cache.extern_locations[&did.krate] {
413                 (.., render::Remote(ref s)) => s.to_string(),
414                 (.., render::Local) => repeat("../").take(loc.len()).collect(),
415                 (.., render::Unknown) => return None,
416             })
417         }
418     };
419     for component in &fqp[..fqp.len() - 1] {
420         url.push_str(component);
421         url.push_str("/");
422     }
423     match shortty {
424         ItemType::Module => {
425             url.push_str(fqp.last().unwrap());
426             url.push_str("/index.html");
427         }
428         _ => {
429             url.push_str(shortty.css_class());
430             url.push_str(".");
431             url.push_str(fqp.last().unwrap());
432             url.push_str(".html");
433         }
434     }
435     Some((url, shortty, fqp.to_vec()))
436 }
437
438 /// Used when rendering a `ResolvedPath` structure. This invokes the `path`
439 /// rendering function with the necessary arguments for linking to a local path.
440 fn resolved_path(w: &mut fmt::Formatter, did: DefId, path: &clean::Path,
441                  print_all: bool, use_absolute: bool) -> fmt::Result {
442     let last = path.segments.last().unwrap();
443
444     if print_all {
445         for seg in &path.segments[..path.segments.len() - 1] {
446             write!(w, "{}::", seg.name)?;
447         }
448     }
449     if w.alternate() {
450         write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
451     } else {
452         let path = if use_absolute {
453             match href(did) {
454                 Some((_, _, fqp)) => {
455                     format!("{}::{}",
456                             fqp[..fqp.len() - 1].join("::"),
457                             HRef::new(did, fqp.last().unwrap()))
458                 }
459                 None => format!("{}", HRef::new(did, &last.name)),
460             }
461         } else {
462             format!("{}", HRef::new(did, &last.name))
463         };
464         write!(w, "{}{}", path, last.params)?;
465     }
466     Ok(())
467 }
468
469 fn primitive_link(f: &mut fmt::Formatter,
470                   prim: clean::PrimitiveType,
471                   name: &str) -> fmt::Result {
472     let m = cache();
473     let mut needs_termination = false;
474     if !f.alternate() {
475         match m.primitive_locations.get(&prim) {
476             Some(&def_id) if def_id.is_local() => {
477                 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
478                 let len = if len == 0 {0} else {len - 1};
479                 write!(f, "<a class=\"primitive\" href=\"{}primitive.{}.html\">",
480                        repeat("../").take(len).collect::<String>(),
481                        prim.to_url_str())?;
482                 needs_termination = true;
483             }
484             Some(&def_id) => {
485                 let loc = match m.extern_locations[&def_id.krate] {
486                     (ref cname, _, render::Remote(ref s)) => {
487                         Some((cname, s.to_string()))
488                     }
489                     (ref cname, _, render::Local) => {
490                         let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
491                         Some((cname, repeat("../").take(len).collect::<String>()))
492                     }
493                     (.., render::Unknown) => None,
494                 };
495                 if let Some((cname, root)) = loc {
496                     write!(f, "<a class=\"primitive\" href=\"{}{}/primitive.{}.html\">",
497                            root,
498                            cname,
499                            prim.to_url_str())?;
500                     needs_termination = true;
501                 }
502             }
503             None => {}
504         }
505     }
506     write!(f, "{}", name)?;
507     if needs_termination {
508         write!(f, "</a>")?;
509     }
510     Ok(())
511 }
512
513 /// Helper to render type parameters
514 fn tybounds(w: &mut fmt::Formatter,
515             typarams: &Option<Vec<clean::TyParamBound>>) -> fmt::Result {
516     match *typarams {
517         Some(ref params) => {
518             for param in params {
519                 write!(w, " + ")?;
520                 fmt::Display::fmt(param, w)?;
521             }
522             Ok(())
523         }
524         None => Ok(())
525     }
526 }
527
528 impl<'a> HRef<'a> {
529     pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
530         HRef { did: did, text: text }
531     }
532 }
533
534 impl<'a> fmt::Display for HRef<'a> {
535     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
536         match href(self.did) {
537             Some((url, shortty, fqp)) => if !f.alternate() {
538                 write!(f, "<a class=\"{}\" href=\"{}\" title=\"{} {}\">{}</a>",
539                        shortty, url, shortty, fqp.join("::"), self.text)
540             } else {
541                 write!(f, "{}", self.text)
542             },
543             _ => write!(f, "{}", self.text),
544         }
545     }
546 }
547
548 fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter, use_absolute: bool) -> fmt::Result {
549     match *t {
550         clean::Generic(ref name) => {
551             f.write_str(name)
552         }
553         clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
554             // Paths like T::Output and Self::Output should be rendered with all segments
555             resolved_path(f, did, path, is_generic, use_absolute)?;
556             tybounds(f, typarams)
557         }
558         clean::Infer => write!(f, "_"),
559         clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
560         clean::BareFunction(ref decl) => {
561             if f.alternate() {
562                 write!(f, "{}{:#}fn{:#}{:#}",
563                        UnsafetySpace(decl.unsafety),
564                        AbiSpace(decl.abi),
565                        CommaSep(&decl.generic_params),
566                        decl.decl)
567             } else {
568                 write!(f, "{}{}", UnsafetySpace(decl.unsafety), AbiSpace(decl.abi))?;
569                 primitive_link(f, PrimitiveType::Fn, "fn")?;
570                 write!(f, "{}{}", CommaSep(&decl.generic_params), decl.decl)
571             }
572         }
573         clean::Tuple(ref typs) => {
574             match &typs[..] {
575                 &[] => primitive_link(f, PrimitiveType::Unit, "()"),
576                 &[ref one] => {
577                     primitive_link(f, PrimitiveType::Tuple, "(")?;
578                     //carry f.alternate() into this display w/o branching manually
579                     fmt::Display::fmt(one, f)?;
580                     primitive_link(f, PrimitiveType::Tuple, ",)")
581                 }
582                 many => {
583                     primitive_link(f, PrimitiveType::Tuple, "(")?;
584                     fmt::Display::fmt(&CommaSep(many), f)?;
585                     primitive_link(f, PrimitiveType::Tuple, ")")
586                 }
587             }
588         }
589         clean::Slice(ref t) => {
590             primitive_link(f, PrimitiveType::Slice, "[")?;
591             fmt::Display::fmt(t, f)?;
592             primitive_link(f, PrimitiveType::Slice, "]")
593         }
594         clean::Array(ref t, ref n) => {
595             primitive_link(f, PrimitiveType::Array, "[")?;
596             fmt::Display::fmt(t, f)?;
597             primitive_link(f, PrimitiveType::Array, &format!("; {}]", n))
598         }
599         clean::Never => primitive_link(f, PrimitiveType::Never, "!"),
600         clean::RawPointer(m, ref t) => {
601             match **t {
602                 clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
603                     if f.alternate() {
604                         primitive_link(f, clean::PrimitiveType::RawPointer,
605                                        &format!("*{}{:#}", RawMutableSpace(m), t))
606                     } else {
607                         primitive_link(f, clean::PrimitiveType::RawPointer,
608                                        &format!("*{}{}", RawMutableSpace(m), t))
609                     }
610                 }
611                 _ => {
612                     primitive_link(f, clean::PrimitiveType::RawPointer,
613                                    &format!("*{}", RawMutableSpace(m)))?;
614                     fmt::Display::fmt(t, f)
615                 }
616             }
617         }
618         clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
619             let lt = match *l {
620                 Some(ref l) => format!("{} ", *l),
621                 _ => "".to_string(),
622             };
623             let m = MutableSpace(mutability);
624             let amp = if f.alternate() {
625                 "&".to_string()
626             } else {
627                 "&amp;".to_string()
628             };
629             match **ty {
630                 clean::Slice(ref bt) => { // BorrowedRef{ ... Slice(T) } is &[T]
631                     match **bt {
632                         clean::Generic(_) => {
633                             if f.alternate() {
634                                 primitive_link(f, PrimitiveType::Slice,
635                                     &format!("{}{}{}[{:#}]", amp, lt, m, **bt))
636                             } else {
637                                 primitive_link(f, PrimitiveType::Slice,
638                                     &format!("{}{}{}[{}]", amp, lt, m, **bt))
639                             }
640                         }
641                         _ => {
642                             primitive_link(f, PrimitiveType::Slice,
643                                            &format!("{}{}{}[", amp, lt, m))?;
644                             if f.alternate() {
645                                 write!(f, "{:#}", **bt)?;
646                             } else {
647                                 write!(f, "{}", **bt)?;
648                             }
649                             primitive_link(f, PrimitiveType::Slice, "]")
650                         }
651                     }
652                 }
653                 clean::ResolvedPath { typarams: Some(ref v), .. } if !v.is_empty() => {
654                     write!(f, "{}{}{}(", amp, lt, m)?;
655                     fmt_type(&ty, f, use_absolute)?;
656                     write!(f, ")")
657                 }
658                 clean::Generic(..) => {
659                     primitive_link(f, PrimitiveType::Reference,
660                                    &format!("{}{}{}", amp, lt, m))?;
661                     fmt_type(&ty, f, use_absolute)
662                 }
663                 _ => {
664                     write!(f, "{}{}{}", amp, lt, m)?;
665                     fmt_type(&ty, f, use_absolute)
666                 }
667             }
668         }
669         clean::ImplTrait(ref bounds) => {
670             write!(f, "impl {}", TyParamBounds(bounds))
671         }
672         clean::QPath { ref name, ref self_type, ref trait_ } => {
673             let should_show_cast = match *trait_ {
674                 box clean::ResolvedPath { ref path, .. } => {
675                     !path.segments.is_empty() && !self_type.is_self_type()
676                 }
677                 _ => true,
678             };
679             if f.alternate() {
680                 if should_show_cast {
681                     write!(f, "<{:#} as {:#}>::", self_type, trait_)?
682                 } else {
683                     write!(f, "{:#}::", self_type)?
684                 }
685             } else {
686                 if should_show_cast {
687                     write!(f, "&lt;{} as {}&gt;::", self_type, trait_)?
688                 } else {
689                     write!(f, "{}::", self_type)?
690                 }
691             };
692             match *trait_ {
693                 // It's pretty unsightly to look at `<A as B>::C` in output, and
694                 // we've got hyperlinking on our side, so try to avoid longer
695                 // notation as much as possible by making `C` a hyperlink to trait
696                 // `B` to disambiguate.
697                 //
698                 // FIXME: this is still a lossy conversion and there should probably
699                 //        be a better way of representing this in general? Most of
700                 //        the ugliness comes from inlining across crates where
701                 //        everything comes in as a fully resolved QPath (hard to
702                 //        look at).
703                 box clean::ResolvedPath { did, ref typarams, .. } => {
704                     match href(did) {
705                         Some((ref url, _, ref path)) if !f.alternate() => {
706                             write!(f,
707                                    "<a class=\"type\" href=\"{url}#{shortty}.{name}\" \
708                                    title=\"type {path}::{name}\">{name}</a>",
709                                    url = url,
710                                    shortty = ItemType::AssociatedType,
711                                    name = name,
712                                    path = path.join("::"))?;
713                         }
714                         _ => write!(f, "{}", name)?,
715                     }
716
717                     // FIXME: `typarams` are not rendered, and this seems bad?
718                     drop(typarams);
719                     Ok(())
720                 }
721                 _ => {
722                     write!(f, "{}", name)
723                 }
724             }
725         }
726         clean::Unique(..) => {
727             panic!("should have been cleaned")
728         }
729     }
730 }
731
732 impl fmt::Display for clean::Type {
733     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
734         fmt_type(self, f, false)
735     }
736 }
737
738 fn fmt_impl(i: &clean::Impl,
739             f: &mut fmt::Formatter,
740             link_trait: bool,
741             use_absolute: bool) -> fmt::Result {
742     if f.alternate() {
743         write!(f, "impl{:#} ", i.generics)?;
744     } else {
745         write!(f, "impl{} ", i.generics)?;
746     }
747
748     if let Some(ref ty) = i.trait_ {
749         if i.polarity == Some(clean::ImplPolarity::Negative) {
750             write!(f, "!")?;
751         }
752
753         if link_trait {
754             fmt::Display::fmt(ty, f)?;
755         } else {
756             match *ty {
757                 clean::ResolvedPath { typarams: None, ref path, is_generic: false, .. } => {
758                     let last = path.segments.last().unwrap();
759                     fmt::Display::fmt(&last.name, f)?;
760                     fmt::Display::fmt(&last.params, f)?;
761                 }
762                 _ => unreachable!(),
763             }
764         }
765         write!(f, " for ")?;
766     }
767
768     fmt_type(&i.for_, f, use_absolute)?;
769
770     fmt::Display::fmt(&WhereClause { gens: &i.generics, indent: 0, end_newline: true }, f)?;
771     Ok(())
772 }
773
774 impl fmt::Display for clean::Impl {
775     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
776         fmt_impl(self, f, true, false)
777     }
778 }
779
780 // The difference from above is that trait is not hyperlinked.
781 pub fn fmt_impl_for_trait_page(i: &clean::Impl,
782                                f: &mut fmt::Formatter,
783                                use_absolute: bool) -> fmt::Result {
784     fmt_impl(i, f, false, use_absolute)
785 }
786
787 impl fmt::Display for clean::Arguments {
788     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
789         for (i, input) in self.values.iter().enumerate() {
790             if !input.name.is_empty() {
791                 write!(f, "{}: ", input.name)?;
792             }
793             if f.alternate() {
794                 write!(f, "{:#}", input.type_)?;
795             } else {
796                 write!(f, "{}", input.type_)?;
797             }
798             if i + 1 < self.values.len() { write!(f, ", ")?; }
799         }
800         Ok(())
801     }
802 }
803
804 impl fmt::Display for clean::FunctionRetTy {
805     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
806         match *self {
807             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
808             clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
809             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
810             clean::DefaultReturn => Ok(()),
811         }
812     }
813 }
814
815 impl fmt::Display for clean::FnDecl {
816     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
817         if self.variadic {
818             if f.alternate() {
819                 write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output)
820             } else {
821                 write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
822             }
823         } else {
824             if f.alternate() {
825                 write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
826             } else {
827                 write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
828             }
829         }
830     }
831 }
832
833 impl<'a> fmt::Display for Method<'a> {
834     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835         let &Method { decl, name_len, indent } = self;
836         let amp = if f.alternate() { "&" } else { "&amp;" };
837         let mut args = String::new();
838         let mut args_plain = String::new();
839         for (i, input) in decl.inputs.values.iter().enumerate() {
840             if i == 0 {
841                 args.push_str("<br>");
842             }
843
844             if let Some(selfty) = input.to_self() {
845                 match selfty {
846                     clean::SelfValue => {
847                         args.push_str("self");
848                         args_plain.push_str("self");
849                     }
850                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
851                         args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
852                         args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
853                     }
854                     clean::SelfBorrowed(None, mtbl) => {
855                         args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
856                         args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
857                     }
858                     clean::SelfExplicit(ref typ) => {
859                         if f.alternate() {
860                             args.push_str(&format!("self: {:#}", *typ));
861                         } else {
862                             args.push_str(&format!("self: {}", *typ));
863                         }
864                         args_plain.push_str(&format!("self: {:#}", *typ));
865                     }
866                 }
867             } else {
868                 if i > 0 {
869                     args.push_str(" <br>");
870                     args_plain.push_str(" ");
871                 }
872                 if !input.name.is_empty() {
873                     args.push_str(&format!("{}: ", input.name));
874                     args_plain.push_str(&format!("{}: ", input.name));
875                 }
876
877                 if f.alternate() {
878                     args.push_str(&format!("{:#}", input.type_));
879                 } else {
880                     args.push_str(&format!("{}", input.type_));
881                 }
882                 args_plain.push_str(&format!("{:#}", input.type_));
883             }
884             if i + 1 < decl.inputs.values.len() {
885                 args.push(',');
886                 args_plain.push(',');
887             }
888         }
889
890         if decl.variadic {
891             args.push_str(",<br> ...");
892             args_plain.push_str(", ...");
893         }
894
895         let arrow_plain = format!("{:#}", decl.output);
896         let arrow = if f.alternate() {
897             format!("{:#}", decl.output)
898         } else {
899             format!("{}", decl.output)
900         };
901
902         let pad = repeat(" ").take(name_len).collect::<String>();
903         let plain = format!("{pad}({args}){arrow}",
904                         pad = pad,
905                         args = args_plain,
906                         arrow = arrow_plain);
907
908         let output = if plain.len() > 80 {
909             let full_pad = format!("<br>{}", repeat("&nbsp;").take(indent + 4).collect::<String>());
910             let close_pad = format!("<br>{}", repeat("&nbsp;").take(indent).collect::<String>());
911             format!("({args}{close}){arrow}",
912                     args = args.replace("<br>", &full_pad),
913                     close = close_pad,
914                     arrow = arrow)
915         } else {
916             format!("({args}){arrow}", args = args.replace("<br>", ""), arrow = arrow)
917         };
918
919         if f.alternate() {
920             write!(f, "{}", output.replace("<br>", "\n"))
921         } else {
922             write!(f, "{}", output)
923         }
924     }
925 }
926
927 impl<'a> fmt::Display for VisSpace<'a> {
928     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
929         match *self.get() {
930             Some(clean::Public) => write!(f, "pub "),
931             Some(clean::Inherited) | None => Ok(())
932         }
933     }
934 }
935
936 impl fmt::Display for UnsafetySpace {
937     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
938         match self.get() {
939             hir::Unsafety::Unsafe => write!(f, "unsafe "),
940             hir::Unsafety::Normal => Ok(())
941         }
942     }
943 }
944
945 impl fmt::Display for ConstnessSpace {
946     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
947         match self.get() {
948             hir::Constness::Const => write!(f, "const "),
949             hir::Constness::NotConst => Ok(())
950         }
951     }
952 }
953
954 impl fmt::Display for clean::Import {
955     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
956         match *self {
957             clean::Import::Simple(ref name, ref src) => {
958                 if *name == src.path.last_name() {
959                     write!(f, "use {};", *src)
960                 } else {
961                     write!(f, "use {} as {};", *src, *name)
962                 }
963             }
964             clean::Import::Glob(ref src) => {
965                 if src.path.segments.is_empty() {
966                     write!(f, "use *;")
967                 } else {
968                     write!(f, "use {}::*;", *src)
969                 }
970             }
971         }
972     }
973 }
974
975 impl fmt::Display for clean::ImportSource {
976     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
977         match self.did {
978             Some(did) => resolved_path(f, did, &self.path, true, false),
979             _ => {
980                 for (i, seg) in self.path.segments.iter().enumerate() {
981                     if i > 0 {
982                         write!(f, "::")?
983                     }
984                     write!(f, "{}", seg.name)?;
985                 }
986                 Ok(())
987             }
988         }
989     }
990 }
991
992 impl fmt::Display for clean::TypeBinding {
993     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
994         if f.alternate() {
995             write!(f, "{} = {:#}", self.name, self.ty)
996         } else {
997             write!(f, "{} = {}", self.name, self.ty)
998         }
999     }
1000 }
1001
1002 impl fmt::Display for MutableSpace {
1003     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1004         match *self {
1005             MutableSpace(clean::Immutable) => Ok(()),
1006             MutableSpace(clean::Mutable) => write!(f, "mut "),
1007         }
1008     }
1009 }
1010
1011 impl fmt::Display for RawMutableSpace {
1012     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1013         match *self {
1014             RawMutableSpace(clean::Immutable) => write!(f, "const "),
1015             RawMutableSpace(clean::Mutable) => write!(f, "mut "),
1016         }
1017     }
1018 }
1019
1020 impl fmt::Display for AbiSpace {
1021     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1022         let quot = if f.alternate() { "\"" } else { "&quot;" };
1023         match self.0 {
1024             Abi::Rust => Ok(()),
1025             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1026         }
1027     }
1028 }