@opentui/core 0.2.15 → 0.3.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/index.js CHANGED
@@ -26,7 +26,6 @@ import {
26
26
  InputRenderableEvents,
27
27
  LineNumberRenderable,
28
28
  MarkdownRenderable,
29
- NativeSpanFeed,
30
29
  PROTANOPIA_COMP_MATRIX,
31
30
  PROTANOPIA_SIM_MATRIX,
32
31
  RainbowTextEffect,
@@ -72,7 +71,7 @@ import {
72
71
  resolveCoreSlot,
73
72
  setupAudio,
74
73
  vstyles
75
- } from "./index-yyyfmp8n.js";
74
+ } from "./index-sq86yyfz.js";
76
75
  import {
77
76
  ASCIIFontSelectionHelper,
78
77
  ATTRIBUTE_BASE_BITS,
@@ -104,6 +103,7 @@ import {
104
103
  MouseButton,
105
104
  MouseEvent,
106
105
  MouseParser,
106
+ NativeSpanFeed,
107
107
  OptimizedBuffer,
108
108
  PasteEvent,
109
109
  RGBA,
@@ -246,7 +246,7 @@ import {
246
246
  white,
247
247
  wrapWithDelegates,
248
248
  yellow
249
- } from "./index-3fq5hq97.js";
249
+ } from "./index-081xws23.js";
250
250
  export {
251
251
  yellow,
252
252
  wrapWithDelegates,
@@ -494,5 +494,5 @@ export {
494
494
  ACHROMATOPSIA_MATRIX
495
495
  };
496
496
 
497
- //# debugId=3B163E1BF0509BD764756E2164756E21
497
+ //# debugId=893EFD9F8A7D3C4264756E2164756E21
498
498
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -4,6 +4,6 @@
4
4
  "sourcesContent": [
5
5
  ],
6
6
  "mappings": "",
7
- "debugId": "3B163E1BF0509BD764756E2164756E21",
7
+ "debugId": "893EFD9F8A7D3C4264756E2164756E21",
8
8
  "names": []
9
9
  }
package/lib/extmarks.d.ts CHANGED
@@ -67,6 +67,7 @@ export declare class ExtmarksController {
67
67
  adjustExtmarksAfterDeletion(deleteOffset: number, length: number): void;
68
68
  private offsetToPosition;
69
69
  private positionToOffset;
70
+ private getNextCursorOffset;
70
71
  private updateHighlights;
71
72
  private offsetExcludingNewlines;
72
73
  create(options: ExtmarkOptions): number;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "index.js",
5
5
  "types": "index.d.ts",
6
6
  "type": "module",
7
- "version": "0.2.15",
7
+ "version": "0.3.0",
8
8
  "description": "OpenTUI is a TypeScript library on a native Zig core for building terminal user interfaces (TUIs)",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -69,11 +69,11 @@
69
69
  "web-tree-sitter": "0.25.10"
70
70
  },
71
71
  "optionalDependencies": {
72
- "@opentui/core-darwin-x64": "0.2.15",
73
- "@opentui/core-darwin-arm64": "0.2.15",
74
- "@opentui/core-linux-x64": "0.2.15",
75
- "@opentui/core-linux-arm64": "0.2.15",
76
- "@opentui/core-win32-x64": "0.2.15",
77
- "@opentui/core-win32-arm64": "0.2.15"
72
+ "@opentui/core-darwin-x64": "0.3.0",
73
+ "@opentui/core-darwin-arm64": "0.3.0",
74
+ "@opentui/core-linux-x64": "0.3.0",
75
+ "@opentui/core-linux-arm64": "0.3.0",
76
+ "@opentui/core-win32-x64": "0.3.0",
77
+ "@opentui/core-win32-arm64": "0.3.0"
78
78
  }
79
79
  }
@@ -6,6 +6,8 @@ export type InputKeyBinding = TextareaKeyBinding;
6
6
  export interface InputRenderableOptions extends Omit<TextareaOptions, "height" | "minHeight" | "maxHeight" | "initialValue"> {
7
7
  /** Initial text value (newlines are stripped) */
8
8
  value?: string;
9
+ /** Minimum number of characters allowed */
10
+ minLength?: number;
9
11
  /** Maximum number of characters allowed */
10
12
  maxLength?: number;
11
13
  /** Placeholder text (Input only supports string, not StyledText) */
@@ -29,6 +31,7 @@ export declare enum InputRenderableEvents {
29
31
  */
30
32
  export declare class InputRenderable extends TextareaRenderable {
31
33
  private _maxLength;
34
+ private _minLength;
32
35
  private _lastCommittedValue;
33
36
  private static readonly defaultOptions;
34
37
  constructor(ctx: RenderContext, options: InputRenderableOptions);
@@ -61,6 +64,8 @@ export declare class InputRenderable extends TextareaRenderable {
61
64
  deleteCharacter(direction: "backward" | "forward"): void;
62
65
  set maxLength(maxLength: number);
63
66
  get maxLength(): number;
67
+ set minLength(minLength: number);
68
+ get minLength(): number;
64
69
  set placeholder(placeholder: string);
65
70
  get placeholder(): string;
66
71
  set initialValue(value: string);
@@ -123,6 +123,7 @@ export interface BlockState {
123
123
  marginTop?: number;
124
124
  renderable: Renderable;
125
125
  tableContentCache?: TableContentCache;
126
+ tracksInterBlockMargin?: boolean;
126
127
  }
127
128
  export type { ParseState };
128
129
  export declare class MarkdownRenderable extends Renderable {
@@ -190,7 +191,6 @@ export declare class MarkdownRenderable extends Renderable {
190
191
  private getRenderableListItemTokens;
191
192
  private applyListChildRenderable;
192
193
  private destroyListItemChildrenAfter;
193
- private getListChildMarkdownRaw;
194
194
  private applyListItemMarker;
195
195
  private createListChildRenderable;
196
196
  private createHorizontalRuleRenderable;
@@ -200,6 +200,7 @@ export declare class MarkdownRenderable extends Renderable {
200
200
  private applyCodeBlockRenderable;
201
201
  private shouldRenderSeparately;
202
202
  private getInterBlockMargin;
203
+ private applyInterBlockMargin;
203
204
  private createMarkdownBlockToken;
204
205
  private normalizeMarkdownBlockRaw;
205
206
  private normalizeScrollbackMarkdownBlockRaw;
@@ -86,6 +86,7 @@ export declare class ScrollBoxRenderable extends BoxRenderable {
86
86
  y: number;
87
87
  }): void;
88
88
  private isAtStickyPosition;
89
+ private isAtStickyReengagePoint;
89
90
  add(obj: Renderable | VNode<any, any[]>, index?: number): number;
90
91
  insertBefore(obj: Renderable | VNode<any, any[]> | unknown, anchor?: Renderable | unknown): number;
91
92
  remove(id: string): void;
package/renderer.d.ts CHANGED
@@ -3,7 +3,7 @@ import { DebugOverlayCorner, type CursorStyleOptions, type MousePointerStyle, ty
3
3
  import { RGBA, type ColorInput } from "./lib/RGBA.js";
4
4
  import type { Pointer } from "./platform/ffi.js";
5
5
  import { OptimizedBuffer } from "./buffer.js";
6
- import { type RenderLib } from "./zig.js";
6
+ import { type NativeBufferedOutput, type NativeRenderStats } from "./zig.js";
7
7
  import { TerminalConsole, type ConsoleOptions } from "./console.js";
8
8
  import { type MouseEventType, type RawMouseEvent, type ScrollInfo } from "./lib/parse.mouse.js";
9
9
  import { Selection } from "./lib/selection.js";
@@ -16,8 +16,10 @@ import { type Clock } from "./lib/clock.js";
16
16
  export interface CliRendererConfig {
17
17
  stdin?: NodeJS.ReadStream;
18
18
  stdout?: NodeJS.WriteStream;
19
+ width?: number;
20
+ height?: number;
19
21
  remote?: boolean;
20
- testing?: boolean;
22
+ bufferedOutput?: NativeBufferedOutput;
21
23
  exitOnCtrlC?: boolean;
22
24
  exitSignals?: NodeJS.Signals[];
23
25
  clearOnShutdown?: boolean;
@@ -48,11 +50,34 @@ export interface CliRendererConfig {
48
50
  }
49
51
  export type ScreenMode = "alternate-screen" | "main-screen" | "split-footer";
50
52
  export type ExternalOutputMode = "capture-stdout" | "passthrough";
53
+ export interface CliRendererExternalOutputEvent {
54
+ snapshot: OptimizedBuffer;
55
+ rowColumns: number;
56
+ startOnNewLine: boolean;
57
+ trailingNewline: boolean;
58
+ }
51
59
  export type ConsoleMode = "console-overlay" | "disabled";
52
60
  export type PixelResolution = {
53
61
  width: number;
54
62
  height: number;
55
63
  };
64
+ export interface CliRendererStats extends NativeRenderStats {
65
+ fps: number;
66
+ frameCount: number;
67
+ frameTimes: number[];
68
+ averageFrameTime: number;
69
+ minFrameTime: number;
70
+ maxFrameTime: number;
71
+ frameCallbackTime: number;
72
+ }
73
+ export interface CliRendererFrameEvent {
74
+ frameId: number;
75
+ }
76
+ export interface RendererSchedulerState {
77
+ isRunning: boolean;
78
+ isRendering: boolean;
79
+ hasScheduledRender: boolean;
80
+ }
56
81
  export interface ScrollbackRenderContext {
57
82
  width: number;
58
83
  widthMethod: WidthMethod;
@@ -142,9 +167,16 @@ export declare enum MouseButton {
142
167
  WHEEL_UP = 4,
143
168
  WHEEL_DOWN = 5
144
169
  }
170
+ /**
171
+ * Create a CLI renderer and run its async terminal setup. The constructor
172
+ * owns all stream and backend decisions; this factory only layers on the
173
+ * `--delay-start` flag and the `await setupTerminal()` convenience.
174
+ */
145
175
  export declare function createCliRenderer(config?: CliRendererConfig): Promise<CliRenderer>;
146
176
  export declare enum CliRenderEvents {
147
177
  RESIZE = "resize",
178
+ FRAME = "frame",
179
+ EXTERNAL_OUTPUT = "external_output",
148
180
  FOCUS = "focus",
149
181
  BLUR = "blur",
150
182
  FOCUSED_RENDERABLE = "focused_renderable",
@@ -178,6 +210,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
178
210
  private _destroyPending;
179
211
  private _destroyFinalized;
180
212
  private _destroyCleanupPrepared;
213
+ private _streamLeaseAcquired;
181
214
  nextRenderBuffer: OptimizedBuffer;
182
215
  currentRenderBuffer: OptimizedBuffer;
183
216
  private _isRunning;
@@ -292,8 +325,37 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
292
325
  private dumpOutputCache;
293
326
  private exitHandler;
294
327
  private warningHandler;
328
+ private readonly _usesProcessStdout;
329
+ private _feed;
330
+ private _detachFeed;
331
+ private _detachFeedError;
332
+ private feedIdleRenderScheduled;
295
333
  get controlState(): RendererControlState;
296
- constructor(lib: RenderLib, rendererPtr: Pointer, stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream, width: number, height: number, config?: CliRendererConfig);
334
+ /**
335
+ * Construct a renderer over the given streams.
336
+ *
337
+ * If `stdout` is not `process.stdout`, a `NativeSpanFeed` is allocated
338
+ * internally and rendered bytes are piped through it to `stdout` unless
339
+ * `bufferedOutput: "memory"` is set. Prefer `createCliRenderer` for the async
340
+ * `setupTerminal` convenience.
341
+ *
342
+ * Construction side effects (observable before the constructor returns):
343
+ * - Acquires exclusive ownership of the given stdin/stdout streams
344
+ * - Allocates a `NativeSpanFeed` (for non-process stdout unless bufferedOutput is "memory")
345
+ * - Calls `lib.createRenderer` → native Zig allocation
346
+ * - Registers in the process-wide `rendererTracker`
347
+ * - Adds `process.on(...)` listeners for SIGWINCH (process.stdout only),
348
+ * "warning", "uncaughtException", "unhandledRejection", "beforeExit",
349
+ * plus the configured `exitSignals`
350
+ * - Replaces `global.requestAnimationFrame` with the renderer's impl
351
+ * - When `setupTerminal()` is called, it will put `stdin` in raw mode and
352
+ * call `stdin.resume()`
353
+ *
354
+ * Some late constructor side effects are not rolled back if construction
355
+ * throws partway; production callers should use `createCliRenderer`, which
356
+ * wraps `setupTerminal()` in a try/catch that calls `destroy()` on failure.
357
+ */
358
+ constructor(stdin: NodeJS.ReadStream, stdout: NodeJS.WriteStream, width: number, height: number, config?: CliRendererConfig);
297
359
  private addExitListeners;
298
360
  private removeExitListeners;
299
361
  get isDestroyed(): boolean;
@@ -314,6 +376,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
314
376
  get widthMethod(): WidthMethod;
315
377
  get frameId(): number;
316
378
  private writeOut;
379
+ private scheduleRenderAfterFeedIdle;
317
380
  requestRender(): void;
318
381
  private activateFrame;
319
382
  get consoleMode(): ConsoleMode;
@@ -322,6 +385,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
322
385
  private isIdleNow;
323
386
  private resolveIdleIfNeeded;
324
387
  idle(): Promise<void>;
388
+ getSchedulerState(): RendererSchedulerState;
325
389
  get resolution(): PixelResolution | null;
326
390
  get console(): TerminalConsole;
327
391
  get keyInput(): KeyHandler;
@@ -426,6 +490,15 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
426
490
  private handleResize;
427
491
  private queryPixelResolution;
428
492
  private processResize;
493
+ /**
494
+ * Programmatically resize the renderer to new dimensions.
495
+ *
496
+ * Use this for externally-driven resize events — for example, an SSH
497
+ * `window-change` signal or a test harness simulating a terminal resize.
498
+ * When the renderer is attached to `process.stdout`, `SIGWINCH` is handled
499
+ * automatically and callers do not need this method.
500
+ */
501
+ resize(width: number, height: number): void;
429
502
  setBackgroundColor(color: ColorInput): void;
430
503
  toggleDebugOverlay(): void;
431
504
  configureDebugOverlay(options: {
@@ -444,7 +517,7 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
444
517
  isOsc52Supported(): boolean;
445
518
  dumpHitGrid(): void;
446
519
  dumpBuffers(timestamp?: number): void;
447
- dumpStdoutBuffer(timestamp?: number): void;
520
+ dumpOutputBuffer(timestamp?: number): void;
448
521
  static setCursorPosition(renderer: CliRenderer, x: number, y: number, visible?: boolean): void;
449
522
  static setCursorStyle(renderer: CliRenderer, options: CursorStyleOptions): void;
450
523
  static setCursorColor(renderer: CliRenderer, color: RGBA): void;
@@ -478,14 +551,8 @@ export declare class CliRenderer extends EventEmitter implements RenderContext {
478
551
  intermediateRender(): void;
479
552
  private renderNative;
480
553
  private collectStatSample;
481
- getStats(): {
482
- fps: number;
483
- frameCount: number;
484
- frameTimes: number[];
485
- averageFrameTime: number;
486
- minFrameTime: number;
487
- maxFrameTime: number;
488
- };
554
+ getNativeStats(): NativeRenderStats;
555
+ getStats(): CliRendererStats;
489
556
  resetStats(): void;
490
557
  setGatherStats(enabled: boolean): void;
491
558
  getSelection(): Selection | null;
@@ -1,13 +1,13 @@
1
1
  // @bun
2
2
  import {
3
3
  ensureRuntimePluginSupport
4
- } from "./index-bdfngvbe.js";
4
+ } from "./index-dhbwkghw.js";
5
5
  import {
6
6
  createRuntimePlugin,
7
7
  runtimeModuleIdForSpecifier
8
- } from "./index-pzzbb0f6.js";
9
- import"./index-yyyfmp8n.js";
10
- import"./index-3fq5hq97.js";
8
+ } from "./index-qwem5zxy.js";
9
+ import"./index-sq86yyfz.js";
10
+ import"./index-081xws23.js";
11
11
  export {
12
12
  runtimeModuleIdForSpecifier,
13
13
  ensureRuntimePluginSupport,
@@ -1,13 +1,13 @@
1
1
  // @bun
2
2
  import {
3
3
  ensureRuntimePluginSupport
4
- } from "./index-bdfngvbe.js";
4
+ } from "./index-dhbwkghw.js";
5
5
  import {
6
6
  createRuntimePlugin,
7
7
  runtimeModuleIdForSpecifier
8
- } from "./index-pzzbb0f6.js";
9
- import"./index-yyyfmp8n.js";
10
- import"./index-3fq5hq97.js";
8
+ } from "./index-qwem5zxy.js";
9
+ import"./index-sq86yyfz.js";
10
+ import"./index-081xws23.js";
11
11
  // src/runtime-plugin-support.ts
12
12
  ensureRuntimePluginSupport();
13
13
  export {
package/runtime-plugin.js CHANGED
@@ -3,9 +3,9 @@ import {
3
3
  createRuntimePlugin,
4
4
  isCoreRuntimeModuleSpecifier,
5
5
  runtimeModuleIdForSpecifier
6
- } from "./index-pzzbb0f6.js";
7
- import"./index-yyyfmp8n.js";
8
- import"./index-3fq5hq97.js";
6
+ } from "./index-qwem5zxy.js";
7
+ import"./index-sq86yyfz.js";
8
+ import"./index-081xws23.js";
9
9
  export {
10
10
  runtimeModuleIdForSpecifier,
11
11
  isCoreRuntimeModuleSpecifier,
@@ -20,7 +20,7 @@ export interface TestRecorderOptions {
20
20
  now?: () => number;
21
21
  }
22
22
  /**
23
- * TestRecorder records frames from a TestRenderer by hooking into the render pipeline.
23
+ * TestRecorder records frames from a TestRenderer by listening to rendered frame events.
24
24
  * It captures the character frame after each native render pass.
25
25
  */
26
26
  export declare class TestRecorder {
@@ -29,17 +29,17 @@ export declare class TestRecorder {
29
29
  private recording;
30
30
  private frameNumber;
31
31
  private startTime;
32
- private originalRenderNative?;
33
32
  private decoder;
34
33
  private recordBuffers;
35
34
  private now;
35
+ private readonly onFrame;
36
36
  constructor(renderer: TestRenderer, options?: TestRecorderOptions);
37
37
  /**
38
- * Start recording frames. This hooks into the renderer's renderNative method.
38
+ * Start recording frames.
39
39
  */
40
40
  rec(): void;
41
41
  /**
42
- * Stop recording frames and restore the original renderNative method.
42
+ * Stop recording frames.
43
43
  */
44
44
  stop(): void;
45
45
  /**
@@ -1,4 +1,5 @@
1
1
  import { CliRenderer, type CliRendererConfig } from "../renderer.js";
2
+ import type { NativeRenderStats } from "../zig.js";
2
3
  import { createMockKeys } from "./mock-keys.js";
3
4
  import { createMockMouse } from "./mock-mouse.js";
4
5
  import type { CapturedFrame } from "../types.js";
@@ -8,16 +9,46 @@ export interface TestRendererOptions extends CliRendererConfig {
8
9
  kittyKeyboard?: boolean;
9
10
  otherModifiersMode?: boolean;
10
11
  }
11
- export interface TestRenderer extends CliRenderer {
12
- }
12
+ export type TestRenderer = CliRenderer;
13
13
  export type MockInput = ReturnType<typeof createMockKeys>;
14
14
  export type MockMouse = ReturnType<typeof createMockMouse>;
15
- export declare function createTestRenderer(options: TestRendererOptions): Promise<{
15
+ export interface TestFlushOptions {
16
+ maxPasses?: number;
17
+ }
18
+ export interface TestVisualIdleOptions {
19
+ quietFrames?: number;
20
+ maxFrames?: number;
21
+ }
22
+ export interface TestWaitForOptions {
23
+ maxPasses?: number;
24
+ }
25
+ export interface TestExternalOutputCommit {
26
+ text: string;
27
+ rows: string[];
28
+ width: number;
29
+ height: number;
30
+ rowColumns: number;
31
+ startOnNewLine: boolean;
32
+ trailingNewline: boolean;
33
+ }
34
+ export interface TestExternalOutput {
35
+ take(): TestExternalOutputCommit[];
36
+ takeText(): string;
37
+ clear(): void;
38
+ }
39
+ export interface TestRendererSetup {
16
40
  renderer: TestRenderer;
17
41
  mockInput: MockInput;
18
42
  mockMouse: MockMouse;
19
43
  renderOnce: () => Promise<void>;
44
+ flush: (options?: TestFlushOptions) => Promise<void>;
45
+ waitFor: (predicate: () => boolean | Promise<boolean>, options?: TestWaitForOptions) => Promise<void>;
46
+ waitForFrame: (predicate: (frame: string) => boolean | Promise<boolean>, options?: TestWaitForOptions) => Promise<string>;
47
+ waitForVisualIdle: (options?: TestVisualIdleOptions) => Promise<void>;
48
+ externalOutput: TestExternalOutput;
49
+ getNativeStats: () => NativeRenderStats;
20
50
  captureCharFrame: () => string;
21
51
  captureSpans: () => CapturedFrame;
22
52
  resize: (width: number, height: number) => void;
23
- }>;
53
+ }
54
+ export declare function createTestRenderer(options: TestRendererOptions): Promise<TestRendererSetup>;
@@ -0,0 +1,12 @@
1
+ import { Writable } from "stream";
2
+ export declare class TestWriteStream extends Writable {
3
+ readonly isTTY = true;
4
+ readonly columns: number;
5
+ readonly rows: number;
6
+ constructor(columns?: number, rows?: number);
7
+ _write(_chunk: any, _encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
8
+ getColorDepth(): number;
9
+ }
10
+ export type TestStdout = TestWriteStream & NodeJS.WriteStream;
11
+ export declare function createTestStdin(): NodeJS.ReadStream;
12
+ export declare function createTestStdout(columns?: number, rows?: number): NodeJS.WriteStream;
package/testing.d.ts CHANGED
@@ -4,4 +4,5 @@ export * from "./testing/mock-mouse.js";
4
4
  export * from "./testing/mock-tree-sitter-client.js";
5
5
  export * from "./testing/terminal-capabilities.js";
6
6
  export * from "./testing/spy.js";
7
+ export { ManualClock } from "./testing/manual-clock.js";
7
8
  export { TestRecorder, type RecordedFrame } from "./testing/test-recorder.js";