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