aboutsummaryrefslogtreecommitdiff
path: root/timer.1
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 19:02:35 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-25 19:02:35 +0200
commit8f99f1650e4a7363af1d83190b4082fb72a9f73f (patch)
tree86ed3b714c376e95f98d33d7572e76d6b43f06d3 /timer.1
parent2f6b29abd0d766ef477eb29c5a7bf6c1e88e9630 (diff)
downloadttym-8f99f1650e4a7363af1d83190b4082fb72a9f73f.tar.gz
ttym-8f99f1650e4a7363af1d83190b4082fb72a9f73f.zip
ttym 3.0: fix terminal and config bugs, fold terminal-only patches into base
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
Diffstat (limited to 'timer.1')
-rw-r--r--timer.1153
1 files changed, 116 insertions, 37 deletions
diff --git a/timer.1 b/timer.1
index 57f84bb..e72566f 100644
--- a/timer.1
+++ b/timer.1
@@ -1,9 +1,25 @@
-.TH TIMER 1 "ttym 2.0"
+.TH TIMER 1 "ttym 3.0"
.SH NAME
timer \- terminal countdown and stopwatch
.SH SYNOPSIS
.B timer
.RB [ \-qs ]
+.RB [ \-\-no\-persist ]
+.RB [ \-\-flash
+.BR on | off ]
+.RB [ \-\-bar
+.IR style ]
+.RB [ \-\- ]
+.RI [ duration ]
+.PP
+The remaining forms exist only when the corresponding patch is applied;
+each is annotated
+.RI [patch: name ]
+under
+.BR OPTIONS .
+.PP
+.B timer
+.RB [ \-qs ]
.RB [ \-c
.IR text ]
.RB [ \-\-no\-persist ]
@@ -11,6 +27,7 @@ timer \- terminal countdown and stopwatch
.BR on | off ]
.RB [ \-\-bar
.IR style ]
+.RB [ \-\-dump\-config ]
.RB [ \-\- ]
.RI [ duration ]
.RI [ message
@@ -32,9 +49,11 @@ The progress bar, current elapsed time and time remaining
are redrawn on the same line ten times per second.
.PP
The binary is intentionally small and modular.
-Beyond the base build (countdown, stopwatch, ASCII progress bar,
-pause/resume, one\-shot terminal bell on completion) every feature is
-an optional patch under
+The base build is terminal\-only: countdown, stopwatch, pause/resume,
+the progress bar and its eight styles, and the alert\-until\-keypress
+loop with its optional terminal flash. It writes no files and spawns no
+processes. Every feature that touches the filesystem, runs a subprocess
+or depends on an external binary is an optional patch under
.IR patches/ .
Each section below describing a non\-base feature is annotated with
.RI [patch: name ];
@@ -46,8 +65,11 @@ always reflects the actual build.
.SS Base
.TP
.B \-q
-Suppress the one\-shot completion bell.
-Persistent alert loops, if enabled by a patch, still ring the bell.
+Suppress the one\-shot completion bell. With the
+.B notify
+patch it also suppresses the completion sound, though not the desktop
+notification. Persistent alert loops, if enabled by a patch, still ring
+the bell.
.TP
.B \-s
Silent. No bell, no notification, no alert loop.
@@ -60,36 +82,22 @@ Print usage and exit. Reflects the actual build.
End of options. Subsequent arguments are treated as positional even if
they begin with
.BR \- .
-.SS Optional, added by patches
-.TP
-.BR \-c \ \fItext\fR
-.RI [patch: logging,
-.RI hooks]
-Comment associated with this session. With the
-.B logging
-patch, it is written as the third TSV field and any
-.BI + tag
-tokens within it are picked up by
-.BR "timer \-\-stats" .
-With the
-.B hooks
-patch, it is passed as the fourth argument to each hook script.
.TP
.B \-\-no\-persist
-.RI [patch: persist\-alert]
Skip the alert\-until\-keypress loop.
.B timer
-emits one bell and one notification, then exits.
+emits one bell, then exits.
.TP
.BR \-\-flash \ \fBon\fR | \fBoff\fR
-.RI [patch: flash]
Toggle the reverse\-video terminal flash that runs during the
persistent alert loop. Accepts
.BR on / off / true / false / 1 / 0 / yes / no .
-Default is build\-dependent.
+Default is
+.B FLASH
+in
+.IR config.h .
.TP
.BR \-\-bar \ \fIstyle\fR
-.RI [patch: bar\-styles]
Progress bar style. One of
.BR unicode ,
.BR ascii ,
@@ -99,12 +107,40 @@ Progress bar style. One of
.BR block ,
.BR arrow ,
.BR minimal .
-With no patch applied the bar uses the compile\-time
+Unset (the default) auto\-detects: unicode on a UTF\-8 locale,
+otherwise ascii. The
.B BAR_FILL
and
.B BAR_EMPTY
-glyphs from
-.IR config.h .
+glyphs in
+.I config.h
+are the fallback when no style matches.
+.SS Optional, added by patches
+.TP
+.BR \-c \ \fItext\fR
+.RI [patch: logging,
+.RI hooks]
+Comment associated with this session. With the
+.B logging
+patch, it is written as the third TSV field and any
+.BI + tag
+tokens within it are picked up by
+.BR "timer \-\-stats" .
+With the
+.B hooks
+patch, it is passed as the third argument to each hook script.
+.TP
+.B \-\-dump\-config
+.RI [patch: config\-file]
+Print a commented configuration template on stdout and exit.
+.B timer
+never creates the file itself:
+.PP
+.RS
+.nf
+timer \-\-dump\-config > ~/.config/ttym/config
+.fi
+.RE
.SH SUBCOMMANDS
.SS timer \-r [\-n N] [\-\-raw]
.RI [patch: logging]
@@ -178,7 +214,6 @@ Quit immediately. Logs the partial session if logging is enabled.
Same as
.BR q .
.SH ALERT LOOP
-.RI [patch: persist\-alert]
When a countdown reaches zero, instead of emitting one bell and
exiting, the program rings the bell every \(ti1.5 s and polls for a
keypress. Any key acknowledges and exits.
@@ -191,12 +226,14 @@ Background jobs
.IR ... \ &)
get one bell and exit normally, leaving the shell quiet.
.PP
-If the
-.B flash
-patch is also applied, each beat of the loop briefly inverts the
-terminal colours (reverse\-video). The flash can be suppressed without
-disabling the loop via
-.BR "\-\-flash off" .
+Each beat of the loop briefly inverts the terminal colours
+(reverse\-video). The flash can be suppressed without disabling the
+loop via
+.BR "\-\-flash off" ,
+or permanently via
+.B FLASH
+in
+.IR config.h .
.SH HOOKS
.RI [patch: hooks]
On state transitions
@@ -228,12 +265,54 @@ or
the others come from the running session. Hooks must be marked
executable. Standard streams are redirected to
.IR /dev/null .
+.SH EXIT STATUS
+.TP
+.B 0
+A countdown ran to completion.
+.TP
+.B 1
+Usage error: an unknown option, or a duration that could not be parsed.
+.TP
+.B 130
+The session was cut short, either by
+.B q
+or by
+.BR SIGINT ,
+.BR SIGTERM ,
+.BR SIGQUIT
+or
+.BR SIGHUP .
+The terminal is restored in every case.
+A stopwatch always exits this way \(em it has no natural end.
+.SH ENVIRONMENT
+.TP
+.B XDG_CONFIG_HOME
+Base directory for the files below. Defaults to
+.I ~/.config
+when unset or empty.
.SH FILES
.TP
+.I /etc/ttym.conf
+.RI [patch: config\-file]
+System\-wide runtime configuration, read before the per\-user file.
+.TP
.I ~/.config/ttym/config
.RI [patch: config\-file]
-Runtime configuration. Auto\-generated on first run with all keys
-commented out.
+Per\-user runtime configuration;
+.BR key " = " value
+lines. A
+.B #
+begins a comment at the start of a line or after whitespace, and never
+inside quotes; quote a value to protect surrounding spaces or a leading
+.BR # .
+Unknown keys and unparseable values are reported on stderr.
+Command\-line flags override this file, which overrides
+.IR /etc/ttym.conf ,
+which overrides the compile\-time defaults in
+.IR config.h .
+.B timer
+never creates this file \(em see
+.BR \-\-dump\-config .
.TP
.I ~/.config/ttym/ttym.log
.RI [patch: logging]