]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/html/format.rs
eef530081abe358b00ec2da39f707682f4fc76f1
[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, LOCAL_CRATE};
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'>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() > 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                     clause = clause.replace("class='where'", "class='where fmt-newline'");
215                     repeat("&nbsp;").take(8).collect::<String>()
216                 } else {
217                     repeat("&nbsp;").take(pad + 6).collect::<String>()
218                 };
219                 clause = clause.replace("<br>", &format!("<br>{}", padding));
220             } else {
221                 clause = clause.replace("<br>", " ");
222             }
223         }
224         write!(f, "{}", clause)
225     }
226 }
227
228 impl fmt::Display for clean::Lifetime {
229     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230         f.write_str(self.get_ref())?;
231         Ok(())
232     }
233 }
234
235 impl fmt::Display for clean::PolyTrait {
236     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237         if !self.lifetimes.is_empty() {
238             if f.alternate() {
239                 f.write_str("for<")?;
240             } else {
241                 f.write_str("for&lt;")?;
242             }
243             for (i, lt) in self.lifetimes.iter().enumerate() {
244                 if i > 0 {
245                     f.write_str(", ")?;
246                 }
247                 write!(f, "{}", lt)?;
248             }
249             if f.alternate() {
250                 f.write_str("> ")?;
251             } else {
252                 f.write_str("&gt; ")?;
253             }
254         }
255         if f.alternate() {
256             write!(f, "{:#}", self.trait_)
257         } else {
258             write!(f, "{}", self.trait_)
259         }
260     }
261 }
262
263 impl fmt::Display for clean::TyParamBound {
264     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
265         match *self {
266             clean::RegionBound(ref lt) => {
267                 write!(f, "{}", *lt)
268             }
269             clean::TraitBound(ref ty, modifier) => {
270                 let modifier_str = match modifier {
271                     hir::TraitBoundModifier::None => "",
272                     hir::TraitBoundModifier::Maybe => "?",
273                 };
274                 if f.alternate() {
275                     write!(f, "{}{:#}", modifier_str, *ty)
276                 } else {
277                     write!(f, "{}{}", modifier_str, *ty)
278                 }
279             }
280         }
281     }
282 }
283
284 impl fmt::Display for clean::PathParameters {
285     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286         match *self {
287             clean::PathParameters::AngleBracketed {
288                 ref lifetimes, ref types, ref bindings
289             } => {
290                 if !lifetimes.is_empty() || !types.is_empty() || !bindings.is_empty() {
291                     if f.alternate() {
292                         f.write_str("<")?;
293                     } else {
294                         f.write_str("&lt;")?;
295                     }
296                     let mut comma = false;
297                     for lifetime in lifetimes {
298                         if comma {
299                             f.write_str(", ")?;
300                         }
301                         comma = true;
302                         write!(f, "{}", *lifetime)?;
303                     }
304                     for ty in types {
305                         if comma {
306                             f.write_str(", ")?;
307                         }
308                         comma = true;
309                         if f.alternate() {
310                             write!(f, "{:#}", *ty)?;
311                         } else {
312                             write!(f, "{}", *ty)?;
313                         }
314                     }
315                     for binding in bindings {
316                         if comma {
317                             f.write_str(", ")?;
318                         }
319                         comma = true;
320                         if f.alternate() {
321                             write!(f, "{:#}", *binding)?;
322                         } else {
323                             write!(f, "{}", *binding)?;
324                         }
325                     }
326                     if f.alternate() {
327                         f.write_str(">")?;
328                     } else {
329                         f.write_str("&gt;")?;
330                     }
331                 }
332             }
333             clean::PathParameters::Parenthesized { ref inputs, ref output } => {
334                 f.write_str("(")?;
335                 let mut comma = false;
336                 for ty in inputs {
337                     if comma {
338                         f.write_str(", ")?;
339                     }
340                     comma = true;
341                     if f.alternate() {
342                         write!(f, "{:#}", *ty)?;
343                     } else {
344                         write!(f, "{}", *ty)?;
345                     }
346                 }
347                 f.write_str(")")?;
348                 if let Some(ref ty) = *output {
349                     if f.alternate() {
350                         write!(f, " -> {:#}", ty)?;
351                     } else {
352                         write!(f, " -&gt; {}", ty)?;
353                     }
354                 }
355             }
356         }
357         Ok(())
358     }
359 }
360
361 impl fmt::Display for clean::PathSegment {
362     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
363         f.write_str(&self.name)?;
364         if f.alternate() {
365             write!(f, "{:#}", self.params)
366         } else {
367             write!(f, "{}", self.params)
368         }
369     }
370 }
371
372 impl fmt::Display for clean::Path {
373     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
374         if self.global {
375             f.write_str("::")?
376         }
377
378         for (i, seg) in self.segments.iter().enumerate() {
379             if i > 0 {
380                 f.write_str("::")?
381             }
382             if f.alternate() {
383                 write!(f, "{:#}", seg)?;
384             } else {
385                 write!(f, "{}", seg)?;
386             }
387         }
388         Ok(())
389     }
390 }
391
392 pub fn href(did: DefId) -> Option<(String, ItemType, Vec<String>)> {
393     let cache = cache();
394     if !did.is_local() && !cache.access_levels.is_doc_reachable(did) {
395         return None
396     }
397
398     let loc = CURRENT_LOCATION_KEY.with(|l| l.borrow().clone());
399     let (fqp, shortty, mut url) = match cache.paths.get(&did) {
400         Some(&(ref fqp, shortty)) => {
401             (fqp, shortty, repeat("../").take(loc.len()).collect())
402         }
403         None => match cache.external_paths.get(&did) {
404             Some(&(ref fqp, shortty)) => {
405                 (fqp, shortty, match cache.extern_locations[&did.krate] {
406                     (_, render::Remote(ref s)) => s.to_string(),
407                     (_, render::Local) => repeat("../").take(loc.len()).collect(),
408                     (_, render::Unknown) => return None,
409                 })
410             }
411             None => return None,
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) -> fmt::Result {
437     let last = path.segments.last().unwrap();
438     let rel_root = match &*path.segments[0].name {
439         "self" => Some("./".to_string()),
440         _ => None,
441     };
442
443     if print_all {
444         let amt = path.segments.len() - 1;
445         match rel_root {
446             Some(mut root) => {
447                 for seg in &path.segments[..amt] {
448                     if "super" == seg.name || "self" == seg.name || w.alternate() {
449                         write!(w, "{}::", seg.name)?;
450                     } else {
451                         root.push_str(&seg.name);
452                         root.push_str("/");
453                         write!(w, "<a class='mod'
454                                        href='{}index.html'>{}</a>::",
455                                  root,
456                                  seg.name)?;
457                     }
458                 }
459             }
460             None => {
461                 for seg in &path.segments[..amt] {
462                     write!(w, "{}::", seg.name)?;
463                 }
464             }
465         }
466     }
467     if w.alternate() {
468         write!(w, "{:#}{:#}", HRef::new(did, &last.name), last.params)?;
469     } else {
470         write!(w, "{}{}", HRef::new(did, &last.name), last.params)?;
471     }
472     Ok(())
473 }
474
475 fn primitive_link(f: &mut fmt::Formatter,
476                   prim: clean::PrimitiveType,
477                   name: &str) -> fmt::Result {
478     let m = cache();
479     let mut needs_termination = false;
480     if !f.alternate() {
481         match m.primitive_locations.get(&prim) {
482             Some(&LOCAL_CRATE) => {
483                 let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
484                 let len = if len == 0 {0} else {len - 1};
485                 write!(f, "<a class='primitive' href='{}primitive.{}.html'>",
486                        repeat("../").take(len).collect::<String>(),
487                        prim.to_url_str())?;
488                 needs_termination = true;
489             }
490             Some(&cnum) => {
491                 let loc = match m.extern_locations[&cnum] {
492                     (ref cname, render::Remote(ref s)) => Some((cname, s.to_string())),
493                     (ref cname, render::Local) => {
494                         let len = CURRENT_LOCATION_KEY.with(|s| s.borrow().len());
495                         Some((cname, repeat("../").take(len).collect::<String>()))
496                     }
497                     (_, render::Unknown) => None,
498                 };
499                 if let Some((cname, root)) = loc {
500                     write!(f, "<a class='primitive' href='{}{}/primitive.{}.html'>",
501                            root,
502                            cname,
503                            prim.to_url_str())?;
504                     needs_termination = true;
505                 }
506             }
507             None => {}
508         }
509     }
510     write!(f, "{}", name)?;
511     if needs_termination {
512         write!(f, "</a>")?;
513     }
514     Ok(())
515 }
516
517 /// Helper to render type parameters
518 fn tybounds(w: &mut fmt::Formatter,
519             typarams: &Option<Vec<clean::TyParamBound> >) -> fmt::Result {
520     match *typarams {
521         Some(ref params) => {
522             for param in params {
523                 write!(w, " + ")?;
524                 fmt::Display::fmt(param, w)?;
525             }
526             Ok(())
527         }
528         None => Ok(())
529     }
530 }
531
532 impl<'a> HRef<'a> {
533     pub fn new(did: DefId, text: &'a str) -> HRef<'a> {
534         HRef { did: did, text: text }
535     }
536 }
537
538 impl<'a> fmt::Display for HRef<'a> {
539     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
540         match href(self.did) {
541             Some((url, shortty, fqp)) => if !f.alternate() {
542                 write!(f, "<a class='{}' href='{}' title='{}'>{}</a>",
543                        shortty, url, fqp.join("::"), self.text)
544             } else {
545                 write!(f, "{}", self.text)
546             },
547             _ => write!(f, "{}", self.text),
548         }
549     }
550 }
551
552 impl fmt::Display for clean::Type {
553     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
554         match *self {
555             clean::Generic(ref name) => {
556                 f.write_str(name)
557             }
558             clean::ResolvedPath{ did, ref typarams, ref path, is_generic } => {
559                 // Paths like T::Output and Self::Output should be rendered with all segments
560                 resolved_path(f, did, path, is_generic)?;
561                 tybounds(f, typarams)
562             }
563             clean::Infer => write!(f, "_"),
564             clean::Primitive(prim) => primitive_link(f, prim, prim.as_str()),
565             clean::BareFunction(ref decl) => {
566                 if f.alternate() {
567                     write!(f, "{}{}fn{:#}{:#}",
568                            UnsafetySpace(decl.unsafety),
569                            AbiSpace(decl.abi),
570                            decl.generics,
571                            decl.decl)
572                 } else {
573                     write!(f, "{}{}fn{}{}",
574                            UnsafetySpace(decl.unsafety),
575                            AbiSpace(decl.abi),
576                            decl.generics,
577                            decl.decl)
578                 }
579             }
580             clean::Tuple(ref typs) => {
581                 match &typs[..] {
582                     &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
583                     &[ref one] => {
584                         primitive_link(f, PrimitiveType::Tuple, "(")?;
585                         //carry f.alternate() into this display w/o branching manually
586                         fmt::Display::fmt(one, f)?;
587                         primitive_link(f, PrimitiveType::Tuple, ",)")
588                     }
589                     many => {
590                         primitive_link(f, PrimitiveType::Tuple, "(")?;
591                         fmt::Display::fmt(&CommaSep(&many), f)?;
592                         primitive_link(f, PrimitiveType::Tuple, ")")
593                     }
594                 }
595             }
596             clean::Vector(ref t) => {
597                 primitive_link(f, PrimitiveType::Slice, &format!("["))?;
598                 fmt::Display::fmt(t, f)?;
599                 primitive_link(f, PrimitiveType::Slice, &format!("]"))
600             }
601             clean::FixedVector(ref t, ref s) => {
602                 primitive_link(f, PrimitiveType::Array, "[")?;
603                 fmt::Display::fmt(t, f)?;
604                 if f.alternate() {
605                     primitive_link(f, PrimitiveType::Array,
606                                    &format!("; {}]", s))
607                 } else {
608                     primitive_link(f, PrimitiveType::Array,
609                                    &format!("; {}]", Escape(s)))
610                 }
611             }
612             clean::Never => f.write_str("!"),
613             clean::RawPointer(m, ref t) => {
614                 match **t {
615                     clean::Generic(_) | clean::ResolvedPath {is_generic: true, ..} => {
616                         if f.alternate() {
617                             primitive_link(f, clean::PrimitiveType::RawPointer,
618                                            &format!("*{}{:#}", RawMutableSpace(m), t))
619                         } else {
620                             primitive_link(f, clean::PrimitiveType::RawPointer,
621                                            &format!("*{}{}", RawMutableSpace(m), t))
622                         }
623                     }
624                     _ => {
625                         primitive_link(f, clean::PrimitiveType::RawPointer,
626                                        &format!("*{}", RawMutableSpace(m)))?;
627                         fmt::Display::fmt(t, f)
628                     }
629                 }
630             }
631             clean::BorrowedRef{ lifetime: ref l, mutability, type_: ref ty} => {
632                 let lt = match *l {
633                     Some(ref l) => format!("{} ", *l),
634                     _ => "".to_string(),
635                 };
636                 let m = MutableSpace(mutability);
637                 match **ty {
638                     clean::Vector(ref bt) => { // BorrowedRef{ ... Vector(T) } is &[T]
639                         match **bt {
640                             clean::Generic(_) =>
641                                 if f.alternate() {
642                                     primitive_link(f, PrimitiveType::Slice,
643                                         &format!("&{}{}[{:#}]", lt, m, **bt))
644                                 } else {
645                                     primitive_link(f, PrimitiveType::Slice,
646                                         &format!("&amp;{}{}[{}]", lt, m, **bt))
647                                 },
648                             _ => {
649                                 if f.alternate() {
650                                     primitive_link(f, PrimitiveType::Slice,
651                                                    &format!("&{}{}[", lt, m))?;
652                                     write!(f, "{:#}", **bt)?;
653                                 } else {
654                                     primitive_link(f, PrimitiveType::Slice,
655                                                    &format!("&amp;{}{}[", lt, m))?;
656                                     write!(f, "{}", **bt)?;
657                                 }
658                                 primitive_link(f, PrimitiveType::Slice, "]")
659                             }
660                         }
661                     }
662                     _ => {
663                         if f.alternate() {
664                             write!(f, "&{}{}{:#}", lt, m, **ty)
665                         } else {
666                             write!(f, "&amp;{}{}{}", lt, m, **ty)
667                         }
668                     }
669                 }
670             }
671             clean::PolyTraitRef(ref bounds) => {
672                 for (i, bound) in bounds.iter().enumerate() {
673                     if i != 0 {
674                         write!(f, " + ")?;
675                     }
676                     if f.alternate() {
677                         write!(f, "{:#}", *bound)?;
678                     } else {
679                         write!(f, "{}", *bound)?;
680                     }
681                 }
682                 Ok(())
683             }
684             clean::ImplTrait(ref bounds) => {
685                 write!(f, "impl ")?;
686                 for (i, bound) in bounds.iter().enumerate() {
687                     if i != 0 {
688                         write!(f, " + ")?;
689                     }
690                     if f.alternate() {
691                         write!(f, "{:#}", *bound)?;
692                     } else {
693                         write!(f, "{}", *bound)?;
694                     }
695                 }
696                 Ok(())
697             }
698             // It's pretty unsightly to look at `<A as B>::C` in output, and
699             // we've got hyperlinking on our side, so try to avoid longer
700             // notation as much as possible by making `C` a hyperlink to trait
701             // `B` to disambiguate.
702             //
703             // FIXME: this is still a lossy conversion and there should probably
704             //        be a better way of representing this in general? Most of
705             //        the ugliness comes from inlining across crates where
706             //        everything comes in as a fully resolved QPath (hard to
707             //        look at).
708             clean::QPath {
709                 ref name,
710                 ref self_type,
711                 trait_: box clean::ResolvedPath { did, ref typarams, .. },
712             } => {
713                 if f.alternate() {
714                     write!(f, "{:#}::", self_type)?;
715                 } else {
716                     write!(f, "{}::", self_type)?;
717                 }
718                 let path = clean::Path::singleton(name.clone());
719                 resolved_path(f, did, &path, false)?;
720
721                 // FIXME: `typarams` are not rendered, and this seems bad?
722                 drop(typarams);
723                 Ok(())
724             }
725             clean::QPath { ref name, ref self_type, ref trait_ } => {
726                 if f.alternate() {
727                     write!(f, "<{:#} as {:#}>::{}", self_type, trait_, name)
728                 } else {
729                     write!(f, "&lt;{} as {}&gt;::{}", self_type, trait_, name)
730                 }
731             }
732             clean::Unique(..) => {
733                 panic!("should have been cleaned")
734             }
735         }
736     }
737 }
738
739 fn fmt_impl(i: &clean::Impl, f: &mut fmt::Formatter, link_trait: bool) -> fmt::Result {
740     let mut plain = String::new();
741
742     if f.alternate() {
743         write!(f, "impl{:#} ", i.generics)?;
744     } else {
745         write!(f, "impl{} ", i.generics)?;
746     }
747     plain.push_str(&format!("impl{:#} ", i.generics));
748
749     if let Some(ref ty) = i.trait_ {
750         if i.polarity == Some(clean::ImplPolarity::Negative) {
751             write!(f, "!")?;
752             plain.push_str("!");
753         }
754
755         if link_trait {
756             fmt::Display::fmt(ty, f)?;
757             plain.push_str(&format!("{:#}", ty));
758         } else {
759             match *ty {
760                 clean::ResolvedPath{ typarams: None, ref path, is_generic: false, .. } => {
761                     let last = path.segments.last().unwrap();
762                     fmt::Display::fmt(&last.name, f)?;
763                     fmt::Display::fmt(&last.params, f)?;
764                     plain.push_str(&format!("{:#}{:#}", last.name, last.params));
765                 }
766                 _ => unreachable!(),
767             }
768         }
769         write!(f, " for ")?;
770         plain.push_str(" for ");
771     }
772
773     fmt::Display::fmt(&i.for_, f)?;
774     plain.push_str(&format!("{:#}", i.for_));
775
776     fmt::Display::fmt(&WhereClause(&i.generics, plain.len() + 1), 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)
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, f: &mut fmt::Formatter) -> fmt::Result {
788     fmt_impl(i, f, false)
789 }
790
791 impl fmt::Display for clean::Arguments {
792     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
793         for (i, input) in self.values.iter().enumerate() {
794             if !input.name.is_empty() {
795                 write!(f, "{}: ", input.name)?;
796             }
797             if f.alternate() {
798                 write!(f, "{:#}", input.type_)?;
799             } else {
800                 write!(f, "{}", input.type_)?;
801             }
802             if i + 1 < self.values.len() { write!(f, ", ")?; }
803         }
804         Ok(())
805     }
806 }
807
808 impl fmt::Display for clean::FunctionRetTy {
809     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
810         match *self {
811             clean::Return(clean::Tuple(ref tys)) if tys.is_empty() => Ok(()),
812             clean::Return(ref ty) if f.alternate() => write!(f, " -> {:#}", ty),
813             clean::Return(ref ty) => write!(f, " -&gt; {}", ty),
814             clean::DefaultReturn => Ok(()),
815         }
816     }
817 }
818
819 impl fmt::Display for clean::FnDecl {
820     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
821         if self.variadic {
822             if f.alternate() {
823                 write!(f, "({args:#}, ...){arrow:#}", args = self.inputs, arrow = self.output)
824             } else {
825                 write!(f, "({args}, ...){arrow}", args = self.inputs, arrow = self.output)
826             }
827         } else {
828             if f.alternate() {
829                 write!(f, "({args:#}){arrow:#}", args = self.inputs, arrow = self.output)
830             } else {
831                 write!(f, "({args}){arrow}", args = self.inputs, arrow = self.output)
832             }
833         }
834     }
835 }
836
837 impl<'a> fmt::Display for Method<'a> {
838     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
839         let decl = self.0;
840         let indent = self.1;
841         let amp = if f.alternate() { "&" } else { "&amp;" };
842         let mut args = String::new();
843         let mut args_plain = String::new();
844         for (i, input) in decl.inputs.values.iter().enumerate() {
845             if let Some(selfty) = input.to_self() {
846                 match selfty {
847                     clean::SelfValue => {
848                         args.push_str("self");
849                         args_plain.push_str("self");
850                     }
851                     clean::SelfBorrowed(Some(ref lt), mtbl) => {
852                         args.push_str(&format!("{}{} {}self", amp, *lt, MutableSpace(mtbl)));
853                         args_plain.push_str(&format!("&{} {}self", *lt, MutableSpace(mtbl)));
854                     }
855                     clean::SelfBorrowed(None, mtbl) => {
856                         args.push_str(&format!("{}{}self", amp, MutableSpace(mtbl)));
857                         args_plain.push_str(&format!("&{}self", MutableSpace(mtbl)));
858                     }
859                     clean::SelfExplicit(ref typ) => {
860                         if f.alternate() {
861                             args.push_str(&format!("self: {:#}", *typ));
862                         } else {
863                             args.push_str(&format!("self: {}", *typ));
864                         }
865                         args_plain.push_str(&format!("self: {:#}", *typ));
866                     }
867                 }
868             } else {
869                 if i > 0 {
870                     args.push_str("<br> ");
871                     args_plain.push_str(" ");
872                 }
873                 if !input.name.is_empty() {
874                     args.push_str(&format!("{}: ", input.name));
875                     args_plain.push_str(&format!("{}: ", input.name));
876                 }
877
878                 if f.alternate() {
879                     args.push_str(&format!("{:#}", input.type_));
880                 } else {
881                     args.push_str(&format!("{}", input.type_));
882                 }
883                 args_plain.push_str(&format!("{:#}", input.type_));
884             }
885             if i + 1 < decl.inputs.values.len() {
886                 args.push_str(",");
887                 args_plain.push_str(",");
888             }
889         }
890
891         if decl.variadic {
892             args.push_str(",<br> ...");
893             args_plain.push_str(", ...");
894         }
895
896         let arrow_plain = format!("{:#}", decl.output);
897         let arrow = if f.alternate() {
898             format!("{:#}", decl.output)
899         } else {
900             format!("{}", decl.output)
901         };
902
903         let mut output: String;
904         let plain: String;
905         let pad = repeat(" ").take(indent).collect::<String>();
906         if arrow.is_empty() {
907             output = format!("({})", args);
908             plain = format!("{}({})", pad, args_plain);
909         } else {
910             output = format!("({args})<br>{arrow}", args = args, arrow = arrow);
911             plain = format!("{pad}({args}){arrow}",
912                             pad = pad,
913                             args = args_plain,
914                             arrow = arrow_plain);
915         }
916
917         if plain.len() > 80 {
918             let pad = repeat("&nbsp;").take(indent).collect::<String>();
919             let pad = format!("<br>{}", pad);
920             output = output.replace("<br>", &pad);
921         } else {
922             output = output.replace("<br>", "");
923         }
924         if f.alternate() {
925             write!(f, "{}", output.replace("<br>", "\n"))
926         } else {
927             write!(f, "{}", output)
928         }
929     }
930 }
931
932 impl<'a> fmt::Display for VisSpace<'a> {
933     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
934         match *self.get() {
935             Some(clean::Public) => write!(f, "pub "),
936             Some(clean::Inherited) | None => Ok(())
937         }
938     }
939 }
940
941 impl fmt::Display for UnsafetySpace {
942     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
943         match self.get() {
944             hir::Unsafety::Unsafe => write!(f, "unsafe "),
945             hir::Unsafety::Normal => Ok(())
946         }
947     }
948 }
949
950 impl fmt::Display for ConstnessSpace {
951     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
952         match self.get() {
953             hir::Constness::Const => write!(f, "const "),
954             hir::Constness::NotConst => Ok(())
955         }
956     }
957 }
958
959 impl fmt::Display for clean::Import {
960     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
961         match *self {
962             clean::Import::Simple(ref name, ref src) => {
963                 if *name == src.path.last_name() {
964                     write!(f, "use {};", *src)
965                 } else {
966                     write!(f, "use {} as {};", *src, *name)
967                 }
968             }
969             clean::Import::Glob(ref src) => {
970                 write!(f, "use {}::*;", *src)
971             }
972             clean::Import::List(ref src, ref names) => {
973                 write!(f, "use {}::{{", *src)?;
974                 for (i, n) in names.iter().enumerate() {
975                     if i > 0 {
976                         write!(f, ", ")?;
977                     }
978                     write!(f, "{}", *n)?;
979                 }
980                 write!(f, "}};")
981             }
982         }
983     }
984 }
985
986 impl fmt::Display for clean::ImportSource {
987     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
988         match self.did {
989             Some(did) => resolved_path(f, did, &self.path, true),
990             _ => {
991                 for (i, seg) in self.path.segments.iter().enumerate() {
992                     if i > 0 {
993                         write!(f, "::")?
994                     }
995                     write!(f, "{}", seg.name)?;
996                 }
997                 Ok(())
998             }
999         }
1000     }
1001 }
1002
1003 impl fmt::Display for clean::ViewListIdent {
1004     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1005         match self.source {
1006             Some(did) => {
1007                 let path = clean::Path::singleton(self.name.clone());
1008                 resolved_path(f, did, &path, false)?;
1009             }
1010             _ => write!(f, "{}", self.name)?,
1011         }
1012
1013         if let Some(ref name) = self.rename {
1014             write!(f, " as {}", name)?;
1015         }
1016         Ok(())
1017     }
1018 }
1019
1020 impl fmt::Display for clean::TypeBinding {
1021     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1022         if f.alternate() {
1023             write!(f, "{}={:#}", self.name, self.ty)
1024         } else {
1025             write!(f, "{}={}", self.name, self.ty)
1026         }
1027     }
1028 }
1029
1030 impl fmt::Display for MutableSpace {
1031     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1032         match *self {
1033             MutableSpace(clean::Immutable) => Ok(()),
1034             MutableSpace(clean::Mutable) => write!(f, "mut "),
1035         }
1036     }
1037 }
1038
1039 impl fmt::Display for RawMutableSpace {
1040     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1041         match *self {
1042             RawMutableSpace(clean::Immutable) => write!(f, "const "),
1043             RawMutableSpace(clean::Mutable) => write!(f, "mut "),
1044         }
1045     }
1046 }
1047
1048 impl fmt::Display for AbiSpace {
1049     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1050         let quot = if f.alternate() { "\"" } else { "&quot;" };
1051         match self.0 {
1052             Abi::Rust => Ok(()),
1053             Abi::C => write!(f, "extern "),
1054             abi => write!(f, "extern {0}{1}{0} ", quot, abi.name()),
1055         }
1056     }
1057 }