docs(extensions): documented composer shape renderer and styling contract

- Document the `registerComposerShape` API method for adding input-editor layouts.
- Detail the `ComposerStyle` layout metadata properties and rendering methods.
- Provide a full implementation example demonstrating custom composer styling and registration.
This commit is contained in:
can1357
2026-08-20 06:36:43 +02:00
parent a02da243e7
commit 2c588d8750
+76
View File
@@ -115,6 +115,7 @@ Core methods:
- `on(event, handler)`
- `registerTool`, `registerCommand`, `registerShortcut`, `registerFlag`
- `registerMessageRenderer`, `registerAssistantThinkingRenderer`
- `registerComposerShape`
- `setLabel`, `getFlag`
- `sendMessage`, `sendUserMessage`, `appendEntry`, `exec`
- `getActiveTools`, `getAllTools`, `setActiveTools`
@@ -576,6 +577,81 @@ pi.on("session_start", async (_event, ctx) => {
## Rendering extension points
## Composer shape renderer
`registerComposerShape` adds an extension-owned input-editor layout to **Appearance → Composer Shape**. Register it from the extension factory; the renderer is used by the live editor and its settings preview.
```ts
import type { ExtensionAPI } from "@oh-my-pi/pi-coding-agent";
import type { ComposerStyle } from "@oh-my-pi/pi-tui";
const dockStyle: ComposerStyle = {
id: "acme-dock",
sideBorders: false,
verticalChrome: 1,
statusAttachment: "none",
bottomBar: "full",
bottomBarGap: true,
defaultPromptGutter: "❯ ",
defaultPaddingX: () => 0,
sideChromeWidth: () => 0,
renderTop: ({ box, width, borderColor }) =>
borderColor(box.horizontal.repeat(width)),
renderRow: ({ gutter, text, pad }) => [gutter + text + pad],
renderBottom: () => undefined,
};
export default function (pi: ExtensionAPI) {
pi.registerComposerShape({
label: "Acme Dock",
description: "Prompt below a single rule",
style: dockStyle,
});
}
```
`ComposerShapeDefinition` contains:
- `label`: required selector label.
- `description`: optional selector detail.
- `style`: the complete `ComposerStyle` rendering contract. `style.id` is also the persisted `composer.shape` value.
Use a package-qualified, non-empty, trimmed `style.id`. Built-in ids (`box`, `claude`, `pi`, `borderless`, `rule`, `field`, and `rail`) cannot be replaced. If the extension is unavailable while its id remains configured, the editor falls back to `box`.
### `ComposerStyle` layout metadata
- `sideBorders`: whether content rows own side chrome. This controls cursor reserve, IME layout, and scrollbar behavior; it is not merely descriptive.
- `verticalChrome`: exact number of fixed top/bottom chrome rows (`0`, `1`, or `2`) used for editor height budgeting.
- `statusAttachment`: `"top-border"` receives the embedded status gauge, `"top-rule-chip"` receives the right status group for docking on a rule, and `"none"` detaches status from the editor chrome.
- `bottomBar`: standalone status content below the editor: `"none"`, `"left"`, or `"full"`.
- `bottomBarGap`: whether a blank row separates the editor from a standalone bottom status bar.
- `defaultPromptGutter`: prompt text used when the host supplies no override.
- `defaultPaddingX(themePaddingX)`: horizontal padding selected for this style.
- `sideChromeWidth(paddingX)`: visible cells consumed on **each** side of a content row, including padding and border/rail glyphs.
`renderTop` and `renderBottom` return one styled terminal row or `undefined`. `renderRow` returns one or more styled rows. Every normal rendered row must occupy exactly `ctx.width` visible cells; ANSI escape sequences have zero width. Preserve the supplied `gutter`, `text`, and `pad` instead of reflowing or truncating them.
### Renderer context
All render methods receive `width`, `paddingX`, the theme's `box` glyphs, and three styling functions:
- `borderColor(text)`: ordinary frame/rule color.
- `accentColor(text)`: stable accent for shape-defining rails or caps.
- `surfaceColor(text)`: composer background fill that survives nested SGR resets in decorated input.
`topBorder`, when present, is already-styled status content with its visible `width`. A top renderer owns its placement and must leave the final line at `ctx.width`.
`renderRow` additionally receives:
- `gutter`, `text`, and `pad`: pre-rendered content pieces.
- `isLastRow`: last visible input row.
- `cursorOverflow`: cells consumed from the right chrome by an end-of-line cursor.
- `imeSafeCursorTail`: omit right-side cells after the cursor so terminal-local IME preedit cannot shift the chrome.
- `scrollbarThumb`: this row intersects the editor scrollbar thumb.
The built-in implementations in `packages/tui/src/components/composer/` are the reference for framed, rule, filled-surface, and IME-safe layouts.
## Custom message renderer
```ts