From e92ac9033a06e3541db489d567708033291fdaef Mon Sep 17 00:00:00 2001 From: Robin Steinberg Date: Wed, 19 Aug 2026 16:02:12 +0200 Subject: [PATCH] Create HYPRLAND_LUA_MIGRATION.md --- HYPRLAND_LUA_MIGRATION.md | 216 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 HYPRLAND_LUA_MIGRATION.md diff --git a/HYPRLAND_LUA_MIGRATION.md b/HYPRLAND_LUA_MIGRATION.md new file mode 100644 index 0000000..85e654e --- /dev/null +++ b/HYPRLAND_LUA_MIGRATION.md @@ -0,0 +1,216 @@ +# Hyprland Lua Migration Guide for AI Agents + +## Objective +Migrate an existing legacy Hyprland configuration (using `.conf` files based on the old `hyprlang` syntax) to the new Lua-based configuration system introduced in Hyprland v0.55+. + +**CRITICAL INSTRUCTION FOR THE AGENT:** +The target machine has a slightly different configuration (e.g., different monitors, workspaces, applications, keybindings) than the original machine this guide was generated on. **Do NOT blindly copy-paste the examples below.** Use them *only* as a translation reference to convert the exact values found on the target machine into the new Lua syntax. + +## Migration Principles +1. **Modularity**: Lua uses `require("module_name")` for imports instead of `source = ...`. A file `bindings.lua` is imported via `require("bindings")`. Subdirectories work via dot-notation: `require("bindings.media")` maps to `bindings/media.lua`. +2. **Extensions**: Create new `.lua` files mirroring the names of the old `.conf` files. +3. **Scope**: Only Hyprland config files are migrated to Lua (e.g., `hyprland.conf`, `monitors.conf`, `bindings.conf`). Do **not** migrate configurations for external tools like `hypridle.conf`, `hyprlock.conf`, `waybar`, or `hyprpaper`. + +--- + +## Syntax Translation Reference + +### 1. Variables and Environment Variables +**Legacy (.conf):** +```hyprlang +$terminal = kitty +env = GDK_SCALE,1 +``` +**Lua (.lua):** +```lua +local terminal = "kitty" +hl.env("GDK_SCALE", "1") +``` + +### 2. Autostart (`exec-once`) +**Legacy:** +```hyprlang +exec-once = uwsm app -- waybar +exec-once = uwsm app -- hyprpaper +``` +**Lua:** +```lua +hl.on("hyprland.start", function () + hl.exec_cmd("uwsm app -- waybar") + hl.exec_cmd("uwsm app -- hyprpaper") +end) +``` + +### 3. Monitors +**Legacy:** +```hyprlang +monitor=eDP-1,1920x1080,auto,1 +monitor=desc:Xiaomi Corporation Mi Monitor,3440x1440@60,auto,1 +``` +**Lua:** +```lua +hl.monitor({ output = "eDP-1", mode = "1920x1080", position = "auto", scale = 1 }) +hl.monitor({ output = "desc:Xiaomi Corporation Mi Monitor", mode = "3440x1440@60", position = "auto", scale = 1 }) +``` + +### 4. Configuration Blocks (`general`, `decoration`, etc.) +**Legacy:** +```hyprlang +general { + gaps_in = 4 + col.active_border = rgba(33ccffee) + layout = dwindle +} +decoration { + rounding = 4 + blur { + enabled = true + size = 8 + } +} +``` +**Lua:** +```lua +hl.config({ + general = { + gaps_in = 4, + col = { + active_border = "rgba(33ccffee)", + }, + layout = "dwindle", + }, + decoration = { + rounding = 4, + blur = { + enabled = true, + size = 8, + }, + }, +}) +``` + +### 5. Keybindings (`bind`, `bindd`, `bindm`, `bindl`, `binde`) +**Legacy:** +```hyprlang +bind = SUPER, Q, killactive, +bindd = SUPER, B, Launch Browser, exec, firefox +bind = SUPER, left, movefocus, l +bind = SUPER, 1, workspace, 1 +bindm = SUPER, mouse:272, movewindow +bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+ +bind = SUPER, code:10, workspace, 1 +bind = SUPER SHIFT, S, swapwindow, l +``` +**Lua:** +Flags from the legacy format (`e` for repeat, `l` for locked, `m` for mouse) become booleans in the options table. Dispatchers must use the `hl.dsp.*` API. **If a dispatcher isn't listed below, fall back to `hl.dsp.exec_cmd("hyprctl dispatch ")`**. +```lua +hl.bind("SUPER + Q", hl.dsp.window.close()) +hl.bind("SUPER + B", hl.dsp.exec_cmd("firefox"), { description = "Launch Browser" }) +hl.bind("SUPER + left", hl.dsp.focus({ direction = "left" })) +hl.bind("SUPER + 1", hl.dsp.focus({ workspace = 1 })) + +hl.bind("SUPER + mouse:272", hl.dsp.window.drag(), { mouse = true }) +hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+"), { repeating = true, locked = true }) + +-- Keycodes use the `code:` prefix directly in the string +hl.bind("SUPER + code:10", hl.dsp.focus({ workspace = 1 })) + +-- Fallback for undocumented or complex dispatchers +hl.bind("SUPER + SHIFT + S", hl.dsp.exec_cmd("hyprctl dispatch swapwindow l")) +``` +*Note: Key combinations are joined by ` + `.* +*Common Dispatchers translation:* +- `killactive` -> `hl.dsp.window.close()` +- `togglefloating` -> `hl.dsp.window.float({ action = "toggle" })` +- `fullscreen, 0` -> `hl.dsp.window.fullscreen(0)` +- `togglesplit` -> `hl.dsp.layout("togglesplit")` +- `movefocus, l` -> `hl.dsp.focus({ direction = "left" })` +- `workspace, 1` -> `hl.dsp.focus({ workspace = 1 })` +- `movetoworkspace, 1` -> `hl.dsp.window.move({ workspace = 1 })` +- `cyclenext` -> `hl.dsp.exec_cmd("hyprctl dispatch cyclenext")` + +### 6. Window and Layer Rules +**Legacy:** +```hyprlang +layerrule = blur true, match:namespace waybar +windowrule = opacity 0.85 0.8,match:class ^chrome-gemini\.google\.com.* +windowrule = float true,match:class ^org\.gnome\.Calculator$ +windowrule = no_focus true,match:class ^$,match:title ^$,match:xwayland true +``` +**Lua:** +*Watch out for string escaping in regex! Single backslashes in regex must become double backslashes in Lua strings.* Multi-matches are grouped into the `match` table. +```lua +hl.layer_rule({ match = { namespace = "waybar" }, blur = true }) + +hl.window_rule({ match = { class = "^chrome-gemini\\.google\\.com.*" }, opacity = "0.85 0.8" }) +hl.window_rule({ match = { class = "^org\\.gnome\\.Calculator$" }, float = true }) +hl.window_rule({ + match = { class = "^$", title = "^$", xwayland = true }, + no_focus = true +}) +``` + +### 7. Advanced Features (Animations, Devices, Gestures) +**Legacy Animations:** +```hyprlang +bezier = easeOutQuint, 0.23, 1, 0.32, 1 +animation = windows, 1, 4.79, easeOutQuint +animation = windowsIn, 1, 4.1, easeOutQuint, popin 87% +``` +**Lua Animations:** +*Note: Speed 1 in legacy = 100ms in lua. 4.79 -> 4.79.* +```lua +hl.curve("easeOutQuint", { type = "bezier", points = {{0.23, 1}, {0.32, 1}} }) + +hl.animation({ leaf = "windows", enabled = true, speed = 4.79, bezier = "easeOutQuint" }) +hl.animation({ leaf = "windowsIn", enabled = true, speed = 4.1, bezier = "easeOutQuint", style = "popin 87%" }) +``` + +**Legacy Devices & Gestures:** +```hyprlang +device { + name = epic-mouse-v1 + sensitivity = -0.5 +} +gesture = 3, horizontal, workspace +``` +**Lua Devices & Gestures:** +```lua +hl.device({ + name = "epic-mouse-v1", + sensitivity = -0.5 +}) + +hl.gesture({ + fingers = 3, + direction = "horizontal", + action = "workspace" +}) +``` + +--- + +## Validation Steps (Post-Migration) + +Once the agent has translated the `.conf` files into `.lua` files, it MUST perform the following validations before declaring the task complete: + +1. **Syntax Check**: Use the built-in Lua compiler to ensure there are no missing brackets or syntax errors. + ```bash + luac -p ~/.config/hypr/hyprland.lua + # Run this for every .lua file generated + ``` + +2. **Restart Notification**: Inform the user that because the configuration language is shifting from `.conf` to `.lua`, Hyprland will only detect this on a fresh startup. The user MUST log out and log back in to activate the new configuration. + +3. **Runtime Validation Commands**: Provide the user with these commands to verify the migration worked once they log back in: + - Check if Lua is the active config provider: + ```bash + hyprctl systeminfo | grep -i config + # Should output: configProvider: lua + ``` + - Check if Lua keybindings are registered: + ```bash + hyprctl binds | grep -i "__lua" | head -n 5 + ``` + +4. **Cleanup Phase**: Once the user confirms the Lua configuration is active and working correctly, instruct the user to remove the old `.conf` files (or do it for them if requested). Leave `hypridle.conf`, `hyprlock.conf`, and `hyprpaper.conf` intact! \ No newline at end of file