@@ -7,7 +7,9 @@ use crate::html::escape::Escape;
77use crate :: html:: format:: { Buffer , Print } ;
88use crate :: html:: render:: { ensure_trailing_slash, StylePath } ;
99
10- #[ derive( Clone ) ]
10+ use serde:: Serialize ;
11+
12+ #[ derive( Clone , Serialize ) ]
1113crate struct Layout {
1214 crate logo : String ,
1315 crate favicon : String ,
@@ -22,6 +24,7 @@ crate struct Layout {
2224 crate generate_search_filter : bool ,
2325}
2426
27+ #[ derive( Serialize ) ]
2528crate struct Page < ' a > {
2629 crate title : & ' a str ,
2730 crate css_class : & ' a str ,
@@ -40,192 +43,55 @@ impl<'a> Page<'a> {
4043 }
4144}
4245
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+
4357crate fn render < T : Print , S : Print > (
58+ templates : & tera:: Tera ,
4459 layout : & Layout ,
4560 page : & Page < ' _ > ,
4661 sidebar : S ,
4762 t : T ,
4863 style_files : & [ StylePath ] ,
4964) -> String {
5065 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| {
12874 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!(
19675 r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"# ,
19776 Escape ( & format!( "{}{}{}" , static_root_path, t. 0 , page. resource_suffix) ) ,
19877 if t. 1 { "disabled" } else { "" } ,
19978 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 ( )
22995}
23096
23197crate fn redirect ( url : & str ) -> String {
0 commit comments