chore: audit all components (#2)

Reviewed-on: #2
This commit was merged in pull request #2.
This commit is contained in:
2026-11-08 06:27:12 +00:00
parent 0ad5c3fe90
commit 11b29dc91a
51 changed files with 2096 additions and 958 deletions
+59 -5
View File
@@ -4,7 +4,7 @@
use std::collections::HashMap;
use gpui::Hsla;
use gpui::{Hsla, Pixels, px};
use crate::system::{PartialPalette, SourceKind, SystemTheme};
@@ -14,6 +14,9 @@ pub(crate) struct KdeScheme {
pub(crate) accent: Option<Hsla>,
pub(crate) background: Option<Hsla>,
pub(crate) palette: PartialPalette,
/// The root font size parsed from `[General] font=` (family, pointSize,
/// pixelSize, ...).
pub(crate) root_font_size: Option<Pixels>,
}
impl KdeScheme {
@@ -54,6 +57,7 @@ impl KdeScheme {
accent,
background,
palette,
root_font_size: root_font_size(groups.get("General")),
}
}
@@ -77,10 +81,17 @@ impl KdeScheme {
.unwrap_or(crate::ThemeVariant::Light),
accent: self.accent.or(portal_accent),
palette: self.palette,
control_radius: None,
input_height: None,
titlebar_height: None,
root_font_size: None,
control_radius: Some(px(5.)),
overlay_radius: Some(px(5.)),
sm_radius: None,
control_height: Some(px(33.)),
input_height: Some(px(29.)),
menu_item_height: Some(px(29.)),
switch_height: Some(px(18.)),
switch_width: Some(px(36.)),
switch_knob: Some(px(18.)),
titlebar_height: Some(px(44.)),
root_font_size: Some(self.root_font_size.unwrap_or(px(13.33))),
accessibility,
source: SourceKind::Kde,
}
@@ -95,6 +106,22 @@ fn variant_by_lightness(background: Hsla) -> crate::ThemeVariant {
}
}
/// The root font size of a `[General]` group's `font=` QFont string.
fn root_font_size(group: Option<&HashMap<&str, &str>>) -> Option<Pixels> {
let fields: Vec<&str> = group?.get("font")?.split(',').map(str::trim).collect();
let points = fields.get(1)?.parse::<f32>().ok()?;
let pixels = fields
.get(2)
.and_then(|size| size.parse::<f32>().ok())
.unwrap_or(-1.0);
let size = if pixels > 0.0 {
pixels
} else {
points * 96.0 / 72.0
};
(size > 0.0).then(|| px(size))
}
fn parse_groups(text: &str) -> HashMap<&str, HashMap<&str, &str>> {
let mut groups: HashMap<&str, HashMap<&str, &str>> = HashMap::new();
let mut section: Option<&str> = None;
@@ -305,4 +332,31 @@ activeBackground=39,44,49
let system = scheme.into_system(Default::default(), None, Some(crate::ThemeVariant::Light));
assert_eq!(system.variant, crate::ThemeVariant::Light);
}
#[test]
fn the_scheme_states_breeze_metrics_and_the_default_font() {
let system = KdeScheme::parse(BREEZE_DARK).into_system(Default::default(), None, None);
assert_eq!(system.control_height, Some(px(33.)));
assert_eq!(system.input_height, Some(px(29.)));
assert_eq!(system.menu_item_height, Some(px(29.)));
assert_eq!(system.control_radius, Some(px(5.)));
assert_eq!(system.overlay_radius, Some(px(5.)));
assert_eq!(system.switch_height, Some(px(18.)));
assert_eq!(system.switch_width, Some(px(36.)));
assert_eq!(system.switch_knob, Some(px(18.)));
assert_eq!(system.titlebar_height, Some(px(44.)));
assert!((system.root_font_size.unwrap() - px(13.33)).abs() < px(0.01));
}
#[test]
fn the_stated_font_beats_the_default() {
let text = "[General]\nfont=Noto Sans,10,-1,5,50,0,0,0,0,0\n";
let system = KdeScheme::parse(text).into_system(Default::default(), None, None);
assert!((system.root_font_size.unwrap() - px(10.0 * 96.0 / 72.0)).abs() < px(0.01));
let text = "[General]\nfont=Adwaita Sans,-1,12,5,50,0,0,0,0,0\n";
let system = KdeScheme::parse(text).into_system(Default::default(), None, None);
assert_eq!(system.root_font_size, Some(px(12.)));
}
}
+107 -30
View File
@@ -5,7 +5,7 @@
use std::path::{Path, PathBuf};
use gpui::Hsla;
use gpui::{Hsla, Pixels};
use notify::{RecursiveMode, Watcher};
use super::ThemeSource;
@@ -55,11 +55,12 @@ fn detect(home: &Path, portal_reachable: bool, gsettings_reachable: bool) -> Bac
}
}
/// What `gsettings` states for GNOME sessions without a portal.
/// What `gsettings` states for GNOME sessions.
#[derive(Clone, Copy, Debug, Default, PartialEq)]
struct GSettingsSnapshot {
variant: Option<ThemeVariant>,
accent: Option<Hsla>,
root_font_size: Option<Pixels>,
}
fn gsettings_value(args: &[&str]) -> Option<String> {
@@ -97,23 +98,31 @@ fn read_gsettings() -> Option<GSettingsSnapshot> {
"prefer-light" => Some(ThemeVariant::Light),
_ => None,
});
let accent = gsettings_value(&["get", "org.gnome.desktop.interface", "accent-color"])
.and_then(|value| accent_rgb(value.trim().trim_matches('\'')));
if variant.is_none() && accent.is_none() {
let root_font_size = gsettings_value(&["get", "org.gnome.desktop.interface", "font-name"])
.and_then(|value| font_root_px(value.trim().trim_matches('\'')));
if variant.is_none() && accent.is_none() && root_font_size.is_none() {
return None;
}
Some(GSettingsSnapshot { variant, accent })
Some(GSettingsSnapshot {
variant,
accent,
root_font_size,
})
}
fn font_root_px(name: &str) -> Option<Pixels> {
let points = name.split_whitespace().last()?.parse::<f32>().ok()?;
(points > 0.0).then(|| gpui::px(points * 96.0 / 72.0))
}
pub(crate) fn platform_source() -> Box<dyn ThemeSource> {
let portal = portal::io::PortalClient::connect();
let gsettings = if portal.is_none() {
read_gsettings()
} else {
None
};
let gsettings = read_gsettings();
let backend = home_dir()
.map(|home| detect(&home, portal.is_some(), gsettings.is_some()))
@@ -129,6 +138,36 @@ pub(crate) fn platform_source() -> Box<dyn ThemeSource> {
}
impl LinuxSource {
fn gnome_snapshot(
&self,
variant: ThemeVariant,
accent: Option<Hsla>,
accessibility: crate::system::AccessibilityPreferences,
) -> SystemTheme {
SystemTheme {
variant,
accent,
palette: PartialPalette::default(),
control_radius: Some(gpui::px(9.)),
overlay_radius: Some(gpui::px(15.)),
sm_radius: Some(gpui::px(6.)),
control_height: Some(gpui::px(34.)),
input_height: Some(gpui::px(34.)),
menu_item_height: Some(gpui::px(32.)),
switch_height: Some(gpui::px(26.)),
switch_width: Some(gpui::px(46.)),
switch_knob: Some(gpui::px(20.)),
titlebar_height: Some(gpui::px(47.)),
root_font_size: Some(
self.gsettings
.and_then(|gsettings| gsettings.root_font_size)
.unwrap_or(gpui::px(14.67)),
),
accessibility,
source: SourceKind::Gnome,
}
}
fn portal_snapshot(
&self,
variant: ThemeVariant,
@@ -136,31 +175,21 @@ impl LinuxSource {
accessibility: crate::system::AccessibilityPreferences,
) -> SystemTheme {
if let Some(appearance) = portal_appearance {
return SystemTheme {
variant: appearance.variant(variant),
accent: appearance.accent,
palette: PartialPalette::default(),
control_radius: None,
input_height: None,
titlebar_height: None,
root_font_size: None,
return self.gnome_snapshot(
appearance.variant(variant),
appearance.accent,
accessibility,
source: SourceKind::Gnome,
};
);
}
if let Some(gsettings) = self.gsettings {
return SystemTheme {
variant: gsettings.variant.unwrap_or(variant),
accent: gsettings.accent,
palette: PartialPalette::default(),
control_radius: None,
input_height: None,
titlebar_height: None,
root_font_size: None,
return self.gnome_snapshot(
gsettings.variant.unwrap_or(variant),
gsettings.accent,
accessibility,
source: SourceKind::Gnome,
};
);
}
SystemTheme::fallback(variant)
}
}
@@ -289,4 +318,52 @@ mod tests {
assert_eq!(detect(&home, true, false), Backend::Kde);
std::fs::remove_dir_all(&home).expect("cleanup");
}
#[test]
fn the_gsettings_font_name_states_the_root_font_size() {
assert_eq!(
font_root_px("Adwaita Sans 11"),
Some(gpui::px(11.0 * 96.0 / 72.0))
);
assert_eq!(
font_root_px("Noto Sans 10"),
Some(gpui::px(10.0 * 96.0 / 72.0))
);
assert_eq!(
font_root_px("Cantarell Bold 12.5"),
Some(gpui::px(12.5 * 96.0 / 72.0))
);
assert_eq!(font_root_px("Adwaita Sans"), None);
assert_eq!(font_root_px("Sans 0"), None);
}
#[test]
fn the_gnome_snapshot_states_the_libadwaita_metrics() {
let source = LinuxSource {
backend: Backend::Portal,
portal: None,
gsettings: None,
file_watcher: None,
_signal: None,
};
let system = source.gnome_snapshot(
ThemeVariant::Light,
None,
crate::system::AccessibilityPreferences::default(),
);
assert_eq!(system.source, SourceKind::Gnome);
assert_eq!(system.control_height, Some(gpui::px(34.)));
assert_eq!(system.input_height, Some(gpui::px(34.)));
assert_eq!(system.menu_item_height, Some(gpui::px(32.)));
assert_eq!(system.control_radius, Some(gpui::px(9.)));
assert_eq!(system.overlay_radius, Some(gpui::px(15.)));
assert_eq!(system.sm_radius, Some(gpui::px(6.)));
assert_eq!(system.switch_height, Some(gpui::px(26.)));
assert_eq!(system.switch_width, Some(gpui::px(46.)));
assert_eq!(system.switch_knob, Some(gpui::px(20.)));
assert_eq!(system.titlebar_height, Some(gpui::px(47.)));
// The default 11pt font when gsettings states none.
assert_eq!(system.root_font_size, Some(gpui::px(14.67)));
}
}
+18 -1
View File
@@ -22,6 +22,16 @@ use crate::system::{AccessibilityPreferences, PartialPalette, SourceKind, System
const CONTROL_RADIUS_PTS: f32 = 6.0;
/// The rounded-bezel text field's intrinsic height at regular size.
const INPUT_HEIGHT_PTS: f32 = 24.0;
/// AppKit's regular push button, measured via `NSButton::fittingSize`.
const CONTROL_HEIGHT_PTS: f32 = 24.0;
/// The standard `NSMenu` row height.
const MENU_ITEM_HEIGHT_PTS: f32 = 20.0;
/// `NSSwitch`, measured via `fittingSize`.
const SWITCH_TRACK_HEIGHT_PTS: f32 = 24.0;
const SWITCH_TRACK_WIDTH_PTS: f32 = 54.0;
const SWITCH_KNOB_PTS: f32 = 20.0;
/// The standard titled window's titlebar, measured via `contentLayoutRect`.
const TITLEBAR_HEIGHT_PTS: f32 = 32.0;
/// The HIG's default body text on macOS is 13 pt (system font size 13 at 1x).
const ROOT_FONT_SIZE_PTS: f32 = 13.0;
@@ -112,8 +122,15 @@ impl ThemeSource for MacosSource {
accent: Self::color_to_hsla(&NSColor::controlAccentColor()),
palette,
control_radius: Some(gpui::px(CONTROL_RADIUS_PTS)),
overlay_radius: None,
sm_radius: None,
control_height: Some(gpui::px(CONTROL_HEIGHT_PTS)),
input_height: Some(gpui::px(INPUT_HEIGHT_PTS)),
titlebar_height: None,
menu_item_height: Some(gpui::px(MENU_ITEM_HEIGHT_PTS)),
switch_height: Some(gpui::px(SWITCH_TRACK_HEIGHT_PTS)),
switch_width: Some(gpui::px(SWITCH_TRACK_WIDTH_PTS)),
switch_knob: Some(gpui::px(SWITCH_KNOB_PTS)),
titlebar_height: Some(gpui::px(TITLEBAR_HEIGHT_PTS)),
root_font_size: Some(gpui::px(ROOT_FONT_SIZE_PTS)),
accessibility,
source: SourceKind::Macos,
+23 -4
View File
@@ -60,8 +60,15 @@ impl OmarchyTheme {
variant: self.variant,
accent: self.accent,
palette: self.palette,
control_radius: None,
input_height: None,
control_radius: Some(gpui::px(9.)),
overlay_radius: Some(gpui::px(15.)),
sm_radius: Some(gpui::px(6.)),
control_height: Some(gpui::px(34.)),
input_height: Some(gpui::px(34.)),
menu_item_height: Some(gpui::px(32.)),
switch_height: Some(gpui::px(26.)),
switch_width: Some(gpui::px(46.)),
switch_knob: Some(gpui::px(20.)),
titlebar_height: None,
root_font_size: None,
accessibility,
@@ -216,7 +223,19 @@ color15 = \"#635d6f\"
}
#[test]
fn non_toml_text_is_rejected() {
assert!(OmarchyTheme::parse("not a theme").is_none());
fn omarchy_shares_the_gnome_control_metrics() {
let theme = OmarchyTheme::parse(TOKYO_NIGHT).expect("parses");
let system = theme.into_system(Default::default());
assert_eq!(system.control_height, Some(gpui::px(34.)));
assert_eq!(system.input_height, Some(gpui::px(34.)));
assert_eq!(system.menu_item_height, Some(gpui::px(32.)));
assert_eq!(system.control_radius, Some(gpui::px(9.)));
assert_eq!(system.overlay_radius, Some(gpui::px(15.)));
assert_eq!(system.switch_height, Some(gpui::px(26.)));
assert_eq!(system.switch_width, Some(gpui::px(46.)));
assert_eq!(system.switch_knob, Some(gpui::px(20.)));
assert_eq!(system.titlebar_height, None);
assert_eq!(system.root_font_size, None);
}
}
-10
View File
@@ -206,16 +206,6 @@ mod tests {
);
}
#[test]
fn an_unset_scheme_yields_the_callers_variant() {
let appearance = AppearanceValues::default().decode();
assert_eq!(
appearance.variant(crate::ThemeVariant::Dark),
crate::ThemeVariant::Dark
);
assert_eq!(appearance, Appearance::default());
}
#[test]
fn accessibility_flags_forward() {
let accessibility = AppearanceValues {
+17
View File
@@ -14,8 +14,18 @@ use crate::system::{AccessibilityPreferences, PartialPalette, SourceKind, System
/// WinUI 11's `ControlCornerRadius`, in pixels at 100% scaling.
const CONTROL_RADIUS_PX: f32 = 4.0;
/// WinUI 11's `OverlayCornerRadius`, in pixels at 100% scaling.
const OVERLAY_RADIUS_PX: f32 = 8.0;
/// WinUI 11's default text-box height, in pixels at 100% scaling.
const INPUT_HEIGHT_PX: f32 = 32.0;
/// The default button height, in pixels at 100% scaling.
const CONTROL_HEIGHT_PX: f32 = 32.0;
/// The default menu row: item padding 4/5 + a 20px Body line + 2px item margins.
const MENU_ITEM_HEIGHT_PX: f32 = 33.0;
/// ToggleSwitch: a 40x20 track with a 12px resting knob.
const SWITCH_TRACK_HEIGHT_PX: f32 = 20.0;
const SWITCH_TRACK_WIDTH_PX: f32 = 40.0;
const SWITCH_KNOB_PX: f32 = 12.0;
/// The window caption's height, in pixels at 100% scaling, as Win32 reports it.
const TITLEBAR_HEIGHT_PX: f32 = 32.0;
/// WinUI 11's default body text size, in pixels at 100% scaling.
@@ -159,7 +169,14 @@ impl ThemeSource for WindowsSource {
..PartialPalette::default()
},
control_radius: Some(gpui::px(CONTROL_RADIUS_PX)),
overlay_radius: Some(gpui::px(OVERLAY_RADIUS_PX)),
sm_radius: None,
control_height: Some(gpui::px(CONTROL_HEIGHT_PX)),
input_height: Some(gpui::px(INPUT_HEIGHT_PX)),
menu_item_height: Some(gpui::px(MENU_ITEM_HEIGHT_PX)),
switch_height: Some(gpui::px(SWITCH_TRACK_HEIGHT_PX)),
switch_width: Some(gpui::px(SWITCH_TRACK_WIDTH_PX)),
switch_knob: Some(gpui::px(SWITCH_KNOB_PX)),
titlebar_height: Some(gpui::px(TITLEBAR_HEIGHT_PX)),
root_font_size: Some(gpui::px(ROOT_FONT_SIZE_PX * text_scale as f32)),
accessibility: self.accessibility(),