This commit is contained in:
Ray Elliott 2026-10-28 20:04:29 +00:00
commit 948de94e95
3 changed files with 147 additions and 13 deletions

View file

@ -72,7 +72,8 @@ The loader sources every readable `bashrc.d/*.bash` file in lexical order:
- `50-completions.bash`: command-specific completion setup. - `50-completions.bash`: command-specific completion setup.
- `60-directory-notes.bash`: `TODO.md` and `.autonote.md` display after `cd`. - `60-directory-notes.bash`: `TODO.md` and `.autonote.md` display after `cd`.
- `70-development.bash`: OpenCode and Pyenv initialization. - `70-development.bash`: OpenCode and Pyenv initialization.
- `90-memory-question.bash`: daily shell-memory question and `answerpls`. - `90-memory-question.bash`: persisted shuffled question deck, `answerpls` and
on-demand `refreshpls` rotation.
Keep cross-module dependencies explicit through this numbering. New modules Keep cross-module dependencies explicit through this numbering. New modules
should own one coherent area rather than becoming another general-purpose RC. should own one coherent area rather than becoming another general-purpose RC.

View file

@ -1,6 +1,8 @@
# shellcheck shell=bash # shellcheck shell=bash
_memory_file="${XDG_CONFIG_HOME:-$HOME/.config}/bash/memory.tsv" _memory_file="${XDG_CONFIG_HOME:-$HOME/.config}/bash/memory.tsv"
_memory_state_dir="${XDG_STATE_HOME:-$HOME/.local/state}/bash"
_memory_state_file="$_memory_state_dir/memory-question"
_memory_question_color='\033[38;5;11m' _memory_question_color='\033[38;5;11m'
_memory_names=() _memory_names=()
_memory_questions=() _memory_questions=()
@ -40,18 +42,141 @@ else
fi fi
if [[ $_memory_invalid -eq 0 && ${#_memory_names[@]} -gt 0 ]]; then if [[ $_memory_invalid -eq 0 && ${#_memory_names[@]} -gt 0 ]]; then
_memory_day=$(date -d "$(date +%F) 00:00" +%s) _memory_load_state() {
_memory_index=$(( (_memory_day / 86400) % ${#_memory_names[@]} )) local -a fields=() state_deck=()
_MEMORY_ANSWER=${_memory_answers[$_memory_index]} local state_date state_index item
local -A state_seen=()
[[ -r "$_memory_state_file" ]] || return 1
IFS=$'\t' read -r -a fields < "$_memory_state_file"
[[ ${#fields[@]} -eq $((${#_memory_names[@]} + 2)) ]] || return 1
state_date=${fields[0]}
state_index=${fields[1]}
state_deck=("${fields[@]:2}")
[[ $state_index =~ ^[0-9]+$ && $state_index -lt ${#state_deck[@]} ]] || return 1
for item in "${state_deck[@]}"; do
[[ -n ${_memory_seen[$item]:-} && -z ${state_seen[$item]:-} ]] || return 1
state_seen[$item]=1
done
_memory_state_date=$state_date
_memory_index=$state_index
_memory_deck=("${state_deck[@]}")
}
_memory_shuffle_deck() {
local previous_name=$1
local i j swap
_memory_deck=("${_memory_names[@]}")
for ((i = ${#_memory_deck[@]} - 1; i > 0; i--)); do
j=$((RANDOM % (i + 1)))
swap=${_memory_deck[$i]}
_memory_deck[i]=${_memory_deck[j]}
_memory_deck[j]=$swap
done
if [[ ${#_memory_deck[@]} -gt 1 && ${_memory_deck[0]} == "$previous_name" ]]; then
swap=${_memory_deck[0]}
_memory_deck[0]=${_memory_deck[1]}
_memory_deck[1]=$swap
fi
_memory_index=0
}
_memory_save_state() {
local state_tmp="${_memory_state_file}.$$"
local item
mkdir -p "$_memory_state_dir" || return 1
{
printf '%s\t%s' "$_memory_state_date" "$_memory_index"
for item in "${_memory_deck[@]}"; do
printf '\t%s' "$item"
done
printf '\n'
} > "$state_tmp" || return 1
mv -f -- "$state_tmp" "$_memory_state_file"
}
_memory_select_current() {
local current_name=${_memory_deck[$_memory_index]}
local i
for ((i = 0; i < ${#_memory_names[@]}; i++)); do
if [[ ${_memory_names[$i]} == "$current_name" ]]; then
_MEMORY_ANSWER=${_memory_answers[$i]}
_MEMORY_QUESTION=${_memory_questions[$i]}
return
fi
done
return 1
}
_memory_advance() {
local previous_name=${_memory_deck[$_memory_index]}
((_memory_index++))
if [[ $_memory_index -ge ${#_memory_deck[@]} ]]; then
_memory_shuffle_deck "$previous_name"
fi
_memory_select_current
_memory_save_state
}
_memory_sync_day() {
local today
today=$(date +%F)
[[ $_memory_state_date != "$today" ]] || return 0
_memory_state_date=$today
_memory_advance
}
_memory_print_question() {
printf '%b%s%b (answerpls, refreshpls)\n\n' \
"$_memory_question_color" "$_MEMORY_QUESTION" "$_NC"
}
_memory_today=$(date +%F)
if _memory_load_state; then
_memory_select_current
_memory_sync_day
else
_memory_state_date=$_memory_today
_memory_shuffle_deck ''
_memory_select_current
_memory_save_state
fi
answerpls() { answerpls() {
printf '%s\n' "$_MEMORY_ANSWER" printf '%s\n' "$_MEMORY_ANSWER"
} }
printf '%b%s%b (answerpls)\n\n' \ refreshpls() {
"$_memory_question_color" "${_memory_questions[$_memory_index]}" "$_NC" if _memory_load_state; then
_memory_select_current
else
_memory_state_date=$(date +%F)
_memory_shuffle_deck "${_memory_deck[$_memory_index]:-}"
_memory_select_current
_memory_save_state
fi
_memory_sync_day
_memory_advance
_memory_print_question
}
_memory_print_question
fi fi
unset _memory_file _memory_question_color _memory_names _memory_questions _memory_answers unset _memory_file
unset _memory_seen _memory_invalid _memory_line_number _memory_name _memory_question unset _memory_invalid _memory_line_number _memory_name _memory_question
unset _memory_answer _memory_extra _memory_day _memory_index unset _memory_answer _memory_extra _memory_today

View file

@ -14,10 +14,18 @@ name question answer
- `question` is displayed on shell startup. - `question` is displayed on shell startup.
- `answer` is displayed by running `answerpls` in that terminal. - `answer` is displayed by running `answerpls` in that terminal.
Run `refreshpls` to advance to another question before the next calendar day.
`answerpls` then displays the answer to the newly shown question. Refreshing is
persisted under `$XDG_STATE_HOME/bash` (or `~/.local/state/bash` when that
variable is unset), so new terminals show the refreshed question for the rest
of that calendar day. The normal daily selection takes over again the following
day.
The file has no header or comments. Empty fields, duplicate names and malformed The file has no header or comments. Empty fields, duplicate names and malformed
rows are errors. rows are errors.
Bash selects one entry deterministically from the local calendar date. Every Bash works through a persisted, randomly shuffled deck. Each question appears
terminal opened on the same day therefore shows the same question without once before the deck is shuffled again, and a new deck does not begin with the
requiring a state file. Editing the bank may change which question maps to a question that ended the previous one. The deck advances on a new calendar day
given date. or when `refreshpls` is run, while every terminal opened on the same day shows
the current persisted question. Editing the bank starts a newly shuffled deck.