17
17
//! let s = "My *markdown* _text_";
18
18
//! let mut id_map = IdMap::new();
19
19
//! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map),
20
- //! ErrorCodes::Yes, Edition::Edition2015));
20
+ //! ErrorCodes::Yes, Edition::Edition2015, None ));
21
21
//! // ... something using html
22
22
//! ```
23
23
@@ -59,16 +59,24 @@ pub struct Markdown<'a>(
59
59
pub ErrorCodes ,
60
60
/// Default edition to use when parsing doctests (to add a `fn main`).
61
61
pub Edition ,
62
+ pub & ' a Option < Playground > ,
62
63
) ;
63
64
/// A tuple struct like `Markdown` that renders the markdown with a table of contents.
64
65
pub struct MarkdownWithToc < ' a > (
65
66
pub & ' a str ,
66
67
pub RefCell < & ' a mut IdMap > ,
67
68
pub ErrorCodes ,
68
69
pub Edition ,
70
+ pub & ' a Option < Playground > ,
69
71
) ;
70
72
/// A tuple struct like `Markdown` that renders the markdown escaping HTML tags.
71
- pub struct MarkdownHtml < ' a > ( pub & ' a str , pub RefCell < & ' a mut IdMap > , pub ErrorCodes , pub Edition ) ;
73
+ pub struct MarkdownHtml < ' a > (
74
+ pub & ' a str ,
75
+ pub RefCell < & ' a mut IdMap > ,
76
+ pub ErrorCodes ,
77
+ pub Edition ,
78
+ pub & ' a Option < Playground > ,
79
+ ) ;
72
80
/// A tuple struct like `Markdown` that renders only the first paragraph.
73
81
pub struct MarkdownSummaryLine < ' a > ( pub & ' a str , pub & ' a [ ( String , String ) ] ) ;
74
82
@@ -155,30 +163,39 @@ fn slugify(c: char) -> Option<char> {
155
163
}
156
164
}
157
165
158
- // Information about the playground if a URL has been specified, containing an
159
- // optional crate name and the URL.
160
- thread_local ! ( pub static PLAYGROUND : RefCell < Option <( Option < String >, String ) >> = {
161
- RefCell :: new ( None )
162
- } ) ;
166
+ # [ derive ( Clone , Debug ) ]
167
+ pub struct Playground {
168
+ pub crate_name : Option < String > ,
169
+ pub url : String ,
170
+ }
163
171
164
172
/// Adds syntax highlighting and playground Run buttons to Rust code blocks.
165
- struct CodeBlocks < ' a , I : Iterator < Item = Event < ' a > > > {
173
+ struct CodeBlocks < ' p , ' a , I : Iterator < Item = Event < ' a > > > {
166
174
inner : I ,
167
175
check_error_codes : ErrorCodes ,
168
176
edition : Edition ,
177
+ // Information about the playground if a URL has been specified, containing an
178
+ // optional crate name and the URL.
179
+ playground : & ' p Option < Playground > ,
169
180
}
170
181
171
- impl < ' a , I : Iterator < Item = Event < ' a > > > CodeBlocks < ' a , I > {
172
- fn new ( iter : I , error_codes : ErrorCodes , edition : Edition ) -> Self {
182
+ impl < ' p , ' a , I : Iterator < Item = Event < ' a > > > CodeBlocks < ' p , ' a , I > {
183
+ fn new (
184
+ iter : I ,
185
+ error_codes : ErrorCodes ,
186
+ edition : Edition ,
187
+ playground : & ' p Option < Playground > ,
188
+ ) -> Self {
173
189
CodeBlocks {
174
190
inner : iter,
175
191
check_error_codes : error_codes,
176
192
edition,
193
+ playground,
177
194
}
178
195
}
179
196
}
180
197
181
- impl < ' a , I : Iterator < Item = Event < ' a > > > Iterator for CodeBlocks < ' a , I > {
198
+ impl < ' a , I : Iterator < Item = Event < ' a > > > Iterator for CodeBlocks < ' _ , ' a , I > {
182
199
type Item = Event < ' a > ;
183
200
184
201
fn next ( & mut self ) -> Option < Self :: Item > {
@@ -213,86 +230,86 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
213
230
}
214
231
let lines = origtext. lines ( ) . filter_map ( |l| map_line ( l) . for_html ( ) ) ;
215
232
let text = lines. collect :: < Vec < Cow < ' _ , str > > > ( ) . join ( "\n " ) ;
216
- PLAYGROUND . with ( |play| {
217
- // insert newline to clearly separate it from the
218
- // previous block so we can shorten the html output
219
- let mut s = String :: from ( "\n " ) ;
220
- let playground_button = play. borrow ( ) . as_ref ( ) . and_then ( |& ( ref krate, ref url) | {
221
- if url. is_empty ( ) {
222
- return None ;
223
- }
224
- let test = origtext. lines ( )
225
- . map ( |l| map_line ( l) . for_code ( ) )
226
- . collect :: < Vec < Cow < ' _ , str > > > ( ) . join ( "\n " ) ;
227
- let krate = krate. as_ref ( ) . map ( |s| & * * s) ;
228
- let ( test, _) = test:: make_test ( & test, krate, false ,
229
- & Default :: default ( ) , edition) ;
230
- let channel = if test. contains ( "#![feature(" ) {
231
- "&version=nightly"
232
- } else {
233
- ""
234
- } ;
235
-
236
- let edition_string = format ! ( "&edition={}" , edition) ;
237
-
238
- // These characters don't need to be escaped in a URI.
239
- // FIXME: use a library function for percent encoding.
240
- fn dont_escape ( c : u8 ) -> bool {
241
- ( b'a' <= c && c <= b'z' ) ||
242
- ( b'A' <= c && c <= b'Z' ) ||
243
- ( b'0' <= c && c <= b'9' ) ||
244
- c == b'-' || c == b'_' || c == b'.' ||
245
- c == b'~' || c == b'!' || c == b'\'' ||
246
- c == b'(' || c == b')' || c == b'*'
247
- }
248
- let mut test_escaped = String :: new ( ) ;
249
- for b in test. bytes ( ) {
250
- if dont_escape ( b) {
251
- test_escaped. push ( char:: from ( b) ) ;
252
- } else {
253
- write ! ( test_escaped, "%{:02X}" , b) . unwrap ( ) ;
254
- }
255
- }
256
- Some ( format ! (
257
- r#"<a class="test-arrow" target="_blank" href="{}?code={}{}{}">Run</a>"# ,
258
- url, test_escaped, channel, edition_string
259
- ) )
260
- } ) ;
261
-
262
- let tooltip = if ignore {
263
- Some ( ( "This example is not tested" . to_owned ( ) , "ignore" ) )
264
- } else if compile_fail {
265
- Some ( ( "This example deliberately fails to compile" . to_owned ( ) , "compile_fail" ) )
266
- } else if explicit_edition {
267
- Some ( ( format ! ( "This code runs with edition {}" , edition) , "edition" ) )
233
+ // insert newline to clearly separate it from the
234
+ // previous block so we can shorten the html output
235
+ let mut s = String :: from ( "\n " ) ;
236
+ let playground_button = self . playground . as_ref ( ) . and_then ( |playground| {
237
+ let krate = & playground. crate_name ;
238
+ let url = & playground. url ;
239
+ if url. is_empty ( ) {
240
+ return None ;
241
+ }
242
+ let test = origtext. lines ( )
243
+ . map ( |l| map_line ( l) . for_code ( ) )
244
+ . collect :: < Vec < Cow < ' _ , str > > > ( ) . join ( "\n " ) ;
245
+ let krate = krate. as_ref ( ) . map ( |s| & * * s) ;
246
+ let ( test, _) = test:: make_test ( & test, krate, false ,
247
+ & Default :: default ( ) , edition) ;
248
+ let channel = if test. contains ( "#![feature(" ) {
249
+ "&version=nightly"
268
250
} else {
269
- None
251
+ ""
270
252
} ;
271
253
272
- if let Some ( ( s1, s2) ) = tooltip {
273
- s. push_str ( & highlight:: render_with_highlighting (
274
- & text,
275
- Some ( & format ! ( "rust-example-rendered{}" ,
276
- if ignore { " ignore" }
277
- else if compile_fail { " compile_fail" }
278
- else if explicit_edition { " edition " }
279
- else { "" } ) ) ,
280
- playground_button. as_ref ( ) . map ( String :: as_str) ,
281
- Some ( ( s1. as_str ( ) , s2) ) ) ) ;
282
- Some ( Event :: Html ( s. into ( ) ) )
283
- } else {
284
- s. push_str ( & highlight:: render_with_highlighting (
285
- & text,
286
- Some ( & format ! ( "rust-example-rendered{}" ,
287
- if ignore { " ignore" }
288
- else if compile_fail { " compile_fail" }
289
- else if explicit_edition { " edition " }
290
- else { "" } ) ) ,
291
- playground_button. as_ref ( ) . map ( String :: as_str) ,
292
- None ) ) ;
293
- Some ( Event :: Html ( s. into ( ) ) )
254
+ let edition_string = format ! ( "&edition={}" , edition) ;
255
+
256
+ // These characters don't need to be escaped in a URI.
257
+ // FIXME: use a library function for percent encoding.
258
+ fn dont_escape ( c : u8 ) -> bool {
259
+ ( b'a' <= c && c <= b'z' ) ||
260
+ ( b'A' <= c && c <= b'Z' ) ||
261
+ ( b'0' <= c && c <= b'9' ) ||
262
+ c == b'-' || c == b'_' || c == b'.' ||
263
+ c == b'~' || c == b'!' || c == b'\'' ||
264
+ c == b'(' || c == b')' || c == b'*'
294
265
}
295
- } )
266
+ let mut test_escaped = String :: new ( ) ;
267
+ for b in test. bytes ( ) {
268
+ if dont_escape ( b) {
269
+ test_escaped. push ( char:: from ( b) ) ;
270
+ } else {
271
+ write ! ( test_escaped, "%{:02X}" , b) . unwrap ( ) ;
272
+ }
273
+ }
274
+ Some ( format ! (
275
+ r#"<a class="test-arrow" target="_blank" href="{}?code={}{}{}">Run</a>"# ,
276
+ url, test_escaped, channel, edition_string
277
+ ) )
278
+ } ) ;
279
+
280
+ let tooltip = if ignore {
281
+ Some ( ( "This example is not tested" . to_owned ( ) , "ignore" ) )
282
+ } else if compile_fail {
283
+ Some ( ( "This example deliberately fails to compile" . to_owned ( ) , "compile_fail" ) )
284
+ } else if explicit_edition {
285
+ Some ( ( format ! ( "This code runs with edition {}" , edition) , "edition" ) )
286
+ } else {
287
+ None
288
+ } ;
289
+
290
+ if let Some ( ( s1, s2) ) = tooltip {
291
+ s. push_str ( & highlight:: render_with_highlighting (
292
+ & text,
293
+ Some ( & format ! ( "rust-example-rendered{}" ,
294
+ if ignore { " ignore" }
295
+ else if compile_fail { " compile_fail" }
296
+ else if explicit_edition { " edition " }
297
+ else { "" } ) ) ,
298
+ playground_button. as_ref ( ) . map ( String :: as_str) ,
299
+ Some ( ( s1. as_str ( ) , s2) ) ) ) ;
300
+ Some ( Event :: Html ( s. into ( ) ) )
301
+ } else {
302
+ s. push_str ( & highlight:: render_with_highlighting (
303
+ & text,
304
+ Some ( & format ! ( "rust-example-rendered{}" ,
305
+ if ignore { " ignore" }
306
+ else if compile_fail { " compile_fail" }
307
+ else if explicit_edition { " edition " }
308
+ else { "" } ) ) ,
309
+ playground_button. as_ref ( ) . map ( String :: as_str) ,
310
+ None ) ) ;
311
+ Some ( Event :: Html ( s. into ( ) ) )
312
+ }
296
313
}
297
314
}
298
315
@@ -676,7 +693,7 @@ impl LangString {
676
693
677
694
impl < ' a > fmt:: Display for Markdown < ' a > {
678
695
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
679
- let Markdown ( md, links, ref ids, codes, edition) = * self ;
696
+ let Markdown ( md, links, ref ids, codes, edition, playground ) = * self ;
680
697
let mut ids = ids. borrow_mut ( ) ;
681
698
682
699
// This is actually common enough to special-case
@@ -695,7 +712,7 @@ impl<'a> fmt::Display for Markdown<'a> {
695
712
696
713
let p = HeadingLinks :: new ( p, None , & mut ids) ;
697
714
let p = LinkReplacer :: new ( p, links) ;
698
- let p = CodeBlocks :: new ( p, codes, edition) ;
715
+ let p = CodeBlocks :: new ( p, codes, edition, playground ) ;
699
716
let p = Footnotes :: new ( p) ;
700
717
html:: push_html ( & mut s, p) ;
701
718
@@ -705,7 +722,7 @@ impl<'a> fmt::Display for Markdown<'a> {
705
722
706
723
impl < ' a > fmt:: Display for MarkdownWithToc < ' a > {
707
724
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
708
- let MarkdownWithToc ( md, ref ids, codes, edition) = * self ;
725
+ let MarkdownWithToc ( md, ref ids, codes, edition, playground ) = * self ;
709
726
let mut ids = ids. borrow_mut ( ) ;
710
727
711
728
let p = Parser :: new_ext ( md, opts ( ) ) ;
@@ -716,7 +733,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
716
733
717
734
{
718
735
let p = HeadingLinks :: new ( p, Some ( & mut toc) , & mut ids) ;
719
- let p = CodeBlocks :: new ( p, codes, edition) ;
736
+ let p = CodeBlocks :: new ( p, codes, edition, playground ) ;
720
737
let p = Footnotes :: new ( p) ;
721
738
html:: push_html ( & mut s, p) ;
722
739
}
@@ -729,7 +746,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> {
729
746
730
747
impl < ' a > fmt:: Display for MarkdownHtml < ' a > {
731
748
fn fmt ( & self , fmt : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
732
- let MarkdownHtml ( md, ref ids, codes, edition) = * self ;
749
+ let MarkdownHtml ( md, ref ids, codes, edition, playground ) = * self ;
733
750
let mut ids = ids. borrow_mut ( ) ;
734
751
735
752
// This is actually common enough to special-case
@@ -745,7 +762,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
745
762
let mut s = String :: with_capacity ( md. len ( ) * 3 / 2 ) ;
746
763
747
764
let p = HeadingLinks :: new ( p, None , & mut ids) ;
748
- let p = CodeBlocks :: new ( p, codes, edition) ;
765
+ let p = CodeBlocks :: new ( p, codes, edition, playground ) ;
749
766
let p = Footnotes :: new ( p) ;
750
767
html:: push_html ( & mut s, p) ;
751
768
0 commit comments