aboutsummaryrefslogtreecommitdiff
Commit message (Collapse)AuthorAgeFilesLines
* timer.1: document how to run hooks selectivelyHEADmainLukasz Kasprzak2026-08-252-1/+61
| | | | | | | | | | | | | | | | | | | | | | | Hooks are all-or-nothing per user: a file is installed or it is not, and there is no per-run flag. That the gate belongs inside the hook, and what it has to gate on, was only discoverable by reading the source. A hook inherits the environment timer was run with and is handed the -c comment as $3, so three gates are available: an environment variable for explicit opt-in, a +tag in the comment (free if you already pass -c, and still visible to timer --stats), or the session itself via $1 and $2 -- countdowns over ten minutes, say -- which needs nothing remembered. Also records the asymmetry that is easy to get wrong: gate on_start only. A hook that undoes something must run unconditionally in on_done and on_quit, or a session ending without the gate set leaves notifications paused or music stopped. Restore paths are harmless when there was nothing to restore. The shipped on_start now points at the new section, so the trick is visible from the file someone is already editing. Claude-Session: https://claude.ai/code/session_01APLBs8RB1FcUaC4viVkzbP
* hooks: replace the examples with ones that do what the binary cannotLukasz Kasprzak2026-08-255-56/+120
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The previous examples largely duplicated features of the patched build. on_done sent a desktop notification and played a sound, both of which the notify patch already does, so a user who copied it got two of each. on_quit recorded abandoned sessions, but the logging patch calls write_log() unconditionally at the end of every run: abandoned sessions were already in the log behind timer -r. The new set does two things nothing else can: - Intent versus outcome. The log stores elapsed seconds only, so a finished 25m and an abandoned 30m that ran 25m are indistinguishable in it. The duration actually requested is visible to on_start and nowhere else, so the examples write START/DONE/QUIT records to $XDG_STATE_HOME/ttym/sessions.tsv. - Focus mode. During a countdown, pause dunst notifications and any playerctl/mpc playback; restore on done or quit. Countdown only, so a stopwatch cannot silence notifications indefinitely. A timewarrior bridge is included but commented out. Two behaviours documented in the file comments, both read off the code rather than assumed: notify_and_sound() runs before the on_done hook, so with dunst paused the completion popup is queued and appears when the hook unpauses -- delayed, not lost; and nothing restores dunst if the process is killed with -9. Every external command is guarded with command -v, so the examples degrade to the session record alone on a machine without those tools. Each hook works standalone -- the man page and README now say so explicitly, since installing only on_quit is a normal setup. All three pass sh -n and shellcheck, and were tested across all three paths: completed countdown, abandoned countdown, stopped stopwatch, with dunstctl is-paused confirmed false afterwards. Claude-Session: https://claude.ai/code/session_01APLBs8RB1FcUaC4viVkzbP
* hooks: ship three commented examples, install them, document the contractLukasz Kasprzak2026-08-256-12/+197
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Add hooks/on_start, hooks/on_done and hooks/on_quit. They are named after the hooks themselves so copying one into ~/.config/ttym/hooks/ is the entire installation step, and each carries its argument contract in a header comment. on_start sets the terminal window title to what is running on_done desktop notification plus a sound, both backgrounded, with the first available of paplay/aplay/mpv/ffplay on_quit records abandoned sessions to a TSV under XDG_STATE_HOME and restores the terminal title make install places them in PREFIX/share/doc/ttym/hooks; make uninstall removes them and both directories; make dist ships hooks/ with the executable bits intact. The man page's HOOKS section now documents what the code actually does rather than what could be assumed from the call sites: - $2 differs per hook: requested duration on on_start, full duration on on_done, and time actually elapsed -- excluding time spent paused -- on on_quit. An abandoned 25m countdown reports what really ran. - $3 is always passed, so it is never unset. - hooks block: timer forks and waitpid()s, so on_done delays the completion bell and the alert loop. Background anything slow. - stdin, stdout and stderr all go to /dev/null, which is why printing is pointless and cannot corrupt the redrawn progress line. - execvp(3) means a script needs a #! line. README gains a Hooks section. All three examples pass sh -n and shellcheck, and were tested end to end through the documented flow: make install to a staging prefix, copy into a config dir, run. Claude-Session: https://claude.ai/code/session_01APLBs8RB1FcUaC4viVkzbP
* patches: drop generated config.h and binary sections from the diffsLukasz Kasprzak2026-08-255-111/+18
| | | | | | | | | | | | | | | | | | | | | | | The 3.0 patch files each carried a spurious diff section for config.h -- a file the Makefile generates from config.def.h -- plus "Binary files a/timer and b/timer differ" noise. Applying any of them made patch(1) stop and prompt "File to patch:", which stalls a non-interactive apply and prints "1 out of 1 hunk ignored" otherwise. Cause: the diff-generation step cleaned its scratch trees with a glob that matched nothing, and the shell aborts the whole command line on a failed glob, so the cleanup never ran and the build products were left in place. The resulting builds were correct either way, since make regenerates config.h from config.def.h, but the patches were not clean. Each patch now touches only ttym.c and config.def.h. Verified with patch --batch < /dev/null so a prompt is fatal rather than silently skipped: all five apply with no prompt, skip, ignored hunk or fuzz, and compile. Claude-Session: https://claude.ai/code/session_01APLBs8RB1FcUaC4viVkzbP
* ttym 3.0: fix terminal and config bugs, fold terminal-only patches into baseLukasz Kasprzak2026-08-2517-1195/+1056
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Correctness fixes: - restore the terminal on SIGQUIT and SIGHUP. atexit never runs on an uncaught fatal signal, so Ctrl+\ left the cursor hidden and autowrap disabled. - drop the unconditional newline in restore_tty. Every run emitted a stray blank line, including piped output. - treat EINTR as an interruption rather than a poll() failure, which delayed Ctrl+C by up to one 100ms frame. config-file patch: - make comment stripping quote-aware so a value may contain '#', and strip one matched pair of quotes. bar_fill = "#" was silently dropped, despite '#' being the glyph of the hash style this build ships. - resolve bar_fill/bar_empty inside resolve_bar and clear them on --bar, so command-line flags beat the config file as documented. Previously config glyphs silently overrode --bar. - report unknown keys, unparseable booleans and malformed lines on stderr. flash = enabled silently meant off. - never write to disk. --dump-config prints a commented template on stdout instead of the binary creating ~/.config/ttym/config on first run. Patch set: - fold persist-alert, flash and bar-styles into the base. The base is now terminal-only: it opens /dev/tty, draws and exits, with no file writes and no subprocesses. Everything still in patches/ changes what the program touches. - seven patches become four; config-file's prerequisites drop from six patches to one (notify), so it is regenerable mechanically. - regenerate every patch. All apply with zero fuzz and compile. Source: - rewrite argv in place rather than into a malloc'd copy (C99 5.1.2.2.1), removing die(), four free() calls and <stdarg.h>. - fold the duplicated elapsed-time expression into elapsed(). - drop dead code: have_any, (void)cfg, and an unreachable branch in parse_duration. - replace hand-counted padding with \033[K. Docs and build: - timer.1: -c is the third hook argument, not the fourth. Add EXIT STATUS (a stopwatch always exits 130 -- it has no natural end) and ENVIRONMENT. Document config precedence and quoting. - wire VERSION into a dist target; it was defined and never used. - track .gitignore, which previously ignored itself, so a fresh clone had no ignore rules. Claude-Session: https://claude.ai/code/session_01APLBs8RB1FcUaC4viVkzbP
* modified readme.mdLukasz Kasprzak2026-05-201-0/+0
|
* initial commitLukasz Kasprzak2026-05-2016-0/+3529