Skip to content

Commit 2e1cba6

Browse files
EtomicBombethan
authored andcommitted
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
1 parent 3782251 commit 2e1cba6

7 files changed

Lines changed: 419 additions & 135 deletions

File tree

‎src/librustdoc/config.rs‎

Lines changed: 105 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ impl TryFrom<&str> for OutputFormat {
5353
}
5454
}
5555

56+
/// Either an input crate, markdown file, or nothing (--merge=finalize).
57+
pub(crate)enumInputMode{
58+
/// The `--merge=finalize` step does not need an input crate to rustdoc.
59+
NoInputMergeFinalize,
60+
/// A crate or markdown file.
61+
HasFile(Input),
62+
}
63+
5664
/// Configuration options for rustdoc.
5765
#[derive(Clone)]
5866
pub(crate)structOptions{
@@ -286,6 +294,12 @@ pub(crate) struct RenderOptions {
286294
/// This field is only used for the JSON output. If it's set to true, no file will be created
287295
/// and content will be displayed in stdout directly.
288296
pub(crate)output_to_stdout:bool,
297+
/// Whether we should read or write rendered cross-crate info in the doc root.
298+
pub(crate)should_merge:ShouldMerge,
299+
/// Path to crate-info for external crates.
300+
pub(crate)include_parts_dir:Vec<PathToParts>,
301+
/// Where to write crate-info
302+
pub(crate)parts_out_dir:Option<PathToParts>,
289303
}
290304

291305
#[derive(Copy,Clone,Debug,PartialEq,Eq)]
@@ -345,7 +359,7 @@ impl Options {
345359
early_dcx:&mutEarlyDiagCtxt,
346360
matches:&getopts::Matches,
347361
args:Vec<String>,
348-
) -> Option<(Input,Options,RenderOptions)>{
362+
) -> Option<(InputMode,Options,RenderOptions)>{
349363
// Check for unstable options.
350364
nightly_options::check_nightly_options(early_dcx, matches,&opts());
351365

@@ -475,22 +489,34 @@ impl Options {
475489
let(lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
476490

477491
let input = if describe_lints {
478-
""// dummy, this won't be used
492+
InputMode::HasFile(make_input(early_dcx,""))
479493
}else{
480494
match matches.free.as_slice(){
495+
[]if matches.opt_str("merge").as_deref() == Some("finalize") => {
496+
InputMode::NoInputMergeFinalize
497+
}
481498
[] => dcx.fatal("missing file operand"),
482-
[input] => input,
499+
[input] => InputMode::HasFile(make_input(early_dcx,input)),
483500
_ => dcx.fatal("too many file operands"),
484501
}
485502
};
486-
let input = make_input(early_dcx, input);
487503

488504
let externs = parse_externs(early_dcx, matches,&unstable_opts);
489505
let extern_html_root_urls = matchparse_extern_html_roots(matches){
490506
Ok(ex) => ex,
491507
Err(err) => dcx.fatal(err),
492508
};
493509

510+
let parts_out_dir =
511+
match matches.opt_str("parts-out-dir").map(|p| PathToParts::from_flag(p)).transpose(){
512+
Ok(parts_out_dir) => parts_out_dir,
513+
Err(e) => dcx.fatal(e),
514+
};
515+
let include_parts_dir = matchparse_include_parts_dir(matches){
516+
Ok(include_parts_dir) => include_parts_dir,
517+
Err(e) => dcx.fatal(e),
518+
};
519+
494520
let default_settings:Vec<Vec<(String,String)>> = vec![
495521
matches
496522
.opt_str("default-theme")
@@ -732,6 +758,10 @@ impl Options {
732758
let extern_html_root_takes_precedence =
733759
matches.opt_present("extern-html-root-takes-precedence");
734760
let html_no_source = matches.opt_present("html-no-source");
761+
let should_merge = matchparse_merge(matches){
762+
Ok(result) => result,
763+
Err(e) => dcx.fatal(format!("--merge option error: {e}")),
764+
};
735765

736766
if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html){
737767
dcx.struct_warn(
@@ -819,6 +849,9 @@ impl Options {
819849
no_emit_shared:false,
820850
html_no_source,
821851
output_to_stdout,
852+
should_merge,
853+
include_parts_dir,
854+
parts_out_dir,
822855
};
823856
Some((input, options, render_options))
824857
}
@@ -894,3 +927,71 @@ fn parse_extern_html_roots(
894927
}
895928
Ok(externs)
896929
}
930+
931+
/// Path directly to crate-info file.
932+
///
933+
/// For example, `/home/user/project/target/doc.parts/<crate>/crate-info`.
934+
#[derive(Clone,Debug)]
935+
pub(crate)structPathToParts(pub(crate)PathBuf);
936+
937+
implPathToParts{
938+
fnfrom_flag(path:String) -> Result<PathToParts,String>{
939+
letmut path = PathBuf::from(path);
940+
// check here is for diagnostics
941+
if path.exists() && !path.is_dir(){
942+
Err(format!(
943+
"--parts-out-dir and --include-parts-dir expect directories, found: {}",
944+
path.display(),
945+
))
946+
}else{
947+
// if it doesn't exist, we'll create it. worry about that in write_shared
948+
path.push("crate-info");
949+
Ok(PathToParts(path))
950+
}
951+
}
952+
}
953+
954+
/// Reports error if --include-parts-dir / crate-info is not a file
955+
fnparse_include_parts_dir(m:&getopts::Matches) -> Result<Vec<PathToParts>,String>{
956+
letmut ret = Vec::new();
957+
for p in m.opt_strs("include-parts-dir"){
958+
let p = PathToParts::from_flag(p)?;
959+
// this is just for diagnostic
960+
if !p.0.is_file(){
961+
returnErr(format!("--include-parts-dir expected {} to be a file", p.0.display()));
962+
}
963+
ret.push(p);
964+
}
965+
Ok(ret)
966+
}
967+
968+
/// Controls merging of cross-crate information
969+
#[derive(Debug,Clone)]
970+
pub(crate)structShouldMerge{
971+
/// Should we append to existing cci in the doc root
972+
pub(crate)read_rendered_cci:bool,
973+
/// Should we write cci to the doc root
974+
pub(crate)write_rendered_cci:bool,
975+
}
976+
977+
/// Extracts read_rendered_cci and write_rendered_cci from command line arguments, or
978+
/// reports an error if an invalid option was provided
979+
fnparse_merge(m:&getopts::Matches) -> Result<ShouldMerge,&'staticstr>{
980+
match m.opt_str("merge").as_deref(){
981+
// default = read-write
982+
None => Ok(ShouldMerge{read_rendered_cci:true,write_rendered_cci:true}),
983+
Some("none")if m.opt_present("include-parts-dir") => {
984+
Err("--include-parts-dir not allowed if --merge=none")
985+
}
986+
Some("none") => Ok(ShouldMerge{read_rendered_cci:false,write_rendered_cci:false}),
987+
Some("shared")if m.opt_present("parts-out-dir") || m.opt_present("include-parts-dir") => {
988+
Err("--parts-out-dir and --include-parts-dir not allowed if --merge=shared")
989+
}
990+
Some("shared") => Ok(ShouldMerge{read_rendered_cci:true,write_rendered_cci:true}),
991+
Some("finalize")if m.opt_present("parts-out-dir") => {
992+
Err("--parts-out-dir not allowed if --merge=finalize")
993+
}
994+
Some("finalize") => Ok(ShouldMerge{read_rendered_cci:false,write_rendered_cci:true}),
995+
Some(_) => Err("argument to --merge must be `none`, `shared`, or `finalize`"),
996+
}
997+
}

‎src/librustdoc/html/render/context.rs‎

Lines changed: 91 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ use tracing::info;
1616

1717
usesuper::print_item::{full_path, item_path, print_item};
1818
usesuper::sidebar::{print_sidebar, sidebar_module_like,ModuleLike,Sidebar};
19-
usesuper::write_shared::write_shared;
2019
usesuper::{collect_spans_and_sources, scrape_examples_help,AllTypes,LinkFromSrc,StylePath};
2120
usecrate::clean::types::ExternalLocation;
2221
usecrate::clean::utils::has_doc_flag;
2322
usecrate::clean::{self,ExternalCrate};
24-
usecrate::config::{ModuleSorting,RenderOptions};
23+
usecrate::config::{ModuleSorting,RenderOptions,ShouldMerge};
2524
usecrate::docfs::{DocFS,PathError};
2625
usecrate::error::Error;
2726
usecrate::formats::cache::Cache;
@@ -30,6 +29,7 @@ use crate::formats::FormatRenderer;
3029
usecrate::html::escape::Escape;
3130
usecrate::html::format::{join_with_double_colon,Buffer};
3231
usecrate::html::markdown::{self, plain_text_summary,ErrorCodes,IdMap};
32+
usecrate::html::render::write_shared::write_shared;
3333
usecrate::html::url_parts_builder::UrlPartsBuilder;
3434
usecrate::html::{layout, sources, static_files};
3535
usecrate::scrape_examples::AllCallLocations;
@@ -128,8 +128,10 @@ pub(crate) struct SharedContext<'tcx> {
128128
pub(crate)span_correspondence_map:FxHashMap<rustc_span::Span,LinkFromSrc>,
129129
/// The [`Cache`] used during rendering.
130130
pub(crate)cache:Cache,
131-
132131
pub(crate)call_locations:AllCallLocations,
132+
/// Controls whether we read / write to cci files in the doc root. Defaults read=true,
133+
/// write=true
134+
should_merge:ShouldMerge,
133135
}
134136

135137
implSharedContext<'_>{
@@ -551,6 +553,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
551553
span_correspondence_map: matches,
552554
cache,
553555
call_locations,
556+
should_merge: options.should_merge,
554557
};
555558

556559
let dst = output;
@@ -640,92 +643,96 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
640643
);
641644
shared.fs.write(final_file, v)?;
642645

643-
// Generating settings page.
644-
page.title = "Settings";
645-
page.description = "Settings of Rustdoc";
646-
page.root_path = "./";
647-
page.rust_logo = true;
646+
// if to avoid writing help, settings files to doc root unless we're on the final invocation
647+
if shared.should_merge.write_rendered_cci{
648+
// Generating settings page.
649+
page.title = "Settings";
650+
page.description = "Settings of Rustdoc";
651+
page.root_path = "./";
652+
page.rust_logo = true;
648653

649-
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
650-
let v = layout::render(
651-
&shared.layout,
652-
&page,
653-
sidebar,
654-
|buf:&mutBuffer| {
655-
write!(
656-
buf,
657-
"<div class=\"main-heading\">\
658-
<h1>Rustdoc settings</h1>\
659-
<span class=\"out-of-band\">\
660-
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
661-
Back\
662-
</a>\
663-
</span>\
664-
</div>\
665-
<noscript>\
666-
<section>\
667-
You need to enable JavaScript be able to update your settings.\
668-
</section>\
669-
</noscript>\
670-
<script defer src=\"{static_root_path}{settings_js}\"></script>",
671-
static_root_path = page.get_static_root_path(),
672-
settings_js = static_files::STATIC_FILES.settings_js,
673-
);
674-
// Pre-load all theme CSS files, so that switching feels seamless.
675-
//
676-
// When loading settings.html as a popover, the equivalent HTML is
677-
// generated in main.js.
678-
for file in&shared.style_files{
679-
ifletOk(theme) = file.basename(){
680-
write!(
681-
buf,
682-
"<link rel=\"preload\" href=\"{root_path}{theme}{suffix}.css\"\
683-
as=\"style\">",
684-
root_path = page.static_root_path.unwrap_or(""),
685-
suffix = page.resource_suffix,
686-
);
654+
let sidebar = "<h2 class=\"location\">Settings</h2><div class=\"sidebar-elems\"></div>";
655+
let v = layout::render(
656+
&shared.layout,
657+
&page,
658+
sidebar,
659+
|buf:&mutBuffer| {
660+
write!(
661+
buf,
662+
"<div class=\"main-heading\">\
663+
<h1>Rustdoc settings</h1>\
664+
<span class=\"out-of-band\">\
665+
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
666+
Back\
667+
</a>\
668+
</span>\
669+
</div>\
670+
<noscript>\
671+
<section>\
672+
You need to enable JavaScript be able to update your settings.\
673+
</section>\
674+
</noscript>\
675+
<script defer src=\"{static_root_path}{settings_js}\"></script>",
676+
static_root_path = page.get_static_root_path(),
677+
settings_js = static_files::STATIC_FILES.settings_js,
678+
);
679+
// Pre-load all theme CSS files, so that switching feels seamless.
680+
//
681+
// When loading settings.html as a popover, the equivalent HTML is
682+
// generated in main.js.
683+
for file in&shared.style_files{
684+
ifletOk(theme) = file.basename(){
685+
write!(
686+
buf,
687+
"<link rel=\"preload\" href=\"{root_path}{theme}{suffix}.css\"\
688+
as=\"style\">",
689+
root_path = page.static_root_path.unwrap_or(""),
690+
suffix = page.resource_suffix,
691+
);
692+
}
687693
}
688-
}
689-
},
690-
&shared.style_files,
691-
);
692-
shared.fs.write(settings_file, v)?;
694+
},
695+
&shared.style_files,
696+
);
697+
shared.fs.write(settings_file, v)?;
693698

694-
// Generating help page.
695-
page.title = "Help";
696-
page.description = "Documentation for Rustdoc";
697-
page.root_path = "./";
698-
page.rust_logo = true;
699+
// Generating help page.
700+
page.title = "Help";
701+
page.description = "Documentation for Rustdoc";
702+
page.root_path = "./";
703+
page.rust_logo = true;
699704

700-
let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
701-
let v = layout::render(
702-
&shared.layout,
703-
&page,
704-
sidebar,
705-
|buf:&mutBuffer| {
706-
write!(
707-
buf,
708-
"<div class=\"main-heading\">\
709-
<h1>Rustdoc help</h1>\
710-
<span class=\"out-of-band\">\
711-
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
712-
Back\
713-
</a>\
714-
</span>\
715-
</div>\
716-
<noscript>\
717-
<section>\
718-
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
719-
<p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\
720-
</section>\
721-
</noscript>",
722-
)
723-
},
724-
&shared.style_files,
725-
);
726-
shared.fs.write(help_file, v)?;
705+
let sidebar = "<h2 class=\"location\">Help</h2><div class=\"sidebar-elems\"></div>";
706+
let v = layout::render(
707+
&shared.layout,
708+
&page,
709+
sidebar,
710+
|buf:&mutBuffer| {
711+
write!(
712+
buf,
713+
"<div class=\"main-heading\">\
714+
<h1>Rustdoc help</h1>\
715+
<span class=\"out-of-band\">\
716+
<a id=\"back\" href=\"javascript:void(0)\" onclick=\"history.back();\">\
717+
Back\
718+
</a>\
719+
</span>\
720+
</div>\
721+
<noscript>\
722+
<section>\
723+
<p>You need to enable JavaScript to use keyboard commands or search.</p>\
724+
<p>For more information, browse the <a href=\"https://doc.rust-lang.org/rustdoc/\">rustdoc handbook</a>.</p>\
725+
</section>\
726+
</noscript>",
727+
)
728+
},
729+
&shared.style_files,
730+
);
731+
shared.fs.write(help_file, v)?;
732+
}
727733

728-
if shared.layout.scrape_examples_extension{
734+
// if to avoid writing files to doc root unless we're on the final invocation
735+
if shared.layout.scrape_examples_extension && shared.should_merge.write_rendered_cci{
729736
page.title = "About scraped examples";
730737
page.description = "How the scraped examples feature works in Rustdoc";
731738
let v = layout::render(

‎src/librustdoc/html/render/mod.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use tracing::{debug, info};
6161

6262
pub(crate)useself::context::*;
6363
pub(crate)useself::span_map::{collect_spans_and_sources,LinkFromSrc};
64+
pub(crate)useself::write_shared::*;
6465
usecrate::clean::{self,ItemId,RenderedLink};
6566
usecrate::error::Error;
6667
usecrate::formats::cache::Cache;

0 commit comments

Comments
 (0)