From 1cff03defd76dafc4ba75940fb07a5ebde7364fc Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 12:53:44 -0700 Subject: [PATCH 1/4] Revert "Remove "important traits" feature" This reverts commit 1244ced9580b942926afc06815e0691cf3f4a846. --- src/doc/rustdoc/src/unstable-features.md | 21 ++++ .../src/language-features/doc-spotlight.md | 30 ++++++ src/librustc_feature/active.rs | 3 + src/librustdoc/clean/inline.rs | 4 +- src/librustdoc/clean/mod.rs | 2 + src/librustdoc/clean/types.rs | 1 + src/librustdoc/html/format.rs | 12 +++ src/librustdoc/html/render.rs | 85 +++++++++++++++- src/librustdoc/html/static/main.js | 28 ++++++ src/librustdoc/html/static/rustdoc.css | 96 ++++++++++++++++++- src/librustdoc/html/static/themes/dark.css | 33 +++++++ src/librustdoc/html/static/themes/light.css | 33 +++++++ src/test/rustdoc/doc-spotlight.rs | 36 +++++++ .../feature-gate-doc_spotlight.rs | 4 + .../feature-gate-doc_spotlight.stderr | 12 +++ 15 files changed, 392 insertions(+), 8 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/doc-spotlight.md create mode 100644 src/test/rustdoc/doc-spotlight.rs create mode 100644 src/test/ui/feature-gates/feature-gate-doc_spotlight.rs create mode 100644 src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 84e1ebe5e01f5..baaac94a30e07 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -138,6 +138,27 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg]. [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781 +### Adding your trait to the "Important Traits" dialog + +Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when +implemented on it. These traits are intended to be the primary interface for their types, and are +often the only thing available to be documented on their types. For this reason, Rustdoc will track +when a given type implements one of these traits and call special attention to it when a function +returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next +to the function, which, when clicked, shows the dialog. + +In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and +`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a +special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this +attribute to your own trait to include it in the "Important Traits" dialog in documentation. + +The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate. +For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking +issue][issue-spotlight]. + +[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html +[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040 + ### Exclude certain dependencies from documentation The standard library uses several dependencies which, in turn, use several types and traits from the diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md new file mode 100644 index 0000000000000..8117755fef1c8 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-spotlight.md @@ -0,0 +1,30 @@ +# `doc_spotlight` + +The tracking issue for this feature is: [#45040] + +The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute, +to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]` +attribute to a trait definition will make rustdoc print extra information for functions which return +a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and +`io::Write` traits in the standard library. + +You can do this on your own traits, like this: + +``` +#![feature(doc_spotlight)] + +#[doc(spotlight)] +pub trait MyTrait {} + +pub struct MyStruct; +impl MyTrait for MyStruct {} + +/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`, +/// without having to write that yourself! +pub fn my_fn() -> MyStruct { MyStruct } +``` + +This feature was originally implemented in PR [#45039]. + +[#45040]: https://github.com/rust-lang/rust/issues/45040 +[#45039]: https://github.com/rust-lang/rust/pull/45039 diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 32481bf2b9574..1f04100451d2a 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -368,6 +368,9 @@ declare_features! ( /// Allows `#[doc(masked)]`. (active, doc_masked, "1.21.0", Some(44027), None), + /// Allows `#[doc(spotlight)]`. + (active, doc_spotlight, "1.22.0", Some(45040), None), + /// Allows `#[doc(include = "some-file")]`. (active, external_doc, "1.22.0", Some(44732), None), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 78628b198a3c3..1387389981d26 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -12,7 +12,7 @@ use rustc_metadata::creader::LoadedMacro; use rustc_middle::ty; use rustc_mir::const_eval::is_min_const_fn; use rustc_span::hygiene::MacroKind; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use crate::clean::{self, GetDefId, ToSource, TypeKind}; @@ -194,6 +194,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { let generics = (cx.tcx.generics_of(did), predicates).clean(cx); let generics = filter_non_trait_generics(did, generics); let (generics, supertrait_bounds) = separate_supertrait_bounds(generics); + let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight); let is_auto = cx.tcx.trait_is_auto(did); clean::Trait { auto: auto_trait, @@ -201,6 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait { generics, items: trait_items, bounds: supertrait_bounds, + is_spotlight, is_auto, } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index bfe8464347d29..72519164f8a49 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1007,6 +1007,7 @@ impl Clean for hir::FnRetTy<'_> { impl Clean for doctree::Trait<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let attrs = self.attrs.clean(cx); + let is_spotlight = attrs.has_doc_flag(sym::spotlight); Item { name: Some(self.name.clean(cx)), attrs, @@ -1021,6 +1022,7 @@ impl Clean for doctree::Trait<'_> { items: self.items.iter().map(|ti| ti.clean(cx)).collect(), generics: self.generics.clean(cx), bounds: self.bounds.clean(cx), + is_spotlight, is_auto: self.is_auto.clean(cx), }), } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6dec016cc2ee3..7e282121eebfb 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -993,6 +993,7 @@ pub struct Trait { pub items: Vec, pub generics: Generics, pub bounds: Vec, + pub is_spotlight: bool, pub is_auto: bool, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a453a8b3dcb2a..0d8284029afc7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -63,10 +63,22 @@ impl Buffer { Buffer { for_html: false, buffer: String::new() } } + crate fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + crate fn into_inner(self) -> String { self.buffer } + crate fn insert_str(&mut self, idx: usize, s: &str) { + self.buffer.insert_str(idx, s); + } + + crate fn push_str(&mut self, s: &str) { + self.buffer.push_str(s); + } + // Intended for consumption by write! and writeln! (std::fmt) but without // the fmt::Result return type imposed by fmt::Write (and avoiding the trait // import). diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 04c4685213b2e..87c9baf24f869 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2384,7 +2384,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "
");
+    write!(w, "{}
", render_spotlight_traits(it));
     render_attributes(w, it, false);
     write!(
         w,
@@ -2587,7 +2587,13 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait)
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space()));
-        write!(w, "

", id = id, ns_id = ns_id); + write!( + w, + "

{extra}", + extra = render_spotlight_traits(m), + id = id, + ns_id = ns_id + ); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); render_stability_since(w, m, t); @@ -3550,6 +3556,76 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } +fn render_spotlight_traits(item: &clean::Item) -> String { + match item.inner { + clean::FunctionItem(clean::Function { ref decl, .. }) + | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) + | clean::MethodItem(clean::Method { ref decl, .. }) + | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl), + _ => String::new(), + } +} + +fn spotlight_decl(decl: &clean::FnDecl) -> String { + let mut out = Buffer::html(); + let mut trait_ = String::new(); + + if let Some(did) = decl.output.def_id() { + let c = cache(); + if let Some(impls) = c.impls.get(&did) { + for i in impls { + let impl_ = i.inner_impl(); + if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) { + if out.is_empty() { + out.push_str(&format!( + "

Important traits for {}

\ + ", + impl_.for_.print() + )); + trait_.push_str(&impl_.for_.print().to_string()); + } + + //use the "where" class here to make it small + out.push_str(&format!( + "{}", + impl_.print() + )); + let t_did = impl_.trait_.def_id().unwrap(); + for it in &impl_.items { + if let clean::TypedefItem(ref tydef, _) = it.inner { + out.push_str(" "); + assoc_type( + &mut out, + it, + &[], + Some(&tydef.type_), + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "", + ); + out.push_str(";"); + } + } + } + } + } + } + + if !out.is_empty() { + out.insert_str( + 0, + &format!( + "
ⓘ\ + Important traits for {}
\ +
", + trait_ + ), + ); + out.push_str("
"); + } + + out.into_inner() +} + fn render_impl( w: &mut Buffer, cx: &Context, @@ -3656,13 +3732,14 @@ fn render_impl( (true, " hidden") }; match item.inner { - clean::MethodItem(clean::Method { .. }) - | clean::TyMethodItem(clean::TyMethod { .. }) => { + clean::MethodItem(clean::Method { ref decl, .. }) + | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class); + write!(w, "{}", spotlight_decl(decl)); write!(w, "", ns_id); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 62a23298c1b9f..d3ce66889e5d5 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -363,6 +363,7 @@ function defocusSearchBar() { function handleEscape(ev) { var help = getHelpElement(); var search = getSearchElement(); + hideModal(); if (hasClass(help, "hidden") === false) { displayHelp(false, ev, help); } else if (hasClass(search, "hidden") === false) { @@ -395,6 +396,7 @@ function defocusSearchBar() { case "s": case "S": displayHelp(false, ev); + hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -407,6 +409,7 @@ function defocusSearchBar() { case "?": if (ev.shiftKey) { + hideModal(); displayHelp(true, ev); } break; @@ -2621,6 +2624,31 @@ function defocusSearchBar() { }); }()); + function showModal(content) { + var modal = document.createElement("div"); + modal.id = "important"; + addClass(modal, "modal"); + modal.innerHTML = "
✕" + + "
" + content + + "
"; + document.getElementsByTagName("body")[0].appendChild(modal); + document.getElementById("modal-close").onclick = hideModal; + modal.onclick = hideModal; + } + + function hideModal() { + var modal = document.getElementById("important"); + if (modal) { + modal.parentNode.removeChild(modal); + } + } + + onEachLazy(document.getElementsByClassName("important-traits"), function(e) { + e.onclick = function() { + showModal(e.lastElementChild.innerHTML); + }; + }); + // In the search display, allows to switch between tabs. function printTab(nb) { if (nb === 0 || nb === 1 || nb === 2) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 9c6dd25394db0..d3c083e454203 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -143,9 +143,12 @@ code, pre, a.test-arrow { border-radius: 3px; padding: 0 0.1em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .docblock-short pre code, .docblock code.spotlight { padding: 0; } +.docblock code.spotlight :last-child { + padding-bottom: 0.6em; +} pre { padding: 14px; } @@ -519,7 +522,7 @@ h4 > code, h3 > code, .invisible > code { font-size: 0.8em; } -.content .methods > div { +.content .methods > div:not(.important-traits) { margin-left: 40px; margin-bottom: 15px; } @@ -1094,7 +1097,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -.tooltip .tooltiptext { +.important-traits .tooltip .tooltiptext { border: 1px solid; font-weight: normal; } @@ -1140,6 +1143,17 @@ pre.rust { font-size: 16px; } +.important-traits { + cursor: pointer; + z-index: 2; +} + +h4 > .important-traits { + position: absolute; + left: -44px; + top: 2px; +} + #all-types { text-align: center; border: 1px solid; @@ -1366,6 +1380,12 @@ pre.rust { z-index: 1; } + h4 > .important-traits { + position: absolute; + left: -22px; + top: 24px; + } + #titles > div > div.count { float: left; width: 100%; @@ -1468,12 +1488,82 @@ pre.rust { } } +.modal { + position: fixed; + width: 100vw; + height: 100vh; + z-index: 10000; + top: 0; + left: 0; +} + +.modal-content { + display: block; + max-width: 60%; + min-width: 200px; + padding: 8px; + top: 40%; + position: absolute; + left: 50%; + transform: translate(-50%, -40%); + border: 1px solid; + border-radius: 4px; + border-top-right-radius: 0; +} + +.modal-content > .docblock { + margin: 0; +} + h3.important { margin: 0; margin-bottom: 13px; font-size: 19px; } +.modal-content > .docblock > code.content { + margin: 0; + padding: 0; + font-size: 20px; +} + +.modal-content > .close { + position: absolute; + font-weight: 900; + right: -25px; + top: -1px; + font-size: 18px; + width: 25px; + padding-right: 2px; + border-top-right-radius: 5px; + border-bottom-right-radius: 5px; + text-align: center; + border: 1px solid; + border-right: 0; + cursor: pointer; +} + +.modal-content > .whiter { + height: 25px; + position: absolute; + width: 3px; + right: -2px; + top: 0px; +} + +#main > div.important-traits { + position: absolute; + left: -24px; + margin-top: 16px; +} + +.content > .methods > .method > div.important-traits { + position: absolute; + font-weight: 400; + left: -42px; + margin-top: 2px; +} + kbd { display: inline-block; padding: 3px 5px; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 41dcb5c24507c..daa5ccf34bb18 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,6 +337,12 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } +.important-traits .tooltip .tooltiptext { + background-color: white; + color: black; + border-color: black; +} + #titles > div:not(.selected) { background-color: #252525; border-top-color: #252525; @@ -350,6 +356,33 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } +.modal { + background-color: rgba(0,0,0,0.3); +} + +.modal-content { + background-color: #272727; + border-color: #999; +} + +.modal-content > .close { + background-color: #272727; + border-color: #999; +} + +.modal-content > .close:hover { + background-color: #ff1f1f; + color: white; +} + +.modal-content > .whiter { + background-color: #272727; +} + +.modal-content > .close:hover + .whiter { + background-color: #ff1f1f; +} + @media (max-width: 700px) { .sidebar-menu { background-color: #505050; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 386fe2398e63a..aa7df01dc02b3 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -331,6 +331,12 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } +.important-traits .tooltip .tooltiptext { + background-color: white; + color: black; + border-color: black; +} + #titles > div:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; @@ -344,6 +350,33 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } +.modal { + background-color: rgba(0,0,0,0.3); +} + +.modal-content { + background-color: #eee; + border-color: #999; +} + +.modal-content > .close { + background-color: #eee; + border-color: #999; +} + +.modal-content > .close:hover { + background-color: #ff1f1f; + color: white; +} + +.modal-content > .whiter { + background-color: #eee; +} + +.modal-content > .close:hover + .whiter { + background-color: #ff1f1f; +} + @media (max-width: 700px) { .sidebar-menu { background-color: #F1F1F1; diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs new file mode 100644 index 0000000000000..ddd46c3c2155f --- /dev/null +++ b/src/test/rustdoc/doc-spotlight.rs @@ -0,0 +1,36 @@ +#![feature(doc_spotlight)] + +pub struct Wrapper { + inner: T, +} + +impl SomeTrait for Wrapper {} + +#[doc(spotlight)] +pub trait SomeTrait { + // @has doc_spotlight/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + fn wrap_me(self) -> Wrapper where Self: Sized { + Wrapper { + inner: self, + } + } +} + +pub struct SomeStruct; +impl SomeTrait for SomeStruct {} + +impl SomeStruct { + // @has doc_spotlight/struct.SomeStruct.html + // @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' + // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + pub fn new() -> SomeStruct { + SomeStruct + } +} + +// @has doc_spotlight/fn.bare_fn.html +// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct' +pub fn bare_fn() -> SomeStruct { + SomeStruct +} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs new file mode 100644 index 0000000000000..452b45b34456b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs @@ -0,0 +1,4 @@ +#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental +trait SomeTrait {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr new file mode 100644 index 0000000000000..010d74054a412 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[doc(spotlight)]` is experimental + --> $DIR/feature-gate-doc_spotlight.rs:1:1 + | +LL | #[doc(spotlight)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #45040 for more information + = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 75394511002a8633a7074e1672c4740515a2cdf0 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 12:54:33 -0700 Subject: [PATCH 2/4] Revert "Remove spotlight usage" This reverts commit 13c6d5819aae3c0de6a90e7f17ea967bf4487cbb. --- src/libcore/future/future.rs | 1 + src/libcore/iter/traits/iterator.rs | 1 + src/libcore/lib.rs | 1 + src/librustc_ast_passes/feature_gate.rs | 1 + src/librustc_span/symbol.rs | 2 ++ src/libstd/io/mod.rs | 2 ++ src/libstd/lib.rs | 1 + 7 files changed, 9 insertions(+) diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index abf461338d80a..733ebdc0e97f2 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -24,6 +24,7 @@ use crate::task::{Context, Poll}; /// `.await` the value. /// /// [`Waker`]: ../task/struct.Waker.html +#[doc(spotlight)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index ce4be973140e5..692eed80c0252 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -92,6 +92,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] +#[doc(spotlight)] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { /// The type of the elements being iterated over. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 692d91bd61ddf..0b909a4434ecd 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -96,6 +96,7 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] +#![cfg_attr(not(bootstrap), feature(doc_spotlight))] #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index a7b0c9cf81be6..b424c8afb3471 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -253,6 +253,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { include => external_doc cfg => doc_cfg masked => doc_masked + spotlight => doc_spotlight alias => doc_alias keyword => doc_keyword ); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 92afb7dab88c3..466dc28782f0f 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -298,6 +298,7 @@ symbols! { doc_cfg, doc_keyword, doc_masked, + doc_spotlight, doctest, document_private_items, dotdoteq_in_patterns, @@ -797,6 +798,7 @@ symbols! { Some, specialization, speed, + spotlight, sqrtf32, sqrtf64, sse4a_target_feature, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 717d2868abf98..d5af4f25102d1 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -499,6 +499,7 @@ where /// [`&str`]: ../../std/primitive.str.html /// [slice]: ../../std/primitive.slice.html #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -1261,6 +1262,7 @@ impl Initializer { /// /// [`write_all`]: #method.write_all #[stable(feature = "rust1", since = "1.0.0")] +#[doc(spotlight)] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bd585d39c242f..e11cb3e846931 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -260,6 +260,7 @@ #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] +#![cfg_attr(not(bootstrap), feature(doc_spotlight))] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] From f2b7e837311d18c4593e57752e7839a2b452c610 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 14:13:47 -0700 Subject: [PATCH 3/4] Move spotlight next to the return type --- src/librustdoc/html/render.rs | 32 +++++++++----------------- src/librustdoc/html/static/rustdoc.css | 16 ++----------- 2 files changed, 13 insertions(+), 35 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 87c9baf24f869..e47329e5c2397 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2384,12 +2384,12 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "{}
", render_spotlight_traits(it));
+    write!(w, "
");
     render_attributes(w, it, false);
     write!(
         w,
         "{vis}{constness}{asyncness}{unsafety}{abi}fn \
-           {name}{generics}{decl}{where_clause}
", + {name}{generics}{decl}{spotlight}{where_clause}
", vis = it.visibility.print_with_space(), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), @@ -2399,7 +2399,8 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func generics = f.generics.print(), where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true }, decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness } - .print() + .print(), + spotlight = spotlight_decl(&f.decl), ); document(w, cx, it) } @@ -2589,8 +2590,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait) let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!( w, - "

{extra}", - extra = render_spotlight_traits(m), + "

", id = id, ns_id = ns_id ); @@ -2907,7 +2907,7 @@ fn render_assoc_item( write!( w, "{}{}{}{}{}{}{}fn {name}\ - {generics}{decl}{where_clause}", + {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, meth.visibility.print_with_space(), header.constness.print_with_space(), @@ -2919,6 +2919,7 @@ fn render_assoc_item( name = name, generics = g.print(), decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }.print(), + spotlight = spotlight_decl(&d), where_clause = WhereClause { gens: g, indent, end_newline } ) } @@ -3556,16 +3557,6 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool { } } -fn render_spotlight_traits(item: &clean::Item) -> String { - match item.inner { - clean::FunctionItem(clean::Function { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) - | clean::MethodItem(clean::Method { ref decl, .. }) - | clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl), - _ => String::new(), - } -} - fn spotlight_decl(decl: &clean::FnDecl) -> String { let mut out = Buffer::html(); let mut trait_ = String::new(); @@ -3614,13 +3605,13 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { out.insert_str( 0, &format!( - "
ⓘ\ + "
ⓘ\ Important traits for {}
\
", trait_ ), ); - out.push_str("
"); + out.push_str("
"); } out.into_inner() @@ -3732,14 +3723,13 @@ fn render_impl( (true, " hidden") }; match item.inner { - clean::MethodItem(clean::Method { ref decl, .. }) - | clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => { + clean::MethodItem(clean::Method { .. }) + | clean::TyMethodItem(clean::TyMethod { .. }) => { // Only render when the method is not static or we allow static methods if render_method_item { let id = cx.derive_id(format!("{}.{}", item_type, name)); let ns_id = cx.derive_id(format!("{}.{}", name, item_type.name_space())); write!(w, "

", id, item_type, extra_class); - write!(w, "{}", spotlight_decl(decl)); write!(w, "", ns_id); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index d3c083e454203..b38bddf74ef6f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1078,7 +1078,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 16px; } -.tooltip:hover .tooltiptext { +.important-traits:hover .tooltiptext { display: inline; } @@ -1146,6 +1146,7 @@ pre.rust { .important-traits { cursor: pointer; z-index: 2; + margin-left: 5px; } h4 > .important-traits { @@ -1551,19 +1552,6 @@ h3.important { top: 0px; } -#main > div.important-traits { - position: absolute; - left: -24px; - margin-top: 16px; -} - -.content > .methods > .method > div.important-traits { - position: absolute; - font-weight: 400; - left: -42px; - margin-top: 2px; -} - kbd { display: inline-block; padding: 3px 5px; From b65fa849a2372c61d9e2ebc4fb0e025b84daf347 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 6 Jul 2020 17:18:04 -0700 Subject: [PATCH 4/4] Make spotlight show on hover This makes the spotlight show on hover instead of click. Clicks can be used to persist it, which is also what's used on mobile. --- src/librustdoc/html/render.rs | 10 +- src/librustdoc/html/static/main.js | 21 +--- src/librustdoc/html/static/rustdoc.css | 104 ++++++++------------ src/librustdoc/html/static/themes/dark.css | 34 +------ src/librustdoc/html/static/themes/light.css | 34 +------ 5 files changed, 52 insertions(+), 151 deletions(-) diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index e47329e5c2397..458ba3bf06615 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -3604,14 +3604,10 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { if !out.is_empty() { out.insert_str( 0, - &format!( - "
ⓘ\ - Important traits for {}
\ -
", - trait_ - ), + "
" + ); - out.push_str("
"); + out.push_str("
"); } out.into_inner() diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index d3ce66889e5d5..8df12129b7f98 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -2624,28 +2624,13 @@ function defocusSearchBar() { }); }()); - function showModal(content) { - var modal = document.createElement("div"); - modal.id = "important"; - addClass(modal, "modal"); - modal.innerHTML = "
✕" + - "
" + content + - "
"; - document.getElementsByTagName("body")[0].appendChild(modal); - document.getElementById("modal-close").onclick = hideModal; - modal.onclick = hideModal; - } - - function hideModal() { - var modal = document.getElementById("important"); - if (modal) { - modal.parentNode.removeChild(modal); - } + function showImportantTraits(content) { + let list = content.classList } onEachLazy(document.getElementsByClassName("important-traits"), function(e) { e.onclick = function() { - showModal(e.lastElementChild.innerHTML); + e.getElementsByClassName('important-traits-tooltiptext')[0].classList.toggle("force-tooltip") }; }); diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index b38bddf74ef6f..eddecc67dbde8 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -1078,10 +1078,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 16px; } -.important-traits:hover .tooltiptext { - display: inline; -} - .tooltip .tooltiptext::after { content: " "; position: absolute; @@ -1097,9 +1093,46 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -.important-traits .tooltip .tooltiptext { - border: 1px solid; - font-weight: normal; +.important-traits-tooltip { + display: inline-block; + cursor: pointer; +} + +.important-traits:hover .important-traits-tooltiptext, +.important-traits .important-traits-tooltiptext.force-tooltip { + display: inline-block; +} + +.important-traits .important-traits-tooltiptext { + display: none; + padding: 5px 3px 3px 3px; + border-radius: 6px; + margin-left: 5px; + z-index: 10; + font-size: 16px; + cursor: default; + position: absolute; + /* Themes will override the color here, + but it's necessary to make it opaque */ + background-color: #eee; + border: 1px solid #999; +} + +.important-traits-tooltip::after { + /* The margin on the tooltip does not capture hover events, + this extends the area of hover enough so that mouse hover is not + lost when moving the mouse to the tooltip */ + content: "\00a0\00a0\00a0"; +} + +.important-traits .important, .important-traits .docblock { + margin: 0; +} + +.important-traits .docblock code.content{ + margin: 0; + padding: 0; + font-size: 20px; } pre.rust { @@ -1489,69 +1522,12 @@ h4 > .important-traits { } } -.modal { - position: fixed; - width: 100vw; - height: 100vh; - z-index: 10000; - top: 0; - left: 0; -} - -.modal-content { - display: block; - max-width: 60%; - min-width: 200px; - padding: 8px; - top: 40%; - position: absolute; - left: 50%; - transform: translate(-50%, -40%); - border: 1px solid; - border-radius: 4px; - border-top-right-radius: 0; -} - -.modal-content > .docblock { - margin: 0; -} - h3.important { margin: 0; margin-bottom: 13px; font-size: 19px; } -.modal-content > .docblock > code.content { - margin: 0; - padding: 0; - font-size: 20px; -} - -.modal-content > .close { - position: absolute; - font-weight: 900; - right: -25px; - top: -1px; - font-size: 18px; - width: 25px; - padding-right: 2px; - border-top-right-radius: 5px; - border-bottom-right-radius: 5px; - text-align: center; - border: 1px solid; - border-right: 0; - cursor: pointer; -} - -.modal-content > .whiter { - height: 25px; - position: absolute; - width: 3px; - right: -2px; - top: 0px; -} - kbd { display: inline-block; padding: 3px 5px; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index daa5ccf34bb18..cdfe01f216df3 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -337,10 +337,9 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; +.important-traits-tooltiptext { + background-color: #111 !important; + border-color: #777 !important; } #titles > div:not(.selected) { @@ -356,33 +355,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close { - background-color: #272727; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #272727; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #505050; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index aa7df01dc02b3..8ffb935a37851 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -331,10 +331,9 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: transparent black transparent transparent; } -.important-traits .tooltip .tooltiptext { - background-color: white; - color: black; - border-color: black; +.important-traits-tooltiptext { + background-color: #eee !important; + border-color: #999 !important; } #titles > div:not(.selected) { @@ -350,33 +349,6 @@ pre.ignore:hover, .information:hover + pre.ignore { color: #888; } -.modal { - background-color: rgba(0,0,0,0.3); -} - -.modal-content { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close { - background-color: #eee; - border-color: #999; -} - -.modal-content > .close:hover { - background-color: #ff1f1f; - color: white; -} - -.modal-content > .whiter { - background-color: #eee; -} - -.modal-content > .close:hover + .whiter { - background-color: #ff1f1f; -} - @media (max-width: 700px) { .sidebar-menu { background-color: #F1F1F1;