Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hypr-migrate

Migrate legacy Hyprland hyprlang config files (.conf, Hyprland ≤0.54) to the new Lua config format (.lua, Hyprland ≥0.55).

Implements a three-phase semantic pipeline — Decompose → Sort → Reconstruct — not line-by-line substitution. Every emitted hl.* call matches documented APIs on the Hyprland wiki.

Install

Dependencies

  • Python 3.10+

Standalone (no install)

git clone https://github.com/your-org/hypr-migrate.git
cd hypr-migrate
./hypr_migrate.py ~/.config/hypr/hyprland.conf

pip install

pip install hypr-migrate   # once published
hypr-migrate ~/.config/hypr/hyprland.conf

Arch Linux / NixOS

No special package is needed — just run python hypr_migrate.py directly. Python 3.10+ ships with both distributions. For convenience, symlink it into your PATH:

ln -s "$(pwd)/hypr_migrate.py" ~/.local/bin/hypr-migrate

Usage

# Write to stdout (default)
hypr-migrate ~/.config/hypr/hyprland.conf

# Write to a specific file
hypr-migrate ~/.config/hypr/hyprland.conf --out ~/.config/hypr/hyprland.lua

# In-place: overwrite input path as .lua, backup original as .conf.bak
hypr-migrate ~/.config/hypr/hyprland.conf --in-place

# Show diff against existing .lua
hypr-migrate ~/.config/hypr/hyprland.conf --diff

# Dry-run: parse and report warnings but don't write anything
hypr-migrate ~/.config/hypr/hyprland.conf --dry-run

# Strict mode: exit non-zero if any manual review note is generated
hypr-migrate ~/.config/hypr/hyprland.conf --strict --out converted.lua

# Verbose: print phase-by-phase progress
hypr-migrate ~/.config/hypr/hyprland.conf --verbose

Exit codes

Code Meaning
0 Success, no warnings
1 Success with MIGRATION_WARNINGs (check output)
2 Success with MIGRATION_NOTEs requiring manual review
3 Parse error in input file

Before / After Example

Input (hyprland.conf)

# Monitor setup
monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1

# Variables
$terminal = kitty
$mainMod = SUPER

# Keybinds
bind = $mainMod, Return, exec, $terminal
bind = $mainMod, Q, killactive
bind = $mainMod, 1, workspace, 1
bind = $mainMod, 2, workspace, 2
bind = $mainMod, 3, workspace, 3
bind = $mainMod, 4, workspace, 4
bind = $mainMod, 5, workspace, 5
bind = $mainMod, 6, workspace, 6
bind = $mainMod, 7, workspace, 7
bind = $mainMod, 8, workspace, 8
bind = $mainMod, 9, workspace, 9
bind = $mainMod, 0, workspace, 10

# Window rules
windowrule = float, class:^(pavucontrol)$
windowrulev2 = opacity 0.9 override 0.5 override, class:^(kitty)$, title:^(dialog)$

# Workspace rules
workspace = 1, monitor:DP-1, default:true
workspace = 2, monitor:DP-1

# Startup
exec-once = waybar &

# Environment
env = XCURSOR_SIZE,24

# Colors
general {
    col.active_border = 0xffcba6f7
    col.inactive_border = 0xff45475a
}

decoration {
    rounding = 10
    drop_shadow = true
}

Output (hyprland.lua)

-- hyprland.lua
-- Generated by hypr-migrate from: hyprland.conf
-- Hyprland >= 0.55 required — https://wiki.hypr.land/
--
-- MIGRATION SUMMARY:
--   Variables:       2 resolved
--   Config keys:     4 emitted
--   Monitors:        2
--   Keybinds:        13 total, 9 collapsed into loops
--   Window rules:    2 total, 0 merged
--   Workspace rules: 2
--   Exec commands:   1
--   Warnings:        0  ← search MIGRATION_WARNING
--   Review needed:   0  ← search MIGRATION_NOTE
--
-- IMPORTANT: Verify output against https://wiki.hypr.land/ before use
-- The wiki is the only authoritative reference for Lua syntax.

local terminal = "kitty"
local mainMod = "SUPER"

hl.env("XCURSOR_SIZE", "24")

hl.config({
    general = {
        col.active_border = "rgba(cba6f7ff)",
        col.inactive_border = "rgba(45475aff)",
    },
    decoration = {
        rounding = 10,
        drop_shadow = true,
    },
})

hl.monitor({ output = "DP-1", mode = "2560x1440", refresh = 144, position = "0x0" })
hl.monitor({ output = "HDMI-A-1", mode = "1920x1080", refresh = 60, position = "2560x0" })

hl.workspace_rule({ workspace = "1", monitor = "DP-1", default = true })
hl.workspace_rule({ workspace = "2", monitor = "DP-1" })

hl.window_rule({ match = { class = "^(pavucontrol)$" }, effect = "float" })
hl.window_rule({ match = { class = "^(kitty)$", title = "^(dialog)$" },
                 effect = "opacity 0.9 override 0.5 override" })

-- PATTERN: 10 sequential binds collapsed to loop
for i = 1, 10 do
    hl.bind("SUPER, " .. (i % 10), hl.dsp.workspace({ i }))
end

hl.bind("SUPER, Return", function()
    hl.exec_cmd("kitty")
end)
hl.bind("SUPER, Q", hl.dsp.killactive())

hl.on("hyprland.start", function()
    hl.exec_cmd("waybar &")
end)

Important Notes

  1. Verify against the wiki. This tool is a best-effort migration assistant. The Hyprland wiki at https://wiki.hypr.land/ is the only authoritative reference for Lua config syntax. Always test your migrated configs before deploying.

  2. Backups. Use --in-place to automatically create a .conf.bak backup. The --out flag writes to a separate file and leaves the original unchanged.

  3. hl.dsp.exit() is not available in the Lua API. Binds using the exit dispatcher are annotated with a MIGRATION_NOTE directing you to use uwsm stop instead.

  4. source = path directives are converted to Lua require() calls. Verify that the module path resolves correctly in your Lua setup.

  5. hl.layer_rule() is emitted for layerrule directives, mapping rules directly to effects. hl.animation() is emitted for animation directives in the old NAME, ENABLED, SPEED, CURVE, STYLE format.

  6. wsbind has no direct Lua equivalent and is emitted as a commented MIGRATION_NOTE entry.

  7. Sequential workspace binds (e.g., SUPER+1 through SUPER+0) are automatically collapsed into for loops.

Running Tests

python -m unittest tests.test_hypr_migrate -v

License

MIT

About

Migrate your old .conf files into the new hyprland syntax

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages