Skip to content

config/lua: init lua config manager, use lua if available - #13817

Merged
vaxerski merged 5 commits into
hyprwm:mainfrom
vaxerski:lua-lua-lua-lua-lua-lua-lua
Apr 26, 2026
Merged

config/lua: init lua config manager, use lua if available#13817
vaxerski merged 5 commits into
hyprwm:mainfrom
vaxerski:lua-lua-lua-lua-lua-lua-lua

Conversation

@vaxerski

@vaxerski vaxerski commented Mar 22, 2026

Copy link
Copy Markdown
Member

Adds a new lua config manager, which will automatically be used if there is a lua config present.

Work-in-progress.

Sample syntax is in example/hyprland.lua (I will add a wiki MR later, the config isn't exhaustive, you need to check the src for full list)

Lua will automatically be used if you have a hyprland.lua config file next to your .conf one. Worth noting this is a check at startup - you can't switch from one to another at runtime.

TODOs:

  • Fix missing stuff from hyprlang
  • Test
  • Plugin integration
  • Dispatchers: improve wording, naming, etc.
  • Eval
  • Lua lambda for binds
  • Timers
  • Tests
  • Wiki
  • Emergency Binds
  • LSP
  • Exec rules
  • Gesture: replace dispatcher with lua fn
  • Get config value

Please help with the wiki PR: hyprwm/hyprland-wiki#1434

Comments / ideas / FRs for lua appreciated at this point as we can discuss the API

Also please do let me know which stuff from .conf is missing in lua atm I'll add it to the above list

@AllMeatball

AllMeatball commented Mar 22, 2026

Copy link
Copy Markdown

I would recommend writing the table only function calls like this @vaxerski. parentheses aren't required with single value table or string only function parameters.

Example

hl.window_rule {
    name  = "suppress-maximize-events",
    match = { class = ".*" },
    suppress_event = "maximize",
}

@AllMeatball

Copy link
Copy Markdown

I would recommend writing the table only function calls like this @vaxerski. parentheses aren't required with single value table or string only function parameters.

Example

hl.window_rule {
    name  = "suppress-maximize-events",
    match = { class = ".*" },
    suppress_event = "maximize",
}

An alternative syntax like this could be nice too.

hl.CONFIG_KV.general {
        gaps_in     = 5,
        gaps_out    = 20,
        border_size = 2,
        col = {
            active_border   = { colors= {"rgba(33ccffee)",  "rgba(00ff99ee)"}, angle = 45 },
            inactive_border = "rgba(595959aa)",
        },
        resize_on_border = false,
        allow_tearing    = false,
        layout           = "dwindle",
}

I'm iffy on the CONFIG_KV name though. idk exactly what I would call it.

@Mabi19

Mabi19 commented Mar 22, 2026

Copy link
Copy Markdown

What's the equivalent for source in Lua? Is it just require? My setup currently sources a file from /usr/share, which I don't think would be reachable through the default require paths.

EDIT: I remembered that dofile exists, and would probably work here. Looking at the code, it wouldn't make the file included by it tracked for updates, but at least it'd get loaded (I think. I haven't actually tested.)

@vaxerski

Copy link
Copy Markdown
Member Author

yes its require

@vaxerski

Copy link
Copy Markdown
Member Author

@AllMeatball ok but is that invalid? No? I like it that way.

@kermeow

kermeow commented Mar 23, 2026

Copy link
Copy Markdown

reminder from twitter to add Lua callbacks for binds ❤️ very excited for this

@harshv5094

Copy link
Copy Markdown

One question, are we gradually removing the hyprlang config after lua config is stable?

@ashley-paul-12345

ashley-paul-12345 commented Mar 23, 2026

Copy link
Copy Markdown

will external libraries be supported?
reading and decoding json files will really be helpful

@Dregu

Dregu commented Mar 23, 2026

Copy link
Copy Markdown
Contributor

Lua will automatically be used if you have a hyprland.lua config file next to your .conf one.

Something weird going on with the replace_extension shenanigans, got errors that my ".conf" didn't have function parameters, not having a .conf file is also an error and I only managed to load any lua with ln -s hyprland.lua hyprland.conf

I'm iffy on the CONFIG_KV name though. idk exactly what I would call it.

Well things can be both callable and indexable in lua, so it could just be hl.config.general{...} I guess.

will external libraries be supported?

Already sent Hello World with luasocket from my config to other pc.

reminder from twitter to add Lua callbacks for binds ❤️ very excited for this

Yeah definitely, this will be the thing that solves all the window/layout/date/whatever-specific binds.

@mariuszste

Copy link
Copy Markdown

Don't forget about thread safety. Lua is not thread-aware, and accessing the same state from multiple threads will lead to very nasty bugs. And even if HL makes assumptions about only accessing it from one thread, plugins might not, so either enforce that they can't, or make it thread safe.

@vaxerski

Copy link
Copy Markdown
Member Author

Don't forget about thread safety. Lua is not thread-aware, and accessing the same state from multiple threads will lead to very nasty bugs. And even if HL makes assumptions about only accessing it from one thread, plugins might not, so either enforce that they can't, or make it thread safe.

95% of hyprland is single-threaded, no problems here.

@AllMeatball

AllMeatball commented Mar 23, 2026

Copy link
Copy Markdown

will external libraries be supported? reading and decoding json files will really be helpful

As long require is working you can use these libraries.

https://github.com/rxi/json.lua
https://github.com/actboy168/json.lua

@vaxerski
vaxerski force-pushed the lua-lua-lua-lua-lua-lua-lua branch from 57468d6 to 12ed96c Compare March 23, 2026 16:12
@roshanstudley

Copy link
Copy Markdown

Hello, I would love to help with this feature as I eagerly anticipate it, but I am still at an intermediary stage in my programming expertise, is there any monotonous stuff I can help with to allow the more experienced contributors to focus on more important things?

@chocoblocko9

Copy link
Copy Markdown
Contributor

btw if anyone on nix wants to test this i made this patch to get it to work

no i dont know why Jeremy.hpp seems to need cstdint explicity imported on nix, nix sandbox is stricter maybe?

diff --git a/nix/default.nix b/nix/default.nix
index 51bb58fe..04c84f96 100644
--- a/nix/default.nix
+++ b/nix/default.nix
@@ -36,6 +36,7 @@
   libxkbcommon,
   libuuid,
   libgbm,
+  lua5_5,
   muparser,
   pango,
   pciutils,
@@ -191,6 +192,7 @@ customStdenv.mkDerivation (finalAttrs: {
       libxcursor
       libxkbcommon
       muparser
+      lua5_5
       pango
       pciutils
       re2
diff --git a/src/config/supplementary/jeremy/Jeremy.hpp b/src/config/supplementary/jeremy/Jeremy.hpp
index c1332c28..8fb73316 100644
--- a/src/config/supplementary/jeremy/Jeremy.hpp
+++ b/src/config/supplementary/jeremy/Jeremy.hpp
@@ -2,6 +2,7 @@
 
 #include <string>
 #include <expected>
+#include <cstdint>
 
 namespace Config::Supplementary::Jeremy {
     enum eConfigType : uint8_t {

@chocoblocko9

Copy link
Copy Markdown
Contributor

also not sure if it's just me but the input section seems completely broken to me, changing kb_layout, kb_options, natural_scroll etc just does nothing, even through hyprctl eval

e.g hyprctl eval "hl.config({ input = { kb_layout = 'de' }})" returns ok but doesn't apply, whereas hyprctl eval "hl.config({ general = { gaps_in = 50 }})" works perfectly

also holding down keys to repeat them is broken on both my devices (i assume its related)

@Dregu

Dregu commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

also not sure if it's just me but the input section seems completely broken

Yeah not just you, can't change layout, can't repeat keys.

Also an autoreload when editing the main lua simply breaks things, binds no longer work, timers stop running... Explicit hyprctl reload fixes those things and autoreload by editing a required binds.lua doesn't have the same issue.

Event handlers don't seem to reset on reload, so on(config.reloaded) just multiplies on each reload.

I made a simple REPL console module to poke around the lua env, may not survive a reload either.

@ItsOhen

ItsOhen commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Is col.active_border and col.inactive_border tables or variables?
general { col { active_border = gradient } } ?

@ThrowTop

Copy link
Copy Markdown

Is col.active_border and col.inactive_border tables or variables? general { col { active_border = gradient } } ?

hlc.config = {
    general = {
        gaps_in = 4,
        gaps_out = 8,
        border_size = 2,
        col = {
            active_border = { colors = { "rgb(B4BEFE)", "rgb(303030)", angle = 45 } },
            inactive_border = { colors = { "rgb(303030)", "rgb(B4BEFE)", angle = 35 } },
        },
        layout = "dwindle",
        resize_on_border = false,
        resize_corner = 3,
    }
} 
  

col is table with active and inactive border. gradients themselves are also tables like this.

@kRHYME7

This comment was marked as resolved.

@ItsOhen

ItsOhen commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Not exactly sure why.
But doing hl.dsp.window.fn really fucking grinds my gears.

@vaxerski

Copy link
Copy Markdown
Member Author

I prefer hl.dsp.window.fn than focusworkspaceoncurrentmonitor

@aruhier

aruhier commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

@vaxerski I'm maintaining Hyproverlay (the Gentoo's overlay that provides Hyprland and other hypr packages). Having 5.5 as the minimum required version for lua makes it difficult to package Hyprland as it's quite recent (December) and not yet in Gentoo.

I tried to change the CMakeLists to accept lua54, I can build Hyprland without issue and it runs normally with a hyprlang config file, but I didn't test to use a lua config file. Did you have some specific reasons to require lua55, or accepting lua54 would work as well?

@vaxerski

Copy link
Copy Markdown
Member Author

you can patch to use lua54, I don't really care as long as it works. I picked 5.5 because it's the latest.

@gulafaran

Copy link
Copy Markdown
Contributor

@vaxerski I'm maintaining Hyproverlay (the Gentoo's overlay that provides Hyprland and other hypr packages). Having 5.5 as the minimum required version for lua makes it difficult to package Hyprland as it's quite recent (December) and not yet in Gentoo.

I tried to change the CMakeLists to accept lua54, I can build Hyprland without issue and it runs normally with a hyprlang config file, but I didn't test to use a lua config file. Did you have some specific reasons to require lua55, or accepting lua54 would work as well?

I use gentoo, since lua is slotted making a 5.5 ebuild wasnt hard, the hyproverlay cant have a 5.5 lua ebuild until gentoo repos has it?

@aruhier

aruhier commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

I use gentoo, since lua is slotted making a 5.5 ebuild wasnt hard, the hyproverlay cant have a 5.5 lua ebuild until gentoo repos has it?

We can, but I prefer avoiding to maintain an ebuild of Lua if possible. Patching the CMake dependencies to take lua54 is an easier solution if it works, I opened an issue here: https://codeberg.org/hyproverlay/hyproverlay/issues/60.

@kRHYME7

kRHYME7 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Hi, is hl.unbind borke? a

image image

config

hl.bind("SUPER + TAB", hl.dsp.exec_cmd("kitty"))
hl.unbind("SUPER + TAB")

@vaxerski

Copy link
Copy Markdown
Member Author

looks like it

@kRHYME7

kRHYME7 commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

the wiki is not yet done. So yeah checking the src I just need to separate the mod and key for unbind.
And for bind it only accpets single " string" and uses + as delimiter. It's not neat and confusing.

hl.bind("SUPER + T", hl.dsp.exec_cmd("kitty"))
hl.unbind("SUPER","T") 
hl.bind("SUPER + T", hl.dsp.exec_cmd("kitty"))

this works.

IMO, sepating mod and key is better for binds too.
Edit: But because it is lua I think I can patch for my specific usecase.
Edit2 :yeah making + as convention delimiter for key combos si fine! Thanks!

@ItsOhen

ItsOhen commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Yes. unbind use unbind(mod, key) like the old dispatcher.

@vaxerski

Copy link
Copy Markdown
Member Author

this is fixed with #14199

@vaxerski

Copy link
Copy Markdown
Member Author

IMO, sepating mod and key is better for binds too.

No.

@JohnRTitor

Copy link
Copy Markdown
Contributor

@fufexan can we get Hyprland lua style config via home manager?

@fufexan

fufexan commented Apr 30, 2026

Copy link
Copy Markdown
Member

@fufexan can we get Hyprland lua style config via home manager?

hmmm it can be done if people want to, but you'd need an external lib for it (like https://git.pleshevski.ru/mynix/nix2lua) or to write one from scratch.

I'd rather just write lua files and interpolate nix values where needed.

Anyway, feel free to open a discussion about Nix-managed lua files, I'd like to hear more opinions on this.

@JohnRTitor

Copy link
Copy Markdown
Contributor

I looked at Nixvim's implementation to-lua.nix, perhaps this could be upstreamed into Nixpkgs as lib.generators.toLua?

CC @khaneliman @MattSturgeon I am surprised that we don't have a lua generator in Nixpkgs yet.

@MattSturgeon

MattSturgeon commented May 1, 2026

Copy link
Copy Markdown

I am surprised that we don't have a lua generator in Nixpkgs yet.

Nixpkgs does have lib.generators.toLua (~3yr old) and pkgs.formats.lua {} (~1yr old).

https://github.com/NixOS/nixpkgs/blob/7b18d67286f4c85dafbf3b5fd308f28921d35f6b/lib/generators.nix#L749-L868

https://github.com/NixOS/nixpkgs/blob/7b18d67286f4c85dafbf3b5fd308f28921d35f6b/pkgs/pkgs-lib/formats.nix#L749-L807

Not all of Nixvim's toLua features are present in the Nixpkgs implementation. We're happy to discuss upstreaming any that would be appropriate.

The main missing feature is checking whether table keys are valid lua identifiers, to avoid rendering the ["key"] syntax unnecessarily. Nixvim implements that via isKeyword and isIdentifier, but the keyword list could change with lua version so may not be suitable for a Nixpkgs implementation.

https://github.com/nix-community/nixvim/blob/a67d9cd6ff725a763afe88727aac73208ded3bf4/lib/to-lua.nix#L3-L32

BlueManCZ added a commit to BlueManCZ/hyprland-schema that referenced this pull request May 4, 2026
- Extend the parser to handle the new `ConfigValues.cpp` format introduced in `main` after hyprwm/Hyprland#13817.
- Update `fetch_header` to auto-detect formats and attempt `ConfigValues.cpp` first, with fallback to `ConfigDescriptions.hpp`.
- Add tests covering all types and edge cases for the new format.
- Update documentation, comments, and help text to reflect the dual format support.
@kRHYME7

kRHYME7 commented May 5, 2026

Copy link
Copy Markdown
Contributor

Hi vaxxx.

The wiki says to use

col.something

But it gives erros when using it like this

hl.config({
    general = {
    col.active_border = "0xffffffff",
    col.inactive_border = "0xffffffff",
    col.nogroup_border = "0xffffffff",
    col.nogroup_border_active = "0xffffffff"
}
})

Err:
image

However using this works fine.

hl.config({

general = {
    col = {
        active_border = "0xffffffff",
        inactive_border = "0xffffffff",
        nogroup_border = "0xffffffff",
        nogroup_border_active = "0xffffffff"
    }
}

})

Wiki said https://wiki.hypr.land/Configuring/Basics/Variables/#general
And I think it is affecting all col.

Is this an undocumented behavior?

@kRHYME7

kRHYME7 commented May 5, 2026

Copy link
Copy Markdown
Contributor

Another thing

This works when written in the config file

hl.config({ misc = { disable_autoreload = true } })

however using eval it is not working

hyprctl eval 'hl.config({ misc = { disable_autoreload = true } })'

I notice it still reloads.
image

@ThrowTop

ThrowTop commented May 5, 2026

Copy link
Copy Markdown

Hi vaxxx.

The wiki says to use

col.something

But it gives erros when using it like this

hl.config({
    general = {
    col.active_border = "0xffffffff",
    col.inactive_border = "0xffffffff",
    col.nogroup_border = "0xffffffff",
    col.nogroup_border_active = "0xffffffff"
}
})

Err: image

However using this works fine.

hl.config({

general = {
    col = {
        active_border = "0xffffffff",
        inactive_border = "0xffffffff",
        nogroup_border = "0xffffffff",
        nogroup_border_active = "0xffffffff"
    }
}

})

Wiki said https://wiki.hypr.land/Configuring/Basics/Variables/#general And I think it is affecting all col.

Is this an undocumented behavior?

dot notation is not valid inside table literals.

-- valid
t.col.active_border = "0xff"

-- valid 
t = { col = { active_border = "0xff" } }

-- invalid dot notation inside a table literal
t = { col.active_border = "0xff" }

in the documentaiton it looks like col.active_border is a single key, but because of how lua works col is a table holding with key active_border

Probably not intended as its quite unclear in the documentation.

@vaxerski

vaxerski commented May 5, 2026

Copy link
Copy Markdown
Member Author

MRs welcome

Krapaince added a commit to Krapaince/nix-config that referenced this pull request May 18, 2026
Krapaince added a commit to Krapaince/nix-config that referenced this pull request May 18, 2026
crthpl pushed a commit to crthpl/Hyprland that referenced this pull request Jun 3, 2026
Adds a new lua config manager, which will automatically be used if there is a lua config present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.