From fb5d6a47b9cf038435585c8b57230d5f0b48cbc7 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Wed, 13 May 2026 13:43:29 +0100 Subject: fix(waybar): use makoctl -f format for history picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The text-mode parser was looking for 'Notification N:' on a line by itself, but makoctl prints 'Notification N: ' with the summary inline — so every record was dropped and the picker came up empty. Switch to makoctl list/history -f '%i\t%a\t%s\t%b' which emits one clean tab-separated record per notification (mako >= 1.4). Multi-line bodies are folded back into the previous record. --- dot_config/waybar/executable_mako-history.py | 58 ++++++++++++---------------- 1 file changed, 25 insertions(+), 33 deletions(-) (limited to 'dot_config') diff --git a/dot_config/waybar/executable_mako-history.py b/dot_config/waybar/executable_mako-history.py index 9f4a50d..9bb8eea 100644 --- a/dot_config/waybar/executable_mako-history.py +++ b/dot_config/waybar/executable_mako-history.py @@ -17,50 +17,42 @@ import subprocess from pathlib import Path STATE = Path(os.environ.get("XDG_RUNTIME_DIR", "/tmp")) / "mako-dismissed" -RECORD_RE = re.compile(r"^Notification (\d+):\s*$") -FIELD_RE = re.compile(r"^ ([A-Za-z][A-Za-z ]*?):\s*(.*)$") -def _run_makoctl(subcmd: str) -> str: +def _run_makoctl_f(subcmd: str) -> list[dict]: + """Use makoctl -f to get one tab-separated record per notification. + + Body fields containing literal newlines spread across multiple lines; + we glue them back to the previous record. + """ try: - return subprocess.run( - ["makoctl", subcmd], capture_output=True, text=True, check=True + out = subprocess.run( + ["makoctl", subcmd, "-f", "%i\t%a\t%s\t%b"], + capture_output=True, text=True, check=True, ).stdout except (subprocess.CalledProcessError, FileNotFoundError): - return "" - - -def _parse_block(out: str) -> list[dict]: + return [] notifs: list[dict] = [] - cur: dict | None = None - last_field: str | None = None - for line in out.splitlines(): - m = RECORD_RE.match(line) - if m: - if cur is not None: - notifs.append(cur) - cur = {"id": int(m.group(1))} - last_field = None - continue - if cur is None: - continue - m = FIELD_RE.match(line) - if m: - key = m.group(1).strip().lower().replace(" ", "_") - cur[key] = m.group(2) - last_field = key - continue - if last_field == "body" and line.startswith(" "): - cur["body"] = (cur.get("body", "") + " " + line.strip()).strip() - if cur is not None: - notifs.append(cur) + for raw in out.splitlines(): + parts = raw.split("\t", 3) + if len(parts) == 4 and parts[0].isdigit(): + notifs.append( + { + "id": int(parts[0]), + "app_name": parts[1], + "summary": parts[2], + "body": parts[3], + } + ) + elif notifs: + notifs[-1]["body"] = (notifs[-1]["body"] + " " + raw).strip() return notifs def parse_history() -> list[dict]: """Return visible + history notifications, deduped by id, visible first.""" - visible = _parse_block(_run_makoctl("list")) - history = _parse_block(_run_makoctl("history")) + visible = _run_makoctl_f("list") + history = _run_makoctl_f("history") seen: set[int] = set() out: list[dict] = [] for n in visible + history: -- cgit v1.3.1