From dbad77ffdd59e54b3f496cfbdb7909a6bbd03031 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sat, 10 Aug 2019 18:07:07 -0400 Subject: [PATCH] Remove thread-local for playground config --- src/librustdoc/config.rs | 2 +- src/librustdoc/externalfiles.rs | 8 +- src/librustdoc/html/markdown.rs | 203 +++++++++++++----------- src/librustdoc/html/render.rs | 29 ++-- src/librustdoc/markdown.rs | 11 +- src/tools/error_index_generator/main.rs | 11 +- 6 files changed, 147 insertions(+), 117 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 2be67d707fe..98ab957ecbb 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -378,7 +378,7 @@ impl Options { &matches.opt_strs("html-after-content"), &matches.opt_strs("markdown-before-content"), &matches.opt_strs("markdown-after-content"), - &diag, &mut id_map, edition) { + &diag, &mut id_map, edition, &None) { Some(eh) => eh, None => return Err(3), }; diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index d604ba11d41..d920b7c4c91 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -4,7 +4,7 @@ use std::str; use errors; use crate::syntax::feature_gate::UnstableFeatures; use crate::syntax::edition::Edition; -use crate::html::markdown::{IdMap, ErrorCodes, Markdown}; +use crate::html::markdown::{IdMap, ErrorCodes, Markdown, Playground}; use std::cell::RefCell; @@ -24,7 +24,7 @@ pub struct ExternalHtml { impl ExternalHtml { pub fn load(in_header: &[String], before_content: &[String], after_content: &[String], md_before_content: &[String], md_after_content: &[String], diag: &errors::Handler, - id_map: &mut IdMap, edition: Edition) + id_map: &mut IdMap, edition: Edition, playground: &Option) -> Option { let codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); load_external_files(in_header, diag) @@ -36,7 +36,7 @@ impl ExternalHtml { load_external_files(md_before_content, diag) .map(|m_bc| (ih, format!("{}{}", bc, Markdown(&m_bc, &[], RefCell::new(id_map), - codes, edition)))) + codes, edition, playground)))) ) .and_then(|(ih, bc)| load_external_files(after_content, diag) @@ -46,7 +46,7 @@ impl ExternalHtml { load_external_files(md_after_content, diag) .map(|m_ac| (ih, bc, format!("{}{}", ac, Markdown(&m_ac, &[], RefCell::new(id_map), - codes, edition)))) + codes, edition, playground)))) ) .map(|(ih, bc, ac)| ExternalHtml { diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ef52ce62875..73233a2289c 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -17,7 +17,7 @@ //! let s = "My *markdown* _text_"; //! let mut id_map = IdMap::new(); //! let html = format!("{}", Markdown(s, &[], RefCell::new(&mut id_map), -//! ErrorCodes::Yes, Edition::Edition2015)); +//! ErrorCodes::Yes, Edition::Edition2015, None)); //! // ... something using html //! ``` @@ -59,6 +59,7 @@ pub struct Markdown<'a>( pub ErrorCodes, /// Default edition to use when parsing doctests (to add a `fn main`). pub Edition, + pub &'a Option, ); /// A tuple struct like `Markdown` that renders the markdown with a table of contents. pub struct MarkdownWithToc<'a>( @@ -66,9 +67,16 @@ pub struct MarkdownWithToc<'a>( pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition, + pub &'a Option, ); /// A tuple struct like `Markdown` that renders the markdown escaping HTML tags. -pub struct MarkdownHtml<'a>(pub &'a str, pub RefCell<&'a mut IdMap>, pub ErrorCodes, pub Edition); +pub struct MarkdownHtml<'a>( + pub &'a str, + pub RefCell<&'a mut IdMap>, + pub ErrorCodes, + pub Edition, + pub &'a Option, +); /// A tuple struct like `Markdown` that renders only the first paragraph. pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); @@ -155,30 +163,39 @@ fn slugify(c: char) -> Option { } } -// Information about the playground if a URL has been specified, containing an -// optional crate name and the URL. -thread_local!(pub static PLAYGROUND: RefCell, String)>> = { - RefCell::new(None) -}); +#[derive(Clone, Debug)] +pub struct Playground { + pub crate_name: Option, + pub url: String, +} /// Adds syntax highlighting and playground Run buttons to Rust code blocks. -struct CodeBlocks<'a, I: Iterator>> { +struct CodeBlocks<'p, 'a, I: Iterator>> { inner: I, check_error_codes: ErrorCodes, edition: Edition, + // Information about the playground if a URL has been specified, containing an + // optional crate name and the URL. + playground: &'p Option, } -impl<'a, I: Iterator>> CodeBlocks<'a, I> { - fn new(iter: I, error_codes: ErrorCodes, edition: Edition) -> Self { +impl<'p, 'a, I: Iterator>> CodeBlocks<'p, 'a, I> { + fn new( + iter: I, + error_codes: ErrorCodes, + edition: Edition, + playground: &'p Option, + ) -> Self { CodeBlocks { inner: iter, check_error_codes: error_codes, edition, + playground, } } } -impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { +impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option { @@ -213,86 +230,86 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'a, I> { } let lines = origtext.lines().filter_map(|l| map_line(l).for_html()); let text = lines.collect::>>().join("\n"); - 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"); - 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| map_line(l).for_code()) - .collect::>>().join("\n"); - let krate = krate.as_ref().map(|s| &**s); - let (test, _) = test::make_test(&test, krate, false, - &Default::default(), edition); - let channel = if test.contains("#![feature(") { - "&version=nightly" - } else { - "" - }; - - let edition_string = format!("&edition={}", edition); - - // 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#"Run"#, - url, test_escaped, channel, edition_string - )) - }); - - let tooltip = if ignore { - Some(("This example is not tested".to_owned(), "ignore")) - } else if compile_fail { - Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) - } else if explicit_edition { - Some((format!("This code runs with edition {}", edition), "edition")) + // insert newline to clearly separate it from the + // previous block so we can shorten the html output + let mut s = String::from("\n"); + let playground_button = self.playground.as_ref().and_then(|playground| { + let krate = &playground.crate_name; + let url = &playground.url; + if url.is_empty() { + return None; + } + let test = origtext.lines() + .map(|l| map_line(l).for_code()) + .collect::>>().join("\n"); + let krate = krate.as_ref().map(|s| &**s); + let (test, _) = test::make_test(&test, krate, false, + &Default::default(), edition); + let channel = if test.contains("#![feature(") { + "&version=nightly" } else { - None + "" }; - if let Some((s1, s2)) = tooltip { - s.push_str(&highlight::render_with_highlighting( - &text, - Some(&format!("rust-example-rendered{}", - if ignore { " ignore" } - else if compile_fail { " compile_fail" } - else if explicit_edition { " edition " } - else { "" })), - playground_button.as_ref().map(String::as_str), - Some((s1.as_str(), s2)))); - Some(Event::Html(s.into())) - } else { - s.push_str(&highlight::render_with_highlighting( - &text, - Some(&format!("rust-example-rendered{}", - if ignore { " ignore" } - else if compile_fail { " compile_fail" } - else if explicit_edition { " edition " } - else { "" })), - playground_button.as_ref().map(String::as_str), - None)); - Some(Event::Html(s.into())) + let edition_string = format!("&edition={}", edition); + + // 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#"Run"#, + url, test_escaped, channel, edition_string + )) + }); + + let tooltip = if ignore { + Some(("This example is not tested".to_owned(), "ignore")) + } else if compile_fail { + Some(("This example deliberately fails to compile".to_owned(), "compile_fail")) + } else if explicit_edition { + Some((format!("This code runs with edition {}", edition), "edition")) + } else { + None + }; + + if let Some((s1, s2)) = tooltip { + s.push_str(&highlight::render_with_highlighting( + &text, + Some(&format!("rust-example-rendered{}", + if ignore { " ignore" } + else if compile_fail { " compile_fail" } + else if explicit_edition { " edition " } + else { "" })), + playground_button.as_ref().map(String::as_str), + Some((s1.as_str(), s2)))); + Some(Event::Html(s.into())) + } else { + s.push_str(&highlight::render_with_highlighting( + &text, + Some(&format!("rust-example-rendered{}", + if ignore { " ignore" } + else if compile_fail { " compile_fail" } + else if explicit_edition { " edition " } + else { "" })), + playground_button.as_ref().map(String::as_str), + None)); + Some(Event::Html(s.into())) + } } } @@ -676,7 +693,7 @@ impl LangString { impl<'a> fmt::Display for Markdown<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let Markdown(md, links, ref ids, codes, edition) = *self; + let Markdown(md, links, ref ids, codes, edition, playground) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case @@ -695,7 +712,7 @@ impl<'a> fmt::Display for Markdown<'a> { let p = HeadingLinks::new(p, None, &mut ids); let p = LinkReplacer::new(p, links); - let p = CodeBlocks::new(p, codes, edition); + let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); html::push_html(&mut s, p); @@ -705,7 +722,7 @@ impl<'a> fmt::Display for Markdown<'a> { impl<'a> fmt::Display for MarkdownWithToc<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownWithToc(md, ref ids, codes, edition) = *self; + let MarkdownWithToc(md, ref ids, codes, edition, playground) = *self; let mut ids = ids.borrow_mut(); let p = Parser::new_ext(md, opts()); @@ -716,7 +733,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { { let p = HeadingLinks::new(p, Some(&mut toc), &mut ids); - let p = CodeBlocks::new(p, codes, edition); + let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); html::push_html(&mut s, p); } @@ -729,7 +746,7 @@ impl<'a> fmt::Display for MarkdownWithToc<'a> { impl<'a> fmt::Display for MarkdownHtml<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let MarkdownHtml(md, ref ids, codes, edition) = *self; + let MarkdownHtml(md, ref ids, codes, edition, playground) = *self; let mut ids = ids.borrow_mut(); // This is actually common enough to special-case @@ -745,7 +762,7 @@ impl<'a> fmt::Display for MarkdownHtml<'a> { let mut s = String::with_capacity(md.len() * 3 / 2); let p = HeadingLinks::new(p, None, &mut ids); - let p = CodeBlocks::new(p, codes, edition); + let p = CodeBlocks::new(p, codes, edition, playground); let p = Footnotes::new(p); html::push_html(&mut s, p); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index eb88c72da9e..8a7dfebdbbc 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -170,6 +170,7 @@ struct Context { /// The map used to ensure all generated 'id=' attributes are unique. id_map: Rc>, pub shared: Arc, + playground: Option, } struct SharedContext { @@ -574,9 +575,11 @@ pub fn run(mut krate: clean::Crate, }; // If user passed in `--playground-url` arg, we fill in crate name here + let mut playground = None; if let Some(url) = playground_url { - markdown::PLAYGROUND.with(|slot| { - *slot.borrow_mut() = Some((Some(krate.name.clone()), url)); + playground = Some(markdown::Playground { + crate_name: Some(krate.name.clone()), + url, }); } @@ -592,9 +595,9 @@ pub fn run(mut krate: clean::Crate, scx.layout.logo = s.to_string(); } (sym::html_playground_url, Some(s)) => { - markdown::PLAYGROUND.with(|slot| { - let name = krate.name.clone(); - *slot.borrow_mut() = Some((Some(name), s.to_string())); + playground = Some(markdown::Playground { + crate_name: Some(krate.name.clone()), + url: s.to_string(), }); } (sym::issue_tracker_base_url, Some(s)) => { @@ -618,6 +621,7 @@ pub fn run(mut krate: clean::Crate, edition, id_map: Rc::new(RefCell::new(id_map)), shared: Arc::new(scx), + playground, }; // Crawl the crate to build various caches used for the output @@ -2592,7 +2596,7 @@ fn render_markdown(w: &mut fmt::Formatter<'_>, if is_hidden { " hidden" } else { "" }, prefix, Markdown(md_text, &links, RefCell::new(&mut ids), - cx.codes, cx.edition)) + cx.codes, cx.edition, &cx.playground)) } fn document_short( @@ -2957,7 +2961,8 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { if let Some(note) = note { let mut ids = cx.id_map.borrow_mut(); - let html = MarkdownHtml(¬e, RefCell::new(&mut ids), error_codes, cx.edition); + let html = MarkdownHtml( + ¬e, RefCell::new(&mut ids), error_codes, cx.edition, &cx.playground); message.push_str(&format!(": {}", html)); } stability.push(format!("
{}
", message)); @@ -3006,7 +3011,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { message = format!( "
{}{}
", message, - MarkdownHtml(&unstable_reason, RefCell::new(&mut ids), error_codes, cx.edition) + MarkdownHtml( + &unstable_reason, + RefCell::new(&mut ids), + error_codes, + cx.edition, + &cx.playground, + ) ); } @@ -4237,7 +4248,7 @@ fn render_impl(w: &mut fmt::Formatter<'_>, cx: &Context, i: &Impl, link: AssocIt let mut ids = cx.id_map.borrow_mut(); write!(w, "
{}
", Markdown(&*dox, &i.impl_item.links(), RefCell::new(&mut ids), - cx.codes, cx.edition))?; + cx.codes, cx.edition, &cx.playground))?; } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 50a647f244d..b7dd6c30f09 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -60,9 +60,10 @@ pub fn render( }; let playground_url = options.markdown_playground_url .or(options.playground_url); - if let Some(playground) = playground_url { - markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); }); - } + let playground = playground_url.map(|url| markdown::Playground { + crate_name: None, + url, + }); let mut out = match File::create(&output) { Err(e) => { @@ -82,9 +83,9 @@ pub fn render( let mut ids = IdMap::new(); let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build()); let text = if !options.markdown_no_toc { - MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition).to_string() + MarkdownWithToc(text, RefCell::new(&mut ids), error_codes, edition, &playground).to_string() } else { - Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition).to_string() + Markdown(text, &[], RefCell::new(&mut ids), error_codes, edition, &playground).to_string() }; let err = write!( diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index c31a5069e46..33987b0b542 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -16,7 +16,7 @@ use std::cell::RefCell; use syntax::edition::DEFAULT_EDITION; use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata}; -use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, PLAYGROUND}; +use rustdoc::html::markdown::{Markdown, IdMap, ErrorCodes, Playground}; use rustc_serialize::json; enum OutputFormat { @@ -95,9 +95,13 @@ impl Formatter for HTMLFormatter { match info.description { Some(ref desc) => { let mut id_map = self.0.borrow_mut(); + let playground = Playground { + crate_name: None, + url: String::from("https://play.rust-lang.org/"), + }; write!(output, "{}", Markdown(desc, &[], RefCell::new(&mut id_map), - ErrorCodes::Yes, DEFAULT_EDITION))? + ErrorCodes::Yes, DEFAULT_EDITION, &Some(playground)))? }, None => write!(output, "

No description.

\n")?, } @@ -260,9 +264,6 @@ fn parse_args() -> (OutputFormat, PathBuf) { fn main() { env_logger::init(); - PLAYGROUND.with(|slot| { - *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/"))); - }); let (format, dst) = parse_args(); let result = syntax::with_default_globals(move || { main_with_result(format, &dst)