#!/bin/bash # # Copyright (C) 2026 Danilo M. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # Waybar custom module in continuous mode: prints one JSON line per notmuch # commit, forever, and waybar redraws on each line. Waybar owns this process, # which is why there is no daemon to supervise and no interval to tune. # # The count is the total across every account. A per account breakdown is the # drawer's job; see mail-overview/README.md. set -u QUERY='tag:unread and tag:inbox' # notmuch knows where its own database is, so this follows a moved database # without an edit here. db="$(notmuch config get database.path 2>/dev/null)/xapian" emit() { local n n="$(notmuch count "$QUERY" 2>/dev/null)" # The output is the test, not the exit status. notmuch fails two different # ways: a rejected query prints nothing and exits 1, while a query Xapian # merely misparses ('tag:unread and ((') returns a plausible wrong number # and exits 0. Only the first is detectable, and it is the one that matters # here, because empty output would otherwise render as "no new mail". The # second is why QUERY is a fixed string and not built from anything. if [[ ! "$n" =~ ^[0-9]+$ ]]; then printf '{"text":"!","tooltip":"notmuch count failed","class":"error"}\n' return fi if [[ "$n" -eq 0 ]]; then printf '{"text":"","class":"empty"}\n' else printf '{"text":"%s","class":"unread"}\n' "$n" fi } if [[ ! -d "$db" ]]; then printf '{"text":"!","tooltip":"no notmuch database","class":"error"}\n' exit 1 fi emit while inotifywait -qq -e close_write,moved_to "$db" 2>/dev/null; do # One commit touches several files. Without this the module redraws three # or four times per sync with intermediate counts. sleep 0.3 emit done # Falling out of the loop means inotifywait itself failed. Say so rather than # exiting silently, which looks like an empty inbox. printf '{"text":"!","tooltip":"mail watcher stopped","class":"error"}\n' exit 1