about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Middleton <olliemail27@gmail.com>2016-10-11 09:56:30 +0100
committerOliver Middleton <olliemail27@gmail.com>2016-10-15 18:32:03 +0100
commit0b2746c8db6fc11965b1b6fd1d8536309a0d98b6 (patch)
treeadbfb9474dbe8dd1810f1669fefaf757627fd42e
parent8e05e7ee3c19a5594b79d67c8390cef78970be7c (diff)
downloadrust-0b2746c8db6fc11965b1b6fd1d8536309a0d98b6.tar.gz
rust-0b2746c8db6fc11965b1b6fd1d8536309a0d98b6.zip
rustdoc: Improve playground run buttons
The main change is to stop using javascript to generate the URLs and use
rustdoc instead.

This also adds run buttons to the error index examples.
-rw-r--r--src/doc/footer.inc1
-rw-r--r--src/doc/rust.css8
-rw-r--r--src/librustdoc/html/layout.rs9
-rw-r--r--src/librustdoc/html/markdown.rs43
-rw-r--r--src/librustdoc/html/render.rs8
-rw-r--r--src/librustdoc/html/static/extra.js25
-rw-r--r--src/librustdoc/html/static/playpen.js48
-rw-r--r--src/librustdoc/html/static/rustdoc.css1
-rw-r--r--src/librustdoc/markdown.rs10
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/test/rustdoc/playground-empty.rs21
-rw-r--r--src/test/rustdoc/playground-none.rs19
-rw-r--r--src/test/rustdoc/playground.rs39
-rw-r--r--src/tools/error_index_generator/main.rs5
-rw-r--r--src/tools/rustbook/build.rs7
15 files changed, 131 insertions, 115 deletions
diff --git a/src/doc/footer.inc b/src/doc/footer.inc
index 7513e524e73..77e151235e8 100644
--- a/src/doc/footer.inc
+++ b/src/doc/footer.inc
@@ -5,4 +5,3 @@ or the <a href="https://opensource.org/licenses/MIT">MIT license</a>, at your op
 </p><p>
 This file may not be copied, modified, or distributed except according to those terms.
 </p></footer>
-<script type="text/javascript" src="playpen.js"></script>
diff --git a/src/doc/rust.css b/src/doc/rust.css
index 262db5673e8..932594b9912 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -336,13 +336,11 @@ table th {
 
 /* Code snippets */
 
-.rusttest { display: none; }
 pre.rust { position: relative; }
 a.test-arrow {
+    background-color: rgba(78, 139, 202, 0.2);
     display: inline-block;
     position: absolute;
-
-    background-color: #4e8bca;
     color: #f5f5f5;
     padding: 5px 10px 5px 10px;
     border-radius: 5px;
@@ -350,6 +348,10 @@ a.test-arrow {
     top: 5px;
     right: 5px;
 }
+a.test-arrow:hover{
+    background-color: #4e8bca;
+    text-decoration: none;
+}
 
 .unstable-feature {
     border: 2px solid red;
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index b7c5876c4f9..5353642e294 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -19,7 +19,6 @@ pub struct Layout {
     pub favicon: String,
     pub external_html: ExternalHtml,
     pub krate: String,
-    pub playground_url: String,
 }
 
 pub struct Page<'a> {
@@ -136,11 +135,9 @@ r##"<!DOCTYPE html>
     <script>
         window.rootPath = "{root_path}";
         window.currentCrate = "{krate}";
-        window.playgroundUrl = "{play_url}";
     </script>
     <script src="{root_path}jquery.js"></script>
     <script src="{root_path}main.js"></script>
-    {play_js}
     <script defer src="{root_path}search-index.js"></script>
 </body>
 </html>"##,
@@ -174,12 +171,6 @@ r##"<!DOCTYPE html>
     after_content = layout.external_html.after_content,
     sidebar   = *sidebar,
     krate     = layout.krate,
-    play_url  = layout.playground_url,
-    play_js   = if layout.playground_url.is_empty() {
-        format!(r#"<script src="{}extra.js"></script>"#, page.root_path)
-    } else {
-        format!(r#"<script src="{}playpen.js"></script>"#, page.root_path)
-    }
     )
 }
 
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index e9a1f650c9b..f12349e5b7c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -31,7 +31,7 @@ use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::default::Default;
 use std::ffi::CString;
-use std::fmt;
+use std::fmt::{self, Write};
 use std::slice;
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
@@ -214,7 +214,9 @@ fn collapse_whitespace(s: &str) -> String {
     s.split_whitespace().collect::<Vec<_>>().join(" ")
 }
 
-thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
+// Information about the playground if a URL has been specified, containing an
+// optional crate name and the URL.
+thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> = {
     RefCell::new(None)
 });
 
@@ -248,24 +250,53 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
             });
             let text = lines.collect::<Vec<&str>>().join("\n");
             if rendered { return }
-            PLAYGROUND_KRATE.with(|krate| {
+            PLAYGROUND.with(|play| {
                 // insert newline to clearly separate it from the
                 // previous block so we can shorten the html output
                 let mut s = String::from("\n");
-                krate.borrow().as_ref().map(|krate| {
+                let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
+                    if url.is_empty() {
+                        return None;
+                    }
                     let test = origtext.lines().map(|l| {
                         stripped_filtered_line(l).unwrap_or(l)
                     }).collect::<Vec<&str>>().join("\n");
                     let krate = krate.as_ref().map(|s| &**s);
                     let test = test::maketest(&test, krate, false,
                                               &Default::default());
-                    s.push_str(&format!("<span class='rusttest'>{}</span>", Escape(&test)));
+                    let channel = if test.contains("#![feature(") {
+                        "&amp;version=nightly"
+                    } else {
+                        ""
+                    };
+                    // These characters don't need to be escaped in a URI.
+                    // FIXME: use a library function for percent encoding.
+                    fn dont_escape(c: u8) -> bool {
+                        (b'a' <= c && c <= b'z') ||
+                        (b'A' <= c && c <= b'Z') ||
+                        (b'0' <= c && c <= b'9') ||
+                        c == b'-' || c == b'_' || c == b'.' ||
+                        c == b'~' || c == b'!' || c == b'\'' ||
+                        c == b'(' || c == b')' || c == b'*'
+                    }
+                    let mut test_escaped = String::new();
+                    for b in test.bytes() {
+                        if dont_escape(b) {
+                            test_escaped.push(char::from(b));
+                        } else {
+                            write!(test_escaped, "%{:02X}", b).unwrap();
+                        }
+                    }
+                    Some(format!(
+                        r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
+                        url, test_escaped, channel
+                    ))
                 });
                 s.push_str(&highlight::render_with_highlighting(
                                &text,
                                Some("rust-example-rendered"),
                                None,
-                               Some("<a class='test-arrow' target='_blank' href=''>Run</a>")));
+                               playground_button.as_ref().map(String::as_str)));
                 let output = CString::new(s).unwrap();
                 hoedown_buffer_puts(ob, output.as_ptr());
             })
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index d8dba00e7d5..77a5ff3243a 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -449,7 +449,6 @@ pub fn run(mut krate: clean::Crate,
             favicon: "".to_string(),
             external_html: external_html.clone(),
             krate: krate.name.clone(),
-            playground_url: "".to_string(),
         },
         css_file_extension: css_file_extension.clone(),
     };
@@ -469,11 +468,10 @@ pub fn run(mut krate: clean::Crate,
                 }
                 clean::NameValue(ref x, ref s)
                         if "html_playground_url" == *x => {
-                    scx.layout.playground_url = s.to_string();
-                    markdown::PLAYGROUND_KRATE.with(|slot| {
+                    markdown::PLAYGROUND.with(|slot| {
                         if slot.borrow().is_none() {
                             let name = krate.name.clone();
-                            *slot.borrow_mut() = Some(Some(name));
+                            *slot.borrow_mut() = Some((Some(name), s.clone()));
                         }
                     });
                 }
@@ -659,8 +657,6 @@ fn write_shared(cx: &Context,
           include_bytes!("static/jquery-2.1.4.min.js"))?;
     write(cx.dst.join("main.js"),
           include_bytes!("static/main.js"))?;
-    write(cx.dst.join("playpen.js"),
-          include_bytes!("static/playpen.js"))?;
     write(cx.dst.join("rustdoc.css"),
           include_bytes!("static/rustdoc.css"))?;
     write(cx.dst.join("main.css"),
diff --git a/src/librustdoc/html/static/extra.js b/src/librustdoc/html/static/extra.js
deleted file mode 100644
index d9d97d9b883..00000000000
--- a/src/librustdoc/html/static/extra.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014-2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*jslint browser: true, es5: true */
-/*globals $: true, rootPath: true */
-
-document.addEventListener('DOMContentLoaded', function() {
-    'use strict';
-
-    if (!window.playgroundUrl) {
-        var runButtons = document.querySelectorAll(".test-arrow");
-
-        for (var i = 0; i < runButtons.length; i++) {
-            runButtons[i].classList.remove("test-arrow");
-        }
-        return;
-    }
-});
diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js
deleted file mode 100644
index 8d8953d56e1..00000000000
--- a/src/librustdoc/html/static/playpen.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*jslint browser: true, es5: true */
-/*globals $: true, rootPath: true */
-
-document.addEventListener('DOMContentLoaded', function() {
-    'use strict';
-
-    if (!window.playgroundUrl) {
-        var runButtons = document.querySelectorAll(".test-arrow");
-
-        for (var i = 0; i < runButtons.length; i++) {
-            runButtons[i].classList.remove("test-arrow");
-        }
-        return;
-    }
-
-    var featureRegexp = new RegExp('^\s*#!\\[feature\\(\.*?\\)\\]');
-    var elements = document.querySelectorAll('pre.rust-example-rendered');
-
-    Array.prototype.forEach.call(elements, function(el) {
-        el.onmouseover = function(e) {
-            if (el.contains(e.relatedTarget)) {
-                return;
-            }
-
-            var a = el.querySelectorAll('a.test-arrow')[0];
-
-            var code = el.previousElementSibling.textContent;
-
-            var channel = '';
-            if (featureRegexp.test(code)) {
-                channel = '&version=nightly';
-            }
-
-            a.setAttribute('href', window.playgroundUrl + '?code=' +
-                           encodeURIComponent(code) + channel);
-        };
-    });
-});
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index 85ec4fe3f3f..f49b8556f66 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -575,7 +575,6 @@ pre.rust .question-mark {
     font-weight: bold;
 }
 
-.rusttest { display: none; }
 pre.rust { position: relative; }
 a.test-arrow {
     background-color: rgba(78, 139, 202, 0.2);
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index f708aa54619..b617acfabbb 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -63,11 +63,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
         Err(LoadStringError::ReadFail) => return 1,
         Err(LoadStringError::BadUtf8) => return 2,
     };
-    let playground = matches.opt_str("markdown-playground-url");
-    if playground.is_some() {
-        markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
+    if let Some(playground) = matches.opt_str("markdown-playground-url") {
+        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
     }
-    let playground = playground.unwrap_or("".to_string());
 
     let mut out = match File::create(&output) {
         Err(e) => {
@@ -119,9 +117,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     {before_content}
     <h1 class="title">{title}</h1>
     {text}
-    <script type="text/javascript">
-        window.playgroundUrl = "{playground}";
-    </script>
     {after_content}
 </body>
 </html>"#,
@@ -131,7 +126,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
         before_content = external_html.before_content,
         text = rendered,
         after_content = external_html.after_content,
-        playground = playground,
         );
 
     match err {
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 15fdb0341cb..d1d2b14806f 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -355,7 +355,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool,
     if dont_insert_main || s.contains("fn main") {
         prog.push_str(&everything_else);
     } else {
-        prog.push_str("fn main() {\n    ");
+        prog.push_str("fn main() {\n");
         prog.push_str(&everything_else);
         prog = prog.trim().into();
         prog.push_str("\n}");
diff --git a/src/test/rustdoc/playground-empty.rs b/src/test/rustdoc/playground-empty.rs
new file mode 100644
index 00000000000..00881a62dd0
--- /dev/null
+++ b/src/test/rustdoc/playground-empty.rs
@@ -0,0 +1,21 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+#![doc(html_playground_url = "")]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/rustdoc/playground-none.rs b/src/test/rustdoc/playground-none.rs
new file mode 100644
index 00000000000..83c312d7ab2
--- /dev/null
+++ b/src/test/rustdoc/playground-none.rs
@@ -0,0 +1,19 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs
new file mode 100644
index 00000000000..9eb8dec51a7
--- /dev/null
+++ b/src/test/rustdoc/playground.rs
@@ -0,0 +1,39 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+#![doc(html_playground_url = "https://www.example.com/")]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     println!("Hello, world!");
+//! }
+//! ```
+//!
+//! ```
+//! #![feature(something)]
+//!
+//! fn main() {
+//!     println!("Hello, world!");
+//! }
+//! ```
+
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run"
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 7bdf1343aa9..e33df0dfbc8 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -24,7 +24,7 @@ use std::path::PathBuf;
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::Markdown;
+use rustdoc::html::markdown::{Markdown, PLAYGROUND};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -201,6 +201,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 }
 
 fn main() {
+    PLAYGROUND.with(|slot| {
+        *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
+    });
     let (format, dst) = parse_args();
     if let Err(e) = main_with_result(format, &dst) {
         panic!("{}", e.description());
diff --git a/src/tools/rustbook/build.rs b/src/tools/rustbook/build.rs
index 09c2d2510e3..d88ff48843a 100644
--- a/src/tools/rustbook/build.rs
+++ b/src/tools/rustbook/build.rs
@@ -131,7 +131,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
         {
             let mut buffer = BufWriter::new(File::create(&postlude)?);
             writeln!(&mut buffer, "<script src='rustbook.js'></script>")?;
-            writeln!(&mut buffer, "<script src='playpen.js'></script>")?;
             writeln!(&mut buffer, "</div></div>")?;
         }
 
@@ -143,7 +142,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
             format!("-o{}", out_path.display()),
             format!("--html-before-content={}", prelude.display()),
             format!("--html-after-content={}", postlude.display()),
-            format!("--markdown-playground-url=https://play.rust-lang.org"),
+            format!("--markdown-playground-url=https://play.rust-lang.org/"),
             format!("--markdown-css={}", item.path_to_root.join("rustbook.css").display()),
             "--markdown-no-toc".to_string(),
         ];
@@ -158,10 +157,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
     // create index.html from the root README
     fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))?;
 
-    // Copy js for playpen
-    let mut playpen = File::create(tgt.join("playpen.js"))?;
-    let js = include_bytes!("../../librustdoc/html/static/playpen.js");
-    playpen.write_all(js)?;
     Ok(())
 }