Skip to content

Commit 6dc035e

Browse files
authored
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
2 parents 98a3502 + 0b2746c commit 6dc035e

File tree

15 files changed

+131
-115
lines changed

15 files changed

+131
-115
lines changed

src/doc/footer.inc

-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,3 @@ or the <a href="https://opensource.org/licenses/MIT">MIT license</a>, at your op
55
</p><p>
66
This file may not be copied, modified, or distributed except according to those terms.
77
</p></footer>
8-
<script type="text/javascript" src="playpen.js"></script>

src/doc/rust.css

+5-3
Original file line numberDiff line numberDiff line change
@@ -336,20 +336,22 @@ table th {
336336

337337
/* Code snippets */
338338

339-
.rusttest { display: none; }
340339
pre.rust { position: relative; }
341340
a.test-arrow {
341+
background-color: rgba(78, 139, 202, 0.2);
342342
display: inline-block;
343343
position: absolute;
344-
345-
background-color: #4e8bca;
346344
color: #f5f5f5;
347345
padding: 5px 10px 5px 10px;
348346
border-radius: 5px;
349347
font-size: 130%;
350348
top: 5px;
351349
right: 5px;
352350
}
351+
a.test-arrow:hover{
352+
background-color: #4e8bca;
353+
text-decoration: none;
354+
}
353355

354356
.unstable-feature {
355357
border: 2px solid red;

src/librustdoc/html/layout.rs

-9
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ pub struct Layout {
1919
pub favicon: String,
2020
pub external_html: ExternalHtml,
2121
pub krate: String,
22-
pub playground_url: String,
2322
}
2423

2524
pub struct Page<'a> {
@@ -136,11 +135,9 @@ r##"<!DOCTYPE html>
136135
<script>
137136
window.rootPath = "{root_path}";
138137
window.currentCrate = "{krate}";
139-
window.playgroundUrl = "{play_url}";
140138
</script>
141139
<script src="{root_path}jquery.js"></script>
142140
<script src="{root_path}main.js"></script>
143-
{play_js}
144141
<script defer src="{root_path}search-index.js"></script>
145142
</body>
146143
</html>"##,
@@ -174,12 +171,6 @@ r##"<!DOCTYPE html>
174171
after_content = layout.external_html.after_content,
175172
sidebar = *sidebar,
176173
krate = layout.krate,
177-
play_url = layout.playground_url,
178-
play_js = if layout.playground_url.is_empty() {
179-
format!(r#"<script src="{}extra.js"></script>"#, page.root_path)
180-
} else {
181-
format!(r#"<script src="{}playpen.js"></script>"#, page.root_path)
182-
}
183174
)
184175
}
185176

src/librustdoc/html/markdown.rs

+37-6
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use std::ascii::AsciiExt;
3131
use std::cell::RefCell;
3232
use std::default::Default;
3333
use std::ffi::CString;
34-
use std::fmt;
34+
use std::fmt::{self, Write};
3535
use std::slice;
3636
use std::str;
3737
use 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+
"&amp;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
})

src/librustdoc/html/render.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,6 @@ pub fn run(mut krate: clean::Crate,
449449
favicon: "".to_string(),
450450
external_html: external_html.clone(),
451451
krate: krate.name.clone(),
452-
playground_url: "".to_string(),
453452
},
454453
css_file_extension: css_file_extension.clone(),
455454
};
@@ -469,11 +468,10 @@ pub fn run(mut krate: clean::Crate,
469468
}
470469
clean::NameValue(ref x, ref s)
471470
if "html_playground_url" == *x => {
472-
scx.layout.playground_url = s.to_string();
473-
markdown::PLAYGROUND_KRATE.with(|slot| {
471+
markdown::PLAYGROUND.with(|slot| {
474472
if slot.borrow().is_none() {
475473
let name = krate.name.clone();
476-
*slot.borrow_mut() = Some(Some(name));
474+
*slot.borrow_mut() = Some((Some(name), s.clone()));
477475
}
478476
});
479477
}
@@ -659,8 +657,6 @@ fn write_shared(cx: &Context,
659657
include_bytes!("static/jquery-2.1.4.min.js"))?;
660658
write(cx.dst.join("main.js"),
661659
include_bytes!("static/main.js"))?;
662-
write(cx.dst.join("playpen.js"),
663-
include_bytes!("static/playpen.js"))?;
664660
write(cx.dst.join("rustdoc.css"),
665661
include_bytes!("static/rustdoc.css"))?;
666662
write(cx.dst.join("main.css"),

src/librustdoc/html/static/extra.js

-25
This file was deleted.

src/librustdoc/html/static/playpen.js

-48
This file was deleted.

src/librustdoc/html/static/rustdoc.css

-1
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,6 @@ pre.rust .question-mark {
575575
font-weight: bold;
576576
}
577577

578-
.rusttest { display: none; }
579578
pre.rust { position: relative; }
580579
a.test-arrow {
581580
background-color: rgba(78, 139, 202, 0.2);

src/librustdoc/markdown.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
6363
Err(LoadStringError::ReadFail) => return 1,
6464
Err(LoadStringError::BadUtf8) => return 2,
6565
};
66-
let playground = matches.opt_str("markdown-playground-url");
67-
if playground.is_some() {
68-
markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
66+
if let Some(playground) = matches.opt_str("markdown-playground-url") {
67+
markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
6968
}
70-
let playground = playground.unwrap_or("".to_string());
7169

7270
let mut out = match File::create(&output) {
7371
Err(e) => {
@@ -119,9 +117,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
119117
{before_content}
120118
<h1 class="title">{title}</h1>
121119
{text}
122-
<script type="text/javascript">
123-
window.playgroundUrl = "{playground}";
124-
</script>
125120
{after_content}
126121
</body>
127122
</html>"#,
@@ -131,7 +126,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
131126
before_content = external_html.before_content,
132127
text = rendered,
133128
after_content = external_html.after_content,
134-
playground = playground,
135129
);
136130

137131
match err {

src/librustdoc/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool,
355355
if dont_insert_main || s.contains("fn main") {
356356
prog.push_str(&everything_else);
357357
} else {
358-
prog.push_str("fn main() {\n ");
358+
prog.push_str("fn main() {\n");
359359
prog.push_str(&everything_else);
360360
prog = prog.trim().into();
361361
prog.push_str("\n}");

src/test/rustdoc/playground-empty.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_name = "foo"]
12+
13+
#![doc(html_playground_url = "")]
14+
15+
//! module docs
16+
//!
17+
//! ```
18+
//! println!("Hello, world!");
19+
//! ```
20+
21+
// @!has foo/index.html '//a[@class="test-arrow"]' "Run"

src/test/rustdoc/playground-none.rs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_name = "foo"]
12+
13+
//! module docs
14+
//!
15+
//! ```
16+
//! println!("Hello, world!");
17+
//! ```
18+
19+
// @!has foo/index.html '//a[@class="test-arrow"]' "Run"

src/test/rustdoc/playground.rs

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-tidy-linelength
12+
13+
#![crate_name = "foo"]
14+
15+
#![doc(html_playground_url = "https://www.example.com/")]
16+
17+
//! module docs
18+
//!
19+
//! ```
20+
//! println!("Hello, world!");
21+
//! ```
22+
//!
23+
//! ```
24+
//! fn main() {
25+
//! println!("Hello, world!");
26+
//! }
27+
//! ```
28+
//!
29+
//! ```
30+
//! #![feature(something)]
31+
//!
32+
//! fn main() {
33+
//! println!("Hello, world!");
34+
//! }
35+
//! ```
36+
37+
// @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"
38+
// @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"
39+
// @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"

src/tools/error_index_generator/main.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use std::path::PathBuf;
2424

2525
use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
2626

27-
use rustdoc::html::markdown::Markdown;
27+
use rustdoc::html::markdown::{Markdown, PLAYGROUND};
2828
use rustc_serialize::json;
2929

3030
enum OutputFormat {
@@ -201,6 +201,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
201201
}
202202

203203
fn main() {
204+
PLAYGROUND.with(|slot| {
205+
*slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
206+
});
204207
let (format, dst) = parse_args();
205208
if let Err(e) = main_with_result(format, &dst) {
206209
panic!("{}", e.description());

0 commit comments

Comments
 (0)