@@ -54,16 +54,38 @@ impl HtmlHandlebars {
54
54
let content = ch. content . clone ( ) ;
55
55
let content = utils:: render_markdown ( & content, ctx. html_config . curly_quotes ) ;
56
56
57
- let fixed_content =
58
- utils:: render_markdown_with_path ( & ch. content , ctx. html_config . curly_quotes , Some ( path) ) ;
57
+ let fixed_content = utils:: render_markdown_with_path (
58
+ & ch. content ,
59
+ ctx. html_config . curly_quotes ,
60
+ Some ( path) ,
61
+ ctx. html_config . redirect ,
62
+ ) ;
59
63
if !ctx. is_index && ctx. html_config . print . page_break {
60
64
// Add page break between chapters
61
65
// See https://developer.mozilla.org/en-US/docs/Web/CSS/break-before and https://developer.mozilla.org/en-US/docs/Web/CSS/page-break-before
62
66
// Add both two CSS properties because of the compatibility issue
63
67
print_content
64
68
. push_str ( r#"<div style="break-before: page; page-break-before: always;"></div>"# ) ;
65
69
}
66
- print_content. push_str ( & fixed_content) ;
70
+ let path_id = {
71
+ let mut base = path. display ( ) . to_string ( ) ;
72
+ if base. ends_with ( ".md" ) {
73
+ base. replace_range ( base. len ( ) - 3 .., "" ) ;
74
+ }
75
+ & base
76
+ . replace ( "/" , "-" )
77
+ . replace ( "\\ " , "-" )
78
+ . to_ascii_lowercase ( )
79
+ } ;
80
+
81
+ // We have to build header links in advance so that we can know the ranges
82
+ // for the headers in one page.
83
+ // Insert a dummy div to make sure that we can locate the specific page.
84
+ print_content. push_str ( & ( format ! ( r#"<div id="{}"></div>"# , & path_id) ) ) ;
85
+ print_content. push_str ( & build_header_links (
86
+ & build_print_element_id ( & fixed_content, & path_id) ,
87
+ Some ( path_id) ,
88
+ ) ) ;
67
89
68
90
// Update the context with data for this file
69
91
let ctx_path = path
@@ -188,19 +210,31 @@ impl HtmlHandlebars {
188
210
}
189
211
190
212
#[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: let_and_return) ) ]
191
- fn post_process (
213
+ fn post_process_print (
192
214
& self ,
193
215
rendered : String ,
194
216
playground_config : & Playground ,
195
217
edition : Option < RustEdition > ,
196
218
) -> String {
197
- let rendered = build_header_links ( & rendered) ;
198
219
let rendered = fix_code_blocks ( & rendered) ;
199
220
let rendered = add_playground_pre ( & rendered, playground_config, edition) ;
200
221
201
222
rendered
202
223
}
203
224
225
+ #[ cfg_attr( feature = "cargo-clippy" , allow( clippy:: let_and_return) ) ]
226
+ fn post_process (
227
+ & self ,
228
+ rendered : String ,
229
+ playground_config : & Playground ,
230
+ edition : Option < RustEdition > ,
231
+ ) -> String {
232
+ let rendered = build_header_links ( & rendered, None ) ;
233
+ let rendered = self . post_process_print ( rendered, & playground_config, edition) ;
234
+
235
+ rendered
236
+ }
237
+
204
238
fn copy_static_files (
205
239
& self ,
206
240
destination : & Path ,
@@ -560,7 +594,7 @@ impl Renderer for HtmlHandlebars {
560
594
let rendered = handlebars. render ( "index" , & data) ?;
561
595
562
596
let rendered =
563
- self . post_process ( rendered, & html_config. playground , ctx. config . rust . edition ) ;
597
+ self . post_process_print ( rendered, & html_config. playground , ctx. config . rust . edition ) ;
564
598
565
599
utils:: fs:: write_file ( destination, "print.html" , rendered. as_bytes ( ) ) ?;
566
600
debug ! ( "Creating print.html ✓" ) ;
@@ -760,9 +794,44 @@ fn make_data(
760
794
Ok ( data)
761
795
}
762
796
797
+ /// Goes through part of the rendered print page HTML,
798
+ /// add path id prefix to all the elements id as well as footnote links.
799
+ fn build_print_element_id ( html : & str , path_id : & str ) -> String {
800
+ let all_id = Regex :: new ( r#"(<[^>]*?id=")([^"]+?)""# ) . unwrap ( ) ;
801
+ let footnote_id = Regex :: new (
802
+ r##"(<sup [^>]*?class="footnote-reference"[^>]*?>[^<]*?<a [^>]*?href="#)([^"]+?)""## ,
803
+ )
804
+ . unwrap ( ) ;
805
+
806
+ if path_id. is_empty ( ) {
807
+ return html. to_string ( ) ;
808
+ }
809
+
810
+ let temp_html = all_id
811
+ . replace_all ( html, |caps : & Captures < ' _ > | {
812
+ let mut fixed = String :: new ( ) ;
813
+ fixed. push_str ( & path_id) ;
814
+ fixed. push_str ( "-" ) ;
815
+ fixed. push_str ( & caps[ 2 ] ) ;
816
+ format ! ( "{}{}\" " , & caps[ 1 ] , fixed)
817
+ } )
818
+ . into_owned ( ) ;
819
+
820
+ footnote_id
821
+ . replace_all ( & temp_html, |caps : & Captures < ' _ > | {
822
+ let mut fixed = String :: new ( ) ;
823
+ fixed. push_str ( & path_id) ;
824
+ fixed. push_str ( "-" ) ;
825
+ fixed. push_str ( & caps[ 2 ] ) ;
826
+ format ! ( "{}{}\" " , & caps[ 1 ] , fixed)
827
+ } )
828
+ . into_owned ( )
829
+ }
830
+
763
831
/// Goes through the rendered HTML, making sure all header tags have
764
832
/// an anchor respectively so people can link to sections directly.
765
- fn build_header_links ( html : & str ) -> String {
833
+ <<<<<<< HEAD
834
+ fn build_header_links( html : & str , path_id : Option < & str > ) -> String {
766
835
lazy_static! {
767
836
static ref BUILD_HEADER_LINKS : Regex = Regex :: new( r"<h(\d)>(.*?)</h\d>" ) . unwrap( ) ;
768
837
}
@@ -775,19 +844,26 @@ fn build_header_links(html: &str) -> String {
775
844
. parse( )
776
845
. expect( "Regex should ensure we only ever get numbers here" ) ;
777
846
778
- insert_link_into_header ( level, & caps[ 2 ] , & mut id_counter)
847
+ insert_link_into_header( level, & caps[ 2 ] , & mut id_counter, path_id )
779
848
} )
780
849
. into_owned( )
781
850
}
782
851
783
852
/// Insert a sinle link into a header, making sure each link gets its own
784
853
/// unique ID by appending an auto-incremented number (if necessary).
854
+ ///
855
+ /// For `print.html`, we will add a path id prefix.
785
856
fn insert_link_into_header(
786
857
level: usize ,
787
858
content: & str ,
788
859
id_counter: & mut HashMap <String , usize >,
860
+ path_id: Option <& str >,
789
861
) -> String {
790
- let id = utils:: unique_id_from_content ( content, id_counter) ;
862
+ let id = if let Some ( path_id) = path_id {
863
+ utils:: unique_id_from_content_with_path( content, id_counter, path_id)
864
+ } else {
865
+ utils:: unique_id_from_content( content, id_counter)
866
+ } ;
791
867
792
868
format!(
793
869
r##"<h{level} id="{id}"><a class="header" href="#{id}">{text}</a></h{level}>"## ,
@@ -998,7 +1074,7 @@ mod tests {
998
1074
] ;
999
1075
1000
1076
for ( src, should_be) in inputs {
1001
- let got = build_header_links ( src) ;
1077
+ let got = build_header_links( src, None ) ;
1002
1078
assert_eq!( got, should_be) ;
1003
1079
}
1004
1080
}
0 commit comments