@@ -12,6 +12,7 @@ use std::collections::HashMap;
12
12
use std:: fs:: { self , File } ;
13
13
use std:: path:: { Path , PathBuf } ;
14
14
15
+ use crate :: utils:: fs:: get_404_output_file;
15
16
use handlebars:: Handlebars ;
16
17
use regex:: { Captures , Regex } ;
17
18
@@ -105,6 +106,58 @@ impl HtmlHandlebars {
105
106
Ok ( ( ) )
106
107
}
107
108
109
+ fn render_404 (
110
+ & self ,
111
+ ctx : & RenderContext ,
112
+ html_config : & HtmlConfig ,
113
+ src_dir : & PathBuf ,
114
+ handlebars : & mut Handlebars < ' _ > ,
115
+ data : & mut serde_json:: Map < String , serde_json:: Value > ,
116
+ ) -> Result < ( ) > {
117
+ let destination = & ctx. destination ;
118
+ let content_404 = if let Some ( ref filename) = html_config. input_404 {
119
+ let path = src_dir. join ( filename) ;
120
+ std:: fs:: read_to_string ( & path)
121
+ . with_context ( || format ! ( "unable to open 404 input file {:?}" , path) ) ?
122
+ } else {
123
+ // 404 input not explicitly configured try the default file 404.md
124
+ let default_404_location = src_dir. join ( "404.md" ) ;
125
+ if default_404_location. exists ( ) {
126
+ std:: fs:: read_to_string ( & default_404_location) . with_context ( || {
127
+ format ! ( "unable to open 404 input file {:?}" , default_404_location)
128
+ } ) ?
129
+ } else {
130
+ "# Document not found (404)\n \n This URL is invalid, sorry. Please use the \
131
+ navigation bar or search to continue."
132
+ . to_string ( )
133
+ }
134
+ } ;
135
+ let html_content_404 = utils:: render_markdown ( & content_404, html_config. curly_quotes ) ;
136
+
137
+ let mut data_404 = data. clone ( ) ;
138
+ let base_url = if let Some ( site_url) = & html_config. site_url {
139
+ site_url
140
+ } else {
141
+ debug ! (
142
+ "HTML 'site-url' parameter not set, defaulting to '/'. Please configure \
143
+ this to ensure the 404 page work correctly, especially if your site is hosted in a \
144
+ subdirectory on the HTTP server."
145
+ ) ;
146
+ "/"
147
+ } ;
148
+ data_404. insert ( "base_url" . to_owned ( ) , json ! ( base_url) ) ;
149
+ // Set a dummy path to ensure other paths (e.g. in the TOC) are generated correctly
150
+ data_404. insert ( "path" . to_owned ( ) , json ! ( "404.md" ) ) ;
151
+ data_404. insert ( "content" . to_owned ( ) , json ! ( html_content_404) ) ;
152
+ let rendered = handlebars. render ( "index" , & data_404) ?;
153
+
154
+ let rendered = self . post_process ( rendered, & html_config. playpen , ctx. config . rust . edition ) ;
155
+ let output_file = get_404_output_file ( & html_config. input_404 ) ;
156
+ utils:: fs:: write_file ( & destination, output_file, rendered. as_bytes ( ) ) ?;
157
+ debug ! ( "Creating 404.html ✓" ) ;
158
+ Ok ( ( ) )
159
+ }
160
+
108
161
#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: let_and_return) ) ]
109
162
fn post_process (
110
163
& self ,
@@ -441,6 +494,11 @@ impl Renderer for HtmlHandlebars {
441
494
is_index = false ;
442
495
}
443
496
497
+ // Render 404 page
498
+ if html_config. input_404 != Some ( "" . to_string ( ) ) {
499
+ self . render_404 ( ctx, & html_config, & src_dir, & mut handlebars, & mut data) ?;
500
+ }
501
+
444
502
// Print version
445
503
self . configure_print_version ( & mut data, & print_content) ;
446
504
if let Some ( ref title) = ctx. config . book . title {
0 commit comments