jeopi-tui 16.2.13 → 16.2.14

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/package.json +7 -7
  3. package/src/terminal-capabilities.ts +9 -0
  4. package/dist/types/autocomplete.d.ts +0 -99
  5. package/dist/types/bracketed-paste.d.ts +0 -51
  6. package/dist/types/components/box.d.ts +0 -31
  7. package/dist/types/components/cancellable-loader.d.ts +0 -21
  8. package/dist/types/components/editor.d.ts +0 -155
  9. package/dist/types/components/image.d.ts +0 -112
  10. package/dist/types/components/input.d.ts +0 -23
  11. package/dist/types/components/loader.d.ts +0 -20
  12. package/dist/types/components/markdown.d.ts +0 -64
  13. package/dist/types/components/scroll-view.d.ts +0 -62
  14. package/dist/types/components/select-list.d.ts +0 -68
  15. package/dist/types/components/settings-list.d.ts +0 -123
  16. package/dist/types/components/spacer.d.ts +0 -11
  17. package/dist/types/components/tab-bar.d.ts +0 -89
  18. package/dist/types/components/text.d.ts +0 -14
  19. package/dist/types/components/truncated-text.d.ts +0 -10
  20. package/dist/types/deccara.d.ts +0 -49
  21. package/dist/types/desktop-notify.d.ts +0 -51
  22. package/dist/types/editor-component.d.ts +0 -38
  23. package/dist/types/fuzzy.d.ts +0 -32
  24. package/dist/types/index.d.ts +0 -32
  25. package/dist/types/keybindings.d.ts +0 -191
  26. package/dist/types/keys.d.ts +0 -208
  27. package/dist/types/kill-ring.d.ts +0 -20
  28. package/dist/types/kitty-graphics.d.ts +0 -79
  29. package/dist/types/latex-block.d.ts +0 -7
  30. package/dist/types/latex-to-unicode.d.ts +0 -33
  31. package/dist/types/loop-watchdog.d.ts +0 -39
  32. package/dist/types/mouse.d.ts +0 -67
  33. package/dist/types/stdin-buffer.d.ts +0 -60
  34. package/dist/types/symbols.d.ts +0 -25
  35. package/dist/types/terminal-capabilities.d.ts +0 -284
  36. package/dist/types/terminal.d.ts +0 -107
  37. package/dist/types/ttyid.d.ts +0 -9
  38. package/dist/types/tui.d.ts +0 -423
  39. package/dist/types/utils.d.ts +0 -95
package/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [16.2.14] - 2026-07-02
6
+
5
7
  ### Fixed
6
8
 
7
9
  - Fixed a potential event loop hang caused by processing oversized, unterminated terminal escape sequences (OSC/DCS/APC).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "jeopi-tui",
4
- "version": "16.2.13",
4
+ "version": "16.2.14",
5
5
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
6
6
  "homepage": "https://github.com/akillness/jeopi",
7
7
  "author": "Can Boluk",
@@ -37,14 +37,14 @@
37
37
  "fmt": "biome format --write ."
38
38
  },
39
39
  "dependencies": {
40
- "jeopi-natives": "16.2.13",
41
- "jeopi-utils": "16.2.13",
42
- "lru-cache": "11.5.1",
43
- "marked": "^18.0.5"
40
+ "jeopi-natives": "catalog:",
41
+ "jeopi-utils": "catalog:",
42
+ "lru-cache": "catalog:",
43
+ "marked": "catalog:"
44
44
  },
45
45
  "devDependencies": {
46
- "chalk": "^5.6.2",
47
- "ghostty-web": "^0.4.0"
46
+ "chalk": "catalog:",
47
+ "ghostty-web": "catalog:"
48
48
  },
49
49
  "engines": {
50
50
  "bun": ">=1.3.14"
@@ -525,6 +525,15 @@ export const TERMINAL: RuntimeTerminal = (() => {
525
525
  // ignores DECCARA) exercises the padded-string fallback. Integration tests opt
526
526
  // in explicitly through setTerminalDeccara.
527
527
  resolved.deccara = detectRectangularSgrSupport(resolved.id, Bun.env) && !isBunTestRuntime();
528
+ // OSC 66 text-sizing. The static per-terminal capability lives on
529
+ // KNOWN_TERMINALS (true for kitty/ghostty/wezterm/iterm2) and is otherwise
530
+ // gated behind the `tui.textSizing` setting at runtime — but resolving it raw
531
+ // here means running the test suite itself from inside one of those terminals
532
+ // (e.g. kitty) leaks `TERM_PROGRAM` into `Bun.env` and flips the "disabled by
533
+ // default" assumption every heading test relies on. Force it off under the
534
+ // test runtime, same as deccara above; tests opt in explicitly via
535
+ // setTerminalTextSizing.
536
+ resolved.textSizing = resolved.textSizing && !isBunTestRuntime();
528
537
  return resolved;
529
538
  })();
530
539
 
@@ -1,99 +0,0 @@
1
- /**
2
- * Locate the slash that opens a slash command on the line, allowing leading
3
- * whitespace. Returns the index of the `/` or `null` when the line is not a
4
- * slash command. Aligns with `trimStart` semantics so the editor and provider
5
- * agree on which prefixes count.
6
- */
7
- export declare function findLeadingSlashCommandStart(text: string): number | null;
8
- export declare function findTrailingSlashCommandStart(text: string): number | null;
9
- export interface AutocompleteItem {
10
- value: string;
11
- label: string;
12
- description?: string;
13
- /** Dim hint text shown inline after cursor when this item is selected */
14
- hint?: string;
15
- }
16
- type Awaitable<T> = T | Promise<T>;
17
- export interface SlashCommand {
18
- name: string;
19
- aliases?: string[];
20
- description?: string;
21
- argumentHint?: string;
22
- /** Dynamic display-only description for slash-command autocomplete. Must be synchronous and side-effect free. */
23
- getAutocompleteDescription?: () => string | undefined;
24
- getArgumentCompletions?(argumentPrefix: string): Awaitable<AutocompleteItem[] | null>;
25
- /** Return inline hint text for the current argument state (shown as dim ghost text after cursor) */
26
- getInlineHint?(argumentText: string): string | null;
27
- }
28
- export interface AutocompleteProvider {
29
- /** Get autocomplete suggestions for current text/cursor position */
30
- getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<{
31
- items: AutocompleteItem[];
32
- prefix: string;
33
- } | null>;
34
- /** Apply the selected item and return new text + cursor position */
35
- applyCompletion(lines: string[], cursorLine: number, cursorCol: number, item: AutocompleteItem, prefix: string): {
36
- lines: string[];
37
- cursorLine: number;
38
- cursorCol: number;
39
- onApplied?: () => void;
40
- };
41
- /** Get inline hint text to show as dim ghost text after the cursor */
42
- getInlineHint?(lines: string[], cursorLine: number, cursorCol: number): string | null;
43
- /** Synchronously try to complete a slash command at the start of a line (no async I/O). */
44
- /** Returns matched items and the full prefix, or null if not applicable. */
45
- trySyncSlashCompletion?(textBeforeCursor: string): {
46
- items: AutocompleteItem[];
47
- prefix: string;
48
- } | null;
49
- /**
50
- * Synchronously try to expand text immediately before the cursor (no async I/O).
51
- * Called after every single-character insert. Implementations MUST cheaply
52
- * early-return when the trailing context cannot trigger them.
53
- * Returns the number of characters to delete immediately before the cursor
54
- * and the literal string to insert in their place, or null to leave the
55
- * buffer untouched.
56
- */
57
- trySyncInlineReplace?(textBeforeCursor: string): {
58
- replaceLen: number;
59
- insert: string;
60
- } | null;
61
- /**
62
- * Force file-path completion (called on Tab). Returns matched items plus the
63
- * full prefix, or null when no path token sits before the cursor. Present on
64
- * file-aware providers; absent on slash-only ones.
65
- */
66
- getForceFileSuggestions?(lines: string[], cursorLine: number, cursorCol: number): Promise<{
67
- items: AutocompleteItem[];
68
- prefix: string;
69
- } | null>;
70
- /** Whether a Tab press should attempt file completion at the cursor. */
71
- shouldTriggerFileCompletion?(lines: string[], cursorLine: number, cursorCol: number): boolean;
72
- }
73
- type CommandEntry = SlashCommand | AutocompleteItem;
74
- export declare class CombinedAutocompleteProvider implements AutocompleteProvider {
75
- #private;
76
- constructor(commands?: CommandEntry[], basePath?: string);
77
- getSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<{
78
- items: AutocompleteItem[];
79
- prefix: string;
80
- } | null>;
81
- applyCompletion(lines: string[], cursorLine: number, cursorCol: number, item: AutocompleteItem, prefix: string): {
82
- lines: string[];
83
- cursorLine: number;
84
- cursorCol: number;
85
- };
86
- invalidateDirCache(dir?: string): void;
87
- getForceFileSuggestions(lines: string[], cursorLine: number, cursorCol: number): Promise<{
88
- items: AutocompleteItem[];
89
- prefix: string;
90
- } | null>;
91
- shouldTriggerFileCompletion(lines: string[], cursorLine: number, cursorCol: number): boolean;
92
- /** Get inline hint text for slash commands with subcommand hints */
93
- getInlineHint(lines: string[], cursorLine: number, cursorCol: number): string | null;
94
- trySyncSlashCompletion(textBeforeCursor: string): {
95
- items: AutocompleteItem[];
96
- prefix: string;
97
- } | null;
98
- }
99
- export {};
@@ -1,51 +0,0 @@
1
- export type PasteResult = {
2
- handled: false;
3
- } | {
4
- handled: true;
5
- pasteContent?: string;
6
- remaining: string;
7
- };
8
- /**
9
- * Decode tmux's re-encoded control bytes (both `extended-keys-format` variants) inside a
10
- * bracketed-paste payload back to their literal byte (e.g. Ctrl+J → "\n"). Leaves the rest of
11
- * the text untouched. Call before any control-character stripping so newlines/tabs survive
12
- * instead of leaking the printable escape tail into the buffer.
13
- */
14
- export declare function decodeReencodedPasteControls(text: string): string;
15
- /**
16
- * Options for {@link BracketedPasteHandler}.
17
- */
18
- export type BracketedPasteHandlerOptions = {
19
- /**
20
- * Byte cap for buffered paste content (default: 64 MiB). When exceeded,
21
- * paste mode is aborted and the accumulated content is delivered as
22
- * `pasteContent` on the same `process()` call so a lost/corrupted end
23
- * marker cannot consume unbounded memory. Mirrors `StdinBuffer#abortPaste`
24
- * — defense in depth for callers that bypass `StdinBuffer` (issue #4073
25
- * case B). The normal `ProcessTerminal` path re-wraps `StdinBuffer`'s
26
- * bounded paste with both markers, so this cap only fires on alternate
27
- * callers.
28
- */
29
- byteLimit?: number;
30
- };
31
- /**
32
- * Handles bracketed paste mode buffering for terminal input components.
33
- *
34
- * Bracketed paste mode wraps pasted content between start (\x1b[200~) and
35
- * end (\x1b[201~) markers, which may arrive split across multiple chunks.
36
- * This class buffers incoming data and assembles complete paste payloads.
37
- */
38
- export declare class BracketedPasteHandler {
39
- #private;
40
- constructor(options?: BracketedPasteHandlerOptions);
41
- /**
42
- * Process incoming terminal data for bracketed paste sequences.
43
- *
44
- * @returns `{ handled: false }` if the data contains no paste sequence and
45
- * should be processed normally. `{ handled: true }` if the data was
46
- * consumed by paste buffering — `pasteContent` is set when a complete
47
- * paste has been assembled (or the byte cap has aborted a runaway
48
- * buffer); omitted when still buffering.
49
- */
50
- process(data: string): PasteResult;
51
- }
@@ -1,31 +0,0 @@
1
- import type { Component } from "../tui";
2
- /** Box-drawing glyphs plus an optional colorizer for an outline drawn around a {@link Box}. */
3
- export interface BoxBorder {
4
- chars: {
5
- topLeft: string;
6
- topRight: string;
7
- bottomLeft: string;
8
- bottomRight: string;
9
- horizontal: string;
10
- vertical: string;
11
- };
12
- color?: (text: string) => string;
13
- }
14
- /**
15
- * Box component - a container that applies padding and background to all children
16
- */
17
- export declare class Box implements Component {
18
- #private;
19
- children: Component[];
20
- setIgnoreTight(ignore: boolean): this;
21
- constructor(paddingX?: number, paddingY?: number, bgFn?: (text: string) => string, border?: BoxBorder);
22
- addChild(component: Component): void;
23
- removeChild(component: Component): void;
24
- clear(): void;
25
- setPaddingX(paddingX: number): void;
26
- setPaddingY(paddingY: number): void;
27
- setBgFn(bgFn?: (text: string) => string): void;
28
- setBorder(border?: BoxBorder): void;
29
- invalidate(): void;
30
- render(width: number): readonly string[];
31
- }
@@ -1,21 +0,0 @@
1
- import { Loader } from "./loader";
2
- /**
3
- * Loader that can be cancelled with Escape.
4
- * Extends Loader with an AbortSignal for cancelling async operations.
5
- *
6
- * @example
7
- * const loader = new CancellableLoader(tui, cyan, dim, "Working...");
8
- * loader.onAbort = () => done(null);
9
- * doWork(loader.signal).then(done);
10
- */
11
- export declare class CancellableLoader extends Loader {
12
- #private;
13
- /** Called when user presses Escape */
14
- onAbort?: () => void;
15
- /** AbortSignal that is aborted when user presses Escape */
16
- get signal(): AbortSignal;
17
- /** Whether the loader was aborted */
18
- get aborted(): boolean;
19
- handleInput(data: string): void;
20
- dispose(): void;
21
- }
@@ -1,155 +0,0 @@
1
- import { type AutocompleteProvider } from "../autocomplete";
2
- import type { SymbolTheme } from "../symbols";
3
- import { type Component, type Focusable } from "../tui";
4
- import { type SelectListTheme } from "./select-list";
5
- export interface EditorTheme {
6
- borderColor: (str: string) => string;
7
- selectList: SelectListTheme;
8
- symbols: SymbolTheme;
9
- editorPaddingX?: number;
10
- /** Style function for inline hint/ghost text (dim text after cursor) */
11
- hintStyle?: (text: string) => string;
12
- }
13
- export interface EditorTopBorder {
14
- /** The status content (already styled) */
15
- content: string;
16
- /** Visible width of the content */
17
- width: number;
18
- }
19
- interface HistoryEntry {
20
- prompt: string;
21
- }
22
- interface HistoryStorage {
23
- add(prompt: string, cwd?: string): Promise<void>;
24
- getRecent(limit: number): HistoryEntry[];
25
- }
26
- export declare class Editor implements Component, Focusable {
27
- #private;
28
- /** Focusable interface - set by TUI when focus changes */
29
- focused: boolean;
30
- /** When set, replaces the normal cursor glyph at end-of-text with this ANSI-styled string. */
31
- cursorOverride: string | undefined;
32
- /** Display width of the cursorOverride glyph (needed because override may contain ANSI escapes). */
33
- cursorOverrideWidth: number | undefined;
34
- /** Optional hook that styles displayed input text with zero-width ANSI escapes.
35
- * MUST preserve visible width (may only add SGR codes, never glyphs). Applied per
36
- * layout line to the user-text segments — never to the cursor glyph or inline hint. */
37
- decorateText: ((text: string) => string) | undefined;
38
- borderColor: (str: string) => string;
39
- onAutocompleteUpdate?: () => void;
40
- /** Optional pattern matching atomic placeholder tokens (e.g. `[Image #1, 800x600]` or
41
- * `[Paste #2, +30 lines]`) that the editor treats as indivisible: a backspace or forward-delete
42
- * landing on any character of a token removes the whole token instead of corrupting it into
43
- * stray text. MUST be a global regex; the editor recompiles a private copy so its `lastIndex`
44
- * is never shared with the caller. */
45
- atomicTokenPattern: RegExp | undefined;
46
- onSubmit?: (text: string) => void | Promise<void>;
47
- onAltEnter?: (text: string) => void;
48
- onChange?: (text: string) => void;
49
- /** Called for a "marker-sized" paste — the point where the editor would otherwise collapse it
50
- * into a `[Paste #N]` token (> 10 lines or > 1000 characters). Return `true` to intercept:
51
- * the editor inserts nothing and records no undo state, leaving insertion to the host (e.g. a
52
- * "wrap in a code block / XML / attach as file" menu for very large pastes), which re-inserts
53
- * via {@link insertPaste} or {@link insertText}. Return `false` (or leave unset) for the
54
- * default collapse-to-marker behavior. `lineCount` is the sanitized paste's line count. */
55
- onLargePaste?: (text: string, lineCount: number) => boolean;
56
- onAutocompleteCancel?: () => void;
57
- disableSubmit: boolean;
58
- constructor(theme: EditorTheme);
59
- setAutocompleteProvider(provider: AutocompleteProvider): void;
60
- /**
61
- * Set custom content for the top border (e.g., status line).
62
- * Pass undefined to use the default plain border.
63
- *
64
- * Eager: the passed value is cached and reused every frame. Callers that
65
- * mutate status upstream must recompute and call this again. Prefer
66
- * {@link setTopBorderProvider} for high-frequency updates — it collapses
67
- * per-event rebuilds to one per painted frame.
68
- */
69
- setTopBorder(content: EditorTopBorder | undefined): void;
70
- /**
71
- * Install a lazy provider invoked once per editor render with the current
72
- * `availableWidth`. Overrides any eager content set via {@link setTopBorder}
73
- * — pass `undefined` to detach and fall back to the eager slot.
74
- *
75
- * Use this when the top border derives from state that mutates far faster
76
- * than the render cadence (session events, streaming, subagent updates).
77
- * The TUI already throttles renders, so a provider is invoked at most once
78
- * per frame and never does wasted work between paints.
79
- */
80
- setTopBorderProvider(provider: ((availableWidth: number) => EditorTopBorder | undefined) | undefined): void;
81
- /**
82
- * Show or hide the editor border chrome.
83
- */
84
- setBorderVisible(borderVisible: boolean): void;
85
- setPromptGutter(promptGutter: string | undefined): void;
86
- /**
87
- * Get the available width for top border content given a total terminal width.
88
- * Accounts for the border characters and horizontal padding when visible.
89
- */
90
- getTopBorderAvailableWidth(terminalWidth: number): number;
91
- /**
92
- * Use the real terminal cursor instead of rendering a cursor glyph.
93
- */
94
- setUseTerminalCursor(useTerminalCursor: boolean): void;
95
- getUseTerminalCursor(): boolean;
96
- setMaxHeight(maxHeight: number | undefined): void;
97
- setPaddingX(paddingX: number): void;
98
- getAutocompleteMaxVisible(): number;
99
- setAutocompleteMaxVisible(maxVisible: number): void;
100
- setHistoryStorage(storage: HistoryStorage): void;
101
- /**
102
- * Add a prompt to history for up/down arrow navigation.
103
- * Called after successful submission.
104
- */
105
- addToHistory(text: string): void;
106
- invalidate(): void;
107
- render(width: number): readonly string[];
108
- handleInput(data: string): void;
109
- getText(): string;
110
- /**
111
- * Get text with paste markers expanded to their actual content.
112
- * Use this when you need the full content (e.g., for external editor).
113
- */
114
- getExpandedText(): string;
115
- getLines(): string[];
116
- getCursor(): {
117
- line: number;
118
- col: number;
119
- };
120
- moveToLineStart(): void;
121
- moveToLineEnd(): void;
122
- moveToMessageStart(): void;
123
- moveToMessageEnd(): void;
124
- /**
125
- * Undo the last meaningful edit while ignoring transient text that is still present at the cursor.
126
- * Used for command-like autocomplete actions whose typed trigger should not count as the edit being undone.
127
- */
128
- undoPastTransientText(transientText: string): void;
129
- setText(text: string): void;
130
- submit(): void;
131
- /** Insert text at the current cursor position */
132
- insertText(text: string): void;
133
- /** Delete up to `count` characters immediately before the cursor on the current line.
134
- * Used to "track back" the auto-repeat spaces that the space-hold push-to-talk gesture
135
- * optimistically inserts before it recognizes the hold. Capped at the cursor column so it
136
- * never crosses a line boundary or under-runs the line. */
137
- deleteBeforeCursor(count: number): void;
138
- /** Show or replace a volatile speech-to-text preview at the cursor. The text is
139
- * inserted with undo suspended so a long live dictation never floods the undo
140
- * stack; finalize it with {@link commitVolatileText} or drop it with
141
- * {@link clearVolatileText}. Newlines are allowed. */
142
- setVolatileText(text: string): void;
143
- /** Remove the current volatile preview without committing it. */
144
- clearVolatileText(): void;
145
- /** Drop any volatile preview, then insert `text` as a single undoable edit. */
146
- commitVolatileText(text: string): void;
147
- /** Apply terminal paste semantics to text from non-bracketed paste transports. */
148
- pasteText(text: string): void;
149
- /** Insert `content` as a collapsed `[Paste #N]` marker (stored for expansion on submit via
150
- * {@link getExpandedText}). Hosts that intercept large pastes through {@link onLargePaste} use
151
- * this to re-insert a (possibly transformed) paste without re-triggering the interception hook. */
152
- insertPaste(content: string): void;
153
- isShowingAutocomplete(): boolean;
154
- }
155
- export {};
@@ -1,112 +0,0 @@
1
- import { type ImageDimensions } from "../terminal-capabilities";
2
- import type { Component } from "../tui";
3
- export interface ImageTheme {
4
- fallbackColor: (str: string) => string;
5
- }
6
- export interface ImageOptions {
7
- maxWidthCells?: number;
8
- maxHeightCells?: number;
9
- filename?: string;
10
- /** Shared budget that caps how many inline images render as live graphics. */
11
- budget?: ImageBudget;
12
- /**
13
- * Stable identity for the underlying image (e.g. `toolCallId:index`). Lets the
14
- * budget hand back the same graphics id across component re-creations so a
15
- * repaint replaces the placement instead of stacking a duplicate.
16
- */
17
- imageKey?: string;
18
- }
19
- /** Default count of inline images kept as live graphics before older ones fall back to text. */
20
- export declare const DEFAULT_MAX_INLINE_IMAGES = 8;
21
- /**
22
- * Bounds how many inline images render as live terminal graphics at once.
23
- *
24
- * Terminal graphics protocols — Kitty especially — keep every transmitted image
25
- * in a per-terminal store and re-draw placements as content scrolls; text-clear
26
- * escapes (`CSI 2 J` / `CSI 3 J`) do not remove them. Unbounded, a session that
27
- * shows many images piles up placements plus store memory and leaves ghosts in
28
- * scrollback.
29
- *
30
- * The budget keeps the most recent `cap` images live and demotes older ones to
31
- * their text fallback. Demotion needs a full redraw (so off-screen rows are
32
- * rewritten) plus an explicit graphics purge of the demoted ids — {@link Image}
33
- * reports display order via {@link observe}, and the TUI drives the purge +
34
- * redraw on the frame after a new image pushes the count past the cap.
35
- *
36
- * `cap <= 0` disables budgeting: every image stays a live graphic.
37
- */
38
- export declare class ImageBudget {
39
- #private;
40
- constructor(cap?: number, requestRender?: () => void);
41
- get cap(): number;
42
- get enabled(): boolean;
43
- setRequestRender(requestRender: () => void): void;
44
- setCap(cap: number): void;
45
- /**
46
- * Stable graphics id for a logical image. A non-empty `key` maps to the same
47
- * id across re-creations (so repaints replace the placement); a missing key
48
- * gets a fresh id every call.
49
- */
50
- acquireId(key?: string): number;
51
- /**
52
- * Begin a render pass. Called by the renderer before composing the frame.
53
- * Pass `stable: true` for a partial/throwaway pass that does not walk the
54
- * whole tree in display order (the resize viewport fast path): {@link observe}
55
- * then replays the last committed per-id decision instead of one derived from
56
- * call order, and the pass must NOT be closed with {@link endPass}.
57
- */
58
- beginPass(stable?: boolean): void;
59
- /**
60
- * Record an image in display order and report whether it must render its text
61
- * fallback this frame. Called by every {@link Image} during render — including
62
- * on a cache hit, so the image keeps its display-order slot.
63
- *
64
- * During a `stable` pass ({@link beginPass}) the call order and visible subset
65
- * are not authoritative, so the decision is the committed on-terminal split
66
- * (`#suppressedIds`) keyed by id — order- and partiality-independent.
67
- */
68
- observe(imageId: number): boolean;
69
- /**
70
- * End a render pass. Returns true when this frame must purge graphics and
71
- * fully repaint to apply a stricter budget; read the ids via
72
- * {@link takePurgeIds}.
73
- */
74
- endPass(): boolean;
75
- /** Image ids to delete from the terminal this frame; clears the pending set. */
76
- takePurgeIds(): readonly number[];
77
- /** All image ids believed to be loaded in the terminal store; clears tracking. */
78
- takeAllTransmittedIds(): readonly number[];
79
- /** Whether `imageId`'s data still needs to be transmitted to the terminal. */
80
- shouldTransmit(imageId: number): boolean;
81
- /**
82
- * Queue a one-time transmit for `imageId`. No-op if already transmitted, so a
83
- * repeated call (e.g. a width-change re-render) never re-sends the data.
84
- */
85
- enqueueTransmit(imageId: number, sequence: string): void;
86
- /** Whether a frame has image data queued but not yet written to the terminal. */
87
- hasPendingTransmits(): boolean;
88
- /**
89
- * True when the budget has nothing in flight: no live images observed on
90
- * the last pass, no queued transmits, no pending purges, and no stricter
91
- * threshold left to apply. A component-scoped frame may skip the observe
92
- * pass only then — a partial tree walk would under-count display order.
93
- */
94
- get quiescent(): boolean;
95
- /** Transmit sequences to write before this frame's placements; clears the queue. */
96
- takeTransmits(): readonly string[];
97
- /**
98
- * Drop transmit tracking so every still-live image re-enqueues its data
99
- * (`a=t`) on the next render. Recovers when the terminal dropped the original
100
- * transmit — e.g. Ghostty discarding graphics sent during its post-startup
101
- * window — where a placement-only replay can never bind a Unicode placeholder.
102
- * Pair with a component invalidate + forced repaint so the data and placement
103
- * re-emit together; keeps no base64 in budget state (the transmit-once design).
104
- */
105
- forgetTransmitted(): void;
106
- }
107
- export declare class Image implements Component {
108
- #private;
109
- constructor(base64Data: string, mimeType: string, theme: ImageTheme, options?: ImageOptions, dimensions?: ImageDimensions);
110
- invalidate(): void;
111
- render(width: number): readonly string[];
112
- }
@@ -1,23 +0,0 @@
1
- import { type Component, type Focusable } from "../tui";
2
- /**
3
- * Input component - single-line text input with horizontal scrolling
4
- */
5
- export declare class Input implements Component, Focusable {
6
- #private;
7
- /** Rendered before the editable area; set to "" for chrome-less embedding. */
8
- prompt: string;
9
- onSubmit?: (value: string) => void;
10
- onEscape?: () => void;
11
- /** Focusable interface - set by TUI when focus changes */
12
- focused: boolean;
13
- getValue(): string;
14
- setValue(value: string): void;
15
- setUseTerminalCursor(useTerminalCursor: boolean): void;
16
- getUseTerminalCursor(): boolean;
17
- handleInput(data: string): void;
18
- /** Apply terminal paste semantics to text from non-bracketed paste transports
19
- * (e.g. kitty's OSC 5522 enhanced clipboard read). Mirrors `Editor.pasteText`. */
20
- pasteText(text: string): void;
21
- invalidate(): void;
22
- render(width: number): readonly string[];
23
- }
@@ -1,20 +0,0 @@
1
- import type { TUI } from "../tui";
2
- import { Text } from "./text";
3
- type ColorFn = (str: string) => string;
4
- export type LoaderMessageColorFn = ColorFn & {
5
- readonly animated?: true;
6
- };
7
- export declare class Loader extends Text {
8
- #private;
9
- private spinnerColorFn;
10
- private messageColorFn;
11
- private message;
12
- constructor(ui: TUI, spinnerColorFn: ColorFn, messageColorFn: LoaderMessageColorFn, message?: string, spinnerFrames?: string[]);
13
- render(width: number): readonly string[];
14
- start(): void;
15
- stop(): void;
16
- /** Lifecycle teardown: stop the animation timer. Idempotent. */
17
- dispose(): void;
18
- setMessage(message: string): void;
19
- }
20
- export {};
@@ -1,64 +0,0 @@
1
- import type { SymbolTheme } from "../symbols";
2
- import type { Component } from "../tui";
3
- /** Drop all L2 cache entries. Call on theme change to prevent stale styled output. */
4
- export declare function clearRenderCache(): void;
5
- /**
6
- * Default text styling for markdown content.
7
- * Applied to all text unless overridden by markdown formatting.
8
- */
9
- export interface DefaultTextStyle {
10
- /** Foreground color function */
11
- color?: (text: string) => string;
12
- /** Background color function */
13
- bgColor?: (text: string) => string;
14
- /** Bold text */
15
- bold?: boolean;
16
- /** Italic text */
17
- italic?: boolean;
18
- /** Strikethrough text */
19
- strikethrough?: boolean;
20
- /** Underline text */
21
- underline?: boolean;
22
- }
23
- /**
24
- * Theme functions for markdown elements.
25
- * Each function takes text and returns styled text with ANSI codes.
26
- */
27
- export interface MarkdownTheme {
28
- heading: (text: string) => string;
29
- link: (text: string) => string;
30
- linkUrl: (text: string) => string;
31
- code: (text: string) => string;
32
- codeBlock: (text: string) => string;
33
- codeBlockBorder: (text: string) => string;
34
- quote: (text: string) => string;
35
- quoteBorder: (text: string) => string;
36
- hr: (text: string) => string;
37
- listBullet: (text: string) => string;
38
- bold: (text: string) => string;
39
- italic: (text: string) => string;
40
- strikethrough: (text: string) => string;
41
- underline: (text: string) => string;
42
- highlightCode?: (code: string, lang?: string) => string[];
43
- /**
44
- * Resolve a mermaid ASCII rendering by fenced block source text.
45
- * Return null to fall back to fenced code rendering.
46
- */
47
- resolveMermaidAscii?: (source: string, maxWidth?: number) => string | null;
48
- symbols: SymbolTheme;
49
- }
50
- export declare class Markdown implements Component {
51
- #private;
52
- setIgnoreTight(ignore: boolean): this;
53
- constructor(text: string, paddingX: number, paddingY: number, theme: MarkdownTheme, defaultTextStyle?: DefaultTextStyle, codeBlockIndent?: number);
54
- setText(text: string): void;
55
- invalidate(): void;
56
- get transientRenderCache(): boolean;
57
- set transientRenderCache(value: boolean);
58
- render(width: number): readonly string[];
59
- }
60
- /**
61
- * Render inline markdown (bold, italic, code, links, strikethrough) to a styled string.
62
- * Unlike the full Markdown component, this produces a single line with no block-level elements.
63
- */
64
- export declare function renderInlineMarkdown(text: string, mdTheme: MarkdownTheme, baseColor?: (t: string) => string): string;