diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index f2e083de0ec..f9d4d1af114 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -40,6 +40,9 @@ use crate::lint::init_lints; pub(crate) struct GlobalTestOptions { /// Whether to disable the default `extern crate my_crate;` when creating doctests. pub(crate) no_crate_inject: bool, + /// Whether inserting extra indent spaces in code block, + /// default is `false`, only `true` for generating code link of Rust playground + pub(crate) insert_indent_space: bool, /// Additional crate-level attributes to add to doctests. pub(crate) attrs: Vec, } @@ -221,7 +224,8 @@ pub(crate) fn run_tests( fn scrape_test_config(attrs: &[ast::Attribute]) -> GlobalTestOptions { use rustc_ast_pretty::pprust; - let mut opts = GlobalTestOptions { no_crate_inject: false, attrs: Vec::new() }; + let mut opts = + GlobalTestOptions { no_crate_inject: false, attrs: Vec::new(), insert_indent_space: false }; let test_attrs: Vec<_> = attrs .iter() @@ -725,7 +729,17 @@ pub(crate) fn make_test( // /// ``` <- end of the inner main line_offset += 1; - prog.extend([&main_pre, everything_else, &main_post].iter().cloned()); + // add extra 4 spaces for each line to offset the code block + let content = if opts.insert_indent_space { + everything_else + .lines() + .map(|line| format!(" {}", line)) + .collect::>() + .join("\n") + } else { + everything_else.to_string() + }; + prog.extend([&main_pre, content.as_str(), &main_post].iter().cloned()); } debug!("final doctest:\n{prog}"); diff --git a/src/librustdoc/doctest/tests.rs b/src/librustdoc/doctest/tests.rs index a30fe28f94f..9629acb31eb 100644 --- a/src/librustdoc/doctest/tests.rs +++ b/src/librustdoc/doctest/tests.rs @@ -53,7 +53,8 @@ assert_eq!(2+2, 4); fn make_test_no_crate_inject() { // Even if you do use the crate within the test, setting `opts.no_crate_inject` will skip // adding it anyway. - let opts = GlobalTestOptions { no_crate_inject: true, attrs: vec![] }; + let opts = + GlobalTestOptions { no_crate_inject: true, attrs: vec![], insert_indent_space: false }; let input = "use asdf::qwop; assert_eq!(2+2, 4);"; let expected = "#![allow(unused)] @@ -302,3 +303,44 @@ assert_eq!(2+2, 4); make_test(input, None, false, &opts, DEFAULT_EDITION, Some("_some_unique_name")); assert_eq!((output, len), (expected, 2)); } + +#[test] +fn make_test_insert_extra_space() { + // will insert indent spaces in the code block if `insert_indent_space` is true + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +assert_eq!(2+2, 4); +eprintln!(\"hello anan\"); +"; + let expected = "#![allow(unused)] +fn main() { + use std::*; + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 2)); +} + +#[test] +fn make_test_insert_extra_space_fn_main() { + // if input already has a fn main, it should insert a space before it + let opts = + GlobalTestOptions { no_crate_inject: false, attrs: vec![], insert_indent_space: true }; + let input = "use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}"; + let expected = "#![allow(unused)] +use std::*; +fn main() { + assert_eq!(2+2, 4); + eprintln!(\"hello anan\"); +}" + .to_string(); + let (output, len, _) = make_test(input, None, false, &opts, DEFAULT_EDITION, None); + assert_eq!((output, len), (expected, 1)); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index ee5891c12fc..21f682d15b9 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -45,6 +45,7 @@ use std::str::{self, CharIndices}; use crate::clean::RenderedLink; use crate::doctest; +use crate::doctest::GlobalTestOptions; use crate::html::escape::Escape; use crate::html::format::Buffer; use crate::html::highlight; @@ -302,8 +303,10 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .intersperse("\n".into()) .collect::(); let krate = krate.as_ref().map(|s| s.as_str()); - let (test, _, _) = - doctest::make_test(&test, krate, false, &Default::default(), edition, None); + + let mut opts: GlobalTestOptions = Default::default(); + opts.insert_indent_space = true; + let (test, _, _) = doctest::make_test(&test, krate, false, &opts, edition, None); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let test_escaped = small_url_encode(test); diff --git a/tests/rustdoc/playground-arg.rs b/tests/rustdoc/playground-arg.rs index 2542ed657c1..1d7085064e5 100644 --- a/tests/rustdoc/playground-arg.rs +++ b/tests/rustdoc/playground-arg.rs @@ -10,4 +10,4 @@ pub fn dummy() {} // ensure that `extern crate foo;` was inserted into code snips automatically: -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0Ause+foo::dummy;%0Adummy();%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://example.com/?code=%23!%5Ballow(unused)%5D%0A%23%5Ballow(unused_extern_crates)%5D%0Aextern+crate+r%23foo;%0Afn+main()+%7B%0A++++use+foo::dummy;%0A++++dummy();%0A%7D&edition=2015"]' "Run" diff --git a/tests/rustdoc/playground.rs b/tests/rustdoc/playground.rs index 5c7fa33efc5..a2fc9eb7387 100644 --- a/tests/rustdoc/playground.rs +++ b/tests/rustdoc/playground.rs @@ -22,6 +22,6 @@ //! } //! ``` -// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0Aprintln!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" +// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&edition=2015"]' "Run" // @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Ballow(unused)%5D%0A%23!%5Bfeature(something)%5D%0A%0Afn+main()+%7B%0A++++println!(%22Hello,+world!%22);%0A%7D&version=nightly&edition=2015"]' "Run"