@opentui/core 0.1.24 → 0.1.25

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.
@@ -2175,30 +2175,46 @@ var parseKeypress = (s = "", options = {}) => {
2175
2175
  // src/lib/KeyHandler.ts
2176
2176
  import { EventEmitter } from "events";
2177
2177
 
2178
- // src/singleton.ts
2179
- var singletonCacheSymbol = Symbol.for("@opentui/core/singleton");
2180
- function singleton(key, factory) {
2181
- const bag = globalThis[singletonCacheSymbol] ??= {};
2182
- if (!(key in bag)) {
2183
- bag[key] = factory();
2184
- }
2185
- return bag[key];
2186
- }
2178
+ // src/ansi.ts
2179
+ var ANSI = {
2180
+ switchToAlternateScreen: "\x1B[?1049h",
2181
+ switchToMainScreen: "\x1B[?1049l",
2182
+ reset: "\x1B[0m",
2183
+ scrollDown: (lines) => `\x1B[${lines}T`,
2184
+ scrollUp: (lines) => `\x1B[${lines}S`,
2185
+ moveCursor: (row, col) => `\x1B[${row};${col}H`,
2186
+ moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
2187
+ setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
2188
+ resetBackground: "\x1B[49m",
2189
+ bracketedPasteStart: "\x1B[200~",
2190
+ bracketedPasteEnd: "\x1B[201~"
2191
+ };
2187
2192
 
2188
2193
  // src/lib/KeyHandler.ts
2189
2194
  class KeyHandler extends EventEmitter {
2190
2195
  stdin;
2191
2196
  useKittyKeyboard;
2197
+ listener;
2198
+ pasteMode = false;
2199
+ pasteBuffer = [];
2192
2200
  constructor(stdin, useKittyKeyboard = false) {
2193
2201
  super();
2194
2202
  this.stdin = stdin || process.stdin;
2195
2203
  this.useKittyKeyboard = useKittyKeyboard;
2196
- if (this.stdin.setRawMode) {
2197
- this.stdin.setRawMode(true);
2198
- }
2199
- this.stdin.resume();
2200
- this.stdin.setEncoding("utf8");
2201
- this.stdin.on("data", (key) => {
2204
+ this.listener = (key) => {
2205
+ let data = key.toString();
2206
+ if (data.startsWith(ANSI.bracketedPasteStart)) {
2207
+ this.pasteMode = true;
2208
+ }
2209
+ if (this.pasteMode) {
2210
+ this.pasteBuffer.push(Bun.stripANSI(data));
2211
+ if (data.endsWith(ANSI.bracketedPasteEnd)) {
2212
+ this.pasteMode = false;
2213
+ this.emit("paste", this.pasteBuffer.join(""));
2214
+ this.pasteBuffer = [];
2215
+ }
2216
+ return;
2217
+ }
2202
2218
  const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2203
2219
  switch (parsedKey.eventType) {
2204
2220
  case "press":
@@ -2214,18 +2230,12 @@ class KeyHandler extends EventEmitter {
2214
2230
  this.emit("keypress", parsedKey);
2215
2231
  break;
2216
2232
  }
2217
- });
2233
+ };
2234
+ this.stdin.on("data", this.listener);
2218
2235
  }
2219
2236
  destroy() {
2220
- this.stdin.removeAllListeners("data");
2221
- }
2222
- }
2223
- var keyHandler = null;
2224
- function getKeyHandler(useKittyKeyboard = false) {
2225
- if (!keyHandler) {
2226
- keyHandler = singleton("KeyHandler", () => new KeyHandler(process.stdin, useKittyKeyboard));
2237
+ this.stdin.removeListener("data", this.listener);
2227
2238
  }
2228
- return keyHandler;
2229
2239
  }
2230
2240
 
2231
2241
  // src/lib/RGBA.ts
@@ -4804,6 +4814,166 @@ class ASCIIFontSelectionHelper {
4804
4814
  return previousSelection?.start !== this.localSelection?.start || previousSelection?.end !== this.localSelection?.end;
4805
4815
  }
4806
4816
  }
4817
+
4818
+ // src/lib/singleton.ts
4819
+ var singletonCacheSymbol = Symbol.for("@opentui/core/singleton");
4820
+ function singleton(key, factory) {
4821
+ const bag = globalThis[singletonCacheSymbol] ??= {};
4822
+ if (!(key in bag)) {
4823
+ bag[key] = factory();
4824
+ }
4825
+ return bag[key];
4826
+ }
4827
+
4828
+ // src/lib/env.ts
4829
+ var envRegistry = {};
4830
+ function registerEnvVar(config) {
4831
+ const existing = envRegistry[config.name];
4832
+ if (existing) {
4833
+ if (existing.description !== config.description || existing.type !== config.type || existing.default !== config.default) {
4834
+ throw new Error(`Environment variable "${config.name}" is already registered with different configuration. ` + `Existing: ${JSON.stringify(existing)}, New: ${JSON.stringify(config)}`);
4835
+ }
4836
+ return;
4837
+ }
4838
+ envRegistry[config.name] = config;
4839
+ }
4840
+ function normalizeBoolean(value) {
4841
+ const lowerValue = value.toLowerCase();
4842
+ return ["true", "1", "on", "yes"].includes(lowerValue);
4843
+ }
4844
+ function parseEnvValue(config) {
4845
+ const envValue = process.env[config.name];
4846
+ if (envValue === undefined && config.default !== undefined) {
4847
+ return config.default;
4848
+ }
4849
+ if (envValue === undefined) {
4850
+ throw new Error(`Required environment variable ${config.name} is not set. ${config.description}`);
4851
+ }
4852
+ switch (config.type) {
4853
+ case "boolean":
4854
+ return typeof envValue === "boolean" ? envValue : normalizeBoolean(envValue);
4855
+ case "number":
4856
+ const numValue = Number(envValue);
4857
+ if (isNaN(numValue)) {
4858
+ throw new Error(`Environment variable ${config.name} must be a valid number, got: ${envValue}`);
4859
+ }
4860
+ return numValue;
4861
+ case "string":
4862
+ default:
4863
+ return envValue;
4864
+ }
4865
+ }
4866
+
4867
+ class EnvStore {
4868
+ parsedValues = new Map;
4869
+ get(key) {
4870
+ if (this.parsedValues.has(key)) {
4871
+ return this.parsedValues.get(key);
4872
+ }
4873
+ if (!(key in envRegistry)) {
4874
+ throw new Error(`Environment variable ${key} is not registered.`);
4875
+ }
4876
+ try {
4877
+ const value = parseEnvValue(envRegistry[key]);
4878
+ this.parsedValues.set(key, value);
4879
+ return value;
4880
+ } catch (error) {
4881
+ throw new Error(`Failed to parse env var ${key}: ${error instanceof Error ? error.message : String(error)}`);
4882
+ }
4883
+ }
4884
+ has(key) {
4885
+ return key in envRegistry;
4886
+ }
4887
+ }
4888
+ var envStore = singleton("env-store", () => new EnvStore);
4889
+ function generateEnvMarkdown() {
4890
+ const configs = Object.values(envRegistry);
4891
+ if (configs.length === 0) {
4892
+ return `# Environment Variables
4893
+
4894
+ No environment variables registered.
4895
+ `;
4896
+ }
4897
+ let markdown = `# Environment Variables
4898
+
4899
+ `;
4900
+ for (const config of configs) {
4901
+ markdown += `## ${config.name}
4902
+
4903
+ `;
4904
+ markdown += `${config.description}
4905
+
4906
+ `;
4907
+ markdown += `**Type:** \`${config.type || "string"}\`
4908
+ `;
4909
+ if (config.default !== undefined) {
4910
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
4911
+ markdown += `**Default:** \`${defaultValue}\`
4912
+ `;
4913
+ } else {
4914
+ markdown += `**Default:** *Required*
4915
+ `;
4916
+ }
4917
+ markdown += `
4918
+ `;
4919
+ }
4920
+ return markdown;
4921
+ }
4922
+ function generateEnvColored() {
4923
+ const configs = Object.values(envRegistry);
4924
+ if (configs.length === 0) {
4925
+ return `\x1B[1;36mEnvironment Variables\x1B[0m
4926
+
4927
+ No environment variables registered.
4928
+ `;
4929
+ }
4930
+ let output = `\x1B[1;36mEnvironment Variables\x1B[0m
4931
+
4932
+ `;
4933
+ for (const config of configs) {
4934
+ output += `\x1B[1;33m${config.name}\x1B[0m
4935
+ `;
4936
+ output += `${config.description}
4937
+ `;
4938
+ output += `\x1B[32mType:\x1B[0m \x1B[36m${config.type || "string"}\x1B[0m
4939
+ `;
4940
+ if (config.default !== undefined) {
4941
+ const defaultValue = typeof config.default === "string" ? `"${config.default}"` : String(config.default);
4942
+ output += `\x1B[32mDefault:\x1B[0m \x1B[35m${defaultValue}\x1B[0m
4943
+ `;
4944
+ } else {
4945
+ output += `\x1B[32mDefault:\x1B[0m \x1B[31mRequired\x1B[0m
4946
+ `;
4947
+ }
4948
+ output += `
4949
+ `;
4950
+ }
4951
+ return output;
4952
+ }
4953
+ var env = new Proxy({}, {
4954
+ get(target, prop) {
4955
+ if (typeof prop !== "string") {
4956
+ return;
4957
+ }
4958
+ return envStore.get(prop);
4959
+ },
4960
+ has(target, prop) {
4961
+ return envStore.has(prop);
4962
+ },
4963
+ ownKeys() {
4964
+ return Object.keys(envRegistry);
4965
+ },
4966
+ getOwnPropertyDescriptor(target, prop) {
4967
+ if (envStore.has(prop)) {
4968
+ return {
4969
+ enumerable: true,
4970
+ configurable: true,
4971
+ get: () => envStore.get(prop)
4972
+ };
4973
+ }
4974
+ return;
4975
+ }
4976
+ });
4807
4977
  // src/zig.ts
4808
4978
  import { dlopen, toArrayBuffer as toArrayBuffer2, JSCallback, ptr } from "bun:ffi";
4809
4979
  import { existsSync } from "fs";
@@ -5010,6 +5180,18 @@ var targetLibPath = module.default;
5010
5180
  if (!existsSync(targetLibPath)) {
5011
5181
  throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
5012
5182
  }
5183
+ registerEnvVar({
5184
+ name: "OTUI_DEBUG_FFI",
5185
+ description: "Enable debug logging for the FFI bindings.",
5186
+ type: "boolean",
5187
+ default: false
5188
+ });
5189
+ registerEnvVar({
5190
+ name: "OTUI_TRACE_FFI",
5191
+ description: "Enable tracing for the FFI bindings.",
5192
+ type: "boolean",
5193
+ default: false
5194
+ });
5013
5195
  function getOpenTUILib(libPath) {
5014
5196
  const resolvedLibPath = libPath || targetLibPath;
5015
5197
  const rawSymbols = dlopen(resolvedLibPath, {
@@ -5057,6 +5239,10 @@ function getOpenTUILib(libPath) {
5057
5239
  args: ["ptr"],
5058
5240
  returns: "ptr"
5059
5241
  },
5242
+ queryPixelResolution: {
5243
+ args: ["ptr"],
5244
+ returns: "void"
5245
+ },
5060
5246
  createOptimizedBuffer: {
5061
5247
  args: ["u32", "u32", "bool", "u8", "ptr", "usize"],
5062
5248
  returns: "ptr"
@@ -5346,7 +5532,7 @@ function getOpenTUILib(libPath) {
5346
5532
  returns: "void"
5347
5533
  }
5348
5534
  });
5349
- if (process.env.DEBUG_FFI === "true" || process.env.TRACE_FFI === "true") {
5535
+ if (env.OTUI_DEBUG_FFI || env.OTUI_TRACE_FFI) {
5350
5536
  return {
5351
5537
  symbols: convertToDebugSymbols(rawSymbols.symbols)
5352
5538
  };
@@ -5360,7 +5546,7 @@ function convertToDebugSymbols(symbols) {
5360
5546
  Object.entries(symbols).forEach(([key, value]) => {
5361
5547
  debugSymbols[key] = value;
5362
5548
  });
5363
- if (process.env.DEBUG_FFI === "true") {
5549
+ if (env.OTUI_DEBUG_FFI) {
5364
5550
  Object.entries(symbols).forEach(([key, value]) => {
5365
5551
  if (typeof value === "function") {
5366
5552
  debugSymbols[key] = (...args) => {
@@ -5372,7 +5558,7 @@ function convertToDebugSymbols(symbols) {
5372
5558
  }
5373
5559
  });
5374
5560
  }
5375
- if (process.env.TRACE_FFI === "true") {
5561
+ if (env.OTUI_TRACE_FFI) {
5376
5562
  hasTracing = true;
5377
5563
  Object.entries(symbols).forEach(([key, value]) => {
5378
5564
  if (typeof value === "function") {
@@ -5734,6 +5920,9 @@ class FFIRenderLib {
5734
5920
  setupTerminal(renderer, useAlternateScreen) {
5735
5921
  this.opentui.symbols.setupTerminal(renderer, useAlternateScreen);
5736
5922
  }
5923
+ queryPixelResolution(renderer) {
5924
+ this.opentui.symbols.queryPixelResolution(renderer);
5925
+ }
5737
5926
  createTextBuffer(widthMethod) {
5738
5927
  const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1;
5739
5928
  const bufferPtr = this.opentui.symbols.createTextBuffer(widthMethodCode);
@@ -6222,6 +6411,9 @@ class BaseRenderable extends EventEmitter2 {
6222
6411
  this._visible = value;
6223
6412
  }
6224
6413
  }
6414
+ var yogaConfig = src_default.Config.create();
6415
+ yogaConfig.setUseWebDefaults(false);
6416
+ yogaConfig.setPointScaleFactor(1);
6225
6417
 
6226
6418
  class Renderable extends BaseRenderable {
6227
6419
  static renderablesByNumber = new Map;
@@ -6242,11 +6434,13 @@ class Renderable extends BaseRenderable {
6242
6434
  _focusable = false;
6243
6435
  _focused = false;
6244
6436
  keypressHandler = null;
6437
+ pasteHandler = null;
6245
6438
  _live = false;
6246
6439
  _liveCount = 0;
6247
6440
  _sizeChangeListener = undefined;
6248
6441
  _mouseListener = null;
6249
6442
  _mouseListeners = {};
6443
+ _pasteListener = undefined;
6250
6444
  _keyListeners = {};
6251
6445
  yogaNode;
6252
6446
  _positionType = "relative";
@@ -6283,7 +6477,7 @@ class Renderable extends BaseRenderable {
6283
6477
  this.buffered = options.buffered ?? false;
6284
6478
  this._live = options.live ?? false;
6285
6479
  this._liveCount = this._live && this._visible ? 1 : 0;
6286
- this.yogaNode = src_default.Node.create();
6480
+ this.yogaNode = src_default.Node.create(yogaConfig);
6287
6481
  this.yogaNode.setDisplay(this._visible ? Display.Flex : Display.None);
6288
6482
  this.setupYogaProperties(options);
6289
6483
  this.applyEventOptions(options);
@@ -6356,7 +6550,14 @@ class Renderable extends BaseRenderable {
6356
6550
  this.handleKeyPress(key);
6357
6551
  }
6358
6552
  };
6553
+ this.pasteHandler = (text) => {
6554
+ this._pasteListener?.call(this, text);
6555
+ if (this.handlePaste) {
6556
+ this.handlePaste(text);
6557
+ }
6558
+ };
6359
6559
  this.ctx.keyInput.on("keypress", this.keypressHandler);
6560
+ this.ctx.keyInput.on("paste", this.pasteHandler);
6360
6561
  this.emit("focused" /* FOCUSED */);
6361
6562
  }
6362
6563
  blur() {
@@ -6368,6 +6569,10 @@ class Renderable extends BaseRenderable {
6368
6569
  this.ctx.keyInput.off("keypress", this.keypressHandler);
6369
6570
  this.keypressHandler = null;
6370
6571
  }
6572
+ if (this.pasteHandler) {
6573
+ this.ctx.keyInput.off("paste", this.pasteHandler);
6574
+ this.pasteHandler = null;
6575
+ }
6371
6576
  this.emit("blurred" /* BLURRED */);
6372
6577
  }
6373
6578
  get focused() {
@@ -6396,9 +6601,11 @@ class Renderable extends BaseRenderable {
6396
6601
  for (const child of this._childrenInLayoutOrder) {
6397
6602
  if (child.id === id)
6398
6603
  return child;
6399
- const found = child.findDescendantById(id);
6400
- if (found)
6401
- return found;
6604
+ if (isRenderable(child)) {
6605
+ const found = child.findDescendantById(id);
6606
+ if (found)
6607
+ return found;
6608
+ }
6402
6609
  }
6403
6610
  return;
6404
6611
  }
@@ -6551,8 +6758,7 @@ class Renderable extends BaseRenderable {
6551
6758
  if (options.flexShrink !== undefined) {
6552
6759
  node.setFlexShrink(options.flexShrink);
6553
6760
  } else {
6554
- const shrinkValue = options.flexGrow && options.flexGrow > 0 ? 1 : 0;
6555
- node.setFlexShrink(shrinkValue);
6761
+ node.setFlexShrink(1);
6556
6762
  }
6557
6763
  if (options.flexDirection !== undefined) {
6558
6764
  node.setFlexDirection(parseFlexDirection(options.flexDirection));
@@ -7196,6 +7402,12 @@ class Renderable extends BaseRenderable {
7196
7402
  else
7197
7403
  delete this._mouseListeners["scroll"];
7198
7404
  }
7405
+ set onPaste(handler) {
7406
+ this._pasteListener = handler;
7407
+ }
7408
+ get onPaste() {
7409
+ return this._pasteListener;
7410
+ }
7199
7411
  set onKeyDown(handler) {
7200
7412
  if (handler)
7201
7413
  this._keyListeners["down"] = handler;
@@ -7222,23 +7434,20 @@ class Renderable extends BaseRenderable {
7222
7434
  this.onMouseOver = options.onMouseOver;
7223
7435
  this.onMouseOut = options.onMouseOut;
7224
7436
  this.onMouseScroll = options.onMouseScroll;
7437
+ this.onPaste = options.onPaste;
7225
7438
  this.onKeyDown = options.onKeyDown;
7226
7439
  this.onSizeChange = options.onSizeChange;
7227
7440
  }
7228
7441
  }
7229
7442
 
7230
7443
  class RootRenderable extends Renderable {
7231
- yogaConfig;
7232
7444
  renderList = [];
7233
7445
  constructor(ctx) {
7234
7446
  super(ctx, { id: "__root__", zIndex: 0, visible: true, width: ctx.width, height: ctx.height, enableLayout: true });
7235
- this.yogaConfig = src_default.Config.create();
7236
- this.yogaConfig.setUseWebDefaults(false);
7237
- this.yogaConfig.setPointScaleFactor(1);
7238
7447
  if (this.yogaNode) {
7239
7448
  this.yogaNode.free();
7240
7449
  }
7241
- this.yogaNode = src_default.Node.create(this.yogaConfig);
7450
+ this.yogaNode = src_default.Node.create(yogaConfig);
7242
7451
  this.yogaNode.setWidth(ctx.width);
7243
7452
  this.yogaNode.setHeight(ctx.height);
7244
7453
  this.yogaNode.setFlexDirection(FlexDirection.Column);
@@ -7288,11 +7497,6 @@ class RootRenderable extends Renderable {
7288
7497
  this.height = height;
7289
7498
  this.emit("resized" /* RESIZED */, { width, height });
7290
7499
  }
7291
- destroySelf() {
7292
- try {
7293
- this.yogaConfig.free();
7294
- } catch (error) {}
7295
- }
7296
7500
  }
7297
7501
 
7298
7502
  // src/renderables/composition/vnode.ts
@@ -7535,6 +7739,18 @@ function getCallerInfo() {
7535
7739
  return { functionName, fullPath, fileName, lineNumber, columnNumber };
7536
7740
  }
7537
7741
  var capture = singleton("ConsoleCapture", () => new Capture);
7742
+ registerEnvVar({
7743
+ name: "OTUI_USE_CONSOLE",
7744
+ description: "Whether to use the console. Will not capture console output if set to false.",
7745
+ type: "boolean",
7746
+ default: true
7747
+ });
7748
+ registerEnvVar({
7749
+ name: "SHOW_CONSOLE",
7750
+ description: "Show the console at startup if set to true.",
7751
+ type: "boolean",
7752
+ default: false
7753
+ });
7538
7754
 
7539
7755
  class TerminalConsoleCache extends EventEmitter4 {
7540
7756
  _cachedLogs = [];
@@ -7552,7 +7768,7 @@ class TerminalConsoleCache extends EventEmitter4 {
7552
7768
  this.overrideConsoleMethods();
7553
7769
  }
7554
7770
  setupConsoleCapture() {
7555
- if (process.env.OTUI_USE_CONSOLE === "false")
7771
+ if (!env.OTUI_USE_CONSOLE)
7556
7772
  return;
7557
7773
  const mockStdout = new CapturedWritableStream("stdout", capture);
7558
7774
  const mockStderr = new CapturedWritableStream("stderr", capture);
@@ -7717,7 +7933,7 @@ class TerminalConsole extends EventEmitter4 {
7717
7933
  terminalConsoleCache.on("entry", (logEntry) => {
7718
7934
  this._handleNewLog(logEntry);
7719
7935
  });
7720
- if (process.env.SHOW_CONSOLE === "true") {
7936
+ if (env.SHOW_CONSOLE) {
7721
7937
  this.show();
7722
7938
  }
7723
7939
  }
@@ -8116,37 +8332,6 @@ class TerminalConsole extends EventEmitter4 {
8116
8332
  }
8117
8333
  }
8118
8334
 
8119
- // src/ansi.ts
8120
- var ANSI = {
8121
- switchToAlternateScreen: "\x1B[?1049h",
8122
- switchToMainScreen: "\x1B[?1049l",
8123
- reset: "\x1B[0m",
8124
- hideCursor: "\x1B[?25l",
8125
- showCursor: "\x1B[?25h",
8126
- resetCursorColor: "\x1B]12;default\x07",
8127
- saveCursorState: "\x1B[s",
8128
- restoreCursorState: "\x1B[u",
8129
- queryPixelSize: "\x1B[14t",
8130
- scrollDown: (lines) => `\x1B[${lines}T`,
8131
- scrollUp: (lines) => `\x1B[${lines}S`,
8132
- moveCursor: (row, col) => `\x1B[${row};${col}H`,
8133
- moveCursorAndClear: (row, col) => `\x1B[${row};${col}H\x1B[J`,
8134
- clearFromCursor: "\x1B[J",
8135
- setRgbBackground: (r, g, b) => `\x1B[48;2;${r};${g};${b}m`,
8136
- resetBackground: "\x1B[49m",
8137
- enableMouseTracking: "\x1B[?1000h",
8138
- disableMouseTracking: "\x1B[?1000l",
8139
- enableButtonEventTracking: "\x1B[?1002h",
8140
- disableButtonEventTracking: "\x1B[?1002l",
8141
- enableAnyEventTracking: "\x1B[?1003h",
8142
- disableAnyEventTracking: "\x1B[?1003l",
8143
- enableSGRMouseMode: "\x1B[?1006h",
8144
- disableSGRMouseMode: "\x1B[?1006l",
8145
- makeRoomForRenderer: (height) => `
8146
- `.repeat(height) + `\x1B[${height}A`,
8147
- clearRendererSpace: (height) => `\x1B[${height}A\x1B[1G\x1B[J`
8148
- };
8149
-
8150
8335
  // src/renderer.ts
8151
8336
  import { EventEmitter as EventEmitter5 } from "events";
8152
8337
 
@@ -8226,6 +8411,19 @@ function getObjectsInViewport(viewport, objects, direction = "column", padding =
8226
8411
  }
8227
8412
 
8228
8413
  // src/renderer.ts
8414
+ registerEnvVar({
8415
+ name: "OTUI_DUMP_CAPTURES",
8416
+ description: "Dump captured output when the renderer exits.",
8417
+ type: "boolean",
8418
+ default: false
8419
+ });
8420
+ registerEnvVar({
8421
+ name: "OTUI_NO_NATIVE_RENDER",
8422
+ description: "Disable native rendering. This will not actually output ansi and is useful for debugging.",
8423
+ type: "boolean",
8424
+ default: false
8425
+ });
8426
+
8229
8427
  class MouseEvent {
8230
8428
  type;
8231
8429
  button;
@@ -8277,6 +8475,20 @@ singleton("ProcessExitSignals", () => {
8277
8475
  });
8278
8476
  });
8279
8477
  });
8478
+ var rendererTracker = singleton("RendererTracker", () => {
8479
+ const renderers = new Set;
8480
+ return {
8481
+ addRenderer: (renderer) => {
8482
+ renderers.add(renderer);
8483
+ },
8484
+ removeRenderer: (renderer) => {
8485
+ renderers.delete(renderer);
8486
+ if (renderers.size === 0) {
8487
+ process.stdin.pause();
8488
+ }
8489
+ }
8490
+ };
8491
+ });
8280
8492
  async function createCliRenderer(config = {}) {
8281
8493
  if (process.argv.includes("--delay-start")) {
8282
8494
  await new Promise((resolve) => setTimeout(resolve, 5000));
@@ -8408,17 +8620,7 @@ class CliRenderer extends EventEmitter5 {
8408
8620
  this.realStdoutWrite.call(this.stdout, `
8409
8621
  === FATAL ERROR OCCURRED ===
8410
8622
  `);
8411
- this.realStdoutWrite.call(this.stdout, `Console cache:
8412
- `);
8413
- this.realStdoutWrite.call(this.stdout, this.console.getCachedLogs());
8414
- this.realStdoutWrite.call(this.stdout, `
8415
- Captured output:
8416
- `);
8417
- const capturedOutput = capture.claimOutput();
8418
- if (capturedOutput) {
8419
- this.realStdoutWrite.call(this.stdout, capturedOutput + `
8420
- `);
8421
- }
8623
+ this.dumpOutputCache();
8422
8624
  this.realStdoutWrite.call(this.stdout, `
8423
8625
  Error details:
8424
8626
  `);
@@ -8431,14 +8633,39 @@ Error details:
8431
8633
  process.exit(1);
8432
8634
  });
8433
8635
  }).bind(this);
8636
+ dumpOutputCache(optionalMessage = "") {
8637
+ const cachedLogs = this.console.getCachedLogs();
8638
+ const capturedOutput = capture.claimOutput();
8639
+ if (capturedOutput.length > 0 || cachedLogs.length > 0) {
8640
+ this.realStdoutWrite.call(this.stdout, optionalMessage);
8641
+ }
8642
+ if (cachedLogs.length > 0) {
8643
+ this.realStdoutWrite.call(this.stdout, `Console cache:
8644
+ `);
8645
+ this.realStdoutWrite.call(this.stdout, cachedLogs);
8646
+ }
8647
+ if (capturedOutput.length > 0) {
8648
+ this.realStdoutWrite.call(this.stdout, `
8649
+ Captured output:
8650
+ `);
8651
+ this.realStdoutWrite.call(this.stdout, capturedOutput + `
8652
+ `);
8653
+ }
8654
+ this.realStdoutWrite.call(this.stdout, ANSI.reset);
8655
+ }
8434
8656
  exitHandler = (() => {
8435
8657
  this.destroy();
8658
+ if (env.OTUI_DUMP_CAPTURES) {
8659
+ this.dumpOutputCache(`=== CAPTURED OUTPUT ===
8660
+ `);
8661
+ }
8436
8662
  }).bind(this);
8437
8663
  warningHandler = ((warning) => {
8438
8664
  console.warn(JSON.stringify(warning.message, null, 2));
8439
8665
  }).bind(this);
8440
8666
  constructor(lib, rendererPtr, stdin, stdout, width, height, config = {}) {
8441
8667
  super();
8668
+ rendererTracker.addRenderer(this);
8442
8669
  this.stdin = stdin;
8443
8670
  this.stdout = stdout;
8444
8671
  this.realStdoutWrite = stdout.write;
@@ -8495,7 +8722,7 @@ Error details:
8495
8722
  global.window = {};
8496
8723
  }
8497
8724
  global.window.requestAnimationFrame = requestAnimationFrame;
8498
- if (process.env.OTUI_NO_NATIVE_RENDER === "true") {
8725
+ if (env.OTUI_NO_NATIVE_RENDER) {
8499
8726
  this.renderNative = () => {
8500
8727
  if (this._splitHeight > 0) {
8501
8728
  this.flushStdoutCache(this._splitHeight);
@@ -8698,11 +8925,6 @@ Error details:
8698
8925
  if (this._terminalIsSetup)
8699
8926
  return;
8700
8927
  this._terminalIsSetup = true;
8701
- if (this.stdin.setRawMode) {
8702
- this.stdin.setRawMode(true);
8703
- }
8704
- this.stdin.resume();
8705
- this.stdin.setEncoding("utf8");
8706
8928
  await new Promise((resolve) => {
8707
8929
  const timeout = setTimeout(() => {
8708
8930
  this.stdin.off("data", capListener);
@@ -8739,7 +8961,7 @@ Error details:
8739
8961
  }
8740
8962
  if (this.exitOnCtrlC && str === "\x03") {
8741
8963
  process.nextTick(() => {
8742
- process.exit();
8964
+ this.destroy();
8743
8965
  });
8744
8966
  return;
8745
8967
  }
@@ -8749,6 +8971,11 @@ Error details:
8749
8971
  this.emit("key", data);
8750
8972
  }).bind(this);
8751
8973
  setupInput() {
8974
+ if (this.stdin.setRawMode) {
8975
+ this.stdin.setRawMode(true);
8976
+ }
8977
+ this.stdin.resume();
8978
+ this.stdin.setEncoding("utf8");
8752
8979
  this.stdin.on("data", this.stdinListener);
8753
8980
  }
8754
8981
  handleMouseData(data) {
@@ -8914,7 +9141,7 @@ Error details:
8914
9141
  }
8915
9142
  queryPixelResolution() {
8916
9143
  this.waitingForPixelResolution = true;
8917
- this.writeOut(ANSI.queryPixelSize);
9144
+ this.lib.queryPixelResolution(this.rendererPtr);
8918
9145
  }
8919
9146
  processResize(width, height) {
8920
9147
  if (width === this._terminalWidth && height === this._terminalHeight)
@@ -8977,9 +9204,6 @@ Error details:
8977
9204
  this.lib.setDebugOverlay(this.rendererPtr, this.debugOverlay.enabled, this.debugOverlay.corner);
8978
9205
  this.requestRender();
8979
9206
  }
8980
- clearTerminal() {
8981
- this.lib.clearTerminal(this.rendererPtr);
8982
- }
8983
9207
  setTerminalTitle(title) {
8984
9208
  this.lib.setTerminalTitle(this.rendererPtr, title);
8985
9209
  }
@@ -9092,22 +9316,22 @@ Error details:
9092
9316
  }
9093
9317
  }
9094
9318
  destroy() {
9095
- this.stdin.removeListener("data", this.stdinListener);
9096
9319
  process.removeListener("SIGWINCH", this.sigwinchHandler);
9097
9320
  process.removeListener("uncaughtException", this.handleError);
9098
9321
  process.removeListener("unhandledRejection", this.handleError);
9099
- process.removeListener("exit", this.exitHandler);
9100
9322
  process.removeListener("warning", this.warningHandler);
9101
9323
  capture.removeListener("write", this.captureCallback);
9102
9324
  if (this.memorySnapshotTimer) {
9103
9325
  clearInterval(this.memorySnapshotTimer);
9104
9326
  }
9105
- if (this.stdin.setRawMode) {
9106
- this.stdin.setRawMode(false);
9107
- }
9108
9327
  if (this.isDestroyed)
9109
9328
  return;
9110
9329
  this.isDestroyed = true;
9330
+ if (this.renderTimeout) {
9331
+ clearTimeout(this.renderTimeout);
9332
+ this.renderTimeout = null;
9333
+ }
9334
+ this._isRunning = false;
9111
9335
  this.waitingForPixelResolution = false;
9112
9336
  this.capturedRenderable = undefined;
9113
9337
  this.root.destroyRecursively();
@@ -9117,7 +9341,12 @@ Error details:
9117
9341
  if (this._splitHeight > 0) {
9118
9342
  this.flushStdoutCache(this._splitHeight, true);
9119
9343
  }
9344
+ if (this.stdin.setRawMode) {
9345
+ this.stdin.setRawMode(false);
9346
+ }
9347
+ this.stdin.removeListener("data", this.stdinListener);
9120
9348
  this.lib.destroyRenderer(this.rendererPtr);
9349
+ rendererTracker.removeRenderer(this);
9121
9350
  }
9122
9351
  startRenderLoop() {
9123
9352
  if (!this._isRunning)
@@ -9174,7 +9403,9 @@ Error details:
9174
9403
  postProcessFn(this.nextRenderBuffer, deltaTime);
9175
9404
  }
9176
9405
  this._console.renderToBuffer(this.nextRenderBuffer);
9177
- this.renderNative();
9406
+ if (!this.isDestroyed) {
9407
+ this.renderNative();
9408
+ }
9178
9409
  const overallFrameTime = performance.now() - overallStart;
9179
9410
  this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
9180
9411
  if (this.gatherStats) {
@@ -9341,7 +9572,7 @@ Error details:
9341
9572
  }
9342
9573
  }
9343
9574
 
9344
- export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, KeyHandler, getKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, visualizeRenderableTree, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, t, SyntaxStyle, hastToStyledText, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
9575
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, KeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, visualizeRenderableTree, isStyledText, StyledText, stringToStyledText, black, red, green, yellow, blue, magenta, cyan, white, brightBlack, brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite, bgBlack, bgRed, bgGreen, bgYellow, bgBlue, bgMagenta, bgCyan, bgWhite, bold, italic, underline, strikethrough, dim, reverse, blink, fg, bg, t, SyntaxStyle, hastToStyledText, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, generateEnvMarkdown, generateEnvColored, env, TextBuffer, LogLevel2 as LogLevel, setRenderLibPath, resolveRenderLib, OptimizedBuffer, h, isVNode, maybeMakeRenderable, wrapWithDelegates, instantiate, delegate, isValidPercentage, LayoutEvents, RenderableEvents, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
9345
9576
 
9346
- //# debugId=F7540B181A9A091164756E2164756E21
9347
- //# sourceMappingURL=index-0yx9rnxg.js.map
9577
+ //# debugId=FA47EE78BCA83E8664756E2164756E21
9578
+ //# sourceMappingURL=index-6kvgbzah.js.map