Replace the single file-structure.md with a stratified layout designed
for AI/agent skill consumption: tables and concrete identifiers over
prose, files loaded on demand, content separated by churn rate.
Layers:
- architecture/ stable structural reference (overview, source-map,
test-map, data-flow)
- patterns/ memory, commands, autocomplete, events, xmpp,
encryption, ui, plugins
- testing/ unit-tests, stubs, functional-tests, bench
- build/ local, docker, ci
- playbooks/ add-command, add-test, add-autocomplete,
add-event-handler, add-encryption
- gotchas.md append-only dated entries (seven seed entries)
- wip/ branch-specific notes; deleted on merge to master
Stable layers describe cproof on master only. In-flight feature
branches (currently feat/ai) get a single file under wip/.
INDEX.md is the entry map with churn labels; SKILL.md is the
always-loaded skill hint pointing to it.
98 lines
3.3 KiB
Markdown
98 lines
3.3 KiB
Markdown
# Autocomplete
|
|
|
|
## The `Autocomplete` type
|
|
|
|
`src/tools/autocomplete.h` defines an opaque `Autocomplete` (GList-backed
|
|
sorted set with a stateful "current iterator" for cycling through matches).
|
|
|
|
| Function | Purpose |
|
|
|---|---|
|
|
| `autocomplete_new()` | Create empty AC. |
|
|
| `autocomplete_clear(ac)` | Drop all entries (keep object). |
|
|
| `autocomplete_free(ac)` | Destroy. |
|
|
| `autocomplete_add(ac, item)` | Insert sorted. |
|
|
| `autocomplete_add_unsorted(ac, item, reversed)` | Append, no sort. |
|
|
| `autocomplete_add_all(ac, items)` | Bulk add from `char**`. |
|
|
| `autocomplete_update(ac, items)` | Clear + add_all. |
|
|
| `autocomplete_remove(ac, item)` | Drop one. |
|
|
| `autocomplete_remove_all(ac, items)` | Drop many. |
|
|
| `autocomplete_complete(ac, search, quote, previous)` | Cycle to next/previous match. |
|
|
| `autocomplete_reset(ac)` | Reset cycle position. |
|
|
| `autocomplete_contains(ac, value)` | Membership. |
|
|
|
|
## Two completion flavours used in commands
|
|
|
|
In `src/command/cmd_ac.c`:
|
|
|
|
```c
|
|
autocomplete_param_with_ac(input, "/cmd sub", static_ac, quote, previous);
|
|
autocomplete_param_with_func(input, "/cmd sub", callback, previous, ctx);
|
|
```
|
|
|
|
| When to use | Choose |
|
|
|---|---|
|
|
| Fixed token set known at startup. | `autocomplete_param_with_ac` + a static `Autocomplete` (allocated in `cmd_ac_init`, freed in `cmd_ac_uninit`). |
|
|
| Token set is dynamic / queried from state. | `autocomplete_param_with_func` + a callback `char* fn(const char* search, gboolean previous, void* ctx)`. |
|
|
|
|
## Static Autocompletes
|
|
|
|
Pattern (from `cmd_ac.c`):
|
|
|
|
```c
|
|
// File-scope:
|
|
static Autocomplete account_ac;
|
|
|
|
// In cmd_ac_init():
|
|
account_ac = autocomplete_new();
|
|
autocomplete_add(account_ac, "list");
|
|
autocomplete_add(account_ac, "show");
|
|
autocomplete_add(account_ac, "add");
|
|
// ...
|
|
|
|
// Registered with:
|
|
g_hash_table_insert(ac_funcs, "/account", _account_autocomplete);
|
|
```
|
|
|
|
Static `Autocomplete` instances are added to a file-scope free-list array
|
|
near the top of `cmd_ac.c` so `cmd_ac_uninit` can call `autocomplete_free`
|
|
on each at shutdown. **Add new static ACs to that free-list.**
|
|
|
|
## Function-callback completers
|
|
|
|
```c
|
|
char* roster_contact_autocomplete(const char* const search_str,
|
|
gboolean previous, void* context);
|
|
```
|
|
|
|
- Stateless across invocations — no module-level `_last_match` globals.
|
|
- Returns a freshly-allocated `char*` (caller frees), or `NULL` when no more
|
|
matches.
|
|
- `previous` cycles backward (Shift+Tab).
|
|
- `context` is whatever was passed in `autocomplete_param_with_func`'s last
|
|
arg (often `NULL`).
|
|
|
|
`roster_contact_autocomplete` (`src/xmpp/roster_list.c`) is a clean
|
|
canonical example: it delegates straight to `autocomplete_complete` against
|
|
a roster-owned `Autocomplete` object — no callback-local state.
|
|
|
|
**Avoid the legacy "store previous match in a static" pattern.** Some older
|
|
completers do it; do not copy them. Keeping callbacks stateless makes
|
|
shift-tab cycling and concurrent completers safe.
|
|
|
|
## Per-command dispatcher
|
|
|
|
Every command's autocomplete is a single static function in `cmd_ac.c`:
|
|
|
|
```c
|
|
static char* _account_autocomplete(ProfWin* window, const char* const input, gboolean previous);
|
|
```
|
|
|
|
Registered in `cmd_ac_init`:
|
|
|
|
```c
|
|
g_hash_table_insert(ac_funcs, "/account", _account_autocomplete);
|
|
```
|
|
|
|
The dispatcher inspects the input prefix and picks the right
|
|
`autocomplete_param_with_*` call.
|