From 2b366405676283d578225f9332e233dc9e31f58a Mon Sep 17 00:00:00 2001 From: lew Date: Thu, 2 Apr 2026 15:46:16 +0100 Subject: [PATCH] feat: -f/-v/-e flags, 5-field TSV with tags in field 2 --- nag | 66 +++++++++++++++++++++++++------------------ test/at.bats | 20 +++++++++++-- test/check.bats | 18 ++++++------ test/edit.bats | 10 ++----- test/every.bats | 4 +-- test/help.bats | 2 +- test/list.bats | 10 +++---- test/skip.bats | 2 +- test/test_helper.bash | 2 +- 9 files changed, 76 insertions(+), 58 deletions(-) diff --git a/nag b/nag index e0cf5b0..6c7d453 100755 --- a/nag +++ b/nag @@ -304,16 +304,16 @@ do -h|--help) _SUBCOMMAND="help" ;; - -e|--edit) + -e) _SUBCOMMAND="edit" ;; - --version) + -v) _SUBCOMMAND="version" ;; --debug) _USE_DEBUG=1 ;; - --yes) + -f) _YES=1 ;; *) @@ -511,8 +511,8 @@ _next_id() { # # Description: # Extract a field from a TSV alarm line. -# Fields: 1=id, 2=timestamp, 3=rule, 4=message. -# For field 4 (message), returns everything after the 3rd tab. +# Fields: 1=id, 2=tags, 3=timestamp, 4=rule, 5=message. +# For field 5 (message), returns everything after the 4th tab. _get_alarm_field() { local _line="${1}" local _field="${2}" @@ -522,7 +522,7 @@ _get_alarm_field() { do _rest="${_rest#*$'\t'}" done - if (( _field == 4 )) + if (( _field == 5 )) then printf "%s" "${_rest}" else @@ -938,7 +938,7 @@ _parse_time() { # Description: # Check whether a systemd user timer for `nag check` is active. # If not, prompt the user to install one (or install automatically -# when --yes is set). Falls back to cron if systemd is unavailable. +# when -f is set). Falls back to cron if systemd is unavailable. _prompt_timer() { # Already running? if systemctl --user is-active nag.timer &>/dev/null @@ -1056,9 +1056,9 @@ Usage: ${_ME} version show version Options: - -e, --edit Edit alarms file directly. - --yes Skip all prompts. - --version Show version. + -e Edit alarms file directly. + -f Skip all prompts. + -v Show version. Environment: NAG_DIR Alarm storage directory (default: ~/.local/share/nag) @@ -1072,7 +1072,7 @@ HEREDOC describe "version" <timestampmessage + # Verify TSV structure: idtimestampmessage local _line _line="$(cat "${NAG_DIR}/alarms")" - [[ "${_line}" =~ ^1$'\t'[0-9]+$'\t'$'\t'take\ a\ break$ ]] + [[ "${_line}" =~ ^1$'\t'$'\t'[0-9]+$'\t'$'\t'take\ a\ break$ ]] } @test "at is the implicit subcommand" { @@ -68,13 +68,27 @@ load test_helper run_nag at "${_last_month}" "annual thing" [ "${status}" -eq 0 ] local _ts - _ts="$(cut -f2 "${NAG_DIR}/alarms")" + _ts="$(cut -f3 "${NAG_DIR}/alarms")" local _ts_year _next_year _ts_year="$(date -d "@${_ts}" +%Y)" _next_year="$(date -d "+1 year" +%Y)" [ "${_ts_year}" = "${_next_year}" ] } +@test "-f flag suppresses prompts" { + run "${_NAG}" -f at "tomorrow 3pm" "flagged alarm" + [ "${status}" -eq 0 ] + [[ "${output}" =~ "flagged alarm" ]] +} + +@test "at creates alarm with 5-field TSV (empty tags)" { + run_nag at "tomorrow 3pm" "tagged test" + [ "${status}" -eq 0 ] + local _line + _line="$(cat "${NAG_DIR}/alarms")" + [[ "${_line}" =~ ^1$'\t'$'\t'[0-9]+$'\t'$'\t'tagged\ test$ ]] +} + @test "at without message fails" { run_nag at "tomorrow 3pm" [ "${status}" -eq 1 ] diff --git a/test/check.bats b/test/check.bats index 7e6b68f..e6ff6e3 100644 --- a/test/check.bats +++ b/test/check.bats @@ -4,7 +4,7 @@ load test_helper @test "check fires expired one-shot and removes it" { local _past_ts=$(( $(date +%s) - 60 )) - write_alarm "$(printf "1\t%s\t\tpast alarm" "${_past_ts}")" + write_alarm "$(printf "1\t\t%s\t\tpast alarm" "${_past_ts}")" # Record what was fired. local _fired="${NAG_DIR}/fired" @@ -27,7 +27,7 @@ SCRIPT @test "check reschedules expired repeating alarm" { local _past_ts=$(( $(date +%s) - 60 )) - write_alarm "$(printf "1\t%s\tday\tdaily alarm" "${_past_ts}")" + write_alarm "$(printf "1\t\t%s\tday\tdaily alarm" "${_past_ts}")" run_nag check [ "${status}" -eq 0 ] @@ -35,7 +35,7 @@ SCRIPT # Alarm should still exist with a future timestamp. [ -s "${NAG_DIR}/alarms" ] local _new_ts - _new_ts="$(cut -f2 "${NAG_DIR}/alarms" | head -1)" + _new_ts="$(cut -f3 "${NAG_DIR}/alarms" | head -1)" local _now _now="$(date +%s)" (( _new_ts > _now )) @@ -43,7 +43,7 @@ SCRIPT @test "check does not fire future alarms" { local _future_ts=$(( $(date +%s) + 3600 )) - write_alarm "$(printf "1\t%s\t\tfuture alarm" "${_future_ts}")" + write_alarm "$(printf "1\t\t%s\t\tfuture alarm" "${_future_ts}")" run_nag check [ "${status}" -eq 0 ] @@ -56,8 +56,8 @@ SCRIPT @test "check fires all missed alarms" { local _past1=$(( $(date +%s) - 120 )) local _past2=$(( $(date +%s) - 60 )) - write_alarm "$(printf "1\t%s\t\tmissed one" "${_past1}")" - write_alarm "$(printf "2\t%s\t\tmissed two" "${_past2}")" + write_alarm "$(printf "1\t\t%s\t\tmissed one" "${_past1}")" + write_alarm "$(printf "2\t\t%s\t\tmissed two" "${_past2}")" local _fired="${NAG_DIR}/fired" export NAG_CMD="${NAG_DIR}/recorder" @@ -80,7 +80,7 @@ SCRIPT @test "check silently drops stale one-shot (older than 15 min)" { local _stale_ts=$(( $(date +%s) - 1800 )) # 30 minutes ago - write_alarm "$(printf "1\t%s\t\tstale alarm" "${_stale_ts}")" + write_alarm "$(printf "1\t\t%s\t\tstale alarm" "${_stale_ts}")" local _fired="${NAG_DIR}/fired" export NAG_CMD="${NAG_DIR}/recorder" @@ -102,7 +102,7 @@ SCRIPT @test "check silently reschedules stale repeating alarm" { local _stale_ts=$(( $(date +%s) - 1800 )) # 30 minutes ago - write_alarm "$(printf "1\t%s\tday\tstale repeater" "${_stale_ts}")" + write_alarm "$(printf "1\t\t%s\tday\tstale repeater" "${_stale_ts}")" local _fired="${NAG_DIR}/fired" export NAG_CMD="${NAG_DIR}/recorder" @@ -121,6 +121,6 @@ SCRIPT # Should be rescheduled to a future time. [ -s "${NAG_DIR}/alarms" ] local _new_ts - _new_ts="$(cut -f2 "${NAG_DIR}/alarms" | head -1)" + _new_ts="$(cut -f3 "${NAG_DIR}/alarms" | head -1)" (( _new_ts > $(date +%s) )) } diff --git a/test/edit.bats b/test/edit.bats index b183c04..86eaa05 100644 --- a/test/edit.bats +++ b/test/edit.bats @@ -10,22 +10,16 @@ load test_helper } @test "edit opens the alarms file in EDITOR" { - write_alarm "1 9999999999 test alarm" + write_alarm "1 9999999999 test alarm" EDITOR="cat" run_nag edit [[ "$status" -eq 0 ]] [[ "$output" == *"test alarm"* ]] } @test "-e flag invokes edit" { - write_alarm "1 9999999999 test alarm" + write_alarm "1 9999999999 test alarm" EDITOR="cat" run_nag -e [[ "$status" -eq 0 ]] [[ "$output" == *"test alarm"* ]] } -@test "--edit flag invokes edit" { - write_alarm "1 9999999999 test alarm" - EDITOR="cat" run_nag --edit - [[ "$status" -eq 0 ]] - [[ "$output" == *"test alarm"* ]] -} diff --git a/test/every.bats b/test/every.bats index 6ed45df..3afe543 100644 --- a/test/every.bats +++ b/test/every.bats @@ -10,7 +10,7 @@ load test_helper [[ "${output}" =~ "standup meeting" ]] # Verify TSV has rule in field 3. local _rule - _rule="$(cut -f3 "${NAG_DIR}/alarms")" + _rule="$(cut -f4 "${NAG_DIR}/alarms")" [ "${_rule}" = "weekday" ] } @@ -26,7 +26,7 @@ load test_helper run_nag every weekend "tomorrow 3pm" relax [ "${status}" -eq 0 ] local _ts _dow - _ts="$(cut -f2 "${NAG_DIR}/alarms")" + _ts="$(cut -f3 "${NAG_DIR}/alarms")" _dow="$(date -d "@${_ts}" +%u)" # Day-of-week should be 6 (Sat) or 7 (Sun). [[ "${_dow}" == "6" || "${_dow}" == "7" ]] diff --git a/test/help.bats b/test/help.bats index 8753b73..57e332f 100644 --- a/test/help.bats +++ b/test/help.bats @@ -32,7 +32,7 @@ load test_helper run_nag help version [ "${status}" -eq 0 ] [[ "${output}" =~ "Usage:" ]] - [[ "${output}" =~ "( version | --version )" ]] + [[ "${output}" =~ "( version | -v )" ]] } @test "help stop shows stop usage" { diff --git a/test/list.bats b/test/list.bats index c192747..afa0ddf 100644 --- a/test/list.bats +++ b/test/list.bats @@ -70,7 +70,7 @@ load test_helper @test "list shows Today for alarm due today" { local _ts=$(( $(date -d "$(date +%Y-%m-%d)" +%s) + 82800 )) - write_alarm "$(printf '1\t%s\t\ttoday alarm' "${_ts}")" + write_alarm "$(printf '1\t\t%s\t\ttoday alarm' "${_ts}")" run_nag [ "${status}" -eq 0 ] [[ "${output}" =~ "Today,".*"today alarm" ]] @@ -78,7 +78,7 @@ load test_helper @test "list shows Tomorrow for alarm due tomorrow" { local _ts=$(( $(date -d "$(date +%Y-%m-%d)" +%s) + 86400 + 43200 )) - write_alarm "$(printf '1\t%s\t\ttomorrow alarm' "${_ts}")" + write_alarm "$(printf '1\t\t%s\t\ttomorrow alarm' "${_ts}")" run_nag [ "${status}" -eq 0 ] [[ "${output}" =~ "Tomorrow,".*"tomorrow alarm" ]] @@ -87,7 +87,7 @@ load test_helper @test "list shows This for alarm 3 days away" { local _ts=$(( $(date -d "$(date +%Y-%m-%d)" +%s) + 86400 * 3 + 43200 )) local _day="$(date -d "@${_ts}" +%A)" - write_alarm "$(printf '1\t%s\t\tthis alarm' "${_ts}")" + write_alarm "$(printf '1\t\t%s\t\tthis alarm' "${_ts}")" run_nag [ "${status}" -eq 0 ] [[ "${output}" =~ "This ${_day},".*"this alarm" ]] @@ -96,7 +96,7 @@ load test_helper @test "list shows Next for alarm 10 days away" { local _ts=$(( $(date -d "$(date +%Y-%m-%d)" +%s) + 86400 * 10 + 43200 )) local _day="$(date -d "@${_ts}" +%A)" - write_alarm "$(printf '1\t%s\t\tnext alarm' "${_ts}")" + write_alarm "$(printf '1\t\t%s\t\tnext alarm' "${_ts}")" run_nag [ "${status}" -eq 0 ] [[ "${output}" =~ "Next ${_day},".*"next alarm" ]] @@ -105,7 +105,7 @@ load test_helper @test "list shows date for alarm 30 days away" { local _ts=$(( $(date -d "$(date +%Y-%m-%d)" +%s) + 86400 * 30 + 43200 )) local _date="$(date -d "@${_ts}" "+%a %b %-d")" - write_alarm "$(printf '1\t%s\t\tfar alarm' "${_ts}")" + write_alarm "$(printf '1\t\t%s\t\tfar alarm' "${_ts}")" run_nag [ "${status}" -eq 0 ] [[ "${output}" =~ "${_date},".*"far alarm" ]] diff --git a/test/skip.bats b/test/skip.bats index 939fe8c..852cf19 100644 --- a/test/skip.bats +++ b/test/skip.bats @@ -9,7 +9,7 @@ load test_helper [[ "${output}" =~ "Skipped" ]] [ -s "${NAG_DIR}/alarms" ] local _ts _now - _ts="$(cut -f2 "${NAG_DIR}/alarms")" + _ts="$(cut -f3 "${NAG_DIR}/alarms")" _now="$(date +%s)" (( _ts > _now )) } diff --git a/test/test_helper.bash b/test/test_helper.bash index 65fea0f..980beaa 100644 --- a/test/test_helper.bash +++ b/test/test_helper.bash @@ -15,7 +15,7 @@ teardown() { } run_nag() { - run "${_NAG}" --yes "$@" + run "${_NAG}" -f "$@" } write_alarm() {