@linxiraos/pi-tui 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -2268
- package/LICENSE +23 -0
- package/README.md +1 -1
- package/package.json +68 -69
- package/src/autocomplete.ts +147 -61
- package/src/components/composer/borderless.ts +37 -0
- package/src/components/composer/box.ts +85 -0
- package/src/components/composer/claude.ts +39 -0
- package/src/components/composer/field.ts +47 -0
- package/src/components/composer/index.ts +9 -0
- package/src/components/composer/pi.ts +37 -0
- package/src/components/composer/rail.ts +48 -0
- package/src/components/composer/registry.ts +46 -0
- package/src/components/composer/rule.ts +55 -0
- package/src/components/composer/types.ts +98 -0
- package/src/components/editor.ts +564 -259
- package/src/components/image.ts +4 -6
- package/src/components/loader.ts +1 -9
- package/src/components/markdown.ts +487 -423
- package/src/components/select-list.ts +67 -15
- package/src/components/settings-list.ts +43 -11
- package/src/components/text.ts +8 -18
- package/src/desktop-notify.ts +1 -1
- package/src/fuzzy.ts +63 -6
- package/src/index.ts +1 -0
- package/src/keybindings.ts +5 -0
- package/src/keys.ts +1 -1
- package/src/stdin-buffer.ts +130 -20
- package/src/terminal-capabilities.ts +36 -6
- package/src/terminal.ts +148 -23
- package/src/tui.ts +655 -3458
- package/src/utils.ts +65 -61
- package/dist/types/autocomplete.d.ts +0 -116
- package/dist/types/bracketed-paste.d.ts +0 -51
- package/dist/types/components/box.d.ts +0 -31
- package/dist/types/components/cancellable-loader.d.ts +0 -21
- package/dist/types/components/editor.d.ts +0 -166
- package/dist/types/components/image.d.ts +0 -165
- package/dist/types/components/input.d.ts +0 -25
- package/dist/types/components/loader.d.ts +0 -25
- package/dist/types/components/markdown.d.ts +0 -92
- package/dist/types/components/scroll-view.d.ts +0 -62
- package/dist/types/components/select-list.d.ts +0 -69
- package/dist/types/components/settings-list.d.ts +0 -123
- package/dist/types/components/spacer.d.ts +0 -11
- package/dist/types/components/tab-bar.d.ts +0 -89
- package/dist/types/components/text.d.ts +0 -28
- package/dist/types/components/truncated-text.d.ts +0 -10
- package/dist/types/deccara.d.ts +0 -49
- package/dist/types/desktop-notify.d.ts +0 -52
- package/dist/types/editor-component.d.ts +0 -38
- package/dist/types/fuzzy.d.ts +0 -48
- package/dist/types/index.d.ts +0 -32
- package/dist/types/keybindings.d.ts +0 -197
- package/dist/types/keys.d.ts +0 -210
- package/dist/types/kill-ring.d.ts +0 -20
- package/dist/types/kitty-graphics.d.ts +0 -76
- package/dist/types/latex-block.d.ts +0 -8
- package/dist/types/latex-to-unicode.d.ts +0 -50
- package/dist/types/loop-watchdog.d.ts +0 -49
- package/dist/types/mouse.d.ts +0 -67
- package/dist/types/stdin-buffer.d.ts +0 -60
- package/dist/types/symbols.d.ts +0 -25
- package/dist/types/terminal-capabilities.d.ts +0 -324
- package/dist/types/terminal.d.ts +0 -175
- package/dist/types/tmux.d.ts +0 -6
- package/dist/types/ttyid.d.ts +0 -9
- package/dist/types/tui.d.ts +0 -480
- package/dist/types/utils.d.ts +0 -112
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code-like composer: full-width horizontal rules above and below a
|
|
3
|
+
* borderless `❯ ` prompt. The right status group rides the top rule as a
|
|
4
|
+
* bg chip near the right edge (`─────── hi ─`); the left group renders as a
|
|
5
|
+
* plain standalone bottom bar that yields its row to the autocomplete menu.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { renderTopRule } from "./rule";
|
|
9
|
+
import type { ComposerChromeContext, ComposerRowContext, ComposerStyle } from "./types";
|
|
10
|
+
|
|
11
|
+
export const claudeComposerStyle: ComposerStyle = {
|
|
12
|
+
id: "claude",
|
|
13
|
+
sideBorders: false,
|
|
14
|
+
verticalChrome: 2,
|
|
15
|
+
statusAttachment: "top-rule-chip",
|
|
16
|
+
bottomBar: "left",
|
|
17
|
+
bottomBarGap: false,
|
|
18
|
+
defaultPromptGutter: "❯ ",
|
|
19
|
+
|
|
20
|
+
defaultPaddingX(): number {
|
|
21
|
+
return 0;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
sideChromeWidth(paddingX: number): number {
|
|
25
|
+
return paddingX;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
renderTop(ctx: ComposerChromeContext): string {
|
|
29
|
+
return renderTopRule(ctx);
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
renderRow(ctx: ComposerRowContext): string[] {
|
|
33
|
+
return [ctx.gutter + ctx.text + ctx.pad];
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
renderBottom(ctx: ComposerChromeContext): string {
|
|
37
|
+
return ctx.borderColor(ctx.box.horizontal.repeat(ctx.width));
|
|
38
|
+
},
|
|
39
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compact filled composer: every input row is a one-line field with accent end
|
|
3
|
+
* caps and a subtle surface fill. The complete status line remains below it.
|
|
4
|
+
*/
|
|
5
|
+
import { padding } from "../../utils";
|
|
6
|
+
import type { ComposerRowContext, ComposerStyle } from "./types";
|
|
7
|
+
|
|
8
|
+
const LEFT_CAP = "▐";
|
|
9
|
+
const RIGHT_CAP = "▌";
|
|
10
|
+
|
|
11
|
+
/** One-row filled field with accent caps. */
|
|
12
|
+
export const fieldComposerStyle: ComposerStyle = {
|
|
13
|
+
id: "field",
|
|
14
|
+
sideBorders: true,
|
|
15
|
+
verticalChrome: 0,
|
|
16
|
+
statusAttachment: "none",
|
|
17
|
+
bottomBar: "full",
|
|
18
|
+
bottomBarGap: true,
|
|
19
|
+
defaultPromptGutter: undefined,
|
|
20
|
+
|
|
21
|
+
defaultPaddingX(): number {
|
|
22
|
+
return 1;
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
sideChromeWidth(paddingX: number): number {
|
|
26
|
+
return paddingX + 1;
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
renderTop(): undefined {
|
|
30
|
+
return undefined;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
renderRow(ctx: ComposerRowContext): string[] {
|
|
34
|
+
const left = ctx.accentColor(LEFT_CAP);
|
|
35
|
+
const leftFill = padding(ctx.paddingX) + ctx.gutter + ctx.text;
|
|
36
|
+
if (ctx.imeSafeCursorTail) return [left + ctx.surfaceColor(leftFill)];
|
|
37
|
+
|
|
38
|
+
const rightChromeCells = Math.max(1, ctx.paddingX + 1 - ctx.cursorOverflow);
|
|
39
|
+
const interior = leftFill + ctx.pad + padding(rightChromeCells - 1);
|
|
40
|
+
const rightGlyph = ctx.scrollbarThumb ? "█" : RIGHT_CAP;
|
|
41
|
+
return [left + ctx.surfaceColor(interior) + ctx.accentColor(rightGlyph)];
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
renderBottom(): undefined {
|
|
45
|
+
return undefined;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upstream-pi composer: full-width horizontal rules above and below plain
|
|
3
|
+
* padded text — no side borders, no prompt gutter. The status bar renders as
|
|
4
|
+
* a plain standalone bottom bar with both segment groups.
|
|
5
|
+
*/
|
|
6
|
+
import { padding } from "../../utils";
|
|
7
|
+
import type { ComposerChromeContext, ComposerRowContext, ComposerStyle } from "./types";
|
|
8
|
+
|
|
9
|
+
export const piComposerStyle: ComposerStyle = {
|
|
10
|
+
id: "pi",
|
|
11
|
+
sideBorders: false,
|
|
12
|
+
verticalChrome: 2,
|
|
13
|
+
statusAttachment: "none",
|
|
14
|
+
bottomBar: "full",
|
|
15
|
+
bottomBarGap: false,
|
|
16
|
+
defaultPromptGutter: undefined,
|
|
17
|
+
|
|
18
|
+
defaultPaddingX(): number {
|
|
19
|
+
return 1;
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
sideChromeWidth(paddingX: number): number {
|
|
23
|
+
return paddingX;
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
renderTop(ctx: ComposerChromeContext): string {
|
|
27
|
+
return ctx.borderColor(ctx.box.horizontal.repeat(ctx.width));
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
renderRow(ctx: ComposerRowContext): string[] {
|
|
31
|
+
return [padding(this.sideChromeWidth(ctx.paddingX)) + ctx.gutter + ctx.text + ctx.pad];
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
renderBottom(ctx: ComposerChromeContext): string {
|
|
35
|
+
return ctx.borderColor(ctx.box.horizontal.repeat(ctx.width));
|
|
36
|
+
},
|
|
37
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filled composer with one strong accent rail on the left. The asymmetric
|
|
3
|
+
* silhouette separates input from transcript without enclosing it in a box.
|
|
4
|
+
*/
|
|
5
|
+
import { padding } from "../../utils";
|
|
6
|
+
import type { ComposerRowContext, ComposerStyle } from "./types";
|
|
7
|
+
|
|
8
|
+
const ACCENT_RAIL = "▎";
|
|
9
|
+
|
|
10
|
+
/** Filled composer surface anchored by a single left accent rail. */
|
|
11
|
+
export const railComposerStyle: ComposerStyle = {
|
|
12
|
+
id: "rail",
|
|
13
|
+
sideBorders: true,
|
|
14
|
+
verticalChrome: 0,
|
|
15
|
+
statusAttachment: "none",
|
|
16
|
+
bottomBar: "full",
|
|
17
|
+
bottomBarGap: true,
|
|
18
|
+
defaultPromptGutter: undefined,
|
|
19
|
+
|
|
20
|
+
defaultPaddingX(): number {
|
|
21
|
+
return 1;
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
sideChromeWidth(paddingX: number): number {
|
|
25
|
+
return paddingX + 1;
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
renderTop(): undefined {
|
|
29
|
+
return undefined;
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
renderRow(ctx: ComposerRowContext): string[] {
|
|
33
|
+
const rail = ctx.accentColor(ACCENT_RAIL);
|
|
34
|
+
const leftFill = padding(ctx.paddingX) + ctx.gutter + ctx.text;
|
|
35
|
+
if (ctx.imeSafeCursorTail) return [rail + ctx.surfaceColor(leftFill)];
|
|
36
|
+
|
|
37
|
+
const rightFillCells = Math.max(0, ctx.paddingX + 1 - ctx.cursorOverflow);
|
|
38
|
+
if (ctx.scrollbarThumb && rightFillCells > 0) {
|
|
39
|
+
const interior = leftFill + ctx.pad + padding(rightFillCells - 1);
|
|
40
|
+
return [rail + ctx.surfaceColor(interior) + ctx.accentColor("█")];
|
|
41
|
+
}
|
|
42
|
+
return [rail + ctx.surfaceColor(leftFill + ctx.pad + padding(rightFillCells))];
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
renderBottom(): undefined {
|
|
46
|
+
return undefined;
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { borderlessComposerStyle } from "./borderless";
|
|
2
|
+
import { boxComposerStyle } from "./box";
|
|
3
|
+
import { claudeComposerStyle } from "./claude";
|
|
4
|
+
import { fieldComposerStyle } from "./field";
|
|
5
|
+
import { piComposerStyle } from "./pi";
|
|
6
|
+
import { railComposerStyle } from "./rail";
|
|
7
|
+
import { ruleComposerStyle } from "./rule";
|
|
8
|
+
import type { ComposerStyle, EditorBorderStyle } from "./types";
|
|
9
|
+
|
|
10
|
+
const BUILTIN_COMPOSER_STYLES: Readonly<Record<string, ComposerStyle>> = {
|
|
11
|
+
box: boxComposerStyle,
|
|
12
|
+
claude: claudeComposerStyle,
|
|
13
|
+
pi: piComposerStyle,
|
|
14
|
+
borderless: borderlessComposerStyle,
|
|
15
|
+
rule: ruleComposerStyle,
|
|
16
|
+
field: fieldComposerStyle,
|
|
17
|
+
rail: railComposerStyle,
|
|
18
|
+
};
|
|
19
|
+
const extensionComposerStyles = new Map<string, ComposerStyle>();
|
|
20
|
+
|
|
21
|
+
/** Whether an id names a composer style shipped by pi-tui. */
|
|
22
|
+
export function isBuiltinComposerStyle(id: string): boolean {
|
|
23
|
+
return Object.hasOwn(BUILTIN_COMPOSER_STYLES, id);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Register one extension-owned composer style for this process.
|
|
28
|
+
*
|
|
29
|
+
* Built-in ids and duplicate extension ids are rejected. The returned disposer
|
|
30
|
+
* removes only this registration.
|
|
31
|
+
*/
|
|
32
|
+
export function registerComposerStyle(style: ComposerStyle): () => void {
|
|
33
|
+
const id = style.id.trim();
|
|
34
|
+
if (id.length === 0 || id !== style.id) throw new TypeError("Composer style id must be a non-empty trimmed string");
|
|
35
|
+
if (isBuiltinComposerStyle(id)) throw new Error(`Cannot replace built-in composer style "${id}"`);
|
|
36
|
+
if (extensionComposerStyles.has(id)) throw new Error(`Composer style "${id}" is already registered`);
|
|
37
|
+
extensionComposerStyles.set(id, style);
|
|
38
|
+
return () => {
|
|
39
|
+
if (extensionComposerStyles.get(id) === style) extensionComposerStyles.delete(id);
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Style object for a composer shape; unknown ids fall back to `box`. */
|
|
44
|
+
export function getComposerStyle(id: EditorBorderStyle): ComposerStyle {
|
|
45
|
+
return extensionComposerStyles.get(id) ?? BUILTIN_COMPOSER_STYLES[id] ?? boxComposerStyle;
|
|
46
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Single-rule composer: a borderless prompt docked below one top rule. The
|
|
3
|
+
* right status group rides the rule while the left group remains below the
|
|
4
|
+
* editor, preserving the compact status split without a closing rule.
|
|
5
|
+
*/
|
|
6
|
+
import { truncateToWidth, visibleWidth } from "../../utils";
|
|
7
|
+
import type { ComposerChromeContext, ComposerRowContext, ComposerStyle } from "./types";
|
|
8
|
+
|
|
9
|
+
/** Draw a full-width rule with status content docked at its right edge.
|
|
10
|
+
* Over-wide content is truncated (keeping one rule cell on each side) rather
|
|
11
|
+
* than dropped, so the chip survives narrow terminals and previews. */
|
|
12
|
+
export function renderTopRule(ctx: ComposerChromeContext): string {
|
|
13
|
+
const { box, width, borderColor, topBorder } = ctx;
|
|
14
|
+
if (topBorder && topBorder.width > 0 && width > 2) {
|
|
15
|
+
let { content, width: chipWidth } = topBorder;
|
|
16
|
+
if (chipWidth > width - 2) {
|
|
17
|
+
content = truncateToWidth(content, width - 2);
|
|
18
|
+
chipWidth = visibleWidth(content);
|
|
19
|
+
}
|
|
20
|
+
const leftFill = Math.max(0, width - chipWidth - 1);
|
|
21
|
+
return borderColor(box.horizontal.repeat(leftFill)) + content + borderColor(box.horizontal);
|
|
22
|
+
}
|
|
23
|
+
return borderColor(box.horizontal.repeat(width));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Composer style with one status-bearing top rule and no bottom chrome. */
|
|
27
|
+
export const ruleComposerStyle: ComposerStyle = {
|
|
28
|
+
id: "rule",
|
|
29
|
+
sideBorders: false,
|
|
30
|
+
verticalChrome: 1,
|
|
31
|
+
statusAttachment: "top-rule-chip",
|
|
32
|
+
bottomBar: "left",
|
|
33
|
+
bottomBarGap: true,
|
|
34
|
+
defaultPromptGutter: "❯ ",
|
|
35
|
+
|
|
36
|
+
defaultPaddingX(): number {
|
|
37
|
+
return 0;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
sideChromeWidth(paddingX: number): number {
|
|
41
|
+
return paddingX;
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
renderTop(ctx: ComposerChromeContext): string {
|
|
45
|
+
return renderTopRule(ctx);
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
renderRow(ctx: ComposerRowContext): string[] {
|
|
49
|
+
return [ctx.gutter + ctx.text + ctx.pad];
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
renderBottom(): undefined {
|
|
53
|
+
return undefined;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composer chrome contract. A {@link ComposerStyle} owns everything about how
|
|
3
|
+
* the input editor's frame looks — top/bottom chrome, per-row side chrome,
|
|
4
|
+
* default padding and prompt gutter — plus metadata telling the host where the
|
|
5
|
+
* status bar attaches. The editor, the /settings preview, and the setup-wizard
|
|
6
|
+
* preview all render through the same style object, so the three surfaces can
|
|
7
|
+
* never drift apart.
|
|
8
|
+
*/
|
|
9
|
+
import type { SymbolTheme } from "../../symbols";
|
|
10
|
+
|
|
11
|
+
/** Box-drawing glyph set used for composer chrome (the theme's `boxRound`). */
|
|
12
|
+
export type ComposerBox = SymbolTheme["boxRound"];
|
|
13
|
+
|
|
14
|
+
/** Built-in composer shape identifiers shipped by pi-tui. */
|
|
15
|
+
export const BUILTIN_EDITOR_BORDER_STYLES = ["box", "claude", "pi", "borderless", "rule", "field", "rail"] as const;
|
|
16
|
+
|
|
17
|
+
/** Identifier for a built-in composer shape. */
|
|
18
|
+
export type BuiltinEditorBorderStyle = (typeof BUILTIN_EDITOR_BORDER_STYLES)[number];
|
|
19
|
+
|
|
20
|
+
/** Composer shape identifier; extensions may register additional strings. */
|
|
21
|
+
export type EditorBorderStyle = string;
|
|
22
|
+
|
|
23
|
+
/** Pre-rendered status content injected into the top chrome. */
|
|
24
|
+
export interface EditorTopBorder {
|
|
25
|
+
/** The status content (already styled) */
|
|
26
|
+
content: string;
|
|
27
|
+
/** Visible width of the content */
|
|
28
|
+
width: number;
|
|
29
|
+
/** Optional logical revision that changes independently of available width. */
|
|
30
|
+
revision?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Inputs shared by every chrome row. */
|
|
34
|
+
export interface ComposerChromeContext {
|
|
35
|
+
/** Full terminal width available to the composer. */
|
|
36
|
+
width: number;
|
|
37
|
+
/** Horizontal padding inside the side chrome. */
|
|
38
|
+
paddingX: number;
|
|
39
|
+
borderColor: (str: string) => string;
|
|
40
|
+
/** Stable accent used by shape-defining chrome such as field caps and rails. */
|
|
41
|
+
accentColor: (str: string) => string;
|
|
42
|
+
/** Background fill for composer surfaces; preserves the fill across nested SGR resets. */
|
|
43
|
+
surfaceColor: (str: string) => string;
|
|
44
|
+
/** Box-drawing glyph set (theme's `boxRound`). */
|
|
45
|
+
box: ComposerBox;
|
|
46
|
+
/** Status content for the top chrome; box embeds it after the corner while
|
|
47
|
+
* rule-based styles dock it against the right edge. */
|
|
48
|
+
topBorder?: EditorTopBorder;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Inputs for one content row. */
|
|
52
|
+
export interface ComposerRowContext extends ComposerChromeContext {
|
|
53
|
+
/** Fully decorated row text (cursor glyph / IME marker included). */
|
|
54
|
+
text: string;
|
|
55
|
+
/** Spaces padding the text out to the content width. */
|
|
56
|
+
pad: string;
|
|
57
|
+
/** Prompt gutter cells for this row ("" when the style has none). */
|
|
58
|
+
gutter: string;
|
|
59
|
+
isLastRow: boolean;
|
|
60
|
+
/** Cells the end-of-line cursor overflowed into the right chrome (box). */
|
|
61
|
+
cursorOverflow: number;
|
|
62
|
+
/** Emit an empty right chrome after the cursor so terminal-local IME
|
|
63
|
+
* preedit cannot shift the frame (box last row). */
|
|
64
|
+
imeSafeCursorTail: boolean;
|
|
65
|
+
/** Row lies inside the right-border scrollbar thumb (box). */
|
|
66
|
+
scrollbarThumb: boolean;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ComposerStyle {
|
|
70
|
+
readonly id: EditorBorderStyle;
|
|
71
|
+
/** Content rows carry left/right border glyphs; drives the cursor-reserve
|
|
72
|
+
* column, IME-safe layout, and the right-border scrollbar. */
|
|
73
|
+
readonly sideBorders: boolean;
|
|
74
|
+
/** Rows consumed by top+bottom chrome (drives maxHeight budgeting). */
|
|
75
|
+
readonly verticalChrome: 0 | 1 | 2;
|
|
76
|
+
/** Where the host should attach the status bar: embedded in the top border,
|
|
77
|
+
* docked onto a top rule, or detached into a standalone bottom bar. */
|
|
78
|
+
readonly statusAttachment: "top-border" | "top-rule-chip" | "none";
|
|
79
|
+
/** Which segment groups the standalone bottom status bar shows. */
|
|
80
|
+
readonly bottomBar: "none" | "left" | "full";
|
|
81
|
+
/** Insert a blank spacer row between the editor and the standalone bottom
|
|
82
|
+
* bar. Styles without bottom chrome need it so the bar doesn't sit flush
|
|
83
|
+
* against the last input row. */
|
|
84
|
+
readonly bottomBarGap: boolean;
|
|
85
|
+
/** Default prompt gutter when the host sets none. */
|
|
86
|
+
readonly defaultPromptGutter: string | undefined;
|
|
87
|
+
/** Default horizontal padding; `themePaddingX` is the theme's request. */
|
|
88
|
+
defaultPaddingX(themePaddingX: number | undefined): number;
|
|
89
|
+
/** Cells consumed per side on content rows (border glyph + padding). */
|
|
90
|
+
sideChromeWidth(paddingX: number): number;
|
|
91
|
+
/** Top chrome row; `undefined` renders none. */
|
|
92
|
+
renderTop(ctx: ComposerChromeContext): string | undefined;
|
|
93
|
+
/** Chrome-wrapped content row; box's IME-safe last row emits two rows. */
|
|
94
|
+
renderRow(ctx: ComposerRowContext): string[];
|
|
95
|
+
/** Bottom chrome row; `undefined` renders none (box merges the bottom
|
|
96
|
+
* border into its last content row). */
|
|
97
|
+
renderBottom(ctx: ComposerChromeContext): string | undefined;
|
|
98
|
+
}
|