rfc#3662 changes under unstable flags
* All new functionality is under unstable options * Adds `--merge=shared|none|finalize` flags * Adds `--parts-out-dir=<crate specific directory>` for `--merge=none` to write cross-crate info file for a single crate * Adds `--include-parts-dir=<previously specified directory>` for `--merge=finalize` to write cross-crate info files * update tests/run-make/rustdoc-default-output/rmake.rs golden
This commit is contained in:
parent
3782251c2c
commit
2e1cba6415
@ -53,6 +53,14 @@ fn try_from(value: &str) -> Result<Self, Self::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Either an input crate, markdown file, or nothing (--merge=finalize).
|
||||||
|
pub(crate) enum InputMode {
|
||||||
|
/// The `--merge=finalize` step does not need an input crate to rustdoc.
|
||||||
|
NoInputMergeFinalize,
|
||||||
|
/// A crate or markdown file.
|
||||||
|
HasFile(Input),
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration options for rustdoc.
|
/// Configuration options for rustdoc.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct Options {
|
pub(crate) struct Options {
|
||||||
@ -286,6 +294,12 @@ pub(crate) struct RenderOptions {
|
|||||||
/// This field is only used for the JSON output. If it's set to true, no file will be created
|
/// This field is only used for the JSON output. If it's set to true, no file will be created
|
||||||
/// and content will be displayed in stdout directly.
|
/// and content will be displayed in stdout directly.
|
||||||
pub(crate) output_to_stdout: bool,
|
pub(crate) output_to_stdout: bool,
|
||||||
|
/// Whether we should read or write rendered cross-crate info in the doc root.
|
||||||
|
pub(crate) should_merge: ShouldMerge,
|
||||||
|
/// Path to crate-info for external crates.
|
||||||
|
pub(crate) include_parts_dir: Vec<PathToParts>,
|
||||||
|
/// Where to write crate-info
|
||||||
|
pub(crate) parts_out_dir: Option<PathToParts>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
@ -345,7 +359,7 @@ pub(crate) fn from_matches(
|
|||||||
early_dcx: &mut EarlyDiagCtxt,
|
early_dcx: &mut EarlyDiagCtxt,
|
||||||
matches: &getopts::Matches,
|
matches: &getopts::Matches,
|
||||||
args: Vec<String>,
|
args: Vec<String>,
|
||||||
) -> Option<(Input, Options, RenderOptions)> {
|
) -> Option<(InputMode, Options, RenderOptions)> {
|
||||||
// Check for unstable options.
|
// Check for unstable options.
|
||||||
nightly_options::check_nightly_options(early_dcx, matches, &opts());
|
nightly_options::check_nightly_options(early_dcx, matches, &opts());
|
||||||
|
|
||||||
@ -475,15 +489,17 @@ fn println_condition(condition: Condition) {
|
|||||||
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
|
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
|
||||||
|
|
||||||
let input = if describe_lints {
|
let input = if describe_lints {
|
||||||
"" // dummy, this won't be used
|
InputMode::HasFile(make_input(early_dcx, ""))
|
||||||
} else {
|
} else {
|
||||||
match matches.free.as_slice() {
|
match matches.free.as_slice() {
|
||||||
|
[] if matches.opt_str("merge").as_deref() == Some("finalize") => {
|
||||||
|
InputMode::NoInputMergeFinalize
|
||||||
|
}
|
||||||
[] => dcx.fatal("missing file operand"),
|
[] => dcx.fatal("missing file operand"),
|
||||||
[input] => input,
|
[input] => InputMode::HasFile(make_input(early_dcx, input)),
|
||||||
_ => dcx.fatal("too many file operands"),
|
_ => dcx.fatal("too many file operands"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let input = make_input(early_dcx, input);
|
|
||||||
|
|
||||||
let externs = parse_externs(early_dcx, matches, &unstable_opts);
|
let externs = parse_externs(early_dcx, matches, &unstable_opts);
|
||||||
let extern_html_root_urls = match parse_extern_html_roots(matches) {
|
let extern_html_root_urls = match parse_extern_html_roots(matches) {
|
||||||
@ -491,6 +507,16 @@ fn println_condition(condition: Condition) {
|
|||||||
Err(err) => dcx.fatal(err),
|
Err(err) => dcx.fatal(err),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let parts_out_dir =
|
||||||
|
match matches.opt_str("parts-out-dir").map(|p| PathToParts::from_flag(p)).transpose() {
|
||||||
|
Ok(parts_out_dir) => parts_out_dir,
|
||||||
|
Err(e) => dcx.fatal(e),
|
||||||
|
};
|
||||||
|
let include_parts_dir = match parse_include_parts_dir(matches) {
|
||||||
|
Ok(include_parts_dir) => include_parts_dir,
|
||||||
|
Err(e) => dcx.fatal(e),
|
||||||
|
};
|
||||||
|
|
||||||
let default_settings: Vec<Vec<(String, String)>> = vec![
|
let default_settings: Vec<Vec<(String, String)>> = vec![
|
||||||
matches
|
matches
|
||||||
.opt_str("default-theme")
|
.opt_str("default-theme")
|
||||||
@ -732,6 +758,10 @@ fn println_condition(condition: Condition) {
|
|||||||
let extern_html_root_takes_precedence =
|
let extern_html_root_takes_precedence =
|
||||||
matches.opt_present("extern-html-root-takes-precedence");
|
matches.opt_present("extern-html-root-takes-precedence");
|
||||||
let html_no_source = matches.opt_present("html-no-source");
|
let html_no_source = matches.opt_present("html-no-source");
|
||||||
|
let should_merge = match parse_merge(matches) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(e) => dcx.fatal(format!("--merge option error: {e}")),
|
||||||
|
};
|
||||||
|
|
||||||
if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
|
if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
|
||||||
dcx.struct_warn(
|
dcx.struct_warn(
|
||||||
@ -819,6 +849,9 @@ fn println_condition(condition: Condition) {
|
|||||||
no_emit_shared: false,
|
no_emit_shared: false,
|
||||||
html_no_source,
|
html_no_source,
|
||||||
output_to_stdout,
|
output_to_stdout,
|
||||||
|
should_merge,
|
||||||
|
include_parts_dir,
|
||||||
|
parts_out_dir,
|
||||||
};
|
};
|
||||||
Some((input, options, render_options))
|
Some((input, options, render_options))
|
||||||
}
|
}
|
||||||
@ -894,3 +927,71 @@ fn parse_extern_html_roots(
|
|||||||
}
|
}
|
||||||
Ok(externs)
|
Ok(externs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Path directly to crate-info file.
|
||||||
|
///
|
||||||
|
/// For example, `/home/user/project/target/doc.parts/<crate>/crate-info`.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub(crate) struct PathToParts(pub(crate) PathBuf);
|
||||||
|
|
||||||
|
impl PathToParts {
|
||||||
|
fn from_flag(path: String) -> Result<PathToParts, String> {
|
||||||
|
let mut path = PathBuf::from(path);
|
||||||
|
// check here is for diagnostics
|
||||||
|
if path.exists() && !path.is_dir() {
|
||||||
|
Err(format!(
|
||||||
|
"--parts-out-dir and --include-parts-dir expect directories, found: {}",
|
||||||
|
path.display(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
// if it doesn't exist, we'll create it. worry about that in write_shared
|
||||||
|
path.push("crate-info");
|
||||||
|
Ok(PathToParts(path))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reports error if --include-parts-dir / crate-info is not a file
|
||||||
|
fn parse_include_parts_dir(m: &getopts::Matches) -> Result<Vec<PathToParts>, String> {
|
||||||
|
let mut ret = Vec::new();
|
||||||
|
for p in m.opt_strs("include-parts-dir") {
|
||||||
|
let p = PathToParts::from_flag(p)?;
|
||||||
|
// this is just for diagnostic
|
||||||
|
if !p.0.is_file() {
|
||||||
|
return Err(format!("--include-parts-dir expected {} to be a file", p.0.display()));
|
||||||
|
}
|
||||||
|
ret.push(p);
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Controls merging of cross-crate information
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct ShouldMerge {
|
||||||
|
/// Should we append to existing cci in the doc root
|
||||||
|
pub(crate) read_rendered_cci: bool,
|
||||||
|
/// Should we write cci to the doc root
|
||||||
|
pub(crate) write_rendered_cci: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extracts read_rendered_cci and write_rendered_cci from command line arguments, or
|
||||||
|
/// reports an error if an invalid option was provided
|
||||||
|
fn parse_merge(m: &getopts::Matches) -> Result<ShouldMerge, &'static str> {
|
||||||
|
match m.opt_str("merge").as_deref() {
|
||||||
|
// default = read-write
|
||||||
|
None => Ok(ShouldMerge { read_rendered_cci: true, write_rendered_cci: true }),
|
||||||
|
Some("none") if m.opt_present("include-parts-dir") => {
|
||||||
|
Err("--include-parts-dir not allowed if --merge=none")
|
||||||
|
}
|
||||||
|
Some("none") => Ok(ShouldMerge { read_rendered_cci: false, write_rendered_cci: false }),
|
||||||
|
Some("shared") if m.opt_present("parts-out-dir") || m.opt_present("include-parts-dir") => {
|
||||||
|
Err("--parts-out-dir and --include-parts-dir not allowed if --merge=shared")
|
||||||
|
}
|
||||||
|
Some("shared") => Ok(ShouldMerge { read_rendered_cci: true, write_rendered_cci: true }),
|
||||||
|
Some("finalize") if m.opt_present("parts-out-dir") => {
|
||||||
|
Err("--parts-out-dir not allowed if --merge=finalize")
|
||||||
|
}
|
||||||
|
Some("finalize") => Ok(ShouldMerge { read_rendered_cci: false, write_rendered_cci: true }),
|
||||||
|
Some(_) => Err("argument to --merge must be `none`, `shared`, or `finalize`"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -16,12 +16,11 @@
|
|||||||
|
|
||||||
use super::print_item::{full_path, item_path, print_item};
|
use super::print_item::{full_path, item_path, print_item};
|
||||||
use super::sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar};
|
use super::sidebar::{print_sidebar, sidebar_module_like, ModuleLike, Sidebar};
|
||||||
use super::write_shared::write_shared;
|
|
||||||
use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath};
|
use super::{collect_spans_and_sources, scrape_examples_help, AllTypes, LinkFromSrc, StylePath};
|
||||||
use crate::clean::types::ExternalLocation;
|
use crate::clean::types::ExternalLocation;
|
||||||
use crate::clean::utils::has_doc_flag;
|
use crate::clean::utils::has_doc_flag;
|
||||||
use crate::clean::{self, ExternalCrate};
|
use crate::clean::{self, ExternalCrate};
|
||||||
use crate::config::{ModuleSorting, RenderOptions};
|
use crate::config::{ModuleSorting, RenderOptions, ShouldMerge};
|
||||||
use crate::docfs::{DocFS, PathError};
|
use crate::docfs::{DocFS, PathError};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
@ -30,6 +29,7 @@
|
|||||||
use crate::html::escape::Escape;
|
use crate::html::escape::Escape;
|
||||||
use crate::html::format::{join_with_double_colon, Buffer};
|
use crate::html::format::{join_with_double_colon, Buffer};
|
||||||
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
|
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
|
||||||
|
use crate::html::render::write_shared::write_shared;
|
||||||
use crate::html::url_parts_builder::UrlPartsBuilder;
|
use crate::html::url_parts_builder::UrlPartsBuilder;
|
||||||
use crate::html::{layout, sources, static_files};
|
use crate::html::{layout, sources, static_files};
|
||||||
use crate::scrape_examples::AllCallLocations;
|
use crate::scrape_examples::AllCallLocations;
|
||||||
@ -128,8 +128,10 @@ pub(crate) struct SharedContext<'tcx> {
|
|||||||
pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
|
pub(crate) span_correspondence_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
|
||||||
/// The [`Cache`] used during rendering.
|
/// The [`Cache`] used during rendering.
|
||||||
pub(crate) cache: Cache,
|
pub(crate) cache: Cache,
|
||||||
|
|
||||||
pub(crate) call_locations: AllCallLocations,
|
pub(crate) call_locations: AllCallLocations,
|
||||||
|
/// Controls whether we read / write to cci files in the doc root. Defaults read=true,
|
||||||
|
/// write=true
|
||||||
|
should_merge: ShouldMerge,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedContext<'_> {
|
impl SharedContext<'_> {
|
||||||
@ -551,6 +553,7 @@ fn init(
|
|||||||
span_correspondence_map: matches,
|
span_correspondence_map: matches,
|
||||||
cache,
|
cache,
|
||||||
call_locations,
|
call_locations,
|
||||||
|
should_merge: options.should_merge,
|
||||||
};
|
};
|
||||||
|
|
||||||
let dst = output;
|
let dst = output;
|
||||||
@ -640,92 +643,96 @@ fn after_krate(&mut self) -> Result<(), Error> {
|
|||||||
);
|
);
|
||||||
shared.fs.write(final_file, v)?;
|
shared.fs.write(final_file, v)?;
|
||||||
|
|
||||||
// Generating settings page.
|
// if to avoid writing help, settings files to doc root unless we're on the final invocation
|
||||||
page.title = "Settings";
|
if shared.should_merge.write_rendered_cci {
|
||||||
page.description = "Settings of Rustdoc";
|
// Generating settings page.
|
||||||
page.root_path = "./";
|
page.title = "Settings";
|
||||||
page.rust_logo = true;
|
page.description = "Settings of Rustdoc";
|
||||||
|
page.root_path = "./";
|
||||||
|
page.rust_logo = true;
|
||||||
|
|
||||||
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
|
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
|
||||||
let v = layout::render(
|
let v = layout::render(
|
||||||
&shared.layout,
|
&shared.layout,
|
||||||
&page,
|
&page,
|
||||||
sidebar,
|
sidebar,
|
||||||
|buf: &mut Buffer| {
|
|buf: &mut Buffer| {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"<div class=\"main-heading\">\
|
"<div class=\"main-heading\">\
|
||||||
<h1>Rustdoc settings</h1>\
|
<h1>Rustdoc settings</h1>\
|
||||||
<span class=\"out-of-band\">\
|
<span class=\"out-of-band\">\
|
||||||
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
||||||
Back\
|
Back\
|
||||||
</a>\
|
</a>\
|
||||||
</span>\
|
</span>\
|
||||||
</div>\
|
</div>\
|
||||||
<noscript>\
|
<noscript>\
|
||||||
<section>\
|
<section>\
|
||||||
You need to enable JavaScript be able to update your settings.\
|
You need to enable JavaScript be able to update your settings.\
|
||||||
</section>\
|
</section>\
|
||||||
</noscript>\
|
</noscript>\
|
||||||
<script defer src=\"{static_root_path}{settings_js}\"></script>",
|
<script defer src=\"{static_root_path}{settings_js}\"></script>",
|
||||||
static_root_path = page.get_static_root_path(),
|
static_root_path = page.get_static_root_path(),
|
||||||
settings_js = static_files::STATIC_FILES.settings_js,
|
settings_js = static_files::STATIC_FILES.settings_js,
|
||||||
);
|
);
|
||||||
// Pre-load all theme CSS files, so that switching feels seamless.
|
// Pre-load all theme CSS files, so that switching feels seamless.
|
||||||
//
|
//
|
||||||
// When loading settings.html as a popover, the equivalent HTML is
|
// When loading settings.html as a popover, the equivalent HTML is
|
||||||
// generated in main.js.
|
// generated in main.js.
|
||||||
for file in &shared.style_files {
|
for file in &shared.style_files {
|
||||||
if let Ok(theme) = file.basename() {
|
if let Ok(theme) = file.basename() {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"<link rel=\"preload\" href=\"{root_path}{theme}{suffix}.css\" \
|
"<link rel=\"preload\" href=\"{root_path}{theme}{suffix}.css\" \
|
||||||
as=\"style\">",
|
as=\"style\">",
|
||||||
root_path = page.static_root_path.unwrap_or(""),
|
root_path = page.static_root_path.unwrap_or(""),
|
||||||
suffix = page.resource_suffix,
|
suffix = page.resource_suffix,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
&shared.style_files,
|
||||||
&shared.style_files,
|
);
|
||||||
);
|
shared.fs.write(settings_file, v)?;
|
||||||
shared.fs.write(settings_file, v)?;
|
|
||||||
|
|
||||||
// Generating help page.
|
// Generating help page.
|
||||||
page.title = "Help";
|
page.title = "Help";
|
||||||
page.description = "Documentation for Rustdoc";
|
page.description = "Documentation for Rustdoc";
|
||||||
page.root_path = "./";
|
page.root_path = "./";
|
||||||
page.rust_logo = true;
|
page.rust_logo = true;
|
||||||
|
|
||||||
let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
|
let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
|
||||||
let v = layout::render(
|
let v = layout::render(
|
||||||
&shared.layout,
|
&shared.layout,
|
||||||
&page,
|
&page,
|
||||||
sidebar,
|
sidebar,
|
||||||
|buf: &mut Buffer| {
|
|buf: &mut Buffer| {
|
||||||
write!(
|
write!(
|
||||||
buf,
|
buf,
|
||||||
"<div class=\"main-heading\">\
|
"<div class=\"main-heading\">\
|
||||||
<h1>Rustdoc help</h1>\
|
<h1>Rustdoc help</h1>\
|
||||||
<span class=\"out-of-band\">\
|
<span class=\"out-of-band\">\
|
||||||
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
|
||||||
Back\
|
Back\
|
||||||
</a>\
|
</a>\
|
||||||
</span>\
|
</span>\
|
||||||
</div>\
|
</div>\
|
||||||
<noscript>\
|
<noscript>\
|
||||||
<section>\
|
<section>\
|
||||||
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
|
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
|
||||||
<p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\
|
<p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\
|
||||||
</section>\
|
</section>\
|
||||||
</noscript>",
|
</noscript>",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
&shared.style_files,
|
&shared.style_files,
|
||||||
);
|
);
|
||||||
shared.fs.write(help_file, v)?;
|
shared.fs.write(help_file, v)?;
|
||||||
|
}
|
||||||
|
|
||||||
if shared.layout.scrape_examples_extension {
|
// if to avoid writing files to doc root unless we're on the final invocation
|
||||||
|
if shared.layout.scrape_examples_extension && shared.should_merge.write_rendered_cci {
|
||||||
page.title = "About scraped examples";
|
page.title = "About scraped examples";
|
||||||
page.description = "How the scraped examples feature works in Rustdoc";
|
page.description = "How the scraped examples feature works in Rustdoc";
|
||||||
let v = layout::render(
|
let v = layout::render(
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
|
|
||||||
pub(crate) use self::context::*;
|
pub(crate) use self::context::*;
|
||||||
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
|
pub(crate) use self::span_map::{collect_spans_and_sources, LinkFromSrc};
|
||||||
|
pub(crate) use self::write_shared::*;
|
||||||
use crate::clean::{self, ItemId, RenderedLink};
|
use crate::clean::{self, ItemId, RenderedLink};
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode};
|
use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode};
|
||||||
use crate::clean::{Crate, Item, ItemId, ItemKind};
|
use crate::clean::{Crate, Item, ItemId, ItemKind};
|
||||||
use crate::config::{EmitType, RenderOptions};
|
use crate::config::{EmitType, PathToParts, RenderOptions, ShouldMerge};
|
||||||
use crate::docfs::PathError;
|
use crate::docfs::PathError;
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use crate::formats::cache::Cache;
|
use crate::formats::cache::Cache;
|
||||||
@ -50,12 +50,11 @@
|
|||||||
use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
|
use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
|
||||||
use crate::html::render::search_index::{build_index, SerializedSearchIndex};
|
use crate::html::render::search_index::{build_index, SerializedSearchIndex};
|
||||||
use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate};
|
use crate::html::render::sorted_template::{self, FileFormat, SortedTemplate};
|
||||||
use crate::html::render::{AssocItemLink, ImplRenderingParameters};
|
use crate::html::render::{AssocItemLink, ImplRenderingParameters, StylePath};
|
||||||
use crate::html::static_files::{self, suffix_path};
|
use crate::html::static_files::{self, suffix_path};
|
||||||
use crate::visit::DocVisitor;
|
use crate::visit::DocVisitor;
|
||||||
use crate::{try_err, try_none};
|
use crate::{try_err, try_none};
|
||||||
|
|
||||||
/// Write cross-crate information files, static files, invocation-specific files, etc. to disk
|
|
||||||
pub(crate) fn write_shared(
|
pub(crate) fn write_shared(
|
||||||
cx: &mut Context<'_>,
|
cx: &mut Context<'_>,
|
||||||
krate: &Crate,
|
krate: &Crate,
|
||||||
@ -70,13 +69,14 @@ pub(crate) fn write_shared(
|
|||||||
|
|
||||||
let SerializedSearchIndex { index, desc } =
|
let SerializedSearchIndex { index, desc } =
|
||||||
build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx);
|
build_index(&krate, &mut Rc::get_mut(&mut cx.shared).unwrap().cache, tcx);
|
||||||
write_search_desc(cx, &krate, &desc)?; // does not need to be merged; written unconditionally
|
write_search_desc(cx, &krate, &desc)?; // does not need to be merged
|
||||||
|
|
||||||
let crate_name = krate.name(cx.tcx());
|
let crate_name = krate.name(cx.tcx());
|
||||||
let crate_name = crate_name.as_str(); // rand
|
let crate_name = crate_name.as_str(); // rand
|
||||||
let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand"
|
let crate_name_json = OrderedJson::serialize(crate_name).unwrap(); // "rand"
|
||||||
let external_crates = hack_get_external_crate_names(&cx.dst, &cx.shared.resource_suffix)?;
|
let external_crates = hack_get_external_crate_names(&cx.dst, &cx.shared.resource_suffix)?;
|
||||||
let info = CrateInfo {
|
let info = CrateInfo {
|
||||||
|
version: CrateInfoVersion::V1,
|
||||||
src_files_js: SourcesPart::get(cx, &crate_name_json)?,
|
src_files_js: SourcesPart::get(cx, &crate_name_json)?,
|
||||||
search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?,
|
search_index_js: SearchIndexPart::get(index, &cx.shared.resource_suffix)?,
|
||||||
all_crates: AllCratesPart::get(crate_name_json.clone(), &cx.shared.resource_suffix)?,
|
all_crates: AllCratesPart::get(crate_name_json.clone(), &cx.shared.resource_suffix)?,
|
||||||
@ -85,47 +85,103 @@ pub(crate) fn write_shared(
|
|||||||
type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?,
|
type_impl: TypeAliasPart::get(cx, krate, &crate_name_json)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let crates = vec![info]; // we have info from just one crate. rest will found in out dir
|
if let Some(parts_out_dir) = &opt.parts_out_dir {
|
||||||
|
create_parents(&parts_out_dir.0)?;
|
||||||
write_static_files(cx, &opt)?;
|
try_err!(
|
||||||
let dst = &cx.dst;
|
fs::write(&parts_out_dir.0, serde_json::to_string(&info).unwrap()),
|
||||||
if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) {
|
&parts_out_dir.0
|
||||||
if cx.include_sources {
|
);
|
||||||
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, &crates)?;
|
|
||||||
}
|
|
||||||
write_rendered_cci::<SearchIndexPart, _>(SearchIndexPart::blank, dst, &crates)?;
|
|
||||||
write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, &crates)?;
|
|
||||||
}
|
}
|
||||||
write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, &crates)?;
|
|
||||||
write_rendered_cci::<TypeAliasPart, _>(TypeAliasPart::blank, dst, &crates)?;
|
let mut crates = CrateInfo::read_many(&opt.include_parts_dir)?;
|
||||||
match &opt.index_page {
|
crates.push(info);
|
||||||
Some(index_page) if opt.enable_index_page => {
|
|
||||||
let mut md_opts = opt.clone();
|
if opt.should_merge.write_rendered_cci {
|
||||||
md_opts.output = cx.dst.clone();
|
write_not_crate_specific(
|
||||||
md_opts.external_html = cx.shared.layout.external_html.clone();
|
&crates,
|
||||||
try_err!(
|
&cx.dst,
|
||||||
crate::markdown::render(&index_page, md_opts, cx.shared.edition()),
|
opt,
|
||||||
&index_page
|
&cx.shared.style_files,
|
||||||
);
|
cx.shared.layout.css_file_extension.as_deref(),
|
||||||
|
&cx.shared.resource_suffix,
|
||||||
|
cx.include_sources,
|
||||||
|
)?;
|
||||||
|
match &opt.index_page {
|
||||||
|
Some(index_page) if opt.enable_index_page => {
|
||||||
|
let mut md_opts = opt.clone();
|
||||||
|
md_opts.output = cx.dst.clone();
|
||||||
|
md_opts.external_html = cx.shared.layout.external_html.clone();
|
||||||
|
try_err!(
|
||||||
|
crate::markdown::render(&index_page, md_opts, cx.shared.edition()),
|
||||||
|
&index_page
|
||||||
|
);
|
||||||
|
}
|
||||||
|
None if opt.enable_index_page => {
|
||||||
|
write_rendered_cci::<CratesIndexPart, _>(
|
||||||
|
|| CratesIndexPart::blank(cx),
|
||||||
|
&cx.dst,
|
||||||
|
&crates,
|
||||||
|
&opt.should_merge,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
_ => {} // they don't want an index page
|
||||||
}
|
}
|
||||||
None if opt.enable_index_page => {
|
|
||||||
write_rendered_cci::<CratesIndexPart, _>(|| CratesIndexPart::blank(cx), dst, &crates)?;
|
|
||||||
}
|
|
||||||
_ => {} // they don't want an index page
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
|
Rc::get_mut(&mut cx.shared).unwrap().fs.set_sync_only(false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the static files, the style files, and the css extensions
|
/// Writes files that are written directly to the `--out-dir`, without the prefix from the current
|
||||||
fn write_static_files(cx: &mut Context<'_>, options: &RenderOptions) -> Result<(), Error> {
|
/// crate. These are the rendered cross-crate files that encode info from multiple crates (e.g.
|
||||||
let static_dir = cx.dst.join("static.files");
|
/// search index), and the static files.
|
||||||
|
pub(crate) fn write_not_crate_specific(
|
||||||
|
crates: &[CrateInfo],
|
||||||
|
dst: &Path,
|
||||||
|
opt: &RenderOptions,
|
||||||
|
style_files: &[StylePath],
|
||||||
|
css_file_extension: Option<&Path>,
|
||||||
|
resource_suffix: &str,
|
||||||
|
include_sources: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
write_rendered_cross_crate_info(crates, dst, opt, include_sources)?;
|
||||||
|
write_static_files(dst, opt, style_files, css_file_extension, resource_suffix)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
cx.shared.fs.create_dir_all(&static_dir).map_err(|e| PathError::new(e, "static.files"))?;
|
fn write_rendered_cross_crate_info(
|
||||||
|
crates: &[CrateInfo],
|
||||||
|
dst: &Path,
|
||||||
|
opt: &RenderOptions,
|
||||||
|
include_sources: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let m = &opt.should_merge;
|
||||||
|
if opt.emit.is_empty() || opt.emit.contains(&EmitType::InvocationSpecific) {
|
||||||
|
if include_sources {
|
||||||
|
write_rendered_cci::<SourcesPart, _>(SourcesPart::blank, dst, &crates, m)?;
|
||||||
|
}
|
||||||
|
write_rendered_cci::<SearchIndexPart, _>(SearchIndexPart::blank, dst, &crates, m)?;
|
||||||
|
write_rendered_cci::<AllCratesPart, _>(AllCratesPart::blank, dst, &crates, m)?;
|
||||||
|
}
|
||||||
|
write_rendered_cci::<TraitAliasPart, _>(TraitAliasPart::blank, dst, &crates, m)?;
|
||||||
|
write_rendered_cci::<TypeAliasPart, _>(TypeAliasPart::blank, dst, &crates, m)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the static files, the style files, and the css extensions.
|
||||||
|
/// Have to be careful about these, because they write to the root out dir.
|
||||||
|
fn write_static_files(
|
||||||
|
dst: &Path,
|
||||||
|
opt: &RenderOptions,
|
||||||
|
style_files: &[StylePath],
|
||||||
|
css_file_extension: Option<&Path>,
|
||||||
|
resource_suffix: &str,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let static_dir = dst.join("static.files");
|
||||||
|
try_err!(fs::create_dir_all(&static_dir), &static_dir);
|
||||||
|
|
||||||
// Handle added third-party themes
|
// Handle added third-party themes
|
||||||
for entry in &cx.shared.style_files {
|
for entry in style_files {
|
||||||
let theme = entry.basename()?;
|
let theme = entry.basename()?;
|
||||||
let extension =
|
let extension =
|
||||||
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
|
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
|
||||||
@ -136,22 +192,24 @@ fn write_static_files(cx: &mut Context<'_>, options: &RenderOptions) -> Result<(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let bytes = try_err!(fs::read(&entry.path), &entry.path);
|
let bytes = try_err!(fs::read(&entry.path), &entry.path);
|
||||||
let filename = format!("{theme}{suffix}.{extension}", suffix = cx.shared.resource_suffix);
|
let filename = format!("{theme}{resource_suffix}.{extension}");
|
||||||
cx.shared.fs.write(cx.dst.join(filename), bytes)?;
|
let dst_filename = dst.join(filename);
|
||||||
|
try_err!(fs::write(&dst_filename, bytes), &dst_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the user adds their own CSS files with --extend-css, we write that as an
|
// When the user adds their own CSS files with --extend-css, we write that as an
|
||||||
// invocation-specific file (that is, with a resource suffix).
|
// invocation-specific file (that is, with a resource suffix).
|
||||||
if let Some(ref css) = cx.shared.layout.css_file_extension {
|
if let Some(css) = css_file_extension {
|
||||||
let buffer = try_err!(fs::read_to_string(css), css);
|
let buffer = try_err!(fs::read_to_string(css), css);
|
||||||
let path = static_files::suffix_path("theme.css", &cx.shared.resource_suffix);
|
let path = static_files::suffix_path("theme.css", resource_suffix);
|
||||||
cx.shared.fs.write(cx.dst.join(path), buffer)?;
|
let dst_path = dst.join(path);
|
||||||
|
try_err!(fs::write(&dst_path, buffer), &dst_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.emit.is_empty() || options.emit.contains(&EmitType::Toolchain) {
|
if opt.emit.is_empty() || opt.emit.contains(&EmitType::Toolchain) {
|
||||||
static_files::for_each(|f: &static_files::StaticFile| {
|
static_files::for_each(|f: &static_files::StaticFile| {
|
||||||
let filename = static_dir.join(f.output_filename());
|
let filename = static_dir.join(f.output_filename());
|
||||||
cx.shared.fs.write(filename, f.minified())
|
fs::write(&filename, f.minified()).map_err(|e| PathError::new(e, &filename))
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +244,8 @@ fn write_search_desc(
|
|||||||
|
|
||||||
/// Contains pre-rendered contents to insert into the CCI template
|
/// Contains pre-rendered contents to insert into the CCI template
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
struct CrateInfo {
|
pub(crate) struct CrateInfo {
|
||||||
|
version: CrateInfoVersion,
|
||||||
src_files_js: PartsAndLocations<SourcesPart>,
|
src_files_js: PartsAndLocations<SourcesPart>,
|
||||||
search_index_js: PartsAndLocations<SearchIndexPart>,
|
search_index_js: PartsAndLocations<SearchIndexPart>,
|
||||||
all_crates: PartsAndLocations<AllCratesPart>,
|
all_crates: PartsAndLocations<AllCratesPart>,
|
||||||
@ -195,6 +254,33 @@ struct CrateInfo {
|
|||||||
type_impl: PartsAndLocations<TypeAliasPart>,
|
type_impl: PartsAndLocations<TypeAliasPart>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl CrateInfo {
|
||||||
|
/// Read all of the crate info from its location on the filesystem
|
||||||
|
pub(crate) fn read_many(parts_paths: &[PathToParts]) -> Result<Vec<Self>, Error> {
|
||||||
|
parts_paths
|
||||||
|
.iter()
|
||||||
|
.map(|parts_path| {
|
||||||
|
let path = &parts_path.0;
|
||||||
|
let parts = try_err!(fs::read(&path), &path);
|
||||||
|
let parts: CrateInfo = try_err!(serde_json::from_slice(&parts), &path);
|
||||||
|
Ok::<_, Error>(parts)
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<CrateInfo>, Error>>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Version for the format of the crate-info file.
|
||||||
|
///
|
||||||
|
/// This enum should only ever have one variant, representing the current version.
|
||||||
|
/// Gives pretty good error message about expecting the current version on deserialize.
|
||||||
|
///
|
||||||
|
/// Must be incremented (V2, V3, etc.) upon any changes to the search index or CrateInfo,
|
||||||
|
/// to provide better diagnostics about including an invalid file.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
enum CrateInfoVersion {
|
||||||
|
V1,
|
||||||
|
}
|
||||||
|
|
||||||
/// Paths (relative to the doc root) and their pre-merge contents
|
/// Paths (relative to the doc root) and their pre-merge contents
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
@ -900,10 +986,14 @@ fn create_parents(path: &Path) -> Result<(), Error> {
|
|||||||
fn read_template_or_blank<F, T: FileFormat>(
|
fn read_template_or_blank<F, T: FileFormat>(
|
||||||
mut make_blank: F,
|
mut make_blank: F,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
|
should_merge: &ShouldMerge,
|
||||||
) -> Result<SortedTemplate<T>, Error>
|
) -> Result<SortedTemplate<T>, Error>
|
||||||
where
|
where
|
||||||
F: FnMut() -> SortedTemplate<T>,
|
F: FnMut() -> SortedTemplate<T>,
|
||||||
{
|
{
|
||||||
|
if !should_merge.read_rendered_cci {
|
||||||
|
return Ok(make_blank());
|
||||||
|
}
|
||||||
match fs::read_to_string(&path) {
|
match fs::read_to_string(&path) {
|
||||||
Ok(template) => Ok(try_err!(SortedTemplate::from_str(&template), &path)),
|
Ok(template) => Ok(try_err!(SortedTemplate::from_str(&template), &path)),
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(make_blank()),
|
Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(make_blank()),
|
||||||
@ -916,6 +1006,7 @@ fn write_rendered_cci<T: CciPart, F>(
|
|||||||
mut make_blank: F,
|
mut make_blank: F,
|
||||||
dst: &Path,
|
dst: &Path,
|
||||||
crates_info: &[CrateInfo],
|
crates_info: &[CrateInfo],
|
||||||
|
should_merge: &ShouldMerge,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
F: FnMut() -> SortedTemplate<T::FileFormat>,
|
F: FnMut() -> SortedTemplate<T::FileFormat>,
|
||||||
@ -924,7 +1015,8 @@ fn write_rendered_cci<T: CciPart, F>(
|
|||||||
for (path, parts) in get_path_parts::<T>(dst, crates_info) {
|
for (path, parts) in get_path_parts::<T>(dst, crates_info) {
|
||||||
create_parents(&path)?;
|
create_parents(&path)?;
|
||||||
// read previous rendered cci from storage, append to them
|
// read previous rendered cci from storage, append to them
|
||||||
let mut template = read_template_or_blank::<_, T::FileFormat>(&mut make_blank, &path)?;
|
let mut template =
|
||||||
|
read_template_or_blank::<_, T::FileFormat>(&mut make_blank, &path, should_merge)?;
|
||||||
for part in parts {
|
for part in parts {
|
||||||
template.append(part);
|
template.append(part);
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::config::ShouldMerge;
|
||||||
use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
|
use crate::html::render::ordered_json::{EscapedJson, OrderedJson};
|
||||||
use crate::html::render::sorted_template::{Html, SortedTemplate};
|
use crate::html::render::sorted_template::{Html, SortedTemplate};
|
||||||
use crate::html::render::write_shared::*;
|
use crate::html::render::write_shared::*;
|
||||||
@ -192,16 +193,17 @@ fn read_template_test() {
|
|||||||
let path = path.path().join("file.html");
|
let path = path.path().join("file.html");
|
||||||
let make_blank = || SortedTemplate::<Html>::from_before_after("<div>", "</div>");
|
let make_blank = || SortedTemplate::<Html>::from_before_after("<div>", "</div>");
|
||||||
|
|
||||||
let template = read_template_or_blank(make_blank, &path).unwrap();
|
let should_merge = ShouldMerge { read_rendered_cci: true, write_rendered_cci: true };
|
||||||
|
let template = read_template_or_blank(make_blank, &path, &should_merge).unwrap();
|
||||||
assert_eq!(but_last_line(&template.to_string()), "<div></div>");
|
assert_eq!(but_last_line(&template.to_string()), "<div></div>");
|
||||||
fs::write(&path, template.to_string()).unwrap();
|
fs::write(&path, template.to_string()).unwrap();
|
||||||
let mut template = read_template_or_blank(make_blank, &path).unwrap();
|
let mut template = read_template_or_blank(make_blank, &path, &should_merge).unwrap();
|
||||||
template.append("<img/>".to_string());
|
template.append("<img/>".to_string());
|
||||||
fs::write(&path, template.to_string()).unwrap();
|
fs::write(&path, template.to_string()).unwrap();
|
||||||
let mut template = read_template_or_blank(make_blank, &path).unwrap();
|
let mut template = read_template_or_blank(make_blank, &path, &should_merge).unwrap();
|
||||||
template.append("<br/>".to_string());
|
template.append("<br/>".to_string());
|
||||||
fs::write(&path, template.to_string()).unwrap();
|
fs::write(&path, template.to_string()).unwrap();
|
||||||
let template = read_template_or_blank(make_blank, &path).unwrap();
|
let template = read_template_or_blank(make_blank, &path, &should_merge).unwrap();
|
||||||
|
|
||||||
assert_eq!(but_last_line(&template.to_string()), "<div><br/><img/></div>");
|
assert_eq!(but_last_line(&template.to_string()), "<div><br/><img/></div>");
|
||||||
}
|
}
|
||||||
|
@ -603,6 +603,33 @@ fn opts() -> Vec<RustcOptGroup> {
|
|||||||
"path to function call information (for displaying examples in the documentation)",
|
"path to function call information (for displaying examples in the documentation)",
|
||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
unstable("merge", |o| {
|
||||||
|
o.optopt(
|
||||||
|
"",
|
||||||
|
"merge",
|
||||||
|
"Controls how rustdoc handles files from previously documented crates in the doc root
|
||||||
|
none = Do not write cross-crate information to the --out-dir
|
||||||
|
shared = Append current crate's info to files found in the --out-dir
|
||||||
|
finalize = Write current crate's info and --include-parts-dir info to the --out-dir, overwriting conflicting files",
|
||||||
|
"none|shared|finalize",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
unstable("parts-out-dir", |o| {
|
||||||
|
o.optopt(
|
||||||
|
"",
|
||||||
|
"parts-out-dir",
|
||||||
|
"Writes trait implementations and other info for the current crate to provided path. Only use with --merge=none",
|
||||||
|
"path/to/doc.parts/<crate-name>",
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
unstable("include-parts-dir", |o| {
|
||||||
|
o.optmulti(
|
||||||
|
"",
|
||||||
|
"include-parts-dir",
|
||||||
|
"Includes trait implementations and other crate info from provided path. Only use with --merge=finalize",
|
||||||
|
"path/to/doc.parts/<crate-name>",
|
||||||
|
)
|
||||||
|
}),
|
||||||
// deprecated / removed options
|
// deprecated / removed options
|
||||||
unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
|
unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
|
||||||
stable("plugin-path", |o| {
|
stable("plugin-path", |o| {
|
||||||
@ -697,6 +724,32 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renders and writes cross-crate info files, like the search index. This function exists so that
|
||||||
|
/// we can run rustdoc without a crate root in the `--merge=finalize` mode. Cross-crate info files
|
||||||
|
/// discovered via `--include-parts-dir` are combined and written to the doc root.
|
||||||
|
fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> {
|
||||||
|
assert!(
|
||||||
|
opt.should_merge.write_rendered_cci,
|
||||||
|
"config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!opt.should_merge.read_rendered_cci,
|
||||||
|
"config.rs only allows us to return InputMode::NoInputMergeFinalize if --merge=finalize"
|
||||||
|
);
|
||||||
|
let crates = html::render::CrateInfo::read_many(&opt.include_parts_dir)?;
|
||||||
|
let include_sources = !opt.html_no_source;
|
||||||
|
html::render::write_not_crate_specific(
|
||||||
|
&crates,
|
||||||
|
&opt.output,
|
||||||
|
&opt,
|
||||||
|
&opt.themes,
|
||||||
|
opt.extension_css.as_deref(),
|
||||||
|
&opt.resource_suffix,
|
||||||
|
include_sources,
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn main_args(
|
fn main_args(
|
||||||
early_dcx: &mut EarlyDiagCtxt,
|
early_dcx: &mut EarlyDiagCtxt,
|
||||||
at_args: &[String],
|
at_args: &[String],
|
||||||
@ -737,6 +790,17 @@ fn main_args(
|
|||||||
core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
|
core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
|
||||||
let dcx = dcx.handle();
|
let dcx = dcx.handle();
|
||||||
|
|
||||||
|
let input = match input {
|
||||||
|
config::InputMode::HasFile(input) => input,
|
||||||
|
config::InputMode::NoInputMergeFinalize => {
|
||||||
|
return wrap_return(
|
||||||
|
dcx,
|
||||||
|
run_merge_finalize(render_options)
|
||||||
|
.map_err(|e| format!("could not write merged cross-crate info: {e}")),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match (options.should_test, config::markdown_input(&input)) {
|
match (options.should_test, config::markdown_input(&input)) {
|
||||||
(true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)),
|
(true, Some(_)) => return wrap_return(dcx, doctest::test_markdown(&input, options)),
|
||||||
(true, None) => return doctest::run(dcx, input, options),
|
(true, None) => return doctest::run(dcx, input, options),
|
||||||
|
@ -172,6 +172,23 @@ Options:
|
|||||||
--scrape-tests Include test code when scraping examples
|
--scrape-tests Include test code when scraping examples
|
||||||
--with-examples path to function call information (for displaying examples in the documentation)
|
--with-examples path to function call information (for displaying examples in the documentation)
|
||||||
|
|
||||||
|
--merge none|shared|finalize
|
||||||
|
Controls how rustdoc handles files from previously
|
||||||
|
documented crates in the doc root
|
||||||
|
none = Do not write cross-crate information to the
|
||||||
|
--out-dir
|
||||||
|
shared = Append current crate's info to files found in
|
||||||
|
the --out-dir
|
||||||
|
finalize = Write current crate's info and
|
||||||
|
--include-parts-dir info to the --out-dir, overwriting
|
||||||
|
conflicting files
|
||||||
|
--parts-out-dir path/to/doc.parts/<crate-name>
|
||||||
|
Writes trait implementations and other info for the
|
||||||
|
current crate to provided path. Only use with
|
||||||
|
--merge=none
|
||||||
|
--include-parts-dir path/to/doc.parts/<crate-name>
|
||||||
|
Includes trait implementations and other crate info
|
||||||
|
from provided path. Only use with --merge=finalize
|
||||||
--disable-minification
|
--disable-minification
|
||||||
removed
|
removed
|
||||||
--plugin-path DIR
|
--plugin-path DIR
|
||||||
|
Loading…
Reference in New Issue
Block a user