Diff
diff --cc src/errors.rs
index 9555d90,0a43192..3481d37
--- a/src/errors.rs
+++ b/src/errors.rs
@@@ -25,7 -25,9 +25,10 @@@ pub enum ConfigError
UnknownAction(String),
UnknownBlockCommand(String),
MissingCommandArg { command: String, field: String },
+ ValidationError(String),
+ InvalidVariableName(String),
+ InvalidDefine(String),
+ UndefinedVariable(String),
}
impl std::fmt::Display for WmError {
@@@ -68,7 -70,15 +71,24 @@@ impl std::fmt::Display for ConfigError
Self::MissingCommandArg { command, field } => {
write!(f, "{} command requires {}", command, field)
}
+ Self::ValidationError(msg) => write!(f, "Config validation error: {}", msg),
+ Self::InvalidVariableName(name) => {
+ write!(f, "Invalid variable name '{}': must start with $", name)
+ }
+ Self::InvalidDefine(line) => {
- write!(f, "Invalid #DEFINE syntax: '{}'. Expected: #DEFINE $var_name = value", line)
++ write!(
++ f,
++ "Invalid #DEFINE syntax: '{}'. Expected: #DEFINE $var_name = value",
++ line
++ )
+ }
+ Self::UndefinedVariable(var) => {
- write!(f, "Undefined variable '{}': define it with #DEFINE before use", var)
++ write!(
++ f,
++ "Undefined variable '{}': define it with #DEFINE before use",
++ var
++ )
+ }
}
}
}
diff --cc templates/config.ron
index 8cdbb9a,2f5f18b..a770fa7
--- a/templates/config.ron
+++ b/templates/config.ron
@@@ -23,81 -38,53 +38,73 @@@
(name: "normie", symbol: "[F]"),
],
+ // Keybinding Format:
+ //
+ // New format (supports keychords - multi-key sequences):
+ // (keys: [(modifiers: [...], key: X), (modifiers: [...], key: Y)], action: ..., arg: ...)
+ //
+ // Old format (single key, backwards compatible):
+ // (modifiers: [...], key: X, action: ..., arg: ...)
+ //
+ // Examples:
+ // Single key: (keys: [(modifiers: [Mod4], key: Return)], action: Spawn, arg: "st")
+ // Keychord: (keys: [(modifiers: [Mod4], key: Space), (modifiers: [], key: F)], action: Spawn, arg: "firefox")
+ //
+ // You can cancel any in-progress keychord by pressing Escape.
+
keybindings: [
+ // Basic keybindings (old format for backwards compatibility)
- (modifiers: [Mod4], key: Return, action: Spawn, arg: "st"),
- (modifiers: [Mod4], key: D, action: Spawn, arg: ["sh", "-c", "dmenu_run -l 10"]),
- (modifiers: [Mod4], key: S, action: Spawn, arg: ["sh", "-c", "maim -s | xclip -selection clipboard -t image/png"]),
- (modifiers: [Mod4], key: Q, action: KillClient),
- (modifiers: [Mod4, Shift], key: F, action: ToggleFullScreen),
- (modifiers: [Mod4, Shift], key: Space, action: ToggleFloating),
- (modifiers: [Mod4], key: F, action: ChangeLayout, arg: "normie"),
- (modifiers: [Mod4], key: C, action: ChangeLayout, arg: "tiling"),
- (modifiers: [Mod1], key: N, action: CycleLayout),
- (modifiers: [Mod4], key: A, action: ToggleGaps),
- (modifiers: [Mod4, Shift], key: Q, action: Quit),
- (modifiers: [Mod4, Shift], key: R, action: Restart),
- (modifiers: [Mod4], key: J, action: FocusStack, arg: -1),
- (modifiers: [Mod4], key: K, action: FocusStack, arg: 1),
- (modifiers: [Mod4], key: Comma, action: FocusMonitor, arg: -1),
- (modifiers: [Mod4], key: Period, action: FocusMonitor, arg: 1),
- (modifiers: [Mod4], key: Key1, action: ViewTag, arg: 0),
- (modifiers: [Mod4], key: Key2, action: ViewTag, arg: 1),
- (modifiers: [Mod4], key: Key3, action: ViewTag, arg: 2),
- (modifiers: [Mod4], key: Key4, action: ViewTag, arg: 3),
- (modifiers: [Mod4], key: Key5, action: ViewTag, arg: 4),
- (modifiers: [Mod4], key: Key6, action: ViewTag, arg: 5),
- (modifiers: [Mod4], key: Key7, action: ViewTag, arg: 6),
- (modifiers: [Mod4], key: Key8, action: ViewTag, arg: 7),
- (modifiers: [Mod4], key: Key9, action: ViewTag, arg: 8),
- (modifiers: [Mod4, Shift], key: Key1, action: MoveToTag, arg: 0),
- (modifiers: [Mod4, Shift], key: Key2, action: MoveToTag, arg: 1),
- (modifiers: [Mod4, Shift], key: Key3, action: MoveToTag, arg: 2),
- (modifiers: [Mod4, Shift], key: Key4, action: MoveToTag, arg: 3),
- (modifiers: [Mod4, Shift], key: Key5, action: MoveToTag, arg: 4),
- (modifiers: [Mod4, Shift], key: Key6, action: MoveToTag, arg: 5),
- (modifiers: [Mod4, Shift], key: Key7, action: MoveToTag, arg: 6),
- (modifiers: [Mod4, Shift], key: Key8, action: MoveToTag, arg: 7),
- (modifiers: [Mod4, Shift], key: Key9, action: MoveToTag, arg: 8),
+ (modifiers: [$modkey], key: Return, action: Spawn, arg: $terminal),
+ (modifiers: [$modkey], key: D, action: Spawn, arg: ["sh", "-c", "dmenu_run -l 10"]),
+ (modifiers: [$modkey], key: S, action: Spawn, arg: ["sh", "-c", "maim -s | xclip -selection clipboard -t image/png"]),
+ (modifiers: [$modkey], key: Q, action: KillClient),
+ (modifiers: [$modkey, Shift], key: F, action: ToggleFullScreen),
+ (modifiers: [$modkey, Shift], key: Space, action: ToggleFloating),
+ (modifiers: [$modkey], key: F, action: ChangeLayout, arg: "normie"),
+ (modifiers: [$modkey], key: C, action: ChangeLayout, arg: "tiling"),
+ (modifiers: [$secondary_modkey], key: N, action: CycleLayout),
+ (modifiers: [$modkey], key: A, action: ToggleGaps),
+ (modifiers: [$modkey, Shift], key: Q, action: Quit),
+ (modifiers: [$modkey, Shift], key: R, action: Restart),
+ (modifiers: [$modkey], key: J, action: FocusStack, arg: -1),
+ (modifiers: [$modkey], key: K, action: FocusStack, arg: 1),
+ (modifiers: [$modkey], key: Comma, action: FocusMonitor, arg: -1),
+ (modifiers: [$modkey], key: Period, action: FocusMonitor, arg: 1),
+ (modifiers: [$modkey], key: Key1, action: ViewTag, arg: 0),
+ (modifiers: [$modkey], key: Key2, action: ViewTag, arg: 1),
+ (modifiers: [$modkey], key: Key3, action: ViewTag, arg: 2),
+ (modifiers: [$modkey], key: Key4, action: ViewTag, arg: 3),
+ (modifiers: [$modkey], key: Key5, action: ViewTag, arg: 4),
+ (modifiers: [$modkey], key: Key6, action: ViewTag, arg: 5),
+ (modifiers: [$modkey], key: Key7, action: ViewTag, arg: 6),
+ (modifiers: [$modkey], key: Key8, action: ViewTag, arg: 7),
+ (modifiers: [$modkey], key: Key9, action: ViewTag, arg: 8),
+ (modifiers: [$modkey, Shift], key: Key1, action: MoveToTag, arg: 0),
+ (modifiers: [$modkey, Shift], key: Key2, action: MoveToTag, arg: 1),
+ (modifiers: [$modkey, Shift], key: Key3, action: MoveToTag, arg: 2),
+ (modifiers: [$modkey, Shift], key: Key4, action: MoveToTag, arg: 3),
+ (modifiers: [$modkey, Shift], key: Key5, action: MoveToTag, arg: 4),
+ (modifiers: [$modkey, Shift], key: Key6, action: MoveToTag, arg: 5),
+ (modifiers: [$modkey, Shift], key: Key7, action: MoveToTag, arg: 6),
+ (modifiers: [$modkey, Shift], key: Key8, action: MoveToTag, arg: 7),
+ (modifiers: [$modkey, Shift], key: Key9, action: MoveToTag, arg: 8),
// Moving Windows
- (modifiers: [Mod4, Control], key: K, action: SmartMoveWin, arg: 0), // UP
- (modifiers: [Mod4, Control], key: J, action: SmartMoveWin, arg: 1), // DOWN
- (modifiers: [Mod4, Control], key: H, action: SmartMoveWin, arg: 2), // LEFT
- (modifiers: [Mod4, Control], key: L, action: SmartMoveWin, arg: 3), // RIGHT
+ (modifiers: [$modkey, Control], key: K, action: SmartMoveWin, arg: 0), // UP
+ (modifiers: [$modkey, Control], key: J, action: SmartMoveWin, arg: 1), // DOWN
+ (modifiers: [$modkey, Control], key: H, action: SmartMoveWin, arg: 2), // LEFT
+ (modifiers: [$modkey, Control], key: L, action: SmartMoveWin, arg: 3), // RIGHT
// Exchanging Clients
- (modifiers: [Mod4, Shift], key: K, action: ExchangeClient, arg: 0), // UP
- (modifiers: [Mod4, Shift], key: J, action: ExchangeClient, arg: 1), // DOWN
- (modifiers: [Mod4, Shift], key: H, action: ExchangeClient, arg: 2), // LEFT
- (modifiers: [Mod4, Shift], key: L, action: ExchangeClient, arg: 3), // RIGHT
+ (modifiers: [$modkey, Shift], key: K, action: ExchangeClient, arg: 0), // UP
+ (modifiers: [$modkey, Shift], key: J, action: ExchangeClient, arg: 1), // DOWN
+ (modifiers: [$modkey, Shift], key: H, action: ExchangeClient, arg: 2), // LEFT
+ (modifiers: [$modkey, Shift], key: L, action: ExchangeClient, arg: 3), // RIGHT
+
+ // Example keychord bindings (uncomment to use):
- // Press Mod4+Space, then f to spawn firefox
- // (keys: [(modifiers: [Mod4], key: Space), (modifiers: [], key: F)], action: Spawn, arg: "firefox"),
-
++ // KEYCHORDS
+ // Press Mod4+Space, then t to spawn terminal
- // (keys: [(modifiers: [Mod4], key: Space), (modifiers: [], key: T)], action: Spawn, arg: "st"),
-
- // Press Mod4+e, then e to spawn a text editor (same key twice)
- // (keys: [(modifiers: [Mod4], key: E), (modifiers: [], key: E)], action: Spawn, arg: "nvim"),
-
- // Press Mod4+x, then Shift+c to kill client (modifier on second key)
- // (keys: [(modifiers: [Mod4], key: X), (modifiers: [Shift], key: C)], action: KillClient),
++ (keys: [(modifiers: [Mod4], key: Space), (modifiers: [], key: T)], action: Spawn, arg: $terminal),
],
status_blocks: [
diff --cc test-config.ron
index eb258fc,1553106..4ea92da
--- a/test-config.ron
+++ b/test-config.ron
@@@ -30,8 -42,7 +42,8 @@@
],
keybindings: [
- (modifiers: [Mod1], key: Return, action: Spawn, arg: "st"),
+ (keys: [(modifiers: [Mod1], key: Space), (modifiers: [], key: T)], action: Spawn, arg: "st"),
+ (modifiers: [Mod1], key: Return, action: Spawn, arg: $terminal),
(modifiers: [Mod1], key: D, action: Spawn, arg: ["sh", "-c", "dmenu_run -l 10"]),
(modifiers: [Mod1], key: S, action: Spawn, arg: ["sh", "-c", "maim -s | xclip -selection clipboard -t image/png"]),
(modifiers: [Mod1], key: Q, action: KillClient),