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