Files
root 8f15646cf0 Add Tab completion to mailctl
The command tree lives in Go, in complete.go, next to the commands it
describes: the hidden __complete subcommand is handed the words typed so far
and answers with what may follow the last of them. The zsh function installed
alongside the binary does nothing but pass the line in and hand the answer
back, so it needs no change when a command is added, and it cannot describe a
grammar the tool no longer has.

Two rules hold throughout:

- Completion never writes. It reads through completeValues, which opens the
  database read-only, and not through openDB, which would create it from
  schema.sql and run migrate() on every call. Checked: after repeated
  completions the mtime and size of mail.db are unchanged and no -wal or -shm
  file appears beside it.
- Completion never fails out loud. Every error ends as an empty list, and
  __complete is dispatched before the root check, so as an unprivileged user
  the structure still completes, the values stay empty, nothing reaches
  stderr and the status is 0.

The values come out of the database, so only what exists is offered: `user
enable` lists the locked mailboxes and `user disable` the unlocked ones,
`alias del <source>` only the targets of that alias, `sieve edit <address>`
that mailbox's scripts via doveadm, and `lang allow` the languages Rspamd has
a model for, minus those already on the line. For a path argument the answer
is the single line ":files", which hands over to zsh's own file completion.

Narrowing the answer down to what has been typed is left to the shell rather
than done in Go, so that the matcher-list styles keep working - completing
"MARTIN@" to "martin@example.com" is zsh's business, and a filter here would
defeat it.

Two details on the shell side are worth recording, both found by driving a
real interactive zsh through a pseudo-terminal rather than by reading:

- The binary is located with `whence -p mailctl`, not through $commands.
  That parameter is not populated inside a completion function, so the
  lookup yields nothing and every candidate list silently comes back empty.
- zsh writes "--" between a value and its description. The function sets
  list-separator to a single hyphen, scoped to mailctl's own context so no
  other completion changes, and only when nothing has been set for it
  already.

`make install` now also puts the function in
/usr/local/share/zsh/site-functions. The installer needs no change for it:
stage 8 already builds through `make install`.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 10:48:06 +02:00
..
2026-08-04 11:13:57 +02:00
2026-08-07 10:48:06 +02:00