@opentui/core 0.0.0-20250908-4906ddad → 0.0.0-20250915-f5db043a

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.
@@ -1,3 +1,4 @@
1
+ // @bun
1
2
  var __create = Object.create;
2
3
  var __getProtoOf = Object.getPrototypeOf;
3
4
  var __defProp = Object.defineProperty;
@@ -1790,21 +1791,11 @@ class TrackedNode extends EventEmitter {
1790
1791
  }
1791
1792
  setWidth(width) {
1792
1793
  this._width = width;
1793
- const parsedWidth = this.parseWidth(width);
1794
- if (parsedWidth === "auto") {
1795
- this.yogaNode.setWidthAuto();
1796
- } else {
1797
- this.yogaNode.setWidth(parsedWidth);
1798
- }
1794
+ this.yogaNode.setWidth(width);
1799
1795
  }
1800
1796
  setHeight(height) {
1801
1797
  this._height = height;
1802
- const parsedHeight = this.parseHeight(height);
1803
- if (parsedHeight === "auto") {
1804
- this.yogaNode.setHeightAuto();
1805
- } else {
1806
- this.yogaNode.setHeight(parsedHeight);
1807
- }
1798
+ this.yogaNode.setHeight(height);
1808
1799
  }
1809
1800
  addChild(childNode) {
1810
1801
  if (childNode.parent) {
@@ -1917,6 +1908,237 @@ function createTrackedNode(metadata = {}, yogaConfig) {
1917
1908
 
1918
1909
  // src/lib/parse.keypress.ts
1919
1910
  import { Buffer } from "buffer";
1911
+
1912
+ // src/lib/parse.keypress-kitty.ts
1913
+ var kittyKeyMap = {
1914
+ 27: "escape",
1915
+ 9: "tab",
1916
+ 13: "enter",
1917
+ 127: "backspace",
1918
+ 57344: "escape",
1919
+ 57345: "enter",
1920
+ 57346: "tab",
1921
+ 57347: "backspace",
1922
+ 57348: "insert",
1923
+ 57349: "delete",
1924
+ 57350: "left",
1925
+ 57351: "right",
1926
+ 57352: "up",
1927
+ 57353: "down",
1928
+ 57354: "pageup",
1929
+ 57355: "pagedown",
1930
+ 57356: "home",
1931
+ 57357: "end",
1932
+ 57364: "f1",
1933
+ 57365: "f2",
1934
+ 57366: "f3",
1935
+ 57367: "f4",
1936
+ 57368: "f5",
1937
+ 57369: "f6",
1938
+ 57370: "f7",
1939
+ 57371: "f8",
1940
+ 57372: "f9",
1941
+ 57373: "f10",
1942
+ 57374: "f11",
1943
+ 57375: "f12",
1944
+ 57376: "f13",
1945
+ 57377: "f14",
1946
+ 57378: "f15",
1947
+ 57379: "f16",
1948
+ 57380: "f17",
1949
+ 57381: "f18",
1950
+ 57382: "f19",
1951
+ 57383: "f20",
1952
+ 57384: "f21",
1953
+ 57385: "f22",
1954
+ 57386: "f23",
1955
+ 57387: "f24",
1956
+ 57388: "f25",
1957
+ 57389: "f26",
1958
+ 57390: "f27",
1959
+ 57391: "f28",
1960
+ 57392: "f29",
1961
+ 57393: "f30",
1962
+ 57394: "f31",
1963
+ 57395: "f32",
1964
+ 57396: "f33",
1965
+ 57397: "f34",
1966
+ 57398: "f35",
1967
+ 57400: "kp0",
1968
+ 57401: "kp1",
1969
+ 57402: "kp2",
1970
+ 57403: "kp3",
1971
+ 57404: "kp4",
1972
+ 57405: "kp5",
1973
+ 57406: "kp6",
1974
+ 57407: "kp7",
1975
+ 57408: "kp8",
1976
+ 57409: "kp9",
1977
+ 57410: "kpdecimal",
1978
+ 57411: "kpdivide",
1979
+ 57412: "kpmultiply",
1980
+ 57413: "kpminus",
1981
+ 57414: "kpplus",
1982
+ 57415: "kpenter",
1983
+ 57416: "kpequal",
1984
+ 57428: "mediaplay",
1985
+ 57429: "mediapause",
1986
+ 57430: "mediaplaypause",
1987
+ 57431: "mediareverse",
1988
+ 57432: "mediastop",
1989
+ 57433: "mediafastforward",
1990
+ 57434: "mediarewind",
1991
+ 57435: "medianext",
1992
+ 57436: "mediaprev",
1993
+ 57437: "mediarecord",
1994
+ 57438: "volumedown",
1995
+ 57439: "volumeup",
1996
+ 57440: "mute",
1997
+ 57441: "leftshift",
1998
+ 57442: "leftctrl",
1999
+ 57443: "leftalt",
2000
+ 57444: "leftsuper",
2001
+ 57445: "lefthyper",
2002
+ 57446: "leftmeta",
2003
+ 57447: "rightshift",
2004
+ 57448: "rightctrl",
2005
+ 57449: "rightalt",
2006
+ 57450: "rightsuper",
2007
+ 57451: "righthyper",
2008
+ 57452: "rightmeta",
2009
+ 57453: "iso_level3_shift",
2010
+ 57454: "iso_level5_shift"
2011
+ };
2012
+ function fromKittyMods(mod) {
2013
+ return {
2014
+ shift: !!(mod & 1),
2015
+ alt: !!(mod & 2),
2016
+ ctrl: !!(mod & 4),
2017
+ super: !!(mod & 8),
2018
+ hyper: !!(mod & 16),
2019
+ meta: !!(mod & 32),
2020
+ capsLock: !!(mod & 64),
2021
+ numLock: !!(mod & 128)
2022
+ };
2023
+ }
2024
+ function parseKittyKeyboard(sequence) {
2025
+ const kittyRe = /^\x1b\[([^\x1b]+)u$/;
2026
+ const match = kittyRe.exec(sequence);
2027
+ if (!match)
2028
+ return null;
2029
+ const params = match[1];
2030
+ const fields = params.split(";");
2031
+ if (fields.length < 1)
2032
+ return null;
2033
+ const key = {
2034
+ name: "",
2035
+ ctrl: false,
2036
+ meta: false,
2037
+ shift: false,
2038
+ option: false,
2039
+ number: false,
2040
+ sequence,
2041
+ raw: sequence,
2042
+ eventType: "press",
2043
+ super: false,
2044
+ hyper: false,
2045
+ capsLock: false,
2046
+ numLock: false
2047
+ };
2048
+ let text = "";
2049
+ const field1 = fields[0]?.split(":") || [];
2050
+ const codepointStr = field1[0];
2051
+ if (!codepointStr)
2052
+ return null;
2053
+ const codepoint = parseInt(codepointStr, 10);
2054
+ if (isNaN(codepoint))
2055
+ return null;
2056
+ let shiftedCodepoint;
2057
+ let baseCodepoint;
2058
+ if (field1[1]) {
2059
+ const shifted = parseInt(field1[1], 10);
2060
+ if (!isNaN(shifted) && shifted > 0 && shifted <= 1114111) {
2061
+ shiftedCodepoint = shifted;
2062
+ }
2063
+ }
2064
+ if (field1[2]) {
2065
+ const base = parseInt(field1[2], 10);
2066
+ if (!isNaN(base) && base > 0 && base <= 1114111) {
2067
+ baseCodepoint = base;
2068
+ }
2069
+ }
2070
+ const knownKey = kittyKeyMap[codepoint];
2071
+ if (knownKey) {
2072
+ key.name = knownKey;
2073
+ key.code = `[${codepoint}u`;
2074
+ } else {
2075
+ if (codepoint > 0 && codepoint <= 1114111) {
2076
+ const char = String.fromCodePoint(codepoint);
2077
+ key.name = char;
2078
+ if (baseCodepoint) {
2079
+ key.baseCode = baseCodepoint;
2080
+ }
2081
+ } else {
2082
+ return null;
2083
+ }
2084
+ }
2085
+ if (fields[1]) {
2086
+ const field2 = fields[1].split(":");
2087
+ const modifierStr = field2[0];
2088
+ const eventTypeStr = field2[1];
2089
+ if (modifierStr) {
2090
+ const modifierMask = parseInt(modifierStr, 10);
2091
+ if (!isNaN(modifierMask) && modifierMask > 1) {
2092
+ const mods = fromKittyMods(modifierMask - 1);
2093
+ key.shift = mods.shift;
2094
+ key.ctrl = mods.ctrl;
2095
+ key.meta = mods.alt || mods.meta;
2096
+ key.option = mods.alt;
2097
+ key.super = mods.super;
2098
+ key.hyper = mods.hyper;
2099
+ key.capsLock = mods.capsLock;
2100
+ key.numLock = mods.numLock;
2101
+ }
2102
+ }
2103
+ if (eventTypeStr === "1" || !eventTypeStr) {
2104
+ key.eventType = "press";
2105
+ } else if (eventTypeStr === "2") {
2106
+ key.eventType = "repeat";
2107
+ } else if (eventTypeStr === "3") {
2108
+ key.eventType = "release";
2109
+ } else {
2110
+ key.eventType = "press";
2111
+ }
2112
+ }
2113
+ if (fields[2]) {
2114
+ const codepoints = fields[2].split(":");
2115
+ for (const cpStr of codepoints) {
2116
+ const cp = parseInt(cpStr, 10);
2117
+ if (!isNaN(cp) && cp > 0 && cp <= 1114111) {
2118
+ text += String.fromCodePoint(cp);
2119
+ }
2120
+ }
2121
+ }
2122
+ if (text === "") {
2123
+ const isPrintable = key.name.length > 0 && !kittyKeyMap[codepoint];
2124
+ if (isPrintable) {
2125
+ if (key.shift && shiftedCodepoint) {
2126
+ text = String.fromCodePoint(shiftedCodepoint);
2127
+ } else {
2128
+ text = key.name;
2129
+ }
2130
+ }
2131
+ }
2132
+ if (key.name === " " && key.shift && !key.ctrl && !key.meta) {
2133
+ text = " ";
2134
+ }
2135
+ if (text) {
2136
+ key.sequence = text;
2137
+ }
2138
+ return key;
2139
+ }
2140
+
2141
+ // src/lib/parse.keypress.ts
1920
2142
  var metaKeyCodeRe = /^(?:\x1b)([a-zA-Z0-9])$/;
1921
2143
  var fnKeyRe = /^(?:\x1b+)(O|N|\[|\[\[)(?:(\d+)(?:;(\d+))?([~^$])|(?:1;)?(\d+)?([a-zA-Z]))/;
1922
2144
  var keyName = {
@@ -2000,7 +2222,7 @@ var isShiftKey = (code) => {
2000
2222
  var isCtrlKey = (code) => {
2001
2223
  return ["Oa", "Ob", "Oc", "Od", "Oe", "[2^", "[3^", "[5^", "[6^", "[7^", "[8^"].includes(code);
2002
2224
  };
2003
- var parseKeypress = (s = "") => {
2225
+ var parseKeypress = (s = "", options = {}) => {
2004
2226
  let parts;
2005
2227
  if (Buffer.isBuffer(s)) {
2006
2228
  if (s[0] > 127 && s[1] === undefined) {
@@ -2022,9 +2244,16 @@ var parseKeypress = (s = "") => {
2022
2244
  option: false,
2023
2245
  number: false,
2024
2246
  sequence: s,
2025
- raw: s
2247
+ raw: s,
2248
+ eventType: "press"
2026
2249
  };
2027
2250
  key.sequence = key.sequence || s || key.name;
2251
+ if (options.useKittyKeyboard && /^\x1b\[.*u$/.test(s)) {
2252
+ const kittyResult = parseKittyKeyboard(s);
2253
+ if (kittyResult) {
2254
+ return kittyResult;
2255
+ }
2256
+ }
2028
2257
  if (s === "\r") {
2029
2258
  key.name = "return";
2030
2259
  } else if (s === `
@@ -2064,15 +2293,21 @@ var parseKeypress = (s = "") => {
2064
2293
  key.option = true;
2065
2294
  }
2066
2295
  const code = [parts[1], parts[2], parts[4], parts[6]].filter(Boolean).join("");
2067
- const modifier = (parts[3] || parts[5] || 1) - 1;
2296
+ const modifier = parseInt(parts[3] || parts[5] || "1", 10) - 1;
2068
2297
  key.ctrl = !!(modifier & 4);
2069
2298
  key.meta = !!(modifier & 10);
2070
2299
  key.shift = !!(modifier & 1);
2071
2300
  key.option = !!(modifier & 2);
2072
2301
  key.code = code;
2073
- key.name = keyName[code];
2074
- key.shift = isShiftKey(code) || key.shift;
2075
- key.ctrl = isCtrlKey(code) || key.ctrl;
2302
+ const keyNameResult = keyName[code];
2303
+ if (keyNameResult) {
2304
+ key.name = keyNameResult;
2305
+ key.shift = isShiftKey(code) || key.shift;
2306
+ key.ctrl = isCtrlKey(code) || key.ctrl;
2307
+ } else {
2308
+ key.name = "";
2309
+ key.code = undefined;
2310
+ }
2076
2311
  } else if (s === "\x1B[3~") {
2077
2312
  key.name = "delete";
2078
2313
  key.meta = false;
@@ -2096,26 +2331,43 @@ function singleton(key, factory) {
2096
2331
 
2097
2332
  // src/lib/KeyHandler.ts
2098
2333
  class KeyHandler extends EventEmitter2 {
2099
- constructor() {
2334
+ stdin;
2335
+ useKittyKeyboard;
2336
+ constructor(stdin, useKittyKeyboard = false) {
2100
2337
  super();
2101
- if (process.stdin.setRawMode) {
2102
- process.stdin.setRawMode(true);
2103
- }
2104
- process.stdin.resume();
2105
- process.stdin.setEncoding("utf8");
2106
- process.stdin.on("data", (key) => {
2107
- const parsedKey = parseKeypress(key);
2108
- this.emit("keypress", parsedKey);
2338
+ this.stdin = stdin || process.stdin;
2339
+ this.useKittyKeyboard = useKittyKeyboard;
2340
+ if (this.stdin.setRawMode) {
2341
+ this.stdin.setRawMode(true);
2342
+ }
2343
+ this.stdin.resume();
2344
+ this.stdin.setEncoding("utf8");
2345
+ this.stdin.on("data", (key) => {
2346
+ const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2347
+ switch (parsedKey.eventType) {
2348
+ case "press":
2349
+ this.emit("keypress", parsedKey);
2350
+ break;
2351
+ case "repeat":
2352
+ this.emit("keyrepeat", parsedKey);
2353
+ break;
2354
+ case "release":
2355
+ this.emit("keyrelease", parsedKey);
2356
+ break;
2357
+ default:
2358
+ this.emit("keypress", parsedKey);
2359
+ break;
2360
+ }
2109
2361
  });
2110
2362
  }
2111
2363
  destroy() {
2112
- process.stdin.removeAllListeners("data");
2364
+ this.stdin.removeAllListeners("data");
2113
2365
  }
2114
2366
  }
2115
2367
  var keyHandler = null;
2116
- function getKeyHandler() {
2368
+ function getKeyHandler(useKittyKeyboard = false) {
2117
2369
  if (!keyHandler) {
2118
- keyHandler = singleton("KeyHandler", () => new KeyHandler);
2370
+ keyHandler = singleton("KeyHandler", () => new KeyHandler(process.stdin, useKittyKeyboard));
2119
2371
  }
2120
2372
  return keyHandler;
2121
2373
  }
@@ -3936,11 +4188,40 @@ function createTextAttributes({
3936
4188
  attributes |= TextAttributes.STRIKETHROUGH;
3937
4189
  return attributes;
3938
4190
  }
4191
+ function visualizeRenderableTree(renderable, maxDepth = 10) {
4192
+ function buildTreeLines(node, prefix = "", parentPrefix = "", isLastChild = true, depth = 0) {
4193
+ if (depth >= maxDepth) {
4194
+ return [`${prefix}${node.id} ... (max depth reached)`];
4195
+ }
4196
+ const lines = [];
4197
+ const children = node.getChildren();
4198
+ lines.push(`${prefix}${node.id}`);
4199
+ if (children.length > 0) {
4200
+ const lastChildIndex = children.length - 1;
4201
+ children.forEach((child, index) => {
4202
+ const childIsLast = index === lastChildIndex;
4203
+ const connector = childIsLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
4204
+ const childPrefix = parentPrefix + (isLastChild ? " " : "\u2502 ");
4205
+ const childLines = buildTreeLines(child, childPrefix + connector, childPrefix, childIsLast, depth + 1);
4206
+ lines.push(...childLines);
4207
+ });
4208
+ }
4209
+ return lines;
4210
+ }
4211
+ const treeLines = buildTreeLines(renderable);
4212
+ console.log(`Renderable Tree:
4213
+ ` + treeLines.join(`
4214
+ `));
4215
+ }
3939
4216
 
3940
4217
  // src/lib/styled-text.ts
3941
- var textEncoder = new TextEncoder;
4218
+ var BrandedStyledText = Symbol.for("@opentui/core/StyledText");
4219
+ function isStyledText(obj) {
4220
+ return obj && obj[BrandedStyledText];
4221
+ }
3942
4222
 
3943
4223
  class StyledText {
4224
+ [BrandedStyledText] = true;
3944
4225
  chunks;
3945
4226
  textRenderable;
3946
4227
  constructor(chunks) {
@@ -3998,11 +4279,9 @@ class StyledText {
3998
4279
  }
3999
4280
  }
4000
4281
  function stringToStyledText(content) {
4001
- const textEncoder2 = new TextEncoder;
4002
4282
  const chunk = {
4003
4283
  __isChunk: true,
4004
- text: textEncoder2.encode(content),
4005
- plainText: content
4284
+ text: content
4006
4285
  };
4007
4286
  return new StyledText([chunk]);
4008
4287
  }
@@ -4016,21 +4295,18 @@ function applyStyle(input, style) {
4016
4295
  return {
4017
4296
  __isChunk: true,
4018
4297
  text: existingChunk.text,
4019
- plainText: existingChunk.plainText,
4020
4298
  fg,
4021
4299
  bg,
4022
4300
  attributes: mergedAttrs
4023
4301
  };
4024
4302
  } else {
4025
4303
  const plainTextStr = String(input);
4026
- const text = textEncoder.encode(plainTextStr);
4027
4304
  const fg = style.fg ? parseColor(style.fg) : undefined;
4028
4305
  const bg = style.bg ? parseColor(style.bg) : undefined;
4029
4306
  const attributes = createTextAttributes(style);
4030
4307
  return {
4031
4308
  __isChunk: true,
4032
- text,
4033
- plainText: plainTextStr,
4309
+ text: plainTextStr,
4034
4310
  fg,
4035
4311
  bg,
4036
4312
  attributes
@@ -4077,8 +4353,7 @@ function t(strings, ...values) {
4077
4353
  if (raw) {
4078
4354
  chunks.push({
4079
4355
  __isChunk: true,
4080
- text: textEncoder.encode(raw),
4081
- plainText: raw,
4356
+ text: raw,
4082
4357
  attributes: 0
4083
4358
  });
4084
4359
  }
@@ -4089,8 +4364,7 @@ function t(strings, ...values) {
4089
4364
  const plainTextStr = String(val);
4090
4365
  chunks.push({
4091
4366
  __isChunk: true,
4092
- text: textEncoder.encode(plainTextStr),
4093
- plainText: plainTextStr,
4367
+ text: plainTextStr,
4094
4368
  attributes: 0
4095
4369
  });
4096
4370
  }
@@ -4150,7 +4424,6 @@ class SyntaxStyle {
4150
4424
  return this.mergedStyleCache.size;
4151
4425
  }
4152
4426
  }
4153
- var textEncoder2 = new TextEncoder;
4154
4427
  function hastToTextChunks(node, syntaxStyle, parentStyles = []) {
4155
4428
  const chunks = [];
4156
4429
  if (node.type === "text") {
@@ -4158,8 +4431,7 @@ function hastToTextChunks(node, syntaxStyle, parentStyles = []) {
4158
4431
  const mergedStyle = syntaxStyle.mergeStyles(...stylesToMerge);
4159
4432
  chunks.push({
4160
4433
  __isChunk: true,
4161
- text: textEncoder2.encode(node.value),
4162
- plainText: node.value,
4434
+ text: node.value,
4163
4435
  fg: mergedStyle.fg,
4164
4436
  bg: mergedStyle.bg,
4165
4437
  attributes: mergedStyle.attributes
@@ -4718,10 +4990,16 @@ class OptimizedBuffer {
4718
4990
  _height;
4719
4991
  respectAlpha = false;
4720
4992
  _rawBuffers = null;
4993
+ _destroyed = false;
4721
4994
  get ptr() {
4722
4995
  return this.bufferPtr;
4723
4996
  }
4997
+ guard() {
4998
+ if (this._destroyed)
4999
+ throw new Error(`Buffer ${this.id} is destroyed`);
5000
+ }
4724
5001
  get buffers() {
5002
+ this.guard();
4725
5003
  if (this._rawBuffers === null) {
4726
5004
  const size = this._width * this._height;
4727
5005
  const charPtr = this.lib.bufferGetCharPtr(this.bufferPtr);
@@ -4751,9 +5029,6 @@ class OptimizedBuffer {
4751
5029
  const id = options.id && options.id.trim() !== "" ? options.id : "unnamed buffer";
4752
5030
  return lib.createOptimizedBuffer(width, height, widthMethod, respectAlpha, id);
4753
5031
  }
4754
- coordsToIndex(x, y) {
4755
- return y * this._width + x;
4756
- }
4757
5032
  get width() {
4758
5033
  return this._width;
4759
5034
  }
@@ -4761,22 +5036,35 @@ class OptimizedBuffer {
4761
5036
  return this._height;
4762
5037
  }
4763
5038
  setRespectAlpha(respectAlpha) {
5039
+ this.guard();
4764
5040
  this.lib.bufferSetRespectAlpha(this.bufferPtr, respectAlpha);
4765
5041
  this.respectAlpha = respectAlpha;
4766
5042
  }
4767
5043
  getNativeId() {
5044
+ this.guard();
4768
5045
  return this.lib.bufferGetId(this.bufferPtr);
4769
5046
  }
5047
+ getRealCharBytes(addLineBreaks = false) {
5048
+ this.guard();
5049
+ const realSize = this.lib.bufferGetRealCharSize(this.bufferPtr);
5050
+ const outputBuffer = new Uint8Array(realSize);
5051
+ const bytesWritten = this.lib.bufferWriteResolvedChars(this.bufferPtr, outputBuffer, addLineBreaks);
5052
+ return outputBuffer.slice(0, bytesWritten);
5053
+ }
4770
5054
  clear(bg2 = RGBA.fromValues(0, 0, 0, 1)) {
5055
+ this.guard();
4771
5056
  this.lib.bufferClear(this.bufferPtr, bg2);
4772
5057
  }
4773
5058
  setCell(x, y, char, fg2, bg2, attributes = 0) {
5059
+ this.guard();
4774
5060
  this.lib.bufferSetCell(this.bufferPtr, x, y, char, fg2, bg2, attributes);
4775
5061
  }
4776
5062
  setCellWithAlphaBlending(x, y, char, fg2, bg2, attributes = 0) {
5063
+ this.guard();
4777
5064
  this.lib.bufferSetCellWithAlphaBlending(this.bufferPtr, x, y, char, fg2, bg2, attributes);
4778
5065
  }
4779
5066
  drawText(text, x, y, fg2, bg2, attributes = 0, selection2) {
5067
+ this.guard();
4780
5068
  if (!selection2) {
4781
5069
  this.lib.bufferDrawText(this.bufferPtr, text, x, y, fg2, bg2, attributes);
4782
5070
  return;
@@ -4809,21 +5097,29 @@ class OptimizedBuffer {
4809
5097
  this.lib.bufferFillRect(this.bufferPtr, x, y, width, height, bg2);
4810
5098
  }
4811
5099
  drawFrameBuffer(destX, destY, frameBuffer, sourceX, sourceY, sourceWidth, sourceHeight) {
5100
+ this.guard();
4812
5101
  this.lib.drawFrameBuffer(this.bufferPtr, destX, destY, frameBuffer.ptr, sourceX, sourceY, sourceWidth, sourceHeight);
4813
5102
  }
4814
5103
  destroy() {
5104
+ if (this._destroyed)
5105
+ return;
5106
+ this._destroyed = true;
4815
5107
  this.lib.destroyOptimizedBuffer(this.bufferPtr);
4816
5108
  }
4817
5109
  drawTextBuffer(textBuffer, x, y, clipRect) {
5110
+ this.guard();
4818
5111
  this.lib.bufferDrawTextBuffer(this.bufferPtr, textBuffer.ptr, x, y, clipRect);
4819
5112
  }
4820
5113
  drawSuperSampleBuffer(x, y, pixelDataPtr, pixelDataLength, format, alignedBytesPerRow) {
5114
+ this.guard();
4821
5115
  this.lib.bufferDrawSuperSampleBuffer(this.bufferPtr, x, y, pixelDataPtr, pixelDataLength, format, alignedBytesPerRow);
4822
5116
  }
4823
5117
  drawPackedBuffer(dataPtr, dataLen, posX, posY, terminalWidthCells, terminalHeightCells) {
5118
+ this.guard();
4824
5119
  this.lib.bufferDrawPackedBuffer(this.bufferPtr, dataPtr, dataLen, posX, posY, terminalWidthCells, terminalHeightCells);
4825
5120
  }
4826
5121
  resize(width, height) {
5122
+ this.guard();
4827
5123
  if (this._width === width && this._height === height)
4828
5124
  return;
4829
5125
  this._width = width;
@@ -4832,18 +5128,22 @@ class OptimizedBuffer {
4832
5128
  this.lib.bufferResize(this.bufferPtr, width, height);
4833
5129
  }
4834
5130
  drawBox(options) {
5131
+ this.guard();
4835
5132
  const style = options.borderStyle || "single";
4836
5133
  const borderChars = options.customBorderChars ?? BorderCharArrays[style];
4837
5134
  const packedOptions = packDrawOptions(options.border, options.shouldFill ?? false, options.titleAlignment || "left");
4838
5135
  this.lib.bufferDrawBox(this.bufferPtr, options.x, options.y, options.width, options.height, borderChars, packedOptions, options.borderColor, options.backgroundColor, options.title ?? null);
4839
5136
  }
4840
5137
  pushScissorRect(x, y, width, height) {
5138
+ this.guard();
4841
5139
  this.lib.bufferPushScissorRect(this.bufferPtr, x, y, width, height);
4842
5140
  }
4843
5141
  popScissorRect() {
5142
+ this.guard();
4844
5143
  this.lib.bufferPopScissorRect(this.bufferPtr);
4845
5144
  }
4846
5145
  clearScissorRects() {
5146
+ this.guard();
4847
5147
  this.lib.bufferClearScissorRects(this.bufferPtr);
4848
5148
  }
4849
5149
  }
@@ -4856,17 +5156,17 @@ if (!existsSync(targetLibPath)) {
4856
5156
  }
4857
5157
  function getOpenTUILib(libPath) {
4858
5158
  const resolvedLibPath = libPath || targetLibPath;
4859
- return dlopen(resolvedLibPath, {
5159
+ const rawSymbols = dlopen(resolvedLibPath, {
4860
5160
  setLogCallback: {
4861
5161
  args: ["ptr"],
4862
5162
  returns: "void"
4863
5163
  },
4864
5164
  createRenderer: {
4865
- args: ["u32", "u32"],
5165
+ args: ["u32", "u32", "bool"],
4866
5166
  returns: "ptr"
4867
5167
  },
4868
5168
  destroyRenderer: {
4869
- args: ["ptr", "bool", "u32"],
5169
+ args: ["ptr"],
4870
5170
  returns: "void"
4871
5171
  },
4872
5172
  setUseThread: {
@@ -4953,6 +5253,14 @@ function getOpenTUILib(libPath) {
4953
5253
  args: ["ptr", "ptr", "usize"],
4954
5254
  returns: "usize"
4955
5255
  },
5256
+ bufferGetRealCharSize: {
5257
+ args: ["ptr"],
5258
+ returns: "u32"
5259
+ },
5260
+ bufferWriteResolvedChars: {
5261
+ args: ["ptr", "ptr", "usize", "bool"],
5262
+ returns: "u32"
5263
+ },
4956
5264
  bufferDrawText: {
4957
5265
  args: ["ptr", "ptr", "u32", "u32", "u32", "ptr", "ptr", "u8"],
4958
5266
  returns: "void"
@@ -5186,6 +5494,115 @@ function getOpenTUILib(libPath) {
5186
5494
  returns: "void"
5187
5495
  }
5188
5496
  });
5497
+ if (process.env.DEBUG_FFI === "true" || process.env.TRACE_FFI === "true") {
5498
+ return {
5499
+ symbols: convertToDebugSymbols(rawSymbols.symbols)
5500
+ };
5501
+ }
5502
+ return rawSymbols;
5503
+ }
5504
+ function convertToDebugSymbols(symbols) {
5505
+ const debugSymbols = {};
5506
+ const traceSymbols = {};
5507
+ let hasTracing = false;
5508
+ Object.entries(symbols).forEach(([key, value]) => {
5509
+ debugSymbols[key] = value;
5510
+ });
5511
+ if (process.env.DEBUG_FFI === "true") {
5512
+ Object.entries(symbols).forEach(([key, value]) => {
5513
+ if (typeof value === "function") {
5514
+ debugSymbols[key] = (...args) => {
5515
+ console.log(`${key}(${args.map((arg) => String(arg)).join(", ")})`);
5516
+ const result = value(...args);
5517
+ console.log(`${key} returned:`, String(result));
5518
+ return result;
5519
+ };
5520
+ }
5521
+ });
5522
+ }
5523
+ if (process.env.TRACE_FFI === "true") {
5524
+ hasTracing = true;
5525
+ Object.entries(symbols).forEach(([key, value]) => {
5526
+ if (typeof value === "function") {
5527
+ traceSymbols[key] = [];
5528
+ const originalFunc = debugSymbols[key];
5529
+ debugSymbols[key] = (...args) => {
5530
+ const start = performance.now();
5531
+ const result = originalFunc(...args);
5532
+ const end = performance.now();
5533
+ traceSymbols[key].push(end - start);
5534
+ return result;
5535
+ };
5536
+ }
5537
+ });
5538
+ }
5539
+ if (hasTracing) {
5540
+ process.on("exit", () => {
5541
+ const allStats = [];
5542
+ for (const [key, timings] of Object.entries(traceSymbols)) {
5543
+ if (!Array.isArray(timings) || timings.length === 0) {
5544
+ continue;
5545
+ }
5546
+ const sortedTimings = [...timings].sort((a, b) => a - b);
5547
+ const count = sortedTimings.length;
5548
+ const total = sortedTimings.reduce((acc, t2) => acc + t2, 0);
5549
+ const average = total / count;
5550
+ const min = sortedTimings[0];
5551
+ const max = sortedTimings[count - 1];
5552
+ const medianIndex = Math.floor(count / 2);
5553
+ const p90Index = Math.floor(count * 0.9);
5554
+ const p99Index = Math.floor(count * 0.99);
5555
+ const median = sortedTimings[medianIndex];
5556
+ const p90 = sortedTimings[Math.min(p90Index, count - 1)];
5557
+ const p99 = sortedTimings[Math.min(p99Index, count - 1)];
5558
+ allStats.push({
5559
+ name: key,
5560
+ count,
5561
+ total,
5562
+ average,
5563
+ min,
5564
+ max,
5565
+ median,
5566
+ p90,
5567
+ p99
5568
+ });
5569
+ }
5570
+ allStats.sort((a, b) => b.total - a.total);
5571
+ console.log(`
5572
+ --- OpenTUI FFI Call Performance ---`);
5573
+ console.log("Sorted by total time spent (descending)");
5574
+ console.log("-------------------------------------------------------------------------------------------------------------------------");
5575
+ if (allStats.length === 0) {
5576
+ console.log("No trace data collected or all symbols had zero calls.");
5577
+ } else {
5578
+ const nameHeader = "Symbol";
5579
+ const callsHeader = "Calls";
5580
+ const totalHeader = "Total (ms)";
5581
+ const avgHeader = "Avg (ms)";
5582
+ const minHeader = "Min (ms)";
5583
+ const maxHeader = "Max (ms)";
5584
+ const medHeader = "Med (ms)";
5585
+ const p90Header = "P90 (ms)";
5586
+ const p99Header = "P99 (ms)";
5587
+ const nameWidth = Math.max(nameHeader.length, ...allStats.map((s) => s.name.length));
5588
+ const countWidth = Math.max(callsHeader.length, ...allStats.map((s) => String(s.count).length));
5589
+ const totalWidth = Math.max(totalHeader.length, ...allStats.map((s) => s.total.toFixed(2).length));
5590
+ const avgWidth = Math.max(avgHeader.length, ...allStats.map((s) => s.average.toFixed(2).length));
5591
+ const minWidth = Math.max(minHeader.length, ...allStats.map((s) => s.min.toFixed(2).length));
5592
+ const maxWidth = Math.max(maxHeader.length, ...allStats.map((s) => s.max.toFixed(2).length));
5593
+ const medianWidth = Math.max(medHeader.length, ...allStats.map((s) => s.median.toFixed(2).length));
5594
+ const p90Width = Math.max(p90Header.length, ...allStats.map((s) => s.p90.toFixed(2).length));
5595
+ const p99Width = Math.max(p99Header.length, ...allStats.map((s) => s.p99.toFixed(2).length));
5596
+ console.log(`${nameHeader.padEnd(nameWidth)} | ${callsHeader.padStart(countWidth)} | ${totalHeader.padStart(totalWidth)} | ${avgHeader.padStart(avgWidth)} | ${minHeader.padStart(minWidth)} | ${maxHeader.padStart(maxWidth)} | ${medHeader.padStart(medianWidth)} | ${p90Header.padStart(p90Width)} | ${p99Header.padStart(p99Width)}`);
5597
+ console.log(`${"-".repeat(nameWidth)}-+-${"-".repeat(countWidth)}-+-${"-".repeat(totalWidth)}-+-${"-".repeat(avgWidth)}-+-${"-".repeat(minWidth)}-+-${"-".repeat(maxWidth)}-+-${"-".repeat(medianWidth)}-+-${"-".repeat(p90Width)}-+-${"-".repeat(p99Width)}`);
5598
+ allStats.forEach((stat) => {
5599
+ console.log(`${stat.name.padEnd(nameWidth)} | ${String(stat.count).padStart(countWidth)} | ${stat.total.toFixed(2).padStart(totalWidth)} | ${stat.average.toFixed(2).padStart(avgWidth)} | ${stat.min.toFixed(2).padStart(minWidth)} | ${stat.max.toFixed(2).padStart(maxWidth)} | ${stat.median.toFixed(2).padStart(medianWidth)} | ${stat.p90.toFixed(2).padStart(p90Width)} | ${stat.p99.toFixed(2).padStart(p99Width)}`);
5600
+ });
5601
+ }
5602
+ console.log("-------------------------------------------------------------------------------------------------------------------------");
5603
+ });
5604
+ }
5605
+ return debugSymbols;
5189
5606
  }
5190
5607
  var LogLevel2;
5191
5608
  ((LogLevel3) => {
@@ -5249,11 +5666,11 @@ class FFIRenderLib {
5249
5666
  setLogCallback(callbackPtr) {
5250
5667
  this.opentui.symbols.setLogCallback(callbackPtr);
5251
5668
  }
5252
- createRenderer(width, height) {
5253
- return this.opentui.symbols.createRenderer(width, height);
5669
+ createRenderer(width, height, options = { testing: false }) {
5670
+ return this.opentui.symbols.createRenderer(width, height, options.testing);
5254
5671
  }
5255
- destroyRenderer(renderer, useAlternateScreen, splitHeight) {
5256
- this.opentui.symbols.destroyRenderer(renderer, useAlternateScreen, splitHeight);
5672
+ destroyRenderer(renderer) {
5673
+ this.opentui.symbols.destroyRenderer(renderer);
5257
5674
  }
5258
5675
  setUseThread(renderer, useThread) {
5259
5676
  this.opentui.symbols.setUseThread(renderer, useThread);
@@ -5329,6 +5746,13 @@ class FFIRenderLib {
5329
5746
  const len = typeof actualLen === "bigint" ? Number(actualLen) : actualLen;
5330
5747
  return this.decoder.decode(outBuffer.slice(0, len));
5331
5748
  }
5749
+ bufferGetRealCharSize(buffer) {
5750
+ return this.opentui.symbols.bufferGetRealCharSize(buffer);
5751
+ }
5752
+ bufferWriteResolvedChars(buffer, outputBuffer, addLineBreaks) {
5753
+ const bytesWritten = this.opentui.symbols.bufferWriteResolvedChars(buffer, outputBuffer, outputBuffer.length, addLineBreaks);
5754
+ return typeof bytesWritten === "bigint" ? Number(bytesWritten) : bytesWritten;
5755
+ }
5332
5756
  getBufferWidth(buffer) {
5333
5757
  return this.opentui.symbols.getBufferWidth(buffer);
5334
5758
  }
@@ -5676,21 +6100,28 @@ class TextBuffer {
5676
6100
  _length = 0;
5677
6101
  _capacity;
5678
6102
  _lineInfo;
6103
+ _destroyed = false;
5679
6104
  constructor(lib, ptr2, capacity) {
5680
6105
  this.lib = lib;
5681
6106
  this.bufferPtr = ptr2;
5682
6107
  this._capacity = capacity;
5683
6108
  }
5684
- static create(capacity = 256, widthMethod) {
6109
+ static create(capacity = 64, widthMethod) {
5685
6110
  const lib = resolveRenderLib();
5686
6111
  return lib.createTextBuffer(capacity, widthMethod);
5687
6112
  }
6113
+ guard() {
6114
+ if (this._destroyed)
6115
+ throw new Error("TextBuffer is destroyed");
6116
+ }
5688
6117
  setStyledText(text) {
6118
+ this.guard();
5689
6119
  this.lib.textBufferReset(this.bufferPtr);
5690
6120
  this._length = 0;
5691
6121
  this._lineInfo = undefined;
5692
6122
  for (const chunk of text.chunks) {
5693
- const result = this.lib.textBufferWriteChunk(this.bufferPtr, chunk.text, chunk.fg || null, chunk.bg || null, chunk.attributes ?? null);
6123
+ const textBytes = this.lib.encoder.encode(chunk.text);
6124
+ const result = this.lib.textBufferWriteChunk(this.bufferPtr, textBytes, chunk.fg || null, chunk.bg || null, chunk.attributes ?? null);
5694
6125
  if (result & 1) {
5695
6126
  this._capacity = this.lib.textBufferGetCapacity(this.bufferPtr);
5696
6127
  }
@@ -5699,27 +6130,35 @@ class TextBuffer {
5699
6130
  this._length = this.lib.textBufferGetLength(this.bufferPtr);
5700
6131
  }
5701
6132
  setDefaultFg(fg2) {
6133
+ this.guard();
5702
6134
  this.lib.textBufferSetDefaultFg(this.bufferPtr, fg2);
5703
6135
  }
5704
6136
  setDefaultBg(bg2) {
6137
+ this.guard();
5705
6138
  this.lib.textBufferSetDefaultBg(this.bufferPtr, bg2);
5706
6139
  }
5707
6140
  setDefaultAttributes(attributes) {
6141
+ this.guard();
5708
6142
  this.lib.textBufferSetDefaultAttributes(this.bufferPtr, attributes);
5709
6143
  }
5710
6144
  resetDefaults() {
6145
+ this.guard();
5711
6146
  this.lib.textBufferResetDefaults(this.bufferPtr);
5712
6147
  }
5713
6148
  get length() {
6149
+ this.guard();
5714
6150
  return this._length;
5715
6151
  }
5716
6152
  get capacity() {
6153
+ this.guard();
5717
6154
  return this._capacity;
5718
6155
  }
5719
6156
  get ptr() {
6157
+ this.guard();
5720
6158
  return this.bufferPtr;
5721
6159
  }
5722
6160
  getSelectedText() {
6161
+ this.guard();
5723
6162
  if (this._length === 0)
5724
6163
  return "";
5725
6164
  const selectedBytes = this.lib.getSelectedTextBytes(this.bufferPtr, this.length * 4);
@@ -5728,6 +6167,7 @@ class TextBuffer {
5728
6167
  return this.lib.decoder.decode(selectedBytes);
5729
6168
  }
5730
6169
  getPlainText() {
6170
+ this.guard();
5731
6171
  if (this._length === 0)
5732
6172
  return "";
5733
6173
  const plainBytes = this.lib.getPlainTextBytes(this.bufferPtr, this.length * 4);
@@ -5736,53 +6176,69 @@ class TextBuffer {
5736
6176
  return this.lib.decoder.decode(plainBytes);
5737
6177
  }
5738
6178
  get lineInfo() {
6179
+ this.guard();
5739
6180
  if (!this._lineInfo) {
5740
6181
  this._lineInfo = this.lib.textBufferGetLineInfo(this.bufferPtr);
5741
6182
  }
5742
6183
  return this._lineInfo;
5743
6184
  }
5744
6185
  setSelection(start, end, bgColor, fgColor) {
6186
+ this.guard();
5745
6187
  this.lib.textBufferSetSelection(this.bufferPtr, start, end, bgColor || null, fgColor || null);
5746
6188
  }
5747
6189
  resetSelection() {
6190
+ this.guard();
5748
6191
  this.lib.textBufferResetSelection(this.bufferPtr);
5749
6192
  }
5750
6193
  setLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
6194
+ this.guard();
5751
6195
  return this.lib.textBufferSetLocalSelection(this.bufferPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
5752
6196
  }
5753
6197
  resetLocalSelection() {
6198
+ this.guard();
5754
6199
  this.lib.textBufferResetLocalSelection(this.bufferPtr);
5755
6200
  }
5756
6201
  getSelection() {
6202
+ this.guard();
5757
6203
  return this.lib.textBufferGetSelection(this.bufferPtr);
5758
6204
  }
5759
6205
  hasSelection() {
6206
+ this.guard();
5760
6207
  return this.getSelection() !== null;
5761
6208
  }
5762
6209
  insertChunkGroup(index, text, fg2, bg2, attributes) {
6210
+ this.guard();
5763
6211
  const textBytes = this.lib.encoder.encode(text);
5764
6212
  this.insertEncodedChunkGroup(index, textBytes, fg2, bg2, attributes);
5765
6213
  }
5766
6214
  insertEncodedChunkGroup(index, textBytes, fg2, bg2, attributes) {
6215
+ this.guard();
5767
6216
  this._length = this.lib.textBufferInsertChunkGroup(this.bufferPtr, index, textBytes, fg2 || null, bg2 || null, attributes ?? null);
5768
6217
  this._lineInfo = undefined;
5769
6218
  }
5770
6219
  removeChunkGroup(index) {
6220
+ this.guard();
5771
6221
  this._length = this.lib.textBufferRemoveChunkGroup(this.bufferPtr, index);
5772
6222
  this._lineInfo = undefined;
5773
6223
  }
5774
6224
  replaceChunkGroup(index, text, fg2, bg2, attributes) {
6225
+ this.guard();
5775
6226
  const textBytes = this.lib.encoder.encode(text);
5776
6227
  this.replaceEncodedChunkGroup(index, textBytes, fg2, bg2, attributes);
5777
6228
  }
5778
6229
  replaceEncodedChunkGroup(index, textBytes, fg2, bg2, attributes) {
6230
+ this.guard();
5779
6231
  this._length = this.lib.textBufferReplaceChunkGroup(this.bufferPtr, index, textBytes, fg2 || null, bg2 || null, attributes ?? null);
5780
6232
  this._lineInfo = undefined;
5781
6233
  }
5782
6234
  get chunkGroupCount() {
6235
+ this.guard();
5783
6236
  return this.lib.textBufferGetChunkGroupCount(this.bufferPtr);
5784
6237
  }
5785
6238
  destroy() {
6239
+ if (this._destroyed)
6240
+ return;
6241
+ this._destroyed = true;
5786
6242
  this.lib.destroyTextBuffer(this.bufferPtr);
5787
6243
  }
5788
6244
  }
@@ -5877,12 +6333,40 @@ function isRenderable(obj) {
5877
6333
  return !!obj?.[BrandedRenderable];
5878
6334
  }
5879
6335
 
5880
- class Renderable extends EventEmitter3 {
6336
+ class BaseRenderable extends EventEmitter3 {
5881
6337
  [BrandedRenderable] = true;
5882
6338
  static renderableNumber = 1;
5883
- static renderablesByNumber = new Map;
5884
6339
  id;
5885
6340
  num;
6341
+ _dirty = false;
6342
+ parent = null;
6343
+ _visible = true;
6344
+ constructor(options) {
6345
+ super();
6346
+ this.num = BaseRenderable.renderableNumber++;
6347
+ this.id = options.id ?? `renderable-${this.num}`;
6348
+ }
6349
+ get isDirty() {
6350
+ return this._dirty;
6351
+ }
6352
+ markClean() {
6353
+ this._dirty = false;
6354
+ }
6355
+ markDirty() {
6356
+ this._dirty = true;
6357
+ }
6358
+ destroy() {}
6359
+ destroyRecursively() {}
6360
+ get visible() {
6361
+ return this._visible;
6362
+ }
6363
+ set visible(value) {
6364
+ this._visible = value;
6365
+ }
6366
+ }
6367
+
6368
+ class Renderable extends BaseRenderable {
6369
+ static renderablesByNumber = new Map;
5886
6370
  _isDestroyed = false;
5887
6371
  _ctx;
5888
6372
  _translateX = 0;
@@ -5894,14 +6378,11 @@ class Renderable extends EventEmitter3 {
5894
6378
  _widthValue = 0;
5895
6379
  _heightValue = 0;
5896
6380
  _zIndex;
5897
- _visible;
5898
6381
  selectable = false;
5899
6382
  buffered;
5900
6383
  frameBuffer = null;
5901
- _dirty = false;
5902
- focusable = false;
6384
+ _focusable = false;
5903
6385
  _focused = false;
5904
- keyHandler = getKeyHandler();
5905
6386
  keypressHandler = null;
5906
6387
  _live = false;
5907
6388
  _liveCount = 0;
@@ -5919,12 +6400,12 @@ class Renderable extends EventEmitter3 {
5919
6400
  parent = null;
5920
6401
  childrenPrimarySortDirty = true;
5921
6402
  childrenSortedByPrimaryAxis = [];
6403
+ _newChildren = [];
6404
+ onLifecyclePass = null;
5922
6405
  renderBefore;
5923
6406
  renderAfter;
5924
6407
  constructor(ctx, options) {
5925
- super();
5926
- this.num = Renderable.renderableNumber++;
5927
- this.id = options.id ?? `renderable-${this.num}`;
6408
+ super(options);
5928
6409
  this._ctx = ctx;
5929
6410
  Renderable.renderablesByNumber.set(this.num, this);
5930
6411
  validateOptions(this.id, options);
@@ -5951,12 +6432,19 @@ class Renderable extends EventEmitter3 {
5951
6432
  this.createFrameBuffer();
5952
6433
  }
5953
6434
  }
6435
+ get focusable() {
6436
+ return this._focusable;
6437
+ }
5954
6438
  get ctx() {
5955
6439
  return this._ctx;
5956
6440
  }
5957
6441
  get visible() {
5958
6442
  return this._visible;
5959
6443
  }
6444
+ get primaryAxis() {
6445
+ const dir = this.layoutNode.yogaNode.getFlexDirection();
6446
+ return dir === 2 || dir === 3 ? "row" : "column";
6447
+ }
5960
6448
  set visible(value) {
5961
6449
  if (this._visible === value)
5962
6450
  return;
@@ -5988,8 +6476,9 @@ class Renderable extends EventEmitter3 {
5988
6476
  return false;
5989
6477
  }
5990
6478
  focus() {
5991
- if (this._focused || !this.focusable)
6479
+ if (this._focused || !this._focusable)
5992
6480
  return;
6481
+ this._ctx.focusRenderable(this);
5993
6482
  this._focused = true;
5994
6483
  this.requestRender();
5995
6484
  this.keypressHandler = (key) => {
@@ -5998,16 +6487,16 @@ class Renderable extends EventEmitter3 {
5998
6487
  this.handleKeyPress(key);
5999
6488
  }
6000
6489
  };
6001
- this.keyHandler.on("keypress", this.keypressHandler);
6490
+ this.ctx.keyInput.on("keypress", this.keypressHandler);
6002
6491
  this.emit("focused" /* FOCUSED */);
6003
6492
  }
6004
6493
  blur() {
6005
- if (!this._focused || !this.focusable)
6494
+ if (!this._focused || !this._focusable)
6006
6495
  return;
6007
6496
  this._focused = false;
6008
6497
  this.requestRender();
6009
6498
  if (this.keypressHandler) {
6010
- this.keyHandler.off("keypress", this.keypressHandler);
6499
+ this.ctx.keyInput.off("keypress", this.keypressHandler);
6011
6500
  this.keypressHandler = null;
6012
6501
  }
6013
6502
  this.emit("blurred" /* BLURRED */);
@@ -6034,9 +6523,6 @@ class Renderable extends EventEmitter3 {
6034
6523
  this._liveCount += delta;
6035
6524
  this.parent?.propagateLiveCount(delta);
6036
6525
  }
6037
- get isDirty() {
6038
- return this._dirty;
6039
- }
6040
6526
  findDescendantById(id) {
6041
6527
  for (const child of this.renderableArray) {
6042
6528
  if (child.id === id)
@@ -6047,11 +6533,8 @@ class Renderable extends EventEmitter3 {
6047
6533
  }
6048
6534
  return;
6049
6535
  }
6050
- markClean() {
6051
- this._dirty = false;
6052
- }
6053
6536
  requestRender() {
6054
- this._dirty = true;
6537
+ this.markDirty();
6055
6538
  this._ctx.requestRender();
6056
6539
  }
6057
6540
  get translateX() {
@@ -6164,80 +6647,6 @@ class Renderable extends EventEmitter3 {
6164
6647
  this.needsZIndexSort = false;
6165
6648
  }
6166
6649
  }
6167
- getChildrenInViewport(viewport, padding = 10, minTriggerSize = 16) {
6168
- if (this.renderableArray.length < minTriggerSize)
6169
- return this.renderableArray;
6170
- const viewportTop = viewport.y - padding;
6171
- const viewportBottom = viewport.y + viewport.height + padding;
6172
- const viewportLeft = viewport.x - padding;
6173
- const viewportRight = viewport.x + viewport.width + padding;
6174
- const dir = this.layoutNode.yogaNode.getFlexDirection();
6175
- const isRow = dir === 2 || dir === 3;
6176
- const children = this.getChildrenSortedByPrimaryAxis();
6177
- const totalChildren = children.length;
6178
- if (totalChildren === 0)
6179
- return [];
6180
- const vpStart = isRow ? viewportLeft : viewportTop;
6181
- const vpEnd = isRow ? viewportRight : viewportBottom;
6182
- let lo = 0;
6183
- let hi = totalChildren - 1;
6184
- let candidate = -1;
6185
- while (lo <= hi) {
6186
- const mid = lo + hi >> 1;
6187
- const c = children[mid];
6188
- const start = isRow ? c.x : c.y;
6189
- const end = isRow ? c.x + c.width : c.y + c.height;
6190
- if (end < vpStart) {
6191
- lo = mid + 1;
6192
- } else if (start > vpEnd) {
6193
- hi = mid - 1;
6194
- } else {
6195
- candidate = mid;
6196
- break;
6197
- }
6198
- }
6199
- const visibleChildren = [];
6200
- if (candidate === -1) {
6201
- return visibleChildren;
6202
- }
6203
- let left = candidate;
6204
- while (left - 1 >= 0) {
6205
- const prev = children[left - 1];
6206
- if ((isRow ? prev.x + prev.width : prev.y + prev.height) < vpStart)
6207
- break;
6208
- left--;
6209
- }
6210
- let right = candidate + 1;
6211
- while (right < totalChildren) {
6212
- const next = children[right];
6213
- if ((isRow ? next.x : next.y) > vpEnd)
6214
- break;
6215
- right++;
6216
- }
6217
- for (let i = left;i < right; i++) {
6218
- const child = children[i];
6219
- if (isRow) {
6220
- const childBottom = child.y + child.height;
6221
- if (childBottom < viewportTop)
6222
- continue;
6223
- const childTop = child.y;
6224
- if (childTop > viewportBottom)
6225
- continue;
6226
- } else {
6227
- const childRight = child.x + child.width;
6228
- if (childRight < viewportLeft)
6229
- continue;
6230
- const childLeft = child.x;
6231
- if (childLeft > viewportRight)
6232
- continue;
6233
- }
6234
- visibleChildren.push(child);
6235
- }
6236
- if (visibleChildren.length > 1) {
6237
- visibleChildren.sort((a, b) => a.zIndex > b.zIndex ? 1 : a.zIndex < b.zIndex ? -1 : 0);
6238
- }
6239
- return visibleChildren;
6240
- }
6241
6650
  getChildrenSortedByPrimaryAxis() {
6242
6651
  if (!this.childrenPrimarySortDirty && this.childrenSortedByPrimaryAxis.length === this.renderableArray.length) {
6243
6652
  return this.childrenSortedByPrimaryAxis;
@@ -6609,6 +7018,7 @@ class Renderable extends EventEmitter3 {
6609
7018
  }
6610
7019
  obj.parent = this;
6611
7020
  }
7021
+ _forceLayoutUpdateFor = null;
6612
7022
  add(obj, index) {
6613
7023
  if (!obj) {
6614
7024
  return -1;
@@ -6632,6 +7042,7 @@ class Renderable extends EventEmitter3 {
6632
7042
  let insertedIndex;
6633
7043
  if (index !== undefined) {
6634
7044
  this.renderableArray.splice(index, 0, renderable);
7045
+ this._forceLayoutUpdateFor = this.renderableArray.slice(index);
6635
7046
  insertedIndex = this.layoutNode.insertChild(childLayoutNode, index);
6636
7047
  } else {
6637
7048
  this.renderableArray.push(renderable);
@@ -6640,6 +7051,10 @@ class Renderable extends EventEmitter3 {
6640
7051
  this.needsZIndexSort = true;
6641
7052
  this.childrenPrimarySortDirty = true;
6642
7053
  this.renderableMap.set(renderable.id, renderable);
7054
+ if (typeof renderable.onLifecyclePass === "function") {
7055
+ this._ctx.registerLifecyclePass(renderable);
7056
+ }
7057
+ this._newChildren.push(renderable);
6643
7058
  if (renderable._liveCount > 0) {
6644
7059
  this.propagateLiveCount(renderable._liveCount);
6645
7060
  }
@@ -6657,6 +7072,9 @@ class Renderable extends EventEmitter3 {
6657
7072
  if (!anchor) {
6658
7073
  return this.add(renderable);
6659
7074
  }
7075
+ if (!isRenderable(anchor)) {
7076
+ throw new Error("Anchor must be a Renderable");
7077
+ }
6660
7078
  if (!this.renderableMap.has(anchor.id)) {
6661
7079
  throw new Error("Anchor does not exist");
6662
7080
  }
@@ -6684,6 +7102,7 @@ class Renderable extends EventEmitter3 {
6684
7102
  this.requestRender();
6685
7103
  obj.onRemove();
6686
7104
  obj.parent = null;
7105
+ this._ctx.unregisterLifecyclePass(obj);
6687
7106
  }
6688
7107
  this.renderableMap.delete(id);
6689
7108
  const index = this.renderableArray.findIndex((obj2) => obj2.id === id);
@@ -6700,11 +7119,44 @@ class Renderable extends EventEmitter3 {
6700
7119
  getChildrenCount() {
6701
7120
  return this.renderableArray.length;
6702
7121
  }
6703
- render(buffer, deltaTime) {
7122
+ updateLayout(deltaTime, renderList = []) {
6704
7123
  if (!this.visible)
6705
7124
  return;
6706
7125
  this.onUpdate(deltaTime);
6707
7126
  this.updateFromLayout();
7127
+ renderList.push({ action: "render", renderable: this });
7128
+ if (this._newChildren.length > 0) {
7129
+ for (const child of this._newChildren) {
7130
+ child.updateFromLayout();
7131
+ }
7132
+ this._newChildren = [];
7133
+ }
7134
+ if (this._forceLayoutUpdateFor) {
7135
+ for (const child of this._forceLayoutUpdateFor) {
7136
+ child.updateFromLayout();
7137
+ }
7138
+ this._forceLayoutUpdateFor = null;
7139
+ }
7140
+ this.ensureZIndexSorted();
7141
+ const shouldPushScissor = this._overflow !== "visible" && this.width > 0 && this.height > 0;
7142
+ if (shouldPushScissor) {
7143
+ const scissorRect = this.getScissorRect();
7144
+ renderList.push({
7145
+ action: "pushScissorRect",
7146
+ x: scissorRect.x,
7147
+ y: scissorRect.y,
7148
+ width: scissorRect.width,
7149
+ height: scissorRect.height
7150
+ });
7151
+ }
7152
+ for (const child of this._getChildren()) {
7153
+ child.updateLayout(deltaTime, renderList);
7154
+ }
7155
+ if (shouldPushScissor) {
7156
+ renderList.push({ action: "popScissorRect" });
7157
+ }
7158
+ }
7159
+ render(buffer, deltaTime) {
6708
7160
  let renderBuffer = buffer;
6709
7161
  if (this.buffered && this.frameBuffer) {
6710
7162
  renderBuffer = this.frameBuffer;
@@ -6718,18 +7170,6 @@ class Renderable extends EventEmitter3 {
6718
7170
  }
6719
7171
  this.markClean();
6720
7172
  this._ctx.addToHitGrid(this.x, this.y, this.width, this.height, this.num);
6721
- this.ensureZIndexSorted();
6722
- const shouldPushScissor = this._overflow !== "visible" && this.width > 0 && this.height > 0;
6723
- if (shouldPushScissor) {
6724
- const scissorRect = this.getScissorRect();
6725
- renderBuffer.pushScissorRect(scissorRect.x, scissorRect.y, scissorRect.width, scissorRect.height);
6726
- }
6727
- for (const child of this._getChildren()) {
6728
- child.render(renderBuffer, deltaTime);
6729
- }
6730
- if (shouldPushScissor) {
6731
- renderBuffer.popScissorRect();
6732
- }
6733
7173
  if (this.buffered && this.frameBuffer) {
6734
7174
  buffer.drawFrameBuffer(this.x, this.y, this.frameBuffer);
6735
7175
  }
@@ -6882,6 +7322,7 @@ class Renderable extends EventEmitter3 {
6882
7322
 
6883
7323
  class RootRenderable extends Renderable {
6884
7324
  yogaConfig;
7325
+ renderList = [];
6885
7326
  constructor(ctx) {
6886
7327
  super(ctx, { id: "__root__", zIndex: 0, visible: true, width: ctx.width, height: ctx.height, enableLayout: true });
6887
7328
  this.yogaConfig = src_default.Config.create();
@@ -6896,6 +7337,32 @@ class RootRenderable extends Renderable {
6896
7337
  this.layoutNode.yogaNode.setFlexDirection(FlexDirection.Column);
6897
7338
  this.calculateLayout();
6898
7339
  }
7340
+ render(buffer, deltaTime) {
7341
+ if (!this.visible)
7342
+ return;
7343
+ for (const renderable of this._ctx.getLifecyclePasses()) {
7344
+ renderable.onLifecyclePass?.call(renderable);
7345
+ }
7346
+ if (this.layoutNode.yogaNode.isDirty()) {
7347
+ this.calculateLayout();
7348
+ }
7349
+ this.renderList.length = 0;
7350
+ this.updateLayout(deltaTime, this.renderList);
7351
+ for (let i = 1;i < this.renderList.length; i++) {
7352
+ const command = this.renderList[i];
7353
+ switch (command.action) {
7354
+ case "render":
7355
+ command.renderable.render(buffer, deltaTime);
7356
+ break;
7357
+ case "pushScissorRect":
7358
+ buffer.pushScissorRect(command.x, command.y, command.width, command.height);
7359
+ break;
7360
+ case "popScissorRect":
7361
+ buffer.popScissorRect();
7362
+ break;
7363
+ }
7364
+ }
7365
+ }
6899
7366
  propagateLiveCount(delta) {
6900
7367
  const oldCount = this._liveCount;
6901
7368
  this._liveCount += delta;
@@ -6914,15 +7381,7 @@ class RootRenderable extends Renderable {
6914
7381
  this.height = height;
6915
7382
  this.emit("resized" /* RESIZED */, { width, height });
6916
7383
  }
6917
- onUpdate() {
6918
- if (this.layoutNode.yogaNode.isDirty()) {
6919
- this.calculateLayout();
6920
- }
6921
- }
6922
7384
  destroySelf() {
6923
- if (this.layoutNode) {
6924
- this.layoutNode.destroy();
6925
- }
6926
7385
  try {
6927
7386
  this.yogaConfig.free();
6928
7387
  } catch (error) {}
@@ -7783,6 +8242,83 @@ var ANSI = {
7783
8242
 
7784
8243
  // src/renderer.ts
7785
8244
  import { EventEmitter as EventEmitter6 } from "events";
8245
+
8246
+ // src/lib/objects-in-viewport.ts
8247
+ function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
8248
+ if (objects.length < minTriggerSize)
8249
+ return objects;
8250
+ const viewportTop = viewport.y - padding;
8251
+ const viewportBottom = viewport.y + viewport.height + padding;
8252
+ const viewportLeft = viewport.x - padding;
8253
+ const viewportRight = viewport.x + viewport.width + padding;
8254
+ const isRow = direction === "row";
8255
+ const children = objects;
8256
+ const totalChildren = children.length;
8257
+ if (totalChildren === 0)
8258
+ return [];
8259
+ const vpStart = isRow ? viewportLeft : viewportTop;
8260
+ const vpEnd = isRow ? viewportRight : viewportBottom;
8261
+ let lo = 0;
8262
+ let hi = totalChildren - 1;
8263
+ let candidate = -1;
8264
+ while (lo <= hi) {
8265
+ const mid = lo + hi >> 1;
8266
+ const c = children[mid];
8267
+ const start = isRow ? c.x : c.y;
8268
+ const end = isRow ? c.x + c.width : c.y + c.height;
8269
+ if (end < vpStart) {
8270
+ lo = mid + 1;
8271
+ } else if (start > vpEnd) {
8272
+ hi = mid - 1;
8273
+ } else {
8274
+ candidate = mid;
8275
+ break;
8276
+ }
8277
+ }
8278
+ const visibleChildren = [];
8279
+ if (candidate === -1) {
8280
+ return visibleChildren;
8281
+ }
8282
+ let left = candidate;
8283
+ while (left - 1 >= 0) {
8284
+ const prev = children[left - 1];
8285
+ if ((isRow ? prev.x + prev.width : prev.y + prev.height) < vpStart)
8286
+ break;
8287
+ left--;
8288
+ }
8289
+ let right = candidate + 1;
8290
+ while (right < totalChildren) {
8291
+ const next = children[right];
8292
+ if ((isRow ? next.x : next.y) > vpEnd)
8293
+ break;
8294
+ right++;
8295
+ }
8296
+ for (let i = left;i < right; i++) {
8297
+ const child = children[i];
8298
+ if (isRow) {
8299
+ const childBottom = child.y + child.height;
8300
+ if (childBottom < viewportTop)
8301
+ continue;
8302
+ const childTop = child.y;
8303
+ if (childTop > viewportBottom)
8304
+ continue;
8305
+ } else {
8306
+ const childRight = child.x + child.width;
8307
+ if (childRight < viewportLeft)
8308
+ continue;
8309
+ const childLeft = child.x;
8310
+ if (childLeft > viewportRight)
8311
+ continue;
8312
+ }
8313
+ visibleChildren.push(child);
8314
+ }
8315
+ if (visibleChildren.length > 1) {
8316
+ visibleChildren.sort((a, b) => a.zIndex > b.zIndex ? 1 : a.zIndex < b.zIndex ? -1 : 0);
8317
+ }
8318
+ return visibleChildren;
8319
+ }
8320
+
8321
+ // src/renderer.ts
7786
8322
  class MouseEvent {
7787
8323
  type;
7788
8324
  button;
@@ -7917,6 +8453,7 @@ class CliRenderer extends EventEmitter6 {
7917
8453
  };
7918
8454
  _console;
7919
8455
  _resolution = null;
8456
+ _keyHandler;
7920
8457
  animationRequest = new Map;
7921
8458
  resizeTimeoutId = null;
7922
8459
  resizeDebounceDelay = 100;
@@ -7941,9 +8478,57 @@ class CliRenderer extends EventEmitter6 {
7941
8478
  };
7942
8479
  _useConsole = true;
7943
8480
  mouseParser = new MouseParser;
7944
- sigwinchHandler = null;
8481
+ sigwinchHandler = (() => {
8482
+ const width = this.stdout.columns || 80;
8483
+ const height = this.stdout.rows || 24;
8484
+ this.handleResize(width, height);
8485
+ }).bind(this);
7945
8486
  _capabilities = null;
7946
8487
  _latestPointer = { x: 0, y: 0 };
8488
+ _currentFocusedRenderable = null;
8489
+ lifecyclePasses = new Set;
8490
+ handleError = ((error) => {
8491
+ this.stop();
8492
+ this.destroy();
8493
+ new Promise((resolve) => {
8494
+ setTimeout(() => {
8495
+ resolve(true);
8496
+ }, 100);
8497
+ }).then(() => {
8498
+ this.realStdoutWrite.call(this.stdout, `
8499
+ `.repeat(this._terminalHeight));
8500
+ this.realStdoutWrite.call(this.stdout, `
8501
+ === FATAL ERROR OCCURRED ===
8502
+ `);
8503
+ this.realStdoutWrite.call(this.stdout, `Console cache:
8504
+ `);
8505
+ this.realStdoutWrite.call(this.stdout, this.console.getCachedLogs());
8506
+ this.realStdoutWrite.call(this.stdout, `
8507
+ Captured output:
8508
+ `);
8509
+ const capturedOutput = capture.claimOutput();
8510
+ if (capturedOutput) {
8511
+ this.realStdoutWrite.call(this.stdout, capturedOutput + `
8512
+ `);
8513
+ }
8514
+ this.realStdoutWrite.call(this.stdout, `
8515
+ Error details:
8516
+ `);
8517
+ this.realStdoutWrite.call(this.stdout, error.message || "unknown error");
8518
+ this.realStdoutWrite.call(this.stdout, `
8519
+ `);
8520
+ this.realStdoutWrite.call(this.stdout, error.stack || error.toString());
8521
+ this.realStdoutWrite.call(this.stdout, `
8522
+ `);
8523
+ process.exit(1);
8524
+ });
8525
+ }).bind(this);
8526
+ exitHandler = (() => {
8527
+ this.destroy();
8528
+ }).bind(this);
8529
+ warningHandler = ((warning) => {
8530
+ console.warn(JSON.stringify(warning.message, null, 2));
8531
+ }).bind(this);
7947
8532
  constructor(lib, rendererPtr, stdin, stdout, width, height, config = {}) {
7948
8533
  super();
7949
8534
  this.stdin = stdin;
@@ -7966,7 +8551,7 @@ class CliRenderer extends EventEmitter6 {
7966
8551
  this.exitOnCtrlC = config.exitOnCtrlC === undefined ? true : config.exitOnCtrlC;
7967
8552
  this.resizeDebounceDelay = config.debounceDelay || 100;
7968
8553
  this.targetFps = config.targetFps || 30;
7969
- this.memorySnapshotInterval = config.memorySnapshotInterval || 5000;
8554
+ this.memorySnapshotInterval = config.memorySnapshotInterval ?? 0;
7970
8555
  this.gatherStats = config.gatherStats || false;
7971
8556
  this.maxStatSamples = config.maxStatSamples || 300;
7972
8557
  this.enableMouseMovement = config.enableMouseMovement || true;
@@ -7981,61 +8566,18 @@ class CliRenderer extends EventEmitter6 {
7981
8566
  this.startMemorySnapshotTimer();
7982
8567
  }
7983
8568
  this.stdout.write = this.interceptStdoutWrite.bind(this);
7984
- this.sigwinchHandler = () => {
7985
- const width2 = this.stdout.columns || 80;
7986
- const height2 = this.stdout.rows || 24;
7987
- this.handleResize(width2, height2);
7988
- };
7989
8569
  process.on("SIGWINCH", this.sigwinchHandler);
7990
- const handleError = (error) => {
7991
- this.stop();
7992
- this.destroy();
7993
- new Promise((resolve) => {
7994
- setTimeout(() => {
7995
- resolve(true);
7996
- }, 100);
7997
- }).then(() => {
7998
- this.realStdoutWrite.call(this.stdout, `
7999
- `.repeat(this._terminalHeight));
8000
- this.realStdoutWrite.call(this.stdout, `
8001
- === FATAL ERROR OCCURRED ===
8002
- `);
8003
- this.realStdoutWrite.call(this.stdout, `Console cache:
8004
- `);
8005
- this.realStdoutWrite.call(this.stdout, this.console.getCachedLogs());
8006
- this.realStdoutWrite.call(this.stdout, `
8007
- Captured output:
8008
- `);
8009
- const capturedOutput = capture.claimOutput();
8010
- if (capturedOutput) {
8011
- this.realStdoutWrite.call(this.stdout, capturedOutput + `
8012
- `);
8013
- }
8014
- this.realStdoutWrite.call(this.stdout, `
8015
- Error details:
8016
- `);
8017
- this.realStdoutWrite.call(this.stdout, error.message || "unknown error");
8018
- this.realStdoutWrite.call(this.stdout, `
8019
- `);
8020
- this.realStdoutWrite.call(this.stdout, error.stack || error.toString());
8021
- this.realStdoutWrite.call(this.stdout, `
8022
- `);
8023
- process.exit(1);
8024
- });
8025
- };
8026
- process.on("warning", (warning) => {
8027
- console.warn(JSON.stringify(warning.message, null, 2));
8028
- });
8029
- process.on("uncaughtException", handleError);
8030
- process.on("unhandledRejection", handleError);
8031
- process.on("exit", () => {
8032
- this.destroy();
8033
- });
8570
+ process.on("warning", this.warningHandler);
8571
+ process.on("uncaughtException", this.handleError);
8572
+ process.on("unhandledRejection", this.handleError);
8573
+ process.on("exit", this.exitHandler);
8034
8574
  this._console = new TerminalConsole(this, config.consoleOptions);
8035
8575
  this.useConsole = config.useConsole ?? true;
8576
+ this._keyHandler = new KeyHandler(this.stdin, config.useKittyKeyboard ?? false);
8036
8577
  global.requestAnimationFrame = (callback) => {
8037
8578
  const id = CliRenderer.animationFrameId++;
8038
8579
  this.animationRequest.set(id, callback);
8580
+ this.requestLive();
8039
8581
  return id;
8040
8582
  };
8041
8583
  global.cancelAnimationFrame = (handle) => {
@@ -8053,6 +8595,27 @@ Error details:
8053
8595
  }
8054
8596
  };
8055
8597
  }
8598
+ this.setupInput();
8599
+ }
8600
+ registerLifecyclePass(renderable) {
8601
+ this.lifecyclePasses.add(renderable);
8602
+ }
8603
+ unregisterLifecyclePass(renderable) {
8604
+ this.lifecyclePasses.delete(renderable);
8605
+ }
8606
+ getLifecyclePasses() {
8607
+ return this.lifecyclePasses;
8608
+ }
8609
+ get currentFocusedRenderable() {
8610
+ return this._currentFocusedRenderable;
8611
+ }
8612
+ focusRenderable(renderable) {
8613
+ if (this._currentFocusedRenderable === renderable)
8614
+ return;
8615
+ if (this._currentFocusedRenderable) {
8616
+ this._currentFocusedRenderable.blur();
8617
+ }
8618
+ this._currentFocusedRenderable = renderable;
8056
8619
  }
8057
8620
  addToHitGrid(x, y, width, height, id) {
8058
8621
  if (id !== this.capturedRenderable?.num) {
@@ -8095,6 +8658,9 @@ Error details:
8095
8658
  get console() {
8096
8659
  return this._console;
8097
8660
  }
8661
+ get keyInput() {
8662
+ return this._keyHandler;
8663
+ }
8098
8664
  get terminalWidth() {
8099
8665
  return this._terminalWidth;
8100
8666
  }
@@ -8194,10 +8760,13 @@ Error details:
8194
8760
  const flush = ANSI.moveCursorAndClear(rendererStartLine, 1);
8195
8761
  const outputLine = this._terminalHeight - this._splitHeight;
8196
8762
  const move = ANSI.moveCursor(outputLine, 1);
8197
- const backgroundColor = this.backgroundColor.toInts();
8198
- const newlines = " ".repeat(this.width) + `
8763
+ let clear = "";
8764
+ if (space > 0) {
8765
+ const backgroundColor = this.backgroundColor.toInts();
8766
+ const newlines = " ".repeat(this.width) + `
8199
8767
  `.repeat(space);
8200
- const clear = ANSI.setRgbBackground(backgroundColor[0], backgroundColor[1], backgroundColor[2]) + newlines + ANSI.resetBackground;
8768
+ clear = ANSI.setRgbBackground(backgroundColor[0], backgroundColor[1], backgroundColor[2]) + newlines + ANSI.resetBackground;
8769
+ }
8201
8770
  this.writeOut(flush + move + output + clear);
8202
8771
  return true;
8203
8772
  }
@@ -8246,32 +8815,35 @@ Error details:
8246
8815
  if (this._useMouse) {
8247
8816
  this.enableMouse();
8248
8817
  }
8249
- this.stdin.on("data", (data) => {
8250
- const str = data.toString();
8251
- if (this.waitingForPixelResolution && /\x1b\[4;\d+;\d+t/.test(str)) {
8252
- const match = str.match(/\x1b\[4;(\d+);(\d+)t/);
8253
- if (match) {
8254
- const resolution = {
8255
- width: parseInt(match[2]),
8256
- height: parseInt(match[1])
8257
- };
8258
- this._resolution = resolution;
8259
- this.waitingForPixelResolution = false;
8260
- return;
8261
- }
8262
- }
8263
- if (this.exitOnCtrlC && str === "\x03") {
8264
- process.nextTick(() => {
8265
- process.exit();
8266
- });
8267
- return;
8268
- }
8269
- if (this._useMouse && this.handleMouseData(data)) {
8818
+ this.queryPixelResolution();
8819
+ }
8820
+ stdinListener = ((data) => {
8821
+ const str = data.toString();
8822
+ if (this.waitingForPixelResolution && /\x1b\[4;\d+;\d+t/.test(str)) {
8823
+ const match = str.match(/\x1b\[4;(\d+);(\d+)t/);
8824
+ if (match) {
8825
+ const resolution = {
8826
+ width: parseInt(match[2]),
8827
+ height: parseInt(match[1])
8828
+ };
8829
+ this._resolution = resolution;
8830
+ this.waitingForPixelResolution = false;
8270
8831
  return;
8271
8832
  }
8272
- this.emit("key", data);
8273
- });
8274
- this.queryPixelResolution();
8833
+ }
8834
+ if (this.exitOnCtrlC && str === "\x03") {
8835
+ process.nextTick(() => {
8836
+ process.exit();
8837
+ });
8838
+ return;
8839
+ }
8840
+ if (this._useMouse && this.handleMouseData(data)) {
8841
+ return;
8842
+ }
8843
+ this.emit("key", data);
8844
+ }).bind(this);
8845
+ setupInput() {
8846
+ this.stdin.on("data", this.stdinListener);
8275
8847
  }
8276
8848
  handleMouseData(data) {
8277
8849
  const mouseEvent = this.mouseParser.parseMouseEvent(data);
@@ -8298,7 +8870,7 @@ Error details:
8298
8870
  this.lastOverRenderableNum = maybeRenderableId;
8299
8871
  const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId);
8300
8872
  if (mouseEvent.type === "down" && mouseEvent.button === 0 /* LEFT */ && !this.currentSelection?.isSelecting && !mouseEvent.modifiers.ctrl) {
8301
- if (maybeRenderable && maybeRenderable.selectable && maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)) {
8873
+ if (maybeRenderable && maybeRenderable.selectable && !maybeRenderable.isDestroyed && maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)) {
8302
8874
  this.startSelection(maybeRenderable, mouseEvent.x, mouseEvent.y);
8303
8875
  const event2 = new MouseEvent(maybeRenderable, mouseEvent);
8304
8876
  maybeRenderable.processMouseEvent(event2);
@@ -8386,6 +8958,8 @@ Error details:
8386
8958
  return false;
8387
8959
  }
8388
8960
  takeMemorySnapshot() {
8961
+ if (this.isDestroyed)
8962
+ return;
8389
8963
  const memoryUsage = process.memoryUsage();
8390
8964
  this.lastMemorySnapshot = {
8391
8965
  heapUsed: memoryUsage.heapUsed,
@@ -8598,19 +9172,28 @@ Error details:
8598
9172
  }
8599
9173
  }
8600
9174
  destroy() {
8601
- this.stdin.setRawMode(false);
9175
+ this.stdin.removeListener("data", this.stdinListener);
9176
+ process.removeListener("SIGWINCH", this.sigwinchHandler);
9177
+ process.removeListener("uncaughtException", this.handleError);
9178
+ process.removeListener("unhandledRejection", this.handleError);
9179
+ process.removeListener("exit", this.exitHandler);
9180
+ process.removeListener("warning", this.warningHandler);
9181
+ capture.removeListener("write", this.captureCallback);
9182
+ if (this.memorySnapshotTimer) {
9183
+ clearInterval(this.memorySnapshotTimer);
9184
+ }
9185
+ if (this.stdin.setRawMode) {
9186
+ this.stdin.setRawMode(false);
9187
+ }
8602
9188
  if (this.isDestroyed)
8603
9189
  return;
8604
9190
  this.isDestroyed = true;
8605
9191
  this.waitingForPixelResolution = false;
8606
9192
  this.capturedRenderable = undefined;
8607
- if (this.sigwinchHandler) {
8608
- process.removeListener("SIGWINCH", this.sigwinchHandler);
8609
- this.sigwinchHandler = null;
8610
- }
9193
+ this._keyHandler.destroy();
8611
9194
  this._console.deactivate();
8612
9195
  this.disableStdoutInterception();
8613
- this.lib.destroyRenderer(this.rendererPtr, this._useAlternateScreen, this._splitHeight);
9196
+ this.lib.destroyRenderer(this.rendererPtr);
8614
9197
  }
8615
9198
  startRenderLoop() {
8616
9199
  if (!this._isRunning)
@@ -8646,7 +9229,10 @@ Error details:
8646
9229
  const frameRequests = Array.from(this.animationRequest.values());
8647
9230
  this.animationRequest.clear();
8648
9231
  const animationRequestStart = performance.now();
8649
- frameRequests.forEach((callback) => callback(deltaTime));
9232
+ frameRequests.forEach((callback) => {
9233
+ callback(deltaTime);
9234
+ this.dropLive();
9235
+ });
8650
9236
  const animationRequestEnd = performance.now();
8651
9237
  const animationRequestTime = animationRequestEnd - animationRequestStart;
8652
9238
  const start = performance.now();
@@ -8740,7 +9326,7 @@ Error details:
8740
9326
  clearSelection() {
8741
9327
  if (this.currentSelection) {
8742
9328
  for (const renderable of this.currentSelection.touchedRenderables) {
8743
- if (renderable.selectable) {
9329
+ if (renderable.selectable && !renderable.isDestroyed) {
8744
9330
  renderable.onSelectionChanged(null);
8745
9331
  }
8746
9332
  }
@@ -8815,7 +9401,7 @@ Error details:
8815
9401
  }
8816
9402
  }
8817
9403
  walkSelectableRenderables(container, selectionBounds, selectedRenderables, touchedRenderables) {
8818
- const children = container.getChildrenInViewport(selectionBounds, 0);
9404
+ const children = getObjectsInViewport(selectionBounds, container.getChildrenSortedByPrimaryAxis(), container.primaryAxis, 0);
8819
9405
  for (const child of children) {
8820
9406
  if (child.selectable) {
8821
9407
  const hasSelection = child.onSelectionChanged(this.currentSelection);
@@ -8831,7 +9417,7 @@ Error details:
8831
9417
  }
8832
9418
  }
8833
9419
 
8834
- export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, TrackedNode, createTrackedNode, nonAlphanumericKeys, parseKeypress, KeyHandler, getKeyHandler, RGBA, hexToRgb, rgbToHex, hsvToRgb, parseColor, fonts, measureText, getCharacterPositions, coordinateToCharacterIndex, renderFontToFrameBuffer, TextAttributes, DebugOverlayCorner, createTextAttributes, 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, LayoutEvents, RenderableEvents, isValidPercentage, isMarginType, isPaddingType, isPositionType, isPositionTypeType, isOverflowType, isDimensionType, isFlexBasisType, isSizeType, isRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
9420
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, MeasureMode, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, TrackedNode, createTrackedNode, 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, LayoutEvents, RenderableEvents, isValidPercentage, isMarginType, isPaddingType, isPositionType, isPositionTypeType, isOverflowType, isDimensionType, isFlexBasisType, isSizeType, isRenderable, BaseRenderable, Renderable, RootRenderable, capture, ConsolePosition, TerminalConsole, getObjectsInViewport, MouseEvent, MouseButton, createCliRenderer, CliRenderEvents, CliRenderer };
8835
9421
 
8836
- //# debugId=071E012DDCE3FA6064756E2164756E21
8837
- //# sourceMappingURL=index-d6kwx5pm.js.map
9422
+ //# debugId=ACCACBFBC5B1AC8B64756E2164756E21
9423
+ //# sourceMappingURL=index-6esrcarp.js.map