]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2013 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 | use std::fmt; | |
c34b1796 | 12 | use std::io; |
2c00a5a8 | 13 | use std::path::PathBuf; |
1a4d82fc JJ |
14 | |
15 | use externalfiles::ExternalHtml; | |
16 | ||
17 | #[derive(Clone)] | |
18 | pub struct Layout { | |
19 | pub logo: String, | |
20 | pub favicon: String, | |
21 | pub external_html: ExternalHtml, | |
22 | pub krate: String, | |
1a4d82fc JJ |
23 | } |
24 | ||
25 | pub struct Page<'a> { | |
26 | pub title: &'a str, | |
9e0c209e | 27 | pub css_class: &'a str, |
1a4d82fc JJ |
28 | pub root_path: &'a str, |
29 | pub description: &'a str, | |
54a0048b | 30 | pub keywords: &'a str, |
0531ce1d | 31 | pub resource_suffix: &'a str, |
1a4d82fc JJ |
32 | } |
33 | ||
85aaf69f | 34 | pub fn render<T: fmt::Display, S: fmt::Display>( |
54a0048b | 35 | dst: &mut io::Write, layout: &Layout, page: &Page, sidebar: &S, t: &T, |
2c00a5a8 | 36 | css_file_extension: bool, themes: &[PathBuf]) |
c34b1796 | 37 | -> io::Result<()> |
1a4d82fc JJ |
38 | { |
39 | write!(dst, | |
40 | r##"<!DOCTYPE html> | |
41 | <html lang="en"> | |
42 | <head> | |
43 | <meta charset="utf-8"> | |
44 | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
45 | <meta name="generator" content="rustdoc"> | |
46 | <meta name="description" content="{description}"> | |
47 | <meta name="keywords" content="{keywords}"> | |
48 | ||
49 | <title>{title}</title> | |
50 | ||
0531ce1d XL |
51 | <link rel="stylesheet" type="text/css" href="{root_path}normalize{suffix}.css"> |
52 | <link rel="stylesheet" type="text/css" href="{root_path}rustdoc{suffix}.css" | |
53 | id="mainThemeStyle"> | |
2c00a5a8 | 54 | {themes} |
0531ce1d XL |
55 | <link rel="stylesheet" type="text/css" href="{root_path}dark{suffix}.css"> |
56 | <link rel="stylesheet" type="text/css" href="{root_path}light{suffix}.css" id="themeStyle"> | |
57 | <script src="{root_path}storage{suffix}.js"></script> | |
54a0048b | 58 | {css_extension} |
1a4d82fc JJ |
59 | |
60 | {favicon} | |
61 | {in_header} | |
62 | </head> | |
8bb4bdeb | 63 | <body class="rustdoc {css_class}"> |
1a4d82fc JJ |
64 | <!--[if lte IE 8]> |
65 | <div class="warning"> | |
66 | This old browser is unsupported and will most likely display funky | |
67 | things. | |
68 | </div> | |
69 | <![endif]--> | |
70 | ||
71 | {before_content} | |
72 | ||
e9174d1e | 73 | <nav class="sidebar"> |
ff7c6d11 | 74 | <div class="sidebar-menu">☰</div> |
1a4d82fc JJ |
75 | {logo} |
76 | {sidebar} | |
e9174d1e | 77 | </nav> |
1a4d82fc | 78 | |
2c00a5a8 XL |
79 | <div class="theme-picker"> |
80 | <button id="theme-picker" aria-label="Pick another theme!"> | |
0531ce1d | 81 | <img src="{root_path}brush{suffix}.svg" width="18" alt="Pick another theme!"> |
2c00a5a8 XL |
82 | </button> |
83 | <div id="theme-choices"></div> | |
84 | </div> | |
0531ce1d | 85 | <script src="{root_path}theme{suffix}.js"></script> |
1a4d82fc JJ |
86 | <nav class="sub"> |
87 | <form class="search-form js-only"> | |
88 | <div class="search-container"> | |
89 | <input class="search-input" name="search" | |
90 | autocomplete="off" | |
c1a9b12d | 91 | placeholder="Click or press ‘S’ to search, ‘?’ for more options…" |
1a4d82fc JJ |
92 | type="search"> |
93 | </div> | |
94 | </form> | |
95 | </nav> | |
96 | ||
8bb4bdeb | 97 | <section id='main' class="content">{content}</section> |
1a4d82fc JJ |
98 | <section id='search' class="content hidden"></section> |
99 | ||
100 | <section class="footer"></section> | |
101 | ||
e9174d1e | 102 | <aside id="help" class="hidden"> |
c1a9b12d | 103 | <div> |
e9174d1e SL |
104 | <h1 class="hidden">Help</h1> |
105 | ||
c1a9b12d | 106 | <div class="shortcuts"> |
e9174d1e | 107 | <h2>Keyboard Shortcuts</h2> |
c1a9b12d SL |
108 | |
109 | <dl> | |
2c00a5a8 | 110 | <dt><kbd>?</kbd></dt> |
c1a9b12d | 111 | <dd>Show this help dialog</dd> |
2c00a5a8 | 112 | <dt><kbd>S</kbd></dt> |
c1a9b12d | 113 | <dd>Focus the search field</dd> |
2c00a5a8 | 114 | <dt><kbd>↑</kbd></dt> |
c1a9b12d | 115 | <dd>Move up in search results</dd> |
2c00a5a8 | 116 | <dt><kbd>↓</kbd></dt> |
c1a9b12d | 117 | <dd>Move down in search results</dd> |
2c00a5a8 | 118 | <dt><kbd>↹</kbd></dt> |
abe05a73 | 119 | <dd>Switch tab</dd> |
2c00a5a8 | 120 | <dt><kbd>⏎</kbd></dt> |
c1a9b12d | 121 | <dd>Go to active search result</dd> |
2c00a5a8 XL |
122 | <dt><kbd>+</kbd></dt> |
123 | <dd>Expand all sections</dd> | |
124 | <dt><kbd>-</kbd></dt> | |
125 | <dd>Collapse all sections</dd> | |
c1a9b12d SL |
126 | </dl> |
127 | </div> | |
128 | ||
129 | <div class="infos"> | |
e9174d1e | 130 | <h2>Search Tricks</h2> |
c1a9b12d SL |
131 | |
132 | <p> | |
133 | Prefix searches with a type followed by a colon (e.g. | |
134 | <code>fn:</code>) to restrict the search to a given type. | |
135 | </p> | |
136 | ||
137 | <p> | |
138 | Accepted types are: <code>fn</code>, <code>mod</code>, | |
139 | <code>struct</code>, <code>enum</code>, | |
e9174d1e SL |
140 | <code>trait</code>, <code>type</code>, <code>macro</code>, |
141 | and <code>const</code>. | |
c1a9b12d SL |
142 | </p> |
143 | ||
144 | <p> | |
145 | Search functions by type signature (e.g. | |
7453a54e | 146 | <code>vec -> usize</code> or <code>* -> vec</code>) |
c1a9b12d SL |
147 | </p> |
148 | </div> | |
1a4d82fc | 149 | </div> |
e9174d1e | 150 | </aside> |
1a4d82fc JJ |
151 | |
152 | {after_content} | |
153 | ||
154 | <script> | |
155 | window.rootPath = "{root_path}"; | |
156 | window.currentCrate = "{krate}"; | |
1a4d82fc | 157 | </script> |
0531ce1d | 158 | <script src="{root_path}main{suffix}.js"></script> |
92a42be0 | 159 | <script defer src="{root_path}search-index.js"></script> |
1a4d82fc JJ |
160 | </body> |
161 | </html>"##, | |
54a0048b | 162 | css_extension = if css_file_extension { |
0531ce1d XL |
163 | format!("<link rel=\"stylesheet\" type=\"text/css\" href=\"{root_path}theme{suffix}.css\">", |
164 | root_path = page.root_path, | |
165 | suffix=page.resource_suffix) | |
54a0048b SL |
166 | } else { |
167 | "".to_owned() | |
168 | }, | |
1a4d82fc JJ |
169 | content = *t, |
170 | root_path = page.root_path, | |
9e0c209e | 171 | css_class = page.css_class, |
9346a6ac | 172 | logo = if layout.logo.is_empty() { |
1a4d82fc JJ |
173 | "".to_string() |
174 | } else { | |
175 | format!("<a href='{}{}/index.html'>\ | |
7453a54e | 176 | <img src='{}' alt='logo' width='100'></a>", |
1a4d82fc JJ |
177 | page.root_path, layout.krate, |
178 | layout.logo) | |
179 | }, | |
180 | title = page.title, | |
181 | description = page.description, | |
182 | keywords = page.keywords, | |
9346a6ac | 183 | favicon = if layout.favicon.is_empty() { |
1a4d82fc JJ |
184 | "".to_string() |
185 | } else { | |
186 | format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon) | |
187 | }, | |
188 | in_header = layout.external_html.in_header, | |
189 | before_content = layout.external_html.before_content, | |
190 | after_content = layout.external_html.after_content, | |
191 | sidebar = *sidebar, | |
192 | krate = layout.krate, | |
2c00a5a8 XL |
193 | themes = themes.iter() |
194 | .filter_map(|t| t.file_stem()) | |
195 | .filter_map(|t| t.to_str()) | |
196 | .map(|t| format!(r#"<link rel="stylesheet" type="text/css" href="{}{}">"#, | |
0531ce1d XL |
197 | page.root_path, |
198 | t.replace(".css", &format!("{}.css", page.resource_suffix)))) | |
2c00a5a8 | 199 | .collect::<String>(), |
0531ce1d | 200 | suffix=page.resource_suffix, |
1a4d82fc JJ |
201 | ) |
202 | } | |
203 | ||
c34b1796 | 204 | pub fn redirect(dst: &mut io::Write, url: &str) -> io::Result<()> { |
1a4d82fc JJ |
205 | // <script> triggers a redirect before refresh, so this is fine. |
206 | write!(dst, | |
207 | r##"<!DOCTYPE html> | |
208 | <html lang="en"> | |
209 | <head> | |
210 | <meta http-equiv="refresh" content="0;URL={url}"> | |
211 | </head> | |
212 | <body> | |
213 | <p>Redirecting to <a href="{url}">{url}</a>...</p> | |
214 | <script>location.replace("{url}" + location.search + location.hash);</script> | |
215 | </body> | |
216 | </html>"##, | |
217 | url = url, | |
218 | ) | |
219 | } |