diff --git a/nag b/nag index b0f7a68..c11d701 100755 --- a/nag +++ b/nag @@ -45,7 +45,6 @@ NAG_CMD="${NAG_CMD:-notify-send}" # Sound file to play when an alarm fires. Empty or missing file = no sound. NAG_SOUND="${NAG_SOUND-/usr/share/sounds/freedesktop/stereo/bell.oga}" _MUTE_FILE="${NAG_DIR}/mute" -_SNOOZED_FILE="${NAG_DIR}/snoozed" # The default subcommand if no args are passed. NAG_DEFAULT="${NAG_DEFAULT:-list}" @@ -212,32 +211,23 @@ _piped_input() { } # Usage: -# _confirm_action [] +# _confirm_action # # Prompts the user for confirmation before performing a bulk action on -# alarms. When is provided, the prompt includes the tag name. -# Skipped when -f (force/_YES) is set. In non-interactive mode, prints -# a message asking the caller to pass -f. +# tagged alarms. Skipped when -f (force/_YES) is set. In non-interactive +# mode, prints a message asking the caller to pass -f. # # Exit / Error Status: # 0 (success, true) If the action is confirmed. # 1 (error, false) If the action is denied or non-interactive without -f. _confirm_action() { - local _verb="${1}" _count="${2}" _tag="${3:-}" + local _verb="${1}" _count="${2}" _tag="${3}" (( _YES )) && return 0 - local _desc - if [[ -n "${_tag}" ]] - then - _desc="${_count} alarm(s) tagged [${_tag}]" - else - _desc="${_count} alarm(s)" - fi - if _interactive_input then - printf "%s %s? [y/N] " "${_verb}" "${_desc}" + printf "%s %s alarm(s) tagged [%s]? [y/N] " "${_verb}" "${_count}" "${_tag}" local _reply read -r _reply case "${_reply}" in @@ -245,7 +235,7 @@ _confirm_action() { *) return 1 ;; esac else - printf "%s %s? Pass -f to confirm.\\n" "${_verb}" "${_desc}" + printf "%s %s alarm(s) tagged [%s]? Pass -f to confirm.\n" "${_verb}" "${_count}" "${_tag}" return 1 fi } @@ -335,8 +325,6 @@ _SUBCOMMAND="" _SUBCOMMAND_ARGUMENTS=() _USE_DEBUG=0 _YES=0 -_RAW_TIME=0 -_EPOCH_TIME=0 while ((${#})) do @@ -358,12 +346,6 @@ do -f) _YES=1 ;; - --iso) - _RAW_TIME=1 - ;; - --epoch) - _EPOCH_TIME=1 - ;; *) # The first non-option argument is assumed to be the subcommand name. # All subsequent arguments are added to $_SUBCOMMAND_ARGUMENTS. @@ -662,176 +644,6 @@ _is_muted() { return 1 } -# Usage: -# _is_snoozed -# -# Description: -# Check whether an alarm ID is currently snoozed. If the entry has an -# expiry timestamp, it is only considered snoozed when the expiry is -# still in the future. -# -# Exit / Error Status: -# 0 (success, true) If the alarm is snoozed. -# 1 (error, false) If the alarm is not snoozed. -_is_snoozed() { - local _id="${1}" - [[ -f "${_SNOOZED_FILE}" ]] || return 1 - - local _now _entry - _now="$(date +%s)" - - while IFS= read -r _entry || [[ -n "${_entry}" ]] - do - [[ -n "${_entry}" ]] || continue - local _entry_key="${_entry%%$'\t'*}" - - [[ "${_entry_key}" == "${_id}" ]] || continue - - # Check expiry if present. - if [[ "${_entry}" == *$'\t'* ]] - then - local _expiry="${_entry#*$'\t'}" - (( _expiry > _now )) && return 0 - else - return 0 - fi - done < "${_SNOOZED_FILE}" - - return 1 -} - -# Usage: -# _sweep_expired_snoozes -# -# Description: -# Remove stale snooze entries: expired (past expiry timestamp) and -# orphaned (alarm ID no longer exists in _ALARMS). Expects _ALARMS -# to be populated via _read_alarms before calling. -_sweep_expired_snoozes() { - [[ -f "${_SNOOZED_FILE}" ]] || return 0 - - local _now - _now="$(date +%s)" - local -a _keep=() - local _entry - - while IFS= read -r _entry || [[ -n "${_entry}" ]] - do - [[ -n "${_entry}" ]] || continue - - local _entry_id="${_entry%%$'\t'*}" - - # Drop expired entries. - if [[ "${_entry}" == *$'\t'* ]] - then - local _expiry="${_entry#*$'\t'}" - (( _expiry <= _now )) && continue - fi - - # Drop orphaned entries (alarm no longer exists). - local _exists=0 _line - for _line in "${_ALARMS[@]:-}" - do - [[ -n "${_line}" ]] || continue - [[ "${_line%%$'\t'*}" == "${_entry_id}" ]] && _exists=1 && break - done - (( _exists )) || continue - - _keep+=("${_entry}") - done < "${_SNOOZED_FILE}" - - if (( ${#_keep[@]} == 0 )) - then - rm -f "${_SNOOZED_FILE}" - else - printf "%s\n" "${_keep[@]}" > "${_SNOOZED_FILE}.tmp" - mv -f "${_SNOOZED_FILE}.tmp" "${_SNOOZED_FILE}" - fi -} - -# Usage: -# _get_snooze_display -# -# Description: -# Set REPLY to a display string for the given alarm ID's snooze status. -# Returns " (snoozed)" for indefinite snoozes, " (snoozed until )" -# for timed snoozes, or "" if the alarm is not snoozed. -_get_snooze_display() { - local _id="${1}" - REPLY="" - [[ -f "${_SNOOZED_FILE}" ]] || return 0 - - local _now _entry - _now="$(date +%s)" - - while IFS= read -r _entry || [[ -n "${_entry}" ]] - do - [[ -n "${_entry}" ]] || continue - local _entry_key="${_entry%%$'\t'*}" - - [[ "${_entry_key}" == "${_id}" ]] || continue - - if [[ "${_entry}" == *$'\t'* ]] - then - local _expiry="${_entry#*$'\t'}" - if (( _expiry > _now )) - then - _format_time "${_expiry}" - REPLY=" (snoozed until ${REPLY})" - fi - else - REPLY=" (snoozed)" - fi - return 0 - done < "${_SNOOZED_FILE}" -} - -# Usage: -# _remove_snoozed_entry -# -# Description: -# Remove the entry whose key matches from the snoozed file. -# Returns 1 if no matching entry was found or the file does not exist. -_remove_snoozed_entry() { - local _key="${1}" - [[ -f "${_SNOOZED_FILE}" ]] || return 1 - - local -a _keep=() - local _removed=0 _entry - while IFS= read -r _entry || [[ -n "${_entry}" ]] - do - [[ -n "${_entry}" ]] || continue - local _entry_key="${_entry%%$'\t'*}" - if [[ "${_entry_key}" == "${_key}" ]] - then - _removed=1 - else - _keep+=("${_entry}") - fi - done < "${_SNOOZED_FILE}" - - (( _removed )) || return 1 - - if (( ${#_keep[@]} == 0 )) - then - rm -f "${_SNOOZED_FILE}" - else - printf "%s\n" "${_keep[@]}" > "${_SNOOZED_FILE}.tmp" - mv -f "${_SNOOZED_FILE}.tmp" "${_SNOOZED_FILE}" - fi - return 0 -} - -# Usage: -# _cleanup_alarm_metadata -# -# Description: -# Remove all metadata for an alarm ID (snoozed file entries). -# Called when an alarm is permanently removed. -_cleanup_alarm_metadata() { - _remove_snoozed_entry "${1}" 2>/dev/null || true -} - # Usage: # _tag_list # @@ -885,11 +697,7 @@ _tag_list() { _tag_display=" [${_tags//,/, }]" - local _snooze_display - _get_snooze_display "${_id}" - _snooze_display="${REPLY}" - - printf "[%s]%s %s%s%s — %s\\n" "${_id}" "${_tag_display}" "${_human_time}" "${_rule_display}" "${_snooze_display}" "${_message}" + printf "[%s]%s %s%s — %s\\n" "${_id}" "${_tag_display}" "${_human_time}" "${_rule_display}" "${_message}" done if (( ! _matched )) @@ -910,18 +718,6 @@ _tag_list() { _format_time() { local _timestamp="${1}" - if (( _EPOCH_TIME )) - then - REPLY="${_timestamp}" - return - fi - - if (( _RAW_TIME )) - then - REPLY="$(date -d "@${_timestamp}" "+%Y-%m-%d %H:%M:%S")" - return - fi - # Single date call to get all needed components. local _date_parts _date_parts="$(date -d "@${_timestamp}" "+%-I|%M|%p|%Y-%m-%d|%A|%a %b %-d")" @@ -972,21 +768,12 @@ _format_time() { _date_prefix="Tomorrow" elif (( _days_away <= 6 )) then - _date_prefix="${_day_name}" + _date_prefix="This ${_day_name}" elif (( _days_away <= 13 )) then _date_prefix="Next ${_day_name}" else - local _alarm_year - _alarm_year="$(date -d "${_alarm_date}" +%Y)" - local _this_year - _this_year="$(date +%Y)" - if [[ "${_alarm_year}" != "${_this_year}" ]] - then - _date_prefix="${_short_date} ${_alarm_year}" - else - _date_prefix="${_short_date}" - fi + _date_prefix="${_short_date}" fi REPLY="${_date_prefix}, ${_time_fmt}" @@ -1233,87 +1020,6 @@ _first_occurrence() { fi } -# Usage: -# _unskip_timestamp -# -# Description: -# Compute the next natural occurrence of a repeating alarm from now. -# Handles each rule type appropriately: day-of-week rules use today's -# date at alarm's time, month preserves day-of-month, year preserves -# month and day. For comma-separated rules, returns the earliest. -_unskip_timestamp() { - local _timestamp="${1}" _rules="${2}" - local _now - _now="$(date +%s)" - - local _time_of_day _alarm_day _alarm_month - _time_of_day="$(date -d "@${_timestamp}" +%H:%M:%S)" - _alarm_day="$(date -d "@${_timestamp}" +%-d)" - _alarm_month="$(date -d "@${_timestamp}" +%-m)" - - local _earliest="" - local IFS="," - local _rule - for _rule in ${_rules} - do - local _candidate="" - case "${_rule}" in - hour) - _candidate="$((_now - (_now % 3600) + $(date -d "@${_timestamp}" +%s) % 3600))" - if (( _candidate <= _now )); then - _candidate=$((_candidate + 3600)) - fi - ;; - day) - _candidate="$(date -d "$(date +%Y-%m-%d) ${_time_of_day}" +%s)" - if (( _candidate <= _now )); then - _candidate="$(date -d "$(date +%Y-%m-%d) + 1 day ${_time_of_day}" +%s)" - fi - ;; - month) - local _year_now _month_now - _year_now="$(date +%Y)" - _month_now="$(date +%-m)" - _candidate="$(date -d "$(printf "%04d-%02d-%02d %s" "${_year_now}" "${_month_now}" "${_alarm_day}" "${_time_of_day}")" +%s 2>/dev/null)" || _candidate=0 - if (( _candidate <= _now )); then - if (( _candidate == 0 )); then - _candidate="$(date -d "$(date +%Y-%m-%d) ${_time_of_day}" +%s)" - fi - _candidate="$(_next_month "${_candidate}" "${_time_of_day}")" - fi - ;; - year) - local _year_now - _year_now="$(date +%Y)" - _candidate="$(date -d "$(printf "%04d-%02d-%02d %s" "${_year_now}" "${_alarm_month}" "${_alarm_day}" "${_time_of_day}")" +%s 2>/dev/null)" || _candidate=0 - if (( _candidate <= _now )); then - if (( _candidate == 0 )); then - _candidate="$(date -d "$(date +%Y-%m-%d) ${_time_of_day}" +%s)" - fi - _candidate="$(_next_year "${_candidate}" "${_time_of_day}")" - fi - ;; - *) - # Day-of-week rules (weekday, weekend, mon-sun, week). - local _today_at_alarm_time - _today_at_alarm_time="$(date -d "$(date +%Y-%m-%d) ${_time_of_day}" +%s)" - _candidate="$(_first_occurrence "${_rule}" "${_today_at_alarm_time}")" - if (( _candidate <= _now )); then - _candidate="$(_next_occurrence "${_rule}" "${_candidate}")" - fi - ;; - esac - - if [[ -n "${_candidate}" ]] && (( _candidate > 0 )); then - if [[ -z "${_earliest}" ]] || (( _candidate < _earliest )); then - _earliest="${_candidate}" - fi - fi - done - - printf "%s" "${_earliest}" -} - # Usage: # _timestamp_matches_rule # @@ -1516,14 +1222,11 @@ Usage: ${_ME} list all alarms ${_ME}