From 5b8b959cd18e75b67f7b3cd0ea2b8b24b1f41952 Mon Sep 17 00:00:00 2001 From: sommerfeld Date: Wed, 13 May 2026 13:43:29 +0100 Subject: fix(waybar): parse real makoctl text format (no -f support) This makoctl version doesn't accept -f. Drop that path and parse the actual text dump: Notification N: <- summary on the same line App name: [Category: ] [Body: ...] <- absent on this version, kept anyway Urgency: Verified against the user's pasted output. --- dot_config/waybar/executable_mako-history.py | 68 ++++++++++++++++++---------- 1 file changed, 44 insertions(+), 24 deletions(-) (limited to 'dot_config/waybar/executable_mako-history.py') diff --git a/dot_config/waybar/executable_mako-history.py b/dot_config/waybar/executable_mako-history.py index 9bb8eea..89618d0 100644 --- a/dot_config/waybar/executable_mako-history.py +++ b/dot_config/waybar/executable_mako-history.py @@ -19,40 +19,60 @@ from pathlib import Path STATE = Path(os.environ.get("XDG_RUNTIME_DIR", "/tmp")) / "mako-dismissed" -def _run_makoctl_f(subcmd: str) -> list[dict]: - """Use makoctl -f to get one tab-separated record per notification. +RECORD_RE = re.compile(r"^Notification (\d+):\s?(.*)$") +FIELD_RE = re.compile(r"^ ([A-Za-z][A-Za-z ]*?):\s*(.*)$") - Body fields containing literal newlines spread across multiple lines; - we glue them back to the previous record. - """ + +def _run_makoctl(subcmd: str) -> str: try: - out = subprocess.run( - ["makoctl", subcmd, "-f", "%i\t%a\t%s\t%b"], - capture_output=True, text=True, check=True, + return subprocess.run( + ["makoctl", subcmd], capture_output=True, text=True, check=True ).stdout except (subprocess.CalledProcessError, FileNotFoundError): - return [] + return "" + + +def _parse_block(out: str) -> list[dict]: + """Parse mako's text dump. + + Format (per notification): + Notification N: + App name: + [Category: ] + [Body: ] + [ ] + Urgency: + """ notifs: list[dict] = [] - 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() + 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)), "summary": m.group(2).strip()} + last_field = "summary" + 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) return notifs def parse_history() -> list[dict]: """Return visible + history notifications, deduped by id, visible first.""" - visible = _run_makoctl_f("list") - history = _run_makoctl_f("history") + visible = _parse_block(_run_makoctl("list")) + history = _parse_block(_run_makoctl("history")) seen: set[int] = set() out: list[dict] = [] for n in visible + history: -- cgit v1.3.1