Skip to content
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

rustdoc: use browser-native tooltips for code and notable hover #111856

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
43 changes: 36 additions & 7 deletions src/librustdoc/html/render/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1279,8 +1279,6 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool, tcx: TyCtxt<'_>) ->
}

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())?;

// Box has pass-through impls for Read, Write, Iterator, and Future when the
Expand All @@ -1293,6 +1291,8 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O
return None;
}

let mut notable_tt = String::new();

if let Some(impls) = cx.cache().impls.get(&did) {
for i in impls {
let impl_ = i.inner_impl();
Expand All @@ -1306,20 +1306,49 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O

if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx()))
{
has_notable_trait = true;
if !notable_tt.is_empty() {
notable_tt.push('\n');
}
write!(&mut notable_tt, " {:#}", impl_.print(false, cx))
.expect("infallible write");
for it in &impl_.items {
if let clean::AssocTypeItem(ref tydef, ref bounds) = *it.kind {
write!(
&mut notable_tt,
"\n type {name}{generics:#}",
name = it.name.as_ref().unwrap(),
generics = tydef.generics.print(cx),
)
.expect("infallible write");
if !bounds.is_empty() {
write!(&mut notable_tt, ": {:#}", print_generic_bounds(bounds, cx))
.expect("infallible write");
}
write!(
&mut notable_tt,
"{:#}",
print_where_clause(&tydef.generics, cx, 4, Ending::NoNewline)
)
.expect("infallible write");
write!(&mut notable_tt, " = {:#}", tydef.type_.print(cx))
.expect("infallible write");
}
}
}
}
}
}

if has_notable_trait {
if notable_tt.is_empty() {
None
} else {
cx.types_with_notable_traits.insert(ty.clone());
Some(format!(
" <a href=\"#\" class=\"tooltip\" data-notable-ty=\"{ty}\">ⓘ</a>",
" <a href=\"#\" title=\"Notable traits for {ty}&#10;{tt}\" class=\"tooltip\" \
data-notable-ty=\"{ty}\">ⓘ</a>",
ty = Escape(&format!("{:#}", ty.print(cx))),
tt = Escape(&notable_tt),
))
} else {
None
}
}

Expand Down
6 changes: 0 additions & 6 deletions src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,3 @@ nav.sub {
.source .sidebar {
display: none;
}

.notable-traits {
/* layout requires javascript
https://github.com/rust-lang/rust/issues/102576 */
display: none;
}
12 changes: 0 additions & 12 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -1179,18 +1179,6 @@ a.test-arrow:hover {
position: relative;
}

/* placeholder thunk so that the mouse can easily travel from "(i)" to popover
the resulting "hover tunnel" is a stepped triangle, approximating
https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown */
a.tooltip:hover::after {
position: absolute;
top: calc(100% - 10px);
left: -15px;
right: -15px;
height: 20px;
content: "\00a0";
}

.popover.tooltip .content {
margin: 0.25em 0.5em;
}
Expand Down
42 changes: 4 additions & 38 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -740,12 +740,8 @@ function preLoadCss(cssUrl) {
//
// This means when the window is resized, we need to redo the layout.
const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
const force_visible = base.TOOLTIP_FORCE_VISIBLE;
hideTooltip(false);
if (force_visible) {
showTooltip(base);
base.TOOLTIP_FORCE_VISIBLE = true;
}
showTooltip(base);
}
});

Expand Down Expand Up @@ -824,15 +820,6 @@ function preLoadCss(cssUrl) {
wrapper.style.visibility = "";
window.CURRENT_TOOLTIP_ELEMENT = wrapper;
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_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.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(event.relatedTarget, e)) {
hideTooltip(true);
}
};
}

function tooltipBlurHandler(event) {
Expand All @@ -856,11 +843,8 @@ function preLoadCss(cssUrl) {

function hideTooltip(focus) {
if (window.CURRENT_TOOLTIP_ELEMENT) {
if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
if (focus) {
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
}
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
if (focus) {
window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
}
const body = document.getElementsByTagName("body")[0];
body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
Expand All @@ -870,8 +854,7 @@ function preLoadCss(cssUrl) {

onEachLazy(document.getElementsByClassName("tooltip"), e => {
e.onclick = function() {
this.TOOLTIP_FORCE_VISIBLE = this.TOOLTIP_FORCE_VISIBLE ? false : true;
if (window.CURRENT_TOOLTIP_ELEMENT && !this.TOOLTIP_FORCE_VISIBLE) {
if (window.CURRENT_TOOLTIP_ELEMENT) {
hideTooltip(true);
} else {
showTooltip(this);
Expand All @@ -881,23 +864,6 @@ function preLoadCss(cssUrl) {
}
return false;
};
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;
}
showTooltip(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.TOOLTIP_FORCE_VISIBLE &&
!elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) {
hideTooltip(true);
}
};
});

const sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
Expand Down
6 changes: 1 addition & 5 deletions tests/rustdoc-gui/notable-trait.goml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ compare-elements-position-false: (
("x")
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='tooltip popover']", 0)

// Now only the `i` should be on the next line.
Expand Down Expand Up @@ -116,7 +115,6 @@ assert-position: (
{"x": 0}
)
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//h1"
assert-count: ("//*[@class='tooltip popover']", 0)

// Now check the colors.
Expand All @@ -133,7 +131,7 @@ define-function: (
// We reload the page so the local storage settings are being used.
reload:

move-cursor-to: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
assert-count: (".tooltip.popover", 1)

assert-css: (
Expand Down Expand Up @@ -196,7 +194,6 @@ reload:

// Check that pressing escape works
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//*[@class='tooltip popover']"
assert-count: ("//*[@class='tooltip popover']", 1)
press-key: "Escape"
assert-count: ("//*[@class='tooltip popover']", 0)
Expand All @@ -211,7 +208,6 @@ assert-false: "#method\.create_an_iterator_from_read .tooltip:focus"

// Check that pressing tab over and over works.
click: "//*[@id='method.create_an_iterator_from_read']//*[@class='tooltip']"
move-cursor-to: "//*[@class='tooltip popover']"
assert-count: ("//*[@class='tooltip popover']", 1)
press-key: "Tab"
press-key: "Tab"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script type="text/json" id="notable-traits-data">{"Wrapper&lt;()&gt;":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct foo::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=\"where fmt-newline\"&gt;impl&amp;lt;T&amp;gt; &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait foo::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Wrapper.html\" title=\"struct foo::Wrapper\"&gt;Wrapper&lt;/a&gt;&amp;lt;T&amp;gt;&lt;/span&gt;&lt;span class=\"where fmt-newline\"&gt; type &lt;a href=\"trait.SomeTrait.html#associatedtype.SomeType\" class=\"associatedtype\"&gt;SomeType&lt;/a&gt; = T;&lt;/span&gt;"}</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<a href="#" title="Notable traits for Wrapper&lt;()&gt;&#10; impl&lt;T&gt; SomeTrait for Wrapper&lt;T&gt;&#10; type SomeType = T" class="tooltip" data-notable-ty="Wrapper&lt;()&gt;">&#9432;</a>
24 changes: 24 additions & 0 deletions tests/rustdoc/notable-trait/doc-notable-trait-associated-type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#![feature(doc_notable_trait)]
#![crate_name="foo"]

pub struct Wrapper<T> {
inner: T,
}

impl<T> SomeTrait for Wrapper<T> {
type SomeType = T;
}

#[doc(notable_trait)]
pub trait SomeTrait {
type SomeType;
}

// @has foo/fn.bare_fn.html
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<()>'
// @has - '//a[@class="tooltip"]/@title' 'impl<T> SomeTrait for Wrapper<T> type SomeType = T'
// @snapshot bare_fn_tooltip - '//a[@class="tooltip"]'
// @snapshot bare_fn_data - '//script[@id="notable-traits-data"]'
pub fn bare_fn() -> Wrapper<()> {
unimplemented();
}
1 change: 1 addition & 0 deletions tests/rustdoc/notable-trait/doc-notable_trait-slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct OtherStruct;
impl SomeTrait for &[SomeStruct] {}

// @has doc_notable_trait_slice/fn.bare_fn_matches.html
// @has - '//a[@class="tooltip"]/@title' 'impl SomeTrait for &[SomeStruct]'
// @snapshot bare_fn_matches - '//script[@id="notable-traits-data"]'
pub fn bare_fn_matches() -> &'static [SomeStruct] {
&[]
Expand Down
3 changes: 3 additions & 0 deletions tests/rustdoc/notable-trait/doc-notable_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
pub trait SomeTrait {
// @has doc_notable_trait/trait.SomeTrait.html
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'Wrapper<Self>'
// @has - '//a[@class="tooltip"]/@title' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
// @snapshot wrap-me - '//script[@id="notable-traits-data"]'
fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
Wrapper {
Expand All @@ -24,6 +25,7 @@ impl SomeTrait for SomeStruct {}
impl SomeStruct {
// @has doc_notable_trait/struct.SomeStruct.html
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
// @has - '//a[@class="tooltip"]/@title' 'impl SomeTrait for SomeStruct'
// @snapshot some-struct-new - '//script[@id="notable-traits-data"]'
pub fn new() -> SomeStruct {
SomeStruct
Expand All @@ -32,6 +34,7 @@ impl SomeStruct {

// @has doc_notable_trait/fn.bare_fn.html
// @has - '//a[@class="tooltip"]/@data-notable-ty' 'SomeStruct'
// @has - '//a[@class="tooltip"]/@title' 'impl SomeTrait for SomeStruct'
// @snapshot bare-fn - '//script[@id="notable-traits-data"]'
pub fn bare_fn() -> SomeStruct {
SomeStruct
Expand Down