summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/DECISIONS.md14
-rw-r--r--docs/PROTOCOL.md63
-rw-r--r--docs/STATE.md30
-rw-r--r--docs/TUI-GUIDELINES.md164
4 files changed, 177 insertions, 94 deletions
diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md
index 5499610..c18f49b 100644
--- a/docs/DECISIONS.md
+++ b/docs/DECISIONS.md
@@ -261,6 +261,20 @@ kept verbatim from the STATE.md they were pruned from (2026-09-21).
row, the `F2` menu, delete from list and editor); the other screens
follow.
+29. **Context menu and web-safe keys (2026-09-23)**: `→` opens a context
+ menu ("Åtgärder") where no caret uses the arrow, `^O` everywhere
+ (also in table cells); it is a box at the right edge listing every
+ action with its key, so it doubles as the hotkey list. Choosing an
+ action feeds its key to the widget, so the menu and the accelerator
+ share one path. All function keys are removed (F2 menu, F4 mall, F5
+ refresh/validate/preview, F7, F9 save/post) and so are `Ctrl+N` (now
+ `n`), `Ctrl+Enter` and `Ctrl+F`; the extended keyboard protocols are no
+ longer enabled. Reason: the TUI is to be served in a browser terminal
+ for users outside the home network (the owner and Petter first, others
+ later), and browsers own the F-keys and `Ctrl+N`/`T`/`W`. Supersedes
+ the key parts of #11 and #28; `make check` rejects F-keys, `^N` and
+ `^Enter` in `clients/`.
+
## Completed work formerly listed under "Pending decisions"
- Attachments are complete: download (voucher detail `f`, Underlag `Enter`,
diff --git a/docs/PROTOCOL.md b/docs/PROTOCOL.md
index 9ab9620..709a475 100644
--- a/docs/PROTOCOL.md
+++ b/docs/PROTOCOL.md
@@ -954,9 +954,10 @@ commands. Implemented screens (0.1.0-dev):
`voucher.list` calls) and `s` cycles its sort order (number or date,
ascending or descending, remembered in `tui.conf`); in the detail view
up/down step to the previous/next voucher in that order.
-- **Nytt verifikat** — row editor with live balance display, F5 dry-run
- validation and F9 posting; one `client_ref` per form makes retries safe.
- F4 applies a konteringsmall (prompts for template and `x`).
+- **Nytt verifikat** — row editor with live balance display; the context
+ menu (`^O`) offers Bokför, Validera (dry run), Hämta mall… (prompts for
+ template and `x`) and Bifoga fil…; one `client_ref` per form makes
+ retries safe.
- **Ingående balans** — the effective opening balances of the selected
fiscal year (carry-forward plus any `IB` vouchers, as the reports compute
them); enter accounts with signed amounts (positive debit, negative
@@ -967,7 +968,8 @@ commands. Implemented screens (0.1.0-dev):
as `YYYY-MM-DD - YYYY-MM-DD` (plus label and open/closed) so broken fiscal
years are visible. All screens then work in the selected year.
- **Mallar** — list, create and edit templates in the same form style as
- vouchers (Tab, dynamic rows, F7 clear row, F5 validate, F9 save); archive
+ vouchers (Tab, dynamic rows, `^X` clear row, Validera and Spara in the
+ context menu); archive
keeps the template but hides it from the list.
- **Underlag** — inbox of unlinked attachments; `a` uploads a file and
Enter opens **Granska** (text in a pager, other files in the desktop
@@ -976,47 +978,49 @@ commands. Implemented screens (0.1.0-dev):
- **Bankavstämning** — imported bank transactions (`bank.import`) matched
against vouchers on the bank account, with suggestions; Enter matches the
suggested voucher (or picks another), `u` unmatches, `a` imports a SEB CSV.
- `Ctrl+N` (or the last row `Skapa nytt verifikat…` in the match list) opens
+ `n` (or the last row `Skapa nytt verifikat…` in the match list) opens
**Nytt verifikat** prefilled with the transaction's date, text, signed
amount and bank account; posting it auto-matches the new voucher and
returns to the list. A failed auto-match keeps the posted voucher and
shows the server error.
- **Fakturor** — invoice list (`invoice.list`, newest first) with number,
date, customer, total and status (`utfärdad`/`krediterad`/`betald
- <datum>`). Ctrl+N opens the form, Enter the detail. The form has the
+ <datum>`). `n` opens the form, Enter the detail. The form has the
customer picker, invoice/due (due defaults from the customer's payment
days) and delivery dates, er/var referens and rows (beskrivning, antal,
enhet, à-pris, moms, anm); a row with only beskrivning is a free-text line
- (`text` rows, no amount). `F5` previews the real PDF (`invoice.preview`,
- nothing stored, no number consumed), `F9` issues (`invoice.issue`) and
+ (`text` rows, no amount). The context menu's Förhandsvisa PDF shows the
+ real PDF (`invoice.preview`, nothing stored, no number consumed), Utfärda
+ issues (`invoice.issue`) and
then asks "Skicka faktura <nr> till <e-post>?". The detail shows header
and rows and offers `p = visa PDF` (`invoice.pdf`), `s = skicka`
(`invoice.send`), `u = duplicera` (a new draft with the same rows and
today's dates) and, on unpaid invoices, `b = kvittera betalning`: a
prefilled payment voucher (debit `bank_account`, credit
`invoice_receivable_account`) is opened in the ordinary voucher form and,
- once posted, linked with `invoice.pay`. In the list, `n` sets the next
- invoice number (`invoice.sequence_get`/`sequence_set`, owner-only).
+ once posted, linked with `invoice.pay`. In the list, the context menu's
+ Ändra nästa fakturanummer… sets the next invoice number
+ (`invoice.sequence_get`/`sequence_set`, owner-only).
- **Kunder** — the customer register (name, address, postal code, city, VAT
- number, e-mail, your reference, payment days, notes). Ctrl+N creates,
- Enter edits (F5 validates with a dry run, Ctrl+Enter saves), `d`
- archives/reactivates.
+ number, e-mail, your reference, payment days, notes). `n` creates, Enter
+ edits (Spara row or menu; Validera is a dry run), `d` archives/
+ reactivates a customer or deletes a draft.
- **Lönekörningar** — the monthly payroll runs (`payroll.run_list`, newest
- period first) with status (`bokförd`/`betald`), gross and net. Ctrl+N
+ period first) with status (`bokförd`/`betald`), gross and net. `n`
starts a new run (period YYYY-MM and pay date, defaulting into the
selected fiscal year) when an active employee with a monthly salary
exists, Enter opens an existing run. The run screen shows the status and
- totals, `F5` previews (`payroll.run_preview` for a new run, the stored
- lines for a posted one), `Ctrl+Enter` posts after confirmation
+ totals, Förhandsvisa (`payroll.run_preview` for a new run, the stored
+ lines for a posted one) and Bokför körning… posts after confirmation
(`payroll.run_post`, showing the voucher), and the manual steps are the
action rows **Lönebesked** (PDF via `payroll.payslip`), **AGI-underlag**
(`payroll.agi`, owner only) and **Betala skatt & avgifter**
(`payroll.pay_tax`); a disabled step names its reason. The list title
warns when the current year's tax tables are missing.
- **Anställda** — the employee register (name, masked personnummer, salary,
- tax table/column, e-mail). Ctrl+N creates, Enter edits (an empty
- personnummer keeps the stored one), `d` archives/reactivates; F5
- validates with a dry run and Ctrl+Enter saves.
+ tax table/column, e-mail). `n` creates, Enter edits (an empty
+ personnummer keeps the stored one), `d` archives/reactivates; Validera
+ (dry run) and Spara are in the context menu.
- **Skattetabeller** (via **System**) — stored tax table years, the current
year's status, fetch time and source. Owners fetch Skatteverket's official
monthly table (`payroll.tax_tables_fetch`) or import a file offline
@@ -1028,9 +1032,9 @@ commands. Implemented screens (0.1.0-dev):
Report tables keep their column-header row pinned while the body scrolls.
The draft asks for the board's proposed dividend, kept per fiscal year
with `fiscal_year.update`.
-- **Bokslut** — periodiseringsfond and tax rate fields; F5 shows the posting
- plan as a `bokslut.post` dry run, `^Enter` (or F9) asks for confirmation
- and posts the plan.
+- **Bokslut** — periodiseringsfond and tax rate fields; Visa bokslutsplan
+ shows the posting plan as a `bokslut.post` dry run, Bokför planen… asks
+ for confirmation and posts the plan.
- **Information om året** — the per-year årsredovisning details (material
events, AGM and payment dates, proposed dividend, employees, other notes),
edited per field; a new fiscal year inherits the stable fields. The
@@ -1051,12 +1055,15 @@ commands. Implemented screens (0.1.0-dev):
- **Revision** (via **System**) — chain verification and
behandlingshistorik.
-**Ctrl+N is the universal "add" key**: it starts a new verifikat from the
-dashboard, the voucher list and the voucher detail view; a new mall from the
-Mallar menu; a new customer or employee from their registers; a new payroll
-run from Lönekörningar; a new fiscal year from the year picker; and maps to
-the editor in Ingående balans and to file upload in Underlag. F5 is the
-universal refresh. Hints show the keys per screen.
+**`→` (or `^O`) opens the context menu** ("Åtgärder") with every action of
+the view and the key that does the same; `^O` also works while typing in a
+table cell. **`n` is the universal "add" key**: a new verifikat from the
+dashboard, the voucher list and the voucher detail view; a new mall,
+customer, employee, payroll run, rule or board member from their lists; a
+new fiscal year from the year picker; file upload in Underlag. `r` is the
+universal refresh in lists and views. The TUI uses no function keys and no
+browser-reserved control keys (`Ctrl+N`/`T`/`W`), so it runs unchanged in a
+browser terminal; see TUI-GUIDELINES.md "Keys and the web".
**Ctrl+R reloads the client in place** (for hot-reloading after a rebuild):
it re-execs the installed binary with `--org`, `--fy` and `--screen NAME`
diff --git a/docs/STATE.md b/docs/STATE.md
index 4dcbb35..77ef9a4 100644
--- a/docs/STATE.md
+++ b/docs/STATE.md
@@ -14,6 +14,18 @@ unit tests and the docs consistency check.
## Resume here (2026-09-23)
+- **Context menu and web-safe keys (2026-09-23, branch
+ `eff/context-menu`)**: `→` (or `^O`, also in table cells) opens
+ "Åtgärder", a box at the right edge with every action of the view and
+ its key; every screen declares its actions (`tui_set_actions`). All
+ F-keys, `Ctrl+N` (now `n`), `Ctrl+Enter` and `Ctrl+F` are gone, and the
+ extended keyboard protocols are no longer enabled, so the TUI can run in
+ a browser terminal; `make check` rejects F-keys/`^N`/`^Enter` in
+ `clients/`. Save/post/validate/preview/template/attach in forms are menu
+ actions. Decision #29; spec in TUI-GUIDELINES.md "Actions and the context
+ menu" and "Keys and the web". Next for the web: an upload/download path
+ through the browser instead of the local file browser, and per-user
+ isolation of the TUI processes.
- **Byt lösenord (2026-09-23, deployed in `v0.1.68`)**: new command `user.set_password` (own password, password
session only, current password required and rate limited like logins,
≥ 10 characters, other sessions closed, audited without secrets) and a
@@ -254,8 +266,8 @@ Original entries for the struck items are in `docs/DECISIONS.md`.
Drive the TUI over a pty with `scripts/tui-sandbox.sh -- ./build/bokftui
--socket /tmp/opencode/bokf-local/sock --org 1 --fy 1 ...` plus a small
driver that feeds keys and an ANSI renderer (recreate if gone; arrows are
- `ESC O B/A`, Tab `\t`, `^X` `\x18`, `^Enter` `ESC[27;5;13~`, F5
- `ESC[15~`). Never test against the live daemon.
+ `ESC O B/A`, Tab `\t`, `^X` `\x18`, `^O` `\x0f` for the context
+ menu). Never test against the live daemon.
- Demo: db `~/bokf-demo/bokfd.db`, socket `~/bokf-demo/bokfd.sock`,
@@ -271,18 +283,20 @@ Original entries for the struck items are in `docs/DECISIONS.md`.
(schema v1, old binary) — recreate or migrate it with the current build if
it is still wanted.
- TUI smoke tests: drive over a pty with `script -qec`; function-key escape
- sequences are timing-sensitive there (not an app bug). Arrows arrive as
- application-mode sequences (`ESC O B` for Down), not `ESC [ B`, because
- curses enables the keypad. `Ctrl+N/C/F` are single bytes and reliable.
+ sequences are timing-sensitive there (not an app bug; the TUI no longer
+ uses them). Arrows arrive as application-mode sequences (`ESC O B` for
+ Down), not `ESC [ B`, because curses enables the keypad. `^O`/`^X`/`^C`
+ are single bytes and reliable.
Always wrap the run in `scripts/tui-sandbox.sh -- ./build/bokftui ...`: it
isolates `XDG_CONFIG_HOME`/`XDG_CACHE_HOME` so a test can never overwrite
the real `~/.config/bokf/tui.conf` or `~/.cache/bokf/tui.log`.
## Known caveats
-- Saving with Ctrl+Enter needs a terminal that speaks xterm
- `modifyOtherKeys` level 2 or the Kitty keyboard protocol; gnome-terminal/VTE
- sends neither, so the hints advertise `F9`, which works everywhere.
+- The TUI enables no extended keyboard protocol (no xterm
+ `modifyOtherKeys`, no Kitty protocol) and uses no function keys; saving
+ and posting are context-menu actions, which work in every terminal and
+ in a browser terminal.
- Developer tooling: the `g_cmd_<domain>[]` tables in `src/cmd_*.c` carry
declarative argument schemas (`CMD_ARGS`); `describe` emits them and the
diff --git a/docs/TUI-GUIDELINES.md b/docs/TUI-GUIDELINES.md
index 28b7f89..650f026 100644
--- a/docs/TUI-GUIDELINES.md
+++ b/docs/TUI-GUIDELINES.md
@@ -7,7 +7,9 @@ implementations. Inspired by Midnight Commander, htop, mutt and calcurse.
The **Interaction model** section is the agreed target (settled 2026-09-22,
`DECISIONS.md` #28). The **Kunder** pilot is implemented: drafts in
`$XDG_CACHE_HOME/bokf/drafts.json`, `<UTKAST>` marking, the explicit `Spara`
-row, the `F2` action menu and draft deletion work there. Every other screen
+row and draft deletion work there. The context menu (`→`/`^O`, below) and
+the web-safe keys are implemented in every screen (2026-09-23,
+`DECISIONS.md` #29). Every other screen
still follows the sections below; the interaction model wins where they
conflict as each screen moves over.
@@ -38,16 +40,17 @@ saves a whole form, never deletes and never posts.
| Class | Draft | Commit event | `Esc`/`q` | Examples |
|---|---|---|---|---|
-| **Register** | in memory + local draft file | explicit `Spara` (the save action row, `F9`) after validation | back; the draft stays | customers, employees, templates, momsregler, org data |
-| **Document** | the form is the draft | explicit `Posta` (the save action row, `F9`); immutable once written | back; confirm only when dirty | verifikat, fakturor, löneruns, bokslut |
+| **Register** | in memory + local draft file | explicit `Spara` (the save action row or the context menu) after validation | back; the draft stays | customers, employees, templates, momsregler, org data |
+| **Document** | the form is the draft | explicit `Posta` (the save action row or the context menu); immutable once written | back; confirm only when dirty | verifikat, fakturor, löneruns, bokslut |
| **Settings** | an edit buffer until `Spara` | explicit `Spara` | back | faktura/SMTP/serie-inställningar |
- Every savable form ends with a visible commit action row (`Spara`, or
- `Posta` for documents); `Enter` on the focused row commits (it is an item
- with an action), `F9` is the accelerator.
-- `Ctrl+Enter` is **dropped** as a commit key: gnome-terminal/VTE cannot
- send it. The save action row and `F9` are the only commit gestures, which
- makes every terminal behave the same.
+ `Posta` for documents), or — in a row table, where rows follow — offers it
+ first in the context menu (`^O`, `Enter`). `Enter` on the focused row
+ commits (it is an item with an action).
+- There is no commit hotkey: `Ctrl+Enter` cannot be sent by gnome-terminal/
+ VTE and `F9` is dropped with the other function keys (see "Keys and the
+ web"). The action row and the menu work in every terminal and browser.
- Commit is blocked while the data is invalid: the first invalid field is
focused and its error shown. The draft is untouched. A server error at
commit keeps the draft as well; only a successful command removes it.
@@ -64,8 +67,8 @@ saves a whole form, never deletes and never posts.
and shows up in its list immediately.
- Drafts are marked `<UTKAST>` directly after the row number in lists
(`3. <UTKAST> Namn`) and in the editor's frame title (`Kund <UTKAST>`).
-- **Delete draft** is an action both on the list row (via `F2`) and inside
- the editor, with a confirmation. It removes the memory and file draft and
+- **Delete draft** is an action both on the list row (`d`, also in the
+ context menu) and inside the editor (context menu), with a confirmation. It removes the memory and file draft and
never touches the backend. A successful commit removes the draft too.
- Drafts are client-local and never synced; another client sees the last
committed value.
@@ -76,7 +79,7 @@ saves a whole form, never deletes and never posts.
Bitwarden session file; decide whether such fields are excluded from
drafts.
-### Actions and the `F2` menu
+### Actions and the context menu
Screens declare actions, never keys:
@@ -84,41 +87,79 @@ Screens declare actions, never keys:
struct tui_action {
const char *id; /* stable, e.g. "customer.archive" */
const char *label; /* Swedish UI text */
- int key; /* accelerator; 0 = menu only */
+ int key; /* accelerator, or a virtual key (menu only) */
int enabled; /* 1 runnable, 0 dimmed with a reason, -1 heading */
const char *reason; /* why a disabled action is dim */
};
```
-- One ordered action list per context drives everything: `F2` opens the
- `Åtgärder` menu, the same list dispatches the accelerator keys and builds
- the footer hint. A key can no longer exist outside the registry.
-- The menu is sectioned: **Aktuell rad** (item actions), **Skärmen** (save,
- delete draft, attach, …), **Globalt** (`F5` uppdatera, `Ctrl+R` ladda om,
- …). Destructive actions are last and still ask for confirmation.
-- `Enter` in the menu runs the highlighted action; disabled actions are dim
- with their reason (as in `tui_form_action` today); `Esc` closes. The
- actions that complex forms hide behind hotkeys today live here unchanged.
-- The footer shows at most the two or three most important contextual
- actions plus `F2 = fler`. Universal navigation keys (`Tab`, arrows,
- `PgUp`/`PgDn`, `Home`/`End`) are not repeated there.
-- The session's key decisions: letter accelerators stay, `F9` is the only
- commit key (`Ctrl+Enter` is dropped) and `F2` only — no `§` binding (it is
- not reliably encodable across terminals).
+- **`→` opens the context menu** ("Åtgärder") wherever no caret uses the
+ arrow: lists, menus, pagers (report/detail views), forms and a row
+ table's header fields. **`^O` opens it everywhere**, also while typing in
+ a table cell, where `→` moves the caret. The menu is a box at the right
+ edge next to the selected row; each line shows the label and, right-
+ aligned, the key that does the same thing — the menu doubles as the
+ hotkey list. Up/down/Home/End move, `Enter` (or the action's own key)
+ runs, `Esc`/`←`/`q`/`^O` close. A disabled action is dim and `Enter`
+ shows its reason; a separator line divides the groups.
+- The screen registers its actions with `tui_set_actions(acts, n)` right
+ before the widget call; the widget takes them at entry, so they never leak
+ into a widget opened from a hook. The menu lists the screen's actions
+ first, then the widget's own (Öppna, Ny, Gå till/sök, Uppdatera,
+ Tillbaka; in forms Ändra/Utför; in row tables Ändra fält/Rensa raden,
+ Validera, Spara, Avbryt), skipping own actions whose key the screen took
+ (`tui_ctx_merge`).
+- **Choosing an action is the same as pressing its key**: the widget gets
+ the key as if it was typed, so the accelerator and the menu share one
+ code path in the screen's key hook. An action without a physical key uses
+ a virtual key: `TUI_KEY_SUBMIT` (spara/bokför/utfärda — was F9),
+ `TUI_KEY_REFRESH` (uppdatera/validera/förhandsvisa — was F5) or
+ `TUI_KEY_ACTION(n)` for the screen's own menu-only actions (mall, bifoga
+ in the voucher form, nästa fakturanummer).
+- Right before the menu opens the key hook gets `TUI_KEY_MENU`, so a screen
+ can set `enabled`/`label`/`reason` for the current row in its own array
+ (the Kunder list shows "Radera utkast" for a draft row and "Arkivera" or
+ "Återaktivera" otherwise, all on `d`).
+- Footers show `→ = åtgärder` (`^O` in row tables) and at most the few
+ letter accelerators that matter on the screen. Universal navigation keys
+ are not repeated there.
+
+### Keys and the web
+
+The TUI is meant to run in a browser terminal too (xterm.js/ttyd). A
+browser keeps some keys for itself, so the TUI only uses keys every
+terminal and browser delivers (checked by `make check`):
+
+- **No function keys.** F1/F3/F5/F6/F7/F10/F11/F12 are browser keys and F2,
+ F4, F9 need `Fn` on many laptops. Their old jobs are context-menu actions
+ (F2 → `→`, F5 → "Uppdatera"/"Validera"/"Förhandsvisa" with `r` in lists
+ and pagers, F9 → "Spara"/"Bokför"/"Utfärda", F4 → "Hämta mall…").
+- **No `Ctrl+N`, `Ctrl+T`, `Ctrl+W`, `Ctrl+Tab`**: Chrome never lets a page
+ have them. "Ny" is `n` in lists, menus and the voucher detail.
+- **No `Ctrl+Enter`** and no extended keyboard protocol: the TUI no longer
+ enables xterm `modifyOtherKeys` or the Kitty protocol, so every key comes
+ in its legacy encoding.
+- **Allowed**: arrows, `Enter`, `Esc`, `Tab`/`Shift-Tab`, PgUp/PgDn,
+ Home/End, letters and digits, and the control keys a page can take
+ (`^O` menu, `^X` clear row, `^A`/`^E`/`^U` in fields, `^C` quit, `^R`
+ reload — `^R` is a developer convenience and never the only way).
+- Every action is reachable with arrows + `Enter` through the menu; a
+ letter accelerator is a shortcut, never the only path.
### Implementation status
-1. Done: `struct tui_action`, `tui_action_menu()` and `tui_action_hint()` in
- `clients/tui.[ch]`, unit-tested in `tests/test_tui.c`.
-2. Partly done: the Kunder list builds its `F2` actions in a key hook and
- appends `F2 = åtgärder` to the footer via `tui_list_hint_extra()`; other
- lists have no actions yet, and `tui_rt` still uses its own key branches.
+1. Done: `struct tui_action`, the context menu (`tui_action_menu_at`,
+ `tui_set_actions`, `tui_ctx_merge`, `tui_key_name`) and `→`/`^O` in all
+ widgets, unit-tested in `tests/test_tui.c`; pty scenario `context-menu`.
+2. Done: every screen declares its actions; no F-keys, `^N` or `^Enter`
+ remain (`scripts/check-consistency.sh` fails on `KEY_F(`, `^N` and
+ `CTRL_ENTER` in `clients/`).
3. Done for Kunder: `clients/drafts.[ch]` (JSON store, atomic 0600 write,
temporary ids, `<UTKAST>` marking, delete action), unit-tested.
-4. Done for Kunder: draft/`Spara` model with the `Spara` action row,
- `F2` menu and draft deletion from both the list and the editor. The
- other register screens and the settings forms (explicit `Spara`, no
- per-field autosave) are next.
+4. Done for Kunder: draft/`Spara` model with the `Spara` action row and
+ draft deletion from both the list and the editor. The other register
+ screens and the settings forms (explicit `Spara`, no per-field autosave)
+ are next.
5. Done for Kunder: pty scenarios `customer-draft` and
`customer-draft-save` cover create, edit, `<UTKAST>`, delete and save.
@@ -143,8 +184,10 @@ there.
| Key | Meaning |
|---|---|
-| `Ctrl+N` | Add: new verifikat (dashboard, voucher list/detail), new mall (Mallar), new fiscal year (year picker), open editor (IB), upload file (Underlag) |
-| `F5` | Refresh the view |
+| `→` | Open the context menu ("Åtgärder") for the selected row/view: every action with its key. Not in a table cell, where `→` moves the caret |
+| `^O` | Open the context menu anywhere, also while typing in a table cell |
+| `n` | Ny: new verifikat (dashboard, voucher list/detail), new mall, kund, faktura, anställd, lönekörning, regel, ledamot, new voucher from a bank transaction, upload (Underlag) |
+| `r` | Uppdatera: reload the list or view |
| `Esc` / `q` | Back one level. At the dashboard it does nothing — Esc never exits the app. In a row table (`tui_rt_run`) and while a field is being edited `q` is text; only `Esc` goes back there |
| `Ctrl+C` | Quit the application (closes the session). The only key that exits |
| `Ctrl+R` | Reload the client in place: re-execs the installed binary and restores session, org, fiscal year and the current view (for after a rebuild) |
@@ -153,21 +196,22 @@ there.
| `g` | Live goto or search in every list and menu. The first key decides: a digit makes it "Gå till rad/nummer:" (the selection follows the number as you type, backspace steps back, `g` closes); any other printable key makes it "Sök:" — the selection jumps to the first row (from the top) whose text contains the typed text, case-insensitive also for åäö; up/down step to the next/previous match and wrap; "(ingen träff)" when nothing matches. Digits, `g`, `q` and screen keys (`s` = sortera, `d`…) are text while searching. Backspace to empty returns to the undecided prompt. Enter/Esc close the prompt without opening anything; the selection stays |
| arrows, PgUp/PgDn, Home/End | Move/scroll; selection always stays visible. Pages stop at the first/last row, they never wrap |
| `e` | Edit the shown object (IB, where applicable) |
-| `a` | Add/upload (Underlag) |
+| `a` | Add/upload: upload (Underlag), import a bank file (Bankavstämning), attach a file (voucher detail) |
| `c` | Correct (voucher detail) |
| `d` | Delete/arkivera the selected row (only where the action exists; asks for confirmation) |
| `s` | Verifikat list: cycle the sort order — nummer stigande/fallande, datum stigande/fallande (ties by series and number). The title shows the current order; it is saved as `voucher_sort` in `tui.conf` |
-| up/down (voucher detail) | Previous/next voucher in the list's current order; the title shows `(n av N)`. The detail scrolls with PgUp/PgDn/Home/End (`TUI_PAGER_NO_ARROWS`). A voucher posted from the detail (`^N`) is shown without stepping until the list is reopened |
+| up/down (voucher detail) | Previous/next voucher in the list's current order; the title shows `(n av N)`. The detail scrolls with PgUp/PgDn/Home/End (`TUI_PAGER_NO_ARROWS`). A voucher posted from the detail (`n`) is shown without stepping until the list is reopened |
| `f` | Voucher detail: list the voucher's underlag — Enter opens Granska (text in a pager, PDFs/images in the desktop viewer) or Ladda ned…, `d` removes the link (asks first). Underlag: Enter does the same |
-| `u` / `b` | Faktura detail: `u` duplicates the invoice into a new draft (same rows, dates reset to today), `b` (unpaid invoices) prefills and posts the payment voucher, then marks the invoice paid |
-| `Ctrl+F` | Attach a file via the file browser (voucher form and voucher detail) |
+| `p` / `s` / `u` / `b` | Faktura detail: `p` shows the PDF, `s` sends it, `u` duplicates the invoice into a new draft (same rows, dates reset to today), `b` (unpaid invoices) prefills and posts the payment voucher, then marks the invoice paid |
+| `u` | Bankavstämning: remove the highlighted transaction's match |
| `k` | Underlag: link the highlighted attachment to a voucher picked from a list |
| `Ctrl+X` | Clear the current row — only inside row editors (never "new") |
-| `Ctrl+Enter` | Save/post the current form. Needs xterm `modifyOtherKeys` level 2 or the Kitty keyboard protocol (xterm, kitty, foot, WezTerm); gnome-terminal/VTE sends neither, so the hints advertise `F9`, which works everywhere. The interaction model drops `Ctrl+Enter` entirely — don't add it to new views |
-Every screen prints its keys in the footer via `hints()`. If a key exists, the
-footer shows it; if the footer shows it, the key works. Control keys are
-written compactly as `^N`, `^A`, `^C`, `^R` to save width.
+Saving, posting, validating, previewing, templates and attaching in forms
+have no hotkey: they are context-menu actions (see "Keys and the web").
+Every key a screen handles is listed in its context menu; the footer shows
+`→ = åtgärder` and the most important letters. Control keys are written
+compactly as `^O`, `^X`, `^C`, `^R` to save width.
## Lists (`select_list`, `menu`)
@@ -175,7 +219,7 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width.
- Verifikation ids are shown concatenated as `series+number` (`V-8`, `A8`),
using the org's `series_voucher` (Bolaget → Verifikationsserier) for new
vouchers.
-- The last row may be an action (e.g. `+ Nytt verifikat (Ctrl+N)`); selecting it
+- The last row may be an action (e.g. `+ Nytt verifikat (n)`); selecting it
runs the action instead of opening a detail view.
- Selection memory: lists remember the selected row by identity (voucher id),
not index, across detail round-trips, refreshes and screen re-entry.
@@ -200,7 +244,7 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width.
address as the last argument to `tui_form_run`, `tui_form_run_hook` and
`tui_form_run_actions` (like a list cursor). On entry `*focus` is clamped
to a selectable row — out of range snaps to the nearest end, a heading row
- snaps forward and wraps — and on every return (`Esc`, `F5`, `^Enter`, a
+ snaps forward and wraps — and on every return (`Esc`, Uppdatera, Spara, a
chosen action, an edited field) the row is written back, so a re-run after
a save or a round-trip through another screen lands on the same row.
`NULL` starts at the first focusable row and stores nothing.
@@ -234,7 +278,7 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width.
the dashes themselves: type `20260315` and the field shows `2026-03-15`.
Backspace deletes a digit (with its separator), ←/→/Home/End move by digit,
and the caret renders like in any other field. Validation (`util_parse_iso_date`)
- happens on F5/`^Enter`.
+ happens on Validera/Spara.
- Derived values (account names, balances) are dim and non-editable.
- Row tables: always exactly one empty trailing row; entering data appends a
new empty row; an empty row followed by another empty row collapses.
@@ -259,7 +303,7 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width.
does nothing. The hardware cursor only shows in a table cell. `q` is text
here — only `Esc` leaves the table. Moving to another cell (arrows,
`Enter`, `Tab`) resets the caret to the end of the new cell. A focused
- cell scrolls horizontally like a form field. `F5`/`Ctrl+Enter`/`Esc`
+ cell scrolls horizontally like a form field. `^O`/`Esc`
work the same from both.
- A form may carry an action list under its fields (`tui_form_run_actions`):
fields first, then action rows, one focus ring (`Tab`/`Shift-Tab`/
@@ -276,17 +320,20 @@ written compactly as `^N`, `^A`, `^C`, `^R` to save width.
resultat` voucher that `bokslut.post` creates; a closed year counts as
posted) and the actions Årsredovisning (K2), Inkomstdeklaration
(INK2/SRU), Bokslutsplan (torrkörning) and Bokför bokslut — the last
- dimmed with a reason when the year is closed or already posted. `F5`
- shows the plan, `Ctrl+Enter` posts it.
-- Validation: `F5` validates without writing and reports exactly what is wrong
+ dimmed with a reason when the year is closed or already posted. The
+ context menu's "Visa bokslutsplan" shows the plan, "Bokför planen…" posts
+ it.
+- Validation: the "Validera" action (`TUI_KEY_REFRESH`) validates without
+ writing and reports exactly what is wrong
(field, row number). Server `dry_run` is used where available.
-- Saving: `Ctrl+Enter` writes, shows a confirmation message, and returns to
+- Saving: the "Spara"/"Bokför" action (`TUI_KEY_SUBMIT`) writes, shows a
+ confirmation message, and returns to
the previous view. `Esc` cancels without saving.
- Screen-specific keys (template picker, attach, link, download) are handled
in a key hook, never with a local loop. The hook runs for keys the widget
itself does not handle and returns `TUI_HOOK_*`: `STAY` (consumed, redraw),
- `BACK`, `REFRESH` or `SUBMIT` (the widget returns as on `Esc`/`F5`/
- `Ctrl+Enter`). Hooks exist on `tui_form_run_hook`, `tui_rt_set_key`,
+ `BACK`, `REFRESH` or `SUBMIT` (the widget returns as on `Esc` or the
+ Uppdatera/Spara actions). Hooks exist on `tui_form_run_hook`, `tui_rt_set_key`,
`tui_pager_hook` and `tui_select_list_hook`.
- File browser (`file_browser`): starts in the directory where the last
attachment was picked (remembered in `tui.conf`), falling back to `$HOME`
@@ -404,8 +451,9 @@ only place that touches ncurses. Rules:
one-off questions use the prompts (`tui_prompt_into`,
`tui_date_prompt_into`, `tui_amount_prompt_into`, `tui_choice_prompt`).
All of them share one field editor.
-5. Support `F5` if the data can change elsewhere.
+5. Support refresh (`r` / "Uppdatera") if the data can change elsewhere.
6. Update `PROTOCOL.md` §8 and this file if you add a new key or interaction.
7. Declare the screen's actions in one `tui_action` list (once the
- interaction model is implemented); dispatch, the `F2` menu and the footer
+ interaction model is implemented); dispatch, the context menu and the
+ footer
hint all read that list, so a key cannot exist without a visible action.