diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2020-07-06 12:53:44 -0700 |
|---|---|---|
| committer | Manish Goregaokar <manishsmail@gmail.com> | 2020-07-16 09:58:17 -0700 |
| commit | 98450757e5fa18ee0be9213d2830c9363b0f5fd3 (patch) | |
| tree | 9ad6b743aa1994062558a71568569cce2664b033 /src | |
| parent | 6ee1b62c811a6eb68d6db6dfb91f66a49956749b (diff) | |
| download | rust-98450757e5fa18ee0be9213d2830c9363b0f5fd3.tar.gz rust-98450757e5fa18ee0be9213d2830c9363b0f5fd3.zip | |
Revert "Remove "important traits" feature"
This reverts commit 1244ced9580b942926afc06815e0691cf3f4a846.
Diffstat (limited to 'src')
| -rw-r--r-- | src/doc/rustdoc/src/unstable-features.md | 21 | ||||
| -rw-r--r-- | src/doc/unstable-book/src/language-features/doc-spotlight.md | 30 | ||||
| -rw-r--r-- | src/librustc_feature/active.rs | 3 | ||||
| -rw-r--r-- | src/librustdoc/clean/inline.rs | 4 | ||||
| -rw-r--r-- | src/librustdoc/clean/mod.rs | 2 | ||||
| -rw-r--r-- | src/librustdoc/clean/types.rs | 1 | ||||
| -rw-r--r-- | src/librustdoc/html/format.rs | 12 | ||||
| -rw-r--r-- | src/librustdoc/html/render.rs | 87 | ||||
| -rw-r--r-- | src/librustdoc/html/static/main.js | 28 | ||||
| -rw-r--r-- | src/librustdoc/html/static/rustdoc.css | 96 | ||||
| -rw-r--r-- | src/librustdoc/html/static/themes/dark.css | 33 | ||||
| -rw-r--r-- | src/librustdoc/html/static/themes/light.css | 33 | ||||
| -rw-r--r-- | src/test/rustdoc/doc-spotlight.rs | 36 | ||||
| -rw-r--r-- | src/test/ui/feature-gates/feature-gate-doc_spotlight.rs | 4 | ||||
| -rw-r--r-- | src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr | 12 |
15 files changed, 393 insertions, 9 deletions
diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index eea674f2b84..d16c2a9d034 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -150,6 +150,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 00000000000..8117755fef1 --- /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 0da3693af4f..d7c310a8b4c 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 78628b198a3..1387389981d 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 03d6853494c..8a4ee91df40 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1007,6 +1007,7 @@ impl Clean<FnRetTy> for hir::FnRetTy<'_> { impl Clean<Item> 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<Item> 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 c9ae67ded0a..5f6d9ecc047 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -995,6 +995,7 @@ pub struct Trait { pub items: Vec<Item>, pub generics: Generics, pub bounds: Vec<GenericBound>, + pub is_spotlight: bool, pub is_auto: bool, } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a453a8b3dcb..0d8284029af 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 9fa3f6cc396..940d7e87a18 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2410,7 +2410,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func f.generics.print() ) .len(); - write!(w, "<pre class='rust fn'>"); + write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it)); render_attributes(w, it, false); write!( w, @@ -2612,7 +2612,12 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait) let name = m.name.as_ref().unwrap(); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h3 id='{id}' class='method'><code>", id = id); + write!( + w, + "<h3 id='{id}' class='method'>{extra}<code>", + extra = render_spotlight_traits(m), + id = id + ); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, "</code>"); render_stability_since(w, m, t); @@ -3559,6 +3564,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!( + "<h3 class=\"important\">Important traits for {}</h3>\ + <code class=\"content\">", + impl_.for_.print() + )); + trait_.push_str(&impl_.for_.print().to_string()); + } + + //use the "where" class here to make it small + out.push_str(&format!( + "<span class=\"where fmt-newline\">{}</span>", + 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("<span class=\"where fmt-newline\"> "); + assoc_type( + &mut out, + it, + &[], + Some(&tydef.type_), + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "", + ); + out.push_str(";</span>"); + } + } + } + } + } + } + + if !out.is_empty() { + out.insert_str( + 0, + &format!( + "<div class=\"important-traits\"><div class='tooltip'>ⓘ\ + <span class='tooltiptext'>Important traits for {}</span></div>\ + <div class=\"content hidden\">", + trait_ + ), + ); + out.push_str("</code></div></div>"); + } + + out.into_inner() +} + fn render_impl( w: &mut Buffer, cx: &Context, @@ -3665,12 +3740,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)); - write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class); + write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class); + write!(w, "{}", spotlight_decl(decl)); + write!(w, "<code>"); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, "</code>"); render_stability_since_raw(w, item.stable_since(), outer_version); diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 336c691ac1c..524a841e098 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -365,6 +365,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) { @@ -397,6 +398,7 @@ function defocusSearchBar() { case "s": case "S": displayHelp(false, ev); + hideModal(); ev.preventDefault(); focusSearchBar(); break; @@ -409,6 +411,7 @@ function defocusSearchBar() { case "?": if (ev.shiftKey) { + hideModal(); displayHelp(true, ev); } break; @@ -2636,6 +2639,31 @@ function defocusSearchBar() { }); }()); + function showModal(content) { + var modal = document.createElement("div"); + modal.id = "important"; + addClass(modal, "modal"); + modal.innerHTML = "<div class=\"modal-content\"><div class=\"close\" id=\"modal-close\">✕" + + "</div><div class=\"whiter\"></div><span class=\"docblock\">" + content + + "</span></div>"; + 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 15a0c76ceea..3b2a28a0f5e 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -146,9 +146,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; } @@ -523,7 +526,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; } @@ -1098,7 +1101,7 @@ h3 > .collapse-toggle, h4 > .collapse-toggle { font-size: 20px; } -.tooltip .tooltiptext { +.important-traits .tooltip .tooltiptext { border: 1px solid; font-weight: normal; } @@ -1144,6 +1147,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; @@ -1370,6 +1384,12 @@ pre.rust { z-index: 1; } + h4 > .important-traits { + position: absolute; + left: -22px; + top: 24px; + } + #titles > div > div.count { float: left; width: 100%; @@ -1472,12 +1492,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 41dcb5c2450..daa5ccf34bb 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 386fe2398e6..aa7df01dc02 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 00000000000..ddd46c3c215 --- /dev/null +++ b/src/test/rustdoc/doc-spotlight.rs @@ -0,0 +1,36 @@ +#![feature(doc_spotlight)] + +pub struct Wrapper<T> { + inner: T, +} + +impl<T: SomeTrait> SomeTrait for Wrapper<T> {} + +#[doc(spotlight)] +pub trait SomeTrait { + // @has doc_spotlight/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>' + fn wrap_me(self) -> Wrapper<Self> 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<T: SomeTrait> SomeTrait for Wrapper<T>' + 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 00000000000..452b45b3445 --- /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 00000000000..010d74054a4 --- /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 <https://github.com/rust-lang/rust/issues/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`. |
