Skip to main content

markdown/
typography.rs

1//! What a document is set in.
2//!
3//! Installed once at boot like the highlighter and the link preview, and read
4//! at paint: how a document is set is the app's decision, and this crate holds
5//! only what it defaults to.
6
7use gpui::{App, FontWeight, Global};
8use theme::{Metrics, TextStyle};
9
10/// What a document is set in, role by role.
11#[derive(Clone, Copy, Debug, PartialEq)]
12pub struct Typography {
13    pub body: Metrics,
14    pub h1: Metrics,
15    pub h2: Metrics,
16    pub h3: Metrics,
17    /// Every heading past the third.
18    pub h4: Metrics,
19    /// Code, in a fence and inline.
20    pub code: Metrics,
21    /// A bookmark card's blurb and footer.
22    pub card: Metrics,
23    /// An image's caption.
24    pub caption: Metrics,
25}
26
27impl Typography {
28    /// What documents are set in, or [`Typography::default`] before anything is
29    /// installed. Mirrors [`theme::Theme::of`].
30    pub fn of(cx: &App) -> Self {
31        cx.try_global::<Installed>()
32            .map_or_else(Self::default, |installed| installed.0)
33    }
34
35    /// The same set at `scale` times the ladder — what a zoomed document is
36    /// painted with. Every role moves together, so the ratios hold.
37    pub fn scaled(self, scale: f32) -> Self {
38        Self {
39            body: self.body.scaled(scale),
40            h1: self.h1.scaled(scale),
41            h2: self.h2.scaled(scale),
42            h3: self.h3.scaled(scale),
43            h4: self.h4.scaled(scale),
44            code: self.code.scaled(scale),
45            card: self.card.scaled(scale),
46            caption: self.caption.scaled(scale),
47        }
48    }
49
50    pub fn heading(&self, level: u8) -> Metrics {
51        match level {
52            1 => self.h1,
53            2 => self.h2,
54            3 => self.h3,
55            _ => self.h4,
56        }
57    }
58}
59
60impl Default for Typography {
61    /// Each leading is written as the pixel pair it came from, so the ratio the
62    /// document was tuned at survives a change of size.
63    fn default() -> Self {
64        Self {
65            body: Metrics::new(TextStyle::Body, 22.0 / 14.0, FontWeight::NORMAL),
66            h1: Metrics::new(TextStyle::Title, 27.0 / 19.0, FontWeight::SEMIBOLD),
67            h2: Metrics::new(TextStyle::Title2, 24.0 / 16.0, FontWeight::SEMIBOLD),
68            h3: Metrics::new(TextStyle::Title3, 22.0 / 15.0, FontWeight::SEMIBOLD),
69            h4: Metrics::new(TextStyle::Headline, 22.0 / 14.0, FontWeight::SEMIBOLD),
70            code: Metrics::new(TextStyle::Callout, 18.0 / 12.5, FontWeight::NORMAL),
71            card: Metrics::new(TextStyle::Callout, 17.0 / 12.0, FontWeight::NORMAL),
72            caption: Metrics::new(TextStyle::Subheadline, 17.0 / 11.5, FontWeight::NORMAL),
73        }
74    }
75}
76
77struct Installed(Typography);
78
79impl Global for Installed {}
80
81/// `markdown::set_typography(cx, my_typography)` — call once at boot.
82pub fn set_typography(cx: &mut App, typography: Typography) {
83    cx.set_global(Installed(typography));
84}