Skip to main content

gpui_component/text/
style.rs

1use std::sync::Arc;
2
3use gpui::{HighlightStyle, Pixels, Rems, StyleRefinement, px, rems};
4
5use crate::highlighter::HighlightTheme;
6
7/// TextViewStyle used to customize the style for [`super::TextView`].
8///
9/// This is the component-level style. It is folded onto the style the active
10/// [`crate::Theme`] already derived, so a field left at its default keeps the
11/// themed value rather than overriding it with a neutral one.
12#[derive(Clone)]
13pub struct TextViewStyle {
14    /// Gap of each paragraphs, default is 1 rem.
15    pub paragraph_gap: Rems,
16    /// Base font size for headings, default is 14px.
17    pub heading_base_font_size: Pixels,
18    /// Function to calculate heading font size based on heading level (1-6).
19    ///
20    /// The first parameter is the heading level (1-6), the second parameter is
21    /// the base font size.
22    pub heading_font_size: Option<Arc<dyn Fn(u8, Pixels) -> Pixels + Send + Sync + 'static>>,
23    /// Highlight theme for code blocks. Default: [`HighlightTheme::default_light()`]
24    pub highlight_theme: Arc<HighlightTheme>,
25    /// The style refinement for code blocks.
26    pub code_block: StyleRefinement,
27    /// Style refinement applied to the table container (the bordered wrapper
28    /// in wrap mode, the scroll viewport in horizontal-scroll mode).
29    ///
30    /// Set `overflow_x: scroll` here for adaptive table layout: columns fit
31    /// their content when space allows, shrink (wrapping cell text) down to a
32    /// per-column floor when the frame is narrower, and below that the table
33    /// scrolls horizontally instead of squeezing further, e.g.
34    /// `TextViewStyle::default().table({ let mut s = StyleRefinement::default(); s.overflow.x = Some(Overflow::Scroll); s })`.
35    pub table: StyleRefinement,
36    /// Style refinement applied to the header row (the first row) of a table,
37    /// on top of the `table_head` background and foreground from the theme.
38    pub table_head: StyleRefinement,
39    /// Style refinement applied to each table cell.
40    ///
41    /// With the scroll layout, set `white_space: nowrap` here to keep cells
42    /// on a single line — columns then never shrink and the table scrolls as
43    /// soon as the content is wider than the frame.
44    pub table_cell: StyleRefinement,
45    /// The highlight style for inline code.
46    ///
47    /// Default is [`HighlightStyle::default()`], the `background_color` will
48    /// fallback to `cx.theme().accent`, if it is `None`.
49    pub inline_code: HighlightStyle,
50    /// Whether content-specific rendering should use dark-mode assets.
51    pub is_dark: bool,
52}
53
54impl Default for TextViewStyle {
55    fn default() -> Self {
56        Self {
57            paragraph_gap: rems(1.),
58            heading_base_font_size: px(14.),
59            heading_font_size: None,
60            highlight_theme: HighlightTheme::default_light().clone(),
61            code_block: StyleRefinement::default(),
62            table: StyleRefinement::default(),
63            table_head: StyleRefinement::default(),
64            table_cell: StyleRefinement::default(),
65            inline_code: HighlightStyle::default(),
66            is_dark: false,
67        }
68    }
69}
70
71impl PartialEq for TextViewStyle {
72    fn eq(&self, other: &Self) -> bool {
73        self.paragraph_gap == other.paragraph_gap
74            && self.heading_base_font_size == other.heading_base_font_size
75            && match (&self.heading_font_size, &other.heading_font_size) {
76                (Some(left), Some(right)) => (1..=6).all(|level| {
77                    left(level, self.heading_base_font_size)
78                        == right(level, other.heading_base_font_size)
79                }),
80                (None, None) => true,
81                _ => false,
82            }
83            && self.highlight_theme == other.highlight_theme
84            && self.code_block == other.code_block
85            && self.table == other.table
86            && self.table_head == other.table_head
87            && self.table_cell == other.table_cell
88            && self.inline_code == other.inline_code
89            && self.is_dark == other.is_dark
90    }
91}
92
93impl TextViewStyle {
94    /// Set paragraph gap, default is 1 rem.
95    pub fn paragraph_gap(mut self, gap: Rems) -> Self {
96        self.paragraph_gap = gap;
97        self
98    }
99    /// Set the function that resolves a heading's font size from its level
100    /// (1-6) and [`Self::heading_base_font_size`].
101    pub fn heading_font_size<F>(mut self, f: F) -> Self
102    where
103        F: Fn(u8, Pixels) -> Pixels + Send + Sync + 'static,
104    {
105        self.heading_font_size = Some(Arc::new(f));
106        self
107    }
108    /// Set style for code blocks.
109    pub fn code_block(mut self, style: StyleRefinement) -> Self {
110        self.code_block = style;
111        self
112    }
113    /// Set style for inline code spans.
114    pub fn inline_code(mut self, style: HighlightStyle) -> Self {
115        self.inline_code = style;
116        self
117    }
118    /// Set extra style for the table container.
119    ///
120    /// Set `overflow_x: scroll` on the refinement for adaptive layout: cells
121    /// wrap as the frame narrows, and once columns reach their minimum width
122    /// the table scrolls horizontally instead of shrinking further.
123    pub fn table(mut self, style: StyleRefinement) -> Self {
124        self.table = style;
125        self
126    }
127    /// Set extra style for the table header row.
128    pub fn table_head(mut self, style: StyleRefinement) -> Self {
129        self.table_head = style;
130        self
131    }
132    /// Set extra style for each table cell.
133    ///
134    /// With the scroll table layout, `white_space: nowrap` here keeps cells
135    /// on a single line and the table scrolls whenever the content is wider
136    /// than the frame.
137    pub fn table_cell(mut self, style: StyleRefinement) -> Self {
138        self.table_cell = style;
139        self
140    }
141}