Add a settings screen so nothing needs a text editor
All eighteen options are now reachable from the menu as a cursor list: arrows select, Space or Right cycles a value, q goes back, changes are written immediately. A numbered menu would have run out of digits. Three real bugs surfaced while building it, each found by testing against an actual pty rather than a pipe: - Labels went through printf as format strings, so the percent sign in "Minimum battery level (%)" was an invalid conversion. cau_msg_in now only treats a message as a format string when arguments were actually passed - otherwise any literal % a translator writes is a trap. - Mixing bash's line-mode read into a single-key interface left the following read -sn1 receiving nothing at all, reproducibly, so the screen froze after editing the package list. Replaced with a small line editor built on the same single-character reader. - Backspace was being swallowed: in canonical mode DEL is the ERASE character and the line discipline consumes it, and bash returns to canonical mode between each read -sn1. The interface now holds non-canonical mode for its whole lifetime and hands the terminal back only around actions that print or prompt, with a trap restoring it on Ctrl-C. Translations and config reads are memoized; the screen redraws every label on every keypress and a fork per lookup was the reason the redraw was slow enough to matter.
This commit is contained in:
1 parent
2eff62f9fd
commit
c308b7e286
8 files changed
+491
-26
No files matched your search
+24
-3
@@ -75,13 +75,34 @@ cau_msg() {
|
||||
cau_msg_in "$(cau_ui_locale)" "$@"
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
translated="$(LC_ALL="$locale" LANGUAGE="${locale%%.*}" gettext -- "$msgid" 2>/dev/null)"
|
||||
[[ -n $translated ]] || translated="$msgid"
|
||||
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" "$@"
|
||||
|
||||
Reference in new issue
Block a user