Rollup merge of #129545 - notriddle:notriddle/toolbar-v2, r=GuillaumeGomez

rustdoc: redesign toolbar and disclosure widgets

Fixes #77899
Fixes #90310

## Preview

| before | after
| ------ | -----
| ![image](https://github.com/user-attachments/assets/ebeec185-3a72-481d-921e-a9a885f348d9) | ![image](https://github.com/user-attachments/assets/08735a65-99d1-4523-ab77-ddb164c0a5db)
| ![image](https://github.com/user-attachments/assets/ae8e0f24-49cb-445d-b9bd-cec9c57b94e7) | ![image](https://github.com/user-attachments/assets/ba484f94-b031-41fc-b8a8-6cd81be8fb6b)
| ![image](https://github.com/user-attachments/assets/8c2cc041-a138-4950-a12e-3d529c8a5339) | ![image](https://github.com/user-attachments/assets/e7f010bd-19e2-4711-85bf-3fd00c3e5647)
| ![image](https://github.com/user-attachments/assets/e2b63785-971c-489e-b069-eb85f6a30620) | ![image](https://github.com/user-attachments/assets/b65eea16-d6a3-4aa3-8a27-6ded74009010)
| ![image](https://github.com/user-attachments/assets/1c7b0901-a61a-4325-9d01-9d8b14b476aa) | ![image](https://github.com/user-attachments/assets/d4a485db-d9f1-4a62-94bc-a3d125ea6dc1)
| N/A | ![image](https://github.com/user-attachments/assets/7add0a2a-7fd7-483d-87ee-51ee45a2fe5d)
| ![image](https://github.com/user-attachments/assets/334f50bc-9f8d-42d9-a7df-95058f7cdfd5) | ![image](https://github.com/user-attachments/assets/451fcc22-b034-453c-ae4b-b948fd6bd779)
| ![image](https://github.com/user-attachments/assets/132f720c-802a-466d-bd55-c7a4750acdc3) | ![image](https://github.com/user-attachments/assets/177b7921-06c5-467d-87d3-9cdf88c4e50b)

https://notriddle.com/rustdoc-html-demo-12/toolbar-v2/std/index.html

## Description

This adds labels to the icons and moves them away from the search box.

These changes are made together, because they work together, but are based on several complaints:

* The [+/-] thing are a Reddit-ism. They don't look like buttons, but look like syntax <https://rust-lang.zulipchat.com/#narrow/stream/266220-t-rustdoc/topic/More.20visual.20difference.20for.20the.20.2B.2F-.20.20Icons>, <https://github.com/rust-lang/rust/issues/59851> (some of these are laundry lists with more suggestions, but they all mention [+/-] looking wrong)

* The settings, help, and summary buttons are also too hard to recognize <https://lwn.net/Articles/987070/>, <https://github.com/rust-lang/rust/issues/90310>, <https://github.com/rust-lang/rust/issues/14475#issuecomment-274241997>, <https://internals.rust-lang.org/t/improve-rustdoc-design/12758> ("Not all functionality is self-explanatory, for example the [+] button in the top right corner, the theme picker or the settings button.")

The toggle-all and toggle-individual buttons both need done at once, since we want them to look like they go together. This changes them from both being [+/-] to both being arrows.

CC <https://github.com/rust-lang/rust/pull/113074#issuecomment-1677469680> and ``@jsha`` regarding the use of triangles for disclosure, which is what everyone wanted, but was pending a good toggle-all button. This PR adds a toggle-all button that should work.

Settings and Help are also migrated, so that the whole group can benefit from being described using actual words.

The breadcrumbs also get redesigned, so that they use less space, by shrinking the parent module path parts. This is done at the same time as the toolbar redesign because it's, effectively, moving space from the toolbar to the breadcrumbs.
This is aimed at avoiding any line wrapping at desktop sizes.

## Prior art

This style of toolbar, with explicit labels on the buttons, used to be more popular. It's not very common in web browsers nowadays, and for truly universal icons like ⬅️ I can understand why, but words are great when icons fail.

![image](https://github.com/user-attachments/assets/9a4a0498-232d-4d60-87b9-f601f4515254)
This commit is contained in:
Michael Goulet 2024-09-23 23:49:11 -04:00 committed by GitHub
commit 0a0ea28f26
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 539 additions and 336 deletions

View File

@ -32,13 +32,17 @@
//!
//! Once you are familiar with the contents of the standard library you may
//! begin to find the verbosity of the prose distracting. At this stage in your
//! development you may want to press the `[-]` button near the top of the
//! page to collapse it into a more skimmable view.
//! development you may want to press the <code>
//! <svg style="width:0.75rem;height:0.75rem" viewBox="0 0 12 12"
//! stroke="currentColor" fill="none">
//! <path d="M2,2l4,4l4,-4M2,6l4,4l4,-4"/></svg> Summary</code> button near the
//! top of the page to collapse it into a more skimmable view.
//!
//! While you are looking at that `[-]` button also notice the `source`
//! link. Rust's API documentation comes with the source code and you are
//! encouraged to read it. The standard library source is generally high
//! quality and a peek behind the curtains is often enlightening.
//! While you are looking at the top of the page, also notice the
//! <code>source</code> link. Rust's API documentation comes with the source
//! code and you are encouraged to read it. The standard library source is
//! generally high quality and a peek behind the curtains is
//! often enlightening.
//!
//! # What is in the standard library documentation?
//!

View File

@ -26,8 +26,11 @@ pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), E
let dst = cx.dst.join("src").join(krate.name(cx.tcx()).as_str());
cx.shared.ensure_dir(&dst)?;
let crate_name = krate.name(cx.tcx());
let crate_name = crate_name.as_str();
let mut collector = SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default() };
let mut collector =
SourceCollector { dst, cx, emitted_local_sources: FxHashSet::default(), crate_name };
collector.visit_crate(krate);
Ok(())
}
@ -115,6 +118,8 @@ struct SourceCollector<'a, 'tcx> {
/// Root destination to place all HTML output into
dst: PathBuf,
emitted_local_sources: FxHashSet<PathBuf>,
crate_name: &'a str,
}
impl DocVisitor for SourceCollector<'_, '_> {
@ -210,6 +215,9 @@ impl SourceCollector<'_, '_> {
},
);
let src_fname = p.file_name().expect("source has no filename").to_os_string();
let mut fname = src_fname.clone();
let root_path = PathBuf::from("../../").join(root_path.into_inner());
let mut root_path = root_path.to_string_lossy();
if let Some(c) = root_path.as_bytes().last()
@ -217,12 +225,12 @@ impl SourceCollector<'_, '_> {
{
root_path += "/";
}
let mut file_path = Path::new(&self.crate_name).join(&*cur.borrow());
file_path.push(&fname);
fname.push(".html");
let mut cur = self.dst.join(cur.into_inner());
shared.ensure_dir(&cur)?;
let src_fname = p.file_name().expect("source has no filename").to_os_string();
let mut fname = src_fname.clone();
fname.push(".html");
cur.push(&fname);
let title = format!("{} - source", src_fname.to_string_lossy());
@ -250,7 +258,7 @@ impl SourceCollector<'_, '_> {
cx,
&root_path,
highlight::DecorationInfo::default(),
SourceContext::Standalone,
SourceContext::Standalone { file_path },
)
},
&shared.style_files,
@ -312,10 +320,11 @@ struct ScrapedSource<'a, Code: std::fmt::Display> {
struct Source<Code: std::fmt::Display> {
lines: RangeInclusive<usize>,
code_html: Code,
file_path: Option<(String, String)>,
}
pub(crate) enum SourceContext<'a> {
Standalone,
Standalone { file_path: PathBuf },
Embedded(ScrapedInfo<'a>),
}
@ -344,9 +353,19 @@ pub(crate) fn print_src(
});
let lines = s.lines().count();
match source_context {
SourceContext::Standalone => {
Source { lines: (1..=lines), code_html: code }.render_into(&mut writer).unwrap()
SourceContext::Standalone { file_path } => Source {
lines: (1..=lines),
code_html: code,
file_path: if let Some(file_name) = file_path.file_name()
&& let Some(file_path) = file_path.parent()
{
Some((file_path.display().to_string(), file_name.display().to_string()))
} else {
None
},
}
.render_into(&mut writer)
.unwrap(),
SourceContext::Embedded(info) => {
let lines = (1 + info.offset)..=(lines + info.offset);
ScrapedSource { info, lines, code_html: code }.render_into(&mut writer).unwrap();

View File

@ -61,6 +61,8 @@ nav.sub {
--copy-path-img-hover-filter: invert(35%);
--code-example-button-color: #7f7f7f;
--code-example-button-hover-color: #595959;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(35%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
@ -87,7 +89,6 @@ nav.sub {
--search-tab-button-not-selected-background: #e6e6e6;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@ -192,6 +193,8 @@ nav.sub {
--search-tab-button-not-selected-background: #252525;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #353535;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(65%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;

View File

@ -34,6 +34,8 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
</g></svg>');
--button-left-margin: 4px;
--button-border-radius: 2px;
--toolbar-button-border-radius: 6px;
--code-block-border-radius: 6px;
}
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@ -165,7 +167,7 @@ h1, h2, h3, h4 {
.main-heading h1 {
margin: 0;
padding: 0;
flex-grow: 1;
grid-area: main-heading-h1;
/* We use overflow-wrap: break-word for Safari, which doesn't recognize
`anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
overflow-wrap: break-word;
@ -174,10 +176,28 @@ h1, h2, h3, h4 {
overflow-wrap: anywhere;
}
.main-heading {
display: flex;
flex-wrap: wrap;
position: relative;
display: grid;
grid-template-areas:
"main-heading-breadcrumbs main-heading-breadcrumbs"
"main-heading-h1 main-heading-toolbar"
"main-heading-sub-heading main-heading-toolbar";
grid-template-columns: 1fr max-content;
grid-template-rows: 25px min-content min-content;
padding-bottom: 6px;
margin-bottom: 15px;
margin-bottom: 11px;
}
.rustdoc-breadcrumbs {
grid-area: main-heading-breadcrumbs;
height: 25px;
line-height: 1.25;
display: flex;
align-items: end;
}
.rustdoc-breadcrumbs a {
padding: 4px 0;
margin: -4px 0;
z-index: 1;
}
/* The only headings that get underlines are:
Markdown-generated headings within the top-doc
@ -218,11 +238,13 @@ h1, h2, h3, h4, h5, h6,
.search-results .result-name,
.item-name > a,
.out-of-band,
.sub-heading,
span.since,
a.src,
#help-button > a,
rustdoc-toolbar,
summary.hideme,
.scraped-example-list,
.rustdoc-breadcrumbs,
/* This selector is for the items listed in the "all items" page. */
ul.all-items {
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
@ -891,14 +913,27 @@ both the code example and the line numbers, so we need to remove the radius in t
overflow-x: auto;
}
.out-of-band {
.sub-heading {
font-size: 1rem;
flex-grow: 0;
font-size: 1.125rem;
grid-area: main-heading-sub-heading;
line-height: 1.25;
padding-bottom: 4px;
}
.main-heading rustdoc-toolbar, .main-heading .out-of-band {
grid-area: main-heading-toolbar;
}
rustdoc-toolbar {
display: flex;
flex-direction: row;
flex-wrap: nowrap;
}
.docblock code, .docblock-short code,
pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers {
background-color: var(--code-block-background-color);
border-radius: var(--code-block-border-radius);
}
#main-content {
@ -945,7 +980,7 @@ div.where {
nav.sub {
flex-grow: 1;
flex-flow: row nowrap;
margin: 4px 0 25px 0;
margin: 4px 0 0 0;
display: flex;
align-items: center;
}
@ -956,7 +991,7 @@ nav.sub {
flex-grow: 1;
}
.src nav.sub {
margin: 0 0 15px 0;
margin: 0 0 -10px 0;
}
.section-header {
@ -1066,6 +1101,11 @@ table,
with boxes (i.e. from the flex layout) */
align-items: baseline;
}
.search-results-title + .sub-heading {
color: var(--main-color);
display: flex;
align-items: center;
}
#crate-search-div {
/* ensures that 100% in properties of #crate-search-div:after
are relative to the size of this div */
@ -1289,10 +1329,16 @@ so that we can apply CSS-filters to change the arrow color in themes */
border-color: var(--settings-input-color) !important;
}
#settings.popover {
--popover-arrow-offset: 202px;
top: calc(100% - 16px);
}
/* use larger max-width for help popover, but not for help.html */
#help.popover {
max-width: 600px;
--popover-arrow-offset: 48px;
--popover-arrow-offset: 118px;
top: calc(100% - 16px);
}
#help dt {
@ -1300,10 +1346,15 @@ so that we can apply CSS-filters to change the arrow color in themes */
clear: left;
margin-right: 0.5rem;
}
#help dd {
margin-bottom: 0.5rem;
}
#help span.top, #help span.bottom {
text-align: center;
display: block;
font-size: 1.125rem;
padding: 0 0.5rem;
text-wrap-style: balance;
}
#help span.top {
margin: 10px 0;
@ -1315,10 +1366,13 @@ so that we can apply CSS-filters to change the arrow color in themes */
clear: both;
border-top: 1px solid var(--border-color);
}
.side-by-side {
display: flex;
margin-bottom: 20px;
}
.side-by-side > div {
width: 50%;
float: left;
padding: 0 20px 20px 17px;
padding: 0 20px 0 17px;
}
.item-info .stab {
@ -1381,7 +1435,9 @@ so that we can apply CSS-filters to change the arrow color in themes */
}
.rightside:not(a),
.out-of-band {
.out-of-band,
.sub-heading,
rustdoc-toolbar {
color: var(--right-side-color);
}
@ -1595,8 +1651,8 @@ instead, we check that it's not a "finger" cursor.
display: block;
}
.out-of-band > span.since {
font-size: 1.25rem;
.main-heading span.since::before {
content: "Since ";
}
.sub-variant h4 {
@ -1698,6 +1754,7 @@ a.tooltip:hover::after {
}
#search-tabs {
margin-top: 0.25rem;
display: flex;
flex-direction: row;
gap: 1px;
@ -1759,9 +1816,10 @@ a.tooltip:hover::after {
border-bottom: 1px solid var(--border-color);
}
#settings-menu, #help-button {
#settings-menu, #help-button, button#toggle-all-docs {
margin-left: var(--button-left-margin);
display: flex;
line-height: 1.25;
}
#sidebar-button {
display: none;
@ -1785,33 +1843,36 @@ a.tooltip:hover::after {
.hide-sidebar .src #sidebar-button {
position: static;
}
#settings-menu > a, #help-button > a, #sidebar-button > a {
#settings-menu > a, #help-button > a, #sidebar-button > a, button#toggle-all-docs {
display: flex;
align-items: center;
justify-content: center;
background-color: var(--button-background-color);
border: 1px solid var(--border-color);
flex-direction: column;
border: 1px solid transparent;
border-radius: var(--button-border-radius);
color: var(--settings-button-color);
/* Rare exception to specifying font sizes in rem. Since this is acting
as an icon, it's okay to specify their sizes in pixels. */
font-size: 20px;
color: var(--main-color);
}
#settings-menu > a, #help-button > a, button#toggle-all-docs {
width: 80px;
border-radius: var(--toolbar-button-border-radius);
}
#sidebar-button > a {
background-color: var(--button-background-color);
border-color: var(--border-color);
width: 33px;
}
#settings-menu > a:hover, #settings-menu > a:focus,
#help-button > a:hover, #help-button > a:focus,
#sidebar-button > a:hover, #sidebar-button > a:focus {
#settings-menu > a:hover, #settings-menu > a:focus-visible,
#help-button > a:hover, #help-button > a:focus-visible,
#sidebar-button > a:hover, #sidebar-button > a:focus-visible,
button#toggle-all-docs:hover, button#toggle-all-docs:focus-visible {
border-color: var(--settings-button-border-focus);
text-decoration: none;
}
#settings-menu > a {
line-height: 0;
font-size: 0;
}
#settings-menu > a:before {
/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
content: url('data:image/svg+xml,<svg width="22" height="22" viewBox="0 0 12 12" \
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M10.25,6c0-0.1243286-0.0261841-0.241333-0.0366211-0.362915l1.6077881-1.5545654l\
-1.25-2.1650391 c0,0-1.2674561,0.3625488-2.1323853,0.6099854c-0.2034912-0.1431885-0.421875\
@ -1824,16 +1885,70 @@ a.tooltip:hover::after {
-0.3701782l2.1323853,0.6099854l1.25-2.1650391L10.2133789,6.362915 C10.2238159,6.241333,\
10.25,6.1243286,10.25,6z M6,7.5C5.1715698,7.5,4.5,6.8284302,4.5,6S5.1715698,4.5,6,4.5S7.5\
,5.1715698,7.5,6 S6.8284302,7.5,6,7.5z" fill="black"/></svg>');
width: 22px;
height: 22px;
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
button#toggle-all-docs:before {
/* Custom arrow icon */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M2,2l4,4l4,-4M2,6l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
#help-button > a:before {
/* Question mark with circle */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg" fill="none">\
<circle r="5.25" cx="6" cy="6" stroke-width="1.25" stroke="black"/>\
<text x="6" y="7" style="font:8px sans-serif;font-weight:1000" text-anchor="middle" \
dominant-baseline="middle" fill="black">?</text></svg>');
width: 18px;
height: 18px;
filter: var(--settings-menu-filter);
}
button#toggle-all-docs:before,
#help-button > a:before,
#settings-menu > a:before {
filter: var(--settings-menu-filter);
margin: 8px;
}
@media not (pointer: coarse) {
button#toggle-all-docs:hover:before,
#help-button > a:hover:before,
#settings-menu > a:hover:before {
filter: var(--settings-menu-hover-filter);
}
}
button[disabled]#toggle-all-docs {
opacity: 0.25;
border: solid 1px var(--main-background-color);
background-size: cover;
}
button[disabled]#toggle-all-docs:hover {
border: solid 1px var(--main-background-color);
cursor: not-allowed;
}
rustdoc-toolbar span.label {
font-size: 1rem;
flex-grow: 1;
padding-bottom: 4px;
}
#sidebar-button > a:before {
/* sidebar resizer image */
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m7.6121 3v16 M5.375 7.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
width: 22px;
@ -1948,10 +2063,10 @@ details.toggle > summary.hideme > span {
}
details.toggle > summary::before {
/* toggle plus */
background: url('data:image/svg+xml,<svg width="17" height="17" \
shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7M8.5 12V8.625v0V5"/></svg>') no-repeat top left;
/* arrow pointing left */
background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M4,2l4,4l-4,4" stroke="black" fill="none" stroke-width="1px"/></svg>');
content: "";
cursor: pointer;
width: 16px;
@ -2034,10 +2149,10 @@ details.toggle[open] > summary.hideme > span {
}
details.toggle[open] > summary::before {
/* toggle minus */
background: url('data:image/svg+xml,<svg width="17" height="17" \
shape-rendering="crispEdges" stroke="black" fill="none" xmlns="http://www.w3.org/2000/svg"><path \
d="M5 2.5H2.5v12H5m7-12h2.5v12H12M5 8.5h7"/></svg>') no-repeat top left;
/* arrow pointing down */
background: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M2,4l4,4l4,-4" stroke="black" fill="none" stroke-width="1px"/></svg>');
}
details.toggle[open] > summary::after {
@ -2090,6 +2205,12 @@ However, it's not needed with smaller screen width because the doc/code block is
#search-tabs .count {
display: block;
}
.side-by-side {
flex-direction: column-reverse;
}
.side-by-side > div {
width: auto;
}
}
/*
@ -2106,6 +2227,25 @@ in src-script.js and main.js
scroll-margin-top: 45px;
}
/* We don't display this button on mobile devices. */
#copy-path {
display: none;
}
/* Text label takes up too much space at this size. */
rustdoc-toolbar span.label {
display: none;
}
#settings-menu > a, #help-button > a, button#toggle-all-docs {
width: 33px;
}
#settings.popover {
--popover-arrow-offset: 86px;
}
#help.popover {
--popover-arrow-offset: 48px;
}
.rustdoc {
/* Sidebar should overlay main content, rather than pushing main content to the right.
Turn off `display: flex` on the body element. */
@ -2117,20 +2257,6 @@ in src-script.js and main.js
padding-top: 0px;
}
.main-heading {
flex-direction: column;
}
.out-of-band {
text-align: left;
margin-left: initial;
padding: initial;
}
.out-of-band .since::before {
content: "Since ";
}
/* Hide the logo and item name from the sidebar. Those are displayed
in the mobile-topbar instead. */
.sidebar .logo-container,
@ -2163,6 +2289,9 @@ in src-script.js and main.js
.src .search-form {
margin-left: 40px;
}
.src .main-heading {
margin-left: 8px;
}
.hide-sidebar .search-form {
margin-left: 32px;
}
@ -2234,16 +2363,11 @@ in src-script.js and main.js
left: -11px;
}
/* We don't display these buttons on mobile devices. */
#copy-path, #help-button {
display: none;
}
/* sidebar button becomes topbar button */
#sidebar-button > a:before {
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m3 7.375h16m0-3h-4" stroke-width="1.25"/></svg>');
width: 22px;
@ -2305,7 +2429,7 @@ in src-script.js and main.js
}
.src nav.sub {
margin: 0;
margin: 0 0 -25px 0;
padding: var(--nav-sub-mobile-padding);
}
}
@ -2543,6 +2667,8 @@ by default.
--copy-path-img-hover-filter: invert(35%);
--code-example-button-color: #7f7f7f;
--code-example-button-hover-color: #595959;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(35%);
--codeblock-error-hover-color: rgb(255, 0, 0);
--codeblock-error-color: rgba(255, 0, 0, .5);
--codeblock-ignore-hover-color: rgb(255, 142, 0);
@ -2569,7 +2695,6 @@ by default.
--search-tab-button-not-selected-background: #e6e6e6;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;
@ -2673,7 +2798,8 @@ by default.
--search-tab-button-not-selected-background: #252525;
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #353535;
--settings-menu-filter: none;
--settings-menu-filter: invert(50%);
--settings-menu-hover-filter: invert(65%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ab8ac1;
@ -2784,7 +2910,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--search-tab-button-not-selected-background: transparent !important;
--search-tab-button-selected-border-top-color: none;
--search-tab-button-selected-background: #141920 !important;
--settings-menu-filter: invert(100%);
--settings-menu-filter: invert(70%);
--settings-menu-hover-filter: invert(100%);
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--code-highlight-kw-color: #ff7733;

View File

@ -1,6 +1,6 @@
// Local js definitions:
/* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */
/* global onEach, onEachLazy, removeClass, getVar */
/* global onEachLazy, removeClass, getVar */
"use strict";
@ -19,17 +19,25 @@ function resourcePath(basename, extension) {
function hideMain() {
addClass(document.getElementById(MAIN_ID), "hidden");
const toggle = document.getElementById("toggle-all-docs");
if (toggle) {
toggle.setAttribute("disabled", "disabled");
}
}
function showMain() {
removeClass(document.getElementById(MAIN_ID), "hidden");
}
function blurHandler(event, parentElem, hideCallback) {
if (!parentElem.contains(document.activeElement) &&
!parentElem.contains(event.relatedTarget)
) {
hideCallback();
const main = document.getElementById(MAIN_ID);
removeClass(main, "hidden");
const mainHeading = main.querySelector(".main-heading");
if (mainHeading && searchState.rustdocToolbar) {
if (searchState.rustdocToolbar.parentElement) {
searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
}
mainHeading.appendChild(searchState.rustdocToolbar);
}
const toggle = document.getElementById("toggle-all-docs");
if (toggle) {
toggle.removeAttribute("disabled");
}
}
@ -167,6 +175,14 @@ function switchDisplayedElement(elemToDisplay) {
el.appendChild(elemToDisplay);
hideMain();
removeClass(el, "hidden");
const mainHeading = elemToDisplay.querySelector(".main-heading");
if (mainHeading && searchState.rustdocToolbar) {
if (searchState.rustdocToolbar.parentElement) {
searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
}
mainHeading.appendChild(searchState.rustdocToolbar);
}
}
function browserSupportsHistoryApi() {
@ -194,33 +210,36 @@ function preLoadCss(cssUrl) {
document.head.append(script);
}
getSettingsButton().onclick = event => {
if (event.ctrlKey || event.altKey || event.metaKey) {
return;
}
window.hideAllModals(false);
addClass(getSettingsButton(), "rotate");
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
loadScript(getVar("static-root-path") + getVar("settings-js"));
// Pre-load all theme CSS files, so that switching feels seamless.
//
// When loading settings.html as a standalone page, the equivalent HTML is
// generated in context.rs.
setTimeout(() => {
const themes = getVar("themes").split(",");
for (const theme of themes) {
// if there are no themes, do nothing
// "".split(",") == [""]
if (theme !== "") {
preLoadCss(getVar("root-path") + theme + ".css");
}
if (getSettingsButton()) {
getSettingsButton().onclick = event => {
if (event.ctrlKey || event.altKey || event.metaKey) {
return;
}
}, 0);
};
window.hideAllModals(false);
addClass(getSettingsButton(), "rotate");
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
loadScript(getVar("static-root-path") + getVar("settings-js"));
// Pre-load all theme CSS files, so that switching feels seamless.
//
// When loading settings.html as a standalone page, the equivalent HTML is
// generated in context.rs.
setTimeout(() => {
const themes = getVar("themes").split(",");
for (const theme of themes) {
// if there are no themes, do nothing
// "".split(",") == [""]
if (theme !== "") {
preLoadCss(getVar("root-path") + theme + ".css");
}
}
}, 0);
};
}
window.searchState = {
rustdocToolbar: document.querySelector("rustdoc-toolbar"),
loadingText: "Loading search results...",
input: document.getElementsByClassName("search-input")[0],
outputElement: () => {
@ -919,8 +938,7 @@ function preLoadCss(cssUrl) {
e.open = true;
}
});
innerToggle.title = "collapse all docs";
innerToggle.children[0].innerText = "\u2212"; // "\u2212" is "" minus sign
innerToggle.children[0].innerText = "Summary";
}
function collapseAllDocs() {
@ -934,8 +952,7 @@ function preLoadCss(cssUrl) {
e.open = false;
}
});
innerToggle.title = "expand all docs";
innerToggle.children[0].innerText = "+";
innerToggle.children[0].innerText = "Show all";
}
function toggleAllDocs() {
@ -1330,7 +1347,13 @@ function preLoadCss(cssUrl) {
}
function helpBlurHandler(event) {
blurHandler(event, getHelpButton(), window.hidePopoverMenus);
if (!getHelpButton().contains(document.activeElement) &&
!getHelpButton().contains(event.relatedTarget) &&
!getSettingsButton().contains(document.activeElement) &&
!getSettingsButton().contains(event.relatedTarget)
) {
window.hidePopoverMenus();
}
}
function buildHelpMenu() {
@ -1433,9 +1456,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
* Hide all the popover menus.
*/
window.hidePopoverMenus = () => {
onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
elem.style.display = "none";
});
const button = getHelpButton();
if (button) {
removeClass(button, "help-open");
}
};
/**
@ -1460,7 +1487,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
function showHelp() {
// Prevent `blur` events from being dispatched as a result of closing
// other modals.
getHelpButton().querySelector("a").focus();
const button = getHelpButton();
addClass(button, "help-open");
button.querySelector("a").focus();
const menu = getHelpMenu(true);
if (menu.style.display === "none") {
window.hideAllModals();
@ -1468,28 +1497,15 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
}
}
const helpLink = document.querySelector(`#${HELP_BUTTON_ID} > a`);
if (isHelpPage) {
showHelp();
document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
// Already on the help page, make help button a no-op.
const target = event.target;
if (target.tagName !== "A" ||
target.parentElement.id !== HELP_BUTTON_ID ||
event.ctrlKey ||
event.altKey ||
event.metaKey) {
return;
}
event.preventDefault();
});
} else {
document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click", event => {
buildHelpMenu();
} else if (helpLink) {
helpLink.addEventListener("click", event => {
// By default, have help button open docs in a popover.
// If user clicks with a moderator, though, use default browser behavior,
// probably opening in a new window or tab.
const target = event.target;
if (target.tagName !== "A" ||
target.parentElement.id !== HELP_BUTTON_ID ||
if (!helpLink.contains(helpLink) ||
event.ctrlKey ||
event.altKey ||
event.metaKey) {
@ -1812,14 +1828,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
return;
}
but.onclick = () => {
const parent = but.parentElement;
const path = [];
onEach(parent.childNodes, child => {
if (child.tagName === "A") {
path.push(child.textContent);
}
onEachLazy(document.querySelectorAll(".rustdoc-breadcrumbs a"), a => {
path.push(a.textContent);
});
path.push(document.querySelector("title").textContent.split(" ")[0]);
copyContentToClipboard(path.join("::"));
copyButtonAnimation(but);

View File

@ -3597,15 +3597,16 @@ async function showResults(results, go_to_first, filterCrates) {
let crates = "";
if (rawSearchIndex.size > 1) {
crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
"<option value=\"all crates\">all crates</option>";
crates = "<div class=\"sub-heading\"> in&nbsp;<div id=\"crate-search-div\">" +
"<select id=\"crate-search\"><option value=\"all crates\">all crates</option>";
for (const c of rawSearchIndex.keys()) {
crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
}
crates += "</select></div>";
crates += "</select></div></div>";
}
let output = `<h1 class="search-results-title">Results${crates}</h1>`;
let output = `<div class="main-heading">\
<h1 class="search-results-title">Results</h1>${crates}</div>`;
if (results.query.error !== null) {
const error = results.query.error;
error.forEach((value, index) => {
@ -3662,6 +3663,9 @@ async function showResults(results, go_to_first, filterCrates) {
resultsElem.appendChild(ret_returned[0]);
search.innerHTML = output;
if (searchState.rustdocToolbar) {
search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
}
const crateSearch = document.getElementById("crate-search");
if (crateSearch) {
crateSearch.addEventListener("input", updateCrate);

View File

@ -1,7 +1,7 @@
// Local js definitions:
/* global getSettingValue, updateLocalStorage, updateTheme */
/* global addClass, removeClass, onEach, onEachLazy, blurHandler */
/* global MAIN_ID, getVar, getSettingsButton */
/* global addClass, removeClass, onEach, onEachLazy */
/* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
"use strict";
@ -267,15 +267,16 @@
}
function settingsBlurHandler(event) {
blurHandler(event, getSettingsButton(), window.hidePopoverMenus);
if (!getHelpButton().contains(document.activeElement) &&
!getHelpButton().contains(event.relatedTarget) &&
!getSettingsButton().contains(document.activeElement) &&
!getSettingsButton().contains(event.relatedTarget)
) {
window.hidePopoverMenus();
}
}
if (isSettingsPage) {
// We replace the existing "onclick" callback to do nothing if clicked.
getSettingsButton().onclick = event => {
event.preventDefault();
};
} else {
if (!isSettingsPage) {
// We replace the existing "onclick" callback.
const settingsButton = getSettingsButton();
const settingsMenu = document.getElementById("settings");

View File

@ -274,16 +274,29 @@ class RustdocSearchElement extends HTMLElement {
spellcheck="false"
placeholder="Type S or / to search, ? for more options…"
type="search">
<div id="help-button" tabindex="-1">
<a href="${rootPath}help.html" title="help">?</a>
</div>
<div id="settings-menu" tabindex="-1">
<a href="${rootPath}settings.html" title="settings">
Settings
</a>
</div>
</form>
</nav>`;
}
}
window.customElements.define("rustdoc-search", RustdocSearchElement);
class RustdocToolbarElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
// Avoid replacing the children after they're already here.
if (this.firstElementChild) {
return;
}
const rootPath = getVar("root-path");
this.innerHTML = `
<div id="settings-menu" tabindex="-1">
<a href="${rootPath}settings.html"><span class="label">Settings</span></a>
</div>
<div id="help-button" tabindex="-1">
<a href="${rootPath}help.html"><span class="label">Help</span></a>
</div>
<button id="toggle-all-docs"><span class="label">Summary</span></button>`;
}
}
window.customElements.define("rustdoc-toolbar", RustdocToolbarElement);

View File

@ -1,26 +1,33 @@
<div class="main-heading"> {# #}
{% if !path_components.is_empty() %}
<span class="rustdoc-breadcrumbs">
{% for (i, component) in path_components.iter().enumerate() %}
{% if i != 0 %}
::<wbr>
{% endif %}
<a href="{{component.path|safe}}index.html">{{component.name}}</a>
{% endfor %}
</span>
{% endif %}
<h1>
{{typ}}
{# The breadcrumbs of the item path, like std::string #}
{% for component in path_components %}
<a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
{% endfor %}
<a class="{{item_type}}" href="#">{{name}}</a> {# #}
<span{% if item_type != "mod" +%} class="{{item_type}}"{% endif %}>
{{name}}
</span> {# #}
<button id="copy-path" title="Copy item path to clipboard"> {# #}
Copy item path {# #}
</button> {# #}
</h1> {# #}
<span class="out-of-band">
<rustdoc-toolbar></rustdoc-toolbar> {# #}
<span class="sub-heading">
{% if !stability_since_raw.is_empty() %}
{{ stability_since_raw|safe +}} · {#+ #}
{{ stability_since_raw|safe +}}
{% endif %}
{% match src_href %}
{% when Some with (href) %}
<a class="src" href="{{href|safe}}">source</a> · {#+ #}
{% if !stability_since_raw.is_empty() +%} · {%+ endif %}
<a class="src" href="{{href|safe}}">source</a> {#+ #}
{% else %}
{% endmatch %}
<button id="toggle-all-docs" title="collapse all docs"> {# #}
[<span>&#x2212;</span>] {# #}
</button> {# #}
</span> {# #}
</div> {# #}

View File

@ -1,4 +1,15 @@
<div class="example-wrap">
{% match file_path %}
{% when Some with ((path, name)) %}
<div class="main-heading"> {# #}
<h1> {# #}
<div class="sub-heading">{{path}}/</div>
{{name}}
</h1> {# #}
<rustdoc-toolbar></rustdoc-toolbar> {# #}
</div>
{% else %}
{% endmatch %}
<div class="example-wrap"> {# #}
{# https://developers.google.com/search/docs/crawling-indexing/robots-meta-tag#data-nosnippet-attr
Do not show "1 2 3 4 5 ..." in web search results. #}
<div data-nosnippet><pre class="src-line-numbers">

View File

@ -10,6 +10,7 @@
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(os_str_display)]
#![feature(round_char_boundary)]
#![feature(test)]
#![feature(type_alias_impl_trait)]

View File

@ -1963,7 +1963,7 @@ impl<'test> TestCx<'test> {
#[rustfmt::skip]
let tidy_args = [
"--new-blocklevel-tags", "rustdoc-search",
"--new-blocklevel-tags", "rustdoc-search,rustdoc-toolbar",
"--indent", "yes",
"--indent-spaces", "2",
"--wrap", "0",

View File

@ -31,7 +31,7 @@ fn check_html_file(file: &Path) -> usize {
.arg("--mute-id") // this option is useful in case we want to mute more warnings
.arg("yes")
.arg("--new-blocklevel-tags")
.arg("rustdoc-search") // custom elements
.arg("rustdoc-search,rustdoc-toolbar") // custom elements
.arg("--mute")
.arg(&to_mute_s)
.arg(file);

View File

@ -12,8 +12,7 @@ define-function: (
call-function: ("switch-theme", {"theme": |theme|})
assert-css: ("#toggle-all-docs", {"color": |main_color|})
assert-css: (".main-heading h1 a:nth-of-type(1)", {"color": |main_heading_color|})
assert-css: (".main-heading a:nth-of-type(2)", {"color": |main_heading_type_color|})
assert-css: (".main-heading h1 span", {"color": |main_heading_type_color|})
assert-css: (
".rightside a.src",
{"color": |src_link_color|, "text-decoration": "none solid " + |src_link_color|},
@ -55,7 +54,7 @@ define-function: (
assert-css: ("#top-doc-prose-title", {"color": |title_color|})
assert-css: (".sidebar .block a", {"color": |sidebar_link_color|})
assert-css: (".main-heading h1 a", {"color": |title_color|})
assert-css: (".main-heading h1", {"color": |title_color|})
// We move the cursor over the "Implementations" title so the anchor is displayed.
move-cursor-to: "h2#implementations"

View File

@ -4,7 +4,7 @@ set-window-size: (1000, 1000) // Try desktop size first.
wait-for: "#help"
assert-css: ("#help", {"display": "block"})
assert-css: ("#help dd", {"font-size": "16px"})
click: "#help-button > a"
assert-false: "#help-button > a"
assert-css: ("#help", {"display": "block"})
compare-elements-property: (".sub", "#help", ["offsetWidth"])
compare-elements-position: (".sub", "#help", ["x"])
@ -50,7 +50,8 @@ call-function: ("check-colors", {
})
// This test ensures that opening the help popover without switching pages works.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
wait-for: "#search-tabs" // Waiting for the search.js to load.
set-window-size: (1000, 1000) // Only supported on desktop.
assert-false: "#help"
click: "#help-button > a"
@ -62,7 +63,8 @@ compare-elements-property-false: (".sub", "#help", ["offsetWidth"])
compare-elements-position-false: (".sub", "#help", ["x"])
// This test ensures that the "the rustdoc book" anchor link within the help popover works.
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=a"
wait-for: "#search-tabs" // Waiting for the search.js to load.
set-window-size: (1000, 1000) // Popover only appears when the screen width is >700px.
assert-false: "#help"
click: "#help-button > a"

View File

@ -20,7 +20,7 @@ store-position: (
{"x": second_line_x, "y": second_line_y},
)
assert: |first_line_x| != |second_line_x| && |first_line_x| == 516 && |second_line_x| == 272
assert: |first_line_y| != |second_line_y| && |first_line_y| == 688 && |second_line_y| == 711
assert: |first_line_y| != |second_line_y| && |first_line_y| == 714 && |second_line_y| == 737
// Now we ensure that they're not rendered on the same line.
set-window-size: (1100, 800)

View File

@ -5,23 +5,8 @@ set-window-size: (400, 600)
set-font-size: 18
wait-for: 100 // wait a bit for the resize and the font-size change to be fully taken into account.
// The out-of-band info (source, stable version, collapse) should be below the
// h1 when the screen gets narrow enough.
assert-css: (".main-heading", {
"display": "flex",
"flex-direction": "column"
})
assert-property: (".mobile-topbar h2", {"offsetHeight": 33})
// Note: We can't use assert-text here because the 'Since' is set by CSS and
// is therefore not part of the DOM.
assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
set-window-size: (1000, 1000)
wait-for: 100 // wait a bit for the resize to be fully taken into account.
assert-css-false: (".content .out-of-band .since::before", { "content": "\"Since \"" })
// On the settings page, the theme buttons should not line-wrap. Instead, they should
// all be placed as a group on a line below the setting name "Theme."
go-to: "file://" + |DOC_PATH| + "/settings.html"

View File

@ -248,12 +248,13 @@ click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
assert-false: "//*[@class='sidebar shown']"
// Also check the focus handling for the help button.
// Also check the focus handling for the settings button.
set-window-size: (1100, 600)
reload:
assert-count: ("//*[@class='tooltip popover']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: ("//*[@class='tooltip popover']", 1)
click: "#help-button a"
click: "#settings-menu a"
wait-for: "#settings"
assert-count: ("//*[@class='tooltip popover']", 0)
assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"

View File

@ -1,6 +1,7 @@
// This test ensures that the "pocket menus" are working as expected.
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
wait-for: "#crate-search"
// First we check that the help menu doesn't exist yet.
assert-false: "#help-button .popover"
// Then we display the help menu.

View File

@ -80,8 +80,8 @@ click: ".scraped-example .button-holder .expand"
store-value: (offset_y, 4)
// First with desktop
assert-position: (".scraped-example", {"y": 226})
assert-position: (".scraped-example .prev", {"y": 226 + |offset_y|})
assert-position: (".scraped-example", {"y": 252})
assert-position: (".scraped-example .prev", {"y": 252 + |offset_y|})
// Gradient background should be at the top of the code block.
assert-css: (".scraped-example .example-wrap::before", {"top": "0px"})
@ -90,8 +90,8 @@ assert-css: (".scraped-example .example-wrap::after", {"bottom": "0px"})
// Then with mobile
set-window-size: (600, 600)
store-size: (".scraped-example .scraped-example-title", {"height": title_height})
assert-position: (".scraped-example", {"y": 284})
assert-position: (".scraped-example .prev", {"y": 284 + |offset_y| + |title_height|})
assert-position: (".scraped-example", {"y": 281})
assert-position: (".scraped-example .prev", {"y": 281 + |offset_y| + |title_height|})
define-function: (
"check_title_and_code_position",

View File

@ -56,7 +56,8 @@ assert-property: ("#crate-search", {"value": "lib2"})
assert-false: "#results .externcrate"
// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
assert-text: (".search-results-title", "Results", STARTS_WITH)
assert-text: (".search-results-title + .sub-heading", " in all crates", STARTS_WITH)
// Checking the display of the crate filter.
// We start with the light theme.
@ -84,6 +85,6 @@ wait-for-css: ("#crate-search", {
click: "#theme-ayu"
wait-for-css: ("#crate-search", {
"border": "1px solid #5c6773",
"color": "#fff",
"color": "#c5c5c5",
"background-color": "#0f1419",
})

View File

@ -1,13 +1,14 @@
// This test ensures that the elements in ".search-form" have the expected display.
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=test"
wait-for: "#search-tabs" // Waiting for the search.js to load.
show-text: true
define-function: (
"check-search-colors",
[
theme, border, background, search_input_color, search_input_border_focus,
menu_button_border, menu_button_a_color, menu_button_a_border_hover, menu_a_color,
menu_button_a_color, menu_button_a_border_hover, menu_a_color,
],
block {
call-function: ("switch-theme", {"theme": |theme|})
@ -29,30 +30,22 @@ define-function: (
"color": |search_input_color|,
},
)
assert-css: (
"#help-button",
{"border-color": |menu_button_border|},
)
assert-css: (
"#help-button > a",
{
"color": |menu_button_a_color|,
"border-color": |border|,
"background-color": |background|,
"border-color": "transparent",
"background-color": "transparent",
},
)
// Hover help button.
move-cursor-to: "#help-button"
assert-css: (
"#help-button:hover",
{"border-color": |menu_button_border|},
)
assert-css: (
"#help-button > a",
{
"color": |menu_button_a_color|,
"border-color": |menu_button_a_border_hover|,
"background-color": |background|,
"background-color": "transparent",
},
)
// Link color inside
@ -63,30 +56,22 @@ define-function: (
"color": |menu_a_color|,
},
)
assert-css: (
"#settings-menu",
{"border-color": |menu_button_border|},
)
assert-css: (
"#settings-menu > a",
{
"color": |menu_button_a_color|,
"border-color": |border|,
"background-color": |background|,
"border-color": "transparent",
"background-color": "transparent",
},
)
// Hover settings menu.
move-cursor-to: "#settings-menu"
assert-css: (
"#settings-menu:hover",
{"border-color": |menu_button_border|},
)
assert-css: (
"#settings-menu:hover > a",
{
"color": |menu_button_a_color|,
"border-color": |menu_button_a_border_hover|,
"background-color": |background|,
"background-color": "transparent",
},
)
},
@ -100,8 +85,7 @@ call-function: (
"background": "#141920",
"search_input_color": "#fff",
"search_input_border_focus": "#5c6773",
"menu_button_border": "#c5c5c5",
"menu_button_a_color": "#fff",
"menu_button_a_color": "#c5c5c5",
"menu_button_a_border_hover": "#e0e0e0",
"menu_a_color": "#39afd7",
}
@ -114,8 +98,7 @@ call-function: (
"background": "#f0f0f0",
"search_input_color": "#111",
"search_input_border_focus": "#008dfd",
"menu_button_border": "#ddd",
"menu_button_a_color": "#000",
"menu_button_a_color": "#ddd",
"menu_button_a_border_hover": "#ffb900",
"menu_a_color": "#d2991d",
}
@ -128,7 +111,6 @@ call-function: (
"background": "#fff",
"search_input_color": "#000",
"search_input_border_focus": "#66afe9",
"menu_button_border": "#000",
"menu_button_a_color": "#000",
"menu_button_a_border_hover": "#717171",
"menu_a_color": "#3873ad",

View File

@ -50,8 +50,11 @@ compare-elements-size-near: (
set-window-size: (900, 900)
// First we check the current width, height and position.
assert-css: ("#crate-search", {"width": "223px"})
assert-css: (".search-results-title", {"height": "50px", "width": "640px"})
assert-css: ("#crate-search", {"width": "159px"})
store-size: (".search-results-title", {
"height": search_results_title_height,
"width": search_results_title_width,
})
assert-css: ("#search", {"width": "640px"})
// Then we update the text of one of the `<option>`.
@ -61,10 +64,12 @@ set-text: (
)
// Then we compare again to confirm the height didn't change.
assert-size: ("#crate-search", {"width": 527})
assert-size: (".search-results-title", {"height": 50, "width": 640})
// And we check that the `<select>` isn't bigger than its container (".search-results-title").
assert-size: ("#crate-search", {"width": 509})
assert-size: (".search-results-title", {
"height": |search_results_title_height|,
})
assert-css: ("#search", {"width": "640px"})
assert: |search_results_title_width| <= 640
// Now checking that the crate filter is working as expected too.
show-text: true

View File

@ -16,4 +16,5 @@ assert-css: ("#main-content", {"display": "none"})
// Now we can check that the feature is working as expected!
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=struct%3AFoo&go_to_first=true"
// Waiting for the page to load...
wait-for-text: (".main-heading h1", "Struct test_docs::FooCopy item path")
wait-for-text: (".main-heading .rustdoc-breadcrumbs", "test_docs")
wait-for-text: (".main-heading h1", "Struct FooCopy item path")

View File

@ -11,8 +11,8 @@ define-function: (
call-function: ("switch-theme", {"theme": |theme|})
assert-css: ("#settings-menu > a::before", {
"filter": |filter|,
"width": "22px",
"height": "22px",
"width": "18px",
"height": "18px",
})
}
)
@ -23,9 +23,9 @@ call-function: ("check-image", {
})
call-function: ("check-image", {
"theme": "dark",
"filter": "none",
"filter": "invert(0.65)",
})
call-function: ("check-image", {
"theme": "light",
"filter": "none",
"filter": "invert(0.35)",
})

View File

@ -305,6 +305,7 @@ wait-for-css: ("#help-button .popover", {"display": "block"})
// Now we go to the settings page to check that the CSS is loaded as expected.
go-to: "file://" + |DOC_PATH| + "/settings.html"
wait-for: "#settings"
assert-false: "#settings-menu"
assert-css: (".setting-radio", {"cursor": "pointer"})
assert-attribute-false: ("#settings", {"class": "popover"}, CONTAINS)
@ -324,6 +325,5 @@ javascript: true
show-text: true
reload:
set-window-size: (300, 1000)
click: "#settings-menu"
wait-for: "#settings"
assert-css: (".setting-radio", {"cursor": "pointer"})

View File

@ -13,19 +13,19 @@ press-key: "Escape"
assert-css: ("#help-button .popover", {"display": "none"})
// Checking doc collapse and expand.
// It should be displaying a "-":
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
press-key: "-"
wait-for-text: ("#toggle-all-docs", "[+]")
wait-for-text: ("#toggle-all-docs", "Show all")
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
// Pressing it again shouldn't do anything.
press-key: "-"
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-attribute: ("#toggle-all-docs", {"class": "will-expand"})
// Expanding now.
press-key: "+"
wait-for-text: ("#toggle-all-docs", "[]")
wait-for-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#toggle-all-docs", {"class": ""})
// Pressing it again shouldn't do anything.
press-key: "+"
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#toggle-all-docs", {"class": ""})

View File

@ -141,7 +141,7 @@ click: "#sidebar-button"
wait-for-css: (".src .sidebar > *", {"visibility": "hidden"})
// We scroll to line 117 to change the scroll position.
scroll-to: '//*[@id="117"]'
store-value: (y_offset, "2493")
store-value: (y_offset, "2564")
assert-window-property: {"pageYOffset": |y_offset|}
// Expanding the sidebar...
click: "#sidebar-button"

View File

@ -160,12 +160,12 @@ click: "//ul[@class='block mod']/preceding-sibling::h3/a"
// PAGE: index.html
assert-css: ("#modules", {"background-color": "#fdffd3"})
// Finally, assert that the `[+]/[]` toggle doesn't affect sidebar width.
// Finally, assert that the Summary toggle doesn't affect sidebar width.
click: "#toggle-all-docs"
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-property: (".sidebar", {"clientWidth": "200"})
click: "#toggle-all-docs"
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-property: (".sidebar", {"clientWidth": "200"})
// Checks that all.html and index.html have their sidebar link in the same place.

View File

@ -8,13 +8,13 @@ set-window-size: (600, 800)
assert-property: ("html", {"scrollTop": "0"})
click: '//a[text() = "barbar" and @href="#5-7"]'
assert-property: ("html", {"scrollTop": "123"})
assert-property: ("html", {"scrollTop": "194"})
click: '//a[text() = "bar" and @href="#28-36"]'
assert-property: ("html", {"scrollTop": "154"})
assert-property: ("html", {"scrollTop": "225"})
click: '//a[normalize-space() = "sub_fn" and @href="#2-4"]'
assert-property: ("html", {"scrollTop": "51"})
assert-property: ("html", {"scrollTop": "122"})
// We now check that clicking on lines doesn't change the scroll
// Extra information: the "sub_fn" function header is on line 1.
click: '//*[@id="6"]'
assert-property: ("html", {"scrollTop": "51"})
assert-property: ("html", {"scrollTop": "122"})

View File

@ -89,9 +89,9 @@ assert-css: (".src-line-numbers", {"text-align": "right"})
// do anything (and certainly not add a `#NaN` to the URL!).
go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// We use this assert-position to know where we will click.
assert-position: ("//*[@id='1']", {"x": 88, "y": 86})
assert-position: ("//*[@id='1']", {"x": 88, "y": 163})
// We click on the left of the "1" anchor but still in the "src-line-number" `<pre>`.
click: (87, 77)
click: (163, 77)
assert-document-property: ({"URL": "/lib.rs.html"}, ENDS_WITH)
// Checking the source code sidebar.
@ -159,19 +159,21 @@ call-function: ("check-sidebar-dir-entry", {
// Check the search form
assert-css: ("nav.sub", {"flex-direction": "row"})
// The goal of this test is to ensure the search input is perfectly centered
// between the top of the page and the top of the gray code block.
// between the top of the page and the header.
// To check this, we maintain the invariant:
//
// offsetTop[nav.sub form] = offsetTop[#main-content] - offsetHeight[nav.sub form] - offsetTop[nav.sub form]
assert-property: ("nav.sub form", {"offsetTop": 15, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 64})
assert-position: ("nav.sub form", {"y": 15})
assert-property: ("nav.sub form", {"offsetHeight": 34})
assert-position: ("h1", {"y": 64})
// 15 = 64 - 34 - 15
// Now do the same check on moderately-sized, tablet mobile.
set-window-size: (700, 700)
assert-css: ("nav.sub", {"flex-direction": "row"})
assert-property: ("nav.sub form", {"offsetTop": 8, "offsetHeight": 34})
assert-property: ("#main-content", {"offsetTop": 50})
assert-position: ("nav.sub form", {"y": 8})
assert-property: ("nav.sub form", {"offsetHeight": 34})
assert-position: ("h1", {"y": 50})
// 8 = 50 - 34 - 8
// Check the sidebar directory entries have a marker and spacing (tablet).

View File

@ -52,6 +52,8 @@
--search-tab-button-selected-border-top-color: #0089ff;
--search-tab-button-selected-background: #fff;
--settings-menu-filter: none;
--settings-menu-hover-filter: invert(35%);
--settings-menu-disabled-filter: invert(14%) sepia(11%) saturate(14%) hue-rotate(337deg);
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--code-highlight-kw-color: #8959a8;

View File

@ -12,4 +12,5 @@ assert-attribute-false: (".impl-items .toggle", {"open": ""})
// Click the "Trait" part of "impl Trait" and verify it navigates.
click: "#impl-Trait-for-Foo h3 a:first-of-type"
assert-text: (".main-heading h1", "Trait lib2::TraitCopy item path")
assert-text: (".main-heading .rustdoc-breadcrumbs", "lib2")
assert-text: (".main-heading h1", "Trait TraitCopy item path")

View File

@ -3,12 +3,12 @@
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
set-window-size: (433, 600)
assert-attribute: (".top-doc", {"open": ""})
click: (4, 270) // This is the position of the top doc comment toggle
click: (4, 260) // This is the position of the top doc comment toggle
assert-attribute-false: (".top-doc", {"open": ""})
click: (4, 270)
click: (4, 260)
assert-attribute: (".top-doc", {"open": ""})
// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
click: (3, 270)
click: (3, 260)
assert-attribute: (".top-doc", {"open": ""})
// Assert the position of the toggle on the top doc block.
@ -24,10 +24,10 @@ assert-position: (
// Now we do the same but with a little bigger width
set-window-size: (600, 600)
assert-attribute: (".top-doc", {"open": ""})
click: (4, 270) // New Y position since all search elements are back on one line.
click: (4, 260) // New Y position since all search elements are back on one line.
assert-attribute-false: (".top-doc", {"open": ""})
click: (4, 270)
click: (4, 260)
assert-attribute: (".top-doc", {"open": ""})
// To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
click: (3, 270)
click: (3, 260)
assert-attribute: (".top-doc", {"open": ""})

View File

@ -2,12 +2,12 @@
include: "utils.goml"
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
assert-attribute: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
click: "#toggle-all-docs"
wait-for: 50
// This is now collapsed so there shouldn't be the "open" attribute on details.
assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[+]")
assert-text: ("#toggle-all-docs", "Show all")
assert-css: (
"#main-content > details.top-doc > summary",
{"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'},
@ -15,12 +15,12 @@ assert-css: (
click: "#toggle-all-docs"
// Not collapsed anymore so the "open" attribute should be back.
wait-for-attribute: ("#main-content > details.top-doc", {"open": ""})
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
// Check that it works on non-module pages as well.
go-to: "file://" + |DOC_PATH| + "/test_docs/struct.Foo.html"
// We first check that everything is visible.
assert-text: ("#toggle-all-docs", "[]")
assert-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("#implementations-list details.toggle", {"open": ""}, ALL)
assert-attribute: ("#trait-implementations-list details.toggle", {"open": ""}, ALL)
assert-attribute-false: (
@ -31,7 +31,7 @@ assert-attribute-false: (
// We collapse them all.
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[+]")
wait-for-text: ("#toggle-all-docs", "Show all")
// We check that all <details> are collapsed (except for the impl block ones).
assert-attribute-false: ("details.toggle:not(.implementors-toggle)", {"open": ""}, ALL)
assert-attribute: ("#implementations-list > details.implementors-toggle", {"open": ""})
@ -43,7 +43,7 @@ assert-attribute-false: (
)
// We open them all again.
click: "#toggle-all-docs"
wait-for-text: ("#toggle-all-docs", "[]")
wait-for-text: ("#toggle-all-docs", "Summary")
assert-attribute: ("details.toggle", {"open": ""}, ALL)
// Checking the toggles style.

View File

@ -51,22 +51,23 @@ store-property: (".mobile-topbar", {"scrollWidth": scrollWidth})
assert-property: (".mobile-topbar", {"clientWidth": |scrollWidth|})
assert-css: (".mobile-topbar h2", {"overflow-x": "hidden"})
// Check wrapping for top main-heading h1 and out-of-band.
// On desktop, they wrap when too big.
// Check that main heading and toolbar go side-by-side, both on desktop and on mobile.
set-window-size: (1100, 800)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position: (".main-heading h1", ".main-heading .out-of-band", ["y"])
// make sure there is a gap between them
compare-elements-position-near-false: (".main-heading h1", ".main-heading .out-of-band", {"x": 550})
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 550})
// On mobile, they always wrap.
set-window-size: (600, 600)
go-to: "file://" + |DOC_PATH| + "/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
go-to: "file://" + |DOC_PATH| + "/lib2/index.html"
compare-elements-position-false: (".main-heading h1", ".main-heading .out-of-band", ["y"])
compare-elements-position: (".main-heading h1", ".main-heading rustdoc-toolbar", ["y"])
compare-elements-position-near-false: (".main-heading h1", ".main-heading rustdoc-toolbar", {"x": 200})
// Now we will check that the scrolling is working.
// First on an item with "hidden methods".

View File

@ -2,15 +2,18 @@
//@ has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
//@ hasraw 'empty_mod_private/sidebar-items.js' 'foo'
//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module empty_mod_private::foo'
//@ matches 'empty_mod_private/foo/index.html' '//h1' 'Module foo'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
mod foo {}
//@ has 'empty_mod_private/index.html' '//a[@href="bar/index.html"]' 'bar'
//@ hasraw 'empty_mod_private/sidebar-items.js' 'bar'
//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module empty_mod_private::bar'
//@ matches 'empty_mod_private/bar/index.html' '//h1' 'Module bar'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private'
mod bar {
//@ has 'empty_mod_private/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
//@ hasraw 'empty_mod_private/bar/sidebar-items.js' 'baz'
//@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module empty_mod_private::bar::baz'
//@ matches 'empty_mod_private/bar/baz/index.html' '//h1' 'Module baz'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_private::bar'
mod baz {}
}

View File

@ -1,14 +1,17 @@
//@ has 'empty_mod_public/index.html' '//a[@href="foo/index.html"]' 'foo'
//@ hasraw 'empty_mod_public/sidebar-items.js' 'foo'
//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module empty_mod_public::foo'
//@ matches 'empty_mod_public/foo/index.html' '//h1' 'Module foo'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
pub mod foo {}
//@ has 'empty_mod_public/index.html' '//a[@href="bar/index.html"]' 'bar'
//@ hasraw 'empty_mod_public/sidebar-items.js' 'bar'
//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module empty_mod_public::bar'
//@ matches 'empty_mod_public/bar/index.html' '//h1' 'Module bar'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public'
pub mod bar {
//@ has 'empty_mod_public/bar/index.html' '//a[@href="baz/index.html"]' 'baz'
//@ hasraw 'empty_mod_public/bar/sidebar-items.js' 'baz'
//@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module empty_mod_public::bar::baz'
//@ matches 'empty_mod_public/bar/baz/index.html' '//h1' 'Module baz'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'empty_mod_public::bar'
pub mod baz {}
}

View File

@ -11,14 +11,14 @@
//@ files 'src/foo' '[]'
//@ has foo/fn.foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub fn foo() {}
//@ has foo/struct.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub struct Bar;

View File

@ -10,15 +10,19 @@ extern crate foo;
//@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
//@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
//@ has foo/iter/struct.DeprecatedStepBy.html
//@ has - '//h1' "Struct foo::iter::DeprecatedStepBy"
//@ has - '//h1' "Struct DeprecatedStepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
//@ has foo/iter/struct.StepBy.html
//@ has - '//h1' "Struct foo::iter::StepBy"
//@ has - '//h1' "Struct StepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo::iter'
//@ has bar/iter/index.html
//@ has - '//a/[@href="struct.DeprecatedStepBy.html"]' "DeprecatedStepBy"
//@ has - '//a/[@href="struct.StepBy.html"]' "StepBy"
//@ has bar/iter/struct.DeprecatedStepBy.html
//@ has - '//h1' "Struct bar::iter::DeprecatedStepBy"
//@ has - '//h1' "Struct DeprecatedStepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
//@ has bar/iter/struct.StepBy.html
//@ has - '//h1' "Struct bar::iter::StepBy"
//@ has - '//h1' "Struct StepBy"
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'bar::iter'
pub use foo::iter;

View File

@ -6,7 +6,6 @@
//@ has foo/index.html '//a[@href="keyword.match.html"]' 'match'
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords'
//@ has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords'
//@ has foo/keyword.match.html '//a[@class="keyword"]' 'match'
//@ has foo/keyword.match.html '//h1' 'Keyword match'
//@ has foo/keyword.match.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has foo/index.html '//a/@href' '../foo/index.html'

View File

@ -8,7 +8,6 @@
//@ has - '//div[@class="sidebar-elems"]//li/a' 'Primitive Types'
//@ has - '//div[@class="sidebar-elems"]//li/a/@href' '#primitives'
//@ has foo/primitive.reference.html
//@ has - '//a[@class="primitive"]' 'reference'
//@ has - '//h1' 'Primitive Type reference'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
//@ has - '//h1' 'Primitive Type slice'
//@ has foo/primitive.slice.html '//h1' 'Primitive Type slice'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T]where T: Send'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.tuple.html '//a[@class="primitive"]' 'tuple'
//@ has - '//h1' 'Primitive Type tuple'
//@ has foo/primitive.tuple.html '//h1' 'Primitive Type tuple'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'Send'

View File

@ -3,8 +3,7 @@
#![crate_name = "foo"]
#![feature(rustc_attrs)]
//@ has foo/primitive.unit.html '//a[@class="primitive"]' 'unit'
//@ has - '//h1' 'Primitive Type unit'
//@ has foo/primitive.unit.html '//h1' 'Primitive Type unit'
//@ has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
//@ has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
//@ has - '//div[@id="synthetic-implementations-list"]//h3' 'impl Send for ()'

View File

@ -3,7 +3,7 @@
#![feature(staged_api)]
//@ has foo/trait.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub trait Bar {
//@ has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0.0 · source'
@ -14,7 +14,7 @@ pub trait Bar {
//@ has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0.0 · source'
//@ has foo/struct.Foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "baz", since = "1.0")]
pub struct Foo;

View File

@ -5,53 +5,65 @@
//@ matches 'foo/index.html' '//div[@class="sidebar-crate"]/h2/a' 'foo'
//@ count 'foo/index.html' '//h2[@class="location"]' 0
//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
//@ matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
//@ matches 'foo/foo_mod/index.html' '//h1' 'Module foo_mod'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'Module foo_mod'
pub mod foo_mod {
pub struct __Thing {}
}
extern "C" {
//@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo::foo_ffn'
//@ matches 'foo/fn.foo_ffn.html' '//h1' 'Function foo_ffn'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub fn foo_ffn();
}
//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo::foo_fn'
//@ matches 'foo/fn.foo_fn.html' '//h1' 'Function foo_fn'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub fn foo_fn() {}
//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
//@ matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
//@ matches 'foo/trait.FooTrait.html' '//h1' 'Trait FooTrait'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooTrait'
pub trait FooTrait {}
//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
//@ matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
//@ matches 'foo/struct.FooStruct.html' '//h1' 'Struct FooStruct'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooStruct'
pub struct FooStruct;
//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
//@ matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
//@ matches 'foo/enum.FooEnum.html' '//h1' 'Enum FooEnum'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooEnum'
pub enum FooEnum {}
//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias foo::FooType'
//@ matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
//@ matches 'foo/type.FooType.html' '//h1' 'Type Alias FooType'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
//@ matches - '//h2[@class="location"]' 'FooType'
pub type FooType = FooStruct;
//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
//@ matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo_macro'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
#[macro_export]
macro_rules! foo_macro {
() => {};
}
//@ matches 'foo/primitive.bool.html' '//h1' 'Primitive Type bool'
//@ count - '//*[@class="rustdoc-breadcrumbs"]' 0
#[rustc_doc_primitive = "bool"]
mod bool {}
//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static foo::FOO_STATIC'
//@ matches 'foo/static.FOO_STATIC.html' '//h1' 'Static FOO_STATIC'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub static FOO_STATIC: FooStruct = FooStruct;
extern "C" {
//@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static foo::FOO_FSTATIC'
//@ matches 'foo/static.FOO_FSTATIC.html' '//h1' 'Static FOO_FSTATIC'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub static FOO_FSTATIC: FooStruct;
}
//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant foo::FOO_CONSTANT'
//@ matches 'foo/constant.FOO_CONSTANT.html' '//h1' 'Constant FOO_CONSTANT'
//@ matches - '//*[@class="rustdoc-breadcrumbs"]' 'foo'
pub const FOO_CONSTANT: FooStruct = FooStruct;

View File

@ -4,14 +4,14 @@
#![crate_name = "foo"]
//@ has foo/fn.foo.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub fn foo() {}
//@ has foo/struct.Bar.html
//@ has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · '
//@ !has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0.0 · source · '
//@ has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0'
//@ !has - '//div[@class="main-heading"]/*[@class="sub-heading"]' '1.0.0 · source'
#[stable(feature = "bar", since = "1.0")]
pub struct Bar;