From 0909f7be5b98383f59bd936b2052834ec662605e Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Feb 2020 14:20:42 +0100 Subject: [PATCH 1/6] Implement --source-code-external-url option --- src/librustdoc/config.rs | 18 +++++++++ src/librustdoc/html/render.rs | 27 +++++++++---- src/librustdoc/html/sources.rs | 73 ++++++++++++++++++---------------- src/librustdoc/lib.rs | 8 ++++ 4 files changed, 84 insertions(+), 42 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 33b3e800374e3..896fab0c57cbc 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -220,6 +220,8 @@ pub struct RenderOptions { pub generate_search_filter: bool, /// Option (disabled by default) to generate files used by RLS and some other tools. pub generate_redirect_pages: bool, + /// Base URL to use for source code linking. + pub source_code_external_url: Option, } impl Options { @@ -496,6 +498,21 @@ impl Options { let enable_per_target_ignores = matches.opt_present("enable-per-target-ignores"); let document_private = matches.opt_present("document-private-items"); let document_hidden = matches.opt_present("document-hidden-items"); + let source_code_external_url = matches.opt_str("source-code-external-url").map(|mut h| { + if !h.ends_with('/') { + h.push('/'); + } + h + }); + if let Some(ref source_code_external_url) = source_code_external_url { + if !source_code_external_url.starts_with("http://") + && !source_code_external_url.starts_with("https://") + { + diag.struct_err("option `--source-code-external-url` argument must be an URL") + .emit(); + return Err(1); + } + } let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -552,6 +569,7 @@ impl Options { markdown_playground_url, generate_search_filter, generate_redirect_pages, + source_code_external_url, }, }) } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 4dd2a6562a4cd..f80628abca40d 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -200,6 +200,7 @@ crate struct SharedContext { /// The default edition used to parse doctests. pub edition: Edition, pub codes: ErrorCodes, + pub source_code_external_url: Option, playground: Option, } @@ -409,6 +410,7 @@ pub fn run( static_root_path, generate_search_filter, generate_redirect_pages, + source_code_external_url, .. } = options; @@ -467,6 +469,7 @@ pub fn run( collapsed: krate.collapsed, src_root, include_sources, + source_code_external_url, local_sources: Default::default(), issue_tracker_base_url, layout, @@ -1602,13 +1605,23 @@ impl Context { } else { format!("{}-{}", item.source.loline, item.source.hiline) }; - Some(format!( - "{root}src/{krate}/{path}#{lines}", - root = Escape(&root), - krate = krate, - path = path, - lines = lines - )) + if let Some(ref source_code_external_url) = self.shared.source_code_external_url { + Some(format!( + "{root}{krate}/{path}#{lines}", + root = source_code_external_url, + krate = krate, + path = path, + lines = lines + )) + } else { + Some(format!( + "{root}src/{krate}/{path}#{lines}", + root = Escape(&root), + krate = krate, + path = path, + lines = lines + )) + } } } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 79e7d3d783b80..6f13c4a3842e2 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -74,17 +74,6 @@ impl<'a> SourceCollector<'a> { return Ok(()); } - let contents = match fs::read_to_string(&p) { - Ok(contents) => contents, - Err(e) => { - return Err(Error::new(e, &p)); - } - }; - - // Remove the utf-8 BOM if any - let contents = - if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] }; - // Create the intermediate directories let mut cur = self.dst.clone(); let mut root_path = String::from("../../"); @@ -101,30 +90,44 @@ impl<'a> SourceCollector<'a> { cur.push(&fname); href.push_str(&fname.to_string_lossy()); - let title = format!( - "{} -- source", - cur.file_name().expect("failed to get file name").to_string_lossy() - ); - let desc = format!("Source to the Rust file `{}`.", filename); - let page = layout::Page { - title: &title, - css_class: "source", - root_path: &root_path, - static_root_path: self.scx.static_root_path.as_deref(), - description: &desc, - keywords: BASIC_KEYWORDS, - resource_suffix: &self.scx.resource_suffix, - extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], - static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], - }; - let v = layout::render( - &self.scx.layout, - &page, - "", - |buf: &mut _| print_src(buf, &contents), - &self.scx.themes, - ); - self.scx.fs.write(&cur, v.as_bytes())?; + // we don't emit source if we have an external location for it + if self.scx.source_code_external_url.is_none() { + let contents = match fs::read_to_string(&p) { + Ok(contents) => contents, + Err(e) => { + return Err(Error::new(e, &p)); + } + }; + + // Remove the utf-8 BOM if any + let contents = + if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] }; + + let title = format!( + "{} -- source", + cur.file_name().expect("failed to get file name").to_string_lossy() + ); + let desc = format!("Source to the Rust file `{}`.", filename); + let page = layout::Page { + title: &title, + css_class: "source", + root_path: &root_path, + static_root_path: self.scx.static_root_path.as_deref(), + description: &desc, + keywords: BASIC_KEYWORDS, + resource_suffix: &self.scx.resource_suffix, + extra_scripts: &[&format!("source-files{}", self.scx.resource_suffix)], + static_extra_scripts: &[&format!("source-script{}", self.scx.resource_suffix)], + }; + let v = layout::render( + &self.scx.layout, + &page, + "", + |buf: &mut _| print_src(buf, &contents), + &self.scx.themes, + ); + self.scx.fs.write(&cur, v.as_bytes())?; + } self.scx.local_sources.insert(p.clone(), href); Ok(()) } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4ea14ab9077c6..2dac90475325a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -418,6 +418,14 @@ fn opts() -> Vec { "specified the rustc-like binary to use as the test builder", ) }), + unstable("source-code-external-url", |o| { + o.optopt( + "", + "source-code-external-url", + "Base URL for external source code linking", + "URL", + ) + }), ] } From 0a079f04cd2d3d1f7d01bf3b9d8b1418a0a63de1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Feb 2020 14:20:59 +0100 Subject: [PATCH 2/6] Add tests for --source-code-external-url option --- src/test/rustdoc-ui/invalid_source_code_external_url.rs | 3 +++ .../rustdoc-ui/invalid_source_code_external_url.stderr | 2 ++ src/test/rustdoc/source_code_external_url.rs | 8 ++++++++ src/test/rustdoc/source_code_external_url2.rs | 8 ++++++++ 4 files changed, 21 insertions(+) create mode 100644 src/test/rustdoc-ui/invalid_source_code_external_url.rs create mode 100644 src/test/rustdoc-ui/invalid_source_code_external_url.stderr create mode 100644 src/test/rustdoc/source_code_external_url.rs create mode 100644 src/test/rustdoc/source_code_external_url2.rs diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.rs b/src/test/rustdoc-ui/invalid_source_code_external_url.rs new file mode 100644 index 0000000000000..54bc7cbb1a0d9 --- /dev/null +++ b/src/test/rustdoc-ui/invalid_source_code_external_url.rs @@ -0,0 +1,3 @@ +// compile-flags:--Z unstable-options --source-code-external-url hello + +pub struct Foo; diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.stderr b/src/test/rustdoc-ui/invalid_source_code_external_url.stderr new file mode 100644 index 0000000000000..087956b2b0226 --- /dev/null +++ b/src/test/rustdoc-ui/invalid_source_code_external_url.stderr @@ -0,0 +1,2 @@ +error: option `--source-code-external-url` argument must be an URL + diff --git a/src/test/rustdoc/source_code_external_url.rs b/src/test/rustdoc/source_code_external_url.rs new file mode 100644 index 0000000000000..2d606defb2c2d --- /dev/null +++ b/src/test/rustdoc/source_code_external_url.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength +// compile-flags: -Z unstable-options --source-code-external-url https://a.a + +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//h1[@class="fqn"]//a[@href="https://a.a/foo/source_code_external_url.rs.html#8"]' '[src]' +pub struct Foo; diff --git a/src/test/rustdoc/source_code_external_url2.rs b/src/test/rustdoc/source_code_external_url2.rs new file mode 100644 index 0000000000000..7bbee0ee76f38 --- /dev/null +++ b/src/test/rustdoc/source_code_external_url2.rs @@ -0,0 +1,8 @@ +// ignore-tidy-linelength +// compile-flags: -Z unstable-options --source-code-external-url https://a.a/ + +#![crate_name = "foo"] + +// @has foo/struct.Foo.html +// @has - '//h1[@class="fqn"]//a[@href="https://a.a/foo/source_code_external_url2.rs.html#8"]' '[src]' +pub struct Foo; From 52dbe7c1f1f3081a457d5f63bebe4b7669464410 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 14 Feb 2020 14:31:22 +0100 Subject: [PATCH 3/6] Add documentation for --source-code-external-url option --- src/doc/rustdoc/src/unstable-features.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index a48526d39fd0a..d7cbac8fc2b05 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -453,7 +453,7 @@ override `ignore`. ### `--runtool`, `--runtool-arg`: program to run tests with; args to pass to it -Using thses options looks like this: +Using these options looks like this: ```bash $ rustdoc src/lib.rs -Z unstable-options --runtool runner --runtool-arg --do-thing --runtool-arg --do-other-thing @@ -467,3 +467,20 @@ $ rustdoc src/lib.rs -Z unstable-options --runtool valgrind ``` Another use case would be to run a test inside an emulator, or through a Virtual Machine. + +### `--source-code-external-url`: using external source code + +In case you don't want to generate the source code files and instead use existing ones (available +through an HTTP URL!), you can use this option: + +```bash +$ rustdoc src/lib.rs -Z unstable-options --source-code-external-url 'https://somewhere.com' +``` + +Note that generated source URLs will look like this: + +```text +https://somewhere.com/[crate name] +``` + +It is equivalent to the local `src/[crate name]` folder. From 7cc197c0b60e8d21ed4661514887f2b25e9dc2fe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Mar 2020 14:17:32 +0100 Subject: [PATCH 4/6] Handle external sources URL differently --- src/librustdoc/config.rs | 12 ++++++------ src/librustdoc/html/render.rs | 26 ++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 896fab0c57cbc..02f73b6310bb0 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -502,14 +502,14 @@ impl Options { if !h.ends_with('/') { h.push('/'); } - h + h.replace("\\", "/") }); if let Some(ref source_code_external_url) = source_code_external_url { - if !source_code_external_url.starts_with("http://") - && !source_code_external_url.starts_with("https://") - { - diag.struct_err("option `--source-code-external-url` argument must be an URL") - .emit(); + if source_code_external_url.starts_with("/") { + diag.struct_err( + "option `--source-code-external-url` argument cannot be an absolute local path", + ) + .emit(); return Err(1); } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index f80628abca40d..1c3a583d8142a 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1553,6 +1553,21 @@ impl Context { } } +fn compute_path(path: String) -> String { + if path.split('/').find(|x| *x == "..").is_none() { + return path; + } + let mut new_path = Vec::new(); + for part in path.split('/') { + if part == ".." && !new_path.is_empty() { + new_path.pop(); + } else { + new_path.push(part); + } + } + new_path.join("/") +} + impl Context { /// Generates a url appropriate for an `href` attribute back to the source of /// this item. @@ -1607,10 +1622,13 @@ impl Context { }; if let Some(ref source_code_external_url) = self.shared.source_code_external_url { Some(format!( - "{root}{krate}/{path}#{lines}", - root = source_code_external_url, - krate = krate, - path = path, + "{path}#{lines}", + path = compute_path(format!( + "{root}{krate}/{path}", + root = source_code_external_url, + krate = krate, + path = path, + ),), lines = lines )) } else { From b5c573b25f29fc28f6187493b0c57ad1994c43be Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 6 Mar 2020 14:17:48 +0100 Subject: [PATCH 5/6] Update source code external URL test --- src/test/rustdoc-ui/invalid_source_code_external_url.rs | 2 +- src/test/rustdoc-ui/invalid_source_code_external_url.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.rs b/src/test/rustdoc-ui/invalid_source_code_external_url.rs index 54bc7cbb1a0d9..6c289425357cd 100644 --- a/src/test/rustdoc-ui/invalid_source_code_external_url.rs +++ b/src/test/rustdoc-ui/invalid_source_code_external_url.rs @@ -1,3 +1,3 @@ -// compile-flags:--Z unstable-options --source-code-external-url hello +// compile-flags:--Z unstable-options --source-code-external-url /hello pub struct Foo; diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.stderr b/src/test/rustdoc-ui/invalid_source_code_external_url.stderr index 087956b2b0226..0f8ef11a6bde8 100644 --- a/src/test/rustdoc-ui/invalid_source_code_external_url.stderr +++ b/src/test/rustdoc-ui/invalid_source_code_external_url.stderr @@ -1,2 +1,2 @@ -error: option `--source-code-external-url` argument must be an URL +error: option `--source-code-external-url` argument cannot be an absolute local path From cbf13bd450fde08914f8a86156d59c97b8960175 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 9 Mar 2020 09:29:26 +0100 Subject: [PATCH 6/6] Remove absolute path check --- src/librustdoc/config.rs | 9 --------- src/librustdoc/html/render.rs | 8 ++++---- src/test/rustdoc-ui/invalid_source_code_external_url.rs | 3 --- .../rustdoc-ui/invalid_source_code_external_url.stderr | 2 -- 4 files changed, 4 insertions(+), 18 deletions(-) delete mode 100644 src/test/rustdoc-ui/invalid_source_code_external_url.rs delete mode 100644 src/test/rustdoc-ui/invalid_source_code_external_url.stderr diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 02f73b6310bb0..eb44ef60b0041 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -504,15 +504,6 @@ impl Options { } h.replace("\\", "/") }); - if let Some(ref source_code_external_url) = source_code_external_url { - if source_code_external_url.starts_with("/") { - diag.struct_err( - "option `--source-code-external-url` argument cannot be an absolute local path", - ) - .emit(); - return Err(1); - } - } let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 1c3a583d8142a..f7eb545c6beb7 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -1559,10 +1559,10 @@ fn compute_path(path: String) -> String { } let mut new_path = Vec::new(); for part in path.split('/') { - if part == ".." && !new_path.is_empty() { - new_path.pop(); - } else { + if part != ".." { new_path.push(part); + } else if !new_path.is_empty() { + new_path.pop(); } } new_path.join("/") @@ -1624,7 +1624,7 @@ impl Context { Some(format!( "{path}#{lines}", path = compute_path(format!( - "{root}{krate}/{path}", + "{root}/{path}", root = source_code_external_url, krate = krate, path = path, diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.rs b/src/test/rustdoc-ui/invalid_source_code_external_url.rs deleted file mode 100644 index 6c289425357cd..0000000000000 --- a/src/test/rustdoc-ui/invalid_source_code_external_url.rs +++ /dev/null @@ -1,3 +0,0 @@ -// compile-flags:--Z unstable-options --source-code-external-url /hello - -pub struct Foo; diff --git a/src/test/rustdoc-ui/invalid_source_code_external_url.stderr b/src/test/rustdoc-ui/invalid_source_code_external_url.stderr deleted file mode 100644 index 0f8ef11a6bde8..0000000000000 --- a/src/test/rustdoc-ui/invalid_source_code_external_url.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: option `--source-code-external-url` argument cannot be an absolute local path -