Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T03:34:11.732Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

settings.rs

765 lines · 29.7 KB · rust
1#![allow(missing_docs)]
2
3use crate::schema::{status_colors_refinement, syntax_overrides, theme_colors_refinement};
4use crate::{merge_accent_colors, merge_player_colors};
5use collections::HashMap;
6use gpui::{
7    App, Context, Font, FontFallbacks, FontStyle, Global, Pixels, SharedString, Subscription,
8    Window, px,
9};
10use refineable::Refineable;
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13pub use settings::{FontFamilyName, IconThemeName, ThemeAppearanceMode, ThemeName};
14use settings::{IntoGpui, RegisterSetting, Settings, SettingsContent};
15use std::sync::Arc;
16use theme::{Appearance, DEFAULT_ICON_THEME_NAME, SyntaxTheme, Theme, UiDensity};
17
18const MIN_FONT_SIZE: Pixels = px(6.0);
19const MAX_FONT_SIZE: Pixels = px(100.0);
20const MIN_LINE_HEIGHT: f32 = 1.0;
21
22pub(crate) fn ui_density_from_settings(val: settings::UiDensity) -> UiDensity {
23    match val {
24        settings::UiDensity::Compact => UiDensity::Compact,
25        settings::UiDensity::Default => UiDensity::Default,
26        settings::UiDensity::Comfortable => UiDensity::Comfortable,
27    }
28}
29
30pub fn appearance_to_mode(appearance: Appearance) -> ThemeAppearanceMode {
31    match appearance {
32        Appearance::Light => ThemeAppearanceMode::Light,
33        Appearance::Dark => ThemeAppearanceMode::Dark,
34    }
35}
36
37/// Customizable settings for the UI and theme system.
38#[derive(Clone, PartialEq, RegisterSetting)]
39pub struct ThemeSettings {
40    /// The UI font size. Determines the size of text in the UI,
41    /// as well as the size of a [gpui::Rems] unit.
42    ///
43    /// Changing this will impact the size of all UI elements.
44    ui_font_size: Pixels,
45    /// The font used for UI elements.
46    pub ui_font: Font,
47    /// The font size used for buffers, and the terminal.
48    ///
49    /// The terminal font size can be overridden using it's own setting.
50    buffer_font_size: Pixels,
51    /// The font used for buffers, and the terminal.
52    ///
53    /// The terminal font family can be overridden using it's own setting.
54    pub buffer_font: Font,
55    /// The agent font size. Determines the size of text in the agent panel. Falls back to the UI font size if unset.
56    agent_ui_font_size: Option<Pixels>,
57    /// The agent buffer font size. Determines the size of user messages in the agent panel.
58    agent_buffer_font_size: Option<Pixels>,
59    git_commit_buffer_font_size: Option<Pixels>,
60    /// The font family to use for rendering in the markdown preview.
61    /// Falls back to the UI font family if unset.
62    markdown_preview_font_family: Option<SharedString>,
63    /// The font family to use for code in the markdown preview.
64    /// Falls back to the buffer font family if unset.
65    markdown_preview_code_font_family: Option<SharedString>,
66    /// The font size to use for rendering in the markdown preview.
67    /// Falls back to the UI font size if unset.
68    markdown_preview_font_size: Option<Pixels>,
69    /// The theme to use for the markdown preview.
70    /// Falls back to the main editor theme if unset.
71    pub markdown_preview_theme: Option<ThemeSelection>,
72    /// The line height for buffers, and the terminal.
73    ///
74    /// Changing this may affect the spacing of some UI elements.
75    ///
76    /// The terminal font family can be overridden using it's own setting.
77    pub buffer_line_height: BufferLineHeight,
78    /// The current theme selection.
79    pub theme: ThemeSelection,
80    /// Manual overrides for the active theme.
81    ///
82    /// Note: This setting is still experimental. See [this tracking issue](https://github.com/zed-industries/zed/issues/18078)
83    pub experimental_theme_overrides: Option<settings::ThemeStyleContent>,
84    /// Manual overrides per theme
85    pub theme_overrides: HashMap<String, settings::ThemeStyleContent>,
86    /// The current icon theme selection.
87    pub icon_theme: IconThemeSelection,
88    /// The density of the UI.
89    /// Note: This setting is still experimental. See [this tracking issue](
90    pub ui_density: UiDensity,
91    /// The amount of fading applied to unnecessary code.
92    pub unnecessary_code_fade: f32,
93}
94
95/// Returns the name of the default theme for the given [`Appearance`].
96pub fn default_theme(appearance: Appearance) -> &'static str {
97    match appearance {
98        Appearance::Light => settings::DEFAULT_LIGHT_THEME,
99        Appearance::Dark => settings::DEFAULT_DARK_THEME,
100    }
101}
102
103#[derive(Default)]
104struct BufferFontSize(Pixels);
105
106impl Global for BufferFontSize {}
107
108#[derive(Default)]
109pub(crate) struct UiFontSize(Pixels);
110
111impl Global for UiFontSize {}
112
113/// In-memory override for the UI font size in the agent panel.
114#[derive(Default)]
115pub struct AgentUiFontSize(Pixels);
116
117impl Global for AgentUiFontSize {}
118
119/// In-memory override for the buffer font size in the agent panel.
120#[derive(Default)]
121pub struct AgentBufferFontSize(Pixels);
122
123impl Global for AgentBufferFontSize {}
124
125#[derive(Default)]
126pub struct GitCommitBufferFontSize(Pixels);
127
128impl Global for GitCommitBufferFontSize {}
129
130/// In-memory override for the markdown preview font size.
131#[derive(Default)]
132pub struct MarkdownPreviewFontSize(Pixels);
133
134impl Global for MarkdownPreviewFontSize {}
135
136/// Represents the selection of a theme, which can be either static or dynamic.
137#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
138#[serde(untagged)]
139pub enum ThemeSelection {
140    /// A static theme selection, represented by a single theme name.
141    Static(ThemeName),
142    /// A dynamic theme selection, which can change based the [ThemeMode].
143    Dynamic {
144        /// The mode used to determine which theme to use.
145        #[serde(default)]
146        mode: ThemeAppearanceMode,
147        /// The theme to use for light mode.
148        light: ThemeName,
149        /// The theme to use for dark mode.
150        dark: ThemeName,
151    },
152}
153
154impl From<settings::ThemeSelection> for ThemeSelection {
155    fn from(selection: settings::ThemeSelection) -> Self {
156        match selection {
157            settings::ThemeSelection::Static(theme) => ThemeSelection::Static(theme),
158            settings::ThemeSelection::Dynamic { mode, light, dark } => {
159                ThemeSelection::Dynamic { mode, light, dark }
160            }
161        }
162    }
163}
164
165impl ThemeSelection {
166    /// Returns the theme name for the selected [ThemeMode].
167    pub fn name(&self, system_appearance: Appearance) -> ThemeName {
168        match self {
169            Self::Static(theme) => theme.clone(),
170            Self::Dynamic { mode, light, dark } => match mode {
171                ThemeAppearanceMode::Light => light.clone(),
172                ThemeAppearanceMode::Dark => dark.clone(),
173                ThemeAppearanceMode::System => match system_appearance {
174                    Appearance::Light => light.clone(),
175                    Appearance::Dark => dark.clone(),
176                },
177            },
178        }
179    }
180
181    /// Returns the [ThemeMode] for the [ThemeSelection].
182    pub fn mode(&self) -> Option<ThemeAppearanceMode> {
183        match self {
184            ThemeSelection::Static(_) => None,
185            ThemeSelection::Dynamic { mode, .. } => Some(*mode),
186        }
187    }
188}
189
190/// Represents the selection of an icon theme, which can be either static or dynamic.
191#[derive(Clone, Debug, PartialEq, Eq)]
192pub enum IconThemeSelection {
193    /// A static icon theme selection, represented by a single icon theme name.
194    Static(IconThemeName),
195    /// A dynamic icon theme selection, which can change based on the [`ThemeMode`].
196    Dynamic {
197        /// The mode used to determine which theme to use.
198        mode: ThemeAppearanceMode,
199        /// The icon theme to use for light mode.
200        light: IconThemeName,
201        /// The icon theme to use for dark mode.
202        dark: IconThemeName,
203    },
204}
205
206impl From<settings::IconThemeSelection> for IconThemeSelection {
207    fn from(selection: settings::IconThemeSelection) -> Self {
208        match selection {
209            settings::IconThemeSelection::Static(theme) => IconThemeSelection::Static(theme),
210            settings::IconThemeSelection::Dynamic { mode, light, dark } => {
211                IconThemeSelection::Dynamic { mode, light, dark }
212            }
213        }
214    }
215}
216
217impl IconThemeSelection {
218    /// Returns the icon theme name based on the given [`Appearance`].
219    pub fn name(&self, system_appearance: Appearance) -> IconThemeName {
220        match self {
221            Self::Static(theme) => theme.clone(),
222            Self::Dynamic { mode, light, dark } => match mode {
223                ThemeAppearanceMode::Light => light.clone(),
224                ThemeAppearanceMode::Dark => dark.clone(),
225                ThemeAppearanceMode::System => match system_appearance {
226                    Appearance::Light => light.clone(),
227                    Appearance::Dark => dark.clone(),
228                },
229            },
230        }
231    }
232
233    /// Returns the [`ThemeMode`] for the [`IconThemeSelection`].
234    pub fn mode(&self) -> Option<ThemeAppearanceMode> {
235        match self {
236            IconThemeSelection::Static(_) => None,
237            IconThemeSelection::Dynamic { mode, .. } => Some(*mode),
238        }
239    }
240}
241
242/// Sets the theme for the given appearance to the theme with the specified name.
243///
244/// The caller should make sure that the [`Appearance`] matches the theme associated with the name.
245///
246/// If the current [`ThemeAppearanceMode`] is set to [`System`] and the user's system [`Appearance`]
247/// is different than the new theme's [`Appearance`], this function will update the
248/// [`ThemeAppearanceMode`] to the new theme's appearance in order to display the new theme.
249///
250/// [`System`]: ThemeAppearanceMode::System
251pub fn set_theme(
252    current: &mut SettingsContent,
253    theme_name: impl Into<Arc<str>>,
254    theme_appearance: Appearance,
255    system_appearance: Appearance,
256) {
257    let theme_name = ThemeName(theme_name.into());
258
259    let Some(selection) = current.theme.theme.as_mut() else {
260        current.theme.theme = Some(settings::ThemeSelection::Static(theme_name));
261        return;
262    };
263
264    match selection {
265        settings::ThemeSelection::Static(theme) => {
266            *theme = theme_name;
267        }
268        settings::ThemeSelection::Dynamic { mode, light, dark } => {
269            match theme_appearance {
270                Appearance::Light => *light = theme_name,
271                Appearance::Dark => *dark = theme_name,
272            }
273
274            let should_update_mode =
275                !(mode == &ThemeAppearanceMode::System && theme_appearance == system_appearance);
276
277            if should_update_mode {
278                *mode = appearance_to_mode(theme_appearance);
279            }
280        }
281    }
282}
283
284/// Sets the icon theme for the given appearance to the icon theme with the specified name.
285pub fn set_icon_theme(
286    current: &mut SettingsContent,
287    icon_theme_name: IconThemeName,
288    appearance: Appearance,
289) {
290    if let Some(selection) = current.theme.icon_theme.as_mut() {
291        let icon_theme_to_update = match selection {
292            settings::IconThemeSelection::Static(theme) => theme,
293            settings::IconThemeSelection::Dynamic { mode, light, dark } => match mode {
294                ThemeAppearanceMode::Light => light,
295                ThemeAppearanceMode::Dark => dark,
296                ThemeAppearanceMode::System => match appearance {
297                    Appearance::Light => light,
298                    Appearance::Dark => dark,
299                },
300            },
301        };
302
303        *icon_theme_to_update = icon_theme_name;
304    } else {
305        current.theme.icon_theme = Some(settings::IconThemeSelection::Static(icon_theme_name));
306    }
307}
308
309/// Sets the mode for the theme.
310pub fn set_mode(content: &mut SettingsContent, mode: ThemeAppearanceMode) {
311    let theme = content.theme.as_mut();
312
313    if let Some(selection) = theme.theme.as_mut() {
314        match selection {
315            settings::ThemeSelection::Static(_) => {
316                *selection = settings::ThemeSelection::Dynamic {
317                    mode: ThemeAppearanceMode::System,
318                    light: ThemeName(settings::DEFAULT_LIGHT_THEME.into()),
319                    dark: ThemeName(settings::DEFAULT_DARK_THEME.into()),
320                };
321            }
322            settings::ThemeSelection::Dynamic {
323                mode: mode_to_update,
324                ..
325            } => *mode_to_update = mode,
326        }
327    } else {
328        theme.theme = Some(settings::ThemeSelection::Dynamic {
329            mode,
330            light: ThemeName(settings::DEFAULT_LIGHT_THEME.into()),
331            dark: ThemeName(settings::DEFAULT_DARK_THEME.into()),
332        });
333    }
334
335    if let Some(selection) = theme.icon_theme.as_mut() {
336        match selection {
337            settings::IconThemeSelection::Static(icon_theme) => {
338                *selection = settings::IconThemeSelection::Dynamic {
339                    mode,
340                    light: icon_theme.clone(),
341                    dark: icon_theme.clone(),
342                };
343            }
344            settings::IconThemeSelection::Dynamic {
345                mode: mode_to_update,
346                ..
347            } => *mode_to_update = mode,
348        }
349    } else {
350        theme.icon_theme = Some(settings::IconThemeSelection::Static(IconThemeName(
351            DEFAULT_ICON_THEME_NAME.into(),
352        )));
353    }
354}
355
356/// The buffer's line height.
357#[derive(Clone, Copy, Debug, PartialEq, Default)]
358pub enum BufferLineHeight {
359    /// A less dense line height.
360    #[default]
361    Comfortable,
362    /// The default line height.
363    Standard,
364    /// A custom line height, where 1.0 is the font's height. Must be at least 1.0.
365    Custom(f32),
366}
367
368impl From<settings::BufferLineHeight> for BufferLineHeight {
369    fn from(value: settings::BufferLineHeight) -> Self {
370        match value {
371            settings::BufferLineHeight::Comfortable => BufferLineHeight::Comfortable,
372            settings::BufferLineHeight::Standard => BufferLineHeight::Standard,
373            settings::BufferLineHeight::Custom(line_height) => {
374                BufferLineHeight::Custom(line_height)
375            }
376        }
377    }
378}
379
380impl BufferLineHeight {
381    /// Returns the value of the line height.
382    pub fn value(&self) -> f32 {
383        match self {
384            BufferLineHeight::Comfortable => 1.618,
385            BufferLineHeight::Standard => 1.3,
386            BufferLineHeight::Custom(line_height) => *line_height,
387        }
388    }
389}
390
391impl ThemeSettings {
392    /// Returns the buffer font size.
393    pub fn buffer_font_size(&self, cx: &App) -> Pixels {
394        let font_size = cx
395            .try_global::<BufferFontSize>()
396            .map(|size| size.0)
397            .unwrap_or(self.buffer_font_size);
398        clamp_font_size(font_size)
399    }
400
401    /// Returns the UI font size.
402    pub fn ui_font_size(&self, cx: &App) -> Pixels {
403        let font_size = cx
404            .try_global::<UiFontSize>()
405            .map(|size| size.0)
406            .unwrap_or(self.ui_font_size);
407        clamp_font_size(font_size)
408    }
409
410    /// Returns the agent panel font size. Falls back to the UI font size if unset.
411    pub fn agent_ui_font_size(&self, cx: &App) -> Pixels {
412        cx.try_global::<AgentUiFontSize>()
413            .map(|size| size.0)
414            .or(self.agent_ui_font_size)
415            .map(clamp_font_size)
416            .unwrap_or_else(|| self.ui_font_size(cx))
417    }
418
419    /// Returns the agent panel buffer font size.
420    pub fn agent_buffer_font_size(&self, cx: &App) -> Pixels {
421        cx.try_global::<AgentBufferFontSize>()
422            .map(|size| size.0)
423            .or(self.agent_buffer_font_size)
424            .map(clamp_font_size)
425            .unwrap_or_else(|| self.buffer_font_size(cx))
426    }
427
428    pub fn git_commit_buffer_font_size(&self, cx: &App) -> Pixels {
429        cx.try_global::<GitCommitBufferFontSize>()
430            .map(|size| size.0)
431            .or(self.git_commit_buffer_font_size)
432            .map(clamp_font_size)
433            .unwrap_or_else(|| self.buffer_font_size(cx))
434    }
435
436    /// Returns the font family to use in the markdown preview,
437    /// falling back to the UI font family when unset.
438    pub fn markdown_preview_font_family(&self) -> &SharedString {
439        self.markdown_preview_font_family
440            .as_ref()
441            .unwrap_or(&self.ui_font.family)
442    }
443
444    /// Returns the font family to use for code in the markdown preview,
445    /// falling back to the buffer font family when unset.
446    pub fn markdown_preview_code_font_family(&self) -> &SharedString {
447        self.markdown_preview_code_font_family
448            .as_ref()
449            .unwrap_or(&self.buffer_font.family)
450    }
451
452    /// Returns the markdown preview font size.
453    ///
454    /// Note: the fallback deliberately uses `self.ui_font_size` instead of `ui_font_size(cx)`,
455    /// so that temporary UI zoom does not also resize the markdown preview.
456    pub fn markdown_preview_font_size(&self, cx: &App) -> Pixels {
457        cx.try_global::<MarkdownPreviewFontSize>()
458            .map(|size| size.0)
459            .or(self.markdown_preview_font_size)
460            .map(clamp_font_size)
461            .unwrap_or_else(|| clamp_font_size(self.ui_font_size))
462    }
463
464    /// Returns the buffer font size, read from the settings.
465    ///
466    /// The real buffer font size is stored in-memory, to support temporary font size changes.
467    /// Use [`Self::buffer_font_size`] to get the real font size.
468    pub fn buffer_font_size_settings(&self) -> Pixels {
469        self.buffer_font_size
470    }
471
472    /// Returns the UI font size, read from the settings.
473    ///
474    /// The real UI font size is stored in-memory, to support temporary font size changes.
475    /// Use [`Self::ui_font_size`] to get the real font size.
476    pub fn ui_font_size_settings(&self) -> Pixels {
477        self.ui_font_size
478    }
479
480    /// Returns the agent font size, read from the settings.
481    ///
482    /// The real agent font size is stored in-memory, to support temporary font size changes.
483    /// Use [`Self::agent_ui_font_size`] to get the real font size.
484    pub fn agent_ui_font_size_settings(&self) -> Option<Pixels> {
485        self.agent_ui_font_size
486    }
487
488    /// Returns the agent buffer font size, read from the settings.
489    ///
490    /// The real agent buffer font size is stored in-memory, to support temporary font size changes.
491    /// Use [`Self::agent_buffer_font_size`] to get the real font size.
492    pub fn agent_buffer_font_size_settings(&self) -> Option<Pixels> {
493        self.agent_buffer_font_size
494    }
495
496    pub fn git_commit_buffer_font_size_settings(&self) -> Option<Pixels> {
497        self.git_commit_buffer_font_size
498    }
499
500    /// Returns the markdown preview font size, read from the settings.
501    ///
502    /// The real markdown preview font size is stored in-memory, to support temporary
503    /// font size changes. Use [`Self::markdown_preview_font_size`] to get the real font size.
504    pub fn markdown_preview_font_size_settings(&self) -> Option<Pixels> {
505        self.markdown_preview_font_size
506    }
507
508    /// Returns the buffer's line height.
509    pub fn line_height(&self) -> f32 {
510        f32::max(self.buffer_line_height.value(), MIN_LINE_HEIGHT)
511    }
512
513    /// Applies the theme overrides, if there are any, to the current theme.
514    pub fn apply_theme_overrides(&self, mut arc_theme: Arc<Theme>) -> Arc<Theme> {
515        if let Some(experimental_theme_overrides) = &self.experimental_theme_overrides {
516            let mut theme = (*arc_theme).clone();
517            ThemeSettings::modify_theme(&mut theme, experimental_theme_overrides);
518            arc_theme = Arc::new(theme);
519        }
520
521        if let Some(theme_overrides) = self.theme_overrides.get(arc_theme.name.as_ref()) {
522            let mut theme = (*arc_theme).clone();
523            ThemeSettings::modify_theme(&mut theme, theme_overrides);
524            arc_theme = Arc::new(theme);
525        }
526
527        arc_theme
528    }
529
530    fn modify_theme(base_theme: &mut Theme, theme_overrides: &settings::ThemeStyleContent) {
531        if let Some(window_background_appearance) = theme_overrides.window_background_appearance {
532            base_theme.styles.window_background_appearance =
533                window_background_appearance.into_gpui();
534        }
535        let status_color_refinement = status_colors_refinement(&theme_overrides.status);
536
537        let theme_color_refinement = theme_colors_refinement(
538            &theme_overrides.colors,
539            &status_color_refinement,
540            base_theme.appearance.is_light(),
541        );
542        base_theme.styles.colors.refine(&theme_color_refinement);
543        base_theme.styles.status.refine(&status_color_refinement);
544        merge_player_colors(&mut base_theme.styles.player, &theme_overrides.players);
545        merge_accent_colors(&mut base_theme.styles.accents, &theme_overrides.accents);
546        base_theme.styles.syntax = SyntaxTheme::merge(
547            base_theme.styles.syntax.clone(),
548            syntax_overrides(theme_overrides),
549        );
550    }
551}
552
553/// Observe changes to the adjusted buffer font size.
554pub fn observe_buffer_font_size_adjustment<V: 'static>(
555    cx: &mut Context<V>,
556    f: impl 'static + Fn(&mut V, &mut Context<V>),
557) -> Subscription {
558    cx.observe_global::<BufferFontSize>(f)
559}
560
561/// Gets the font size, adjusted by the difference between the current buffer font size and the one set in the settings.
562pub fn adjusted_font_size(size: Pixels, cx: &App) -> Pixels {
563    let adjusted_font_size =
564        if let Some(BufferFontSize(adjusted_size)) = cx.try_global::<BufferFontSize>() {
565            let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
566            let delta = *adjusted_size - buffer_font_size;
567            size + delta
568        } else {
569            size
570        };
571    clamp_font_size(adjusted_font_size)
572}
573
574/// Adjusts the buffer font size, without persisting the result in the settings.
575/// This will be effective until the app is restarted.
576pub fn adjust_buffer_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
577    let buffer_font_size = ThemeSettings::get_global(cx).buffer_font_size;
578    let adjusted_size = cx
579        .try_global::<BufferFontSize>()
580        .map_or(buffer_font_size, |adjusted_size| adjusted_size.0);
581    cx.set_global(BufferFontSize(clamp_font_size(f(adjusted_size))));
582    cx.refresh_windows();
583}
584
585/// Resets the buffer font size to the default value.
586pub fn reset_buffer_font_size(cx: &mut App) {
587    if cx.has_global::<BufferFontSize>() {
588        cx.remove_global::<BufferFontSize>();
589        cx.refresh_windows();
590    }
591}
592
593#[allow(missing_docs)]
594pub fn setup_ui_font(window: &mut Window, cx: &mut App) -> gpui::Font {
595    let (ui_font, ui_font_size) = {
596        let theme_settings = ThemeSettings::get_global(cx);
597        let font = theme_settings.ui_font.clone();
598        (font, theme_settings.ui_font_size(cx))
599    };
600
601    window.set_rem_size(ui_font_size);
602    ui_font
603}
604
605/// Sets the adjusted UI font size.
606pub fn adjust_ui_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
607    let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
608    let adjusted_size = cx
609        .try_global::<UiFontSize>()
610        .map_or(ui_font_size, |adjusted_size| adjusted_size.0);
611    cx.set_global(UiFontSize(clamp_font_size(f(adjusted_size))));
612    cx.refresh_windows();
613}
614
615/// Resets the UI font size to the default value.
616pub fn reset_ui_font_size(cx: &mut App) {
617    if cx.has_global::<UiFontSize>() {
618        cx.remove_global::<UiFontSize>();
619        cx.refresh_windows();
620    }
621}
622
623/// Sets the adjusted font size of agent responses in the agent panel.
624pub fn adjust_agent_ui_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
625    let agent_ui_font_size = ThemeSettings::get_global(cx).agent_ui_font_size(cx);
626    let adjusted_size = cx
627        .try_global::<AgentUiFontSize>()
628        .map_or(agent_ui_font_size, |adjusted_size| adjusted_size.0);
629    cx.set_global(AgentUiFontSize(clamp_font_size(f(adjusted_size))));
630    cx.refresh_windows();
631}
632
633/// Resets the agent response font size in the agent panel to the default value.
634pub fn reset_agent_ui_font_size(cx: &mut App) {
635    if cx.has_global::<AgentUiFontSize>() {
636        cx.remove_global::<AgentUiFontSize>();
637        cx.refresh_windows();
638    }
639}
640
641/// Sets the adjusted font size of user messages in the agent panel.
642pub fn adjust_agent_buffer_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
643    let agent_buffer_font_size = ThemeSettings::get_global(cx).agent_buffer_font_size(cx);
644    let adjusted_size = cx
645        .try_global::<AgentBufferFontSize>()
646        .map_or(agent_buffer_font_size, |adjusted_size| adjusted_size.0);
647    cx.set_global(AgentBufferFontSize(clamp_font_size(f(adjusted_size))));
648    cx.refresh_windows();
649}
650
651/// Resets the user message font size in the agent panel to the default value.
652pub fn reset_agent_buffer_font_size(cx: &mut App) {
653    if cx.has_global::<AgentBufferFontSize>() {
654        cx.remove_global::<AgentBufferFontSize>();
655        cx.refresh_windows();
656    }
657}
658
659pub fn adjust_git_commit_buffer_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
660    let git_commit_buffer_font_size = ThemeSettings::get_global(cx).git_commit_buffer_font_size(cx);
661    let adjusted_size = cx
662        .try_global::<GitCommitBufferFontSize>()
663        .map_or(git_commit_buffer_font_size, |adjusted_size| adjusted_size.0);
664    cx.set_global(GitCommitBufferFontSize(clamp_font_size(f(adjusted_size))));
665    cx.refresh_windows();
666}
667
668pub fn reset_git_commit_buffer_font_size(cx: &mut App) {
669    if cx.has_global::<GitCommitBufferFontSize>() {
670        cx.remove_global::<GitCommitBufferFontSize>();
671        cx.refresh_windows();
672    }
673}
674
675/// Sets the adjusted font size of the markdown preview.
676pub fn adjust_markdown_preview_font_size(cx: &mut App, f: impl FnOnce(Pixels) -> Pixels) {
677    let markdown_preview_font_size = ThemeSettings::get_global(cx).markdown_preview_font_size(cx);
678    let adjusted_size = cx
679        .try_global::<MarkdownPreviewFontSize>()
680        .map_or(markdown_preview_font_size, |adjusted_size| adjusted_size.0);
681    cx.set_global(MarkdownPreviewFontSize(clamp_font_size(f(adjusted_size))));
682    cx.refresh_windows();
683}
684
685/// Resets the markdown preview font size to the default value.
686pub fn reset_markdown_preview_font_size(cx: &mut App) {
687    if cx.has_global::<MarkdownPreviewFontSize>() {
688        cx.remove_global::<MarkdownPreviewFontSize>();
689        cx.refresh_windows();
690    }
691}
692
693/// Ensures font size is within the valid range.
694pub fn clamp_font_size(size: Pixels) -> Pixels {
695    size.clamp(MIN_FONT_SIZE, MAX_FONT_SIZE)
696}
697
698fn font_fallbacks_from_settings(
699    fallbacks: Option<Vec<settings::FontFamilyName>>,
700) -> Option<FontFallbacks> {
701    fallbacks.map(|fallbacks| {
702        FontFallbacks::from_fonts(
703            fallbacks
704                .into_iter()
705                .map(|font_family| font_family.0.to_string())
706                .collect(),
707        )
708    })
709}
710
711impl settings::Settings for ThemeSettings {
712    fn from_settings(content: &settings::SettingsContent) -> Self {
713        let content = &content.theme;
714        let theme_selection: ThemeSelection = content.theme.clone().unwrap().into();
715        let icon_theme_selection: IconThemeSelection = content.icon_theme.clone().unwrap().into();
716        Self {
717            ui_font_size: clamp_font_size(content.ui_font_size.unwrap().into_gpui()),
718            ui_font: Font {
719                family: content.ui_font_family.as_ref().unwrap().0.clone().into(),
720                features: content.ui_font_features.clone().unwrap().into_gpui(),
721                fallbacks: font_fallbacks_from_settings(content.ui_font_fallbacks.clone()),
722                weight: content.ui_font_weight.unwrap().into_gpui(),
723                style: Default::default(),
724            },
725            buffer_font: Font {
726                family: content
727                    .buffer_font_family
728                    .as_ref()
729                    .unwrap()
730                    .0
731                    .clone()
732                    .into(),
733                features: content.buffer_font_features.clone().unwrap().into_gpui(),
734                fallbacks: font_fallbacks_from_settings(content.buffer_font_fallbacks.clone()),
735                weight: content.buffer_font_weight.unwrap().into_gpui(),
736                style: FontStyle::default(),
737            },
738            buffer_font_size: clamp_font_size(content.buffer_font_size.unwrap().into_gpui()),
739            buffer_line_height: content.buffer_line_height.unwrap().into(),
740            agent_ui_font_size: content.agent_ui_font_size.map(|s| s.into_gpui()),
741            agent_buffer_font_size: content.agent_buffer_font_size.map(|s| s.into_gpui()),
742            git_commit_buffer_font_size: content.git_commit_buffer_font_size.map(|s| s.into_gpui()),
743            markdown_preview_font_family: content
744                .markdown_preview_font_family
745                .as_ref()
746                .map(|f| f.0.clone().into()),
747            markdown_preview_code_font_family: content
748                .markdown_preview_code_font_family
749                .as_ref()
750                .map(|f| f.0.clone().into()),
751            markdown_preview_font_size: content.markdown_preview_font_size.map(|s| s.into_gpui()),
752            markdown_preview_theme: content
753                .markdown_preview_theme
754                .clone()
755                .map(ThemeSelection::from),
756            theme: theme_selection,
757            experimental_theme_overrides: content.experimental_theme_overrides.clone(),
758            theme_overrides: content.theme_overrides.clone(),
759            icon_theme: icon_theme_selection,
760            ui_density: ui_density_from_settings(content.ui_density.unwrap_or_default()),
761            unnecessary_code_fade: content.unnecessary_code_fade.unwrap().0.clamp(0.0, 0.9),
762        }
763    }
764}
765
Served at tenant.openagents/omega Member data and write actions are omitted.