Skip to content

rustdoc: use javascript to layout notable traits popups #104129

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Nov 11, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions src/librustdoc/html/format.rs
Original file line number Diff line number Diff line change
@@ -107,10 +107,6 @@ impl Buffer {
self.buffer
}

pub(crate) fn insert_str(&mut self, idx: usize, s: &str) {
self.buffer.insert_str(idx, s);
}

pub(crate) fn push_str(&mut self, s: &str) {
self.buffer.push_str(s);
}
7 changes: 6 additions & 1 deletion src/librustdoc/html/render/context.rs
Original file line number Diff line number Diff line change
@@ -69,11 +69,13 @@ pub(crate) struct Context<'tcx> {
/// the source files are present in the html rendering, then this will be
/// `true`.
pub(crate) include_sources: bool,
/// Collection of all types with notable traits referenced in the current module.
pub(crate) types_with_notable_traits: FxHashSet<clean::Type>,
}

// `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
#[cfg(all(not(windows), target_arch = "x86_64", target_pointer_width = "64"))]
rustc_data_structures::static_assert_size!(Context<'_>, 128);
rustc_data_structures::static_assert_size!(Context<'_>, 160);

/// Shared mutable state used in [`Context`] and elsewhere.
pub(crate) struct SharedContext<'tcx> {
@@ -532,6 +534,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
deref_id_map: FxHashMap::default(),
shared: Rc::new(scx),
include_sources,
types_with_notable_traits: FxHashSet::default(),
};

if emit_crate {
@@ -560,6 +563,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
id_map: IdMap::new(),
shared: Rc::clone(&self.shared),
include_sources: self.include_sources,
types_with_notable_traits: FxHashSet::default(),
}
}

@@ -803,6 +807,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
}
}
}

Ok(())
}

195 changes: 122 additions & 73 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ use rustc_span::{
symbol::{sym, Symbol},
BytePos, FileName, RealFileName,
};
use serde::ser::SerializeSeq;
use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Serialize, Serializer};

use crate::clean::{self, ItemId, RenderedLink, SelfTy};
@@ -803,7 +803,7 @@ fn assoc_method(
d: &clean::FnDecl,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
cx: &mut Context<'_>,
render_mode: RenderMode,
) {
let tcx = cx.tcx();
@@ -836,6 +836,8 @@ fn assoc_method(
+ name.as_str().len()
+ generics_len;

let notable_traits = d.output.as_return().and_then(|output| notable_traits_button(output, cx));

let (indent, indent_str, end_newline) = if parent == ItemType::Trait {
header_len += 4;
let indent_str = " ";
@@ -861,9 +863,9 @@ fn assoc_method(
name = name,
generics = g.print(cx),
decl = d.full_print(header_len, indent, cx),
notable_traits = notable_traits_decl(d, cx),
notable_traits = notable_traits.unwrap_or_default(),
where_clause = print_where_clause(g, cx, indent, end_newline),
)
);
}

/// Writes a span containing the versions at which an item became stable and/or const-stable. For
@@ -963,7 +965,7 @@ fn render_assoc_item(
item: &clean::Item,
link: AssocItemLink<'_>,
parent: ItemType,
cx: &Context<'_>,
cx: &mut Context<'_>,
render_mode: RenderMode,
) {
match &*item.kind {
@@ -1273,88 +1275,135 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
}
}

fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
let mut out = Buffer::html();
pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> Option<String> {
let mut has_notable_trait = false;

let did = ty.def_id(cx.cache())?;

if let Some((did, ty)) = decl.output.as_return().and_then(|t| Some((t.def_id(cx.cache())?, t)))
// Box has pass-through impls for Read, Write, Iterator, and Future when the
// boxed type implements one of those. We don't want to treat every Box return
// as being notably an Iterator (etc), though, so we exempt it. Pin has the same
// issue, with a pass-through impl for Future.
if Some(did) == cx.tcx().lang_items().owned_box()
|| Some(did) == cx.tcx().lang_items().pin_type()
{
// Box has pass-through impls for Read, Write, Iterator, and Future when the
// boxed type implements one of those. We don't want to treat every Box return
// as being notably an Iterator (etc), though, so we exempt it. Pin has the same
// issue, with a pass-through impl for Future.
if Some(did) == cx.tcx().lang_items().owned_box()
|| Some(did) == cx.tcx().lang_items().pin_type()
{
return "".to_string();
}
if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache())
return None;
}

if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
// Two different types might have the same did,
// without actually being the same.
continue;
}
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();

if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx()))
{
// Two different types might have the same did,
// without actually being the same.
continue;
has_notable_trait = true;
}
}
}
}

if has_notable_trait {
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
"<span class=\"notable-traits\" data-ty=\"{ty}\">\
<span class=\"notable-traits-tooltip\">ⓘ</span>\
</span>",
ty = Escape(&format!("{:#}", ty.print(cx))),
))
} else {
None
}
}

fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) {
let mut out = Buffer::html();

let did = ty.def_id(cx.cache()).expect("notable_traits_button already checked this");

let impls = cx.cache().impls.get(&did).expect("notable_traits_button already checked this");

for i in impls {
let impl_ = i.inner_impl();
if !impl_.for_.without_borrowed_ref().is_same(ty.without_borrowed_ref(), cx.cache()) {
// Two different types might have the same did,
// without actually being the same.
continue;
}
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();

if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) {
if out.is_empty() {
write!(
&mut out,
"<h3 class=\"notable\">Notable traits for <code>{}</code></h3>\
<pre class=\"content\"><code>",
impl_.for_.print(cx)
);
}
if let Some(trait_) = &impl_.trait_ {
let trait_did = trait_.def_id();

if cx
.cache()
.traits
.get(&trait_did)
.map_or(false, |t| t.is_notable_trait(cx.tcx()))
{
if out.is_empty() {
write!(
&mut out,
"<span class=\"notable\">Notable traits for {}</span>\
<code class=\"content\">",
impl_.for_.print(cx)
);
}

//use the "where" class here to make it small
write!(
//use the "where" class here to make it small
write!(
&mut out,
"<span class=\"where fmt-newline\">{}</span>",
impl_.print(false, cx)
);
for it in &impl_.items {
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
let empty_set = FxHashSet::default();
let src_link = AssocItemLink::GotoSource(trait_did.into(), &empty_set);
assoc_type(
&mut out,
"<span class=\"where fmt-newline\">{}</span>",
impl_.print(false, cx)
it,
&tydef.generics,
&[], // intentionally leaving out bounds
Some(&tydef.type_),
src_link,
0,
cx,
);
for it in &impl_.items {
if let clean::AssocTypeItem(ref tydef, ref _bounds) = *it.kind {
out.push_str("<span class=\"where fmt-newline\"> ");
let empty_set = FxHashSet::default();
let src_link =
AssocItemLink::GotoSource(trait_did.into(), &empty_set);
assoc_type(
&mut out,
it,
&tydef.generics,
&[], // intentionally leaving out bounds
Some(&tydef.type_),
src_link,
0,
cx,
);
out.push_str(";</span>");
}
}
out.push_str(";</span>");
}
}
}
}
}

if !out.is_empty() {
out.insert_str(
0,
"<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
<span class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
);
out.push_str("</code></span></span></span></span>");
if out.is_empty() {
write!(&mut out, "</code></pre>",);
}

out.into_inner()
(format!("{:#}", ty.print(cx)), out.into_inner())
}

pub(crate) fn notable_traits_json<'a>(
tys: impl Iterator<Item = &'a clean::Type>,
cx: &Context<'_>,
) -> String {
let mut mp: Vec<(String, String)> = tys.map(|ty| notable_traits_decl(ty, cx)).collect();
mp.sort_by(|(name1, _html1), (name2, _html2)| name1.cmp(name2));
struct NotableTraitsMap(Vec<(String, String)>);
impl Serialize for NotableTraitsMap {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut map = serializer.serialize_map(Some(self.0.len()))?;
for item in &self.0 {
map.serialize_entry(&item.0, &item.1)?;
}
map.end()
}
}
serde_json::to_string(&NotableTraitsMap(mp))
.expect("serialize (string, string) -> json object cannot fail")
}

#[derive(Clone, Copy, Debug)]
24 changes: 19 additions & 5 deletions src/librustdoc/html/render/print_item.rs
Original file line number Diff line number Diff line change
@@ -17,9 +17,10 @@ use std::rc::Rc;

use super::{
collect_paths_for_type, document, ensure_trailing_slash, get_filtered_impls_for_reference,
item_ty_to_section, notable_traits_decl, render_all_impls, render_assoc_item,
render_assoc_items, render_attributes_in_code, render_attributes_in_pre, render_impl,
render_rightside, render_stability_since_raw, AssocItemLink, Context, ImplRenderingParameters,
item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
render_impl, render_rightside, render_stability_since_raw, AssocItemLink, Context,
ImplRenderingParameters,
};
use crate::clean;
use crate::config::ModuleSorting;
@@ -183,6 +184,16 @@ pub(super) fn print_item(
unreachable!();
}
}

// Render notable-traits.js used for all methods in this module.
if !cx.types_with_notable_traits.is_empty() {
write!(
buf,
r#"<script type="text/json" id="notable-traits-data">{}</script>"#,
notable_traits_json(cx.types_with_notable_traits.iter(), cx)
);
cx.types_with_notable_traits.clear();
}
}

/// For large structs, enums, unions, etc, determine whether to hide their fields
@@ -516,6 +527,9 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
+ name.as_str().len()
+ generics_len;

let notable_traits =
f.decl.output.as_return().and_then(|output| notable_traits_button(output, cx));

wrap_into_item_decl(w, |w| {
wrap_item(w, "fn", |w| {
render_attributes_in_pre(w, it, "");
@@ -533,11 +547,11 @@ fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &cle
generics = f.generics.print(cx),
where_clause = print_where_clause(&f.generics, cx, 0, Ending::Newline),
decl = f.decl.full_print(header_len, 0, cx),
notable_traits = notable_traits_decl(&f.decl, cx),
notable_traits = notable_traits.unwrap_or_default(),
);
});
});
document(w, cx, it, None, HeadingOffset::H2)
document(w, cx, it, None, HeadingOffset::H2);
}

fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) {
6 changes: 6 additions & 0 deletions src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
@@ -22,3 +22,9 @@ nav.sub {
.source .sidebar {
display: none;
}

.notable-traits {
/* layout requires javascript
https://github.com/rust-lang/rust/issues/102576 */
display: none;
}
23 changes: 14 additions & 9 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
@@ -183,6 +183,8 @@ h4.code-header {
font-weight: 600;
margin: 0;
padding: 0;
/* position notable traits in mobile mode within the header */
position: relative;
}

#crate-search,
@@ -1268,13 +1270,12 @@ h3.variant {
cursor: pointer;
}

.notable-traits:hover .notable-traits-tooltiptext,
.notable-traits .notable-traits-tooltiptext.force-tooltip {
.notable-traits .notable-traits-tooltiptext {
display: inline-block;
visibility: hidden;
}

.notable-traits .notable-traits-tooltiptext {
display: none;
.notable-traits-tooltiptext {
padding: 5px 3px 3px 3px;
border-radius: 6px;
margin-left: 5px;
@@ -1292,22 +1293,26 @@ h3.variant {
content: "\00a0\00a0\00a0";
}

.notable-traits .docblock {
.notable-traits-tooltiptext .docblock {
margin: 0;
}

.notable-traits .notable {
margin: 0;
margin-bottom: 13px;
.notable-traits-tooltiptext .notable {
font-size: 1.1875rem;
font-weight: 600;
display: block;
}

.notable-traits .docblock code.content {
.notable-traits-tooltiptext pre, .notable-traits-tooltiptext code {
background: transparent;
}

.notable-traits-tooltiptext .docblock pre.content {
margin: 0;
padding: 0;
font-size: 1.25rem;
white-space: pre-wrap;
overflow: hidden;
}

.search-failed {
87 changes: 85 additions & 2 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
@@ -790,6 +790,19 @@ function loadCss(cssUrl) {
// we need to switch away from mobile mode and make the main content area scrollable.
hideSidebar();
}
if (window.CURRENT_NOTABLE_ELEMENT) {
// As a workaround to the behavior of `contains: layout` used in doc togglers, the
// notable traits popup is positioned using javascript.
//
// This means when the window is resized, we need to redo the layout.
const base = window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE;
const force_visible = base.NOTABLE_FORCE_VISIBLE;
hideNotable();
if (force_visible) {
showNotable(base);
base.NOTABLE_FORCE_VISIBLE = true;
}
}
});

function handleClick(id, f) {
@@ -822,10 +835,80 @@ function loadCss(cssUrl) {
});
});

function showNotable(e) {
if (!window.NOTABLE_TRAITS) {
const data = document.getElementById("notable-traits-data");
if (data) {
window.NOTABLE_TRAITS = JSON.parse(data.innerText);
} else {
throw new Error("showNotable() called on page without any notable traits!");
}
}
if (window.CURRENT_NOTABLE_ELEMENT && window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE === e) {
// Make this function idempotent.
return;
}
hideNotable();
const ty = e.getAttribute("data-ty");
const tooltip = e.getElementsByClassName("notable-traits-tooltip")[0];
const wrapper = document.createElement("div");
wrapper.innerHTML = "<div class=\"docblock\">" + window.NOTABLE_TRAITS[ty] + "</div>";
wrapper.className = "notable-traits-tooltiptext";
tooltip.appendChild(wrapper);
const pos = wrapper.getBoundingClientRect();
tooltip.removeChild(wrapper);
wrapper.style.top = (pos.top + window.scrollY) + "px";
wrapper.style.left = (pos.left + window.scrollX) + "px";
wrapper.style.width = pos.width + "px";
const body = document.getElementsByTagName("body")[0];
body.appendChild(wrapper);
window.CURRENT_NOTABLE_ELEMENT = wrapper;
window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE = e;
wrapper.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
if (!e.NOTABLE_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
hideNotable();
}
};
}

function hideNotable() {
if (window.CURRENT_NOTABLE_ELEMENT) {
window.CURRENT_NOTABLE_ELEMENT.NOTABLE_BASE.NOTABLE_FORCE_VISIBLE = false;
const body = document.getElementsByTagName("body")[0];
body.removeChild(window.CURRENT_NOTABLE_ELEMENT);
window.CURRENT_NOTABLE_ELEMENT = null;
}
}

onEachLazy(document.getElementsByClassName("notable-traits"), e => {
e.onclick = function() {
this.getElementsByClassName("notable-traits-tooltiptext")[0]
.classList.toggle("force-tooltip");
this.NOTABLE_FORCE_VISIBLE = this.NOTABLE_FORCE_VISIBLE ? false : true;
if (window.CURRENT_NOTABLE_ELEMENT && !this.NOTABLE_FORCE_VISIBLE) {
hideNotable();
} else {
showNotable(this);
}
};
e.onpointerenter = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
showNotable(this);
};
e.onpointerleave = function(ev) {
// If this is a synthetic touch event, ignore it. A click event will be along shortly.
if (ev.pointerType !== "mouse") {
return;
}
if (!this.NOTABLE_FORCE_VISIBLE &&
!elemIsInParent(event.relatedTarget, window.CURRENT_NOTABLE_ELEMENT)) {
hideNotable();
}
};
});

102 changes: 93 additions & 9 deletions src/test/rustdoc-gui/notable-trait.goml
Original file line number Diff line number Diff line change
@@ -25,22 +25,28 @@ assert-position: (
{"x": 951},
)
// The tooltip should be beside the `i`
// Also, clicking the tooltip should bring its text into the DOM
assert-count: ("//*[@class='notable-traits-tooltiptext']", 0)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable-traits-tooltiptext']", 1)
compare-elements-position-near: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
"//*[@class='notable-traits-tooltiptext']",
{"y": 2}
)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
"//*[@class='notable-traits-tooltiptext']",
("x")
)
// The docblock should be flush with the border.
assert-css: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
"//*[@class='notable-traits-tooltiptext']/*[@class='docblock']",
{"margin-left": "0px"}
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='notable-traits-tooltiptext']", 0)

// Now only the `i` should be on the next line.
size: (1055, 600)
@@ -98,26 +104,31 @@ assert-position: (
{"x": 289},
)
// The tooltip should be below `i`
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
assert-count: ("//*[@class='notable-traits-tooltiptext']", 1)
compare-elements-position-near-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
"//*[@class='notable-traits-tooltiptext']",
{"y": 2}
)
compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
"//*[@class='notable-traits-tooltiptext']",
("x")
)
compare-elements-position-near: (
"//*[@id='method.create_an_iterator_from_read']/parent::*",
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
{"x": 5}
"//*[@id='method.create_an_iterator_from_read']",
"//*[@class='notable-traits-tooltiptext']",
{"x": 10}
)
// The docblock should be flush with the border.
assert-css: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
"//*[@class='notable-traits-tooltiptext']/*[@class='docblock']",
{"margin-left": "0px"}
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='notable-traits-tooltiptext']", 0)

// Checking on very small mobile. The `i` should be on its own line.
size: (365, 600)
@@ -126,3 +137,76 @@ compare-elements-position-false: (
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
("y", "x"),
)

// Now check the colors.
define-function: (
"check-colors",
(theme, header_color, content_color, type_color, trait_color),
[
("goto", "file://" + |DOC_PATH| + "/test_docs/struct.NotableStructWithLongName.html"),
// This is needed to ensure that the text color is computed.
("show-text", true),

// Setting the theme.
("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
// We reload the page so the local storage settings are being used.
("reload"),

("move-cursor-to", "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"),
("assert-count", (".notable-traits-tooltiptext", 1)),

("assert-css", (
".notable-traits-tooltiptext h3.notable",
{"color": |header_color|},
ALL,
)),
("assert-css", (
".notable-traits-tooltiptext pre.content",
{"color": |content_color|},
ALL,
)),
("assert-css", (
".notable-traits-tooltiptext pre.content a.struct",
{"color": |type_color|},
ALL,
)),
("assert-css", (
".notable-traits-tooltiptext pre.content a.trait",
{"color": |trait_color|},
ALL,
)),
]
)

call-function: (
"check-colors",
{
"theme": "ayu",
"content_color": "rgb(230, 225, 207)",
"header_color": "rgb(255, 255, 255)",
"type_color": "rgb(255, 160, 165)",
"trait_color": "rgb(57, 175, 215)",
},
)

call-function: (
"check-colors",
{
"theme": "dark",
"content_color": "rgb(221, 221, 221)",
"header_color": "rgb(221, 221, 221)",
"type_color": "rgb(45, 191, 184)",
"trait_color": "rgb(183, 140, 242)",
},
)

call-function: (
"check-colors",
{
"theme": "light",
"content_color": "rgb(0, 0, 0)",
"header_color": "rgb(0, 0, 0)",
"type_color": "rgb(173, 55, 138)",
"trait_color": "rgb(110, 79, 201)",
},
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"&amp;'static [SomeStruct]":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_slice::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &amp;amp;[&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait_slice::SomeStruct\"&gt;SomeStruct&lt;/a&gt;]&lt;/span&gt;"}</script>
4 changes: 2 additions & 2 deletions src/test/rustdoc/doc-notable_trait-slice.rs
Original file line number Diff line number Diff line change
@@ -8,13 +8,13 @@ pub struct OtherStruct;
impl SomeTrait for &[SomeStruct] {}

// @has doc_notable_trait_slice/fn.bare_fn_matches.html
// @has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
// @snapshot bare_fn_matches - '//script[@id="notable-traits-data"]'
pub fn bare_fn_matches() -> &'static [SomeStruct] {
&[]
}

// @has doc_notable_trait_slice/fn.bare_fn_no_matches.html
// @!has - '//code[@class="content"]' 'impl SomeTrait for &[SomeStruct]'
// @count - '//script[@id="notable-traits-data"]' 0
pub fn bare_fn_no_matches() -> &'static [OtherStruct] {
&[]
}
1 change: 1 addition & 0 deletions src/test/rustdoc/doc-notable_trait.bare-fn.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;"}</script>
10 changes: 6 additions & 4 deletions src/test/rustdoc/doc-notable_trait.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,8 @@ impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
#[doc(notable_trait)]
pub trait SomeTrait {
// @has doc_notable_trait/trait.SomeTrait.html
// @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
// @has - '//span[@class="notable-traits"]/@data-ty' 'Wrapper<Self>'
// @snapshot wrap-me - '//script[@id="notable-traits-data"]'
fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
Wrapper {
inner: self,
@@ -22,15 +23,16 @@ impl SomeTrait for SomeStruct {}

impl SomeStruct {
// @has doc_notable_trait/struct.SomeStruct.html
// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
// @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
// @has - '//span[@class="notable-traits"]/@data-ty' 'SomeStruct'
// @snapshot some-struct-new - '//script[@id="notable-traits-data"]'
pub fn new() -> SomeStruct {
SomeStruct
}
}

// @has doc_notable_trait/fn.bare_fn.html
// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
// @has - '//span[@class="notable-traits"]/@data-ty' 'SomeStruct'
// @snapshot bare-fn - '//script[@id="notable-traits-data"]'
pub fn bare_fn() -> SomeStruct {
SomeStruct
}
1 change: 1 addition & 0 deletions src/test/rustdoc/doc-notable_trait.some-struct-new.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"SomeStruct":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.SomeStruct.html\" title=\"struct doc_notable_trait::SomeStruct\"&gt;SomeStruct&lt;/a&gt;&lt;/span&gt;","Wrapper&lt;Self&gt;":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
1 change: 1 addition & 0 deletions src/test/rustdoc/doc-notable_trait.wrap-me.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"Wrapper&lt;Self&gt;":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T:&amp;nbsp;&lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt;&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct doc_notable_trait::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;"}</script>
1 change: 1 addition & 0 deletions src/test/rustdoc/spotlight-from-dependency.odd.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"Odd":"&lt;h3 class=\"notable\"&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre class=\"content\"&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl &lt;a class=\"trait\" href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html\" title=\"trait core::iter::traits::iterator::Iterator\"&gt;Iterator&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Odd.html\" title=\"struct foo::Odd\"&gt;Odd&lt;/a&gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt; type &lt;a href=\"{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item\" class=\"associatedtype\"&gt;Item&lt;/a&gt; = &lt;a class=\"primitive\" href=\"{{channel}}/std/primitive.usize.html\"&gt;usize&lt;/a&gt;;&lt;/span&gt;"}</script>
3 changes: 2 additions & 1 deletion src/test/rustdoc/spotlight-from-dependency.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,8 @@
use std::iter::Iterator;

// @has foo/struct.Odd.html
// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
// @has - '//*[@id="method.new"]//span[@class="notable-traits"]/@data-ty' 'Odd'
// @snapshot odd - '//script[@id="notable-traits-data"]'
pub struct Odd {
current: usize,
}