Skip to content

Commit 2067160

Browse files
committed
Introduce "wrapper" helpers to rustdoc
1 parent cdf9661 commit 2067160

File tree

4 files changed

+248
-238
lines changed

4 files changed

+248
-238
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)