# 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