@@ -31,7 +31,7 @@ use std::ascii::AsciiExt;
31
31
use std:: cell:: RefCell ;
32
32
use std:: default:: Default ;
33
33
use std:: ffi:: CString ;
34
- use std:: fmt;
34
+ use std:: fmt:: { self , Write } ;
35
35
use std:: slice;
36
36
use std:: str;
37
37
use syntax:: feature_gate:: UnstableFeatures ;
@@ -214,7 +214,9 @@ fn collapse_whitespace(s: &str) -> String {
214
214
s. split_whitespace ( ) . collect :: < Vec < _ > > ( ) . join ( " " )
215
215
}
216
216
217
- thread_local ! ( pub static PLAYGROUND_KRATE : RefCell <Option <Option <String >>> = {
217
+ // Information about the playground if a URL has been specified, containing an
218
+ // optional crate name and the URL.
219
+ thread_local ! ( pub static PLAYGROUND : RefCell <Option <( Option <String >, String ) >> = {
218
220
RefCell :: new( None )
219
221
} ) ;
220
222
@@ -248,24 +250,53 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
248
250
} ) ;
249
251
let text = lines. collect :: < Vec < & str > > ( ) . join ( "\n " ) ;
250
252
if rendered { return }
251
- PLAYGROUND_KRATE . with ( |krate | {
253
+ PLAYGROUND . with ( |play | {
252
254
// insert newline to clearly separate it from the
253
255
// previous block so we can shorten the html output
254
256
let mut s = String :: from ( "\n " ) ;
255
- krate. borrow ( ) . as_ref ( ) . map ( |krate| {
257
+ let playground_button = play. borrow ( ) . as_ref ( ) . and_then ( |& ( ref krate, ref url) | {
258
+ if url. is_empty ( ) {
259
+ return None ;
260
+ }
256
261
let test = origtext. lines ( ) . map ( |l| {
257
262
stripped_filtered_line ( l) . unwrap_or ( l)
258
263
} ) . collect :: < Vec < & str > > ( ) . join ( "\n " ) ;
259
264
let krate = krate. as_ref ( ) . map ( |s| & * * s) ;
260
265
let test = test:: maketest ( & test, krate, false ,
261
266
& Default :: default ( ) ) ;
262
- s. push_str ( & format ! ( "<span class='rusttest'>{}</span>" , Escape ( & test) ) ) ;
267
+ let channel = if test. contains ( "#![feature(" ) {
268
+ "&version=nightly"
269
+ } else {
270
+ ""
271
+ } ;
272
+ // These characters don't need to be escaped in a URI.
273
+ // FIXME: use a library function for percent encoding.
274
+ fn dont_escape ( c : u8 ) -> bool {
275
+ ( b'a' <= c && c <= b'z' ) ||
276
+ ( b'A' <= c && c <= b'Z' ) ||
277
+ ( b'0' <= c && c <= b'9' ) ||
278
+ c == b'-' || c == b'_' || c == b'.' ||
279
+ c == b'~' || c == b'!' || c == b'\'' ||
280
+ c == b'(' || c == b')' || c == b'*'
281
+ }
282
+ let mut test_escaped = String :: new ( ) ;
283
+ for b in test. bytes ( ) {
284
+ if dont_escape ( b) {
285
+ test_escaped. push ( char:: from ( b) ) ;
286
+ } else {
287
+ write ! ( test_escaped, "%{:02X}" , b) . unwrap ( ) ;
288
+ }
289
+ }
290
+ Some ( format ! (
291
+ r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"# ,
292
+ url, test_escaped, channel
293
+ ) )
263
294
} ) ;
264
295
s. push_str ( & highlight:: render_with_highlighting (
265
296
& text,
266
297
Some ( "rust-example-rendered" ) ,
267
298
None ,
268
- Some ( "<a class='test-arrow' target='_blank' href=''>Run</a>" ) ) ) ;
299
+ playground_button . as_ref ( ) . map ( String :: as_str ) ) ) ;
269
300
let output = CString :: new ( s) . unwrap ( ) ;
270
301
hoedown_buffer_puts ( ob, output. as_ptr ( ) ) ;
271
302
} )
0 commit comments