Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fa830284e | ||
|
|
c308b7e286 |
No files matched your search
@@ -8,7 +8,7 @@
|
||||
# Overridable so a packager can pass the version it is actually building
|
||||
# (`make VERSION=$pkgver`). The literal below is the fallback for builds
|
||||
# straight from a checkout, and is what a release tag has to carry.
|
||||
VERSION ?= 1.0.9
|
||||
VERSION ?= 1.1.1
|
||||
|
||||
PREFIX ?= /usr
|
||||
DESTDIR ?=
|
||||
|
||||
@@ -30,9 +30,14 @@ That opens a menu with the two switches there are:
|
||||
[3] Update now
|
||||
[4] Show log
|
||||
[5] Show current conditions
|
||||
[6] Settings
|
||||
[q] Quit
|
||||
```
|
||||
|
||||
Everything is configurable from **[6] Settings** — a cursor list covering all
|
||||
eighteen options, so nothing needs a text editor. Arrow keys select, Space or
|
||||
Right changes a value, `q` goes back; changes are written immediately.
|
||||
|
||||
The interface is fully translated; on a German system everything above appears
|
||||
in German.
|
||||
|
||||
|
||||
@@ -16,7 +16,10 @@ updated in the background, with no password prompt and no terminal.
|
||||
|
||||
Run without a command it opens a small interactive menu with the two switches
|
||||
that matter - automatic updates on/off and notifications on/off - plus the
|
||||
current status.
|
||||
current status, and a settings screen covering every remaining option so the
|
||||
configuration file never has to be edited by hand. In the settings screen the
|
||||
arrow keys select, Space or Right changes a value, and _q_ goes back; every
|
||||
change is written out immediately.
|
||||
|
||||
The actual work is done by a systemd system service. The timer ticks hourly;
|
||||
whether a tick does anything is decided by _UpdateInterval_ (daily by default).
|
||||
|
||||
@@ -269,3 +269,69 @@ msgstr ""
|
||||
|
||||
msgid "%d packages are being updated. Please leave the computer switched on until this is done."
|
||||
msgstr ""
|
||||
|
||||
msgid "Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "(none)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Up/Down select - Space or Right changes - q goes back"
|
||||
msgstr ""
|
||||
|
||||
msgid "Package names separated by spaces, empty to clear:"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify when an update starts"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify after a successful update"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify when something goes wrong"
|
||||
msgstr ""
|
||||
|
||||
msgid "Notify when a restart is needed"
|
||||
msgstr ""
|
||||
|
||||
msgid "Time between update runs"
|
||||
msgstr ""
|
||||
|
||||
msgid "Postpone while a game is running"
|
||||
msgstr ""
|
||||
|
||||
msgid "Only update on mains power"
|
||||
msgstr ""
|
||||
|
||||
msgid "Minimum battery level (%)"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update AUR packages"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update Flatpaks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Update AppImages"
|
||||
msgstr ""
|
||||
|
||||
msgid "Also rebuild -git packages"
|
||||
msgstr ""
|
||||
|
||||
msgid "AUR helper"
|
||||
msgstr ""
|
||||
|
||||
msgid "Resolve package conflicts automatically"
|
||||
msgstr ""
|
||||
|
||||
msgid "Trim the package cache"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cached versions to keep"
|
||||
msgstr ""
|
||||
|
||||
msgid "Remove packages nothing needs any more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Never update these packages"
|
||||
msgstr ""
|
||||
@@ -271,3 +271,69 @@ msgstr "Updates werden installiert"
|
||||
#, c-format
|
||||
msgid "%d packages are being updated. Please leave the computer switched on until this is done."
|
||||
msgstr "%d Pakete werden gerade aktualisiert. Bitte den Rechner so lange eingeschaltet lassen."
|
||||
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
msgid "(none)"
|
||||
msgstr "(keine)"
|
||||
|
||||
msgid "Up/Down select - Space or Right changes - q goes back"
|
||||
msgstr "Hoch/Runter wählen – Leertaste oder Rechts ändert – q zurück"
|
||||
|
||||
msgid "Package names separated by spaces, empty to clear:"
|
||||
msgstr "Paketnamen mit Leerzeichen getrennt, leer zum Löschen:"
|
||||
|
||||
msgid "Notify when an update starts"
|
||||
msgstr "Melden, wenn ein Update beginnt"
|
||||
|
||||
msgid "Notify after a successful update"
|
||||
msgstr "Melden nach erfolgreichem Update"
|
||||
|
||||
msgid "Notify when something goes wrong"
|
||||
msgstr "Melden, wenn etwas schiefgeht"
|
||||
|
||||
msgid "Notify when a restart is needed"
|
||||
msgstr "Melden, wenn ein Neustart nötig ist"
|
||||
|
||||
msgid "Time between update runs"
|
||||
msgstr "Abstand zwischen Update-Läufen"
|
||||
|
||||
msgid "Postpone while a game is running"
|
||||
msgstr "Verschieben, solange ein Spiel läuft"
|
||||
|
||||
msgid "Only update on mains power"
|
||||
msgstr "Nur am Stromnetz aktualisieren"
|
||||
|
||||
msgid "Minimum battery level (%)"
|
||||
msgstr "Mindest-Akkustand (%)"
|
||||
|
||||
msgid "Update AUR packages"
|
||||
msgstr "AUR-Pakete aktualisieren"
|
||||
|
||||
msgid "Update Flatpaks"
|
||||
msgstr "Flatpaks aktualisieren"
|
||||
|
||||
msgid "Update AppImages"
|
||||
msgstr "AppImages aktualisieren"
|
||||
|
||||
msgid "Also rebuild -git packages"
|
||||
msgstr "Auch -git-Pakete neu bauen"
|
||||
|
||||
msgid "AUR helper"
|
||||
msgstr "AUR-Helfer"
|
||||
|
||||
msgid "Resolve package conflicts automatically"
|
||||
msgstr "Paketkonflikte automatisch auflösen"
|
||||
|
||||
msgid "Trim the package cache"
|
||||
msgstr "Paket-Cache beschneiden"
|
||||
|
||||
msgid "Cached versions to keep"
|
||||
msgstr "Behaltene Versionen im Cache"
|
||||
|
||||
msgid "Remove packages nothing needs any more"
|
||||
msgstr "Nicht mehr benötigte Pakete entfernen"
|
||||
|
||||
msgid "Never update these packages"
|
||||
msgstr "Diese Pakete nie aktualisieren"
|
||||
+43
-1
@@ -75,13 +75,55 @@ cau_msg() {
|
||||
cau_msg_in "$(cau_ui_locale)" "$@"
|
||||
}
|
||||
|
||||
# cau_msg_into <locale> <msgid>
|
||||
# Plain lookup with the result in CAU_MSG_RESULT and no printf formatting.
|
||||
# For callers that redraw many labels per keypress, where wrapping cau_msg in a
|
||||
# command substitution would cost a fork per label.
|
||||
CAU_MSG_RESULT=''
|
||||
|
||||
cau_msg_into() {
|
||||
local locale="$1" msgid="$2" cachekey
|
||||
cachekey="${locale}"$'\x1f'"${msgid}"
|
||||
|
||||
if [[ -n ${CAU_MSG_CACHE[$cachekey]+set} ]]; then
|
||||
CAU_MSG_RESULT="${CAU_MSG_CACHE[$cachekey]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
CAU_MSG_RESULT="$(LC_ALL="$locale" LANGUAGE="${locale%%.*}" gettext -- "$msgid" 2>/dev/null)"
|
||||
[[ -n $CAU_MSG_RESULT ]] || CAU_MSG_RESULT="$msgid"
|
||||
CAU_MSG_CACHE[$cachekey]="$CAU_MSG_RESULT"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Translations are memoized. Every gettext lookup is a fork, and the settings
|
||||
# screen redraws forty-odd labels per keypress; without this the redraw takes
|
||||
# long enough that a keystroke arriving during it is lost when the terminal
|
||||
# switches back to single-character mode.
|
||||
declare -A CAU_MSG_CACHE=()
|
||||
|
||||
# cau_msg_in <locale> <msgid> [printf args...]
|
||||
cau_msg_in() {
|
||||
local locale="$1" msgid="$2" translated
|
||||
local locale="$1" msgid="$2" translated cachekey
|
||||
shift 2
|
||||
|
||||
cachekey="${locale}"$'\x1f'"${msgid}"
|
||||
if [[ -n ${CAU_MSG_CACHE[$cachekey]+set} ]]; then
|
||||
translated="${CAU_MSG_CACHE[$cachekey]}"
|
||||
else
|
||||
translated="$(LC_ALL="$locale" LANGUAGE="${locale%%.*}" gettext -- "$msgid" 2>/dev/null)"
|
||||
[[ -n $translated ]] || translated="$msgid"
|
||||
CAU_MSG_CACHE[$cachekey]="$translated"
|
||||
fi
|
||||
|
||||
# With no arguments the message is plain text, not a format string. Feeding
|
||||
# it to printf anyway turns any literal percent sign in it - "Battery (%)",
|
||||
# "100 % done" - into an invalid conversion, and that is a trap every
|
||||
# translator would eventually walk into.
|
||||
if (( $# == 0 )); then
|
||||
printf '%s' "$translated"
|
||||
return
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2059 # the format string is the translated message
|
||||
printf -- "$translated" "$@"
|
||||
|
||||
+40
-11
@@ -6,14 +6,39 @@
|
||||
# root-run daemon, and sourcing it would turn a stray line into arbitrary code
|
||||
# execution. The format is one "Key=Value" per line, '#' starts a comment.
|
||||
|
||||
# cau_config_get <Key> [default]
|
||||
cau_config_get() {
|
||||
local key="$1" default="${2:-}" val
|
||||
# The file is cached and parsed in-process rather than shelled out to sed on
|
||||
# every lookup. The settings screen reads every key on every redraw, and a fork
|
||||
# per key made the redraw slow enough to swallow keystrokes.
|
||||
CAU_CONFIG_CACHE=''
|
||||
CAU_CONFIG_CACHED=0
|
||||
|
||||
[[ -r $CAU_CONFIG ]] || { printf '%s\n' "$default"; return; }
|
||||
_cau_config_slurp() {
|
||||
(( CAU_CONFIG_CACHED )) && return 0
|
||||
CAU_CONFIG_CACHE=''
|
||||
[[ -r $CAU_CONFIG ]] && CAU_CONFIG_CACHE="$(< "$CAU_CONFIG")"
|
||||
CAU_CONFIG_CACHED=1
|
||||
return 0
|
||||
}
|
||||
|
||||
val="$(sed -nE "s/^[[:space:]]*${key}[[:space:]]*=[[:space:]]*(.*)$/\\1/p" \
|
||||
"$CAU_CONFIG" 2>/dev/null | tail -n1)"
|
||||
# _cau_config_lookup <Key> [default]
|
||||
# Result in CAU_CONFIG_VALUE. Assigning rather than printing matters on the
|
||||
# settings screen, which reads every key on every frame: a command substitution
|
||||
# there is a fork, and forks were the entire cost of a redraw.
|
||||
CAU_CONFIG_VALUE=''
|
||||
|
||||
_cau_config_lookup() {
|
||||
local key="$1" default="${2:-}" val='' line
|
||||
|
||||
CAU_CONFIG_VALUE="$default"
|
||||
[[ -r $CAU_CONFIG ]] || return 0
|
||||
_cau_config_slurp
|
||||
|
||||
# last assignment wins, matching the previous sed|tail behaviour
|
||||
while IFS= read -r line; do
|
||||
[[ $line == *"$key"* ]] || continue
|
||||
[[ $line =~ ^[[:space:]]*"$key"[[:space:]]*=(.*)$ ]] || continue
|
||||
val="${BASH_REMATCH[1]}"
|
||||
done <<< "$CAU_CONFIG_CACHE"
|
||||
|
||||
# strip a trailing comment and surrounding whitespace/quotes
|
||||
val="${val%%#*}"
|
||||
@@ -22,11 +47,14 @@ cau_config_get() {
|
||||
val="${val%\"}"
|
||||
val="${val#\"}"
|
||||
|
||||
if [[ -n $val ]]; then
|
||||
printf '%s\n' "$val"
|
||||
else
|
||||
printf '%s\n' "$default"
|
||||
fi
|
||||
[[ -n $val ]] && CAU_CONFIG_VALUE="$val"
|
||||
return 0
|
||||
}
|
||||
|
||||
# cau_config_get <Key> [default]
|
||||
cau_config_get() {
|
||||
_cau_config_lookup "$@"
|
||||
printf '%s\n' "$CAU_CONFIG_VALUE"
|
||||
}
|
||||
|
||||
# cau_config_bool <Key> <default: yes|no>
|
||||
@@ -78,6 +106,7 @@ cau_config_set() {
|
||||
fi
|
||||
|
||||
mv -f "$tmp" "$CAU_CONFIG"
|
||||
CAU_CONFIG_CACHED=0
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
+340
-18
@@ -7,6 +7,317 @@
|
||||
|
||||
CAU_UNIT="cachy-auto-update.timer"
|
||||
|
||||
# Terminal mode.
|
||||
#
|
||||
# bash flips the terminal into non-canonical mode for each `read -sn1` and back
|
||||
# out again in between. That gap matters: in canonical mode DEL is the ERASE
|
||||
# character, so the line discipline eats it instead of delivering it, and a
|
||||
# backspace typed while the interface was between reads simply vanished.
|
||||
# Holding non-canonical mode for the whole interface removes the gap.
|
||||
CAU_TERM_SAVED=''
|
||||
|
||||
cau_ui_term_raw() {
|
||||
cau_have stty || return 0
|
||||
[[ -t 0 ]] || return 0
|
||||
[[ -n $CAU_TERM_SAVED ]] && return 0
|
||||
|
||||
CAU_TERM_SAVED="$(stty -g 2>/dev/null)" || { CAU_TERM_SAVED=''; return 0; }
|
||||
stty -icanon -echo min 1 time 0 2>/dev/null || true
|
||||
}
|
||||
|
||||
cau_ui_term_restore() {
|
||||
[[ -n $CAU_TERM_SAVED ]] || return 0
|
||||
stty "$CAU_TERM_SAVED" 2>/dev/null || true
|
||||
CAU_TERM_SAVED=''
|
||||
}
|
||||
|
||||
# Runs an action with the terminal handed back to normal line mode, so anything
|
||||
# it prints - or prompts for - behaves the way a program expects.
|
||||
cau_ui_cooked() {
|
||||
cau_ui_term_restore
|
||||
"$@"
|
||||
local rc=$?
|
||||
cau_ui_term_raw
|
||||
return $rc
|
||||
}
|
||||
|
||||
# cau_read_key
|
||||
# One keypress, resolved to a symbolic name: a literal character, or one of
|
||||
# up/down/left/right/enter/space/escape. Arrow keys arrive as ESC [ A, so the
|
||||
# tail of the sequence is consumed here rather than being mistaken for three
|
||||
# separate presses.
|
||||
cau_read_key() {
|
||||
local k rest
|
||||
|
||||
IFS= read -rsn1 k || return 1
|
||||
|
||||
case "$k" in
|
||||
$'\e')
|
||||
if IFS= read -rsn2 -t 0.05 rest; then
|
||||
case "$rest" in
|
||||
'[A') printf 'up\n' ;;
|
||||
'[B') printf 'down\n' ;;
|
||||
'[C') printf 'right\n' ;;
|
||||
'[D') printf 'left\n' ;;
|
||||
*) printf 'escape\n' ;;
|
||||
esac
|
||||
else
|
||||
printf 'escape\n'
|
||||
fi
|
||||
;;
|
||||
# Enter is an empty read in cooked mode and a carriage return in raw
|
||||
# mode, depending on whether the terminal is translating it.
|
||||
''|$'\r') printf 'enter\n' ;;
|
||||
$'\x7f'|$'\b') printf 'backspace\n' ;;
|
||||
' ') printf 'space\n' ;;
|
||||
*) printf '%s\n' "$k" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# cau_ui_read_line <initial>
|
||||
# A minimal line editor built on cau_read_key, with the result in
|
||||
# CAU_LINE_RESULT.
|
||||
#
|
||||
# This exists instead of bash's own `read -r` because mixing line mode into a
|
||||
# single-key interface breaks it: after one cooked-mode read the following
|
||||
# `read -sn1` stops receiving keystrokes entirely, reproducibly, on a real pty.
|
||||
# Never leaving single-character mode side-steps that completely.
|
||||
CAU_LINE_RESULT=''
|
||||
|
||||
cau_ui_read_line() {
|
||||
local buf="${1:-}" key
|
||||
|
||||
CAU_LINE_RESULT=''
|
||||
printf '%s' "$buf"
|
||||
|
||||
while true; do
|
||||
key="$(cau_read_key)" || { printf '\n'; return 1; }
|
||||
|
||||
case "$key" in
|
||||
enter)
|
||||
printf '\n'
|
||||
CAU_LINE_RESULT="$buf"
|
||||
return 0
|
||||
;;
|
||||
escape)
|
||||
printf '\n'
|
||||
return 1
|
||||
;;
|
||||
backspace)
|
||||
if [[ -n $buf ]]; then
|
||||
buf="${buf%?}"
|
||||
printf '\b \b'
|
||||
fi
|
||||
;;
|
||||
space)
|
||||
buf+=' '
|
||||
printf ' '
|
||||
;;
|
||||
up|down|left|right) ;; # no cursor movement in this editor
|
||||
*)
|
||||
# a single printable character; control keys arrive as names
|
||||
[[ ${#key} -eq 1 ]] || continue
|
||||
buf+="$key"
|
||||
printf '%s' "$key"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Everything that can be changed without opening a text editor.
|
||||
# Format: Key|type|default|label-msgid
|
||||
# type is bool, choice:<space separated values>, or text.
|
||||
CAU_SETTINGS=(
|
||||
"NotifyOnStart|bool|yes|Notify when an update starts"
|
||||
"NotifyOnSuccess|bool|yes|Notify after a successful update"
|
||||
"NotifyOnError|bool|yes|Notify when something goes wrong"
|
||||
"NotifyReboot|bool|yes|Notify when a restart is needed"
|
||||
"UpdateInterval|choice:6h 12h 1d 2d 1w|1d|Time between update runs"
|
||||
"SkipWhenGaming|bool|yes|Postpone while a game is running"
|
||||
"RequireAC|bool|no|Only update on mains power"
|
||||
"MinBatteryPercent|choice:0 20 30 40 50 60 70 80|40|Minimum battery level (%)"
|
||||
"UpdateAUR|bool|yes|Update AUR packages"
|
||||
"UpdateFlatpak|bool|yes|Update Flatpaks"
|
||||
"UpdateAppImages|bool|yes|Update AppImages"
|
||||
"UpdateDevel|bool|no|Also rebuild -git packages"
|
||||
"AURHelper|choice:auto paru yay pikaur|auto|AUR helper"
|
||||
"AutoResolveConflicts|bool|yes|Resolve package conflicts automatically"
|
||||
"CleanCache|bool|yes|Trim the package cache"
|
||||
"KeepOldPackages|choice:0 1 2 3 5|3|Cached versions to keep"
|
||||
"RemoveOrphans|bool|no|Remove packages nothing needs any more"
|
||||
"IgnorePkg|text||Never update these packages"
|
||||
)
|
||||
|
||||
_cau_is_true() {
|
||||
case "${1,,}" in
|
||||
yes|y|true|1|on|enabled) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# _cau_setting_display <type> <value>
|
||||
# Result in CAU_SETTING_SHOWN. The three constant strings are resolved once by
|
||||
# the caller into CAU_LBL_*; looking them up here would put a translation call
|
||||
# on the per-line path.
|
||||
CAU_SETTING_SHOWN=''
|
||||
CAU_LBL_ON=''
|
||||
CAU_LBL_OFF=''
|
||||
CAU_LBL_NONE=''
|
||||
|
||||
_cau_setting_display() {
|
||||
local type="$1" value="$2"
|
||||
|
||||
case "$type" in
|
||||
bool)
|
||||
if _cau_is_true "$value"; then
|
||||
CAU_SETTING_SHOWN="${CAU_C_GREEN}${CAU_LBL_ON}${CAU_C_RESET}"
|
||||
else
|
||||
CAU_SETTING_SHOWN="${CAU_C_DIM}${CAU_LBL_OFF}${CAU_C_RESET}"
|
||||
fi
|
||||
;;
|
||||
text)
|
||||
if [[ -n $value ]]; then
|
||||
CAU_SETTING_SHOWN="$value"
|
||||
else
|
||||
CAU_SETTING_SHOWN="${CAU_C_DIM}${CAU_LBL_NONE}${CAU_C_RESET}"
|
||||
fi
|
||||
;;
|
||||
*) CAU_SETTING_SHOWN="$value" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# _cau_setting_cycle <type> <value> <direction: 1|-1>
|
||||
# The next value for this setting. Choices wrap around, so one key is enough to
|
||||
# reach everything without needing a second one for the other direction.
|
||||
_cau_setting_cycle() {
|
||||
local type="$1" value="$2" dir="$3"
|
||||
|
||||
if [[ $type == bool ]]; then
|
||||
_cau_is_true "$value" && printf 'no\n' || printf 'yes\n'
|
||||
return
|
||||
fi
|
||||
|
||||
local -a choices
|
||||
read -r -a choices <<< "${type#choice:}"
|
||||
(( ${#choices[@]} )) || { printf '%s\n' "$value"; return; }
|
||||
|
||||
local i idx=0
|
||||
for i in "${!choices[@]}"; do
|
||||
[[ ${choices[i]} == "$value" ]] && { idx=$i; break; }
|
||||
done
|
||||
|
||||
idx=$(( (idx + dir + ${#choices[@]}) % ${#choices[@]} ))
|
||||
printf '%s\n' "${choices[idx]}"
|
||||
}
|
||||
|
||||
# cau_ui_settings
|
||||
# A cursor list rather than a numbered menu: there are eighteen settings, and
|
||||
# numbering them would run out of digits and force paging.
|
||||
#
|
||||
# The frame is assembled in memory and written once. Everything constant - the
|
||||
# specs, the translated labels, the clear sequence - is resolved before the
|
||||
# loop, and the values are re-read only after something actually changes.
|
||||
# Drawing the naive way cost a command substitution per label per frame, which
|
||||
# measured 435 ms per keypress: arrow keys felt like the console was reloading,
|
||||
# because in effect it was.
|
||||
cau_ui_settings() {
|
||||
local count=${#CAU_SETTINGS[@]}
|
||||
local -a names=() types=() defaults=() labels=()
|
||||
local -a values=()
|
||||
local spec name type default label locale i key frame row pad dirty=1 cursor=0
|
||||
|
||||
locale="$(cau_ui_locale)"
|
||||
cau_msg_into "$locale" "ON"; CAU_LBL_ON="$CAU_MSG_RESULT"
|
||||
cau_msg_into "$locale" "OFF"; CAU_LBL_OFF="$CAU_MSG_RESULT"
|
||||
cau_msg_into "$locale" "(none)"; CAU_LBL_NONE="$CAU_MSG_RESULT"
|
||||
|
||||
for spec in "${CAU_SETTINGS[@]}"; do
|
||||
IFS='|' read -r name type default label <<< "$spec"
|
||||
names+=("$name"); types+=("$type"); defaults+=("$default")
|
||||
cau_msg_into "$locale" "$label"
|
||||
labels+=("$CAU_MSG_RESULT")
|
||||
done
|
||||
|
||||
local title hint
|
||||
cau_msg_into "$locale" "Settings"; title="$CAU_MSG_RESULT"
|
||||
cau_msg_into "$locale" "Up/Down select - Space or Right changes - q goes back"
|
||||
hint="$CAU_MSG_RESULT"
|
||||
|
||||
# the terminfo clear string, fetched once instead of forking per frame
|
||||
local clearseq
|
||||
clearseq="$(clear 2>/dev/null)" || clearseq=$'\033[H\033[2J'
|
||||
|
||||
while true; do
|
||||
if (( dirty )); then
|
||||
for i in "${!names[@]}"; do
|
||||
_cau_config_lookup "${names[i]}" "${defaults[i]}"
|
||||
values[i]="$CAU_CONFIG_VALUE"
|
||||
done
|
||||
dirty=0
|
||||
fi
|
||||
|
||||
frame="$clearseq"$'\n'"${CAU_C_BOLD}${CAU_C_BLUE} ${title}${CAU_C_RESET}"$'\n\n'
|
||||
|
||||
local marker selected="${CAU_C_BLUE}▸${CAU_C_RESET} "
|
||||
for i in "${!names[@]}"; do
|
||||
_cau_setting_display "${types[i]}" "${values[i]}"
|
||||
pad=$(( 42 - ${#labels[i]} ))
|
||||
(( pad < 0 )) && pad=0
|
||||
if (( i == cursor )); then marker="$selected"; else marker=' '; fi
|
||||
printf -v row ' %s%s%*s %s' \
|
||||
"$marker" "${labels[i]}" "$pad" '' "$CAU_SETTING_SHOWN"
|
||||
frame+="$row"$'\n'
|
||||
done
|
||||
|
||||
frame+=$'\n'" ${CAU_C_DIM}${hint}${CAU_C_RESET}"$'\n'
|
||||
printf '%s' "$frame"
|
||||
|
||||
key="$(cau_read_key)" || return 0
|
||||
|
||||
type="${types[cursor]}"
|
||||
name="${names[cursor]}"
|
||||
|
||||
case "$key" in
|
||||
up|k) cursor=$(( (cursor - 1 + count) % count )) ;;
|
||||
down|j) cursor=$(( (cursor + 1) % count )) ;;
|
||||
space|enter|right|l)
|
||||
if [[ $type == text ]]; then
|
||||
cau_ui_edit_text "$name" "${values[cursor]}"
|
||||
else
|
||||
cau_config_set "$name" "$(_cau_setting_cycle "$type" "${values[cursor]}" 1)" \
|
||||
|| { cau_bad "$(cau_msg "Could not write the configuration file.")"; cau_pause; }
|
||||
fi
|
||||
dirty=1
|
||||
;;
|
||||
left|h)
|
||||
if [[ $type != text ]]; then
|
||||
cau_config_set "$name" "$(_cau_setting_cycle "$type" "${values[cursor]}" -1)" \
|
||||
|| { cau_bad "$(cau_msg "Could not write the configuration file.")"; cau_pause; }
|
||||
dirty=1
|
||||
fi
|
||||
;;
|
||||
q|Q|escape) return 0 ;;
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# cau_ui_edit_text <key> <current>
|
||||
# The one setting that is a free-text list rather than a choice.
|
||||
cau_ui_edit_text() {
|
||||
local name="$1" current="$2"
|
||||
|
||||
printf '\n %s\n' "$(cau_msg "Package names separated by spaces, empty to clear:")"
|
||||
printf ' > '
|
||||
|
||||
# pre-filled with the current value so it can be corrected rather than
|
||||
# retyped; Escape leaves it unchanged
|
||||
if cau_ui_read_line "$current"; then
|
||||
cau_config_set "$name" "$CAU_LINE_RESULT" \
|
||||
|| { cau_bad "$(cau_msg "Could not write the configuration file.")"; cau_pause; }
|
||||
fi
|
||||
}
|
||||
|
||||
# _cau_row <label> <value>
|
||||
# printf's %-28s pads by bytes, so a label containing "ü" comes out one column
|
||||
# short. ${#s} counts characters in a UTF-8 locale, so the padding is computed
|
||||
@@ -141,6 +452,10 @@ cau_ui_status_conditions() {
|
||||
cau_ui_menu() {
|
||||
local choice
|
||||
|
||||
cau_ui_term_raw
|
||||
# restore the terminal even if this exits through Ctrl-C or an error
|
||||
trap 'cau_ui_term_restore' EXIT INT TERM
|
||||
|
||||
while true; do
|
||||
cau_config_load
|
||||
|
||||
@@ -153,45 +468,52 @@ cau_ui_menu() {
|
||||
printf ' [3] %s\n' "$(cau_msg "Update now")"
|
||||
printf ' [4] %s\n' "$(cau_msg "Show log")"
|
||||
printf ' [5] %s\n' "$(cau_msg "Show current conditions")"
|
||||
printf ' [6] %s\n' "$(cau_msg "Settings")"
|
||||
printf ' [q] %s\n' "$(cau_msg "Quit")"
|
||||
printf '\n > '
|
||||
|
||||
# One keypress, no Enter. -s keeps the raw character out of the
|
||||
# display so the echo below is the only thing printed, and a failing
|
||||
# read means EOF (Ctrl-D, or a script piping input) - that quits.
|
||||
read -rsn1 choice || { printf '\n'; return 0; }
|
||||
# One keypress, no Enter. A failing read means EOF (Ctrl-D, or a
|
||||
# script piping input), which quits.
|
||||
choice="$(cau_read_key)" || {
|
||||
printf '\n'; cau_ui_term_restore; trap - EXIT INT TERM; return 0
|
||||
}
|
||||
case "$choice" in
|
||||
enter|space|up|down|left|right|escape) choice='' ;;
|
||||
esac
|
||||
printf '%s\n' "$choice"
|
||||
|
||||
# Actions run in normal line mode: they print program output and some
|
||||
# of them prompt, neither of which behaves in raw mode.
|
||||
case "$choice" in
|
||||
# The two switches flip and return straight to the menu, where the
|
||||
# status block shows the result. Only a warning or an error holds
|
||||
# the screen (see CAU_UI_NEEDS_ACK).
|
||||
1)
|
||||
CAU_UI_NEEDS_ACK=''
|
||||
if [[ $CFG_ENABLED == yes ]]; then cau_do_disable; else cau_do_enable; fi
|
||||
if [[ $CFG_ENABLED == yes ]]; then
|
||||
cau_ui_cooked cau_do_disable
|
||||
else
|
||||
cau_ui_cooked cau_do_enable
|
||||
fi
|
||||
if [[ -n $CAU_UI_NEEDS_ACK ]]; then cau_pause; fi
|
||||
;;
|
||||
2)
|
||||
CAU_UI_NEEDS_ACK=''
|
||||
if [[ $CFG_NOTIFICATIONS == yes ]]; then
|
||||
cau_do_notifications off
|
||||
cau_ui_cooked cau_do_notifications off
|
||||
else
|
||||
cau_do_notifications on
|
||||
cau_ui_cooked cau_do_notifications on
|
||||
fi
|
||||
if [[ -n $CAU_UI_NEEDS_ACK ]]; then cau_pause; fi
|
||||
;;
|
||||
3) cau_do_run --force; cau_pause ;;
|
||||
4) cau_do_log; cau_pause ;;
|
||||
3) cau_ui_cooked cau_do_run --force; cau_pause ;;
|
||||
4) cau_ui_cooked cau_do_log; cau_pause ;;
|
||||
5) cau_ui_status_conditions; cau_pause ;;
|
||||
q|Q) return 0 ;;
|
||||
$'\e')
|
||||
# Arrow keys and friends arrive as ESC [ X. Swallow the rest so
|
||||
# one keypress does not redraw the menu three times. Escape is
|
||||
# deliberately not a quit key: that would make a stray arrow
|
||||
# key close the menu.
|
||||
read -rsn2 -t 0.05 _ 2>/dev/null || true
|
||||
;;
|
||||
# Anything else, Enter included, just redraws.
|
||||
6) cau_ui_settings ;;
|
||||
q|Q) cau_ui_term_restore; trap - EXIT INT TERM; return 0 ;;
|
||||
# Anything else - Enter, arrow keys, stray characters - just
|
||||
# redraws. Escape is deliberately not a quit key, so a mistyped
|
||||
# arrow key cannot close the menu.
|
||||
*) ;;
|
||||
esac
|
||||
done
|
||||
|
||||
Reference in new issue
Block a user