feat(nix): title_rule asserts what kfw does: a rule decides when a window opens

This commit is contained in:
LGUG2Z committed 2026-10-30 14:12:15 -07:00
1 parent 84080f879e
commit 3830bb27e9
3 files changed
+33 -27

No files matched your search

@@ -1,48 +1,54 @@
"""A rule that matches a title decides when the window has its title."""
"""A rule decides when a window opens: a title change later does not make the daemon look again."""
from komorebi_vm.core.checks import Checks
from komorebi_vm.core.platform import Client, Platform
from komorebi_vm.core.scenarios.support import QUIET
PENDING = "pending-rule"
RENAMED = "renamed-rule"
MANAGED = "managed-before"
MANAGED_RENAMED = "managed-after"
AFTER = 6
def run(platform: Platform, checks: Checks) -> None:
"""A window that opens with a title the ignore rule matches is left alone, and tiled once it
gives itself another title.
"""A window that opens with a title an ignore rule matches is left alone, and stays so when it
gives itself another title; a window that is managed stays managed when it renames itself.
The daemon runs with its windows tiled; the window is closed at the end, and the rule stays.
The daemon runs with its windows tiled; the windows are closed at the end, and the rule stays.
"""
platform.komorebic("ignore-rule", "title", PENDING)
before = platform.state().managed()
# the window renames itself after the daemon has had time to decide about the first title
platform.spawn(PENDING, rename_to=RENAMED, after=6)
platform.spawn(PENDING, rename_to=RENAMED, after=AFTER)
renamed = Client(RENAMED)
checks.check(
"a window the ignore rule matches by its title is left alone",
not platform.wait_for(lambda: platform.state().managed() != before, timeout=2)
and platform.os_window(Client(PENDING)) is not None,
platform.state().workspace_of(PENDING) is None and platform.state().managed() == before,
)
checks.check(
"once it has a title the rule does not match, it is tiled",
platform.wait_for(
lambda: (
platform.os_window(renamed) is not None and platform.state().managed() == before + 1
),
timeout=30,
),
"it gives itself another title",
platform.wait_for(lambda: platform.os_window(renamed) is not None, timeout=30),
)
window = platform.os_window(renamed)
checks.check(
"... and inside the work area",
window is not None and window.frame.inside(platform.work_area(), 2),
"... and the daemon leaves it alone: a rule decides when a window opens",
not platform.wait_for(lambda: platform.state().managed() != before, timeout=QUIET),
)
platform.close(renamed)
platform.wait_for(lambda: platform.os_window(renamed) is None, timeout=10)
platform.spawn(MANAGED, rename_to=MANAGED_RENAMED, after=AFTER)
kept = Client(MANAGED_RENAMED)
checks.check(
"a window that is managed when it renames itself stays managed",
platform.wait_for(lambda: platform.os_window(kept) is not None, timeout=30)
and platform.wait_for(lambda: platform.state().managed() == before + 1, timeout=10),
)
platform.close(kept)
checks.check(
"closed, it leaves the daemon",
platform.wait_for(
lambda: platform.os_window(renamed) is None and platform.state().managed() == before,
lambda: platform.os_window(kept) is None and platform.state().managed() == before,
timeout=10,
),
)
+3 -3
View File
@@ -78,7 +78,7 @@ class FakePlatform:
panel: int = 0,
ignores_panel: bool = False,
second: Rect | None = None,
follows_renames: bool = True,
reevaluates_on_rename: bool = False,
honours_ignore: bool = True,
unmanages: bool = True,
manages: bool = True,
@@ -131,7 +131,7 @@ class FakePlatform:
self.manages = manages
self.let_go: list[str] = []
"""The windows `unmanage` let go of, the last one at the end."""
self.follows_renames = follows_renames
self.reevaluates_on_rename = reevaluates_on_rename
self.honours_ignore = honours_ignore
self.clock = 0.0
self.renames: list[tuple[float, str, str]] = []
@@ -253,7 +253,7 @@ class FakePlatform:
for table in (self.exes, self.classes):
if old in table:
table[new] = table.pop(old)
if old not in self.unmanaged or not self.follows_renames:
if old not in self.unmanaged or not self.reevaluates_on_rename:
for stack in [s for cs in self.spaces for s in cs]:
stack[:] = [new if t == old else t for t in stack]
self.unmanaged[:] = [new if t == old else t for t in self.unmanaged]
+5 -5
View File
@@ -27,14 +27,14 @@ def opened(platform: FakePlatform, checks: Checks): # noqa: ANN201
return tiling.run(platform, checks)
def test_a_daemon_that_follows_a_rename_passes_title_rule() -> None:
def test_a_daemon_that_does_not_look_again_at_a_renamed_window_passes_title_rule() -> None:
platform = FakePlatform()
checks = Checks()
opened(platform, checks)
base = checks.passed
title_rule.run(platform, checks)
assert checks.failed == 0, checks.failures
assert checks.passed - base == 4
assert checks.passed - base == 5
def test_a_daemon_that_manages_an_ignored_title_fails_title_rule() -> None:
@@ -45,12 +45,12 @@ def test_a_daemon_that_manages_an_ignored_title_fails_title_rule() -> None:
assert any("left alone" in f for f in checks.failures)
def test_a_daemon_that_misses_the_rename_fails_title_rule() -> None:
platform = FakePlatform(follows_renames=False)
def test_a_daemon_that_looks_again_at_a_renamed_window_fails_title_rule() -> None:
platform = FakePlatform(reevaluates_on_rename=True)
checks = Checks()
opened(platform, checks)
title_rule.run(platform, checks)
assert any("it is tiled" in f for f in checks.failures)
assert any("leaves it alone" in f for f in checks.failures)
def test_a_daemon_that_lets_go_and_takes_up_again_passes_handover() -> None: