Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit db61452

Browse filesBrowse 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
Copy full SHA for db61452

File tree

Expand file treeCollapse file tree

13 files changed

+342
-88
lines changed
Filter options
Expand file treeCollapse file tree

13 files changed

+342
-88
lines changed

‎src/doc/rustdoc/src/SUMMARY.md

Copy file name to clipboardExpand all lines: src/doc/rustdoc/src/SUMMARY.md
+1Lines changed: 1 addition & 0 deletions
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)
+55Lines changed: 55 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/librustdoc/html/render/context.rs
+17-2Lines changed: 17 additions & 2 deletions
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

Copy file name to clipboardExpand all lines: src/librustdoc/html/render/mod.rs
+35-1Lines changed: 35 additions & 1 deletion
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

Copy file name to clipboardExpand all lines: src/librustdoc/html/static/css/rustdoc.css
+44-37Lines changed: 44 additions & 37 deletions
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

Copy file name to clipboardExpand all lines: src/librustdoc/html/static/css/themes/ayu.css
+14-2Lines changed: 14 additions & 2 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.