A CachyOS Hyprland Starter Kit

TL3 users can create and edit wiki entries. I know this from experience.
Instructions: Editing and creating wiki posts - Using Discourse - Discourse Meta

Yup, but they are not allowed to move threads to different categories since that unfortunate event (and I still hope this gets changed again)

While I’m waiting for Noctalia to finish its remake, I don’t see why I wouldn’t get everything else in place to compliment it when the time comes.

While my goal with the first was to create a starter/learning environment, I feel like the next take should be a little more of a fully fleshed out desktop environment. My question would be, how far do I go? So, in the spirit of that, the first thing I want to do is generate a list of software dependencies and figure out the beginning state of the desktop.

Display Manager: greetd and nwg-hello
I see no reason to move away from this. I’ve started using this combo on my primary desktop and have grown to like it very much.

Authentication Agent: hyprpolkitagent
I don’t see any reason to change this, unless anyone brings up a good reason to use another polkit.

Notification Daemon: Handled by Noctalia

File Manager: thunar
While I’ve personally started experimenting with TUI file managers(specifically yazi), I still think the default file manager should be GUI and my thoughts on how well Thunar performs this task hasn’t changed either. Does anyone have experience and thoughts about pcmanfm-qt? That’s something I’d been meaning to experiment with but was so impressed with Thunar that I never got there.

Application Launcher: Handled by Noctalia
Status Bar: Handled by Noctalia
Clipboard Daemon: Handled by Noctalia

Screenshot Utility: grimblast-git
I’ve used this for as long as I’ve been using Hyprland because it’s what came with the original CachyOS settings. It suits my needs perfectly as I prefer my screenshots all go straight to clipboard rather than the screenshot utility handling anything else. However, I’m open to exploring other options if anyone has any ideas.

Session Menu: Handled by Noctalia
Lockscreen: Handled by Noctalia
Idle Handler: Handled by Noctalia

Theme Management: nwg-look(GTK), qt6ct(QT), and kvantum(QT)
No reason to deviate from these, especially considering that Noctalia integrates with them well.

Theming: Color scheming handled by Noctalia, but that doesn’t cover everything so I’ll have to still come up with the other components(Styling, Icons, Fonts, etc) and I’m willing to be a bit more adventurous here rather than sticking to only what I could find in the native repos.


That does it for the components that the last configuration handled, but now is the interesting part. To determine what other software is added by default and what remains up to the user. It’s a strange line to straddle, because one of the reasons people load up a desktop shell like Noctalia is to have a fully functional desktop waiting for them. For some, reasonable defaults(like CachyOS itself) is the idea rather than spending unconscionable amounts of time configuring every little thing. On the other hand, this is Arch Linux after all and I’d naturally want to avoid installing too much software by default. I expect some discussion will help me a lot here.

Browser: My hands are tied here, since CachyOS installs Firefox by default in a different category as the desktop environment. The same installation instructions I used before(I assume everything will be installed other than a desktop environment) will still stand, and I’m definitely not going to install a second browser. If a user wants to use something different, then they can take the initiative to uncheck Firefox in the installer and pacman their own after installation is complete.

Text Editor: In the beginner config I use mousepad here. I’m open to suggestions here. I would absolutely like to install a text editor, but I’m not sure what the best course of action is. Personally, I would be inclined to installing xdg-terminal-exec from the AUR, which allows Thunar to launch terminal applications. This would open the CachyOS installed text editors nano, micro, and vim to be executed through Thunar’s context menu. Another advantage to this is it enables the cachy-update tray icon to use alacritty(more CachyOS default software) to execute its arch-install script.

However, I would love to consider other options here. After all, the text editor is an awfully important piece of software in an environment configured entirely by text files.

For personal use, I’ve been using vscodium but I actually kind of hate it and have been entertaining migrating to zed.

Image Viewer: I mention this because it’s one of those pieces of software that is rarely thought of since it performs a fairly simple task, and most people just use the one supplied with their desktop environment. So I think it’s a good idea to make sure one is included.

Up until recently, I’d been using swayimg but after wrestling with its config file for far too long I migrated to ristretto, which has been a enormous improvement.

Document Viewer: It’s hard to tell how necessary this is, which probably gives me the answer I need on whether one should be installed by default, but I figure it’s a good idea to ask. I personally use zathura which has worked very well once I figured out its config and bound my preferred keybinds.


So, that’s what I’ve got for now. Interested in hearing opinions on the matter so I can get a software list and default config files squared away whilst waiting for Noctalia’s evolution.

I am currently in the process of configuring my noctalia shell on niri and i have been experimenting with a bunch of software. One really cool feature in my opinion is the automatic color scheme generation from wallpapers. My main goal right now is to get as much as possible of my software stack to update seamlessly with that feature.

The overall project is still a work in progress. So i probably wont be writing a proper guide for a while. But i think i can offer a couple tips:

  • I tried theming dolphin, thunar and nautilus, the theming works but you will probably need a different icon set plus their colors wont change while they are open (either a software restart or manual theme reload is required).
    I tried getting dolphin to reload its theme via commands but I couldn’t find KDE documentation regarding this. I will be trying to get either thunar or the default nautilus to reload live in the next couple of days.
  • From what I can tell this also holds true for GTK and QT software. Theme changes require a software reload.
  • Terminal emulator choice is vital here, especially if you want to use TUI software. The default alacritty does not support sixel out of the box (sixel handles displaying images in terminal emulators). I am thinking of looking into ueberzugpp as a possible solution atm.
  • Steam template works, but you need to configure it as matugen BEFORE you enable the theme. Otherwise it will just load Blue every time lul. (if you already have this issue just disable the theme then change the config and enable it when you get the prompt).
  • The software I tried so far that has Noctalia templates that does not update without closing the software or changing the theme manually: spotify + spicetify, zen-browser (pywalzen didn’t work whatsoever).
  • I tried a lot to get zen-browser to reload its theme while open but it didn’t work after several days of trying. I doubt its impossible to do but I lack the prerequisite experience, if you are gonna go for predefined themes zen-browser is really nice.
  • Pywalfox works out of the box, you need firefox + the pywalfox extention and the pywalfox package. but once its set up Firefox looks fantastic.
  • I would also recommend keeping firefox because, at least on the niri fresh install, it was required to open images from nautilus since there was no image viewer installed by default.

Yesterday i got the swayimg to properly load its theme from a template file while open.
The trick is to put every config command that requires a template in a file separate from init.lua, for example i called it initDoFile.lua then using the lua command dofile in the on_signal functions. Then having Noctalia modify the initDoFile.lua using user templates with a post_hook: kill -s USR1 $(pidof swayimg).
The dofile function needs absolute path or it wont find the file properly.
The template file needs to be separate because the init.lua file is loaded at startup and is not watched for changes by swayimg, i confirmed this by having it print the color hex with an on key function in the init.lua file, regardless of what changed the hex remained constant.

Well, it has arrived.

Compatibility with older Hyprland configurations is being maintained for a few releases until users transition to the new Lua-based configurations.

I’m going to dive into this and see how easy it is to use. But it’s no exaggeration to say that if it’s awful then I’ll probably be exploring the idea of switching to Niri in the near future before the old configuration syntax is deprecated.

Well, I finished converting my config to Lua after a couple hours of work I wish I could get back.

On the bright side, since this isn’t some home grown language, it should no longer change syntax with the changing of the seasons and once the conversion is done then that’s that.

On the not so bright side, it feels like the switch to Lua is meant for extending the power of the window manager in ways that don’t mean much to me personally. So all that’s really changed for me is complicating the syntax of the configuration files.

I’m exhausted by it right now and that matters, but I know on a few days I’ll stop caring because the part that truly annoyed me was configuring the keybinds which is something I’ll never change again so getting bent out of shape over it is kinda pointless.

Here’s a before and after comparison of my keybinds to give an idea:

$mainMod = SUPER # Sets "Windows" key as main modifier

# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more
bind = $mainMod, RETURN, exec, $terminal
bind = $mainMod, SPACE, exec, $fileManager
bind = $mainMod, Q, killactive
bind = $mainMod, L, exec, $lockscreen
bind = $mainMod, C, exec, kcalc
bind = $mainMod, V, togglefloating
bind = $mainMod, F, fullscreen, 0
bind = $mainMod, M, fullscreen, 1
bind = $mainMod, R, exec, $launcher
bind = $mainMod, E, exec, $sessionmenu
bind = $mainMod, P, pseudo, # dwindle
bind = $mainMod, J, togglesplit, # dwindle
bind = SUPER, Menu, exec, pactl set-source-mute @DEFAULT_SOURCE@ toggle # Toggle microphone mute
local mainMod = "SUPER" -- Sets "Windows" key as main modifier

-- Example binds, see https://wiki.hypr.land/Configuring/Basics/Binds/ for more
hl.bind(mainMod .. " + RETURN", hl.dsp.exec_cmd(terminal))
local closeWindowBind = hl.bind(mainMod .. " + Q", hl.dsp.window.close())
-- closeWindowBind:set_enabled(false)
hl.bind(mainMod .. " + K", hl.dsp.exec_cmd("command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch 'hl.dsp.exit()'"))
hl.bind(mainMod .. " + SPACE", hl.dsp.exec_cmd(fileManager))
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + R", hl.dsp.exec_cmd(launcher))
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo())
hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit"))    -- dwindle only
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd(lockscreen))
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(sessionmenu))
hl.bind(mainMod .. " + M", hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" }))
hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen({ mode = "fullscreen", action = "toggle" }))
hl.bind(mainMod .. " + N", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call controlCenter toggle"))
hl.bind(mainMod .. " + S", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call settings toggle"))
hl.bind(mainMod .. " + MENU", hl.dsp.exec_cmd("pactl set-source-mute @DEFAULT_SOURCE@ toggle "))

It’s so that it’s more flexible, letting you define (say) a complex key-binding that fires off several things, and doesn’t have to chain together a list of shell commands to get the name of a widget to pass to yet another chain of commands…

I switched to Lua, and everything except one thing worked with changing every config file. Binds do not work for me and I always get the same message, even with the official config example.

require (modules.binds"): bad argument #1 to ‘?’ (string expected, got nil)

Note that I started with Linux in January so I am quite new and might be missing some context for the problem I have. However, I can not see the logic in this after so many time trying to adress this problem. Anyone else had problems converting binds to lua or have knowledge of this issue?

In Kate, which I use for editing the configs I also get this warning: [Lua Diagnostics.] (undefined-global) Undefined global hl.

I am not sure if that says anything of importance, but global hl. should be automatically known for lua with hyprland installed and updated I would think.

hyprland.lua :

require(“modules.monitors”)
require(“modules.programs”)
require(“modules.binds”)
require(“modules.autostart”)
require(“modules.env”)
require(“modules.decorations”)
require(“modules.animations”)
require(“modules.windowrules”)
require(“modules.layout”)
require(“modules.misc”)
require(“modules.input”)

binds.lua:

Summary

hl.exec_cmd(“dbus-update-activation-environment --systemd --all”)
hl.exec_cmd(“systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP”)

local mainMod = “SUPER”
local closeWindowBind = hl.bind(mainMod .. " + C", hl.dsp.window.close())
– closeWindowBind:set_enabled(false)

hl.bind(mainMod .. " + Q", hl.dsp.exec_cmd(terminal))

– hl.bind(mainMod .. " + A", hl.dsp.exec_cmd(waybar/scripts/launch.sh))

hl.bind(mainMod .. " + A", hl.dsp.exec_cmd(“pkill waybar; waybar &”))
hl.bind(mainMod .. " + B", hl.dsp.exec_cmd(swaync-client -t))
hl.bind(mainMod .. " + D", hl.dsp.exec_cmd(menu))
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager))
hl.bind(mainMod .. " + F", hl.dsp.exec_cmd(Fullscreen))
–hl.bind(mainMod .. " + H", hl.dsp.exec_cmd(cliphist list | rofi -dmenu -display-columns 2 -p “Clipboard” -theme ~/.config/rofi/style-1.rasi | cliphist decode | wl-copy))
hl.bind(mainMod .. " + J", hl.dsp.layout(“togglesplit”)) – dwindle only
hl.bind(mainMod .. " + M", hl.dsp.exec_cmd(wlogout))
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo())
hl.bind(mainMod .. " + R", hl.dsp.exec_cmd(pwvucontrol))

– Example special workspace (scratchpad)
hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special(“magic”))
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = “special:magic” }))
hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(cachyos-pi))
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = “toggle” }))
hl.bind(mainMod .. " + W", hl.dsp.exec_cmd(killactive))
hl.bind(mainMod .. " + Z", hl.dsp.exec_cmd(vivaldi))

– Normal Binds :
– hl.bind(“Print”, hl.dsp.exec_cmd(hyprshot -m region -o ~/Pictures/Screenshots))

– To switch between windows in a floating workspace:
hl.bind(“SUPER + Tab”, function()
hl.dispatch(hl.dsp.window.cycle_next()) – Change focus to another window
hl.dispatch(hl.dsp.window.bring_to_top()) – Bring it to the top
end)

– Move focus with mainMod + arrow keys
hl.bind(mainMod .. " + left", hl.dsp.focus({ direction = “left” }))
hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = “right” }))
hl.bind(mainMod .. " + up", hl.dsp.focus({ direction = “up” }))
hl.bind(mainMod .. " + down", hl.dsp.focus({ direction = “down” }))

– Switch workspaces with mainMod + [0-9]
– Move active window to a workspace with mainMod + SHIFT + [0-9]
for i = 1, 10 do
local key = i % 10 – 10 maps to key 0
hl.bind(mainMod .. " + " .. key, hl.dsp.focus({ workspace = i}))
hl.bind(mainMod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = i }))
end

-- Scroll through existing workspaces with mainMod + scroll
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
hl.bind(mainMod .. " + mouse_up",   hl.dsp.focus({ workspace = "e-1" }))

-- Move/resize windows with mainMod + LMB/RMB and dragging
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(),   { mouse = true })
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })

-- Laptop multimedia keys for volume and LCD brightness
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"),      { locked = true, repeating = true })
hl.bind("XF86AudioMute",        hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"),     { locked = true, repeating = true })
hl.bind("XF86AudioMicMute",     hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"),   { locked = true, repeating = true })
hl.bind("XF86MonBrightnessUp",  hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"),                  { locked = true, repeating = true })
hl.bind("XF86MonBrightnessDown",hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"),                  { locked = true, repeating = true })

-- Requires playerctl
hl.bind("XF86AudioNext",  hl.dsp.exec_cmd("playerctl next"),       { locked = true })
hl.bind("XF86AudioPause", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPlay",  hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPrev",  hl.dsp.exec_cmd("playerctl previous"),   { locked = true })

I’m in the process of relearning this system myself.

Could you try:

  1. Moving the entire contents of binds.lua into hyprland.lua instead and see if it accepts that.
  2. If that works, then moving only the local declarations into hyprland.lua.

I’m not at my desktop at the moment but my current config has everything broken out into require() like you but not my keybinds and it works. I suspect there’s something in there that doesn’t want to be called upon with require() but I haven’t pinpointed what it is just yet.

It’d be nice if Hyprland told you where the error originates but I guess that’d just be too easy.

Hi and thanks for suggestions!

I tried to move everything from binds.lua into hyprland.lua and then got this error message instead:

Your config has errors: bad argument #1 to ‘?’ (string expected, got nil)

stack trackback:

[C]: in ?

[C]: in field ‘exec_cmd’

(1 more…)

Also worth noting I have tried to change from UWSM-manager to Hyprland but the same result there. And somehow, the emergency shortcuts no longer works either. I have to keep my Vivaldi windows open to be able to trick myself into the terminal and file manager/kate. If I closed these now, I would be stuck I guess :sweat_smile:

I am thinking about installing cachyos anew and starting from scratch, starting to believe I have some deeper problem and not being able to identify it. This works for many others it seems, or maybe it has something to do with cachyos. Also, I have never been able to make the icons work in waybar either, same problem there with having done everything acc. to “spec” and not being able to adress the problem.

I’m tight on time so I can’t do any real troubleshooting, but here’s my hyprland.lua which is currently working fine:

------------------
---- MONITORS ----
------------------

require("monitors")

---------------------
---- MY PROGRAMS ----
---------------------

-- Set programs that you use
local terminal = "alacritty"
local fileManager = "thunar"
local browser = "librewolf"
local launcher = "qs -c noctalia-shell ipc call launcher toggle"
local sessionmenu = "qs -c noctalia-shell ipc call sessionMenu toggle"
local lockscreen = "qs -c noctalia-shell ipc call lockScreen lock"

-------------------
---- AUTOSTART ----
-------------------

require("autostart")

-------------------------------
---- ENVIRONMENT VARIABLES ----
-------------------------------

require("environment")

-----------------------
----- PERMISSIONS -----
-----------------------

require("permissions")


-----------------------
---- LOOK AND FEEL ----
-----------------------

require("lookandfeel")

---------------
---- INPUT ----
---------------

require("input")

---------------------
---- KEYBINDINGS ----
---------------------

local mainMod = "SUPER" -- Sets "Windows" key as main modifier

-- Example binds, see https://wiki.hypr.land/Configuring/Basics/Binds/ for more
hl.bind(mainMod .. " + RETURN", hl.dsp.exec_cmd(terminal))
local closeWindowBind = hl.bind(mainMod .. " + Q", hl.dsp.window.close())
-- closeWindowBind:set_enabled(false)
hl.bind(mainMod .. " + K", hl.dsp.exec_cmd("command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch 'hl.dsp.exit()'"))
hl.bind(mainMod .. " + SPACE", hl.dsp.exec_cmd(fileManager))
hl.bind(mainMod .. " + V", hl.dsp.window.float({ action = "toggle" }))
hl.bind(mainMod .. " + R", hl.dsp.exec_cmd(launcher))
hl.bind(mainMod .. " + P", hl.dsp.window.pseudo())
hl.bind(mainMod .. " + J", hl.dsp.layout("togglesplit"))    -- dwindle only
hl.bind(mainMod .. " + L", hl.dsp.exec_cmd(lockscreen))
hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(sessionmenu))
hl.bind(mainMod .. " + M", hl.dsp.window.fullscreen({ mode = "maximized", action = "toggle" }))
hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen({ mode = "fullscreen", action = "toggle" }))
hl.bind(mainMod .. " + N", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call controlCenter toggle" ))
hl.bind(mainMod .. " + S", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call settings toggle"))
hl.bind(mainMod .. " + MENU", hl.dsp.exec_cmd("pactl set-source-mute @DEFAULT_SOURCE@ toggle" ))

-- Screenshot Taking
hl.bind("Print", hl.dsp.exec_cmd("grimblast copy area"))
hl.bind("ALT + Print", hl.dsp.exec_cmd("grimblast copy active"))
hl.bind("CTRL + Print", hl.dsp.exec_cmd("grimblast copy output"))

-- Move focus with mainMod + arrow keys
hl.bind(mainMod .. " + left",  hl.dsp.focus({ direction = "left" }))
hl.bind(mainMod .. " + right", hl.dsp.focus({ direction = "right" }))
hl.bind(mainMod .. " + up",    hl.dsp.focus({ direction = "up" }))
hl.bind(mainMod .. " + down",  hl.dsp.focus({ direction = "down" }))

-- Switch workspaces with mainMod + [0-9]
-- Move active window to a workspace with mainMod + SHIFT + [0-9]
for i = 1, 10 do
    local key = i % 10 -- 10 maps to key 0
    hl.bind(mainMod .. " + " .. key,             hl.dsp.focus({ workspace = i}))
    hl.bind(mainMod .. " + SHIFT + " .. key,     hl.dsp.window.move({ workspace = i }))
end

-- Example special workspace (scratchpad)
hl.bind(mainMod .. " + S",         hl.dsp.workspace.toggle_special("magic"))
hl.bind(mainMod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:magic" }))

-- Scroll through existing workspaces with mainMod + scroll
hl.bind(mainMod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
hl.bind(mainMod .. " + mouse_up",   hl.dsp.focus({ workspace = "e-1" }))

-- Move/resize windows with mainMod + LMB/RMB and dragging
hl.bind(mainMod .. " + mouse:272", hl.dsp.window.drag(),   { mouse = true })
hl.bind(mainMod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })

-- Laptop multimedia keys for volume and LCD brightness
hl.bind("XF86AudioRaiseVolume", hl.dsp.exec_cmd("wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"), { locked = true, repeating = true })
hl.bind("XF86AudioLowerVolume", hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"),      { locked = true, repeating = true })
hl.bind("XF86AudioMute",        hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"),     { locked = true, repeating = true })
hl.bind("XF86AudioMicMute",     hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"),   { locked = true, repeating = true })
hl.bind("XF86MonBrightnessUp",  hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%+"),                  { locked = true, repeating = true })
hl.bind("XF86MonBrightnessDown",hl.dsp.exec_cmd("brightnessctl -e4 -n2 set 5%-"),                  { locked = true, repeating = true })

-- Requires playerctl
hl.bind("XF86AudioNext",  hl.dsp.exec_cmd("playerctl next"), { locked = true })
hl.bind("XF86AudioStop", hl.dsp.exec_cmd("playerctl stop"), { locked = true })
hl.bind("XF86AudioPlay",  hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
hl.bind("XF86AudioPrev",  hl.dsp.exec_cmd("playerctl previous"), { locked = true })

--------------------------------
---- WINDOWS AND WORKSPACES ----
--------------------------------

require("rules")

----------------------------
---- USER CONFIGURATION ----
----------------------------

require("user-config")

Maybe you can spot something in there that will help.

Doing a clean install isn’t a bad idea. I intend to do the same once I figure out what I’m going to use. Still contemplating a switch to Niri.

Thanks mate :slight_smile: I will have a look and see! Posted the same info on hyprland forums too, Niri might be interesting too, but if I can get Hyprland to work well, I will stay with it for the time being.

I believe I’ve found the issue.

local variables are truly local and it appears that they are not passed around the full require() environment.

So if I were to declare some local variables in defaults.lua and then call upon them in keybindings.lua, then the keybindings config would fail because it does not see what is set behind those variables.

Even setting the variables in the top level hyprland.lua did not allow them to pass through to the require() config files.

I fixed the issue by just moving all local declarations to the top of their relevant configuration files and this fixed the issue.

It’s an easy mistake for us to make.
A. This behavior is a regression from how we used hyprlang in hyprland.conf.
B. The Hyprland wiki does not inform users about this new behavior. In fact, the wiki implies that the old variable structure should still work when it implores us to make use of require() to break down the main file, as well as their example in the default config being require("myColors"). A colors file is nothing more than rounding up color variables.


Anyway, hope this helps. That should be the reason you’re seeing “bad argument”. The config sees terminal and has no idea what that means since it’s declared elsewhere.

Another fix would be to use global instead of local but I’m unsure what that word actually means in this context. If it’s “global throughout the Lua environment” then that would be fine since we’re working with a few kilobytes of files. I’m just wary of unnecessary performance hits.

I already made the switch to niri since hyprland config got changed too often with changes that brought config errors. I’ve got tired of having to tweak config every 2 or 3 updates. Niri is way more consistent (with less distraction).

I found the error, with help from Hyperland forums.

It was pretty simple really, the exec-cmd needs quotes around the literal, and I did not notice this, propably happened when copying from first line when migrating and editing in new variables..

hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(cachyos-pi))

–>

hl.bind(mainMod .. " + T", hl.dsp.exec_cmd(“cachyos-pi”))

That’s an easy mistake to make since the quotes aren’t used when the exec is a local variable.

For example:

local terminal = "alacritty"

hl.bind(mainMod .. " + RETURN", hl.dsp.exec_cmd(terminal))

hl.bind(mainMod .. " + N", hl.dsp.exec_cmd("qs -c noctalia-shell ipc call controlCenter toggle" ))

I should’ve caught that when I looked over yours. My bad.

No you have been super helpful mate! It would have helped if the lua-language-server reported the syntax error in the editor though, I assumed too much from the errors coming up :grinning_face_with_smiling_eyes:

Anyways, there are definitively need for som extra pointers towards common problems in the wiki, I guess that will come when enough people troubleshoot the same problems.

I also moved the local function to the top to avoid more problems!

No you have been super helpful mate! It would have helped if the lua-language-server reported the syntax error in the editor though, I assumed too much from the errors coming up :grinning_face_with_smiling_eyes:

Anyways, there are definitively need for som extra pointers towards common problems in the wiki, I guess that will come when enough people troubleshoot the same problems.

I also moved the local function to the top to avoid more problems!

Edit:

Actually, there are still problems.

Some lines with hl.dsp.exec.cmd is not supposed to have quotes but removing them gives me error message in hyprland and binds not working still.

Example:

hl.bind(mainMod .. " + E", hl.dsp.exec_cmd(fileManager))

this should actually be a valid line. Others use it from what I can see. I get the same string expected, got nil error.

If I use quotes, error disappears, but binds do not work.

Some others still work

hl.bind(mainMod .. " + SPACE", hl.dsp.exec_cmd(fileManager))

Ae there special rules for which entries must have quotes and are there relations from that to the startup programs?

Also, here your tip came handy. I had to move the locals from programs.lua into the binds.lua to make the keybinds work.

That now leaves three binds not working. Fullscreen. togglesplit and killactive.

The only one I really need is fullscreen. But even another syntax like this does not work, gives error:

hl.bind(mainMod .. " + F", hl.dsp.window.fullscreen({ mode = “fullscreen”, action = “toggle” }))

.. and of course, I now have a more messy setup, where I have duplicates of default programs :sweat_smile:

–> I think the problem you are talking about is the culprit for the most part here. Maybe again try like you did to have the binds in the main config together with default programs again.

I am seriously starting to evaluate niri myself. This is getting annoying :rofl:

Edit: yes, moving now, like you suggested earlier, after fixing the quotes, works. But must have both programs and binds in main config :+1:

The installation repo has been updated using the new hyprland.lua configuration.

The updated config:

I wanted to alter it as little as possible so it’s completely contained within one file without using require().

When I make the Hyprland Noctalia installation script I will be a little more hands-on in regard to how everything is set up.

Edit: It looks like Waybar’s Hyprland workspace module doesn’t work all that well with the Lua config quite yet. Might be worth sticking to .conf for the time being.