Skip to content

Commit 3328bd9

Browse files
committed
Add long cfg description to tooltip on short description
1 parent 234ec95 commit 3328bd9

File tree

3 files changed

+105
-38
lines changed

3 files changed

+105
-38
lines changed

src/librustdoc/clean/cfg.rs

+83-32
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl Cfg {
135135

136136
/// Renders the configuration for human display, as a short HTML description.
137137
pub(crate) fn render_short_html(&self) -> String {
138-
let mut msg = Html(self, true).to_string();
138+
let mut msg = Display(self, Format::ShortHtml).to_string();
139139
if self.should_capitalize_first_letter() {
140140
if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) {
141141
msg[i..i + 1].make_ascii_uppercase();
@@ -148,14 +148,29 @@ impl Cfg {
148148
pub(crate) fn render_long_html(&self) -> String {
149149
let on = if self.should_use_with_in_description() { "with" } else { "on" };
150150

151-
let mut msg = format!("This is supported {} <strong>{}</strong>", on, Html(self, false));
151+
let mut msg = format!(
152+
"This is supported {} <strong>{}</strong>",
153+
on,
154+
Display(self, Format::LongHtml)
155+
);
152156
if self.should_append_only_to_description() {
153157
msg.push_str(" only");
154158
}
155159
msg.push('.');
156160
msg
157161
}
158162

163+
/// Renders the configuration for long display, as a long plain text description.
164+
pub(crate) fn render_long_plain(&self) -> String {
165+
let on = if self.should_use_with_in_description() { "with" } else { "on" };
166+
167+
let mut msg = format!("This is supported {} {}", on, Display(self, Format::LongPlain));
168+
if self.should_append_only_to_description() {
169+
msg.push_str(" only");
170+
}
171+
msg
172+
}
173+
159174
fn should_capitalize_first_letter(&self) -> bool {
160175
match *self {
161176
Cfg::False | Cfg::True | Cfg::Not(..) => true,
@@ -286,9 +301,31 @@ impl ops::BitOr for Cfg {
286301
}
287302
}
288303

289-
/// Pretty-print wrapper for a `Cfg`. Also indicates whether the "short-form" rendering should be
290-
/// used.
291-
struct Html<'a>(&'a Cfg, bool);
304+
#[derive(Clone, Copy)]
305+
enum Format {
306+
LongHtml,
307+
LongPlain,
308+
ShortHtml,
309+
}
310+
311+
impl Format {
312+
fn is_long(self) -> bool {
313+
match self {
314+
Format::LongHtml | Format::LongPlain => true,
315+
Format::ShortHtml => false,
316+
}
317+
}
318+
319+
fn is_html(self) -> bool {
320+
match self {
321+
Format::LongHtml | Format::ShortHtml => true,
322+
Format::LongPlain => false,
323+
}
324+
}
325+
}
326+
327+
/// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
328+
struct Display<'a>(&'a Cfg, Format);
292329

293330
fn write_with_opt_paren<T: fmt::Display>(
294331
fmt: &mut fmt::Formatter<'_>,
@@ -305,7 +342,7 @@ fn write_with_opt_paren<T: fmt::Display>(
305342
Ok(())
306343
}
307344

308-
impl<'a> fmt::Display for Html<'a> {
345+
impl<'a> fmt::Display for Display<'a> {
309346
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
310347
match *self.0 {
311348
Cfg::Not(ref child) => match **child {
@@ -314,18 +351,18 @@ impl<'a> fmt::Display for Html<'a> {
314351
if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " };
315352
for (i, sub_cfg) in sub_cfgs.iter().enumerate() {
316353
fmt.write_str(if i == 0 { "neither " } else { separator })?;
317-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
354+
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
318355
}
319356
Ok(())
320357
}
321-
ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple, self.1)),
322-
ref c => write!(fmt, "not ({})", Html(c, self.1)),
358+
ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)),
359+
ref c => write!(fmt, "not ({})", Display(c, self.1)),
323360
},
324361

325362
Cfg::Any(ref sub_cfgs) => {
326363
let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " };
327364

328-
let short_longhand = !self.1 && {
365+
let short_longhand = self.1.is_long() && {
329366
let all_crate_features = sub_cfgs
330367
.iter()
331368
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
@@ -349,16 +386,20 @@ impl<'a> fmt::Display for Html<'a> {
349386
fmt.write_str(separator)?;
350387
}
351388
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
352-
write!(fmt, "<code>{}</code>", feat)?;
389+
if self.1.is_html() {
390+
write!(fmt, "<code>{}</code>", feat)?;
391+
} else {
392+
write!(fmt, "`{}`", feat)?;
393+
}
353394
} else {
354-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?;
395+
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
355396
}
356397
}
357398
Ok(())
358399
}
359400

360401
Cfg::All(ref sub_cfgs) => {
361-
let short_longhand = !self.1 && {
402+
let short_longhand = self.1.is_long() && {
362403
let all_crate_features = sub_cfgs
363404
.iter()
364405
.all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_))));
@@ -382,9 +423,13 @@ impl<'a> fmt::Display for Html<'a> {
382423
fmt.write_str(" and ")?;
383424
}
384425
if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) {
385-
write!(fmt, "<code>{}</code>", feat)?;
426+
if self.1.is_html() {
427+
write!(fmt, "<code>{}</code>", feat)?;
428+
} else {
429+
write!(fmt, "`{}`", feat)?;
430+
}
386431
} else {
387-
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg, self.1))?;
432+
write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?;
388433
}
389434
}
390435
Ok(())
@@ -453,33 +498,39 @@ impl<'a> fmt::Display for Html<'a> {
453498
},
454499
(sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian),
455500
(sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits),
456-
(sym::target_feature, Some(feat)) => {
457-
if self.1 {
458-
return write!(fmt, "<code>{}</code>", feat);
459-
} else {
501+
(sym::target_feature, Some(feat)) => match self.1 {
502+
Format::LongHtml => {
460503
return write!(fmt, "target feature <code>{}</code>", feat);
461504
}
462-
}
463-
(sym::feature, Some(feat)) => {
464-
if self.1 {
465-
return write!(fmt, "<code>{}</code>", feat);
466-
} else {
505+
Format::LongPlain => return write!(fmt, "target feature `{}`", feat),
506+
Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat),
507+
},
508+
(sym::feature, Some(feat)) => match self.1 {
509+
Format::LongHtml => {
467510
return write!(fmt, "crate feature <code>{}</code>", feat);
468511
}
469-
}
512+
Format::LongPlain => return write!(fmt, "crate feature `{}`", feat),
513+
Format::ShortHtml => return write!(fmt, "<code>{}</code>", feat),
514+
},
470515
_ => "",
471516
};
472517
if !human_readable.is_empty() {
473518
fmt.write_str(human_readable)
474519
} else if let Some(v) = value {
475-
write!(
476-
fmt,
477-
"<code>{}=\"{}\"</code>",
478-
Escape(&name.as_str()),
479-
Escape(&v.as_str())
480-
)
481-
} else {
520+
if self.1.is_html() {
521+
write!(
522+
fmt,
523+
r#"<code>{}="{}"</code>"#,
524+
Escape(&name.as_str()),
525+
Escape(&v.as_str())
526+
)
527+
} else {
528+
write!(fmt, r#"`{}="{}"`"#, name, v)
529+
}
530+
} else if self.1.is_html() {
482531
write!(fmt, "<code>{}</code>", Escape(&name.as_str()))
532+
} else {
533+
write!(fmt, "`{}`", name)
483534
}
484535
}
485536
}

src/librustdoc/html/render/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -2108,8 +2108,8 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
21082108
fn stability_tags(item: &clean::Item) -> String {
21092109
let mut tags = String::new();
21102110

2111-
fn tag_html(class: &str, contents: &str) -> String {
2112-
format!(r#"<span class="stab {}">{}</span>"#, class, contents)
2111+
fn tag_html(class: &str, title: &str, contents: &str) -> String {
2112+
format!(r#"<span class="stab {}" title="{}">{}</span>"#, class, Escape(title), contents)
21132113
}
21142114

21152115
// The trailing space after each tag is to space it properly against the rest of the docs.
@@ -2118,7 +2118,7 @@ fn stability_tags(item: &clean::Item) -> String {
21182118
if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) {
21192119
message = "Deprecation planned";
21202120
}
2121-
tags += &tag_html("deprecated", message);
2121+
tags += &tag_html("deprecated", "", message);
21222122
}
21232123

21242124
// The "rustc_private" crates are permanently unstable so it makes no sense
@@ -2129,11 +2129,11 @@ fn stability_tags(item: &clean::Item) -> String {
21292129
.map(|s| s.level == stability::Unstable && s.feature.as_deref() != Some("rustc_private"))
21302130
== Some(true)
21312131
{
2132-
tags += &tag_html("unstable", "Experimental");
2132+
tags += &tag_html("unstable", "", "Experimental");
21332133
}
21342134

21352135
if let Some(ref cfg) = item.attrs.cfg {
2136-
tags += &tag_html("portability", &cfg.render_short_html());
2136+
tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html());
21372137
}
21382138

21392139
tags

src/test/rustdoc/duplicate-cfg.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,20 @@
33
#![crate_name = "foo"]
44
#![feature(doc_cfg)]
55

6+
// @has 'foo/index.html'
7+
// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$'
8+
// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only'
9+
610
// @has 'foo/struct.Foo.html'
7-
// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
11+
// @has '-' '//*[@class="stab portability"]' 'sync'
812
#[doc(cfg(feature = "sync"))]
913
#[doc(cfg(feature = "sync"))]
1014
pub struct Foo;
1115

16+
// @has 'foo/bar/index.html'
17+
// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$'
18+
// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only'
19+
1220
// @has 'foo/bar/struct.Bar.html'
1321
// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.'
1422
#[doc(cfg(feature = "sync"))]
@@ -17,6 +25,10 @@ pub mod bar {
1725
pub struct Bar;
1826
}
1927

28+
// @has 'foo/baz/index.html'
29+
// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$'
30+
// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only'
31+
2032
// @has 'foo/baz/struct.Baz.html'
2133
// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.'
2234
#[doc(cfg(all(feature = "sync", feature = "send")))]
@@ -33,6 +45,10 @@ pub mod qux {
3345
pub struct Qux;
3446
}
3547

48+
// @has 'foo/quux/index.html'
49+
// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$'
50+
// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only'
51+
3652
// @has 'foo/quux/struct.Quux.html'
3753
// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.'
3854
#[doc(cfg(all(feature = "sync", feature = "send", foo)))]

0 commit comments

Comments
 (0)