Tracking issue. Not a current priority. Prerequisite for #147 — bundled Postman-like extension.
What
Give vimcode Lua plugins the ability to declare rich UI using `quadraui` primitives (`Form`, `TreeView`, `TreeTable`, `ListView`, `TextDisplay`, `TextEditor`, `Dialog`, `Palette`, etc.) and receive events routed back to plugin callbacks.
Today, vimcode's Lua API (`vimcode.*`) is limited to annotations, set_line, commands, and keymaps. Plugins cannot declare forms, tables, or interactive panels. This blocks anything beyond lightweight scripts.
Why
- Enables a Postman-like HTTP client extension (see sibling issue)
- Enables plugin-authored tool panels (SQL runner, API tester, log filter, etc.) without touching vimcode's Rust code
- Converts vimcode into a general-purpose plugin-extensible keyboard-first shell, the same way VSCode's extension ecosystem works
Rough API shape (illustrative, not final)
```lua
-- Register a panel
vimcode.ui.register_panel("my-ext", {
title = "My Panel",
icon = "",
render = function(ctx)
return {
type = "form",
id = "main-form",
fields = {
{ type = "text", id = "url", label = "URL" },
{ type = "dropdown", id = "method", options = {"GET","POST"} },
{ type = "button", id = "send", label = "Send" },
},
}
end,
on_event = function(ctx, event)
if event.widget_id == "send" and event.kind == "ButtonClicked" then
-- do the thing
end
end,
})
```
Design invariants to preserve when building quadraui
These are properties the quadraui design must maintain so this feature is implementable later without breaking changes:
- `WidgetId` must be owned/allocatable (e.g. `String` or `Cow`), not `&'static str`. Plugins generate IDs at runtime.
- Events are dispatched as plain data, not Rust closures. Backend emits `UiEvent`; app (vimcode) routes to plugin by widget ID. No closures crossing the Rust/Lua boundary.
- Primitive data structs must be serde-compatible (Serialize + Deserialize). Lua tables convert to JSON and then to Rust structs.
- `WidgetId` namespace support. Apps can reserve an ID prefix per plugin so plugin widget IDs don't collide (e.g., `"plugin:my-ext:send"`).
- No global event handlers. All widgets have an ID; all events reference it. No "on_change" magic that doesn't carry the widget.
- Primitives don't borrow from app state. They own their data (or accept `&'a` with a clear lifetime). Plugins can pass owned data without borrow-checker puzzles.
These are already the design's intent per `docs/UI_CRATE_DESIGN.md`. This issue documents them explicitly to prevent drift.
Additional vimcode-side work required
Beyond quadraui, vimcode needs:
- `vimcode.http` API for async HTTP (uses `reqwest` internally; callbacks as plugin events) — needed for Postman-alike and generally useful
- JSON parse/stringify in Lua (a Rust crate wrapped, or bundle a Lua JSON lib)
- Plugin-scoped storage (persistent key-value for plugin state)
- Panel registration currently exists (`PanelRegistration`) — extend it to accept a render function producing a quadraui tree
Non-goals
- FFI / direct Rust access for plugins
- Letting plugins define new primitives (they compose existing ones)
- WebAssembly plugin runtime (Lua stays primary; WASM is a separate future topic)
Dependencies
- quadraui primitives stabilized and using the design invariants above
- Ideally after quadraui 1.0 publishes; could be v1.x work
Priority
Low until a concrete plugin needs it (Postman extension, SQL client extension, etc.).
Tracking issue. Not a current priority. Prerequisite for #147 — bundled Postman-like extension.
What
Give vimcode Lua plugins the ability to declare rich UI using `quadraui` primitives (`Form`, `TreeView`, `TreeTable`, `ListView`, `TextDisplay`, `TextEditor`, `Dialog`, `Palette`, etc.) and receive events routed back to plugin callbacks.
Today, vimcode's Lua API (`vimcode.*`) is limited to annotations, set_line, commands, and keymaps. Plugins cannot declare forms, tables, or interactive panels. This blocks anything beyond lightweight scripts.
Why
Rough API shape (illustrative, not final)
```lua
-- Register a panel
vimcode.ui.register_panel("my-ext", {
title = "My Panel",
icon = "",
render = function(ctx)
return {
type = "form",
id = "main-form",
fields = {
{ type = "text", id = "url", label = "URL" },
{ type = "dropdown", id = "method", options = {"GET","POST"} },
{ type = "button", id = "send", label = "Send" },
},
}
end,
on_event = function(ctx, event)
if event.widget_id == "send" and event.kind == "ButtonClicked" then
-- do the thing
end
end,
})
```
Design invariants to preserve when building quadraui
These are properties the quadraui design must maintain so this feature is implementable later without breaking changes:
These are already the design's intent per `docs/UI_CRATE_DESIGN.md`. This issue documents them explicitly to prevent drift.
Additional vimcode-side work required
Beyond quadraui, vimcode needs:
Non-goals
Dependencies
Priority
Low until a concrete plugin needs it (Postman extension, SQL client extension, etc.).