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    /// Whether content-specific rendering should use dark-mode assets.
52    pub is_dark: bool,
53}
54
55impl Default for TextViewStyle {
56    fn default() -> Self {
57        Self {
58            paragraph_gap: rems(1.),
59            heading_base_font_size: px(14.),
60            heading_font_size: None,
61            highlight_theme: HighlightTheme::default_light().clone(),
62            code_block: StyleRefinement::default(),
63            table: StyleRefinement::default(),
64            table_head: StyleRefinement::default(),
65            table_cell: StyleRefinement::default(),
66            inline_code: HighlightStyle::default(),
67            is_dark: false,
68        }
69    }
70}
71
72impl PartialEq for TextViewStyle {
73    fn eq(&self, other: &Self) -> bool {
74        self.paragraph_gap == other.paragraph_gap
75            && self.heading_base_font_size == other.heading_base_font_size
76            && match (&self.heading_font_size, &other.heading_font_size) {
77                (Some(left), Some(right)) => (1..=6).all(|level| {
78                    left(level, self.heading_base_font_size)
79                        == right(level, other.heading_base_font_size)
80                }),
81                (None, None) => true,
82                _ => false,
83            }
84            && self.highlight_theme == other.highlight_theme
85            && self.code_block == other.code_block
86            && self.table == other.table
87            && self.table_head == other.table_head
88            && self.table_cell == other.table_cell
89            && self.inline_code == other.inline_code
90            && self.is_dark == other.is_dark
91    }
92}
93
94impl TextViewStyle {
95    /// Set paragraph gap, default is 1 rem.
96    pub fn paragraph_gap(mut self, gap: Rems) -> Self {
97        self.paragraph_gap = gap;
98        self
99    }
100    /// Set the function that resolves a heading's font size from its level
101    /// (1-6) and [`Self::heading_base_font_size`].
102    pub fn heading_font_size<F>(mut self, f: F) -> Self
103    where
104        F: Fn(u8, Pixels) -> Pixels + Send + Sync + 'static,
105    {
106        self.heading_font_size = Some(Arc::new(f));
107        self
108    }
109    /// Set style for code blocks.
110    pub fn code_block(mut self, style: StyleRefinement) -> Self {
111        self.code_block = style;
112        self
113    }
114    /// Set style for inline code spans.
115    pub fn inline_code(mut self, style: HighlightStyle) -> Self {
116        self.inline_code = style;
117        self
118    }
119    /// Set extra style for the table container.
120    ///
121    /// Set `overflow_x: scroll` on the refinement for adaptive layout: cells
122    /// wrap as the frame narrows, and once columns reach their minimum width
123    /// the table scrolls horizontally instead of shrinking further.
124    pub fn table(mut self, style: StyleRefinement) -> Self {
125        self.table = style;
126        self
127    }
128    /// Set extra style for the table header row.
129    pub fn table_head(mut self, style: StyleRefinement) -> Self {
130        self.table_head = style;
131        self
132    }
133    /// Set extra style for each table cell.
134    ///
135    /// With the scroll table layout, `white_space: nowrap` here keeps cells
136    /// on a single line and the table scrolls whenever the content is wider
137    /// than the frame.
138    pub fn table_cell(mut self, style: StyleRefinement) -> Self {
139        self.table_cell = style;
140        self
141    }
142}