25
25
//! ```
26
26
27
27
use rustc:: session:: config:: get_unstable_features_setting;
28
+ use std:: ascii:: AsciiExt ;
28
29
use std:: borrow:: Cow ;
29
30
use std:: cell:: RefCell ;
30
31
use std:: fmt:: { self , Write } ;
@@ -34,7 +35,7 @@ use cmark::{Parser, Event as CmEvent, Tag};
34
35
use hamlet:: Token as HmToken ;
35
36
use cmark_hamlet;
36
37
37
- // use html::render::derive_id;
38
+ use html:: render:: derive_id;
38
39
//use html::toc::TocBuilder;
39
40
use html:: highlight;
40
41
use html:: escape:: Escape ;
@@ -76,13 +77,64 @@ thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
76
77
RefCell :: new( None )
77
78
} ) ;
78
79
80
+ fn is_header ( tag_name : & str ) -> bool {
81
+ if tag_name. len ( ) == 2 {
82
+ tag_name. char_indices ( ) . all ( |( i, c) | {
83
+ ( i == 0 && c == 'h' ) || ( i == 1 && c >= '1' && c <= '6' )
84
+ } )
85
+ } else {
86
+ false
87
+ }
88
+ }
89
+
90
+ fn id_from_text ( text : & str ) -> String {
91
+ let id = text. chars ( ) . filter_map ( |c| {
92
+ if c. is_alphanumeric ( ) || c == '-' || c == '_' {
93
+ if c. is_ascii ( ) {
94
+ Some ( c. to_ascii_lowercase ( ) )
95
+ } else {
96
+ Some ( c)
97
+ }
98
+ } else if c. is_whitespace ( ) && c. is_ascii ( ) {
99
+ Some ( '-' )
100
+ } else {
101
+ None
102
+ }
103
+ } ) . collect :: < String > ( ) ;
104
+ derive_id ( id)
105
+ }
106
+
79
107
pub fn render ( w : & mut fmt:: Formatter , md : & str , _: bool ) -> fmt:: Result {
80
108
let mut rust_block = false ;
109
+ let mut header = false ;
110
+ let mut header_inner_buf = String :: from ( "" ) ;
111
+ let mut header_id_buf = String :: from ( "" ) ;
81
112
for hm_tok in cmark_hamlet:: Adapter :: new ( Parser :: new ( md) , true ) {
82
113
match hm_tok {
83
- HmToken :: StartTag { ref name, .. } |
84
- HmToken :: EndTag { ref name } if rust_block && name. as_ref ( ) == "code" => ( ) ,
85
- HmToken :: StartTag { name : Cow :: Borrowed ( "pre" ) , ref attrs, .. } => {
114
+ HmToken :: StartTag { ref name, .. } if is_header ( name. as_ref ( ) ) => {
115
+ header = true ;
116
+ }
117
+ HmToken :: EndTag { ref name } if is_header ( name. as_ref ( ) ) => {
118
+ let id = id_from_text ( & * header_id_buf) ;
119
+ try!( write ! ( w,
120
+ "{start}<a href=\" #{id}\" >{inner}</a>{end}" ,
121
+ start = HmToken :: start_tag( name. as_ref( ) ,
122
+ attrs!( id = & * id,
123
+ class = "section-header" ) ) ,
124
+ id = & * id,
125
+ inner = header_inner_buf,
126
+ end = hm_tok) ) ;
127
+ header = false ;
128
+ header_id_buf. truncate ( 0 ) ;
129
+ header_inner_buf. truncate ( 0 ) ;
130
+ }
131
+ _ if header => {
132
+ if let HmToken :: Text ( ref text) = hm_tok {
133
+ try!( write ! ( header_id_buf, "{}" , text) ) ;
134
+ }
135
+ try!( write ! ( header_inner_buf, "{}" , hm_tok) ) ;
136
+ }
137
+ HmToken :: StartTag { ref name, ref attrs, .. } if name. as_ref ( ) == "pre" => {
86
138
let is_rust = attrs. get ( "data-lang" )
87
139
. map ( |lang| LangString :: parse ( lang) . rust ) ;
88
140
if let Some ( true ) = is_rust {
@@ -91,6 +143,8 @@ pub fn render(w: &mut fmt::Formatter, md: &str, _: bool) -> fmt::Result {
91
143
try!( write ! ( w, "{}" , hm_tok) ) ;
92
144
}
93
145
}
146
+ HmToken :: StartTag { ref name, .. } |
147
+ HmToken :: EndTag { ref name } if rust_block && name. as_ref ( ) == "code" => ( ) ,
94
148
HmToken :: Text ( ref text) if rust_block => {
95
149
let code = text. as_ref ( ) ;
96
150
// insert newline to clearly separate it from the
0 commit comments