Skip to main content

native_theme_gpui/
config.rs

1//! ThemeFonts/ThemeGeometry -> gpui_component::theme::ThemeConfig mapping.
2//!
3//! Maps native-theme's font and geometry settings to gpui-component's
4//! `ThemeConfig`, which controls per-theme font family, font size, radius,
5//! and shadow settings.
6
7use gpui::SharedString;
8use gpui_component::theme::{ThemeConfig, ThemeMode};
9use native_theme::ThemeVariant;
10
11/// Build a [`ThemeConfig`] from a [`ThemeVariant`].
12///
13/// Maps ThemeFonts fields to font_family/mono_font_family/font_size/mono_font_size,
14/// and ThemeGeometry fields to radius/radius_lg/shadow. Remaining ThemeConfig
15/// fields use defaults.
16pub fn to_theme_config(variant: &ThemeVariant, name: &str, mode: ThemeMode) -> ThemeConfig {
17    let fonts = &variant.fonts;
18    let geometry = &variant.geometry;
19
20    ThemeConfig {
21        name: SharedString::from(name.to_string()),
22        mode,
23
24        font_family: fonts.family.as_ref().map(|s| SharedString::from(s.clone())),
25        font_size: fonts.size.map(|pt| pt * (96.0 / 72.0)),
26        mono_font_family: fonts
27            .mono_family
28            .as_ref()
29            .map(|s| SharedString::from(s.clone())),
30        mono_font_size: fonts.mono_size.map(|pt| pt * (96.0 / 72.0)),
31
32        radius: geometry.radius.map(|r| r as usize),
33        radius_lg: geometry.radius_lg.map(|r| r as usize),
34        shadow: geometry.shadow,
35
36        ..ThemeConfig::default()
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn to_theme_config_populated() {
46        let mut variant = ThemeVariant::default();
47        variant.fonts.family = Some("Inter".into());
48        variant.fonts.size = Some(14.0);
49        variant.fonts.mono_family = Some("JetBrains Mono".into());
50        variant.fonts.mono_size = Some(13.0);
51        variant.geometry.radius = Some(4.0);
52        variant.geometry.radius_lg = Some(8.0);
53        variant.geometry.shadow = Some(true);
54
55        let config = to_theme_config(&variant, "Test Theme", ThemeMode::Light);
56
57        assert_eq!(config.name.to_string(), "Test Theme");
58        assert_eq!(
59            config.font_family.as_ref().map(|s| s.to_string()),
60            Some("Inter".to_string())
61        );
62        assert_eq!(config.font_size, Some(14.0 * (96.0 / 72.0)));
63        assert_eq!(
64            config.mono_font_family.as_ref().map(|s| s.to_string()),
65            Some("JetBrains Mono".to_string())
66        );
67        assert_eq!(config.mono_font_size, Some(13.0 * (96.0 / 72.0)));
68        assert_eq!(config.radius, Some(4));
69        assert_eq!(config.radius_lg, Some(8));
70        assert_eq!(config.shadow, Some(true));
71    }
72
73    #[test]
74    fn to_theme_config_empty_uses_defaults() {
75        let variant = ThemeVariant::default();
76        let config = to_theme_config(&variant, "Empty", ThemeMode::Dark);
77
78        assert_eq!(config.name.to_string(), "Empty");
79        assert_eq!(config.mode, ThemeMode::Dark);
80        assert!(config.font_family.is_none());
81        assert!(config.font_size.is_none());
82        assert!(config.mono_font_family.is_none());
83        assert!(config.mono_font_size.is_none());
84        assert!(config.radius.is_none());
85        assert!(config.radius_lg.is_none());
86        assert!(config.shadow.is_none());
87    }
88
89    #[test]
90    fn to_theme_config_partial_fonts() {
91        let mut variant = ThemeVariant::default();
92        variant.fonts.family = Some("Segoe UI".into());
93        // size, mono_family, mono_size left as None
94
95        let config = to_theme_config(&variant, "Partial", ThemeMode::Light);
96
97        assert_eq!(
98            config.font_family.as_ref().map(|s| s.to_string()),
99            Some("Segoe UI".to_string())
100        );
101        assert!(config.font_size.is_none());
102        assert!(config.mono_font_family.is_none());
103    }
104}