fix: snooze and unsnooze always resolve targets to alarm IDs

This commit is contained in:
Lewis Wynne 2026-04-02 19:35:42 +01:00
parent ed10ae8842
commit a2c3755635
2 changed files with 156 additions and 65 deletions

146
nag
View file

@ -2033,20 +2033,34 @@ _snooze_by_tag() {
fi fi
_ensure_nag_dir _ensure_nag_dir
local _until_ts="" _until_date=""
if [[ -n "${_duration_str}" ]] if [[ -n "${_duration_str}" ]]
then then
local _until_ts
_until_ts="$(_parse_time "${_duration_str}")" _until_ts="$(_parse_time "${_duration_str}")"
printf "%s\t%s\\n" "${_tag}" "${_until_ts}" >> "${_SNOOZED_FILE}"
_release_lock
local _until_date
_until_date="$(date -d "@${_until_ts}" "+%b %-d")" _until_date="$(date -d "@${_until_ts}" "+%b %-d")"
printf "Snoozed [%s] until %s.\\n" "${_tag}" "${_until_date}"
else
printf "%s\\n" "${_tag}" >> "${_SNOOZED_FILE}"
_release_lock
printf "Snoozed [%s].\\n" "${_tag}"
fi fi
for _line in "${_ALARMS[@]}"
do
[[ -n "${_line}" ]] || continue
local _tags _id _message
_tags="$(_get_alarm_field "${_line}" 2)"
_alarm_has_tag "${_tags}" "${_tag}" || continue
_id="${_line%%$'\t'*}"
_message="$(_get_alarm_field "${_line}" 5)"
_remove_snoozed_entry "${_id}" 2>/dev/null || true
if [[ -n "${_until_ts}" ]]
then
printf "%s\t%s\\n" "${_id}" "${_until_ts}" >> "${_SNOOZED_FILE}"
printf "Snoozed [%s] %s until %s.\\n" "${_id}" "${_message}" "${_until_date}"
else
printf "%s\\n" "${_id}" >> "${_SNOOZED_FILE}"
printf "Snoozed [%s] %s.\\n" "${_id}" "${_message}"
fi
done
_release_lock
} }
snooze() { snooze() {
@ -2056,22 +2070,43 @@ snooze() {
if [[ "${_target}" == "all" ]] if [[ "${_target}" == "all" ]]
then then
local _duration_str="${2:-}" local _duration_str="${2:-}"
_ensure_nag_dir
_acquire_lock _acquire_lock
_read_alarms
if (( ${#_ALARMS[@]} == 0 ))
then
_release_lock
_exit_1 printf "No alarms to snooze.\\n"
fi
_ensure_nag_dir
local _until_ts="" _until_date=""
if [[ -n "${_duration_str}" ]] if [[ -n "${_duration_str}" ]]
then then
local _until_ts
_until_ts="$(_parse_time "${_duration_str}")" _until_ts="$(_parse_time "${_duration_str}")"
printf "*\t%s\\n" "${_until_ts}" > "${_SNOOZED_FILE}"
_release_lock
local _until_date
_until_date="$(date -d "@${_until_ts}" "+%b %-d")" _until_date="$(date -d "@${_until_ts}" "+%b %-d")"
printf "Snoozed all until %s.\\n" "${_until_date}"
else
printf "*\\n" > "${_SNOOZED_FILE}"
_release_lock
printf "Snoozed all.\\n"
fi fi
local _line
for _line in "${_ALARMS[@]}"
do
[[ -n "${_line}" ]] || continue
local _id _message
_id="${_line%%$'\t'*}"
_message="$(_get_alarm_field "${_line}" 5)"
_remove_snoozed_entry "${_id}" 2>/dev/null || true
if [[ -n "${_until_ts}" ]]
then
printf "%s\t%s\\n" "${_id}" "${_until_ts}" >> "${_SNOOZED_FILE}"
printf "Snoozed [%s] %s until %s.\\n" "${_id}" "${_message}" "${_until_date}"
else
printf "%s\\n" "${_id}" >> "${_SNOOZED_FILE}"
printf "Snoozed [%s] %s.\\n" "${_id}" "${_message}"
fi
done
_release_lock
return return
fi fi
@ -2107,6 +2142,7 @@ snooze() {
local _duration_str="${2:-}" local _duration_str="${2:-}"
_ensure_nag_dir _ensure_nag_dir
_remove_snoozed_entry "${_target}" 2>/dev/null || true
if [[ -n "${_duration_str}" ]] if [[ -n "${_duration_str}" ]]
then then
local _until_ts local _until_ts
@ -2127,46 +2163,66 @@ _unsnooze_by_tag() {
local _tag="${1}" local _tag="${1}"
_acquire_lock _acquire_lock
if [[ ! -f "${_SNOOZED_FILE}" ]]
then
_release_lock
_exit_1 printf "Tag [%s] is not snoozed.\\n" "${_tag}"
fi
local _found_in_file=0 _entry
while IFS= read -r _entry || [[ -n "${_entry}" ]]
do
[[ -n "${_entry}" ]] || continue
local _key="${_entry%%$'\t'*}"
[[ "${_key}" == "${_tag}" ]] && _found_in_file=1 && break
done < "${_SNOOZED_FILE}"
if (( ! _found_in_file ))
then
_release_lock
_exit_1 printf "Tag [%s] is not snoozed.\\n" "${_tag}"
fi
_read_alarms _read_alarms
local _match_count=0 _line
# Find alarms with this tag whose IDs are in the snoozed file.
local -a _snoozed_ids=()
local _line
for _line in "${_ALARMS[@]:-}" for _line in "${_ALARMS[@]:-}"
do do
[[ -n "${_line}" ]] || continue [[ -n "${_line}" ]] || continue
local _tags local _tags
_tags="$(_get_alarm_field "${_line}" 2)" _tags="$(_get_alarm_field "${_line}" 2)"
_alarm_has_tag "${_tags}" "${_tag}" && _match_count=$((_match_count + 1)) _alarm_has_tag "${_tags}" "${_tag}" || continue
local _id="${_line%%$'\t'*}"
# Check if this ID is in the snoozed file.
if [[ -f "${_SNOOZED_FILE}" ]]
then
local _entry
while IFS= read -r _entry || [[ -n "${_entry}" ]]
do
[[ -n "${_entry}" ]] || continue
local _key="${_entry%%$'\t'*}"
if [[ "${_key}" == "${_id}" ]]
then
_snoozed_ids+=("${_id}")
break
fi
done < "${_SNOOZED_FILE}"
fi
done done
if ! _confirm_action "Unsnooze" "${_match_count}" "${_tag}" if (( ${#_snoozed_ids[@]} == 0 ))
then
_release_lock
_exit_1 printf "[%s] alarms are not snoozed.\\n" "${_tag}"
fi
if ! _confirm_action "Unsnooze" "${#_snoozed_ids[@]}" "${_tag}"
then then
_release_lock _release_lock
return 0 return 0
fi fi
_remove_snoozed_entry "${_tag}" local _id
for _id in "${_snoozed_ids[@]}"
do
_remove_snoozed_entry "${_id}"
local _message=""
for _line in "${_ALARMS[@]:-}"
do
[[ -n "${_line}" ]] || continue
local _aid="${_line%%$'\t'*}"
if [[ "${_aid}" == "${_id}" ]]
then
_message="$(_get_alarm_field "${_line}" 5)"
break
fi
done
printf "Unsnoozed [%s] %s.\\n" "${_id}" "${_message}"
done
_release_lock _release_lock
printf "Unsnoozed [%s].\\n" "${_tag}"
} }
# unsnooze ################################################################### # unsnooze ###################################################################

View file

@ -27,31 +27,36 @@ load test_helper
[ "${status}" -eq 1 ] [ "${status}" -eq 1 ]
} }
@test "snooze all creates global entry" { @test "snooze all creates entries for all alarm IDs" {
run_nag at "tomorrow 3pm" "first"
run_nag at "tomorrow 4pm" "second"
run_nag snooze all run_nag snooze all
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "Snoozed all." ]] [[ "${output}" =~ "Snoozed [1]" ]]
[[ "${output}" =~ "Snoozed [2]" ]]
[ -f "${NAG_DIR}/snoozed" ] [ -f "${NAG_DIR}/snoozed" ]
grep -q "^\*$" "${NAG_DIR}/snoozed" grep -q "^1$" "${NAG_DIR}/snoozed"
grep -q "^2$" "${NAG_DIR}/snoozed"
} }
@test "snooze all with duration sets expiry" { @test "snooze all with duration sets expiry for each alarm" {
run_nag at "tomorrow 3pm" "first"
run_nag at "tomorrow 4pm" "second"
run_nag snooze all "tomorrow" run_nag snooze all "tomorrow"
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "Snoozed all" ]]
[[ "${output}" =~ "until" ]] [[ "${output}" =~ "until" ]]
local _line grep -q "^1"$'\t' "${NAG_DIR}/snoozed"
_line="$(cat "${NAG_DIR}/snoozed")" grep -q "^2"$'\t' "${NAG_DIR}/snoozed"
[[ "${_line}" == \*$'\t'* ]]
} }
@test "snooze by tag creates entry in snoozed file" { @test "snooze by tag creates entries for matching alarm IDs" {
run_nag at "tomorrow 3pm" "work task" run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work run_nag tag 1 work
run_nag snooze work run_nag snooze work
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "Snoozed [work]" ]] [[ "${output}" =~ "Snoozed [1]" ]]
grep -q "^work$" "${NAG_DIR}/snoozed" grep -q "^1$" "${NAG_DIR}/snoozed"
! grep -q "^work" "${NAG_DIR}/snoozed"
} }
@test "snooze by tag requires -f" { @test "snooze by tag requires -f" {
@ -80,16 +85,15 @@ load test_helper
[[ "${_line}" == 1$'\t'* ]] [[ "${_line}" == 1$'\t'* ]]
} }
@test "snooze by tag with duration sets expiry" { @test "snooze by tag with duration sets expiry for matching IDs" {
run_nag at "tomorrow 3pm" "work task" run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work run_nag tag 1 work
run_nag snooze work "tomorrow" run_nag snooze work "tomorrow"
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "Snoozed [work]" ]] [[ "${output}" =~ "Snoozed [1]" ]]
[[ "${output}" =~ "until" ]] [[ "${output}" =~ "until" ]]
local _line grep -q "^1"$'\t' "${NAG_DIR}/snoozed"
_line="$(cat "${NAG_DIR}/snoozed")" ! grep -q "^work" "${NAG_DIR}/snoozed"
[[ "${_line}" == work$'\t'* ]]
} }
@test "unsnooze by ID removes entry from snoozed file" { @test "unsnooze by ID removes entry from snoozed file" {
@ -102,6 +106,7 @@ load test_helper
} }
@test "unsnooze all removes snoozed file" { @test "unsnooze all removes snoozed file" {
run_nag at "tomorrow 3pm" "test alarm"
run_nag snooze all run_nag snooze all
run_nag unsnooze all run_nag unsnooze all
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
@ -120,14 +125,14 @@ load test_helper
[ "${status}" -eq 1 ] [ "${status}" -eq 1 ]
} }
@test "unsnooze by tag removes tag entry" { @test "unsnooze by tag removes snoozed entries for matching alarms" {
run_nag at "tomorrow 3pm" "work task" run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work run_nag tag 1 work
run_nag snooze work run_nag snooze work
run_nag unsnooze work run_nag unsnooze work
[ "${status}" -eq 0 ] [ "${status}" -eq 0 ]
[[ "${output}" =~ "Unsnoozed [work]" ]] [[ "${output}" =~ "Unsnoozed [1]" ]]
! grep -q "^work" "${NAG_DIR}/snoozed" 2>/dev/null ! grep -q "^1" "${NAG_DIR}/snoozed" 2>/dev/null
} }
@test "unsnooze by tag requires -f" { @test "unsnooze by tag requires -f" {
@ -145,10 +150,40 @@ load test_helper
[ "${status}" -eq 1 ] [ "${status}" -eq 1 ]
} }
@test "unsnooze tag that is not snoozed fails" { @test "unsnooze tag with no snoozed alarms fails" {
run_nag at "tomorrow 3pm" "work task" run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work run_nag tag 1 work
run "${_NAG}" -f unsnooze work run "${_NAG}" -f unsnooze work
[ "${status}" -eq 1 ] [ "${status}" -eq 1 ]
[[ "${output}" =~ "not snoozed" ]] [[ "${output}" =~ "not snoozed" ]]
} }
@test "snooze replaces existing entry instead of duplicating" {
run_nag at "tomorrow 3pm" "take a break"
run_nag snooze 1
run_nag snooze 1
[ "${status}" -eq 0 ]
[ "$(grep -c "^1" "${NAG_DIR}/snoozed")" -eq 1 ]
}
@test "snooze by tag does not duplicate already-snoozed IDs" {
run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work
run_nag snooze 1
run_nag snooze work
[ "${status}" -eq 0 ]
[ "$(grep -c "^1" "${NAG_DIR}/snoozed")" -eq 1 ]
}
@test "unsnooze by tag removes ID-snoozed alarms with that tag" {
run_nag at "tomorrow 3pm" "work task"
run_nag tag 1 work
run_nag snooze 1
run_nag snooze work
run_nag unsnooze work
[ "${status}" -eq 0 ]
# Alarm should be fully unsnoozed, no entries left
if [ -f "${NAG_DIR}/snoozed" ]; then
[ ! -s "${NAG_DIR}/snoozed" ] || ! grep -q "^1" "${NAG_DIR}/snoozed"
fi
}