Skip to content

Commit db61452

Browse files
authored
Rollup merge of #93217 - willcrichton:example-analyzer, r=GuillaumeGomez
Improve Rustdoc UI for scraped examples with multiline arguments, fix overflow in line numbers This PR improves a few aspects of the scrape examples feature in Rustdoc. * Only function names and not the full call expression are highlighted. * For call-sites with multiline arguments, the minimized code viewer will scroll to the top of the call-site rather than the middle if the argument is larger than the viewer size, ensuring that the function name is visible. * This fixes an issue where the line numbers column had a visible x-scroll bar. r? `@GuillaumeGomez`
2 parents f38c5c8 + 6a18b68 commit db61452

File tree

13 files changed

+342
-88
lines changed

13 files changed

+342
-88
lines changed

src/doc/rustdoc/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- [Linking to items by name](write-documentation/linking-to-items-by-name.md)
1010
- [Documentation tests](write-documentation/documentation-tests.md)
1111
- [Rustdoc-specific lints](lints.md)
12+
- [Scraped examples](scraped-examples.md)
1213
- [Advanced features](advanced-features.md)
1314
- [Unstable features](unstable-features.md)
1415
- [Deprecated features](deprecated-features.md)
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Scraped examples
2+
3+
Rustdoc has an unstable feature where it can automatically scrape examples of items being documented from the `examples/` directory of a Cargo workspace. These examples will be included within the generated documentation for that item. For example, if your library contains a public function:
4+
5+
```rust,ignore (needs-other-file)
6+
// a_crate/src/lib.rs
7+
pub fn a_func() {}
8+
```
9+
10+
And you have an example calling this function:
11+
12+
```rust,ignore (needs-other-file)
13+
// a_crate/examples/ex.rs
14+
fn main() {
15+
a_crate::a_func();
16+
}
17+
```
18+
19+
Then this code snippet will be included in the documentation for `a_func`. This documentation is inserted by Rustdoc and cannot be manually edited by the crate author.
20+
21+
22+
## How to use this feature
23+
24+
This feature is unstable, so you can enable it by calling Rustdoc with the unstable `rustdoc-scrape-examples` flag:
25+
26+
```bash
27+
cargo doc -Zunstable-options -Zrustdoc-scrape-examples=examples
28+
```
29+
30+
To enable this feature on [docs.rs](https://docs.rs), add this to your Cargo.toml:
31+
32+
```toml
33+
[package.metadata.docs.rs]
34+
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
35+
```
36+
37+
38+
## How it works
39+
40+
When you run `cargo doc`, Rustdoc will analyze all the crates that match Cargo's `--examples` filter for instances of items being documented. Then Rustdoc will include the source code of these instances in the generated documentation.
41+
42+
Rustdoc has a few techniques to ensure these examples don't overwhelm documentation readers, and that it doesn't blow up the page size:
43+
44+
1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code.
45+
2. Only one example is shown by default, and the remaining examples are hidden behind a toggle.
46+
3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation.
47+
48+
For a given item, Rustdoc sorts its examples based on the size of the example — smaller ones are shown first.
49+
50+
51+
## FAQ
52+
53+
### My example is not showing up in the documentation
54+
55+
This feature uses Cargo's convention for finding examples. You should ensure that `cargo check --examples` includes your example file.

src/librustdoc/html/render/context.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use super::print_item::{full_path, item_path, print_item};
1717
use super::search_index::build_index;
1818
use super::write_shared::write_shared;
1919
use super::{
20-
collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
21-
BASIC_KEYWORDS,
20+
collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
21+
LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
2222
};
2323

2424
use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -551,6 +551,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
551551
let crate_name = self.tcx().crate_name(LOCAL_CRATE);
552552
let final_file = self.dst.join(crate_name.as_str()).join("all.html");
553553
let settings_file = self.dst.join("settings.html");
554+
let scrape_examples_help_file = self.dst.join("scrape-examples-help.html");
554555

555556
let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
556557
if !root_path.ends_with('/') {
@@ -606,6 +607,20 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
606607
&self.shared.style_files,
607608
);
608609
self.shared.fs.write(settings_file, v)?;
610+
611+
if self.shared.layout.scrape_examples_extension {
612+
page.title = "About scraped examples";
613+
page.description = "How the scraped examples feature works in Rustdoc";
614+
let v = layout::render(
615+
&self.shared.layout,
616+
&page,
617+
"",
618+
scrape_examples_help(&*self.shared),
619+
&self.shared.style_files,
620+
);
621+
self.shared.fs.write(scrape_examples_help_file, v)?;
622+
}
623+
609624
if let Some(ref redirections) = self.shared.redirections {
610625
if !redirections.borrow().is_empty() {
611626
let redirect_map_path =

src/librustdoc/html/render/mod.rs

+35-1
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,10 @@ use crate::html::format::{
7575
use crate::html::highlight;
7676
use crate::html::markdown::{HeadingOffset, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine};
7777
use crate::html::sources;
78+
use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
7879
use crate::scrape_examples::{CallData, CallLocation};
7980
use crate::try_none;
81+
use crate::DOC_RUST_LANG_ORG_CHANNEL;
8082

8183
/// A pair of name and its optional document.
8284
crate type NameDoc = (String, Option<String>);
@@ -460,6 +462,34 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S
460462
))
461463
}
462464

465+
fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
466+
let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
467+
content.push_str(&format!(
468+
"## More information\n\n\
469+
If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
470+
DOC_RUST_LANG_ORG_CHANNEL));
471+
472+
let mut ids = IdMap::default();
473+
format!(
474+
"<div class=\"main-heading\">\
475+
<h1 class=\"fqn\">\
476+
<span class=\"in-band\">About scraped examples</span>\
477+
</h1>\
478+
</div>\
479+
<div>{}</div>",
480+
Markdown {
481+
content: &content,
482+
links: &[],
483+
ids: &mut ids,
484+
error_codes: shared.codes,
485+
edition: shared.edition(),
486+
playground: &shared.playground,
487+
heading_offset: HeadingOffset::H1
488+
}
489+
.into_string()
490+
)
491+
}
492+
463493
fn document(
464494
w: &mut Buffer,
465495
cx: &Context<'_>,
@@ -2743,7 +2773,9 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
27432773
<span></span>\
27442774
<h5 id=\"{id}\">\
27452775
<a href=\"#{id}\">Examples found in repository</a>\
2776+
<a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
27462777
</h5>",
2778+
root_path = cx.root_path(),
27472779
id = id
27482780
);
27492781

@@ -2795,9 +2827,10 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
27952827
.locations
27962828
.iter()
27972829
.map(|loc| {
2798-
let (byte_lo, byte_hi) = loc.call_expr.byte_span;
2830+
let (byte_lo, byte_hi) = loc.call_ident.byte_span;
27992831
let (line_lo, line_hi) = loc.call_expr.line_span;
28002832
let byte_range = (byte_lo - byte_min, byte_hi - byte_min);
2833+
28012834
let line_range = (line_lo - line_min, line_hi - line_min);
28022835
let (line_url, line_title) = link_to_loc(call_data, loc);
28032836

@@ -2913,6 +2946,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
29132946
<summary class=\"hideme\">\
29142947
<span>More examples</span>\
29152948
</summary>\
2949+
<div class=\"hide-more\">Hide additional examples</div>\
29162950
<div class=\"more-scraped-examples\">\
29172951
<div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
29182952
<div class=\"more-scraped-examples-inner\">"

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

+44-37
Original file line numberDiff line numberDiff line change
@@ -618,7 +618,7 @@ h2.location a {
618618
position: relative;
619619
}
620620

621-
.docblock > :not(.information) {
621+
.docblock > :not(.information):not(.more-examples-toggle) {
622622
max-width: 100%;
623623
overflow-x: auto;
624624
}
@@ -840,8 +840,8 @@ h2.small-section-header > .anchor {
840840
content: '§';
841841
}
842842

843-
.docblock a:not(.srclink):not(.test-arrow):hover,
844-
.docblock-short a:not(.srclink):not(.test-arrow):hover, .item-info a {
843+
.docblock a:not(.srclink):not(.test-arrow):not(.scrape-help):hover,
844+
.docblock-short a:not(.srclink):not(.test-arrow):not(.scrape-help):hover, .item-info a {
845845
text-decoration: underline;
846846
}
847847

@@ -2038,21 +2038,45 @@ details.rustdoc-toggle[open] > summary.hideme::after {
20382038

20392039
/* Begin: styles for --scrape-examples feature */
20402040

2041+
.scraped-example-list .scrape-help {
2042+
margin-left: 10px;
2043+
padding: 0 4px;
2044+
font-weight: normal;
2045+
font-size: 12px;
2046+
position: relative;
2047+
bottom: 1px;
2048+
background: transparent;
2049+
border-width: 1px;
2050+
border-style: solid;
2051+
border-radius: 50px;
2052+
}
2053+
20412054
.scraped-example-title {
20422055
font-family: 'Fira Sans';
20432056
}
20442057

2045-
.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
2046-
overflow: hidden;
2058+
.scraped-example .code-wrapper {
2059+
position: relative;
2060+
display: flex;
2061+
flex-direction: row;
2062+
flex-wrap: wrap;
2063+
width: 100%;
2064+
}
2065+
2066+
.scraped-example:not(.expanded) .code-wrapper {
20472067
max-height: 240px;
20482068
}
20492069

2050-
.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
2070+
.scraped-example:not(.expanded) .code-wrapper pre {
20512071
overflow-y: hidden;
20522072
max-height: 240px;
20532073
padding-bottom: 0;
20542074
}
20552075

2076+
.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
2077+
overflow-x: hidden;
2078+
}
2079+
20562080
.scraped-example .code-wrapper .prev {
20572081
position: absolute;
20582082
top: 0.25em;
@@ -2077,22 +2101,13 @@ details.rustdoc-toggle[open] > summary.hideme::after {
20772101
cursor: pointer;
20782102
}
20792103

2080-
.scraped-example .code-wrapper {
2081-
position: relative;
2082-
display: flex;
2083-
flex-direction: row;
2084-
flex-wrap: wrap;
2085-
width: 100%;
2086-
}
2087-
20882104
.scraped-example:not(.expanded) .code-wrapper:before {
20892105
content: " ";
20902106
width: 100%;
20912107
height: 5px;
20922108
position: absolute;
20932109
z-index: 100;
20942110
top: 0;
2095-
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
20962111
}
20972112

20982113
.scraped-example:not(.expanded) .code-wrapper:after {
@@ -2102,12 +2117,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
21022117
position: absolute;
21032118
z-index: 100;
21042119
bottom: 0;
2105-
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
2106-
}
2107-
2108-
.scraped-example:not(.expanded) .code-wrapper {
2109-
overflow: hidden;
2110-
max-height: 240px;
21112120
}
21122121

21132122
.scraped-example .code-wrapper .line-numbers {
@@ -2126,34 +2135,37 @@ details.rustdoc-toggle[open] > summary.hideme::after {
21262135
margin-bottom: 0;
21272136
}
21282137

2138+
.scraped-example:not(.expanded) .code-wrapper .example-wrap {
2139+
overflow-x: hidden;
2140+
}
2141+
21292142
.scraped-example .code-wrapper .example-wrap pre.rust {
21302143
overflow-x: inherit;
21312144
width: inherit;
21322145
overflow-y: hidden;
21332146
}
21342147

2135-
.scraped-example .example-wrap .rust span.highlight {
2136-
background: #fcffd6;
2137-
}
2138-
2139-
.scraped-example .example-wrap .rust span.highlight.focus {
2140-
background: #f6fdb0;
2141-
}
21422148

21432149
.more-examples-toggle {
2150+
max-width: calc(100% + 25px);
21442151
margin-top: 10px;
2152+
margin-left: -25px;
2153+
}
2154+
2155+
.more-examples-toggle .hide-more {
2156+
margin-left: 25px;
2157+
margin-bottom: 5px;
2158+
cursor: pointer;
21452159
}
21462160

2147-
.more-examples-toggle summary {
2148-
color: #999;
2161+
.more-examples-toggle summary, .more-examples-toggle .hide-more {
21492162
font-family: 'Fira Sans';
21502163
}
21512164

21522165
.more-scraped-examples {
2153-
margin-left: 25px;
2166+
margin-left: 5px;
21542167
display: flex;
21552168
flex-direction: row;
2156-
width: calc(100% - 25px);
21572169
}
21582170

21592171
.more-scraped-examples-inner {
@@ -2169,13 +2181,8 @@ details.rustdoc-toggle[open] > summary.hideme::after {
21692181
cursor: pointer;
21702182
}
21712183

2172-
.toggle-line:hover .toggle-line-inner {
2173-
background: #aaa;
2174-
}
2175-
21762184
.toggle-line-inner {
21772185
min-width: 2px;
2178-
background: #ddd;
21792186
height: 100%;
21802187
}
21812188

src/librustdoc/html/static/css/themes/ayu.css

+14-2
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,18 @@ input:checked + .slider {
611611
background-color: #ffb454 !important;
612612
}
613613

614+
615+
.scraped-example-list .scrape-help {
616+
border-color: #aaa;
617+
color: #eee;
618+
}
619+
.scraped-example-list .scrape-help:hover {
620+
border-color: white;
621+
color: white;
622+
}
623+
.more-examples-toggle summary, .more-examples-toggle .hide-more {
624+
color: #999;
625+
}
614626
.scraped-example .example-wrap .rust span.highlight {
615627
background: rgb(91, 59, 1);
616628
}
@@ -624,8 +636,8 @@ input:checked + .slider {
624636
background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
625637
}
626638
.toggle-line-inner {
627-
background: #616161;
639+
background: #999;
628640
}
629641
.toggle-line:hover .toggle-line-inner {
630-
background: #898989;
642+
background: #c5c5c5;
631643
}

0 commit comments

Comments
 (0)