aboutsummaryrefslogtreecommitdiff
path: root/working/hyprland-lua-port/reader-changes-for-lua.patch
diff options
context:
space:
mode:
Diffstat (limited to 'working/hyprland-lua-port/reader-changes-for-lua.patch')
-rw-r--r--working/hyprland-lua-port/reader-changes-for-lua.patch241
1 files changed, 241 insertions, 0 deletions
diff --git a/working/hyprland-lua-port/reader-changes-for-lua.patch b/working/hyprland-lua-port/reader-changes-for-lua.patch
new file mode 100644
index 0000000..747b047
--- /dev/null
+++ b/working/hyprland-lua-port/reader-changes-for-lua.patch
@@ -0,0 +1,241 @@
+diff --git a/common/.local/bin/dotfiles-validate b/common/.local/bin/dotfiles-validate
+index 57a7505..d5e6695 100755
+--- a/common/.local/bin/dotfiles-validate
++++ b/common/.local/bin/dotfiles-validate
+@@ -3,6 +3,7 @@
+ #
+ # Walks the tree and extracts the commands that configs promise to launch:
+ # - hypr conf files: exec-once = CMD / exec = CMD / bind* = ..., exec, CMD
++# - hypr lua configs: at_start/at_shutdown/at_reload("CMD"), exec_cmd("CMD")
+ # - waybar config: "exec(-if)", "on-click*", "on-scroll-*",
+ # "on-double-click" values
+ # - systemd user units: Exec*= lines (leading -/@ modifiers stripped)
+@@ -45,6 +46,30 @@ find "$root" -path '*/.config/hypr/*.conf' -type f 2>/dev/null | while read -r f
+ ' "$f"
+ done >> "$refs_file"
+
++# --- hypr lua configs: autostart collectors and exec_cmd dispatchers ---
++# The Lua config manager (Hyprland 0.55+) spells the same two things as function
++# calls rather than assignments, so the .conf walk above sees none of them. Only
++# the first word is taken, as everywhere else here. The two matches are written
++# out rather than folded into a helper: awk cannot take a regex literal as a
++# function parameter -- it collapses to a boolean match against $0, which
++# silently turns every line into a bogus reference.
++find "$root" -path '*/.config/hypr/*.lua' -type f 2>/dev/null | while read -r f; do
++ awk -v file="$f" '
++ match($0, /at_(start|shutdown|reload)\("/) {
++ rest = substr($0, RSTART + RLENGTH)
++ sub(/".*$/, "", rest)
++ n = split(rest, w, /[ \t]+/)
++ if (n > 0 && w[1] != "") print file ":" FNR ":" w[1]
++ }
++ match($0, /hl\.dsp\.exec_cmd\("/) {
++ rest = substr($0, RSTART + RLENGTH)
++ sub(/".*$/, "", rest)
++ n = split(rest, w, /[ \t]+/)
++ if (n > 0 && w[1] != "") print file ":" FNR ":" w[1]
++ }
++ ' "$f"
++done >> "$refs_file"
++
+ # --- waybar configs: command-bearing JSON values ---
+ find "$root" -path '*/.config/waybar/*' -type f \( -name config -o -name '*.json' -o -name '*.jsonc' \) 2>/dev/null | while read -r f; do
+ awk -v file="$f" '
+diff --git a/tests/layout-cycle/test_layout_cycle.py b/tests/layout-cycle/test_layout_cycle.py
+index 1454817..3740024 100644
+--- a/tests/layout-cycle/test_layout_cycle.py
++++ b/tests/layout-cycle/test_layout_cycle.py
+@@ -18,6 +18,7 @@ Run from repo root:
+
+ import json
+ import os
++import re
+ import subprocess
+ import tempfile
+ import unittest
+@@ -25,7 +26,7 @@ import unittest
+ REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+ SCRIPT = os.path.join(REPO_ROOT, "hyprland/.local/bin/layout-cycle")
+ FAKE_HYPRCTL = os.path.join(os.path.dirname(__file__), "fake-hyprctl")
+-HYPRLAND_CONF = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.conf")
++HYPRLAND_CFG = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.lua")
+
+ FLASH = "rgba(ffd24aff)"
+ ACTIVE = "rgba(daa520ff)"
+@@ -326,7 +327,7 @@ class TestFlashAllBorders(LayoutCycleHarness):
+
+
+ class TestScrollLayoutDisabledInConfig(unittest.TestCase):
+- """Pin the hyprland.conf half of the scrolling disable.
++ """Pin the hyprland.lua half of the scrolling disable.
+
+ The script tests above prove the ring skips scrolling; these prove no
+ keybinding reaches it either, and that the freed Super+Shift+S chord
+@@ -335,10 +336,20 @@ class TestScrollLayoutDisabledInConfig(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+- with open(HYPRLAND_CONF) as f:
++ with open(HYPRLAND_CFG) as f:
+ cls.conf = f.read()
++ # Every bind in the Lua config is a top-level hl.bind() call; the
++ # locked/mouse/repeat variants that hyprlang spelled bindl/bindm/binde
++ # are the same call with an options table, so one prefix covers them.
+ cls.binds = [l for l in cls.conf.splitlines()
+- if l.strip().startswith(("bind", "bindl", "bindm"))]
++ if l.strip().startswith("hl.bind")]
++
++ def test_the_binds_were_actually_found(self):
++ """Guard the guard: a renamed call would empty the list and make both
++ assertions below pass against nothing."""
++ self.assertGreater(len(self.binds), 50,
++ "found almost no hl.bind lines -- the two assertions "
++ "below would pass vacuously")
+
+ def test_no_bind_selects_scrolling_layout(self):
+ offenders = [l for l in self.binds if "general:layout scrolling" in l]
+@@ -346,7 +357,7 @@ class TestScrollLayoutDisabledInConfig(unittest.TestCase):
+
+ def test_super_shift_s_is_fullscreen_screenshot(self):
+ shift_s = [l for l in self.binds
+- if "$mod SHIFT, S," in l]
++ if re.search(r'\bmod\s*\.\.\s*"\s*\+\s*SHIFT\s*\+\s*S"', l)]
+ self.assertEqual(len(shift_s), 1, msg=f"binds found: {shift_s}")
+ self.assertIn("screenshot fullscreen", shift_s[0])
+
+diff --git a/tests/settings/test_session_restore.py b/tests/settings/test_session_restore.py
+index a989d52..b2a2721 100644
+--- a/tests/settings/test_session_restore.py
++++ b/tests/settings/test_session_restore.py
+@@ -585,12 +585,32 @@ class TestCompositorWiring(unittest.TestCase):
+ script and passing tests while never being placed in the bar.
+ """
+
+- CONF = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.conf")
++ CONF = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.lua")
+
+ def _lines(self):
++ """The autostart commands, in launch order.
++
++ The Lua config collects startup commands with at_start("CMD") and one
++ hl.on("hyprland.start") handler at the bottom replays the list in order,
++ so position in this file is still position at launch -- which is what
++ the ordering assertion below reads. Returning the command strings rather
++ than raw lines means every entry here is by construction an autostart
++ command, so the old startswith("exec-once") filter has nothing left to do.
++ """
++ out = []
+ with open(self.CONF) as f:
+- return [ln.strip() for ln in f
+- if ln.strip() and not ln.strip().startswith("#")]
++ for ln in f:
++ m = re.search(r'at_start\("(.*)"\)', ln.strip())
++ if m:
++ out.append(m.group(1))
++ return out
++
++ def test_the_autostart_commands_were_actually_found(self):
++ """Guard the guard: a renamed collector would empty the list and make
++ every assertion below pass against nothing."""
++ self.assertGreater(len(self._lines()), 10,
++ "found almost no at_start commands -- the assertions "
++ "below would pass vacuously")
+
+ @staticmethod
+ def _is_toggle_restore(line):
+@@ -607,22 +627,19 @@ class TestCompositorWiring(unittest.TestCase):
+
+ def test_restore_runs_at_session_start(self):
+ self.assertTrue(
+- any(ln.startswith("exec-once") and self._is_toggle_restore(ln)
+- for ln in self._lines()),
+- "hyprland.conf has no exec-once running `settings restore` — "
++ any(self._is_toggle_restore(ln) for ln in self._lines()),
++ "hyprland.lua has no at_start running `settings restore` — "
+ "remembered toggles would never be replayed")
+
+ def test_wallpaper_restore_runs_at_session_start(self):
+ self.assertTrue(
+- any(ln.startswith("exec-once") and "settings restore-wallpaper" in ln
+- for ln in self._lines()),
+- "hyprland.conf has no exec-once running `settings restore-wallpaper` "
++ any("settings restore-wallpaper" in ln for ln in self._lines()),
++ "hyprland.lua has no at_start running `settings restore-wallpaper` "
+ "— the stored wallpaper would never be put back")
+
+ def test_the_toggle_restore_runs_only_once(self):
+ """Twice means the whole re-assert budget is spent twice per login."""
+- lines = [ln for ln in self._lines()
+- if ln.startswith("exec-once") and self._is_toggle_restore(ln)]
++ lines = [ln for ln in self._lines() if self._is_toggle_restore(ln)]
+ self.assertEqual(len(lines), 1, lines)
+
+ def test_restore_is_ordered_after_the_backings_it_corrects(self):
+@@ -631,17 +648,15 @@ class TestCompositorWiring(unittest.TestCase):
+ # burn attempts on backings that aren't up yet.
+ lines = self._lines()
+ restore = next(i for i, ln in enumerate(lines)
+- if ln.startswith("exec-once")
+- and self._is_toggle_restore(ln))
++ if self._is_toggle_restore(ln))
+ for backing in ("hypridle", "dunst"):
+- launch = next(i for i, ln in enumerate(lines)
+- if ln.startswith("exec-once") and backing in ln)
++ launch = next(i for i, ln in enumerate(lines) if backing in ln)
+ self.assertLess(launch, restore,
+ f"`settings restore` is ordered before {backing}")
+
+
+ class DimEnv(TempEnv):
+- """Adds the hyprctl fake, whose dim default is 1 -- as hyprland.conf's is."""
++ """Adds the hyprctl fake, whose dim default is 1 -- as hyprland.lua's is."""
+
+ def setUp(self):
+ super().setUp()
+diff --git a/tests/waybar-reserve/test_reserve_pairing.py b/tests/waybar-reserve/test_reserve_pairing.py
+index 7421692..fbeb95d 100644
+--- a/tests/waybar-reserve/test_reserve_pairing.py
++++ b/tests/waybar-reserve/test_reserve_pairing.py
+@@ -26,7 +26,7 @@ import unittest
+
+ REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+ WAYBAR = os.path.join(REPO_ROOT, "hyprland/.config/waybar/config")
+-HYPR = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.conf")
++HYPR = os.path.join(REPO_ROOT, "hyprland/.config/hypr/hyprland.lua")
+
+
+ def waybar_config():
+@@ -35,13 +35,19 @@ def waybar_config():
+
+
+ def reserve_exec_wired():
+- """True when hyprland.conf runs waybar-reserve via exec (not exec-once).
++ """True when the config re-runs waybar-reserve on every config reload.
+
+- Matches waybar-reserve invoked anywhere in an ``exec =`` line, so the
+- reload-race-safe retry-loop form (``exec = for i in 1 2 3; do sleep 0.2;
+- waybar-reserve; done``) counts the same as a bare ``exec = waybar-reserve``."""
++ Matches waybar-reserve invoked anywhere in an ``at_reload(...)`` line, so the
++ reload-race-safe retry-loop form (``at_reload("for i in 1 2 3; do sleep 0.2;
++ waybar-reserve; done")``) counts the same as a bare ``at_reload("waybar-reserve")``.
++
++ at_reload and not at_start, because hyprlang's ``exec`` ran at startup AND on
++ every reload, and the Lua port splits those two jobs. at_reload's handler is
++ ``hl.on("config.reloaded")``, which fires on the initial load as well, so it
++ alone covers both. Matching at_start instead would pass while reservations
++ died on the next reload -- which is exactly the defect this guards."""
+ with open(HYPR) as f:
+- return any(re.match(r"\s*exec\s*=.*\bwaybar-reserve\b", ln) for ln in f)
++ return any(re.match(r'\s*at_reload\(".*\bwaybar-reserve\b', ln) for ln in f)
+
+
+ def reserve_target():
+@@ -61,7 +67,7 @@ class ReservePairingHarness(unittest.TestCase):
+
+ def test_hyprland_wires_the_reserve_script(self):
+ self.assertTrue(reserve_exec_wired(),
+- "hyprland.conf lacks `exec = waybar-reserve`: reservations "
++ "hyprland.lua lacks `at_reload(... waybar-reserve ...)`: reservations "
+ "die on the next config reload")
+
+ def test_reserve_target_covers_the_bar(self):