182 lines
4.4 KiB
Bash
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
|