@@ -7,7 +7,9 @@ use crate::html::escape::Escape;
7
7
use crate :: html:: format:: { Buffer , Print } ;
8
8
use crate :: html:: render:: { ensure_trailing_slash, StylePath } ;
9
9
10
- #[ derive( Clone ) ]
10
+ use serde:: Serialize ;
11
+
12
+ #[ derive( Clone , Serialize ) ]
11
13
crate struct Layout {
12
14
crate logo : String ,
13
15
crate favicon : String ,
@@ -22,6 +24,7 @@ crate struct Layout {
22
24
crate generate_search_filter : bool ,
23
25
}
24
26
27
+ #[ derive( Serialize ) ]
25
28
crate struct Page < ' a > {
26
29
crate title : & ' a str ,
27
30
crate css_class : & ' a str ,
@@ -40,192 +43,55 @@ impl<'a> Page<'a> {
40
43
}
41
44
}
42
45
46
+ #[ derive( Serialize ) ]
47
+ struct PageLayout < ' a > {
48
+ static_root_path : & ' a str ,
49
+ page : & ' a Page < ' a > ,
50
+ layout : & ' a Layout ,
51
+ style_files : String ,
52
+ sidebar : String ,
53
+ content : String ,
54
+ krate_with_trailing_slash : String ,
55
+ }
56
+
43
57
crate fn render < T : Print , S : Print > (
58
+ templates : & tera:: Tera ,
44
59
layout : & Layout ,
45
60
page : & Page < ' _ > ,
46
61
sidebar : S ,
47
62
t : T ,
48
63
style_files : & [ StylePath ] ,
49
64
) -> String {
50
65
let static_root_path = page. get_static_root_path ( ) ;
51
- format ! (
52
- "<!DOCTYPE html>\
53
- <html lang=\" en\" >\
54
- <head>\
55
- <meta charset=\" utf-8\" >\
56
- <meta name=\" viewport\" content=\" width=device-width, initial-scale=1.0\" >\
57
- <meta name=\" generator\" content=\" rustdoc\" >\
58
- <meta name=\" description\" content=\" {description}\" >\
59
- <meta name=\" keywords\" content=\" {keywords}\" >\
60
- <title>{title}</title>\
61
- <link rel=\" stylesheet\" type=\" text/css\" href=\" {static_root_path}normalize{suffix}.css\" >\
62
- <link rel=\" stylesheet\" type=\" text/css\" href=\" {static_root_path}rustdoc{suffix}.css\" \
63
- id=\" mainThemeStyle\" >\
64
- {style_files}\
65
- <script id=\" default-settings\" {default_settings}></script>\
66
- <script src=\" {static_root_path}storage{suffix}.js\" ></script>\
67
- <script src=\" {root_path}crates{suffix}.js\" ></script>\
68
- <noscript><link rel=\" stylesheet\" href=\" {static_root_path}noscript{suffix}.css\" ></noscript>\
69
- {css_extension}\
70
- {favicon}\
71
- {in_header}\
72
- <style type=\" text/css\" >\
73
- #crate-search{{background-image:url(\" {static_root_path}down-arrow{suffix}.svg\" );}}\
74
- </style>\
75
- </head>\
76
- <body class=\" rustdoc {css_class}\" >\
77
- <!--[if lte IE 11]>\
78
- <div class=\" warning\" >\
79
- This old browser is unsupported and will most likely display funky \
80
- things.\
81
- </div>\
82
- <![endif]-->\
83
- {before_content}\
84
- <nav class=\" sidebar\" >\
85
- <div class=\" sidebar-menu\" role=\" button\" >☰</div>\
86
- {logo}\
87
- {sidebar}\
88
- </nav>\
89
- <div class=\" theme-picker\" >\
90
- <button id=\" theme-picker\" aria-label=\" Pick another theme!\" aria-haspopup=\" menu\" title=\" themes\" >\
91
- <img src=\" {static_root_path}brush{suffix}.svg\" \
92
- width=\" 18\" height=\" 18\" \
93
- alt=\" Pick another theme!\" >\
94
- </button>\
95
- <div id=\" theme-choices\" role=\" menu\" ></div>\
96
- </div>\
97
- <nav class=\" sub\" >\
98
- <form class=\" search-form\" >\
99
- <div class=\" search-container\" >\
100
- <div>{filter_crates}\
101
- <input class=\" search-input\" name=\" search\" \
102
- disabled \
103
- autocomplete=\" off\" \
104
- spellcheck=\" false\" \
105
- placeholder=\" Click or press ‘S’ to search, ‘?’ for more options…\" \
106
- type=\" search\" >\
107
- </div>\
108
- <button type=\" button\" id=\" help-button\" title=\" help\" >?</button>\
109
- <a id=\" settings-menu\" href=\" {root_path}settings.html\" title=\" settings\" >\
110
- <img src=\" {static_root_path}wheel{suffix}.svg\" \
111
- width=\" 18\" height=\" 18\" \
112
- alt=\" Change settings\" >\
113
- </a>\
114
- </div>\
115
- </form>\
116
- </nav>\
117
- <section id=\" main\" class=\" content\" >{content}</section>\
118
- <section id=\" search\" class=\" content hidden\" ></section>\
119
- {after_content}\
120
- <div id=\" rustdoc-vars\" data-root-path=\" {root_path}\" data-current-crate=\" {krate}\" \
121
- data-search-index-js=\" {root_path}search-index{suffix}.js\" \
122
- data-search-js=\" {static_root_path}search{suffix}.js\" ></div>\
123
- <script src=\" {static_root_path}main{suffix}.js\" ></script>\
124
- {extra_scripts}\
125
- </body>\
126
- </html>",
127
- css_extension = if layout. css_file_extension. is_some( ) {
66
+ let krate_with_trailing_slash = ensure_trailing_slash ( & layout. krate ) . to_string ( ) ;
67
+ let style_files = style_files
68
+ . iter ( )
69
+ . filter_map ( |t| {
70
+ if let Some ( stem) = t. path . file_stem ( ) { Some ( ( stem, t. disabled ) ) } else { None }
71
+ } )
72
+ . filter_map ( |t| if let Some ( path) = t. 0 . to_str ( ) { Some ( ( path, t. 1 ) ) } else { None } )
73
+ . map ( |t| {
128
74
format ! (
129
- "<link rel=\" stylesheet\" \
130
- type=\" text/css\" \
131
- href=\" {static_root_path}theme{suffix}.css\" >",
132
- static_root_path = static_root_path,
133
- suffix = page. resource_suffix
134
- )
135
- } else {
136
- String :: new( )
137
- } ,
138
- content = Buffer :: html( ) . to_display( t) ,
139
- static_root_path = static_root_path,
140
- root_path = page. root_path,
141
- css_class = page. css_class,
142
- logo = {
143
- if layout. logo. is_empty( ) {
144
- format!(
145
- "<a href='{root}{path}index.html'>\
146
- <div class='logo-container rust-logo'>\
147
- <img src='{static_root_path}rust-logo{suffix}.png' alt='logo'></div></a>",
148
- root = page. root_path,
149
- path = ensure_trailing_slash( & layout. krate) ,
150
- static_root_path = static_root_path,
151
- suffix = page. resource_suffix
152
- )
153
- } else {
154
- format!(
155
- "<a href='{root}{path}index.html'>\
156
- <div class='logo-container'><img src='{logo}' alt='logo'></div></a>",
157
- root = page. root_path,
158
- path = ensure_trailing_slash( & layout. krate) ,
159
- logo = layout. logo
160
- )
161
- }
162
- } ,
163
- title = page. title,
164
- description = Escape ( page. description) ,
165
- keywords = page. keywords,
166
- favicon = if layout. favicon. is_empty( ) {
167
- format!(
168
- r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
169
- <link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
170
- <link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"## ,
171
- static_root_path = static_root_path,
172
- suffix = page. resource_suffix
173
- )
174
- } else {
175
- format!( r#"<link rel="shortcut icon" href="{}">"# , layout. favicon)
176
- } ,
177
- in_header = layout. external_html. in_header,
178
- before_content = layout. external_html. before_content,
179
- after_content = layout. external_html. after_content,
180
- sidebar = Buffer :: html( ) . to_display( sidebar) ,
181
- krate = layout. krate,
182
- default_settings = layout
183
- . default_settings
184
- . iter( )
185
- . map( |( k, v) | format!( r#" data-{}="{}""# , k. replace( '-' , "_" ) , Escape ( v) ) )
186
- . collect:: <String >( ) ,
187
- style_files = style_files
188
- . iter( )
189
- . filter_map( |t| {
190
- if let Some ( stem) = t. path. file_stem( ) { Some ( ( stem, t. disabled) ) } else { None }
191
- } )
192
- . filter_map( |t| {
193
- if let Some ( path) = t. 0 . to_str( ) { Some ( ( path, t. 1 ) ) } else { None }
194
- } )
195
- . map( |t| format!(
196
75
r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"# ,
197
76
Escape ( & format!( "{}{}{}" , static_root_path, t. 0 , page. resource_suffix) ) ,
198
77
if t. 1 { "disabled" } else { "" } ,
199
78
if t. 0 == "light" { "id=\" themeStyle\" " } else { "" }
200
- ) )
201
- . collect:: <String >( ) ,
202
- suffix = page. resource_suffix,
203
- extra_scripts = page
204
- . static_extra_scripts
205
- . iter( )
206
- . map( |e| {
207
- format!(
208
- "<script src=\" {static_root_path}{extra_script}.js\" ></script>" ,
209
- static_root_path = static_root_path,
210
- extra_script = e
211
- )
212
- } )
213
- . chain( page. extra_scripts. iter( ) . map( |e| {
214
- format!(
215
- "<script src=\" {root_path}{extra_script}.js\" ></script>" ,
216
- root_path = page. root_path,
217
- extra_script = e
218
- )
219
- } ) )
220
- . collect:: <String >( ) ,
221
- filter_crates = if layout. generate_search_filter {
222
- "<select id=\" crate-search\" >\
223
- <option value=\" All crates\" >All crates</option>\
224
- </select>"
225
- } else {
226
- ""
227
- } ,
228
- )
79
+ )
80
+ } )
81
+ . collect :: < String > ( ) ;
82
+ let content = Buffer :: html ( ) . to_display ( t) ; // Note: This must happen before making the sidebar.
83
+ let sidebar = Buffer :: html ( ) . to_display ( sidebar) ;
84
+ let teractx = tera:: Context :: from_serialize ( PageLayout {
85
+ static_root_path,
86
+ page,
87
+ layout,
88
+ style_files,
89
+ sidebar,
90
+ content,
91
+ krate_with_trailing_slash,
92
+ } )
93
+ . unwrap ( ) ;
94
+ templates. render ( "page.html" , & teractx) . unwrap ( )
229
95
}
230
96
231
97
crate fn redirect ( url : & str ) -> String {
0 commit comments