// SPDX-License-Identifier: GPL-3.0-only use cosmic::{ cosmic_config::{self, CosmicConfigEntry, cosmic_config_derive::CosmicConfigEntry}, theme, }; use cosmic_text::Metrics; use serde::{Deserialize, Serialize}; use std::{collections::VecDeque, path::PathBuf}; pub const CONFIG_VERSION: u64 = 1; #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)] pub enum AppTheme { Dark, Light, System, } impl AppTheme { pub fn theme(&self) -> theme::Theme { match self { Self::Dark => { let mut t = theme::system_dark(); t.theme_type.prefer_dark(Some(true)); t } Self::Light => { let mut t = theme::system_light(); t.theme_type.prefer_dark(Some(false)); t } Self::System => theme::system_preference(), } } } #[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct Config { pub app_theme: AppTheme, pub auto_indent: bool, pub find_case_sensitive: bool, pub find_use_regex: bool, pub find_wrap_around: bool, pub font_name: String, pub font_size: u16, pub font_size_zoom_step_mul_100: u16, pub highlight_current_line: bool, pub line_numbers: bool, pub syntax_theme_dark: String, pub syntax_theme_light: String, pub tab_width: u16, pub vim_bindings: bool, pub word_wrap: bool, } impl Default for Config { fn default() -> Self { Self { app_theme: AppTheme::System, auto_indent: true, find_case_sensitive: false, find_use_regex: false, find_wrap_around: true, font_name: "Noto Sans Mono".to_string(), font_size: 14, font_size_zoom_step_mul_100: 100, highlight_current_line: true, line_numbers: true, syntax_theme_dark: "COSMIC Dark".to_string(), syntax_theme_light: "COSMIC Light".to_string(), tab_width: 4, vim_bindings: false, word_wrap: true, } } } impl Config { pub fn font_size_adjusted(&self, zoom_adj: i8) -> f32 { let font_size = f32::from(self.font_size).max(1.0); let adj = f32::from(zoom_adj); let adj_step = f32::from(self.font_size_zoom_step_mul_100) / 100.0; (font_size + adj * adj_step).max(1.0) } pub fn find_regex(&self, pattern: &str) -> Result { let mut builder = if self.find_use_regex { regex::RegexBuilder::new(pattern) } else { regex::RegexBuilder::new(®ex::escape(pattern)) }; builder.case_insensitive(!self.find_case_sensitive); builder.build() } // Calculate metrics from font size pub fn metrics(&self, zoom_adj: i8) -> Metrics { let font_size = self.font_size_adjusted(zoom_adj); let line_height = (font_size * 1.4).ceil(); Metrics::new(font_size, line_height) } // Get current syntax theme based on dark mode pub fn syntax_theme(&self) -> &str { let dark = self.app_theme.theme().theme_type.is_dark(); if dark { &self.syntax_theme_dark } else { &self.syntax_theme_light } } } #[derive(Clone, CosmicConfigEntry, Debug, Deserialize, Eq, PartialEq, Serialize)] pub struct ConfigState { pub recent_files: VecDeque, pub recent_projects: VecDeque, } impl Default for ConfigState { fn default() -> Self { Self { recent_files: VecDeque::new(), recent_projects: VecDeque::new(), } } }