@@ -4,23 +4,39 @@ use comrak::{
4
4
ComrakRenderPlugins ,
5
5
} ;
6
6
use once_cell:: sync:: Lazy ;
7
- use std:: collections:: HashMap ;
8
- use std:: fmt:: Write ;
7
+ use std:: { collections:: HashMap , fmt:: Write } ;
9
8
10
9
#[ derive( Debug ) ]
11
- struct CodeAdapter ;
10
+ struct CodeAdapter < F > ( F ) ;
12
11
13
- impl SyntaxHighlighterAdapter for CodeAdapter {
12
+ impl < F : Fn ( Option < & str > , & str ) -> String > SyntaxHighlighterAdapter for CodeAdapter < F > {
14
13
fn highlight ( & self , lang : Option < & str > , code : & str ) -> String {
15
- highlight_code ( lang, code)
14
+ // comrak does not treat `,` as an info-string delimiter, so we do that here
15
+ // TODO: https://github.com/kivikakk/comrak/issues/246
16
+ let lang = lang. and_then ( |lang| lang. split ( ',' ) . next ( ) ) ;
17
+ ( self . 0 ) ( lang, code)
16
18
}
17
19
18
20
fn build_pre_tag ( & self , attributes : & HashMap < String , String > ) -> String {
19
21
build_opening_tag ( "pre" , attributes)
20
22
}
21
23
22
24
fn build_code_tag ( & self , attributes : & HashMap < String , String > ) -> String {
23
- build_opening_tag ( "code" , attributes)
25
+ // similarly to above, since comrak does not treat `,` as an info-string delimiter it will
26
+ // try to apply `class="language-rust,ignore"` for the info-string `rust,ignore`, so we
27
+ // have to detect that case and fixup the class here
28
+ // TODO: https://github.com/kivikakk/comrak/issues/246
29
+ let mut attributes = attributes. clone ( ) ;
30
+ if let Some ( classes) = attributes. get_mut ( "class" ) {
31
+ * classes = classes
32
+ . split ( ' ' )
33
+ . flat_map ( |class| [ class. split ( ',' ) . next ( ) . unwrap_or ( class) , " " ] )
34
+ . collect ( ) ;
35
+ // remove trailing ' '
36
+ // TODO: https://github.com/rust-lang/rust/issues/79524 or itertools
37
+ classes. pop ( ) ;
38
+ }
39
+ build_opening_tag ( "code" , & attributes)
24
40
}
25
41
}
26
42
@@ -82,8 +98,10 @@ pub fn highlight_code(lang: Option<&str>, code: &str) -> String {
82
98
}
83
99
}
84
100
85
- /// Wrapper around the Markdown parser and renderer to render markdown
86
- pub ( crate ) fn render ( text : & str ) -> String {
101
+ fn render_with_highlighter (
102
+ text : & str ,
103
+ highlighter : impl Fn ( Option < & str > , & str ) -> String ,
104
+ ) -> String {
87
105
comrak:: markdown_to_html_with_plugins (
88
106
text,
89
107
& ComrakOptions {
@@ -99,8 +117,52 @@ pub(crate) fn render(text: &str) -> String {
99
117
} ,
100
118
& ComrakPlugins {
101
119
render : ComrakRenderPlugins {
102
- codefence_syntax_highlighter : Some ( & CodeAdapter ) ,
120
+ codefence_syntax_highlighter : Some ( & CodeAdapter ( highlighter ) ) ,
103
121
} ,
104
122
} ,
105
123
)
106
124
}
125
+
126
+ /// Wrapper around the Markdown parser and renderer to render markdown
127
+ pub fn render ( text : & str ) -> String {
128
+ render_with_highlighter ( text, highlight_code)
129
+ }
130
+
131
+ #[ cfg( test) ]
132
+ mod test {
133
+ use super :: { highlight_code, render_with_highlighter} ;
134
+ use indoc:: indoc;
135
+ use std:: cell:: RefCell ;
136
+
137
+ #[ test]
138
+ fn ignore_info_string_attributes ( ) {
139
+ let highlighted = RefCell :: new ( vec ! [ ] ) ;
140
+
141
+ let output = render_with_highlighter (
142
+ indoc ! { "
143
+ ```rust,ignore
144
+ ignore::commas();
145
+ ```
146
+
147
+ ```rust ignore
148
+ ignore::spaces();
149
+ ```
150
+ " } ,
151
+ |lang, code| {
152
+ highlighted
153
+ . borrow_mut ( )
154
+ . push ( ( lang. map ( str:: to_owned) , code. to_owned ( ) ) ) ;
155
+ highlight_code ( lang, code)
156
+ } ,
157
+ ) ;
158
+
159
+ assert ! ( output. matches( r#"<code class="language-rust">"# ) . count( ) == 2 ) ;
160
+ assert_eq ! (
161
+ highlighted. borrow( ) . as_slice( ) ,
162
+ [
163
+ ( Some ( "rust" . into( ) ) , "ignore::commas();\n " . into( ) ) ,
164
+ ( Some ( "rust" . into( ) ) , "ignore::spaces();\n " . into( ) )
165
+ ]
166
+ ) ;
167
+ }
168
+ }
0 commit comments