Skip to main content

gpui_macos/
text.rs

1//! Read-only rich text using base's Markdown and HTML renderers.
2use crate::ActiveTheme;
3use gpui_kit::base::{TextView, TextViewStyle};
4use gpui_kit::{App, ElementId, SharedString, StyleRefinement, Styled, Window, rems};
5
6/// Theme mapping shared by Markdown, HTML and state-backed TextViews.
7pub fn text_view_style(window: &Window, cx: &App) -> TextViewStyle {
8    let t = cx.macos();
9    TextViewStyle::from_theme(&gpui_kit::base::Theme::global(cx))
10        .with_foreground(t.foreground)
11        .with_muted_foreground(t.secondary)
12        .with_link(t.accent)
13        .with_selection(t.selection)
14        .with_border(t.divider())
15        .with_code_background(t.normal_fill())
16        .with_inline_code(gpui_kit::HighlightStyle {
17            background_color: Some(t.normal_fill()),
18            ..Default::default()
19        })
20        .with_paragraph_gap(rems(0.75))
21        .with_heading({
22            let base = rems(0.75).to_pixels(window.rem_size());
23            move |level| {
24                StyleRefinement::default().text_size(
25                    base * match level {
26                        1 => 5. / 3.,
27                        2 => 4. / 3.,
28                        3 => 7. / 6.,
29                        _ => 1.,
30                    },
31                )
32            }
33        })
34        .with_code_block(StyleRefinement::default().p(rems(0.625)).rounded(rems(0.5)))
35}
36
37pub fn markdown(
38    id: impl Into<ElementId>,
39    source: impl Into<SharedString>,
40    window: &Window,
41    cx: &App,
42) -> TextView {
43    TextView::markdown(id, source)
44        .style(text_view_style(window, cx))
45        .font_family(cx.macos().font.clone())
46        .text_size(rems(0.8125))
47        .selectable(true)
48}
49
50pub fn html(
51    id: impl Into<ElementId>,
52    source: impl Into<SharedString>,
53    window: &Window,
54    cx: &App,
55) -> TextView {
56    TextView::html(id, source)
57        .style(text_view_style(window, cx))
58        .font_family(cx.macos().font.clone())
59        .text_size(rems(0.8125))
60        .selectable(true)
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66    use gpui_kit::px;
67    use gpui_kit::{Context, IntoElement, Render, TestAppContext, Window, div, point, prelude::*};
68
69    struct Document {
70        html: bool,
71    }
72    impl Render for Document {
73        fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
74            let text = if self.html {
75                html(
76                    "document",
77                    "<p><a href=\"https://github.com/huacnlee/gpui-macos/issues\">Project source</a></p>",
78                    window,
79                    cx,
80                )
81            } else {
82                markdown(
83                    "document",
84                    "[Project source](https://github.com/huacnlee/gpui-macos)",
85                    window,
86                    cx,
87                )
88            };
89            div().w(rems(20.)).child(text)
90        }
91    }
92
93    #[gpui_kit::test]
94    fn markdown_and_html_links_open_their_destination(cx: &mut TestAppContext) {
95        cx.update(crate::init);
96        for html in [false, true] {
97            let (_, window) = cx.add_window_view(move |_, _| Document { html });
98            window.update(|window, cx| window.draw(cx).clear(cx));
99            window.simulate_click(point(px(10.), px(10.)), Default::default());
100            assert_eq!(
101                window.opened_url().as_deref(),
102                Some(if html {
103                    "https://github.com/huacnlee/gpui-macos/issues"
104                } else {
105                    "https://github.com/huacnlee/gpui-macos"
106                })
107            );
108        }
109    }
110}