bash/bashrc.d/90-memory-question.bash
2026-10-28 20:04:29 +00:00

182 lines
4.4 KiB
Bash

# shellcheck shell=bash
_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_names=()
_memory_questions=()
_memory_answers=()
declare -A _memory_seen=()
_memory_invalid=0
_memory_line_number=0
if [[ -r "$_memory_file" ]]; then
while IFS=$'\t' read -r _memory_name _memory_question _memory_answer _memory_extra; do
((_memory_line_number++))
if [[ -z "$_memory_name$_memory_question$_memory_answer$_memory_extra" ]]; then
continue
fi
if [[ -z "$_memory_name" || -z "$_memory_question" || -z "$_memory_answer" || -n "$_memory_extra" ]]; then
printf 'Invalid memory question on line %d.\n' "$_memory_line_number" >&2
_memory_invalid=1
continue
fi
if [[ -n ${_memory_seen[$_memory_name]:-} ]]; then
printf 'Duplicate memory question for %s on line %d.\n' "$_memory_name" "$_memory_line_number" >&2
_memory_invalid=1
continue
fi
_memory_seen[$_memory_name]=1
_memory_names+=("$_memory_name")
_memory_questions+=("$_memory_question")
_memory_answers+=("$_memory_answer")
done < "$_memory_file"
else
printf 'Memory question file is unavailable: %s\n' "$_memory_file" >&2
_memory_invalid=1
fi
if [[ $_memory_invalid -eq 0 && ${#_memory_names[@]} -gt 0 ]]; then
_memory_load_state() {
local -a fields=() state_deck=()
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() {
printf '%s\n' "$_MEMORY_ANSWER"
}
refreshpls() {
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
unset _memory_file
unset _memory_invalid _memory_line_number _memory_name _memory_question
unset _memory_answer _memory_extra _memory_today