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