summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorAnders Betts <anders.betts@gmail.com>2026-09-23 10:58:17 +0200
committerAnders Betts <anders.betts@gmail.com>2026-09-23 10:58:17 +0200
commit71a702f375750829c634b552217c9925d549828b (patch)
tree2b963da1d0110ed43920722ba4193ee9c79f2521 /scripts
parent8ccb6d58d8e2f1c65dfd7ab5f0eb7d93f1f19def (diff)
downloadbokf-71a702f375750829c634b552217c9925d549828b.tar.gz
bokf-71a702f375750829c634b552217c9925d549828b.zip
tui: context menu on → / ^O; no F-keys, ^N or ^Enter
→ (where no caret uses it) and ^O (everywhere, also in table cells) open "Åtgärder": a box at the right edge with every action of the view and its key. Screens declare their actions with tui_set_actions(); choosing one feeds its key to the widget, so the menu and accelerators share one path. Function keys, Ctrl+N (now n), Ctrl+Enter and Ctrl+F are gone and no extended keyboard protocol is enabled, so the TUI works in a browser terminal; save/post/validate/preview/template/attach are menu actions. make check rejects F-keys, ^N and ^Enter in clients/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/check-consistency.sh25
-rwxr-xr-xscripts/tui-golden.py134
2 files changed, 100 insertions, 59 deletions
diff --git a/scripts/check-consistency.sh b/scripts/check-consistency.sh
index 3ca9b0c..d8054e2 100755
--- a/scripts/check-consistency.sh
+++ b/scripts/check-consistency.sh
@@ -6,7 +6,10 @@
# "Command", and vice versa;
# 2. every error code passed to fail()/failf()/add_error() in src/*.c is
# documented in PROTOCOL.md section 5.3, and vice versa (documented but
-# unused codes are warnings only, some are reserved).
+# unused codes are warnings only, some are reserved);
+# 3. the TUI uses no key a browser terminal cannot deliver: no function
+# keys (KEY_F), no Ctrl+N and no Ctrl+Enter (docs/TUI-GUIDELINES.md
+# "Keys and the web").
#
# Run from the repo root: sh scripts/check-consistency.sh
# Exits 0 when there is no drift, 1 when drift is found, 2 on parse errors.
@@ -19,6 +22,8 @@
# PROTOCOL_MD protocol document, default $REPO_ROOT/docs/PROTOCOL.md
# SRC_GLOB shell glob of sources scanned for error codes,
# default $REPO_ROOT/src/*.c
+# CLIENTS_GLOB shell glob of TUI sources scanned for keys,
+# default $REPO_ROOT/clients/*.c
#
# Commands deliberately kept out of the PROTOCOL.md tables. Prefer documenting
# the command in a table over adding it here. Keep sorted, space separated.
@@ -188,6 +193,24 @@ else
echo "(none)"
fi
+section "keys: F-keys, Ctrl+N or Ctrl+Enter used in the TUI"
+CLIENTS_GLOB=${CLIENTS_GLOB:-"$REPO_ROOT/clients/*.c"}
+: > "$tmp/bad_keys"
+for f in $CLIENTS_GLOB; do
+ [ -f "$f" ] || continue
+ grep -nE 'KEY_F\(|TUI_KEY_CTRL_N|KEY_CTRL_N|CTRL_ENTER' "$f" |
+ sed "s|^|$f:|" >> "$tmp/bad_keys" || true
+done
+if [ -s "$tmp/bad_keys" ]; then
+ while IFS= read -r line; do
+ echo "key: not web-safe: $line"
+ problems=$((problems + 1))
+ done < "$tmp/bad_keys"
+ status=1
+else
+ echo "(none)"
+fi
+
section "warnings (not failures)"
if [ -s "$tmp/code_unused" ]; then
while IFS= read -r code; do
diff --git a/scripts/tui-golden.py b/scripts/tui-golden.py
index b6aaada..bce00eb 100755
--- a/scripts/tui-golden.py
+++ b/scripts/tui-golden.py
@@ -57,12 +57,8 @@ KEYS = {
"pgup": "\x1b[5~",
"pgdn": "\x1b[6~",
"ctrlc": "\x03",
- "ctrln": "\x0e",
- "ctrlenter": "\x1b[27;5;13~",
- "ctrlenter-kitty": "\x1b[13;5u",
- "f5": "\x1b[15~",
- "f9": "\x1b[20~",
- "f2": "\x1bOQ",
+ "ctrlo": "\x0f", # context menu, also inside a table cell
+ "f5": "\x1b[15~", # only to prove that F-keys do nothing
"backspace": "\x7f",
"tab": "\t",
}
@@ -120,7 +116,7 @@ SCENARIOS = [
},
{
"keys": ["enter"],
- "expect": ["piltangenter/PgUp/PgDn rullar", "kvitto"],
+ "expect": ["upp/ned/PgUp/PgDn rullar", "kvitto"],
},
{
"keys": ["esc"],
@@ -140,7 +136,7 @@ SCENARIOS = [
},
{
"keys": ["enter"],
- "expect": ["piltangenter/PgUp/PgDn rullar", "kvitto"],
+ "expect": ["upp/ned/PgUp/PgDn rullar", "kvitto"],
},
{
"keys": ["esc"],
@@ -184,7 +180,7 @@ SCENARIOS = [
"expect": ["Bankavstämning", "GOLDEN INSÄTTNING", "CDON"],
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Nytt verifikat", "GOLDEN INSÄTTNING", "123,00",
"1930"],
},
@@ -224,14 +220,19 @@ SCENARIOS = [
"expect": ["Bankavstämning", "CDON", "1 omatchade"],
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Nytt verifikat", "CDON", "24,09", "1930"],
},
{
"keys": ["\t\t\t\t\t\t\t", "3001", "\t", "24,09"],
},
{
- "keys": ["ctrlenter"],
+ "keys": ["ctrlo"],
+ "expect": ["Åtgärder", "Bokför", "Validera (torrkörning)",
+ "Hämta mall…"],
+ },
+ {
+ "keys": ["enter"],
"expect": ["Bokfört"],
},
{
@@ -243,7 +244,7 @@ SCENARIOS = [
"expect": ["→ A2", "0 omatchade"],
},
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Transaktionen är redan matchad."],
},
{
@@ -268,7 +269,7 @@ SCENARIOS = [
"expect": ["Kunder", "Testkund AB"],
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny kund", "<UTKAST>"],
},
{
@@ -284,11 +285,11 @@ SCENARIOS = [
"expect": ["<UTKAST> Utkastkund"],
},
{
- "keys": ["f2"],
- "expect": ["Åtgärder", "Öppna", "Radera utkast"],
+ "keys": ["right"],
+ "expect": ["Åtgärder", "Radera utkast", "Öppna", "Enter"],
},
{
- "keys": ["down", "enter"],
+ "keys": ["enter"],
"expect": ["Radera utkastet?"],
},
{
@@ -303,7 +304,7 @@ SCENARIOS = [
"expect": ["Kunder", "Testkund AB"],
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny kund", "<UTKAST>"],
},
{
@@ -311,7 +312,11 @@ SCENARIOS = [
"expect": ["Sparad kund", "<UTKAST>"],
},
{
- "keys": ["f9"],
+ "keys": ["right"],
+ "expect": ["Åtgärder", "Spara", "Validera"],
+ },
+ {
+ "keys": ["enter"],
"expect": ["Sparat."],
},
{
@@ -325,7 +330,7 @@ SCENARIOS = [
"screen": "invoices",
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny faktura", "Kund"],
},
],
@@ -363,7 +368,7 @@ SCENARIOS = [
"Betalning faktura"],
},
{
- "keys": ["f9"],
+ "keys": ["ctrlo", "enter"],
"expect": ["Bokfört"],
},
{
@@ -382,11 +387,11 @@ SCENARIOS = [
"expect": ["Anställda", "Testanställd", "Ny anställd"],
},
{
- "name": "employee-new-f9",
+ "name": "employee-new-save",
"screen": "employees",
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny anställd", "Personnummer"],
},
{
@@ -398,7 +403,7 @@ SCENARIOS = [
"expect": ["19900101-1234"],
},
{
- "keys": ["f9"],
+ "keys": ["right", "enter"],
"expect": ["Anställd skapad."],
},
{
@@ -408,32 +413,6 @@ SCENARIOS = [
],
},
{
- "name": "employee-new-kitty",
- "screen": "employees",
- "steps": [
- {
- "keys": ["ctrln"],
- "expect": ["Ny anställd", "Personnummer"],
- },
- {
- "keys": ["enter", "Kitty Person", "enter"],
- "expect": ["Kitty Person"],
- },
- {
- "keys": ["down", "enter", "19900202-5678", "enter"],
- "expect": ["19900202-5678"],
- },
- {
- "keys": ["ctrlenter-kitty"],
- "expect": ["Anställd skapad."],
- },
- {
- "keys": ["enter"],
- "expect": ["Anställda", "Kitty Person"],
- },
- ],
- },
- {
"name": "company",
"screen": "company",
"expect": ["Bolaget", "Företagsuppgifter", "Fakturauppgifter",
@@ -515,11 +494,15 @@ SCENARIOS = [
"screen": "payroll",
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny lönekörning", "Period", "Bokför körning"],
},
{
- "keys": ["f5"],
+ "keys": ["right"],
+ "expect": ["Åtgärder", "Förhandsvisa", "Bokför körning…"],
+ },
+ {
+ "keys": ["enter"],
"expect": ["Testanställd", "30 000,00", "Avgifter"],
},
{
@@ -527,7 +510,7 @@ SCENARIOS = [
"expect": ["Ny lönekörning", "Bokför körning"],
},
{
- "keys": ["ctrlenter"],
+ "keys": ["right", "down", "enter"],
"expect": ["Bokför lönekörningen"],
},
{
@@ -646,13 +629,49 @@ SCENARIOS = [
],
},
{
+ # → opens the context menu with the screen's actions first and the
+ # key of each action; choosing one is the same as pressing its key.
+ # F-keys do nothing (browsers own them).
+ "name": "context-menu",
+ "screen": "vouchers",
+ "expect": ["sorterade på nummer, stigande"],
+ "steps": [
+ {
+ "keys": ["right"],
+ "expect": ["Åtgärder", "Nytt verifikat", "Byt sortering",
+ "Gå till rad / sök", "Tillbaka"],
+ },
+ {
+ "keys": ["esc"],
+ "expect": ["Enter = öppna → = åtgärder"],
+ },
+ {
+ "keys": ["right", "down", "enter"],
+ "expect": ["sorterade på nummer, fallande"],
+ },
+ {
+ "keys": ["home", "enter", "right"],
+ "expect": ["Rätta (ändringsverifikat)…", "Bifoga fil…",
+ "Nästa verifikat"],
+ },
+ {
+ "keys": ["left"],
+ "expect": ["n = nytt c = rätta a = bifoga"],
+ },
+ {
+ "keys": ["esc", "f5", "s", "s", "s"],
+ "expect": ["sorterade på nummer, stigande"],
+ },
+ ],
+ },
+ {
# Backspace in a freshly opened field edits the value; the next
# key must not replace everything.
"name": "form-edit-backspace",
"screen": "customers",
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Ny kund", "<UTKAST>"],
},
{
@@ -672,7 +691,7 @@ SCENARIOS = [
"screen": "vouchers",
"steps": [
{
- "keys": ["ctrln"],
+ "keys": ["n"],
"expect": ["Nytt verifikat", "Datum", "Konto"],
},
{
@@ -1355,10 +1374,9 @@ def main(argv):
report_failure(name, missing, "", before)
failures += 1
continue
- if (b"\x1b[>4;2m" not in app.raw or
- b"\x1b[>1u" not in app.raw):
- report_failure(name, ["keyboard protocol enable "
- "sequence"], "", before)
+ if (b"\x1b[>4;2m" in app.raw or b"\x1b[>1u" in app.raw):
+ report_failure(name, ["no extended keyboard protocol "
+ "(legacy keys only)"], "", before)
failures += 1
continue
current = before