oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
12,661 bytes raw
1
use crate::bar::{BlockCommand, BlockConfig};
2
use crate::errors::ConfigError;
3
use crate::keyboard::handlers::Key;
4
use crate::keyboard::keycodes;
5
use crate::keyboard::{Arg, KeyAction};
6
use serde::Deserialize;
7
use std::collections::HashMap;
8
use x11rb::protocol::xproto::{KeyButMask, Keycode};
9
10
#[derive(Debug, Deserialize)]
11
pub enum ModKey {
12
    Mod1,
13
    Mod2,
14
    Mod3,
15
    Mod4,
16
    Mod5,
17
    Shift,
18
    Control,
19
}
20
21
impl ModKey {
22
    fn to_keybut_mask(&self) -> KeyButMask {
23
        match self {
24
            ModKey::Mod1 => KeyButMask::MOD1,
25
            ModKey::Mod2 => KeyButMask::MOD2,
26
            ModKey::Mod3 => KeyButMask::MOD3,
27
            ModKey::Mod4 => KeyButMask::MOD4,
28
            ModKey::Mod5 => KeyButMask::MOD5,
29
            ModKey::Shift => KeyButMask::SHIFT,
30
            ModKey::Control => KeyButMask::CONTROL,
31
        }
32
    }
33
}
34
35
#[rustfmt::skip]
36
#[derive(Debug, Deserialize)]
37
pub enum KeyData {
38
    Return,
39
    Q,
40
    Escape,
41
    Space,
42
    Tab,
43
    Backspace,
44
    Delete,
45
    F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
46
    A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, R, S, T, U, V, W, X, Y, Z,
47
    Key0,
48
    Key1,
49
    Key2,
50
    Key3,
51
    Key4,
52
    Key5,
53
    Key6,
54
    Key7,
55
    Key8,
56
    Key9,
57
    Left,
58
    Right,
59
    Up,
60
    Down,
61
    Home,
62
    End,
63
    PageUp,
64
    PageDown,
65
    Insert,
66
    Minus,
67
    Equal,
68
    BracketLeft,
69
    BracketRight,
70
    Semicolon,
71
    Apostrophe,
72
    Grave,
73
    Backslash,
74
    Comma,
75
    Period,
76
    Slash,
77
}
78
79
impl KeyData {
80
    fn to_keycode(&self) -> Keycode {
81
        match self {
82
            KeyData::Return => keycodes::RETURN,
83
            KeyData::Q => keycodes::Q,
84
            KeyData::Escape => keycodes::ESCAPE,
85
            KeyData::Space => keycodes::SPACE,
86
            KeyData::Tab => keycodes::TAB,
87
            KeyData::Backspace => keycodes::BACKSPACE,
88
            KeyData::Delete => keycodes::DELETE,
89
            KeyData::F1 => keycodes::F1,
90
            KeyData::F2 => keycodes::F2,
91
            KeyData::F3 => keycodes::F3,
92
            KeyData::F4 => keycodes::F4,
93
            KeyData::F5 => keycodes::F5,
94
            KeyData::F6 => keycodes::F6,
95
            KeyData::F7 => keycodes::F7,
96
            KeyData::F8 => keycodes::F8,
97
            KeyData::F9 => keycodes::F9,
98
            KeyData::F10 => keycodes::F10,
99
            KeyData::F11 => keycodes::F11,
100
            KeyData::F12 => keycodes::F12,
101
            KeyData::A => keycodes::A,
102
            KeyData::B => keycodes::B,
103
            KeyData::C => keycodes::C,
104
            KeyData::D => keycodes::D,
105
            KeyData::E => keycodes::E,
106
            KeyData::F => keycodes::F,
107
            KeyData::G => keycodes::G,
108
            KeyData::H => keycodes::H,
109
            KeyData::I => keycodes::I,
110
            KeyData::J => keycodes::J,
111
            KeyData::K => keycodes::K,
112
            KeyData::L => keycodes::L,
113
            KeyData::M => keycodes::M,
114
            KeyData::N => keycodes::N,
115
            KeyData::O => keycodes::O,
116
            KeyData::P => keycodes::P,
117
            KeyData::R => keycodes::R,
118
            KeyData::S => keycodes::S,
119
            KeyData::T => keycodes::T,
120
            KeyData::U => keycodes::U,
121
            KeyData::V => keycodes::V,
122
            KeyData::W => keycodes::W,
123
            KeyData::X => keycodes::X,
124
            KeyData::Y => keycodes::Y,
125
            KeyData::Z => keycodes::Z,
126
            KeyData::Key0 => keycodes::KEY_0,
127
            KeyData::Key1 => keycodes::KEY_1,
128
            KeyData::Key2 => keycodes::KEY_2,
129
            KeyData::Key3 => keycodes::KEY_3,
130
            KeyData::Key4 => keycodes::KEY_4,
131
            KeyData::Key5 => keycodes::KEY_5,
132
            KeyData::Key6 => keycodes::KEY_6,
133
            KeyData::Key7 => keycodes::KEY_7,
134
            KeyData::Key8 => keycodes::KEY_8,
135
            KeyData::Key9 => keycodes::KEY_9,
136
            KeyData::Left => keycodes::LEFT,
137
            KeyData::Right => keycodes::RIGHT,
138
            KeyData::Up => keycodes::UP,
139
            KeyData::Down => keycodes::DOWN,
140
            KeyData::Home => keycodes::HOME,
141
            KeyData::End => keycodes::END,
142
            KeyData::PageUp => keycodes::PAGE_UP,
143
            KeyData::PageDown => keycodes::PAGE_DOWN,
144
            KeyData::Insert => keycodes::INSERT,
145
            KeyData::Minus => keycodes::MINUS,
146
            KeyData::Equal => keycodes::EQUAL,
147
            KeyData::BracketLeft => keycodes::LEFT_BRACKET,
148
            KeyData::BracketRight => keycodes::RIGHT_BRACKET,
149
            KeyData::Semicolon => keycodes::SEMICOLON,
150
            KeyData::Apostrophe => keycodes::APOSTROPHE,
151
            KeyData::Grave => keycodes::GRAVE,
152
            KeyData::Backslash => keycodes::BACKSLASH,
153
            KeyData::Comma => keycodes::COMMA,
154
            KeyData::Period => keycodes::PERIOD,
155
            KeyData::Slash => keycodes::SLASH,
156
        }
157
    }
158
}
159
160
fn preprocess_variables(input: &str) -> Result<String, ConfigError> {
161
    let mut variables: HashMap<String, String> = HashMap::new();
162
    let mut result = String::new();
163
164
    for line in input.lines() {
165
        let trimmed = line.trim();
166
167
        if trimmed.starts_with("#DEFINE") {
168
            let rest = trimmed.strip_prefix("#DEFINE").unwrap().trim();
169
170
            if let Some(eq_pos) = rest.find('=') {
171
                let var_name = rest[..eq_pos].trim();
172
                let value = rest[eq_pos + 1..].trim().trim_end_matches(',');
173
174
                if !var_name.starts_with('$') {
175
                    return Err(ConfigError::InvalidVariableName(var_name.to_string()));
176
                }
177
178
                variables.insert(var_name.to_string(), value.to_string());
179
            } else {
180
                return Err(ConfigError::InvalidDefine(trimmed.to_string()));
181
            }
182
183
            result.push('\n');
184
        } else {
185
            let mut processed_line = line.to_string();
186
            for (var_name, value) in &variables {
187
                processed_line = processed_line.replace(var_name, value);
188
            }
189
            result.push_str(&processed_line);
190
            result.push('\n');
191
        }
192
    }
193
194
    for line in result.lines() {
195
        if let Some(var_start) = line.find('$') {
196
            let rest = &line[var_start..];
197
            let var_end = rest[1..]
198
                .find(|c: char| !c.is_alphanumeric() && c != '_')
199
                .unwrap_or(rest.len() - 1)
200
                + 1;
201
            let undefined_var = &rest[..var_end];
202
            return Err(ConfigError::UndefinedVariable(undefined_var.to_string()));
203
        }
204
    }
205
    Ok(result)
206
}
207
208
pub fn parse_config(input: &str) -> Result<crate::Config, ConfigError> {
209
    let preprocessed = preprocess_variables(input)?;
210
    let config_data: ConfigData = ron::from_str(&preprocessed)?;
211
    config_data_to_config(config_data)
212
}
213
214
#[derive(Debug, Deserialize)]
215
struct LayoutSymbolOverrideData {
216
    name: String,
217
    symbol: String,
218
}
219
220
#[derive(Debug, Deserialize)]
221
struct ConfigData {
222
    border_width: u32,
223
    border_focused: u32,
224
    border_unfocused: u32,
225
    font: String,
226
227
    gaps_enabled: bool,
228
    gap_inner_horizontal: u32,
229
    gap_inner_vertical: u32,
230
    gap_outer_horizontal: u32,
231
    gap_outer_vertical: u32,
232
233
    terminal: String,
234
    modkey: ModKey,
235
236
    tags: Vec<String>,
237
    #[serde(default)]
238
    layout_symbols: Vec<LayoutSymbolOverrideData>,
239
    keybindings: Vec<KeybindingData>,
240
    status_blocks: Vec<StatusBlockData>,
241
242
    scheme_normal: ColorSchemeData,
243
    scheme_occupied: ColorSchemeData,
244
    scheme_selected: ColorSchemeData,
245
}
246
247
#[derive(Debug, Deserialize)]
248
struct KeybindingData {
249
    modifiers: Vec<ModKey>,
250
    key: KeyData,
251
    action: KeyAction,
252
    #[serde(default)]
253
    arg: ArgData,
254
}
255
256
#[derive(Debug, Deserialize)]
257
#[serde(untagged)]
258
enum ArgData {
259
    None,
260
    String(String),
261
    Int(i32),
262
    Array(Vec<String>),
263
}
264
265
impl Default for ArgData {
266
    fn default() -> Self {
267
        ArgData::None
268
    }
269
}
270
271
#[derive(Debug, Deserialize)]
272
struct StatusBlockData {
273
    format: String,
274
    command: String,
275
    #[serde(default)]
276
    command_arg: Option<String>,
277
    #[serde(default)]
278
    battery_formats: Option<BatteryFormats>,
279
    interval_secs: u64,
280
    color: u32,
281
    underline: bool,
282
}
283
284
#[derive(Debug, Deserialize)]
285
struct BatteryFormats {
286
    charging: String,
287
    discharging: String,
288
    full: String,
289
}
290
291
#[derive(Debug, Deserialize)]
292
struct ColorSchemeData {
293
    foreground: u32,
294
    background: u32,
295
    underline: u32,
296
}
297
298
fn config_data_to_config(data: ConfigData) -> Result<crate::Config, ConfigError> {
299
    let modkey = data.modkey.to_keybut_mask();
300
301
    let mut keybindings = Vec::new();
302
    for kb_data in data.keybindings {
303
        let modifiers = kb_data
304
            .modifiers
305
            .iter()
306
            .map(|m| m.to_keybut_mask())
307
            .collect();
308
309
        let key = kb_data.key.to_keycode();
310
        let action = kb_data.action;
311
        let arg = arg_data_to_arg(kb_data.arg)?;
312
313
        keybindings.push(Key::new(modifiers, key, action, arg));
314
    }
315
316
    let mut status_blocks = Vec::new();
317
    for block_data in data.status_blocks {
318
        let command = match block_data.command.as_str() {
319
            "DateTime" => {
320
                let fmt = block_data
321
                    .command_arg
322
                    .ok_or_else(|| ConfigError::MissingCommandArg {
323
                        command: "DateTime".to_string(),
324
                        field: "command_arg".to_string(),
325
                    })?;
326
                BlockCommand::DateTime(fmt)
327
            }
328
            "Shell" => {
329
                let cmd = block_data
330
                    .command_arg
331
                    .ok_or_else(|| ConfigError::MissingCommandArg {
332
                        command: "Shell".to_string(),
333
                        field: "command_arg".to_string(),
334
                    })?;
335
                BlockCommand::Shell(cmd)
336
            }
337
            "Ram" => BlockCommand::Ram,
338
            "Static" => {
339
                let text = block_data.command_arg.unwrap_or_default();
340
                BlockCommand::Static(text)
341
            }
342
            "Battery" => {
343
                let formats =
344
                    block_data
345
                        .battery_formats
346
                        .ok_or_else(|| ConfigError::MissingCommandArg {
347
                            command: "Battery".to_string(),
348
                            field: "battery_formats".to_string(),
349
                        })?;
350
                BlockCommand::Battery {
351
                    format_charging: formats.charging,
352
                    format_discharging: formats.discharging,
353
                    format_full: formats.full,
354
                }
355
            }
356
            _ => return Err(ConfigError::UnknownBlockCommand(block_data.command)),
357
        };
358
359
        status_blocks.push(BlockConfig {
360
            format: block_data.format,
361
            command,
362
            interval_secs: block_data.interval_secs,
363
            color: block_data.color,
364
            underline: block_data.underline,
365
        });
366
    }
367
368
    let layout_symbols = data
369
        .layout_symbols
370
        .into_iter()
371
        .map(|l| crate::LayoutSymbolOverride {
372
            name: l.name,
373
            symbol: l.symbol,
374
        })
375
        .collect();
376
377
    Ok(crate::Config {
378
        border_width: data.border_width,
379
        border_focused: data.border_focused,
380
        border_unfocused: data.border_unfocused,
381
        font: data.font,
382
        gaps_enabled: data.gaps_enabled,
383
        gap_inner_horizontal: data.gap_inner_horizontal,
384
        gap_inner_vertical: data.gap_inner_vertical,
385
        gap_outer_horizontal: data.gap_outer_horizontal,
386
        gap_outer_vertical: data.gap_outer_vertical,
387
        terminal: data.terminal,
388
        modkey,
389
        tags: data.tags,
390
        layout_symbols,
391
        keybindings,
392
        status_blocks,
393
        scheme_normal: crate::ColorScheme {
394
            foreground: data.scheme_normal.foreground,
395
            background: data.scheme_normal.background,
396
            underline: data.scheme_normal.underline,
397
        },
398
        scheme_occupied: crate::ColorScheme {
399
            foreground: data.scheme_occupied.foreground,
400
            background: data.scheme_occupied.background,
401
            underline: data.scheme_occupied.underline,
402
        },
403
        scheme_selected: crate::ColorScheme {
404
            foreground: data.scheme_selected.foreground,
405
            background: data.scheme_selected.background,
406
            underline: data.scheme_selected.underline,
407
        },
408
    })
409
}
410
411
fn arg_data_to_arg(data: ArgData) -> Result<Arg, ConfigError> {
412
    match data {
413
        ArgData::None => Ok(Arg::None),
414
        ArgData::String(s) => Ok(Arg::Str(s)),
415
        ArgData::Int(n) => Ok(Arg::Int(n)),
416
        ArgData::Array(arr) => Ok(Arg::Array(arr)),
417
    }
418
}