Skip to content

Commit

Permalink
Rollup merge of #93217 - willcrichton:example-analyzer, r=GuillaumeGomez
Browse files Browse the repository at this point in the history
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`
  • Loading branch information
Dylan-DPC authored Apr 13, 2022
2 parents f38c5c8 + 6a18b68 commit db61452
Show file tree
Hide file tree
Showing 13 changed files with 342 additions and 88 deletions.
1 change: 1 addition & 0 deletions src/doc/rustdoc/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
- [Linking to items by name](write-documentation/linking-to-items-by-name.md)
- [Documentation tests](write-documentation/documentation-tests.md)
- [Rustdoc-specific lints](lints.md)
- [Scraped examples](scraped-examples.md)
- [Advanced features](advanced-features.md)
- [Unstable features](unstable-features.md)
- [Deprecated features](deprecated-features.md)
Expand Down
55 changes: 55 additions & 0 deletions src/doc/rustdoc/src/scraped-examples.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Scraped examples

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:

```rust,ignore (needs-other-file)
// a_crate/src/lib.rs
pub fn a_func() {}
```

And you have an example calling this function:

```rust,ignore (needs-other-file)
// a_crate/examples/ex.rs
fn main() {
a_crate::a_func();
}
```

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.


## How to use this feature

This feature is unstable, so you can enable it by calling Rustdoc with the unstable `rustdoc-scrape-examples` flag:

```bash
cargo doc -Zunstable-options -Zrustdoc-scrape-examples=examples
```

To enable this feature on [docs.rs](https://docs.rs), add this to your Cargo.toml:

```toml
[package.metadata.docs.rs]
cargo-args = ["-Zunstable-options", "-Zrustdoc-scrape-examples=examples"]
```


## How it works

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.

Rustdoc has a few techniques to ensure these examples don't overwhelm documentation readers, and that it doesn't blow up the page size:

1. For a given item, a maximum of 5 examples are included in the page. The remaining examples are just links to source code.
2. Only one example is shown by default, and the remaining examples are hidden behind a toggle.
3. For a given file that contains examples, only the item containing the examples will be included in the generated documentation.

For a given item, Rustdoc sorts its examples based on the size of the example — smaller ones are shown first.


## FAQ

### My example is not showing up in the documentation

This feature uses Cargo's convention for finding examples. You should ensure that `cargo check --examples` includes your example file.
19 changes: 17 additions & 2 deletions src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use super::print_item::{full_path, item_path, print_item};
use super::search_index::build_index;
use super::write_shared::write_shared;
use super::{
collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
BASIC_KEYWORDS,
collect_spans_and_sources, print_sidebar, scrape_examples_help, settings, AllTypes,
LinkFromSrc, NameDoc, StylePath, BASIC_KEYWORDS,
};

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

let mut root_path = self.dst.to_str().expect("invalid path").to_owned();
if !root_path.ends_with('/') {
Expand Down Expand Up @@ -606,6 +607,20 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
&self.shared.style_files,
);
self.shared.fs.write(settings_file, v)?;

if self.shared.layout.scrape_examples_extension {
page.title = "About scraped examples";
page.description = "How the scraped examples feature works in Rustdoc";
let v = layout::render(
&self.shared.layout,
&page,
"",
scrape_examples_help(&*self.shared),
&self.shared.style_files,
);
self.shared.fs.write(scrape_examples_help_file, v)?;
}

if let Some(ref redirections) = self.shared.redirections {
if !redirections.borrow().is_empty() {
let redirect_map_path =
Expand Down
36 changes: 35 additions & 1 deletion src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@ use crate::html::format::{
use crate::html::highlight;
use crate::html::markdown::{HeadingOffset, IdMap, Markdown, MarkdownHtml, MarkdownSummaryLine};
use crate::html::sources;
use crate::html::static_files::SCRAPE_EXAMPLES_HELP_MD;
use crate::scrape_examples::{CallData, CallLocation};
use crate::try_none;
use crate::DOC_RUST_LANG_ORG_CHANNEL;

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

fn scrape_examples_help(shared: &SharedContext<'_>) -> String {
let mut content = SCRAPE_EXAMPLES_HELP_MD.to_owned();
content.push_str(&format!(
"## More information\n\n\
If you want more information about this feature, please read the [corresponding chapter in the Rustdoc book]({}/rustdoc/scraped-examples.html).",
DOC_RUST_LANG_ORG_CHANNEL));

let mut ids = IdMap::default();
format!(
"<div class=\"main-heading\">\
<h1 class=\"fqn\">\
<span class=\"in-band\">About scraped examples</span>\
</h1>\
</div>\
<div>{}</div>",
Markdown {
content: &content,
links: &[],
ids: &mut ids,
error_codes: shared.codes,
edition: shared.edition(),
playground: &shared.playground,
heading_offset: HeadingOffset::H1
}
.into_string()
)
}

fn document(
w: &mut Buffer,
cx: &Context<'_>,
Expand Down Expand Up @@ -2743,7 +2773,9 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
<span></span>\
<h5 id=\"{id}\">\
<a href=\"#{id}\">Examples found in repository</a>\
<a class=\"scrape-help\" href=\"{root_path}scrape-examples-help.html\">?</a>\
</h5>",
root_path = cx.root_path(),
id = id
);

Expand Down Expand Up @@ -2795,9 +2827,10 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
.locations
.iter()
.map(|loc| {
let (byte_lo, byte_hi) = loc.call_expr.byte_span;
let (byte_lo, byte_hi) = loc.call_ident.byte_span;
let (line_lo, line_hi) = loc.call_expr.line_span;
let byte_range = (byte_lo - byte_min, byte_hi - byte_min);

let line_range = (line_lo - line_min, line_hi - line_min);
let (line_url, line_title) = link_to_loc(call_data, loc);

Expand Down Expand Up @@ -2913,6 +2946,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
<summary class=\"hideme\">\
<span>More examples</span>\
</summary>\
<div class=\"hide-more\">Hide additional examples</div>\
<div class=\"more-scraped-examples\">\
<div class=\"toggle-line\"><div class=\"toggle-line-inner\"></div></div>\
<div class=\"more-scraped-examples-inner\">"
Expand Down
81 changes: 44 additions & 37 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,7 @@ h2.location a {
position: relative;
}

.docblock > :not(.information) {
.docblock > :not(.information):not(.more-examples-toggle) {
max-width: 100%;
overflow-x: auto;
}
Expand Down Expand Up @@ -840,8 +840,8 @@ h2.small-section-header > .anchor {
content: '§';
}

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

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

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

.scraped-example-list .scrape-help {
margin-left: 10px;
padding: 0 4px;
font-weight: normal;
font-size: 12px;
position: relative;
bottom: 1px;
background: transparent;
border-width: 1px;
border-style: solid;
border-radius: 50px;
}

.scraped-example-title {
font-family: 'Fira Sans';
}

.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
overflow: hidden;
.scraped-example .code-wrapper {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}

.scraped-example:not(.expanded) .code-wrapper {
max-height: 240px;
}

.scraped-example:not(.expanded) .code-wrapper .example-wrap pre.rust {
.scraped-example:not(.expanded) .code-wrapper pre {
overflow-y: hidden;
max-height: 240px;
padding-bottom: 0;
}

.scraped-example:not(.expanded) .code-wrapper pre.line-numbers {
overflow-x: hidden;
}

.scraped-example .code-wrapper .prev {
position: absolute;
top: 0.25em;
Expand All @@ -2077,22 +2101,13 @@ details.rustdoc-toggle[open] > summary.hideme::after {
cursor: pointer;
}

.scraped-example .code-wrapper {
position: relative;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}

.scraped-example:not(.expanded) .code-wrapper:before {
content: " ";
width: 100%;
height: 5px;
position: absolute;
z-index: 100;
top: 0;
background: linear-gradient(to bottom, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}

.scraped-example:not(.expanded) .code-wrapper:after {
Expand All @@ -2102,12 +2117,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
position: absolute;
z-index: 100;
bottom: 0;
background: linear-gradient(to top, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}

.scraped-example:not(.expanded) .code-wrapper {
overflow: hidden;
max-height: 240px;
}

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

.scraped-example:not(.expanded) .code-wrapper .example-wrap {
overflow-x: hidden;
}

.scraped-example .code-wrapper .example-wrap pre.rust {
overflow-x: inherit;
width: inherit;
overflow-y: hidden;
}

.scraped-example .example-wrap .rust span.highlight {
background: #fcffd6;
}

.scraped-example .example-wrap .rust span.highlight.focus {
background: #f6fdb0;
}

.more-examples-toggle {
max-width: calc(100% + 25px);
margin-top: 10px;
margin-left: -25px;
}

.more-examples-toggle .hide-more {
margin-left: 25px;
margin-bottom: 5px;
cursor: pointer;
}

.more-examples-toggle summary {
color: #999;
.more-examples-toggle summary, .more-examples-toggle .hide-more {
font-family: 'Fira Sans';
}

.more-scraped-examples {
margin-left: 25px;
margin-left: 5px;
display: flex;
flex-direction: row;
width: calc(100% - 25px);
}

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

.toggle-line:hover .toggle-line-inner {
background: #aaa;
}

.toggle-line-inner {
min-width: 2px;
background: #ddd;
height: 100%;
}

Expand Down
16 changes: 14 additions & 2 deletions src/librustdoc/html/static/css/themes/ayu.css
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,18 @@ input:checked + .slider {
background-color: #ffb454 !important;
}


.scraped-example-list .scrape-help {
border-color: #aaa;
color: #eee;
}
.scraped-example-list .scrape-help:hover {
border-color: white;
color: white;
}
.more-examples-toggle summary, .more-examples-toggle .hide-more {
color: #999;
}
.scraped-example .example-wrap .rust span.highlight {
background: rgb(91, 59, 1);
}
Expand All @@ -624,8 +636,8 @@ input:checked + .slider {
background: linear-gradient(to top, rgba(15, 20, 25, 1), rgba(15, 20, 25, 0));
}
.toggle-line-inner {
background: #616161;
background: #999;
}
.toggle-line:hover .toggle-line-inner {
background: #898989;
background: #c5c5c5;
}
Loading

0 comments on commit db61452

Please sign in to comment.