Skip to content

Commit 9845075

Browse files
committed
Revert "Remove "important traits" feature"
This reverts commit 1244ced.
1 parent 6ee1b62 commit 9845075

File tree

15 files changed

+393
-9
lines changed

15 files changed

+393
-9
lines changed

src/doc/rustdoc/src/unstable-features.md

+21
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,27 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
150150
[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
151151
[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
152152

153+
### Adding your trait to the "Important Traits" dialog
154+
155+
Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when
156+
implemented on it. These traits are intended to be the primary interface for their types, and are
157+
often the only thing available to be documented on their types. For this reason, Rustdoc will track
158+
when a given type implements one of these traits and call special attention to it when a function
159+
returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next
160+
to the function, which, when clicked, shows the dialog.
161+
162+
In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and
163+
`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a
164+
special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this
165+
attribute to your own trait to include it in the "Important Traits" dialog in documentation.
166+
167+
The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate.
168+
For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking
169+
issue][issue-spotlight].
170+
171+
[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html
172+
[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040
173+
153174
### Exclude certain dependencies from documentation
154175

155176
The standard library uses several dependencies which, in turn, use several types and traits from the
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# `doc_spotlight`
2+
3+
The tracking issue for this feature is: [#45040]
4+
5+
The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,
6+
to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`
7+
attribute to a trait definition will make rustdoc print extra information for functions which return
8+
a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and
9+
`io::Write` traits in the standard library.
10+
11+
You can do this on your own traits, like this:
12+
13+
```
14+
#![feature(doc_spotlight)]
15+
16+
#[doc(spotlight)]
17+
pub trait MyTrait {}
18+
19+
pub struct MyStruct;
20+
impl MyTrait for MyStruct {}
21+
22+
/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,
23+
/// without having to write that yourself!
24+
pub fn my_fn() -> MyStruct { MyStruct }
25+
```
26+
27+
This feature was originally implemented in PR [#45039].
28+
29+
[#45040]: https://github.com/rust-lang/rust/issues/45040
30+
[#45039]: https://github.com/rust-lang/rust/pull/45039

src/librustc_feature/active.rs

+3
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ declare_features! (
368368
/// Allows `#[doc(masked)]`.
369369
(active, doc_masked, "1.21.0", Some(44027), None),
370370

371+
/// Allows `#[doc(spotlight)]`.
372+
(active, doc_spotlight, "1.22.0", Some(45040), None),
373+
371374
/// Allows `#[doc(include = "some-file")]`.
372375
(active, external_doc, "1.22.0", Some(44732), None),
373376

src/librustdoc/clean/inline.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_metadata::creader::LoadedMacro;
1212
use rustc_middle::ty;
1313
use rustc_mir::const_eval::is_min_const_fn;
1414
use rustc_span::hygiene::MacroKind;
15-
use rustc_span::symbol::Symbol;
15+
use rustc_span::symbol::{sym, Symbol};
1616
use rustc_span::Span;
1717

1818
use crate::clean::{self, GetDefId, ToSource, TypeKind};
@@ -194,13 +194,15 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
194194
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
195195
let generics = filter_non_trait_generics(did, generics);
196196
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
197+
let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
197198
let is_auto = cx.tcx.trait_is_auto(did);
198199
clean::Trait {
199200
auto: auto_trait,
200201
unsafety: cx.tcx.trait_def(did).unsafety,
201202
generics,
202203
items: trait_items,
203204
bounds: supertrait_bounds,
205+
is_spotlight,
204206
is_auto,
205207
}
206208
}

src/librustdoc/clean/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,7 @@ impl Clean<FnRetTy> for hir::FnRetTy<'_> {
10071007
impl Clean<Item> for doctree::Trait<'_> {
10081008
fn clean(&self, cx: &DocContext<'_>) -> Item {
10091009
let attrs = self.attrs.clean(cx);
1010+
let is_spotlight = attrs.has_doc_flag(sym::spotlight);
10101011
Item {
10111012
name: Some(self.name.clean(cx)),
10121013
attrs,
@@ -1021,6 +1022,7 @@ impl Clean<Item> for doctree::Trait<'_> {
10211022
items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
10221023
generics: self.generics.clean(cx),
10231024
bounds: self.bounds.clean(cx),
1025+
is_spotlight,
10241026
is_auto: self.is_auto.clean(cx),
10251027
}),
10261028
}

src/librustdoc/clean/types.rs

+1
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,7 @@ pub struct Trait {
995995
pub items: Vec<Item>,
996996
pub generics: Generics,
997997
pub bounds: Vec<GenericBound>,
998+
pub is_spotlight: bool,
998999
pub is_auto: bool,
9991000
}
10001001

src/librustdoc/html/format.rs

+12
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,22 @@ impl Buffer {
6363
Buffer { for_html: false, buffer: String::new() }
6464
}
6565

66+
crate fn is_empty(&self) -> bool {
67+
self.buffer.is_empty()
68+
}
69+
6670
crate fn into_inner(self) -> String {
6771
self.buffer
6872
}
6973

74+
crate fn insert_str(&mut self, idx: usize, s: &str) {
75+
self.buffer.insert_str(idx, s);
76+
}
77+
78+
crate fn push_str(&mut self, s: &str) {
79+
self.buffer.push_str(s);
80+
}
81+
7082
// Intended for consumption by write! and writeln! (std::fmt) but without
7183
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
7284
// import).

src/librustdoc/html/render.rs

+82-5
Original file line numberDiff line numberDiff line change
@@ -2410,7 +2410,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
24102410
f.generics.print()
24112411
)
24122412
.len();
2413-
write!(w, "<pre class='rust fn'>");
2413+
write!(w, "{}<pre class='rust fn'>", render_spotlight_traits(it));
24142414
render_attributes(w, it, false);
24152415
write!(
24162416
w,
@@ -2612,7 +2612,12 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait)
26122612
let name = m.name.as_ref().unwrap();
26132613
let item_type = m.type_();
26142614
let id = cx.derive_id(format!("{}.{}", item_type, name));
2615-
write!(w, "<h3 id='{id}' class='method'><code>", id = id);
2615+
write!(
2616+
w,
2617+
"<h3 id='{id}' class='method'>{extra}<code>",
2618+
extra = render_spotlight_traits(m),
2619+
id = id
2620+
);
26162621
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
26172622
write!(w, "</code>");
26182623
render_stability_since(w, m, t);
@@ -3559,6 +3564,76 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
35593564
}
35603565
}
35613566

3567+
fn render_spotlight_traits(item: &clean::Item) -> String {
3568+
match item.inner {
3569+
clean::FunctionItem(clean::Function { ref decl, .. })
3570+
| clean::TyMethodItem(clean::TyMethod { ref decl, .. })
3571+
| clean::MethodItem(clean::Method { ref decl, .. })
3572+
| clean::ForeignFunctionItem(clean::Function { ref decl, .. }) => spotlight_decl(decl),
3573+
_ => String::new(),
3574+
}
3575+
}
3576+
3577+
fn spotlight_decl(decl: &clean::FnDecl) -> String {
3578+
let mut out = Buffer::html();
3579+
let mut trait_ = String::new();
3580+
3581+
if let Some(did) = decl.output.def_id() {
3582+
let c = cache();
3583+
if let Some(impls) = c.impls.get(&did) {
3584+
for i in impls {
3585+
let impl_ = i.inner_impl();
3586+
if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
3587+
if out.is_empty() {
3588+
out.push_str(&format!(
3589+
"<h3 class=\"important\">Important traits for {}</h3>\
3590+
<code class=\"content\">",
3591+
impl_.for_.print()
3592+
));
3593+
trait_.push_str(&impl_.for_.print().to_string());
3594+
}
3595+
3596+
//use the "where" class here to make it small
3597+
out.push_str(&format!(
3598+
"<span class=\"where fmt-newline\">{}</span>",
3599+
impl_.print()
3600+
));
3601+
let t_did = impl_.trait_.def_id().unwrap();
3602+
for it in &impl_.items {
3603+
if let clean::TypedefItem(ref tydef, _) = it.inner {
3604+
out.push_str("<span class=\"where fmt-newline\"> ");
3605+
assoc_type(
3606+
&mut out,
3607+
it,
3608+
&[],
3609+
Some(&tydef.type_),
3610+
AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
3611+
"",
3612+
);
3613+
out.push_str(";</span>");
3614+
}
3615+
}
3616+
}
3617+
}
3618+
}
3619+
}
3620+
3621+
if !out.is_empty() {
3622+
out.insert_str(
3623+
0,
3624+
&format!(
3625+
"<div class=\"important-traits\"><div class='tooltip'>ⓘ\
3626+
<span class='tooltiptext'>Important traits for {}</span></div>\
3627+
<div class=\"content hidden\">",
3628+
trait_
3629+
),
3630+
);
3631+
out.push_str("</code></div></div>");
3632+
}
3633+
3634+
out.into_inner()
3635+
}
3636+
35623637
fn render_impl(
35633638
w: &mut Buffer,
35643639
cx: &Context,
@@ -3665,12 +3740,14 @@ fn render_impl(
36653740
(true, " hidden")
36663741
};
36673742
match item.inner {
3668-
clean::MethodItem(clean::Method { .. })
3669-
| clean::TyMethodItem(clean::TyMethod { .. }) => {
3743+
clean::MethodItem(clean::Method { ref decl, .. })
3744+
| clean::TyMethodItem(clean::TyMethod { ref decl, .. }) => {
36703745
// Only render when the method is not static or we allow static methods
36713746
if render_method_item {
36723747
let id = cx.derive_id(format!("{}.{}", item_type, name));
3673-
write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
3748+
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class);
3749+
write!(w, "{}", spotlight_decl(decl));
3750+
write!(w, "<code>");
36743751
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
36753752
write!(w, "</code>");
36763753
render_stability_since_raw(w, item.stable_since(), outer_version);

src/librustdoc/html/static/main.js

+28
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ function defocusSearchBar() {
365365
function handleEscape(ev) {
366366
var help = getHelpElement();
367367
var search = getSearchElement();
368+
hideModal();
368369
if (hasClass(help, "hidden") === false) {
369370
displayHelp(false, ev, help);
370371
} else if (hasClass(search, "hidden") === false) {
@@ -397,6 +398,7 @@ function defocusSearchBar() {
397398
case "s":
398399
case "S":
399400
displayHelp(false, ev);
401+
hideModal();
400402
ev.preventDefault();
401403
focusSearchBar();
402404
break;
@@ -409,6 +411,7 @@ function defocusSearchBar() {
409411

410412
case "?":
411413
if (ev.shiftKey) {
414+
hideModal();
412415
displayHelp(true, ev);
413416
}
414417
break;
@@ -2636,6 +2639,31 @@ function defocusSearchBar() {
26362639
});
26372640
}());
26382641

2642+
function showModal(content) {
2643+
var modal = document.createElement("div");
2644+
modal.id = "important";
2645+
addClass(modal, "modal");
2646+
modal.innerHTML = "<div class=\"modal-content\"><div class=\"close\" id=\"modal-close\">✕" +
2647+
"</div><div class=\"whiter\"></div><span class=\"docblock\">" + content +
2648+
"</span></div>";
2649+
document.getElementsByTagName("body")[0].appendChild(modal);
2650+
document.getElementById("modal-close").onclick = hideModal;
2651+
modal.onclick = hideModal;
2652+
}
2653+
2654+
function hideModal() {
2655+
var modal = document.getElementById("important");
2656+
if (modal) {
2657+
modal.parentNode.removeChild(modal);
2658+
}
2659+
}
2660+
2661+
onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
2662+
e.onclick = function() {
2663+
showModal(e.lastElementChild.innerHTML);
2664+
};
2665+
});
2666+
26392667
// In the search display, allows to switch between tabs.
26402668
function printTab(nb) {
26412669
if (nb === 0 || nb === 1 || nb === 2) {

0 commit comments

Comments
 (0)