mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-27 09:14:20 +00:00
Auto merge of #37098 - ollie27:rustdoc_playground, r=GuillaumeGomez
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. You can test the changes at https://ollie27.github.io/rust_doc_test/. Fixes #36621 Fixes #36910
This commit is contained in:
commit
6dc035ed91
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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(") {
|
||||
"&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());
|
||||
})
|
||||
|
@ -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"),
|
||||
|
@ -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;
|
||||
}
|
||||
});
|
@ -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);
|
||||
};
|
||||
});
|
||||
});
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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}");
|
||||
|
21
src/test/rustdoc/playground-empty.rs
Normal file
21
src/test/rustdoc/playground-empty.rs
Normal file
@ -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"
|
19
src/test/rustdoc/playground-none.rs
Normal file
19
src/test/rustdoc/playground-none.rs
Normal file
@ -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"
|
39
src/test/rustdoc/playground.rs
Normal file
39
src/test/rustdoc/playground.rs
Normal file
@ -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"
|
@ -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());
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user