Skip to content

Commit 2855bf0

Browse files
committed
Factor scraping and rendering into separate calls to rustdoc
Simplify toggle UI logic, add workspace root for URLs
1 parent 7831fee commit 2855bf0

File tree

8 files changed

+143
-158
lines changed

8 files changed

+143
-158
lines changed

src/librustdoc/clean/types.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ use crate::formats::cache::Cache;
4242
use crate::formats::item_type::ItemType;
4343
use crate::html::render::cache::ExternalLocation;
4444
use crate::html::render::Context;
45-
use crate::scrape_examples::FnCallLocations;
45+
use crate::scrape_examples::{self, FnCallLocations};
4646

4747
use self::FnRetTy::*;
4848
use self::ItemKind::*;
@@ -1261,9 +1261,9 @@ crate struct Function {
12611261
impl Function {
12621262
crate fn load_call_locations(&mut self, def_id: hir::def_id::DefId, cx: &DocContext<'_>) {
12631263
if let Some(call_locations) = cx.render_options.call_locations.as_ref() {
1264-
let key = cx.tcx.def_path(def_id).to_string_no_crate_verbose();
1264+
let key = scrape_examples::def_id_call_key(cx.tcx, def_id);
12651265
self.call_locations = call_locations.get(&key).cloned();
1266-
debug!("call_locations: {} -- {:?}", key, self.call_locations);
1266+
debug!("call_locations: {:?} -- {:?}", key, self.call_locations);
12671267
}
12681268
}
12691269
}

src/librustdoc/config.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::BTreeMap;
22
use std::convert::TryFrom;
33
use std::ffi::OsStr;
44
use std::fmt;
5+
use std::fs;
56
use std::path::PathBuf;
67
use std::str::FromStr;
78

@@ -160,7 +161,12 @@ crate struct Options {
160161
/// Whether to skip capturing stdout and stderr of tests.
161162
crate nocapture: bool,
162163

163-
crate scrape_examples: Vec<String>,
164+
// Options for scraping call sites from examples/ directory
165+
/// Path to output file to write JSON of call sites. If this option is Some(..) then
166+
/// the compiler will scrape examples and not generate documentation.
167+
crate scrape_examples: Option<PathBuf>,
168+
/// Path to the root of the workspace, used to generate workspace-relative file paths.
169+
crate workspace_root: Option<PathBuf>,
164170
}
165171

166172
impl fmt::Debug for Options {
@@ -677,7 +683,32 @@ impl Options {
677683
}
678684

679685
let repository_url = matches.opt_str("repository-url");
680-
let scrape_examples = matches.opt_strs("scrape-examples");
686+
let scrape_examples = matches.opt_str("scrape-examples").map(PathBuf::from);
687+
let workspace_root = matches.opt_str("workspace-root").map(PathBuf::from);
688+
let with_examples = matches.opt_strs("with-examples");
689+
let each_call_locations = with_examples
690+
.into_iter()
691+
.map(|path| {
692+
let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
693+
let calls: AllCallLocations =
694+
serde_json::from_slice(&bytes).map_err(|e| format!("{}", e))?;
695+
Ok(calls)
696+
})
697+
.collect::<Result<Vec<_>, _>>()
698+
.map_err(|e: String| {
699+
diag.err(&format!("failed to load examples with error: {}", e));
700+
1
701+
})?;
702+
let call_locations = (each_call_locations.len() > 0).then(move || {
703+
each_call_locations.into_iter().fold(FxHashMap::default(), |mut acc, map| {
704+
for (function, calls) in map.into_iter() {
705+
acc.entry(function)
706+
.or_insert_with(FxHashMap::default)
707+
.extend(calls.into_iter());
708+
}
709+
acc
710+
})
711+
});
681712

682713
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
683714

@@ -745,13 +776,14 @@ impl Options {
745776
),
746777
emit,
747778
generate_link_to_definition,
748-
call_locations: None,
779+
call_locations,
749780
repository_url,
750781
},
751782
crate_name,
752783
output_format,
753784
json_unused_externs,
754785
scrape_examples,
786+
workspace_root,
755787
})
756788
}
757789

src/librustdoc/doctest.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ crate struct TestOptions {
4545
crate attrs: Vec<String>,
4646
}
4747

48-
crate fn run(options: Options) -> Result<(), ErrorReported> {
48+
crate fn make_rustc_config(options: &Options) -> interface::Config {
4949
let input = config::Input::File(options.input.clone());
5050

5151
let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
@@ -87,7 +87,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
8787
let mut cfgs = options.cfgs.clone();
8888
cfgs.push("doc".to_owned());
8989
cfgs.push("doctest".to_owned());
90-
let config = interface::Config {
90+
interface::Config {
9191
opts: sessopts,
9292
crate_cfg: interface::parse_cfgspecs(cfgs),
9393
input,
@@ -103,7 +103,11 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
103103
override_queries: None,
104104
make_codegen_backend: None,
105105
registry: rustc_driver::diagnostics_registry(),
106-
};
106+
}
107+
}
108+
109+
crate fn run(options: Options) -> Result<(), ErrorReported> {
110+
let config = make_rustc_config(&options);
107111

108112
let test_args = options.test_args.clone();
109113
let display_doctest_warnings = options.display_doctest_warnings;

src/librustdoc/html/render/mod.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2528,9 +2528,16 @@ fn render_call_locations(
25282528
write_example(w, it.next().unwrap());
25292529

25302530
if n_examples > 1 {
2531-
write!(w, r#"<div class="more-scraped-examples hidden">"#);
2531+
write!(
2532+
w,
2533+
r#"<details class="rustdoc-toggle more-examples-toggle">
2534+
<summary class="hideme">
2535+
<span>More examples</span>
2536+
</summary>
2537+
<div class="more-scraped-examples">"#
2538+
);
25322539
it.for_each(|ex| write_example(w, ex));
2533-
write!(w, "</div>");
2540+
write!(w, "</div></details>");
25342541
}
25352542

25362543
write!(w, "</div>");

src/librustdoc/html/static/css/rustdoc.css

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,15 +2066,12 @@ details.undocumented[open] > summary::before {
20662066
background: #f6fdb0;
20672067
}
20682068

2069+
.more-examples-toggle summary {
2070+
color: #999;
2071+
}
2072+
20692073
.more-scraped-examples {
20702074
padding-left: 10px;
20712075
border-left: 1px solid #ccc;
2072-
}
2073-
2074-
.toggle-examples .collapse-toggle {
2075-
position: relative;
2076-
}
2077-
2078-
.toggle-examples a {
2079-
color: #999 !important; // FIXME(wcrichto): why is important needed
2076+
margin-left: 24px;
20802077
}

src/librustdoc/html/static/js/main.js

Lines changed: 11 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,54 +1136,21 @@ function hideThemeButtonState() {
11361136
}
11371137

11381138
function updateScrapedExamples() {
1139-
onEach(document.getElementsByClassName('scraped-example-list'), function (exampleSet) {
1140-
updateScrapedExample(
1141-
exampleSet.querySelector(".small-section-header + .scraped-example")
1142-
);
1143-
});
1144-
1145-
onEach(document.getElementsByClassName("more-scraped-examples"), function (more) {
1146-
var toggle = createSimpleToggle(true);
1147-
var label = "More examples";
1148-
var wrapper = createToggle(toggle, label, 14, "toggle-examples", false);
1149-
more.parentNode.insertBefore(wrapper, more);
1150-
var examples_init = false;
1151-
1152-
// Show additional examples on click
1153-
wrapper.onclick = function () {
1154-
if (hasClass(this, "collapsed")) {
1155-
removeClass(this, "collapsed");
1156-
onEachLazy(this.parentNode.getElementsByClassName("hidden"), function (x) {
1157-
if (hasClass(x, "content") === false) {
1158-
removeClass(x, "hidden");
1159-
addClass(x, "x")
1160-
}
1161-
}, true);
1162-
this.querySelector('.toggle-label').innerHTML = "Hide examples";
1163-
this.querySelector('.inner').innerHTML = labelForToggleButton(false);
1164-
if (!examples_init) {
1165-
examples_init = true;
1166-
onEach(more.getElementsByClassName('scraped-example'),
1167-
updateScrapedExample);
1168-
}
1169-
} else {
1170-
addClass(this, "collapsed");
1171-
onEachLazy(this.parentNode.getElementsByClassName("x"), function (x) {
1172-
if (hasClass(x, "content") === false) {
1173-
addClass(x, "hidden");
1174-
removeClass(x, "x")
1175-
}
1176-
}, true);
1177-
this.querySelector('.toggle-label').innerHTML = label;
1178-
this.querySelector('.inner').innerHTML = labelForToggleButton(true);
1179-
}
1180-
};
1139+
var firstExamples = document.querySelectorAll('.scraped-example-list > .scraped-example');
1140+
onEach(firstExamples, updateScrapedExample);
1141+
onEach(document.querySelectorAll('.more-examples-toggle'), function(toggle) {
1142+
var moreExamples = toggle.querySelectorAll('.scraped-example');
1143+
toggle.querySelector('summary').addEventListener('click', function() {
1144+
// Wrapping in setTimeout ensures the update happens after the elements are actually
1145+
// visible. This is necessary since updateScrapedExample calls scrollToLoc which
1146+
// depends on offsetHeight, a property that requires an element to be visible to
1147+
// compute correctly.
1148+
setTimeout(function() { onEach(moreExamples, updateScrapedExample); });
1149+
}, {once: true});
11811150
});
11821151
}
11831152

1184-
var start = Date.now();
11851153
updateScrapedExamples();
1186-
console.log("updated examples took", Date.now() - start, "ms");
11871154
}());
11881155

11891156
(function () {

src/librustdoc/lib.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,10 @@ fn opts() -> Vec<RustcOptGroup> {
619619
"Make the identifiers in the HTML source code pages navigable",
620620
)
621621
}),
622-
unstable("scrape-examples", |o| o.optmulti("", "scrape-examples", "", "")),
622+
unstable("scrape-examples", |o| o.optopt("", "scrape-examples", "", "")),
623+
unstable("workspace-root", |o| o.optopt("", "workspace-root", "", "")),
623624
unstable("repository-url", |o| o.optopt("", "repository-url", "", "")),
625+
unstable("with-examples", |o| o.optmulti("", "with-examples", "", "")),
624626
]
625627
}
626628

@@ -700,28 +702,20 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
700702
}
701703
}
702704

703-
fn main_options(mut options: config::Options) -> MainResult {
705+
fn main_options(options: config::Options) -> MainResult {
704706
let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
705707

706-
match (options.should_test, options.markdown_input()) {
707-
(true, true) => return wrap_return(&diag, markdown::test(options)),
708-
(true, false) => return doctest::run(options),
709-
(false, true) => {
708+
match (options.should_test, options.markdown_input(), options.scrape_examples.is_some()) {
709+
(_, _, true) => return scrape_examples::run(options),
710+
(true, true, false) => return wrap_return(&diag, markdown::test(options)),
711+
(true, false, false) => return doctest::run(options),
712+
(false, true, false) => {
710713
return wrap_return(
711714
&diag,
712715
markdown::render(&options.input, options.render_options, options.edition),
713716
);
714717
}
715-
(false, false) => {}
716-
}
717-
718-
if options.scrape_examples.len() > 0 {
719-
if let Some(crate_name) = &options.crate_name {
720-
options.render_options.call_locations =
721-
Some(scrape_examples::scrape(&options.scrape_examples, crate_name)?);
722-
} else {
723-
// raise an error?
724-
}
718+
(false, false, false) => {}
725719
}
726720

727721
// need to move these items separately because we lose them by the time the closure is called,

0 commit comments

Comments
 (0)