Skip to content

Commit 681da13

Browse files
authored
Rollup merge of rust-lang#146838 - yotamofek:pr/rustdoc/wrappers, r=lolbinarycat
Introduce "wrapper" helpers to rustdoc Add a few traits for streamlining places where we need to wrap certain `fmt::Display`s in stuff like parentheses or brackets. Hopefully this makes the actual display logic slightly easier to read. First two commits are small, unrelated cleanups. I'll probably add some doc comments to the stuff in `display.rs`, maybe also play around with the API, but wanted to get feedback on this idea first.
2 parents 46be365 + 2067160 commit 681da13

File tree

4 files changed

+262
-251
lines changed

4 files changed

+262
-251
lines changed

src/librustdoc/clean/cfg.rs

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
// FIXME: Once the portability lint RFC is implemented (see tracking issue #41619),
44
// switch to use those structures instead.
55

6-
use std::fmt::{self, Write};
7-
use std::{mem, ops};
6+
use std::{fmt, mem, ops};
87

8+
use itertools::Either;
99
use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
1010
use rustc_data_structures::fx::FxHashSet;
1111
use rustc_session::parse::ParseSess;
1212
use rustc_span::Span;
1313
use rustc_span::symbol::{Symbol, sym};
1414

15-
use crate::display::Joined as _;
15+
use crate::display::{Joined as _, MaybeDisplay, Wrapped};
1616
use crate::html::escape::Escape;
1717

1818
#[cfg(test)]
@@ -376,27 +376,20 @@ impl Format {
376376
Format::LongPlain => false,
377377
}
378378
}
379+
380+
fn escape(self, s: &str) -> impl fmt::Display {
381+
if self.is_html() { Either::Left(Escape(s)) } else { Either::Right(s) }
382+
}
379383
}
380384

381385
/// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used.
382386
struct Display<'a>(&'a Cfg, Format);
383387

384-
fn write_with_opt_paren<T: fmt::Display>(
385-
fmt: &mut fmt::Formatter<'_>,
386-
has_paren: bool,
387-
obj: T,
388-
) -> fmt::Result {
389-
if has_paren {
390-
fmt.write_char('(')?;
391-
}
392-
obj.fmt(fmt)?;
393-
if has_paren {
394-
fmt.write_char(')')?;
388+
impl Display<'_> {
389+
fn code_wrappers(&self) -> Wrapped<&'static str> {
390+
if self.1.is_html() { Wrapped::with("<code>", "</code>") } else { Wrapped::with("`", "`") }
395391
}
396-
Ok(())
397-
}
398392

399-
impl Display<'_> {
400393
fn display_sub_cfgs(
401394
&self,
402395
fmt: &mut fmt::Formatter<'_>,
@@ -427,20 +420,17 @@ impl Display<'_> {
427420
sub_cfgs
428421
.iter()
429422
.map(|sub_cfg| {
430-
fmt::from_fn(move |fmt| {
431-
if let Cfg::Cfg(_, Some(feat)) = sub_cfg
432-
&& short_longhand
433-
{
434-
if self.1.is_html() {
435-
write!(fmt, "<code>{feat}</code>")?;
436-
} else {
437-
write!(fmt, "`{feat}`")?;
438-
}
439-
} else {
440-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?;
441-
}
442-
Ok(())
443-
})
423+
if let Cfg::Cfg(_, Some(feat)) = sub_cfg
424+
&& short_longhand
425+
{
426+
Either::Left(self.code_wrappers().wrap(feat))
427+
} else {
428+
Either::Right(
429+
Wrapped::with_parens()
430+
.when(!sub_cfg.is_all())
431+
.wrap(Display(sub_cfg, self.1)),
432+
)
433+
}
444434
})
445435
.joined(separator, f)
446436
})
@@ -461,9 +451,9 @@ impl fmt::Display for Display<'_> {
461451
sub_cfgs
462452
.iter()
463453
.map(|sub_cfg| {
464-
fmt::from_fn(|fmt| {
465-
write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))
466-
})
454+
Wrapped::with_parens()
455+
.when(!sub_cfg.is_all())
456+
.wrap(Display(sub_cfg, self.1))
467457
})
468458
.joined(separator, fmt)
469459
}
@@ -568,21 +558,13 @@ impl fmt::Display for Display<'_> {
568558
};
569559
if !human_readable.is_empty() {
570560
fmt.write_str(human_readable)
571-
} else if let Some(v) = value {
572-
if self.1.is_html() {
573-
write!(
574-
fmt,
575-
r#"<code>{}="{}"</code>"#,
576-
Escape(name.as_str()),
577-
Escape(v.as_str())
578-
)
579-
} else {
580-
write!(fmt, r#"`{name}="{v}"`"#)
581-
}
582-
} else if self.1.is_html() {
583-
write!(fmt, "<code>{}</code>", Escape(name.as_str()))
584561
} else {
585-
write!(fmt, "`{name}`")
562+
let value = value
563+
.map(|v| fmt::from_fn(move |f| write!(f, "={}", self.1.escape(v.as_str()))))
564+
.maybe_display();
565+
self.code_wrappers()
566+
.wrap(format_args!("{}{value}", self.1.escape(name.as_str())))
567+
.fmt(fmt)
586568
}
587569
}
588570
}

src/librustdoc/display.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Various utilities for working with [`fmt::Display`] implementations.
22
3-
use std::fmt::{self, Display, Formatter};
3+
use std::fmt::{self, Display, Formatter, FormattingOptions};
44

55
pub(crate) trait Joined: IntoIterator {
66
/// Takes an iterator over elements that implement [`Display`], and format them into `f`, separated by `sep`.
@@ -45,3 +45,87 @@ impl<T: Display> MaybeDisplay for Option<T> {
4545
})
4646
}
4747
}
48+
49+
#[derive(Clone, Copy)]
50+
pub(crate) struct Wrapped<T> {
51+
prefix: T,
52+
suffix: T,
53+
}
54+
55+
pub(crate) enum AngleBracket {
56+
Open,
57+
Close,
58+
}
59+
60+
impl Display for AngleBracket {
61+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
62+
f.write_str(match (self, f.alternate()) {
63+
(Self::Open, true) => "<",
64+
(Self::Open, false) => "&lt;",
65+
(Self::Close, true) => ">",
66+
(Self::Close, false) => "&gt;",
67+
})
68+
}
69+
}
70+
71+
impl Wrapped<AngleBracket> {
72+
pub(crate) fn with_angle_brackets() -> Self {
73+
Self { prefix: AngleBracket::Open, suffix: AngleBracket::Close }
74+
}
75+
}
76+
77+
impl Wrapped<char> {
78+
pub(crate) fn with_parens() -> Self {
79+
Self { prefix: '(', suffix: ')' }
80+
}
81+
82+
pub(crate) fn with_square_brackets() -> Self {
83+
Self { prefix: '[', suffix: ']' }
84+
}
85+
}
86+
87+
impl<T: Display> Wrapped<T> {
88+
pub(crate) fn with(prefix: T, suffix: T) -> Self {
89+
Self { prefix, suffix }
90+
}
91+
92+
pub(crate) fn when(self, if_: bool) -> Wrapped<impl Display> {
93+
Wrapped {
94+
prefix: if_.then_some(self.prefix).maybe_display(),
95+
suffix: if_.then_some(self.suffix).maybe_display(),
96+
}
97+
}
98+
99+
pub(crate) fn wrap_fn(
100+
self,
101+
content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
102+
) -> impl Display {
103+
fmt::from_fn(move |f| {
104+
self.prefix.fmt(f)?;
105+
content(f)?;
106+
self.suffix.fmt(f)
107+
})
108+
}
109+
110+
pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
111+
self.wrap_fn(move |f| content.fmt(f))
112+
}
113+
}
114+
115+
#[derive(Clone, Copy)]
116+
pub(crate) struct WithOpts {
117+
opts: FormattingOptions,
118+
}
119+
120+
impl WithOpts {
121+
pub(crate) fn from(f: &Formatter<'_>) -> Self {
122+
Self { opts: f.options() }
123+
}
124+
125+
pub(crate) fn display(self, t: impl Display) -> impl Display {
126+
fmt::from_fn(move |f| {
127+
let mut f = f.with_options(self.opts);
128+
t.fmt(&mut f)
129+
})
130+
}
131+
}

0 commit comments

Comments
 (0)