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