Shared : command system (core/lib/cmd + ui + lua) #5

Open
opened 2026-07-19 02:30:38 +00:00 by agent · 0 comments
Member

Plan: Shared : command system in core/lib/cmd + propagation to res-edit, res-code, res-console, res-sheets

Status: design (decisions locked) → phased implementation plan

Locked decisions (from user)

  1. Console trigger = Alt+: only, hardcoded, non-configurable. Sits in the console's Alt domain. Never a configurable key.
  2. Consolidate modeGoto/modeFind into the : line, but keep Ctrl+F/Ctrl+G shortcuts — they pre-fill the : line.
  3. core/lib/cmd is a builder-type system. Provides interface + standards (parser, Registry, Handler, Context, Result, arg tokenizer with quotes) but ships no app command lists. Each app implements its own registry. res-edit owns its set; res-code composes res-edit's set.
  4. Args parsing: whitespace split plus quoted-string support ("a b" → one arg).
  5. res-sheets refactored LAST (after main build), to consume core/lib/cmd and delete its local runCommand.
  6. Lua bridge: apps expose command.register(verb, fn) so Lua scripts build their own :verb commands. Reusable glue ships as core/lib/cmd/lua.
  7. Shared UI palette: core/lib/cmd/ui ships a premade, position-agnostic bubbletea widget (input line + dropdown + live-filter autocomplete). Apps include it in the appropriate position (bottom for edit/console, top for code).

Three opt-in layers

core/lib/cmd      → pure: Registry, Spec, Handler, Context, Result, parser (quotes)
core/lib/cmd/ui   → premade Palette widget (bubbletea + tui/theme), position-agnostic
core/lib/cmd/lua  → premade Lua bridge (script.Engine ↔ cmd.Handler)

Apps compose only the layers they need:

  • res-edit = cmd + cmd/ui
  • res-code = cmd + cmd/ui (+ later cmd/lua)
  • res-console = cmd + cmd/ui + cmd/lua
  • res-sheets = cmd + cmd/ui (later phase)

Builder API (core/lib/cmd)

  • Context{ Verb, Args, Raw, App }, Result{ Status, Quit }, Handler func(ctx Context) Result
  • Spec{ Verb, Aliases, Usage, Desc, Handler }
  • Registry: NewRegistry, Register (idempotent; later wins), Merge (res-code composes res-edit), Run(line, app), Complete(prefix), Specs()
  • Parser (parse.go): strip one leading :; quote-aware tokenize ("..."/'...'); resolve aliases; unknown verb → status message; Raw = everything after verb.

cmd/lua bridge

  • LuaToHandler(fn, eng), Register(r, eng, verb, fn, opts), BindCommandTable(L, r, eng) — registers a command Lua global so addon scripts do command.register("hello", function(args) return "hi " .. (args[1] or "") end).

cmd/ui palette

  • Palette with Position (PosBottom / PosTop / PosOverlay), live-filter autocomplete, Tab-accept, Enter-run, Esc-cancel, mouse support. All styles from core/lib/tui/theme (amber palette, AGENTS.md §7). Position-agnostic: app decides placement.

Propagation

  • res-edit (core/lib/edit): modeCommand + : entry; editCommands() registry (:w :write :save :q :quit :wq :x :e :edit :goto :g :find :f); adopt ui.Palette (PosBottom); Ctrl+F/Ctrl+G pre-fill; remove old modeFind/modeGoto.
  • res-code (extra/internal/code): modeCommand + :; codeCommands() = Merge(edit.EditCommands(), codeOnly) (:tabnew :tabn :tabp :b :sidebar :term); ui.Palette (PosTop).
  • res-console (core/internal/libs/console): psCommand state; Alt+: trigger; consoleCommands() calling existing Lua surface (:menu :widget :reload :set :q); include cmdlua.BindCommandTable; update docs/console/scripting.md.
  • res-sheets (LAST): replace local runCommand with sheetsCommands(); adopt ui.Palette (PosBottom); delete hardcoded switch.

Implementation phases

  • Phase 0 — core/lib/cmd builder + cmd/ui + cmd/lua + unit tests.
  • Phase 1 — res-edit adopts it.
  • Phase 2 — res-code adopts it.
  • Phase 3 — res-console adopts it (Alt+: + Lua bridge).
  • Phase 4 — res-sheets refactor (LAST).
  • Phase 5 — docs: docs/design/command-registry.md, update docs/keymap.md, per-app docs, AGENTS.md §4 package table.

Verification

  • cd core && go build ./... && go test ./...
  • cd extra && go build ./... && go test ./...
  • Unit tests in core/lib/cmd, cmd/ui, cmd/lua, core/lib/edit, extra/internal/code, extra/lib/sheets/tui.

Risks

  • Console : must never intercept shell input → gated behind Alt+: only (hardcoded).
  • Keep core/lib/cmd base Lua-free & UI-free; cmd/lua + cmd/ui are opt-in subpkgs.
  • Don't break keymap.md (Alt+* console-owned; Ctrl+* editors; : bare-rune safe).
  • Palette must use tui/theme only. PosTop in code must not overlap tab bar.
  • res-sheets refactor deferred to Phase 4 so builder + UI are proven first.
# Plan: Shared `:` command system in `core/lib/cmd` + propagation to res-edit, res-code, res-console, res-sheets **Status:** design (decisions locked) → phased implementation plan ## Locked decisions (from user) 1. **Console trigger = `Alt+:` only**, hardcoded, **non-configurable**. Sits in the console's `Alt` domain. Never a configurable key. 2. **Consolidate `modeGoto`/`modeFind` into the `:` line**, but **keep `Ctrl+F`/`Ctrl+G` shortcuts** — they pre-fill the `:` line. 3. **`core/lib/cmd` is a builder-type system.** Provides interface + standards (parser, `Registry`, `Handler`, `Context`, `Result`, arg tokenizer with quotes) but ships no app command lists. Each app implements its own registry. res-edit owns its set; res-code **composes** res-edit's set. 4. **Args parsing:** whitespace split **plus** quoted-string support (`"a b"` → one arg). 5. **res-sheets refactored LAST** (after main build), to consume `core/lib/cmd` and delete its local `runCommand`. 6. **Lua bridge:** apps expose `command.register(verb, fn)` so Lua scripts build their own `:verb` commands. Reusable glue ships as `core/lib/cmd/lua`. 7. **Shared UI palette:** `core/lib/cmd/ui` ships a premade, position-agnostic bubbletea widget (input line + dropdown + live-filter autocomplete). Apps include it in the appropriate position (bottom for edit/console, top for code). ## Three opt-in layers ``` core/lib/cmd → pure: Registry, Spec, Handler, Context, Result, parser (quotes) core/lib/cmd/ui → premade Palette widget (bubbletea + tui/theme), position-agnostic core/lib/cmd/lua → premade Lua bridge (script.Engine ↔ cmd.Handler) ``` Apps compose only the layers they need: - res-edit = `cmd` + `cmd/ui` - res-code = `cmd` + `cmd/ui` (+ later `cmd/lua`) - res-console = `cmd` + `cmd/ui` + `cmd/lua` - res-sheets = `cmd` + `cmd/ui` (later phase) ## Builder API (`core/lib/cmd`) - `Context{ Verb, Args, Raw, App }`, `Result{ Status, Quit }`, `Handler func(ctx Context) Result` - `Spec{ Verb, Aliases, Usage, Desc, Handler }` - `Registry`: `NewRegistry`, `Register` (idempotent; later wins), `Merge` (res-code composes res-edit), `Run(line, app)`, `Complete(prefix)`, `Specs()` - Parser (`parse.go`): strip one leading `:`; quote-aware tokenize (`"..."`/`'...'`); resolve aliases; unknown verb → status message; `Raw` = everything after verb. ## `cmd/lua` bridge - `LuaToHandler(fn, eng)`, `Register(r, eng, verb, fn, opts)`, `BindCommandTable(L, r, eng)` — registers a `command` Lua global so addon scripts do `command.register("hello", function(args) return "hi " .. (args[1] or "") end)`. ## `cmd/ui` palette - `Palette` with `Position` (PosBottom / PosTop / PosOverlay), live-filter autocomplete, Tab-accept, Enter-run, Esc-cancel, mouse support. All styles from `core/lib/tui/theme` (amber palette, AGENTS.md §7). Position-agnostic: app decides placement. ## Propagation - **res-edit** (`core/lib/edit`): `modeCommand` + `:` entry; `editCommands()` registry (`:w :write :save :q :quit :wq :x :e :edit :goto :g :find :f`); adopt `ui.Palette` (PosBottom); `Ctrl+F`/`Ctrl+G` pre-fill; remove old `modeFind`/`modeGoto`. - **res-code** (`extra/internal/code`): `modeCommand` + `:`; `codeCommands() = Merge(edit.EditCommands(), codeOnly)` (`:tabnew :tabn :tabp :b :sidebar :term`); `ui.Palette` (PosTop). - **res-console** (`core/internal/libs/console`): `psCommand` state; `Alt+:` trigger; `consoleCommands()` calling existing Lua surface (`:menu :widget :reload :set :q`); include `cmdlua.BindCommandTable`; update `docs/console/scripting.md`. - **res-sheets** (LAST): replace local `runCommand` with `sheetsCommands()`; adopt `ui.Palette` (PosBottom); delete hardcoded switch. ## Implementation phases - Phase 0 — `core/lib/cmd` builder + `cmd/ui` + `cmd/lua` + unit tests. - Phase 1 — res-edit adopts it. - Phase 2 — res-code adopts it. - Phase 3 — res-console adopts it (`Alt+:` + Lua bridge). - Phase 4 — res-sheets refactor (LAST). - Phase 5 — docs: `docs/design/command-registry.md`, update `docs/keymap.md`, per-app docs, AGENTS.md §4 package table. ## Verification - `cd core && go build ./... && go test ./...` - `cd extra && go build ./... && go test ./...` - Unit tests in `core/lib/cmd`, `cmd/ui`, `cmd/lua`, `core/lib/edit`, `extra/internal/code`, `extra/lib/sheets/tui`. ## Risks - Console `:` must never intercept shell input → gated behind `Alt+:` only (hardcoded). - Keep `core/lib/cmd` base Lua-free & UI-free; `cmd/lua` + `cmd/ui` are opt-in subpkgs. - Don't break keymap.md (`Alt+*` console-owned; `Ctrl+*` editors; `:` bare-rune safe). - Palette must use `tui/theme` only. `PosTop` in code must not overlap tab bar. - res-sheets refactor deferred to Phase 4 so builder + UI are proven first.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
residual/.agent#5
No description provided.