1use serde::{Deserialize, Serialize};
2use smart_default::SmartDefault;
3use std::fmt::Display;
4
5#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
6#[serde(default, deny_unknown_fields)]
7pub struct Config {
8 #[default = true]
9 pub layerrules: bool,
10 #[default(None)]
11 pub launcher: Option<Launcher>,
12 #[default(Some(Windows::default()))]
13 pub windows: Option<Windows>,
14}
15
16#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
17#[serde(default, deny_unknown_fields)]
18pub struct Launcher {
19 #[default(None)]
20 pub default_terminal: Option<Box<str>>,
21 #[default = 650]
22 pub width: u32,
23 #[default = 5]
24 pub max_items: u8,
25 #[default = 250]
26 pub animate_launch_ms: u64,
27 #[default(Plugins::default())]
28 pub plugins: Plugins,
29}
30
31#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
32#[serde(default, deny_unknown_fields)]
33pub struct Plugins {
34 #[default(Some(Default::default()))]
35 pub applications: Option<ApplicationsPluginConfig>,
36 #[default(Some(Default::default()))]
37 pub terminal: Option<EmptyConfig>,
38 #[default(None)]
39 pub shell: Option<EmptyConfig>,
40 #[default(Some(Default::default()))]
41 pub websearch: Option<WebSearchConfig>,
42 #[default(Some(Default::default()))]
43 pub calc: Option<EmptyConfig>,
44}
45
46#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
47#[serde(default, deny_unknown_fields)]
48pub struct EmptyConfig {}
49
50#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
51#[serde(default, deny_unknown_fields)]
52pub struct ApplicationsPluginConfig {
53 #[default = 4]
54 pub run_cache_weeks: u8,
55 #[default = true]
56 pub show_execs: bool,
57}
58
59#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
60#[serde(default, deny_unknown_fields)]
61pub struct WebSearchConfig {
62 #[default(vec![SearchEngine {
63 url: "https://www.google.com/search?q={}".into(),
64 name: "Google".into(),
65 key: 'g',
66 }])]
67 pub engines: Vec<SearchEngine>,
68}
69
70#[derive(Debug, Clone, Deserialize, Serialize)]
71#[serde(deny_unknown_fields)]
72pub struct SearchEngine {
73 pub url: String,
74 pub name: String,
75 pub key: char,
76}
77
78#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
79#[serde(default, deny_unknown_fields)]
80pub struct Windows {
81 #[default = 8.5]
82 pub scale: f64,
83 #[default = 5]
84 pub workspaces_per_row: u8,
85 #[default = true]
86 pub strip_html_from_workspace_title: bool,
87 pub overview: Option<Overview>,
88 pub switch: Option<Switch>,
89}
90
91#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
92#[serde(default, deny_unknown_fields)]
93pub struct Overview {
94 pub open: OpenOverview,
95 pub navigate: Navigate,
96 pub other: OtherOverview,
97}
98
99#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
100#[serde(default, deny_unknown_fields)]
101pub struct OtherOverview {
102 #[default(Vec::new())]
103 pub filter_by: Vec<FilterBy>,
104 #[default = false]
105 pub hide_filtered: bool,
106}
107
108#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
109#[serde(default, deny_unknown_fields)]
110pub struct OpenOverview {
111 #[default = "super"]
112 pub key: KeyMaybeMod,
113 #[default(Mod::Super)]
114 pub modifier: Mod,
115}
116
117#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
118#[serde(default, deny_unknown_fields)]
119pub struct Navigate {
120 #[default = "tab"]
121 pub forward: String,
122 #[default(Reverse::Mod(Mod::Shift))]
123 pub reverse: Reverse,
124}
125
126#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
127#[serde(default, deny_unknown_fields)]
128pub struct Switch {
129 pub open: OpenSwitch,
130 pub navigate: Navigate,
131 pub other: OtherSwitch,
132}
133
134#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
135#[serde(default, deny_unknown_fields)]
136pub struct OpenSwitch {
137 #[default(Mod::Super)]
138 pub modifier: Mod,
139}
140
141#[derive(SmartDefault, Debug, Clone, Deserialize, Serialize)]
142#[serde(default, deny_unknown_fields)]
143pub struct OtherSwitch {
144 #[default(Vec::new())]
145 pub filter_by: Vec<FilterBy>,
146 #[default = true]
147 pub hide_filtered: bool,
148}
149
150#[derive(Debug, Clone, Copy, Deserialize, Serialize, Eq, PartialEq)]
151#[serde(rename_all = "snake_case")]
152pub enum FilterBy {
153 SameClass,
154 CurrentWorkspace,
155 CurrentMonitor,
156}
157
158#[derive(Debug, Clone, Deserialize, Serialize)]
159#[serde(rename_all = "snake_case")]
160pub enum Reverse {
161 Key(String),
162 Mod(Mod),
163}
164#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
165#[serde(rename_all = "snake_case")]
166pub enum Mod {
167 Alt,
168 Ctrl,
169 Super,
170 Shift,
171}
172
173impl Display for Mod {
174 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175 match self {
176 Mod::Alt => write!(f, "alt"),
177 Mod::Ctrl => write!(f, "ctrl"),
178 Mod::Super => write!(f, "super"),
179 Mod::Shift => write!(f, "shift"),
180 }
181 }
182}
183
184#[derive(Debug, Clone, Deserialize, Serialize)]
185pub struct KeyMaybeMod(String);
186impl From<&str> for KeyMaybeMod {
187 fn from(s: &str) -> Self {
188 Self(s.to_string())
189 }
190}
191
192impl KeyMaybeMod {
195 pub fn to_key(&self) -> String {
196 match &*self.0.to_ascii_lowercase() {
197 "alt" => "alt_l".to_string(),
198 "ctrl" => "ctrl_l".to_string(),
199 "super" => "super_l".to_string(),
200 "shift" => "shift_l".to_string(),
201 a => a.to_string(),
202 }
203 }
204}
205
206impl Mod {
207 pub fn mod_to_keys(&self) -> [&'static str; 2] {
208 match self {
209 Mod::Alt => ["alt_l", "alt_r"],
210 Mod::Ctrl => ["control_l", "control_r"], Mod::Super => ["super_l", "super_r"],
212 Mod::Shift => ["shift_l", "shift_r"],
213 }
214 }
215}