Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions modules/home/lib/generators/generators.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
cfg,
pkgs,
moduleName,
}:
{
keybindings =
if (cfg.package == null) then
{ }
else
import (pkgs.runCommand "sway-keybindings"
{
nativeBuildInputs = [ pkgs.python3 ];
}
''
python ${./keybindings.py} ${cfg.package}/etc/${moduleName}/config > $out
''
) { inherit cfg; };
}
129 changes: 129 additions & 0 deletions modules/home/lib/generators/keybindings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env python3

"""
Converts the Sway config into a Nix attribute set.

Why?
If keybindings were provided manually, they would have to also be updated manually.
This would add more maintenance overhead.

Why Python?
It's a lot simpler and more readable to use Python over Nix for something like this.
"""

from collections import defaultdict
import sys

CONFIG = sys.argv[1]


def escape(s: str) -> str:
"""Basic function to escape some of the Nix expressions"""
return s.replace("\\", "\\\\").replace('"', '\\"').replace("${", "''${")


try:
with open(CONFIG) as f:
lines: list[str] = f.readlines()
except:
print("{}")
sys.exit()

keybindings: dict[str, str] = {}
modes: defaultdict[str, dict[str, str]] = defaultdict(dict)
current_mode: str | None = None

for line in lines:
stripped: str = line.strip()

if stripped == "}" and current_mode is not None:
# Exit mode section:
# }
current_mode = None

elif stripped.startswith("mode"):
# Enter mode section:
# mode "mode" {

# Remove mode prefix
nomode: str = "mode".join(stripped.split("mode")[1:]).strip()

if nomode.startswith('"'):
# Get name from in between the quotes
# (not implementing escaping since it isn't necessary)
current_mode = nomode.split('"')[1]
elif nomode.startswith("'"):
# Same as above but with single quotes
current_mode = nomode.split("'")[1]
else:
# Get name until "{"
# (not implementing one line mode definitions since those don't appear in def config)
current_mode = nomode.split("{")[0].strip()

elif stripped.startswith("bindsym"):
# Parse bindsym line:
# bindsym [--args] keycombo command

# Remove bindsym
nobindsym: str = "bindsym".join(stripped.split("bindsym")[1:]).strip()

# Then iterate through each word
key_list: list[str] = []
value_list: list[str] = []

bind_added: bool = False

for word in nobindsym.split(" "):
if word.startswith("--") and not bind_added:
# Add args
key_list.append(word)
elif not bind_added:
# Add keycombo
key_list.append(word)
bind_added = True
else:
# Add command (rest of the words)
value_list.append(word)

key: str = (
escape(" ".join(key_list))
.replace("$mod", "${cfg.config.modifier}")
.replace("$term", "${cfg.config.terminal}")
.replace("$menu", "${cfg.config.menu}")
.replace("$left", "${cfg.config.left}")
.replace("$right", "${cfg.config.right}")
.replace("$up", "${cfg.config.up}")
.replace("$down", "${cfg.config.down}")
)
value: str = escape(" ".join(value_list))

if current_mode is None:
keybindings.update({key: value})
else:
# Here defaultdict will create the current_mode key automatically
# so we don't have to check if it exists
modes[current_mode].update({key: value})

print("{ cfg }:")
print("{")

print(" keybindings = {")

for keycombo, command in keybindings.items():
print(f' "{keycombo}" = "{command}";')

print(" };")

print(" modes = {")

for mode, binds in modes.items():
print(f' "{mode}" = ' + "{")

for keycombo, command in binds.items():
print(f' "{keycombo}" = "{command}";')

print(" };")

print("};")

print("}")
114 changes: 10 additions & 104 deletions modules/home/scroll.nix
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ let
capitalModuleName = "Scroll";
};

generators = import ./lib/generators/generators.nix {
inherit
cfg
pkgs
;
moduleName = "scroll";
};

configModule = types.submodule {
options = {
inherit (commonOptions)
Expand Down Expand Up @@ -85,75 +93,7 @@ let
keybindings = mkOption {
type = types.attrsOf (types.nullOr types.str);
# https://github.com/dawsers/scroll/blob/master/config.in#L129
default = lib.mapAttrs (_n: lib.mkOptionDefault) {
# TODO: add scroll keybindings
"${cfg.config.modifier}+Return" = "exec ${cfg.config.terminal}";
"${cfg.config.modifier}+Shift+q" = "kill";
"${cfg.config.modifier}+d" = "exec ${cfg.config.menu}";

"${cfg.config.modifier}+${cfg.config.left}" = "focus left";
"${cfg.config.modifier}+${cfg.config.down}" = "focus down";
"${cfg.config.modifier}+${cfg.config.up}" = "focus up";
"${cfg.config.modifier}+${cfg.config.right}" = "focus right";

"${cfg.config.modifier}+Left" = "focus left";
"${cfg.config.modifier}+Down" = "focus down";
"${cfg.config.modifier}+Up" = "focus up";
"${cfg.config.modifier}+Right" = "focus right";

"${cfg.config.modifier}+Shift+${cfg.config.left}" = "move left";
"${cfg.config.modifier}+Shift+${cfg.config.down}" = "move down";
"${cfg.config.modifier}+Shift+${cfg.config.up}" = "move up";
"${cfg.config.modifier}+Shift+${cfg.config.right}" = "move right";

"${cfg.config.modifier}+Shift+Left" = "move left";
"${cfg.config.modifier}+Shift+Down" = "move down";
"${cfg.config.modifier}+Shift+Up" = "move up";
"${cfg.config.modifier}+Shift+Right" = "move right";

"${cfg.config.modifier}+b" = "splith";
"${cfg.config.modifier}+v" = "splitv";
"${cfg.config.modifier}+f" = "fullscreen toggle";
"${cfg.config.modifier}+a" = "focus parent";

"${cfg.config.modifier}+s" = "layout stacking";
"${cfg.config.modifier}+w" = "layout tabbed";
"${cfg.config.modifier}+e" = "layout toggle split";

"${cfg.config.modifier}+Shift+space" = "floating toggle";
"${cfg.config.modifier}+space" = "focus mode_toggle";

"${cfg.config.modifier}+1" = "workspace number 1";
"${cfg.config.modifier}+2" = "workspace number 2";
"${cfg.config.modifier}+3" = "workspace number 3";
"${cfg.config.modifier}+4" = "workspace number 4";
"${cfg.config.modifier}+5" = "workspace number 5";
"${cfg.config.modifier}+6" = "workspace number 6";
"${cfg.config.modifier}+7" = "workspace number 7";
"${cfg.config.modifier}+8" = "workspace number 8";
"${cfg.config.modifier}+9" = "workspace number 9";
"${cfg.config.modifier}+0" = "workspace number 10";

"${cfg.config.modifier}+Shift+1" = "move container to workspace number 1";
"${cfg.config.modifier}+Shift+2" = "move container to workspace number 2";
"${cfg.config.modifier}+Shift+3" = "move container to workspace number 3";
"${cfg.config.modifier}+Shift+4" = "move container to workspace number 4";
"${cfg.config.modifier}+Shift+5" = "move container to workspace number 5";
"${cfg.config.modifier}+Shift+6" = "move container to workspace number 6";
"${cfg.config.modifier}+Shift+7" = "move container to workspace number 7";
"${cfg.config.modifier}+Shift+8" = "move container to workspace number 8";
"${cfg.config.modifier}+Shift+9" = "move container to workspace number 9";
"${cfg.config.modifier}+Shift+0" = "move container to workspace number 10";

"${cfg.config.modifier}+Shift+minus" = "move scratchpad";
"${cfg.config.modifier}+minus" = "scratchpad show";

"${cfg.config.modifier}+Shift+c" = "reload";
"${cfg.config.modifier}+Shift+e" =
"exec swaynag -t warning -m 'You pressed the exit shortcut. Do you really want to exit sway? This will end your Wayland session.' -b 'Yes, exit sway' 'swaymsg exit'";

"${cfg.config.modifier}+r" = "mode resize";
};
default = lib.mapAttrs (_n: lib.mkOptionDefault) generators.keybindings.keybindings;
defaultText = "Default scroll keybindings.";
description = ''
An attribute set that assigns a key press to an action using a key symbol.
Expand Down Expand Up @@ -259,41 +199,7 @@ let

modes = mkOption {
type = types.attrsOf (types.attrsOf types.str);
default = {
resize = {
"${cfg.config.left}" = "resize shrink width 10 px";
"${cfg.config.down}" = "resize grow height 10 px";
"${cfg.config.up}" = "resize shrink height 10 px";
"${cfg.config.right}" = "resize grow width 10 px";
"Left" = "resize shrink width 10 px";
"Down" = "resize grow height 10 px";
"Up" = "resize shrink height 10 px";
"Right" = "resize grow width 10 px";
"Escape" = "mode default";
"Return" = "mode default";
};
# TODO: add more modes
};
defaultText = lib.literalExpression ''
{
resize = {
# Binds arrow keys to resizing commands
''${cfg.config.left}" = "resize shrink width 10 px";
''${cfg.config.down}" = "resize grow height 10 px";
''${cfg.config.up}" = "resize shrink height 10 px";
''${cfg.config.right}" = "resize grow width 10 px";

"Left" = "resize shrink width 10 px";
"Down" = "resize grow height 10 px";
"Up" = "resize shrink height 10 px";
"Right" = "resize grow width 10 px";

# Exit resize mode
"Escape" = "mode default";
"Return" = "mode default";
};
}
'';
default = generators.keybindings.modes;
description = ''
An attribute set that defines binding modes and keybindings
inside them
Expand Down