Skip to content

Commit b6338e7

Browse files
committed
Generate example source files with corresponding links
Add display name Fix remaining merge conflicts Only embed code for items containing examples
1 parent 2855bf0 commit b6338e7

File tree

7 files changed

+160
-108
lines changed

7 files changed

+160
-108
lines changed

src/librustdoc/config.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,9 @@ crate struct Options {
161161
/// Whether to skip capturing stdout and stderr of tests.
162162
crate nocapture: bool,
163163

164-
// Options for scraping call sites from examples/ directory
165164
/// Path to output file to write JSON of call sites. If this option is Some(..) then
166165
/// the compiler will scrape examples and not generate documentation.
167166
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>,
170167
}
171168

172169
impl fmt::Debug for Options {
@@ -290,7 +287,6 @@ crate struct RenderOptions {
290287
/// If `true`, HTML source pages will generate links for items to their definition.
291288
crate generate_link_to_definition: bool,
292289
crate call_locations: Option<AllCallLocations>,
293-
crate repository_url: Option<String>,
294290
}
295291

296292
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -682,9 +678,7 @@ impl Options {
682678
return Err(1);
683679
}
684680

685-
let repository_url = matches.opt_str("repository-url");
686681
let scrape_examples = matches.opt_str("scrape-examples").map(PathBuf::from);
687-
let workspace_root = matches.opt_str("workspace-root").map(PathBuf::from);
688682
let with_examples = matches.opt_strs("with-examples");
689683
let each_call_locations = with_examples
690684
.into_iter()
@@ -777,13 +771,11 @@ impl Options {
777771
emit,
778772
generate_link_to_definition,
779773
call_locations,
780-
repository_url,
781774
},
782775
crate_name,
783776
output_format,
784777
json_unused_externs,
785778
scrape_examples,
786-
workspace_root,
787779
})
788780
}
789781

src/librustdoc/html/render/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,7 @@ impl<'tcx> Context<'tcx> {
351351
let hiline = span.hi(self.sess()).line;
352352
let lines =
353353
if loline == hiline { loline.to_string() } else { format!("{}-{}", loline, hiline) };
354+
354355
Some(format!(
355356
"{root}src/{krate}/{path}#{lines}",
356357
root = Escape(&root),

src/librustdoc/html/render/mod.rs

Lines changed: 50 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ use crate::html::format::{
7070
};
7171
use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
7272
use crate::html::sources;
73-
use crate::scrape_examples::FnCallLocations;
73+
use crate::scrape_examples::{CallData, FnCallLocations};
7474

7575
/// A pair of name and its optional document.
7676
crate type NameDoc = (String, Option<String>);
@@ -2451,6 +2451,8 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
24512451
out
24522452
}
24532453

2454+
const MAX_FULL_EXAMPLES: usize = 5;
2455+
24542456
fn render_call_locations(
24552457
w: &mut Buffer,
24562458
cx: &Context<'_>,
@@ -2463,29 +2465,7 @@ fn render_call_locations(
24632465
}
24642466
};
24652467

2466-
let filtered_locations: Vec<_> = call_locations
2467-
.iter()
2468-
.filter_map(|(file, locs)| {
2469-
// FIXME(wcrichto): file I/O should be cached
2470-
let mut contents = match fs::read_to_string(&file) {
2471-
Ok(contents) => contents,
2472-
Err(e) => {
2473-
eprintln!("Failed to read file {}", e);
2474-
return None;
2475-
}
2476-
};
2477-
2478-
// Remove the utf-8 BOM if any
2479-
if contents.starts_with('\u{feff}') {
2480-
contents.drain(..3);
2481-
}
2482-
2483-
Some((file, contents, locs))
2484-
})
2485-
.collect();
2486-
2487-
let n_examples = filtered_locations.len();
2488-
if n_examples == 0 {
2468+
if call_locations.len() == 0 {
24892469
return;
24902470
}
24912471

@@ -2499,35 +2479,55 @@ fn render_call_locations(
24992479
id
25002480
);
25012481

2502-
let write_example = |w: &mut Buffer, (file, contents, locs): (&String, String, _)| {
2503-
let ex_title = match cx.shared.repository_url.as_ref() {
2504-
Some(url) => format!(
2505-
r#"<a href="{url}/{file}" target="_blank">{file}</a>"#,
2506-
file = file,
2507-
url = url
2508-
),
2509-
None => file.clone(),
2510-
};
2482+
let example_url = |call_data: &CallData| -> String {
2483+
format!(
2484+
r#"<a href="{root}{url}" target="_blank">{name}</a>"#,
2485+
root = cx.root_path(),
2486+
url = call_data.url,
2487+
name = call_data.display_name
2488+
)
2489+
};
2490+
2491+
let write_example = |w: &mut Buffer, (path, call_data): (&PathBuf, &CallData)| {
2492+
let mut contents =
2493+
fs::read_to_string(&path).expect(&format!("Failed to read file: {}", path.display()));
2494+
2495+
let min_loc =
2496+
call_data.locations.iter().min_by_key(|loc| loc.enclosing_item_span.0).unwrap();
2497+
let min_byte = min_loc.enclosing_item_span.0;
2498+
let min_line = min_loc.enclosing_item_lines.0;
2499+
let max_byte =
2500+
call_data.locations.iter().map(|loc| loc.enclosing_item_span.1).max().unwrap();
2501+
contents = contents[min_byte..max_byte].to_string();
2502+
2503+
let locations = call_data
2504+
.locations
2505+
.iter()
2506+
.map(|loc| (loc.call_span.0 - min_byte, loc.call_span.1 - min_byte))
2507+
.collect::<Vec<_>>();
2508+
25112509
let edition = cx.shared.edition();
25122510
write!(
25132511
w,
25142512
r#"<div class="scraped-example" data-code="{code}" data-locs="{locations}">
2515-
<strong>{title}</strong>
2516-
<div class="code-wrapper">"#,
2513+
<strong>{title}</strong>
2514+
<div class="code-wrapper">"#,
25172515
code = contents.replace("\"", "&quot;"),
2518-
locations = serde_json::to_string(&locs).unwrap(),
2519-
title = ex_title,
2516+
locations = serde_json::to_string(&locations).unwrap(),
2517+
title = example_url(call_data),
25202518
);
25212519
write!(w, r#"<span class="prev">&pr;</span> <span class="next">&sc;</span>"#);
25222520
write!(w, r#"<span class="expand">&varr;</span>"#);
2523-
sources::print_src(w, &contents, edition);
2521+
let file_span = rustc_span::DUMMY_SP;
2522+
let root_path = "".to_string();
2523+
sources::print_src(w, &contents, edition, file_span, cx, &root_path, Some(min_line));
25242524
write!(w, "</div></div>");
25252525
};
25262526

2527-
let mut it = filtered_locations.into_iter();
2527+
let mut it = call_locations.into_iter().peekable();
25282528
write_example(w, it.next().unwrap());
25292529

2530-
if n_examples > 1 {
2530+
if it.peek().is_some() {
25312531
write!(
25322532
w,
25332533
r#"<details class="rustdoc-toggle more-examples-toggle">
@@ -2536,7 +2536,16 @@ fn render_call_locations(
25362536
</summary>
25372537
<div class="more-scraped-examples">"#
25382538
);
2539-
it.for_each(|ex| write_example(w, ex));
2539+
(&mut it).take(MAX_FULL_EXAMPLES).for_each(|ex| write_example(w, ex));
2540+
2541+
if it.peek().is_some() {
2542+
write!(w, "Additional examples can be found in:<br /><ul>");
2543+
it.for_each(|(_, call_data)| {
2544+
write!(w, "<li>{}</li>", example_url(call_data));
2545+
});
2546+
write!(w, "</ul>");
2547+
}
2548+
25402549
write!(w, "</div></details>");
25412550
}
25422551

src/librustdoc/html/sources.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,15 @@ impl SourceCollector<'_, 'tcx> {
204204
&page,
205205
"",
206206
|buf: &mut _| {
207-
print_src(buf, contents, self.cx.shared.edition(), file_span, &self.cx, &root_path)
207+
print_src(
208+
buf,
209+
contents,
210+
self.cx.shared.edition(),
211+
file_span,
212+
&self.cx,
213+
&root_path,
214+
None,
215+
)
208216
},
209217
&self.cx.shared.style_files,
210218
);
@@ -250,6 +258,7 @@ crate fn print_src(
250258
file_span: rustc_span::Span,
251259
context: &Context<'_>,
252260
root_path: &str,
261+
offset: Option<usize>,
253262
) {
254263
let lines = s.lines().count();
255264
let mut line_numbers = Buffer::empty_from(buf);
@@ -260,8 +269,9 @@ crate fn print_src(
260269
tmp /= 10;
261270
}
262271
line_numbers.write_str("<pre class=\"line-numbers\">");
272+
let offset = offset.unwrap_or(0);
263273
for i in 1..=lines {
264-
writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i, cols);
274+
writeln!(line_numbers, "<span id=\"{0}\">{0:1$}</span>", i + offset, cols);
265275
}
266276
line_numbers.write_str("</pre>");
267277
highlight::render_with_highlighting(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,7 @@ nav.sub {
453453
text-decoration: underline;
454454
}
455455

456-
.rustdoc:not(.source) .example-wrap > pre:not(.line-number) {
456+
.rustdoc:not(.source) .example-wrap > pre:not(.line-numbers) {
457457
width: 100%;
458458
overflow-x: auto;
459459
}

src/librustdoc/lib.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,6 @@ fn opts() -> Vec<RustcOptGroup> {
620620
)
621621
}),
622622
unstable("scrape-examples", |o| o.optopt("", "scrape-examples", "", "")),
623-
unstable("workspace-root", |o| o.optopt("", "workspace-root", "", "")),
624-
unstable("repository-url", |o| o.optopt("", "repository-url", "", "")),
625623
unstable("with-examples", |o| o.optmulti("", "with-examples", "", "")),
626624
]
627625
}
@@ -705,17 +703,16 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
705703
fn main_options(options: config::Options) -> MainResult {
706704
let diag = core::new_handler(options.error_format, None, &options.debugging_opts);
707705

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) => {
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) => {
713710
return wrap_return(
714711
&diag,
715712
markdown::render(&options.input, options.render_options, options.edition),
716713
);
717714
}
718-
(false, false, false) => {}
715+
(false, false) => {}
719716
}
720717

721718
// need to move these items separately because we lose them by the time the closure is called,
@@ -737,6 +734,7 @@ fn main_options(options: config::Options) -> MainResult {
737734
// FIXME: fix this clone (especially render_options)
738735
let manual_passes = options.manual_passes.clone();
739736
let render_options = options.render_options.clone();
737+
let scrape_examples = options.scrape_examples.clone();
740738
let config = core::create_config(options);
741739

742740
interface::create_compiler_and_run(config, |compiler| {
@@ -773,6 +771,10 @@ fn main_options(options: config::Options) -> MainResult {
773771
});
774772
info!("finished with rustc");
775773

774+
if let Some(example_path) = scrape_examples {
775+
return scrape_examples::run(krate, render_opts, cache, tcx, example_path);
776+
}
777+
776778
cache.crate_version = crate_version;
777779

778780
if show_coverage {

0 commit comments

Comments
 (0)