@@ -31,7 +31,7 @@ use std::ascii::AsciiExt;
3131use std:: cell:: RefCell ;
3232use std:: default:: Default ;
3333use std:: ffi:: CString ;
34- use std:: fmt;
34+ use std:: fmt:: { self , Write } ;
3535use std:: slice;
3636use std:: str;
3737use syntax:: feature_gate:: UnstableFeatures ;
@@ -214,7 +214,9 @@ fn collapse_whitespace(s: &str) -> String {
214214 s. split_whitespace ( ) . collect :: < Vec < _ > > ( ) . join ( " " )
215215}
216216
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 ) >> = {
218220 RefCell :: new( None )
219221} ) ;
220222
@@ -248,24 +250,53 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
248250 } ) ;
249251 let text = lines. collect :: < Vec < & str > > ( ) . join ( "\n " ) ;
250252 if rendered { return }
251- PLAYGROUND_KRATE . with ( |krate | {
253+ PLAYGROUND . with ( |play | {
252254 // insert newline to clearly separate it from the
253255 // previous block so we can shorten the html output
254256 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+ }
256261 let test = origtext. lines ( ) . map ( |l| {
257262 stripped_filtered_line ( l) . unwrap_or ( l)
258263 } ) . collect :: < Vec < & str > > ( ) . join ( "\n " ) ;
259264 let krate = krate. as_ref ( ) . map ( |s| & * * s) ;
260265 let test = test:: maketest ( & test, krate, false ,
261266 & 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+ ) )
263294 } ) ;
264295 s. push_str ( & highlight:: render_with_highlighting (
265296 & text,
266297 Some ( "rust-example-rendered" ) ,
267298 None ,
268- Some ( "<a class='test-arrow' target='_blank' href=''>Run</a>" ) ) ) ;
299+ playground_button . as_ref ( ) . map ( String :: as_str ) ) ) ;
269300 let output = CString :: new ( s) . unwrap ( ) ;
270301 hoedown_buffer_puts ( ob, output. as_ptr ( ) ) ;
271302 } )
0 commit comments