aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/dot_config/waybar
diff options
context:
space:
mode:
authorLibravatar sommerfeld <sommerfeld@sommerfeld.dev>2026-05-13 13:43:42 +0100
committerLibravatar sommerfeld <sommerfeld@sommerfeld.dev>2026-05-13 13:43:42 +0100
commit26ceab690dff09d5162443b14adccfbe0e9bcd5d (patch)
treeacfd10c910e1a73c47d4be118348163705dae57d /dot_config/waybar
parentae464450eb68fb154181823d059cf7124258ad2c (diff)
downloaddotfiles-26ceab690dff09d5162443b14adccfbe0e9bcd5d.tar.gz
dotfiles-26ceab690dff09d5162443b14adccfbe0e9bcd5d.tar.bz2
dotfiles-26ceab690dff09d5162443b14adccfbe0e9bcd5d.zip
refactor(notifications): drop dismissed-state machinery; pending = visible
Set mako default-timeout=0 so notifications stay until acted upon. With auto-timeout off, mako's list IS the pending set, so the $XDG_RUNTIME_DIR/mako-dismissed bridge becomes dead weight. - mako/config: default-timeout=0; drop redundant [urgency=critical] default-timeout=0 override. - Delete dismiss-visible.sh and restore-pending.sh; sway calls makoctl directly (Mod+n=dismiss, Mod+Shift+n=dismiss --all, Mod+Ctrl+n=restore as undo). - Shrink mako-status.sh to a 20-line counter of makoctl list. - Rename mako-history.py -> notification-picker.py; lists only visible, dismisses via makoctl dismiss -n <id>. - Update waybar config.jsonc on-click path. - Update KEYBINDS.md wording (no more 'marks seen' / 'pending set').
Diffstat (limited to 'dot_config/waybar')
-rw-r--r--dot_config/waybar/config.jsonc2
-rw-r--r--dot_config/waybar/executable_dismiss-visible.sh40
-rw-r--r--dot_config/waybar/executable_mako-status.sh55
-rw-r--r--dot_config/waybar/executable_notification-picker.py (renamed from dot_config/waybar/executable_mako-history.py)83
-rw-r--r--dot_config/waybar/executable_restore-pending.sh23
5 files changed, 22 insertions, 181 deletions
diff --git a/dot_config/waybar/config.jsonc b/dot_config/waybar/config.jsonc
index a5bada7..e5ea09b 100644
--- a/dot_config/waybar/config.jsonc
+++ b/dot_config/waybar/config.jsonc
@@ -209,7 +209,7 @@
"exec": "~/.config/waybar/mako-status.sh",
"return-type": "json",
"interval": 2,
- "on-click": "~/.config/waybar/mako-history.py",
+ "on-click": "~/.config/waybar/notification-picker.py",
"on-click-right": "makoctl dismiss --all",
"on-click-middle": "makoctl restore",
"tooltip": true,
diff --git a/dot_config/waybar/executable_dismiss-visible.sh b/dot_config/waybar/executable_dismiss-visible.sh
deleted file mode 100644
index 0f4f987..0000000
--- a/dot_config/waybar/executable_dismiss-visible.sh
+++ /dev/null
@@ -1,40 +0,0 @@
-#!/bin/sh
-# Dismiss currently-visible mako notifications and record their ids in the
-# shared "dismissed" set so they don't linger as pending in waybar.
-#
-# Usage: dismiss-visible.sh [top|all] (default: top)
-#
-# Coordinates with mako-status.sh and mako-history.py via
-# $XDG_RUNTIME_DIR/mako-dismissed (one id per line, per-session).
-
-set -eu
-
-mode=${1:-top}
-state=${XDG_RUNTIME_DIR:-/tmp}/mako-dismissed
-mkdir -p "$(dirname "$state")"
-: >>"$state"
-
-command -v makoctl >/dev/null 2>&1 || exit 0
-
-# This makoctl has no -f; extract ids from the text dump.
-list_ids() {
- makoctl list 2>/dev/null |
- sed -n 's/^Notification \([0-9][0-9]*\):.*/\1/p'
-}
-
-case "$mode" in
- top)
- id=$(list_ids | head -n1 || true)
- [ -n "${id:-}" ] && printf '%s\n' "$id" >>"$state"
- makoctl dismiss
- ;;
- all)
- list_ids >>"$state" || true
- makoctl history 2>/dev/null | sed -n 's/^Notification \([0-9][0-9]*\):.*/\1/p' >>"$state" || true
- makoctl dismiss --all
- ;;
- *)
- echo "usage: $0 [top|all]" >&2
- exit 2
- ;;
-esac
diff --git a/dot_config/waybar/executable_mako-status.sh b/dot_config/waybar/executable_mako-status.sh
index 12e4d82..4e9f053 100644
--- a/dot_config/waybar/executable_mako-status.sh
+++ b/dot_config/waybar/executable_mako-status.sh
@@ -1,56 +1,21 @@
#!/bin/sh
-# Waybar status: count of *pending* notifications, where pending = ids in
-# mako's history/list that have NOT been explicitly dismissed by the user
-# via Mod+n / Mod+Shift+n / the history picker.
-#
-# State file: $XDG_RUNTIME_DIR/mako-dismissed (per-session, plain id list).
+# Waybar status: count of currently-visible mako notifications. With
+# default-timeout=0 in mako/config, "visible" == "pending"; once a
+# notification is dismissed it's gone and never comes back.
set -eu
if ! command -v makoctl >/dev/null 2>&1; then
- printf '{"text":"","tooltip":"mako not installed","class":"off"}
-'
+ printf '{"text":"","tooltip":"mako not installed","class":"off"}\n'
exit 0
fi
-state=${XDG_RUNTIME_DIR:-/tmp}/mako-dismissed
-: >>"$state"
+count=$(makoctl list 2>/dev/null |
+ grep -c '^Notification [0-9][0-9]*:' || true)
-# This makoctl has no -f flag; parse the text dump. Each notification
-# starts with "Notification N: <summary>". Visible bubbles live in
-# `list`, closed ones in `history`; their id-spaces are disjoint.
-extract_ids() {
- makoctl "$1" 2>/dev/null |
- sed -n 's/^Notification \([0-9][0-9]*\):.*/\1/p'
-}
-
-all_ids=$({
- extract_ids list
- extract_ids history
-} | sort -un)
-
-# Prune stale ids (no longer present in mako) from the dismissed file.
-if [ -s "$state" ] && [ -n "$all_ids" ]; then
- tmp=$(mktemp)
- printf '%s
-' "$all_ids" >"$tmp.all"
- grep -Fxf "$tmp.all" "$state" >"$tmp" 2>/dev/null || :
- mv "$tmp" "$state"
- rm -f "$tmp.all"
-fi
-
-if [ -z "$all_ids" ]; then
- pending=0
-else
- pending=$(printf '%s
-' "$all_ids" | grep -Fxvf "$state" | grep -c . || true)
-fi
-
-if [ "$pending" -gt 0 ]; then
- printf '{"text":"󰂞 %s","tooltip":"%s pending","class":"pending"}
-' \
- "$pending" "$pending"
+if [ "$count" -gt 0 ]; then
+ printf '{"text":"󰂞 %s","tooltip":"%s pending","class":"pending"}\n' \
+ "$count" "$count"
else
- printf '{"text":"󰂜","tooltip":"no pending notifications","class":"empty"}
-'
+ printf '{"text":"󰂜","tooltip":"no pending notifications","class":"empty"}\n'
fi
diff --git a/dot_config/waybar/executable_mako-history.py b/dot_config/waybar/executable_notification-picker.py
index a8104f7..e6d6aed 100644
--- a/dot_config/waybar/executable_mako-history.py
+++ b/dot_config/waybar/executable_notification-picker.py
@@ -1,53 +1,30 @@
#!/usr/bin/env python3
-"""Notification history picker.
+"""Notification picker.
-Lists pending mako notifications (visible bubbles + history). Entries
-dismissed via this picker are hidden so the list shrinks as you process it.
-The picker re-opens after each selection so multiple notifications can be
-processed in one go; Esc closes it.
-
-Keys:
- Enter copy "summary\\nbody" to the clipboard, dismiss the entry, reopen
- Esc close the picker
-
-State file: $XDG_RUNTIME_DIR/mako-dismissed (one id per line, per-session).
+Lists currently-visible mako notifications. Selecting one copies its
+"summary\\nbody" to the clipboard and dismisses it via `makoctl dismiss
+-n <id>`. The picker re-opens after each selection so multiple
+notifications can be processed in one go; Esc closes it.
"""
from __future__ import annotations
-import os
import re
import subprocess
from pathlib import Path
from typing import Any
-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 list_notifications() -> list[dict[str, Any]]:
try:
- return subprocess.run(
- ["makoctl", subcmd], capture_output=True, text=True, check=True
+ out = subprocess.run(
+ ["makoctl", "list"], capture_output=True, text=True, check=True
).stdout
except (subprocess.CalledProcessError, FileNotFoundError):
- return ""
-
-
-def _parse_block(out: str) -> list[dict[str, Any]]:
- """Parse mako's text dump.
-
- Format (per notification):
- Notification N: <summary>
- App name: <app>
- [Category: <cat>]
- [Body: <body line>]
- [ <body cont>]
- Urgency: <urgency>
- """
+ return []
notifs: list[dict[str, Any]] = []
cur: dict[str, Any] | None = None
last_field: str | None = None
@@ -74,48 +51,12 @@ def _parse_block(out: str) -> list[dict[str, Any]]:
return notifs
-def parse_history(dismissed: set[str]) -> list[dict[str, Any]]:
- """Return visible + history notifications, deduped by id, visible first.
-
- Entries whose id is in `dismissed` are filtered out.
- """
- visible = _parse_block(_run_makoctl("list"))
- history = _parse_block(_run_makoctl("history"))
- seen: set[int] = set()
- out: list[dict[str, Any]] = []
- for n in visible + history:
- nid = int(n["id"])
- if nid in seen or str(nid) in dismissed:
- continue
- seen.add(nid)
- out.append(n)
- return out
-
-
-def load_dismissed() -> set[str]:
- STATE.parent.mkdir(parents=True, exist_ok=True)
- STATE.touch(exist_ok=True)
- return {x for x in STATE.read_text().split() if x}
-
-
-def save_dismissed(ids: set[str]) -> None:
- payload = "\n".join(sorted(ids, key=lambda s: int(s) if s.isdigit() else 0))
- _ = STATE.write_text(payload + ("\n" if ids else ""))
-
-
-def add_dismissed(nid: int) -> None:
- ids = load_dismissed()
- ids.add(str(nid))
- save_dismissed(ids)
-
-
def fmt_line(n: dict[str, Any]) -> str:
app = (str(n.get("app_name") or "?")).strip() or "?"
summary = str(n.get("summary") or "").strip()
body = str(n.get("body") or "").strip()
text = summary if not body else f"{summary} — {body}"
text = text.replace("\t", " ").replace("\r", " ")
- # Trailing id sentinel for parsing on selection.
return f"[{app}] {text}\t#{n['id']}"
@@ -145,9 +86,7 @@ def run_wofi(input_text: str, lines: int) -> str:
def main() -> None:
while True:
- dismissed = load_dismissed()
- notifs = parse_history(dismissed)
-
+ notifs = list_notifications()
if not notifs:
_ = run_wofi("(no notifications)\n", 1)
return
@@ -168,7 +107,7 @@ def main() -> None:
body = str(notif.get("body") or "").strip()
clip_text = f"{summary}\n{body}".strip()
_ = subprocess.run(["wl-copy"], input=clip_text, text=True, check=False)
- add_dismissed(nid)
+ _ = subprocess.run(["makoctl", "dismiss", "-n", str(nid)], check=False)
if __name__ == "__main__":
diff --git a/dot_config/waybar/executable_restore-pending.sh b/dot_config/waybar/executable_restore-pending.sh
deleted file mode 100644
index 3a08c4f..0000000
--- a/dot_config/waybar/executable_restore-pending.sh
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-# Restore the most recently closed mako notification and remove its id
-# from the dismissed-set so it counts as pending again.
-
-set -eu
-
-state=${XDG_RUNTIME_DIR:-/tmp}/mako-dismissed
-: >>"$state"
-
-command -v makoctl >/dev/null 2>&1 || exit 0
-
-# mako's history is most-recent-first; the next restore() target is the
-# top of the list at the time of the call.
-top_id=$(makoctl history 2>/dev/null |
- sed -n 's/^Notification \([0-9][0-9]*\):.*/\1/p' |
- head -n1 || true)
-makoctl restore || true
-
-if [ -n "${top_id:-}" ] && [ -s "$state" ]; then
- tmp=$(mktemp)
- grep -Fxv "$top_id" "$state" >"$tmp" || :
- mv "$tmp" "$state"
-fi