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