oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
14,747 bytes raw
1
use crate::bar::{BlockCommand, BlockConfig};
2
use crate::errors::ConfigError;
3
use crate::keyboard::handlers::{KeyBinding, KeyPress};
4
use crate::keyboard::keysyms;
5
use crate::keyboard::{Arg, KeyAction};
6
use crate::keyboard::keysyms::Keysym;
7
use serde::Deserialize;
8
use std::collections::HashMap;
9
use x11rb::protocol::xproto::KeyButMask;
10
11
#[derive(Debug, Deserialize)]
12
pub enum ModKey {
13
    Mod,
14
    Mod1,
15
    Mod2,
16
    Mod3,
17
    Mod4,
18
    Mod5,
19
    Shift,
20
    Control,
21
}
22
23
impl ModKey {
24
    fn to_keybut_mask(&self) -> KeyButMask {
25
        match self {
26
            ModKey::Mod => panic!("ModKey::Mod should be replaced during config parsing"),
27
            ModKey::Mod1 => KeyButMask::MOD1,
28
            ModKey::Mod2 => KeyButMask::MOD2,
29
            ModKey::Mod3 => KeyButMask::MOD3,
30
            ModKey::Mod4 => KeyButMask::MOD4,
31
            ModKey::Mod5 => KeyButMask::MOD5,
32
            ModKey::Shift => KeyButMask::SHIFT,
33
            ModKey::Control => KeyButMask::CONTROL,
34
        }
35
    }
36
}
37
38
#[rustfmt::skip]
39
#[derive(Debug, Deserialize)]
40
pub enum KeyData {
41
    Return,
42
    Q,
43
    Escape,
44
    Space,
45
    Tab,
46
    Backspace,
47
    Delete,
48
    F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
49
    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,
50
    Key0,
51
    Key1,
52
    Key2,
53
    Key3,
54
    Key4,
55
    Key5,
56
    Key6,
57
    Key7,
58
    Key8,
59
    Key9,
60
    Left,
61
    Right,
62
    Up,
63
    Down,
64
    Home,
65
    End,
66
    PageUp,
67
    PageDown,
68
    Insert,
69
    Minus,
70
    Equal,
71
    BracketLeft,
72
    BracketRight,
73
    Semicolon,
74
    Apostrophe,
75
    Grave,
76
    Backslash,
77
    Comma,
78
    Period,
79
    Slash,
80
    AudioRaiseVolume,
81
    AudioLowerVolume,
82
    AudioMute,
83
    MonBrightnessUp,
84
    MonBrightnessDown,
85
}
86
87
impl KeyData {
88
    fn to_keysym(&self) -> Keysym {
89
        match self {
90
            KeyData::Return => keysyms::XK_RETURN,
91
            KeyData::Q => keysyms::XK_Q,
92
            KeyData::Escape => keysyms::XK_ESCAPE,
93
            KeyData::Space => keysyms::XK_SPACE,
94
            KeyData::Tab => keysyms::XK_TAB,
95
            KeyData::Backspace => keysyms::XK_BACKSPACE,
96
            KeyData::Delete => keysyms::XK_DELETE,
97
            KeyData::F1 => keysyms::XK_F1,
98
            KeyData::F2 => keysyms::XK_F2,
99
            KeyData::F3 => keysyms::XK_F3,
100
            KeyData::F4 => keysyms::XK_F4,
101
            KeyData::F5 => keysyms::XK_F5,
102
            KeyData::F6 => keysyms::XK_F6,
103
            KeyData::F7 => keysyms::XK_F7,
104
            KeyData::F8 => keysyms::XK_F8,
105
            KeyData::F9 => keysyms::XK_F9,
106
            KeyData::F10 => keysyms::XK_F10,
107
            KeyData::F11 => keysyms::XK_F11,
108
            KeyData::F12 => keysyms::XK_F12,
109
            KeyData::A => keysyms::XK_A,
110
            KeyData::B => keysyms::XK_B,
111
            KeyData::C => keysyms::XK_C,
112
            KeyData::D => keysyms::XK_D,
113
            KeyData::E => keysyms::XK_E,
114
            KeyData::F => keysyms::XK_F,
115
            KeyData::G => keysyms::XK_G,
116
            KeyData::H => keysyms::XK_H,
117
            KeyData::I => keysyms::XK_I,
118
            KeyData::J => keysyms::XK_J,
119
            KeyData::K => keysyms::XK_K,
120
            KeyData::L => keysyms::XK_L,
121
            KeyData::M => keysyms::XK_M,
122
            KeyData::N => keysyms::XK_N,
123
            KeyData::O => keysyms::XK_O,
124
            KeyData::P => keysyms::XK_P,
125
            KeyData::R => keysyms::XK_R,
126
            KeyData::S => keysyms::XK_S,
127
            KeyData::T => keysyms::XK_T,
128
            KeyData::U => keysyms::XK_U,
129
            KeyData::V => keysyms::XK_V,
130
            KeyData::W => keysyms::XK_W,
131
            KeyData::X => keysyms::XK_X,
132
            KeyData::Y => keysyms::XK_Y,
133
            KeyData::Z => keysyms::XK_Z,
134
            KeyData::Key0 => keysyms::XK_0,
135
            KeyData::Key1 => keysyms::XK_1,
136
            KeyData::Key2 => keysyms::XK_2,
137
            KeyData::Key3 => keysyms::XK_3,
138
            KeyData::Key4 => keysyms::XK_4,
139
            KeyData::Key5 => keysyms::XK_5,
140
            KeyData::Key6 => keysyms::XK_6,
141
            KeyData::Key7 => keysyms::XK_7,
142
            KeyData::Key8 => keysyms::XK_8,
143
            KeyData::Key9 => keysyms::XK_9,
144
            KeyData::Left => keysyms::XK_LEFT,
145
            KeyData::Right => keysyms::XK_RIGHT,
146
            KeyData::Up => keysyms::XK_UP,
147
            KeyData::Down => keysyms::XK_DOWN,
148
            KeyData::Home => keysyms::XK_HOME,
149
            KeyData::End => keysyms::XK_END,
150
            KeyData::PageUp => keysyms::XK_PAGE_UP,
151
            KeyData::PageDown => keysyms::XK_PAGE_DOWN,
152
            KeyData::Insert => keysyms::XK_INSERT,
153
            KeyData::Minus => keysyms::XK_MINUS,
154
            KeyData::Equal => keysyms::XK_EQUAL,
155
            KeyData::BracketLeft => keysyms::XK_LEFT_BRACKET,
156
            KeyData::BracketRight => keysyms::XK_RIGHT_BRACKET,
157
            KeyData::Semicolon => keysyms::XK_SEMICOLON,
158
            KeyData::Apostrophe => keysyms::XK_APOSTROPHE,
159
            KeyData::Grave => keysyms::XK_GRAVE,
160
            KeyData::Backslash => keysyms::XK_BACKSLASH,
161
            KeyData::Comma => keysyms::XK_COMMA,
162
            KeyData::Period => keysyms::XK_PERIOD,
163
            KeyData::Slash => keysyms::XK_SLASH,
164
            KeyData::AudioRaiseVolume => keysyms::XF86_AUDIO_RAISE_VOLUME,
165
            KeyData::AudioLowerVolume => keysyms::XF86_AUDIO_LOWER_VOLUME,
166
            KeyData::AudioMute => keysyms::XF86_AUDIO_MUTE,
167
            KeyData::MonBrightnessUp => keysyms::XF86_MON_BRIGHTNESS_UP,
168
            KeyData::MonBrightnessDown => keysyms::XF86_MON_BRIGHTNESS_DOWN,
169
        }
170
    }
171
172
}
173
174
fn preprocess_variables(input: &str) -> Result<String, ConfigError> {
175
    let mut variables: HashMap<String, String> = HashMap::new();
176
    let mut result = String::new();
177
178
    for line in input.lines() {
179
        let trimmed = line.trim();
180
181
        if trimmed.starts_with("#DEFINE") {
182
            let rest = trimmed.strip_prefix("#DEFINE").unwrap().trim();
183
184
            if let Some(eq_pos) = rest.find('=') {
185
                let var_name = rest[..eq_pos].trim();
186
                let value = rest[eq_pos + 1..].trim().trim_end_matches(',');
187
188
                if !var_name.starts_with('$') {
189
                    return Err(ConfigError::InvalidVariableName(var_name.to_string()));
190
                }
191
192
                variables.insert(var_name.to_string(), value.to_string());
193
            } else {
194
                return Err(ConfigError::InvalidDefine(trimmed.to_string()));
195
            }
196
197
            result.push('\n');
198
        } else {
199
            let mut processed_line = line.to_string();
200
            for (var_name, value) in &variables {
201
                processed_line = processed_line.replace(var_name, value);
202
            }
203
            result.push_str(&processed_line);
204
            result.push('\n');
205
        }
206
    }
207
208
    for line in result.lines() {
209
        if let Some(var_start) = line.find('$') {
210
            let rest = &line[var_start..];
211
            let var_end = rest[1..]
212
                .find(|c: char| !c.is_alphanumeric() && c != '_')
213
                .unwrap_or(rest.len() - 1)
214
                + 1;
215
            let undefined_var = &rest[..var_end];
216
            return Err(ConfigError::UndefinedVariable(undefined_var.to_string()));
217
        }
218
    }
219
    Ok(result)
220
}
221
222
pub fn parse_config(input: &str) -> Result<crate::Config, ConfigError> {
223
    let preprocessed = preprocess_variables(input)?;
224
    let config_data: ConfigData = ron::from_str(&preprocessed)?;
225
    config_data_to_config(config_data)
226
}
227
228
#[derive(Debug, Deserialize)]
229
struct LayoutSymbolOverrideData {
230
    name: String,
231
    symbol: String,
232
}
233
234
#[derive(Debug, Deserialize)]
235
struct ConfigData {
236
    border_width: u32,
237
    border_focused: u32,
238
    border_unfocused: u32,
239
    font: String,
240
241
    gaps_enabled: bool,
242
    gap_inner_horizontal: u32,
243
    gap_inner_vertical: u32,
244
    gap_outer_horizontal: u32,
245
    gap_outer_vertical: u32,
246
247
    terminal: String,
248
    modkey: ModKey,
249
250
    tags: Vec<String>,
251
    #[serde(default)]
252
    layout_symbols: Vec<LayoutSymbolOverrideData>,
253
    keybindings: Vec<KeybindingData>,
254
    status_blocks: Vec<StatusBlockData>,
255
256
    scheme_normal: ColorSchemeData,
257
    scheme_occupied: ColorSchemeData,
258
    scheme_selected: ColorSchemeData,
259
260
    #[serde(default)]
261
    autostart: Vec<String>,
262
}
263
264
#[derive(Debug, Deserialize)]
265
struct KeybindingData {
266
    #[serde(default)]
267
    keys: Option<Vec<KeyPressData>>,
268
    #[serde(default)]
269
    modifiers: Option<Vec<ModKey>>,
270
    #[serde(default)]
271
    key: Option<KeyData>,
272
    action: KeyAction,
273
    #[serde(default)]
274
    arg: ArgData,
275
}
276
277
#[derive(Debug, Deserialize)]
278
struct KeyPressData {
279
    modifiers: Vec<ModKey>,
280
    key: KeyData,
281
}
282
283
#[derive(Debug, Deserialize)]
284
#[serde(untagged)]
285
enum ArgData {
286
    None,
287
    String(String),
288
    Int(i32),
289
    Array(Vec<String>),
290
}
291
292
impl Default for ArgData {
293
    fn default() -> Self {
294
        ArgData::None
295
    }
296
}
297
298
#[derive(Debug, Deserialize)]
299
struct StatusBlockData {
300
    format: String,
301
    command: String,
302
    #[serde(default)]
303
    command_arg: Option<String>,
304
    #[serde(default)]
305
    battery_formats: Option<BatteryFormats>,
306
    interval_secs: u64,
307
    color: u32,
308
    underline: bool,
309
}
310
311
#[derive(Debug, Deserialize)]
312
struct BatteryFormats {
313
    charging: String,
314
    discharging: String,
315
    full: String,
316
}
317
318
#[derive(Debug, Deserialize)]
319
struct ColorSchemeData {
320
    foreground: u32,
321
    background: u32,
322
    underline: u32,
323
}
324
325
fn config_data_to_config(data: ConfigData) -> Result<crate::Config, ConfigError> {
326
    let modkey = data.modkey.to_keybut_mask();
327
328
    let mut keybindings = Vec::new();
329
    for kb_data in data.keybindings {
330
        let keys = if let Some(keys_data) = kb_data.keys {
331
            keys_data
332
                .into_iter()
333
                .map(|kp| {
334
                    let modifiers = kp
335
                        .modifiers
336
                        .iter()
337
                        .map(|m| match m {
338
                            ModKey::Mod => modkey,
339
                            _ => m.to_keybut_mask(),
340
                        })
341
                        .collect();
342
343
                    KeyPress {
344
                        modifiers,
345
                        keysym: kp.key.to_keysym(),
346
                    }
347
                })
348
                .collect()
349
        } else if let (Some(modifiers), Some(key)) = (kb_data.modifiers, kb_data.key) {
350
            vec![KeyPress {
351
                modifiers: modifiers
352
                    .iter()
353
                    .map(|m| match m {
354
                        ModKey::Mod => modkey,
355
                        _ => m.to_keybut_mask(),
356
                    })
357
                    .collect(),
358
                keysym: key.to_keysym(),
359
            }]
360
        } else {
361
            return Err(ConfigError::ValidationError(
362
                "Keybinding must have either 'keys' or 'modifiers'+'key'".to_string(),
363
            ));
364
        };
365
366
        let action = kb_data.action;
367
        let arg = arg_data_to_arg(kb_data.arg)?;
368
369
        keybindings.push(KeyBinding::new(keys, action, arg));
370
    }
371
372
    let mut status_blocks = Vec::new();
373
    for block_data in data.status_blocks {
374
        let command = match block_data.command.as_str() {
375
            "DateTime" => {
376
                let fmt = block_data
377
                    .command_arg
378
                    .ok_or_else(|| ConfigError::MissingCommandArg {
379
                        command: "DateTime".to_string(),
380
                        field: "command_arg".to_string(),
381
                    })?;
382
                BlockCommand::DateTime(fmt)
383
            }
384
            "Shell" => {
385
                let cmd = block_data
386
                    .command_arg
387
                    .ok_or_else(|| ConfigError::MissingCommandArg {
388
                        command: "Shell".to_string(),
389
                        field: "command_arg".to_string(),
390
                    })?;
391
                BlockCommand::Shell(cmd)
392
            }
393
            "Ram" => BlockCommand::Ram,
394
            "Static" => {
395
                let text = block_data.command_arg.unwrap_or_default();
396
                BlockCommand::Static(text)
397
            }
398
            "Battery" => {
399
                let formats =
400
                    block_data
401
                        .battery_formats
402
                        .ok_or_else(|| ConfigError::MissingCommandArg {
403
                            command: "Battery".to_string(),
404
                            field: "battery_formats".to_string(),
405
                        })?;
406
                BlockCommand::Battery {
407
                    format_charging: formats.charging,
408
                    format_discharging: formats.discharging,
409
                    format_full: formats.full,
410
                }
411
            }
412
            _ => return Err(ConfigError::UnknownBlockCommand(block_data.command)),
413
        };
414
415
        status_blocks.push(BlockConfig {
416
            format: block_data.format,
417
            command,
418
            interval_secs: block_data.interval_secs,
419
            color: block_data.color,
420
            underline: block_data.underline,
421
        });
422
    }
423
424
    let layout_symbols = data
425
        .layout_symbols
426
        .into_iter()
427
        .map(|l| crate::LayoutSymbolOverride {
428
            name: l.name,
429
            symbol: l.symbol,
430
        })
431
        .collect();
432
433
    Ok(crate::Config {
434
        border_width: data.border_width,
435
        border_focused: data.border_focused,
436
        border_unfocused: data.border_unfocused,
437
        font: data.font,
438
        gaps_enabled: data.gaps_enabled,
439
        gap_inner_horizontal: data.gap_inner_horizontal,
440
        gap_inner_vertical: data.gap_inner_vertical,
441
        gap_outer_horizontal: data.gap_outer_horizontal,
442
        gap_outer_vertical: data.gap_outer_vertical,
443
        terminal: data.terminal,
444
        modkey,
445
        tags: data.tags,
446
        layout_symbols,
447
        keybindings,
448
        status_blocks,
449
        scheme_normal: crate::ColorScheme {
450
            foreground: data.scheme_normal.foreground,
451
            background: data.scheme_normal.background,
452
            underline: data.scheme_normal.underline,
453
        },
454
        scheme_occupied: crate::ColorScheme {
455
            foreground: data.scheme_occupied.foreground,
456
            background: data.scheme_occupied.background,
457
            underline: data.scheme_occupied.underline,
458
        },
459
        scheme_selected: crate::ColorScheme {
460
            foreground: data.scheme_selected.foreground,
461
            background: data.scheme_selected.background,
462
            underline: data.scheme_selected.underline,
463
        },
464
        autostart: data.autostart,
465
    })
466
}
467
468
fn arg_data_to_arg(data: ArgData) -> Result<Arg, ConfigError> {
469
    match data {
470
        ArgData::None => Ok(Arg::None),
471
        ArgData::String(s) => Ok(Arg::Str(s)),
472
        ArgData::Int(n) => Ok(Arg::Int(n)),
473
        ArgData::Array(arr) => Ok(Arg::Array(arr)),
474
    }
475
}