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}