# Hyprland Lua Config Migration (0.55+) ## Summary Hyprland 0.55 deprecates the legacy `hyprlang` (`.conf`) format in favor of a native Lua DSL (`hyprland.lua`). Both formats coexist during transition, but `.lua` is the future. ## Configuration File Priority | File | Format | Priority | |------|--------|----------| | `~/.config/hypr/hyprland.lua` | Lua DSL (`hl.*` API) | **Preferred** (0.55+) | | `~/.config/hypr/hyprland.conf` | Legacy hyprlang | Deprecated | When both exist, Hyprland loads `.lua` first. If `.lua` is present, `.conf` is ignored. ## Lua API Quick Reference ```lua -- Variables local terminal = "kitty" local mainMod = "SUPER" -- Config blocks hl.config({ general = { gaps_in = 5 } }) hl.env("XCURSOR_SIZE", "24") hl.monitor({ output = "", mode = "preferred", position = "auto", scale = "auto" }) -- Keybindings (single combined key string) hl.bind(mainMod .. " + Q", hl.dsp.window.close()) hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(terminal)) -- Window/workspace rules hl.window_rule({ name = "my-rule", match = { class = ".*" }, suppress_event = "maximize" }) hl.workspace_rule({ workspace = 1, monitor = "DP-1", default = true }) -- Autostart hl.on("hyprland.start", function() hl.exec_cmd("waybar &") end) -- Gestures, animations hl.gesture({ fingers = 3, direction = "horizontal", action = "workspace" }) hl.curve("easeOutQuint", { type = "bezier", points = { {0.23, 1}, {0.32, 1} } }) hl.animation({ leaf = "windows", enabled = true, speed = 4.79, spring = "easy" }) ``` ## Dispatcher Functions (`hl.dsp.*`) | Lua API | Legacy .conf equivalent | |---------|------------------------| | `hl.dsp.exec_cmd("cmd")` | `exec, cmd` | | `hl.dsp.window.close()` | `killactive` | | `hl.dsp.window.float({ action = "toggle" })` | `togglefloating` | | `hl.dsp.window.pseudo()` | `pseudo` | | `hl.dsp.window.fullscreen({ mode = 0 })` | `fullscreen, 0` | | `hl.dsp.window.move({ direction = "left" })` | `movewindow, l` | | `hl.dsp.window.move({ workspace = 2 })` | `movetoworkspace, 2` | | `hl.dsp.window.drag()` / `.resize()` | mouse bind | | `hl.dsp.focus({ direction = "left" })` | `movefocus, l` | | `hl.dsp.focus({ workspace = 2 })` | `workspace, 2` | | `hl.dsp.focus({ workspace = "e+1" })` | `workspace, e+1` | | `hl.dsp.workspace.toggle_special("magic")` | `togglespecialworkspace` | | `hl.dsp.layout("togglesplit")` | `layoutmsg, togglesplit` | ## Pitfalls Learned | Issue | Fix | |-------|-----| | `hl.dsp.focus({ direction = "next" })` | **Invalid.** Only `left/right/up/down` accepted. Use `hl.dsp.exec_cmd("hyprctl dispatch cyclenext")` instead. | | `tap-to-click = true` | **Invalid Lua.** Hyphens not allowed in identifiers. Use `tap_to_click` (Hyprland accepts underscores). | | `hl.bind("", "Print", ...)` | **Invalid.** Lua API uses single key string: `hl.bind("Print", ...)`. | | `hl.bind(mainMod, "Q", ...)` | **Invalid.** Combine into one string: `hl.bind(mainMod .. " + Q", ...)`. | | `resizeactive` not in `hl.dsp.*` | Use `hl.dsp.exec_cmd("hyprctl dispatch resizeactive -40 0")` as wrapper. | | `luac -p` false positives | Standard `luac` can't validate Hyprland's custom `hl.*` API. Use `hyprctl configerrors` at runtime instead. | ## Validation ```bash # Runtime validation (requires running Hyprland session) hyprctl configerrors # Over SSH (find instance signature first) HYPRLAND_INSTANCE_SIGNATURE=$(ls /run/user/$(id -u)/hypr/) hyprctl configerrors # Syntax-only check (limited - won't catch hl.* API issues) luac -p ~/.config/hypr/hyprland.lua ``` ## conf-to-lua Migration Mapping | Legacy `.conf` | Lua `.lua` | |----------------|------------| | `$mainMod = SUPER` | `local mainMod = "SUPER"` | | `monitor=DP-1,...` | `hl.monitor({ output = "DP-1", ... })` | | `env = KEY,VALUE` | `hl.env("KEY", "VALUE")` | | `input { ... }` | `hl.config({ input = { ... } })` | | `general { ... }` | `hl.config({ general = { ... } })` | | `bind = MOD, KEY, exec, cmd` | `hl.bind(mod .. " + KEY", hl.dsp.exec_cmd("cmd"))` | | `bind = MOD, KEY, killactive` | `hl.bind(mod .. " + KEY", hl.dsp.window.close())` | | `bind = MOD, KEY, togglefloating` | `hl.bind(mod .. " + KEY", hl.dsp.window.float({ action = "toggle" }))` | | `bind = MOD, KEY, fullscreen, 0` | `hl.bind(mod .. " + KEY", hl.dsp.window.fullscreen({ mode = 0 }))` | | `bind = MOD, KEY, movefocus, l` | `hl.bind(mod .. " + KEY", hl.dsp.focus({ direction = "left" }))` | | `bind = MOD, KEY, movewindow, l` | `hl.bind(mod .. " + KEY", hl.dsp.window.move({ direction = "left" }))` | | `bind = MOD, KEY, workspace, N` | `hl.bind(mod .. " + KEY", hl.dsp.focus({ workspace = N }))` | | `bind = MOD, KEY, cyclenext` | `hl.bind(mod .. " + KEY", hl.dsp.exec_cmd("hyprctl dispatch cyclenext"))` | | `bind = MOD, KEY, pseudo` | `hl.bind(mod .. " + KEY", hl.dsp.window.pseudo())` | | `bind = MOD, KEY, layoutmsg, togglesplit` | `hl.bind(mod .. " + KEY", hl.dsp.layout("togglesplit"))` | | `bind = , Print, exec, cmd` | `hl.bind("Print", hl.dsp.exec_cmd("cmd"))` | | `bind = MOD, KEY, exit` | `hl.bind(mod .. " + KEY", hl.dsp.exec_cmd("hyprctl dispatch exit"))` | | `device { name = "..."; ... }` | `hl.device({ name = "...", ... })` | | `workspace = 1, monitor:DP-1, default:true` | `hl.workspace_rule({ workspace = 1, monitor = "DP-1", default = true })` | | `exec-once = cmd` | `hl.on("hyprland.start", function() hl.exec_cmd("cmd") end)` | | `col.active_border = rgba(...) 45deg` | `col = { active_border = { colors = {"rgba(...)"}, angle = 45 } }` | ## Multi-Machine Setup This project manages configs for two machines with identical keybindings but different hardware: | Aspect | Workstation (pfeddersheim) | MacBook Pro 16,1 | |--------|---------------------------|-------------------| | GPU | NVIDIA (6 env vars) | Intel UHD 630 + AMD RX 5500M (no env vars) | | Monitors | 3 fixed (DP-1, DVI-D-1, HDMI-A-1) | Built-in + HDMI dock (auto-detect) | | Input | de layout, left-handed mouse | de + mac_nodeadkeys + caps:swapescape, touchpad | | Touchpad | N/A | natural_scroll, gestures, disable_while_typing | | Media keys | N/A | Volume, brightness, playerctl | | Window rules | None | Suppress maximize, XWayland fix | | Config format | `.lua` (Ansible-managed) | `.lua` (manual) |