Skip to content

Commit 48d72e3

Browse files
committed
Introduce "wrapper" helpers to rustdoc
1 parent bacb853 commit 48d72e3

File tree

4 files changed

+247
-238
lines changed

4 files changed

+247
-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, Wrapper};
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) -> Wrapper<&'static str> {
390+
if self.1.is_html() { Wrapper::new("<code>", "</code>") } else { Wrapper::new("`", "`") }
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+
Wrapper::parentheses()
430+
.optional(!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+
Wrapper::parentheses()
455+
.optional(!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: 83 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,85 @@ impl<T: Display> MaybeDisplay for Option<T> {
4545
})
4646
}
4747
}
48+
49+
#[derive(Clone, Copy)]
50+
pub(crate) struct Wrapper<T> {
51+
prefix: T,
52+
suffix: T,
53+
}
54+
55+
pub(crate) struct AltBracket {
56+
normal: &'static str,
57+
alternate: &'static str,
58+
}
59+
60+
impl Display for AltBracket {
61+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
62+
if f.alternate() { f.write_str(self.alternate) } else { f.write_str(self.normal) }
63+
}
64+
}
65+
66+
impl Wrapper<AltBracket> {
67+
pub(crate) fn angle_brackets() -> Self {
68+
Self {
69+
prefix: AltBracket { normal: "&lt;", alternate: "<" },
70+
suffix: AltBracket { normal: "&gt;", alternate: ">" },
71+
}
72+
}
73+
}
74+
75+
impl Wrapper<char> {
76+
pub(crate) fn parentheses() -> Self {
77+
Self { prefix: '(', suffix: ')' }
78+
}
79+
80+
pub(crate) fn square_brackets() -> Self {
81+
Self { prefix: '[', suffix: ']' }
82+
}
83+
}
84+
85+
impl<T: Display> Wrapper<T> {
86+
pub(crate) fn new(prefix: T, suffix: T) -> Self {
87+
Self { prefix, suffix }
88+
}
89+
90+
pub(crate) fn optional(self, if_: bool) -> Wrapper<impl Display> {
91+
Wrapper {
92+
prefix: if_.then_some(self.prefix).maybe_display(),
93+
suffix: if_.then_some(self.suffix).maybe_display(),
94+
}
95+
}
96+
97+
pub(crate) fn wrap_fn(
98+
self,
99+
content: impl Fn(&mut Formatter<'_>) -> fmt::Result,
100+
) -> impl Display {
101+
fmt::from_fn(move |f| {
102+
self.prefix.fmt(f)?;
103+
content(f)?;
104+
self.suffix.fmt(f)
105+
})
106+
}
107+
108+
pub(crate) fn wrap<C: Display>(self, content: C) -> impl Display {
109+
self.wrap_fn(move |f| content.fmt(f))
110+
}
111+
}
112+
113+
#[derive(Clone, Copy)]
114+
pub(crate) struct WithOpts {
115+
opts: FormattingOptions,
116+
}
117+
118+
impl WithOpts {
119+
pub(crate) fn new(f: &Formatter<'_>) -> Self {
120+
Self { opts: f.options() }
121+
}
122+
123+
pub(crate) fn display(self, t: impl Display) -> impl Display {
124+
fmt::from_fn(move |f| {
125+
let mut f = f.with_options(self.opts);
126+
t.fmt(&mut f)
127+
})
128+
}
129+
}

0 commit comments

Comments
 (0)