@opentui/core 0.1.25 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/3d.js +1 -1
  2. package/README.md +5 -1
  3. package/Renderable.d.ts +8 -7
  4. package/animation/Timeline.d.ts +2 -1
  5. package/assets/javascript/highlights.scm +205 -0
  6. package/assets/javascript/tree-sitter-javascript.wasm +0 -0
  7. package/assets/typescript/highlights.scm +604 -0
  8. package/assets/typescript/tree-sitter-typescript.wasm +0 -0
  9. package/{index-6kvgbzah.js → index-pxa2sv92.js} +1426 -117
  10. package/index-pxa2sv92.js.map +52 -0
  11. package/index.js +432 -248
  12. package/index.js.map +13 -11
  13. package/lib/KeyHandler.d.ts +51 -12
  14. package/lib/data-paths.d.ts +26 -0
  15. package/lib/debounce.d.ts +42 -0
  16. package/lib/env.d.ts +2 -1
  17. package/lib/hast-styled-text.d.ts +3 -23
  18. package/lib/index.d.ts +5 -0
  19. package/lib/parse.keypress.d.ts +2 -2
  20. package/lib/queue.d.ts +15 -0
  21. package/lib/scroll-acceleration.d.ts +43 -0
  22. package/lib/singleton.d.ts +2 -0
  23. package/lib/styled-text.d.ts +0 -15
  24. package/lib/syntax-style.d.ts +36 -0
  25. package/lib/tree-sitter/assets/update.d.ts +11 -0
  26. package/lib/tree-sitter/client.d.ts +46 -0
  27. package/lib/tree-sitter/default-parsers.d.ts +2 -0
  28. package/lib/tree-sitter/download-utils.d.ts +21 -0
  29. package/lib/tree-sitter/index.d.ts +10 -0
  30. package/lib/tree-sitter/parser.worker.d.ts +1 -0
  31. package/lib/tree-sitter/resolve-ft.d.ts +2 -0
  32. package/lib/tree-sitter/types.d.ts +64 -0
  33. package/lib/tree-sitter-styled-text.d.ts +7 -0
  34. package/lib/validate-dir-name.d.ts +1 -0
  35. package/package.json +21 -8
  36. package/parser.worker.js +640 -0
  37. package/parser.worker.js.map +11 -0
  38. package/renderables/Code.d.ts +31 -0
  39. package/renderables/Input.d.ts +2 -2
  40. package/renderables/ScrollBar.d.ts +2 -2
  41. package/renderables/ScrollBox.d.ts +7 -3
  42. package/renderables/Select.d.ts +2 -2
  43. package/renderables/TabSelect.d.ts +2 -2
  44. package/renderables/Text.d.ts +10 -67
  45. package/renderables/TextBufferRenderable.d.ts +81 -0
  46. package/renderables/TextNode.d.ts +1 -0
  47. package/renderables/index.d.ts +2 -0
  48. package/renderer.d.ts +4 -2
  49. package/testing/spy.d.ts +7 -0
  50. package/testing.d.ts +1 -0
  51. package/testing.js +17 -2
  52. package/testing.js.map +5 -4
  53. package/types.d.ts +2 -1
  54. package/index-6kvgbzah.js.map +0 -39
@@ -1763,7 +1763,7 @@ var BorderCharArrays = {
1763
1763
  };
1764
1764
 
1765
1765
  // src/lib/parse.keypress.ts
1766
- import { Buffer } from "buffer";
1766
+ import { Buffer as Buffer2 } from "buffer";
1767
1767
 
1768
1768
  // src/lib/parse.keypress-kitty.ts
1769
1769
  var kittyKeyMap = {
@@ -2080,7 +2080,7 @@ var isCtrlKey = (code) => {
2080
2080
  };
2081
2081
  var parseKeypress = (s = "", options = {}) => {
2082
2082
  let parts;
2083
- if (Buffer.isBuffer(s)) {
2083
+ if (Buffer2.isBuffer(s)) {
2084
2084
  if (s[0] > 127 && s[1] === undefined) {
2085
2085
  s[0] -= 128;
2086
2086
  s = "\x1B" + String(s);
@@ -2143,6 +2143,10 @@ var parseKeypress = (s = "", options = {}) => {
2143
2143
  key.meta = true;
2144
2144
  key.shift = /^[A-Z]$/.test(parts[1]);
2145
2145
  key.name = parts[1];
2146
+ } else if (s.length === 2 && s[0] === "\x1B" && s[1] <= "\x1A") {
2147
+ key.meta = true;
2148
+ key.ctrl = true;
2149
+ key.name = String.fromCharCode(s.charCodeAt(1) + 97 - 1);
2146
2150
  } else if (parts = fnKeyRe.exec(s)) {
2147
2151
  const segs = [...s];
2148
2152
  if (segs[0] === "\x1B" && segs[1] === "\x1B") {
@@ -2191,6 +2195,62 @@ var ANSI = {
2191
2195
  };
2192
2196
 
2193
2197
  // src/lib/KeyHandler.ts
2198
+ class KeyEvent {
2199
+ name;
2200
+ ctrl;
2201
+ meta;
2202
+ shift;
2203
+ option;
2204
+ sequence;
2205
+ number;
2206
+ raw;
2207
+ eventType;
2208
+ code;
2209
+ super;
2210
+ hyper;
2211
+ capsLock;
2212
+ numLock;
2213
+ baseCode;
2214
+ _defaultPrevented = false;
2215
+ constructor(key) {
2216
+ this.name = key.name;
2217
+ this.ctrl = key.ctrl;
2218
+ this.meta = key.meta;
2219
+ this.shift = key.shift;
2220
+ this.option = key.option;
2221
+ this.sequence = key.sequence;
2222
+ this.number = key.number;
2223
+ this.raw = key.raw;
2224
+ this.eventType = key.eventType;
2225
+ this.code = key.code;
2226
+ this.super = key.super;
2227
+ this.hyper = key.hyper;
2228
+ this.capsLock = key.capsLock;
2229
+ this.numLock = key.numLock;
2230
+ this.baseCode = key.baseCode;
2231
+ }
2232
+ get defaultPrevented() {
2233
+ return this._defaultPrevented;
2234
+ }
2235
+ preventDefault() {
2236
+ this._defaultPrevented = true;
2237
+ }
2238
+ }
2239
+
2240
+ class PasteEvent {
2241
+ text;
2242
+ _defaultPrevented = false;
2243
+ constructor(text) {
2244
+ this.text = text;
2245
+ }
2246
+ get defaultPrevented() {
2247
+ return this._defaultPrevented;
2248
+ }
2249
+ preventDefault() {
2250
+ this._defaultPrevented = true;
2251
+ }
2252
+ }
2253
+
2194
2254
  class KeyHandler extends EventEmitter {
2195
2255
  stdin;
2196
2256
  useKittyKeyboard;
@@ -2210,7 +2270,7 @@ class KeyHandler extends EventEmitter {
2210
2270
  this.pasteBuffer.push(Bun.stripANSI(data));
2211
2271
  if (data.endsWith(ANSI.bracketedPasteEnd)) {
2212
2272
  this.pasteMode = false;
2213
- this.emit("paste", this.pasteBuffer.join(""));
2273
+ this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
2214
2274
  this.pasteBuffer = [];
2215
2275
  }
2216
2276
  return;
@@ -2218,16 +2278,16 @@ class KeyHandler extends EventEmitter {
2218
2278
  const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2219
2279
  switch (parsedKey.eventType) {
2220
2280
  case "press":
2221
- this.emit("keypress", parsedKey);
2281
+ this.emit("keypress", new KeyEvent(parsedKey));
2222
2282
  break;
2223
2283
  case "repeat":
2224
- this.emit("keyrepeat", parsedKey);
2284
+ this.emit("keyrepeat", new KeyEvent(parsedKey));
2225
2285
  break;
2226
2286
  case "release":
2227
- this.emit("keyrelease", parsedKey);
2287
+ this.emit("keyrelease", new KeyEvent(parsedKey));
2228
2288
  break;
2229
2289
  default:
2230
- this.emit("keypress", parsedKey);
2290
+ this.emit("keypress", new KeyEvent(parsedKey));
2231
2291
  break;
2232
2292
  }
2233
2293
  };
@@ -2238,6 +2298,45 @@ class KeyHandler extends EventEmitter {
2238
2298
  }
2239
2299
  }
2240
2300
 
2301
+ class InternalKeyHandler extends KeyHandler {
2302
+ renderableHandlers = new Map;
2303
+ constructor(stdin, useKittyKeyboard = false) {
2304
+ super(stdin, useKittyKeyboard);
2305
+ }
2306
+ emit(event, ...args) {
2307
+ return this.emitWithPriority(event, ...args);
2308
+ }
2309
+ emitWithPriority(event, ...args) {
2310
+ const hasGlobalListeners = super.emit(event, ...args);
2311
+ const renderableSet = this.renderableHandlers.get(event);
2312
+ let hasRenderableListeners = false;
2313
+ if (renderableSet && renderableSet.size > 0) {
2314
+ hasRenderableListeners = true;
2315
+ if (event === "keypress" || event === "keyrepeat" || event === "keyrelease" || event === "paste") {
2316
+ const keyEvent = args[0];
2317
+ if (keyEvent.defaultPrevented)
2318
+ return hasGlobalListeners || hasRenderableListeners;
2319
+ }
2320
+ for (const handler of renderableSet) {
2321
+ handler(...args);
2322
+ }
2323
+ }
2324
+ return hasGlobalListeners || hasRenderableListeners;
2325
+ }
2326
+ onInternal(event, handler) {
2327
+ if (!this.renderableHandlers.has(event)) {
2328
+ this.renderableHandlers.set(event, new Set);
2329
+ }
2330
+ this.renderableHandlers.get(event).add(handler);
2331
+ }
2332
+ offInternal(event, handler) {
2333
+ const handlers = this.renderableHandlers.get(event);
2334
+ if (handlers) {
2335
+ handlers.delete(handler);
2336
+ }
2337
+ }
2338
+ }
2339
+
2241
2340
  // src/lib/RGBA.ts
2242
2341
  class RGBA {
2243
2342
  buffer;
@@ -4089,60 +4188,9 @@ function isStyledText(obj) {
4089
4188
  class StyledText {
4090
4189
  [BrandedStyledText] = true;
4091
4190
  chunks;
4092
- textRenderable;
4093
4191
  constructor(chunks) {
4094
4192
  this.chunks = chunks;
4095
4193
  }
4096
- mount(textRenderable) {
4097
- this.textRenderable = textRenderable;
4098
- }
4099
- insert(chunk, index) {
4100
- const originalLength = this.chunks.length;
4101
- if (this.textRenderable) {
4102
- this.textRenderable.insertChunk(chunk, index ?? originalLength);
4103
- let newChunks;
4104
- if (index === undefined || index === originalLength) {
4105
- newChunks = [...this.chunks, chunk];
4106
- } else {
4107
- newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index)];
4108
- }
4109
- this.chunks = newChunks;
4110
- }
4111
- return this;
4112
- }
4113
- remove(chunk) {
4114
- if (this.textRenderable) {
4115
- this.textRenderable.removeChunk(chunk);
4116
- const originalLength = this.chunks.length;
4117
- const index = this.chunks.indexOf(chunk);
4118
- if (index === -1)
4119
- return this;
4120
- let newChunks;
4121
- if (index === originalLength - 1) {
4122
- newChunks = this.chunks.slice(0, -1);
4123
- } else {
4124
- newChunks = [...this.chunks.slice(0, index), ...this.chunks.slice(index + 1)];
4125
- }
4126
- this.chunks = newChunks;
4127
- }
4128
- return this;
4129
- }
4130
- replace(chunk, oldChunk) {
4131
- if (this.textRenderable) {
4132
- this.textRenderable.replaceChunk(chunk, oldChunk);
4133
- const index = this.chunks.indexOf(oldChunk);
4134
- if (index === -1)
4135
- return this;
4136
- let newChunks;
4137
- if (index === this.chunks.length - 1) {
4138
- newChunks = [...this.chunks.slice(0, -1), chunk];
4139
- } else {
4140
- newChunks = [...this.chunks.slice(0, index), chunk, ...this.chunks.slice(index + 1)];
4141
- }
4142
- this.chunks = newChunks;
4143
- }
4144
- return this;
4145
- }
4146
4194
  }
4147
4195
  function stringToStyledText(content) {
4148
4196
  const chunk = {
@@ -4238,7 +4286,36 @@ function t(strings, ...values) {
4238
4286
  return new StyledText(chunks);
4239
4287
  }
4240
4288
 
4241
- // src/lib/hast-styled-text.ts
4289
+ // src/lib/syntax-style.ts
4290
+ function convertThemeToStyles(theme) {
4291
+ const flatStyles = {};
4292
+ for (const tokenStyle of theme) {
4293
+ const styleDefinition = {};
4294
+ if (tokenStyle.style.foreground) {
4295
+ styleDefinition.fg = parseColor(tokenStyle.style.foreground);
4296
+ }
4297
+ if (tokenStyle.style.background) {
4298
+ styleDefinition.bg = parseColor(tokenStyle.style.background);
4299
+ }
4300
+ if (tokenStyle.style.bold !== undefined) {
4301
+ styleDefinition.bold = tokenStyle.style.bold;
4302
+ }
4303
+ if (tokenStyle.style.italic !== undefined) {
4304
+ styleDefinition.italic = tokenStyle.style.italic;
4305
+ }
4306
+ if (tokenStyle.style.underline !== undefined) {
4307
+ styleDefinition.underline = tokenStyle.style.underline;
4308
+ }
4309
+ if (tokenStyle.style.dim !== undefined) {
4310
+ styleDefinition.dim = tokenStyle.style.dim;
4311
+ }
4312
+ for (const scope of tokenStyle.scope) {
4313
+ flatStyles[scope] = styleDefinition;
4314
+ }
4315
+ }
4316
+ return flatStyles;
4317
+ }
4318
+
4242
4319
  class SyntaxStyle {
4243
4320
  styles;
4244
4321
  mergedStyleCache;
@@ -4246,6 +4323,10 @@ class SyntaxStyle {
4246
4323
  this.styles = styles;
4247
4324
  this.mergedStyleCache = new Map;
4248
4325
  }
4326
+ static fromTheme(theme) {
4327
+ const flatStyles = convertThemeToStyles(theme);
4328
+ return new SyntaxStyle(flatStyles);
4329
+ }
4249
4330
  mergeStyles(...styleNames) {
4250
4331
  const cacheKey = styleNames.join(":");
4251
4332
  const cached = this.mergedStyleCache.get(cacheKey);
@@ -4253,7 +4334,7 @@ class SyntaxStyle {
4253
4334
  return cached;
4254
4335
  const styleDefinition = {};
4255
4336
  for (const name of styleNames) {
4256
- const style = this.styles[name];
4337
+ const style = this.getStyle(name);
4257
4338
  if (!style)
4258
4339
  continue;
4259
4340
  if (style.fg)
@@ -4283,6 +4364,18 @@ class SyntaxStyle {
4283
4364
  this.mergedStyleCache.set(cacheKey, merged);
4284
4365
  return merged;
4285
4366
  }
4367
+ getStyle(name) {
4368
+ if (Object.prototype.hasOwnProperty.call(this.styles, name)) {
4369
+ return this.styles[name];
4370
+ }
4371
+ if (name.includes(".")) {
4372
+ const baseName = name.split(".")[0];
4373
+ if (Object.prototype.hasOwnProperty.call(this.styles, baseName)) {
4374
+ return this.styles[baseName];
4375
+ }
4376
+ }
4377
+ return;
4378
+ }
4286
4379
  clearCache() {
4287
4380
  this.mergedStyleCache.clear();
4288
4381
  }
@@ -4290,6 +4383,8 @@ class SyntaxStyle {
4290
4383
  return this.mergedStyleCache.size;
4291
4384
  }
4292
4385
  }
4386
+
4387
+ // src/lib/hast-styled-text.ts
4293
4388
  function hastToTextChunks(node, syntaxStyle, parentStyles = []) {
4294
4389
  const chunks = [];
4295
4390
  if (node.type === "text") {
@@ -4321,6 +4416,55 @@ function hastToStyledText(hast, syntaxStyle) {
4321
4416
  return new StyledText(chunks);
4322
4417
  }
4323
4418
 
4419
+ // src/lib/scroll-acceleration.ts
4420
+ class LinearScrollAccel {
4421
+ tick(_now) {
4422
+ return 1;
4423
+ }
4424
+ reset() {}
4425
+ }
4426
+
4427
+ class MacOSScrollAccel {
4428
+ opts;
4429
+ lastTickTime = 0;
4430
+ velocityHistory = [];
4431
+ historySize = 3;
4432
+ streakTimeout = 150;
4433
+ minTickInterval = 6;
4434
+ constructor(opts = {}) {
4435
+ this.opts = opts;
4436
+ }
4437
+ tick(now = Date.now()) {
4438
+ const A = this.opts.A ?? 0.8;
4439
+ const tau = this.opts.tau ?? 3;
4440
+ const maxMultiplier = this.opts.maxMultiplier ?? 6;
4441
+ const dt = this.lastTickTime ? now - this.lastTickTime : Infinity;
4442
+ if (dt === Infinity || dt > this.streakTimeout) {
4443
+ this.lastTickTime = now;
4444
+ this.velocityHistory = [];
4445
+ return 1;
4446
+ }
4447
+ if (dt < this.minTickInterval) {
4448
+ return 1;
4449
+ }
4450
+ this.lastTickTime = now;
4451
+ this.velocityHistory.push(dt);
4452
+ if (this.velocityHistory.length > this.historySize) {
4453
+ this.velocityHistory.shift();
4454
+ }
4455
+ const avgInterval = this.velocityHistory.reduce((a, b) => a + b, 0) / this.velocityHistory.length;
4456
+ const referenceInterval = 100;
4457
+ const velocity = referenceInterval / avgInterval;
4458
+ const x = velocity / tau;
4459
+ const multiplier = 1 + A * (Math.exp(x) - 1);
4460
+ return Math.min(multiplier, maxMultiplier);
4461
+ }
4462
+ reset() {
4463
+ this.lastTickTime = 0;
4464
+ this.velocityHistory = [];
4465
+ }
4466
+ }
4467
+
4324
4468
  // src/lib/yoga.options.ts
4325
4469
  function parseAlign(value) {
4326
4470
  switch (value.toLowerCase()) {
@@ -4824,9 +4968,19 @@ function singleton(key, factory) {
4824
4968
  }
4825
4969
  return bag[key];
4826
4970
  }
4971
+ function destroySingleton(key) {
4972
+ const bag = globalThis[singletonCacheSymbol];
4973
+ if (bag && key in bag) {
4974
+ delete bag[key];
4975
+ }
4976
+ }
4977
+ function hasSingleton(key) {
4978
+ const bag = globalThis[singletonCacheSymbol];
4979
+ return bag && key in bag;
4980
+ }
4827
4981
 
4828
4982
  // src/lib/env.ts
4829
- var envRegistry = {};
4983
+ var envRegistry = singleton("env-registry", () => ({}));
4830
4984
  function registerEnvVar(config) {
4831
4985
  const existing = envRegistry[config.name];
4832
4986
  if (existing) {
@@ -4884,8 +5038,14 @@ class EnvStore {
4884
5038
  has(key) {
4885
5039
  return key in envRegistry;
4886
5040
  }
5041
+ clearCache() {
5042
+ this.parsedValues.clear();
5043
+ }
4887
5044
  }
4888
5045
  var envStore = singleton("env-store", () => new EnvStore);
5046
+ function clearEnvCache() {
5047
+ envStore.clearCache();
5048
+ }
4889
5049
  function generateEnvMarkdown() {
4890
5050
  const configs = Object.values(envRegistry);
4891
5051
  if (configs.length === 0) {
@@ -4974,9 +5134,1115 @@ var env = new Proxy({}, {
4974
5134
  return;
4975
5135
  }
4976
5136
  });
5137
+
5138
+ // src/lib/tree-sitter-styled-text.ts
5139
+ function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5140
+ const chunks = [];
5141
+ const defaultStyle = syntaxStyle.getStyle("default");
5142
+ let currentIndex = 0;
5143
+ for (let i = 0;i < highlights.length; i++) {
5144
+ const [startIndex, endIndex, group] = highlights[i];
5145
+ if (startIndex < currentIndex)
5146
+ continue;
5147
+ if (currentIndex < startIndex) {
5148
+ const text2 = content.slice(currentIndex, startIndex);
5149
+ chunks.push({
5150
+ __isChunk: true,
5151
+ text: text2,
5152
+ fg: defaultStyle?.fg,
5153
+ bg: defaultStyle?.bg,
5154
+ attributes: defaultStyle ? createTextAttributes({
5155
+ bold: defaultStyle.bold,
5156
+ italic: defaultStyle.italic,
5157
+ underline: defaultStyle.underline,
5158
+ dim: defaultStyle.dim
5159
+ }) : 0
5160
+ });
5161
+ currentIndex = startIndex;
5162
+ }
5163
+ let resolvedStyle = syntaxStyle.getStyle(group);
5164
+ let j = i + 1;
5165
+ while (j < highlights.length && highlights[j][0] === startIndex) {
5166
+ const [, , nextGroup] = highlights[j];
5167
+ const nextStyle = syntaxStyle.getStyle(nextGroup);
5168
+ if (nextStyle) {
5169
+ resolvedStyle = nextStyle;
5170
+ }
5171
+ j++;
5172
+ }
5173
+ i = j - 1;
5174
+ const text = content.slice(startIndex, endIndex);
5175
+ const styleToUse = resolvedStyle || defaultStyle;
5176
+ chunks.push({
5177
+ __isChunk: true,
5178
+ text,
5179
+ fg: styleToUse?.fg,
5180
+ bg: styleToUse?.bg,
5181
+ attributes: styleToUse ? createTextAttributes({
5182
+ bold: styleToUse.bold,
5183
+ italic: styleToUse.italic,
5184
+ underline: styleToUse.underline,
5185
+ dim: styleToUse.dim
5186
+ }) : 0
5187
+ });
5188
+ currentIndex = endIndex;
5189
+ }
5190
+ if (currentIndex < content.length) {
5191
+ const text = content.slice(currentIndex);
5192
+ chunks.push({
5193
+ __isChunk: true,
5194
+ text,
5195
+ fg: defaultStyle?.fg,
5196
+ bg: defaultStyle?.bg,
5197
+ attributes: defaultStyle ? createTextAttributes({
5198
+ bold: defaultStyle.bold,
5199
+ italic: defaultStyle.italic,
5200
+ underline: defaultStyle.underline,
5201
+ dim: defaultStyle.dim
5202
+ }) : 0
5203
+ });
5204
+ }
5205
+ return chunks;
5206
+ }
5207
+ async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
5208
+ const result = await client.highlightOnce(content, filetype);
5209
+ if (result.highlights && result.highlights.length > 0) {
5210
+ const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle);
5211
+ return new StyledText(chunks);
5212
+ } else {
5213
+ const defaultStyle = syntaxStyle.mergeStyles("default");
5214
+ const chunks = [
5215
+ {
5216
+ __isChunk: true,
5217
+ text: content,
5218
+ fg: defaultStyle.fg,
5219
+ bg: defaultStyle.bg,
5220
+ attributes: defaultStyle.attributes
5221
+ }
5222
+ ];
5223
+ return new StyledText(chunks);
5224
+ }
5225
+ }
5226
+
5227
+ // src/lib/tree-sitter/client.ts
5228
+ import { EventEmitter as EventEmitter2 } from "events";
5229
+
5230
+ // src/lib/debounce.ts
5231
+ var TIMERS_MAP = new Map;
5232
+
5233
+ class DebounceController {
5234
+ scopeId;
5235
+ constructor(scopeId) {
5236
+ this.scopeId = scopeId;
5237
+ if (!TIMERS_MAP.has(this.scopeId)) {
5238
+ TIMERS_MAP.set(this.scopeId, new Map);
5239
+ }
5240
+ }
5241
+ debounce(id, ms, fn) {
5242
+ const scopeMap = TIMERS_MAP.get(this.scopeId);
5243
+ return new Promise((resolve, reject) => {
5244
+ if (scopeMap.has(id)) {
5245
+ clearTimeout(scopeMap.get(id));
5246
+ }
5247
+ const timerId = setTimeout(() => {
5248
+ try {
5249
+ resolve(fn());
5250
+ } catch (error) {
5251
+ reject(error);
5252
+ }
5253
+ scopeMap.delete(id);
5254
+ }, ms);
5255
+ scopeMap.set(id, timerId);
5256
+ });
5257
+ }
5258
+ clearDebounce(id) {
5259
+ const scopeMap = TIMERS_MAP.get(this.scopeId);
5260
+ if (scopeMap && scopeMap.has(id)) {
5261
+ clearTimeout(scopeMap.get(id));
5262
+ scopeMap.delete(id);
5263
+ }
5264
+ }
5265
+ clear() {
5266
+ const scopeMap = TIMERS_MAP.get(this.scopeId);
5267
+ if (scopeMap) {
5268
+ scopeMap.forEach((timerId) => clearTimeout(timerId));
5269
+ scopeMap.clear();
5270
+ }
5271
+ }
5272
+ }
5273
+ function createDebounce(scopeId) {
5274
+ return new DebounceController(scopeId);
5275
+ }
5276
+ function clearDebounceScope(scopeId) {
5277
+ const scopeMap = TIMERS_MAP.get(scopeId);
5278
+ if (scopeMap) {
5279
+ scopeMap.forEach((timerId) => clearTimeout(timerId));
5280
+ scopeMap.clear();
5281
+ }
5282
+ }
5283
+
5284
+ // src/lib/queue.ts
5285
+ class ProcessQueue {
5286
+ processor;
5287
+ queue = [];
5288
+ processing = false;
5289
+ autoProcess = true;
5290
+ constructor(processor, autoProcess = true) {
5291
+ this.processor = processor;
5292
+ this.autoProcess = autoProcess;
5293
+ }
5294
+ enqueue(item) {
5295
+ this.queue.push(item);
5296
+ if (!this.processing && this.autoProcess) {
5297
+ this.processQueue();
5298
+ }
5299
+ }
5300
+ processQueue() {
5301
+ if (this.queue.length === 0) {
5302
+ return;
5303
+ }
5304
+ this.processing = true;
5305
+ queueMicrotask(async () => {
5306
+ if (this.queue.length === 0) {
5307
+ this.processing = false;
5308
+ return;
5309
+ }
5310
+ const item = this.queue.shift();
5311
+ try {
5312
+ await this.processor(item);
5313
+ } catch (error) {
5314
+ console.error("Error processing queue item:", error);
5315
+ }
5316
+ if (this.queue.length > 0) {
5317
+ this.processQueue();
5318
+ } else {
5319
+ this.processing = false;
5320
+ }
5321
+ });
5322
+ }
5323
+ clear() {
5324
+ this.queue = [];
5325
+ }
5326
+ isProcessing() {
5327
+ return this.processing;
5328
+ }
5329
+ size() {
5330
+ return this.queue.length;
5331
+ }
5332
+ }
5333
+
5334
+ // src/lib/tree-sitter/default-parsers.ts
5335
+ import { resolve, dirname } from "path";
5336
+ import { fileURLToPath } from "url";
5337
+ import javascript_highlights from "./assets/javascript/highlights.scm" with { type: "file" };
5338
+ import javascript_language from "./assets/javascript/tree-sitter-javascript.wasm" with { type: "file" };
5339
+ import typescript_highlights from "./assets/typescript/highlights.scm" with { type: "file" };
5340
+ import typescript_language from "./assets/typescript/tree-sitter-typescript.wasm" with { type: "file" };
5341
+ var _cachedParsers;
5342
+ function getParsers() {
5343
+ if (!_cachedParsers) {
5344
+ _cachedParsers = [
5345
+ {
5346
+ filetype: "javascript",
5347
+ queries: {
5348
+ highlights: [resolve(dirname(fileURLToPath(import.meta.url)), javascript_highlights)]
5349
+ },
5350
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), javascript_language)
5351
+ },
5352
+ {
5353
+ filetype: "typescript",
5354
+ queries: {
5355
+ highlights: [resolve(dirname(fileURLToPath(import.meta.url)), typescript_highlights)]
5356
+ },
5357
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), typescript_language)
5358
+ }
5359
+ ];
5360
+ }
5361
+ return _cachedParsers;
5362
+ }
5363
+
5364
+ // src/lib/tree-sitter/client.ts
5365
+ import { resolve as resolve2, isAbsolute } from "path";
5366
+ import { existsSync } from "fs";
5367
+ import { parse } from "path";
5368
+ registerEnvVar({
5369
+ name: "OTUI_TREE_SITTER_WORKER_PATH",
5370
+ description: "Path to the TreeSitter worker",
5371
+ type: "string",
5372
+ default: ""
5373
+ });
5374
+ var DEFAULT_PARSERS = getParsers();
5375
+ function addDefaultParsers(parsers) {
5376
+ for (const parser of parsers) {
5377
+ const existingIndex = DEFAULT_PARSERS.findIndex((p) => p.filetype === parser.filetype);
5378
+ if (existingIndex >= 0) {
5379
+ DEFAULT_PARSERS[existingIndex] = parser;
5380
+ } else {
5381
+ DEFAULT_PARSERS.push(parser);
5382
+ }
5383
+ }
5384
+ }
5385
+ var isUrl = (path) => path.startsWith("http://") || path.startsWith("https://");
5386
+
5387
+ class TreeSitterClient extends EventEmitter2 {
5388
+ initialized = false;
5389
+ worker;
5390
+ buffers = new Map;
5391
+ initializePromise;
5392
+ initializeResolvers;
5393
+ messageCallbacks = new Map;
5394
+ messageIdCounter = 0;
5395
+ editQueues = new Map;
5396
+ debouncer;
5397
+ options;
5398
+ constructor(options) {
5399
+ super();
5400
+ this.options = options;
5401
+ this.debouncer = createDebounce("tree-sitter-client");
5402
+ this.startWorker();
5403
+ }
5404
+ emitError(error, bufferId) {
5405
+ if (this.listenerCount("error") > 0) {
5406
+ this.emit("error", error, bufferId);
5407
+ }
5408
+ }
5409
+ emitWarning(warning, bufferId) {
5410
+ if (this.listenerCount("warning") > 0) {
5411
+ this.emit("warning", warning, bufferId);
5412
+ }
5413
+ }
5414
+ startWorker() {
5415
+ if (this.worker) {
5416
+ return;
5417
+ }
5418
+ let worker_path;
5419
+ if (env.OTUI_TREE_SITTER_WORKER_PATH) {
5420
+ worker_path = env.OTUI_TREE_SITTER_WORKER_PATH;
5421
+ } else if (typeof OTUI_TREE_SITTER_WORKER_PATH !== "undefined") {
5422
+ worker_path = OTUI_TREE_SITTER_WORKER_PATH;
5423
+ } else if (this.options.workerPath) {
5424
+ worker_path = this.options.workerPath;
5425
+ } else {
5426
+ worker_path = new URL("./parser.worker.js", import.meta.url).href;
5427
+ if (!existsSync(resolve2(import.meta.dirname, "parser.worker.js"))) {
5428
+ worker_path = new URL("./parser.worker.ts", import.meta.url).href;
5429
+ }
5430
+ }
5431
+ this.worker = new Worker(worker_path);
5432
+ this.worker.onmessage = this.handleWorkerMessage.bind(this);
5433
+ this.worker.onerror = (error) => {
5434
+ console.error("TreeSitter worker error:", error.message);
5435
+ if (this.initializeResolvers) {
5436
+ clearTimeout(this.initializeResolvers.timeoutId);
5437
+ this.initializeResolvers.reject(new Error(`Worker error: ${error.message}`));
5438
+ this.initializeResolvers = undefined;
5439
+ }
5440
+ this.emitError(`Worker error: ${error.message}`);
5441
+ };
5442
+ }
5443
+ stopWorker() {
5444
+ if (!this.worker) {
5445
+ return;
5446
+ }
5447
+ this.worker.terminate();
5448
+ this.worker = undefined;
5449
+ }
5450
+ handleReset() {
5451
+ this.buffers.clear();
5452
+ this.stopWorker();
5453
+ this.startWorker();
5454
+ this.initializePromise = undefined;
5455
+ this.initializeResolvers = undefined;
5456
+ return this.initialize();
5457
+ }
5458
+ async initialize() {
5459
+ if (this.initializePromise) {
5460
+ return this.initializePromise;
5461
+ }
5462
+ this.initializePromise = new Promise((resolve3, reject) => {
5463
+ const timeoutMs = this.options.initTimeout ?? 1e4;
5464
+ const timeoutId = setTimeout(() => {
5465
+ const error = new Error("Worker initialization timed out");
5466
+ console.error("TreeSitter client:", error.message);
5467
+ this.initializeResolvers = undefined;
5468
+ reject(error);
5469
+ }, timeoutMs);
5470
+ this.initializeResolvers = { resolve: resolve3, reject, timeoutId };
5471
+ this.worker?.postMessage({
5472
+ type: "INIT",
5473
+ dataPath: this.options.dataPath
5474
+ });
5475
+ });
5476
+ await this.initializePromise;
5477
+ await this.registerDefaultParsers();
5478
+ return this.initializePromise;
5479
+ }
5480
+ async registerDefaultParsers() {
5481
+ for (const parser of DEFAULT_PARSERS) {
5482
+ this.addFiletypeParser(parser);
5483
+ }
5484
+ }
5485
+ resolvePath(path) {
5486
+ if (isUrl(path)) {
5487
+ return path;
5488
+ }
5489
+ if (/\$bunfs/.test(path)) {
5490
+ return "/$bunfs/root/" + parse(path).base;
5491
+ }
5492
+ if (!isAbsolute(path)) {
5493
+ return resolve2(path);
5494
+ }
5495
+ return path;
5496
+ }
5497
+ addFiletypeParser(filetypeParser) {
5498
+ const resolvedParser = {
5499
+ ...filetypeParser,
5500
+ wasm: this.resolvePath(filetypeParser.wasm),
5501
+ queries: {
5502
+ highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path))
5503
+ }
5504
+ };
5505
+ this.worker?.postMessage({ type: "ADD_FILETYPE_PARSER", filetypeParser: resolvedParser });
5506
+ }
5507
+ async getPerformance() {
5508
+ const messageId = `performance_${this.messageIdCounter++}`;
5509
+ return new Promise((resolve3) => {
5510
+ this.messageCallbacks.set(messageId, resolve3);
5511
+ this.worker?.postMessage({ type: "GET_PERFORMANCE", messageId });
5512
+ });
5513
+ }
5514
+ async highlightOnce(content, filetype) {
5515
+ if (!this.initialized) {
5516
+ try {
5517
+ await this.initialize();
5518
+ } catch (error) {
5519
+ return { error: "Could not highlight because of initialization error" };
5520
+ }
5521
+ }
5522
+ const messageId = `oneshot_${this.messageIdCounter++}`;
5523
+ return new Promise((resolve3) => {
5524
+ this.messageCallbacks.set(messageId, resolve3);
5525
+ this.worker?.postMessage({
5526
+ type: "ONESHOT_HIGHLIGHT",
5527
+ content,
5528
+ filetype,
5529
+ messageId
5530
+ });
5531
+ });
5532
+ }
5533
+ handleWorkerMessage(event) {
5534
+ const { type, bufferId, error, highlights, warning, messageId, hasParser, performance: performance2, version } = event.data;
5535
+ if (type === "HIGHLIGHT_RESPONSE") {
5536
+ const buffer = this.buffers.get(bufferId);
5537
+ if (!buffer || !buffer.hasParser)
5538
+ return;
5539
+ if (buffer.version !== version) {
5540
+ this.resetBuffer(bufferId, buffer.version, buffer.content);
5541
+ return;
5542
+ }
5543
+ this.emit("highlights:response", bufferId, version, highlights);
5544
+ }
5545
+ if (type === "INIT_RESPONSE") {
5546
+ if (this.initializeResolvers) {
5547
+ clearTimeout(this.initializeResolvers.timeoutId);
5548
+ if (error) {
5549
+ console.error("TreeSitter client initialization failed:", error);
5550
+ this.initializeResolvers.reject(new Error(error));
5551
+ } else {
5552
+ this.initialized = true;
5553
+ this.initializeResolvers.resolve();
5554
+ }
5555
+ this.initializeResolvers = undefined;
5556
+ return;
5557
+ }
5558
+ }
5559
+ if (type === "PARSER_INIT_RESPONSE") {
5560
+ const callback = this.messageCallbacks.get(messageId);
5561
+ if (callback) {
5562
+ this.messageCallbacks.delete(messageId);
5563
+ callback({ hasParser, warning, error });
5564
+ }
5565
+ return;
5566
+ }
5567
+ if (type === "PRELOAD_PARSER_RESPONSE") {
5568
+ const callback = this.messageCallbacks.get(messageId);
5569
+ if (callback) {
5570
+ this.messageCallbacks.delete(messageId);
5571
+ callback({ hasParser });
5572
+ }
5573
+ return;
5574
+ }
5575
+ if (type === "BUFFER_DISPOSED") {
5576
+ const callback = this.messageCallbacks.get(`dispose_${bufferId}`);
5577
+ if (callback) {
5578
+ this.messageCallbacks.delete(`dispose_${bufferId}`);
5579
+ callback(true);
5580
+ }
5581
+ this.emit("buffer:disposed", bufferId);
5582
+ return;
5583
+ }
5584
+ if (type === "PERFORMANCE_RESPONSE") {
5585
+ const callback = this.messageCallbacks.get(messageId);
5586
+ if (callback) {
5587
+ this.messageCallbacks.delete(messageId);
5588
+ callback(performance2);
5589
+ }
5590
+ return;
5591
+ }
5592
+ if (type === "ONESHOT_HIGHLIGHT_RESPONSE") {
5593
+ const callback = this.messageCallbacks.get(messageId);
5594
+ if (callback) {
5595
+ this.messageCallbacks.delete(messageId);
5596
+ callback({ highlights, warning, error });
5597
+ }
5598
+ return;
5599
+ }
5600
+ if (type === "UPDATE_DATA_PATH_RESPONSE") {
5601
+ const callback = this.messageCallbacks.get(messageId);
5602
+ if (callback) {
5603
+ this.messageCallbacks.delete(messageId);
5604
+ callback({ error });
5605
+ }
5606
+ return;
5607
+ }
5608
+ if (warning) {
5609
+ this.emitWarning(warning, bufferId);
5610
+ return;
5611
+ }
5612
+ if (error) {
5613
+ this.emitError(error, bufferId);
5614
+ return;
5615
+ }
5616
+ if (type === "WORKER_LOG") {
5617
+ const { logType, data } = event.data;
5618
+ const message = data.join(" ");
5619
+ this.emit("worker:log", logType, message);
5620
+ if (logType === "log") {
5621
+ console.log("Worker stdout:", ...data);
5622
+ } else if (logType === "error") {
5623
+ console.error("Worker stderr:", ...data);
5624
+ }
5625
+ return;
5626
+ }
5627
+ }
5628
+ async preloadParser(filetype) {
5629
+ const messageId = `has_parser_${this.messageIdCounter++}`;
5630
+ const response = await new Promise((resolve3) => {
5631
+ this.messageCallbacks.set(messageId, resolve3);
5632
+ this.worker?.postMessage({
5633
+ type: "PRELOAD_PARSER",
5634
+ filetype,
5635
+ messageId
5636
+ });
5637
+ });
5638
+ return response.hasParser;
5639
+ }
5640
+ async createBuffer(id, content, filetype, version = 1, autoInitialize = true) {
5641
+ if (!this.initialized) {
5642
+ if (!autoInitialize) {
5643
+ this.emitError("Could not create buffer because client is not initialized");
5644
+ return false;
5645
+ }
5646
+ try {
5647
+ await this.initialize();
5648
+ } catch (error) {
5649
+ this.emitError("Could not create buffer because of initialization error");
5650
+ return false;
5651
+ }
5652
+ }
5653
+ if (this.buffers.has(id)) {
5654
+ throw new Error(`Buffer with id ${id} already exists`);
5655
+ }
5656
+ this.buffers.set(id, { id, content, filetype, version, hasParser: false });
5657
+ const messageId = `init_${this.messageIdCounter++}`;
5658
+ const response = await new Promise((resolve3) => {
5659
+ this.messageCallbacks.set(messageId, resolve3);
5660
+ this.worker?.postMessage({
5661
+ type: "INITIALIZE_PARSER",
5662
+ bufferId: id,
5663
+ version,
5664
+ content,
5665
+ filetype,
5666
+ messageId
5667
+ });
5668
+ });
5669
+ if (!response.hasParser) {
5670
+ this.emit("buffer:initialized", id, false);
5671
+ if (filetype !== "plaintext") {
5672
+ this.emitWarning(response.warning || response.error || "Buffer has no parser", id);
5673
+ }
5674
+ return false;
5675
+ }
5676
+ const bufferState = { id, content, filetype, version, hasParser: true };
5677
+ this.buffers.set(id, bufferState);
5678
+ this.emit("buffer:initialized", id, true);
5679
+ return true;
5680
+ }
5681
+ async updateBuffer(id, edits, newContent, version) {
5682
+ if (!this.initialized) {
5683
+ return;
5684
+ }
5685
+ const buffer = this.buffers.get(id);
5686
+ if (!buffer || !buffer.hasParser) {
5687
+ return;
5688
+ }
5689
+ this.buffers.set(id, { ...buffer, content: newContent, version });
5690
+ if (!this.editQueues.has(id)) {
5691
+ this.editQueues.set(id, new ProcessQueue((item) => this.processEdit(id, item.edits, item.newContent, item.version, item.isReset)));
5692
+ }
5693
+ const bufferQueue = this.editQueues.get(id);
5694
+ bufferQueue.enqueue({ edits, newContent, version });
5695
+ }
5696
+ async processEdit(bufferId, edits, newContent, version, isReset = false) {
5697
+ this.worker?.postMessage({
5698
+ type: isReset ? "RESET_BUFFER" : "HANDLE_EDITS",
5699
+ bufferId,
5700
+ version,
5701
+ content: newContent,
5702
+ edits
5703
+ });
5704
+ }
5705
+ async removeBuffer(bufferId) {
5706
+ if (!this.initialized) {
5707
+ return;
5708
+ }
5709
+ this.buffers.delete(bufferId);
5710
+ if (this.editQueues.has(bufferId)) {
5711
+ this.editQueues.get(bufferId)?.clear();
5712
+ this.editQueues.delete(bufferId);
5713
+ }
5714
+ if (this.worker) {
5715
+ await new Promise((resolve3) => {
5716
+ const messageId = `dispose_${bufferId}`;
5717
+ this.messageCallbacks.set(messageId, resolve3);
5718
+ try {
5719
+ this.worker.postMessage({
5720
+ type: "DISPOSE_BUFFER",
5721
+ bufferId
5722
+ });
5723
+ } catch (error) {
5724
+ console.error("Error disposing buffer", error);
5725
+ resolve3(false);
5726
+ }
5727
+ setTimeout(() => {
5728
+ if (this.messageCallbacks.has(messageId)) {
5729
+ this.messageCallbacks.delete(messageId);
5730
+ console.warn({ bufferId }, "Timed out waiting for buffer to be disposed");
5731
+ resolve3(false);
5732
+ }
5733
+ }, 3000);
5734
+ });
5735
+ }
5736
+ this.debouncer.clearDebounce(`reset-${bufferId}`);
5737
+ }
5738
+ async destroy() {
5739
+ if (this.initializeResolvers) {
5740
+ clearTimeout(this.initializeResolvers.timeoutId);
5741
+ this.initializeResolvers = undefined;
5742
+ }
5743
+ for (const [messageId, callback] of this.messageCallbacks.entries()) {
5744
+ if (typeof callback === "function") {
5745
+ try {
5746
+ callback({ error: "Client destroyed" });
5747
+ } catch (e) {}
5748
+ }
5749
+ }
5750
+ this.messageCallbacks.clear();
5751
+ clearDebounceScope("tree-sitter-client");
5752
+ this.debouncer.clear();
5753
+ this.editQueues.clear();
5754
+ this.buffers.clear();
5755
+ this.stopWorker();
5756
+ this.initialized = false;
5757
+ this.initializePromise = undefined;
5758
+ }
5759
+ async resetBuffer(bufferId, version, content) {
5760
+ if (!this.initialized) {
5761
+ return;
5762
+ }
5763
+ const buffer = this.buffers.get(bufferId);
5764
+ if (!buffer || !buffer.hasParser) {
5765
+ this.emitError("Cannot reset buffer with no parser", bufferId);
5766
+ return;
5767
+ }
5768
+ this.buffers.set(bufferId, { ...buffer, content, version });
5769
+ this.debouncer.debounce(`reset-${bufferId}`, 10, () => this.processEdit(bufferId, [], content, version, true));
5770
+ }
5771
+ getBuffer(bufferId) {
5772
+ return this.buffers.get(bufferId);
5773
+ }
5774
+ getAllBuffers() {
5775
+ return Array.from(this.buffers.values());
5776
+ }
5777
+ isInitialized() {
5778
+ return this.initialized;
5779
+ }
5780
+ async setDataPath(dataPath) {
5781
+ if (this.options.dataPath === dataPath) {
5782
+ return;
5783
+ }
5784
+ this.options.dataPath = dataPath;
5785
+ if (this.initialized && this.worker) {
5786
+ const messageId = `update_datapath_${this.messageIdCounter++}`;
5787
+ return new Promise((resolve3, reject) => {
5788
+ this.messageCallbacks.set(messageId, (response) => {
5789
+ if (response.error) {
5790
+ reject(new Error(response.error));
5791
+ } else {
5792
+ resolve3();
5793
+ }
5794
+ });
5795
+ this.worker.postMessage({
5796
+ type: "UPDATE_DATA_PATH",
5797
+ dataPath,
5798
+ messageId
5799
+ });
5800
+ });
5801
+ }
5802
+ }
5803
+ }
5804
+
5805
+ // src/lib/data-paths.ts
5806
+ import os from "os";
5807
+ import path from "path";
5808
+ import { EventEmitter as EventEmitter3 } from "events";
5809
+
5810
+ // src/lib/validate-dir-name.ts
5811
+ function isValidDirectoryName(name) {
5812
+ if (!name || typeof name !== "string") {
5813
+ return false;
5814
+ }
5815
+ if (name.trim().length === 0) {
5816
+ return false;
5817
+ }
5818
+ const reservedNames = [
5819
+ "CON",
5820
+ "PRN",
5821
+ "AUX",
5822
+ "NUL",
5823
+ "COM1",
5824
+ "COM2",
5825
+ "COM3",
5826
+ "COM4",
5827
+ "COM5",
5828
+ "COM6",
5829
+ "COM7",
5830
+ "COM8",
5831
+ "COM9",
5832
+ "LPT1",
5833
+ "LPT2",
5834
+ "LPT3",
5835
+ "LPT4",
5836
+ "LPT5",
5837
+ "LPT6",
5838
+ "LPT7",
5839
+ "LPT8",
5840
+ "LPT9"
5841
+ ];
5842
+ if (reservedNames.includes(name.toUpperCase())) {
5843
+ return false;
5844
+ }
5845
+ const invalidChars = /[<>:"|?*\/\\\x00-\x1f]/;
5846
+ if (invalidChars.test(name)) {
5847
+ return false;
5848
+ }
5849
+ if (name.endsWith(".") || name.endsWith(" ")) {
5850
+ return false;
5851
+ }
5852
+ if (name === "." || name === "..") {
5853
+ return false;
5854
+ }
5855
+ return true;
5856
+ }
5857
+
5858
+ // src/lib/data-paths.ts
5859
+ registerEnvVar({
5860
+ name: "XDG_CONFIG_HOME",
5861
+ description: "Base directory for user-specific configuration files",
5862
+ type: "string",
5863
+ default: ""
5864
+ });
5865
+ registerEnvVar({
5866
+ name: "XDG_DATA_HOME",
5867
+ description: "Base directory for user-specific data files",
5868
+ type: "string",
5869
+ default: ""
5870
+ });
5871
+
5872
+ class DataPathsManager extends EventEmitter3 {
5873
+ _appName;
5874
+ _globalConfigPath;
5875
+ _globalConfigFile;
5876
+ _localConfigFile;
5877
+ _globalDataPath;
5878
+ constructor() {
5879
+ super();
5880
+ this._appName = "opentui";
5881
+ }
5882
+ get appName() {
5883
+ return this._appName;
5884
+ }
5885
+ set appName(value) {
5886
+ if (!isValidDirectoryName(value)) {
5887
+ throw new Error(`Invalid app name "${value}": must be a valid directory name`);
5888
+ }
5889
+ if (this._appName !== value) {
5890
+ this._appName = value;
5891
+ this._globalConfigPath = undefined;
5892
+ this._globalConfigFile = undefined;
5893
+ this._localConfigFile = undefined;
5894
+ this._globalDataPath = undefined;
5895
+ this.emit("paths:changed", this.toObject());
5896
+ }
5897
+ }
5898
+ get globalConfigPath() {
5899
+ if (this._globalConfigPath === undefined) {
5900
+ const homeDir = os.homedir();
5901
+ const xdgConfigHome = env.XDG_CONFIG_HOME;
5902
+ const baseConfigDir = xdgConfigHome || path.join(homeDir, ".config");
5903
+ this._globalConfigPath = path.join(baseConfigDir, this._appName);
5904
+ }
5905
+ return this._globalConfigPath;
5906
+ }
5907
+ get globalConfigFile() {
5908
+ if (this._globalConfigFile === undefined) {
5909
+ this._globalConfigFile = path.join(this.globalConfigPath, "init.ts");
5910
+ }
5911
+ return this._globalConfigFile;
5912
+ }
5913
+ get localConfigFile() {
5914
+ if (this._localConfigFile === undefined) {
5915
+ this._localConfigFile = path.join(process.cwd(), `.${this._appName}.ts`);
5916
+ }
5917
+ return this._localConfigFile;
5918
+ }
5919
+ get globalDataPath() {
5920
+ if (this._globalDataPath === undefined) {
5921
+ const homeDir = os.homedir();
5922
+ const xdgDataHome = env.XDG_DATA_HOME;
5923
+ const baseDataDir = xdgDataHome || path.join(homeDir, ".local/share");
5924
+ this._globalDataPath = path.join(baseDataDir, this._appName);
5925
+ }
5926
+ return this._globalDataPath;
5927
+ }
5928
+ toObject() {
5929
+ return {
5930
+ globalConfigPath: this.globalConfigPath,
5931
+ globalConfigFile: this.globalConfigFile,
5932
+ localConfigFile: this.localConfigFile,
5933
+ globalDataPath: this.globalDataPath
5934
+ };
5935
+ }
5936
+ }
5937
+ function getDataPaths() {
5938
+ return singleton("data-paths-opentui", () => new DataPathsManager);
5939
+ }
5940
+
5941
+ // src/lib/tree-sitter/resolve-ft.ts
5942
+ function extToFiletype(extension) {
5943
+ const extensionToFiletype = new Map([
5944
+ ["js", "javascript"],
5945
+ ["jsx", "javascriptreact"],
5946
+ ["ts", "typescript"],
5947
+ ["tsx", "typescriptreact"],
5948
+ ["md", "markdown"],
5949
+ ["json", "json"],
5950
+ ["py", "python"],
5951
+ ["rb", "ruby"],
5952
+ ["go", "go"],
5953
+ ["rs", "rust"],
5954
+ ["c", "c"],
5955
+ ["cpp", "cpp"],
5956
+ ["h", "c"],
5957
+ ["hpp", "cpp"],
5958
+ ["html", "html"],
5959
+ ["css", "css"],
5960
+ ["scss", "scss"],
5961
+ ["less", "less"],
5962
+ ["sh", "shell"],
5963
+ ["bash", "shell"],
5964
+ ["zsh", "shell"],
5965
+ ["vim", "vim"],
5966
+ ["yaml", "yaml"],
5967
+ ["yml", "yaml"],
5968
+ ["toml", "toml"],
5969
+ ["xml", "xml"],
5970
+ ["zig", "zig"]
5971
+ ]);
5972
+ return extensionToFiletype.get(extension);
5973
+ }
5974
+ function pathToFiletype(path2) {
5975
+ if (typeof path2 !== "string")
5976
+ return;
5977
+ const lastDot = path2.lastIndexOf(".");
5978
+ if (lastDot === -1 || lastDot === path2.length - 1) {
5979
+ return;
5980
+ }
5981
+ const extension = path2.substring(lastDot + 1);
5982
+ return extToFiletype(extension);
5983
+ }
5984
+
5985
+ // src/lib/tree-sitter/assets/update.ts
5986
+ import { readFile, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
5987
+ import * as path3 from "path";
5988
+
5989
+ // src/lib/tree-sitter/download-utils.ts
5990
+ import { mkdir, writeFile } from "fs/promises";
5991
+ import * as path2 from "path";
5992
+
5993
+ class DownloadUtils {
5994
+ static hashUrl(url) {
5995
+ let hash = 0;
5996
+ for (let i = 0;i < url.length; i++) {
5997
+ const char = url.charCodeAt(i);
5998
+ hash = (hash << 5) - hash + char;
5999
+ hash = hash & hash;
6000
+ }
6001
+ return Math.abs(hash).toString(16);
6002
+ }
6003
+ static async downloadOrLoad(source, cacheDir, cacheSubdir, fileExtension, useHashForCache = true, filetype) {
6004
+ const isUrl2 = source.startsWith("http://") || source.startsWith("https://");
6005
+ if (isUrl2) {
6006
+ let cacheFileName;
6007
+ if (useHashForCache) {
6008
+ const hash = this.hashUrl(source);
6009
+ cacheFileName = filetype ? `${filetype}-${hash}${fileExtension}` : `${hash}${fileExtension}`;
6010
+ } else {
6011
+ cacheFileName = path2.basename(source);
6012
+ }
6013
+ const cacheFile = path2.join(cacheDir, cacheSubdir, cacheFileName);
6014
+ await mkdir(path2.dirname(cacheFile), { recursive: true });
6015
+ try {
6016
+ const cachedContent = await Bun.file(cacheFile).arrayBuffer();
6017
+ if (cachedContent.byteLength > 0) {
6018
+ console.log(`Loaded from cache: ${cacheFile} (${source})`);
6019
+ return { content: cachedContent, filePath: cacheFile };
6020
+ }
6021
+ } catch (error) {}
6022
+ try {
6023
+ console.log(`Downloading from URL: ${source}`);
6024
+ const response = await fetch(source);
6025
+ if (!response.ok) {
6026
+ return { error: `Failed to fetch from ${source}: ${response.statusText}` };
6027
+ }
6028
+ const content = await response.arrayBuffer();
6029
+ try {
6030
+ await writeFile(cacheFile, Buffer.from(content));
6031
+ console.log(`Cached: ${source}`);
6032
+ } catch (cacheError) {
6033
+ console.warn(`Failed to cache: ${cacheError}`);
6034
+ }
6035
+ return { content, filePath: cacheFile };
6036
+ } catch (error) {
6037
+ return { error: `Error downloading from ${source}: ${error}` };
6038
+ }
6039
+ } else {
6040
+ try {
6041
+ console.log(`Loading from local path: ${source}`);
6042
+ const content = await Bun.file(source).arrayBuffer();
6043
+ return { content, filePath: source };
6044
+ } catch (error) {
6045
+ return { error: `Error loading from local path ${source}: ${error}` };
6046
+ }
6047
+ }
6048
+ }
6049
+ static async downloadToPath(source, targetPath) {
6050
+ const isUrl2 = source.startsWith("http://") || source.startsWith("https://");
6051
+ await mkdir(path2.dirname(targetPath), { recursive: true });
6052
+ if (isUrl2) {
6053
+ try {
6054
+ console.log(`Downloading from URL: ${source}`);
6055
+ const response = await fetch(source);
6056
+ if (!response.ok) {
6057
+ return { error: `Failed to fetch from ${source}: ${response.statusText}` };
6058
+ }
6059
+ const content = await response.arrayBuffer();
6060
+ await writeFile(targetPath, Buffer.from(content));
6061
+ console.log(`Downloaded: ${source} -> ${targetPath}`);
6062
+ return { content, filePath: targetPath };
6063
+ } catch (error) {
6064
+ return { error: `Error downloading from ${source}: ${error}` };
6065
+ }
6066
+ } else {
6067
+ try {
6068
+ console.log(`Copying from local path: ${source}`);
6069
+ const content = await Bun.file(source).arrayBuffer();
6070
+ await writeFile(targetPath, Buffer.from(content));
6071
+ return { content, filePath: targetPath };
6072
+ } catch (error) {
6073
+ return { error: `Error copying from local path ${source}: ${error}` };
6074
+ }
6075
+ }
6076
+ }
6077
+ static async fetchHighlightQueries(sources, cacheDir, filetype) {
6078
+ const queryPromises = sources.map((source) => this.fetchHighlightQuery(source, cacheDir, filetype));
6079
+ const queryResults = await Promise.all(queryPromises);
6080
+ const validQueries = queryResults.filter((query) => query.trim().length > 0);
6081
+ return validQueries.join(`
6082
+ `);
6083
+ }
6084
+ static async fetchHighlightQuery(source, cacheDir, filetype) {
6085
+ const result = await this.downloadOrLoad(source, cacheDir, "queries", ".scm", true, filetype);
6086
+ if (result.error) {
6087
+ console.error(`Error fetching highlight query from ${source}:`, result.error);
6088
+ return "";
6089
+ }
6090
+ if (result.content) {
6091
+ return new TextDecoder().decode(result.content);
6092
+ }
6093
+ return "";
6094
+ }
6095
+ }
6096
+
6097
+ // src/lib/tree-sitter/assets/update.ts
6098
+ var __dirname = "/Users/runner/work/opentui/opentui/packages/core/src/lib/tree-sitter/assets";
6099
+ function getDefaultOptions() {
6100
+ return {
6101
+ configPath: path3.resolve(__dirname, "../parsers-config.json"),
6102
+ assetsDir: path3.resolve(__dirname),
6103
+ outputPath: path3.resolve(__dirname, "../default-parsers.ts")
6104
+ };
6105
+ }
6106
+ async function loadConfig(configPath) {
6107
+ const configContent = await readFile(configPath, "utf-8");
6108
+ return JSON.parse(configContent);
6109
+ }
6110
+ async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6111
+ const languageDir = path3.join(assetsDir, filetype);
6112
+ const languageFilename = path3.basename(languageUrl);
6113
+ const languagePath = path3.join(languageDir, languageFilename);
6114
+ const result = await DownloadUtils.downloadToPath(languageUrl, languagePath);
6115
+ if (result.error) {
6116
+ throw new Error(`Failed to download language for ${filetype}: ${result.error}`);
6117
+ }
6118
+ return "./" + path3.relative(path3.dirname(outputPath), languagePath);
6119
+ }
6120
+ async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath) {
6121
+ const queriesDir = path3.join(assetsDir, filetype);
6122
+ const highlightsPath = path3.join(queriesDir, "highlights.scm");
6123
+ const queryContents = [];
6124
+ for (let i = 0;i < queryUrls.length; i++) {
6125
+ const queryUrl = queryUrls[i];
6126
+ console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6127
+ try {
6128
+ const response = await fetch(queryUrl);
6129
+ if (!response.ok) {
6130
+ console.warn(`Failed to download query from ${queryUrl}: ${response.statusText}`);
6131
+ continue;
6132
+ }
6133
+ const content = await response.text();
6134
+ if (content.trim()) {
6135
+ queryContents.push(`; Query from: ${queryUrl}
6136
+ ${content}`);
6137
+ console.log(` \u2713 Downloaded ${content.split(`
6138
+ `).length} lines`);
6139
+ }
6140
+ } catch (error) {
6141
+ console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6142
+ continue;
6143
+ }
6144
+ }
6145
+ const combinedContent = queryContents.join(`
6146
+
6147
+ `);
6148
+ await writeFile2(highlightsPath, combinedContent, "utf-8");
6149
+ console.log(` Combined ${queryContents.length} queries into ${highlightsPath}`);
6150
+ return "./" + path3.relative(path3.dirname(outputPath), highlightsPath);
6151
+ }
6152
+ async function generateDefaultParsersFile(parsers, outputPath) {
6153
+ const imports = parsers.map((parser) => {
6154
+ const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6155
+ return `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }
6156
+ import ${safeFiletype}_language from "${parser.languagePath}" with { type: "file" }`;
6157
+ }).join(`
6158
+ `);
6159
+ const parserDefinitions = parsers.map((parser) => {
6160
+ const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6161
+ return ` {
6162
+ filetype: "${parser.filetype}",
6163
+ queries: {
6164
+ highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],
6165
+ },
6166
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),
6167
+ }`;
6168
+ }).join(`,
6169
+ `);
6170
+ const fileContent = `// This file is generated by assets/update.ts - DO NOT EDIT MANUALLY
6171
+ // Run 'bun assets/update.ts' to regenerate this file
6172
+ // Last generated: ${new Date().toISOString()}
6173
+
6174
+ import type { FiletypeParserOptions } from "./types"
6175
+ import { resolve, dirname } from "path"
6176
+ import { fileURLToPath } from "url"
6177
+
6178
+ ${imports}
6179
+
6180
+ // Cached parsers to avoid re-resolving paths on every call
6181
+ let _cachedParsers: FiletypeParserOptions[] | undefined
6182
+
6183
+ export function getParsers(): FiletypeParserOptions[] {
6184
+ if (!_cachedParsers) {
6185
+ _cachedParsers = [
6186
+ ${parserDefinitions},
6187
+ ]
6188
+ }
6189
+ return _cachedParsers
6190
+ }
6191
+ `;
6192
+ await mkdir2(path3.dirname(outputPath), { recursive: true });
6193
+ await writeFile2(outputPath, fileContent, "utf-8");
6194
+ console.log(`Generated ${path3.basename(outputPath)} with ${parsers.length} parsers`);
6195
+ }
6196
+ async function main(options) {
6197
+ const opts = { ...getDefaultOptions(), ...options };
6198
+ try {
6199
+ console.log("Loading parsers configuration...");
6200
+ console.log(` Config: ${opts.configPath}`);
6201
+ console.log(` Assets Dir: ${opts.assetsDir}`);
6202
+ console.log(` Output: ${opts.outputPath}`);
6203
+ const config = await loadConfig(opts.configPath);
6204
+ console.log(`Found ${config.parsers.length} parsers to process`);
6205
+ const generatedParsers = [];
6206
+ for (const parser of config.parsers) {
6207
+ console.log(`Processing ${parser.filetype}...`);
6208
+ console.log(` Downloading language...`);
6209
+ const languagePath = await downloadLanguage(parser.filetype, parser.wasm, opts.assetsDir, opts.outputPath);
6210
+ console.log(` Downloading ${parser.queries.highlights.length} highlight queries...`);
6211
+ const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath);
6212
+ generatedParsers.push({
6213
+ filetype: parser.filetype,
6214
+ languagePath,
6215
+ highlightsPath
6216
+ });
6217
+ console.log(` \u2713 Completed ${parser.filetype}`);
6218
+ }
6219
+ console.log("Generating output file...");
6220
+ await generateDefaultParsersFile(generatedParsers, opts.outputPath);
6221
+ console.log("\u2705 Update completed successfully!");
6222
+ } catch (error) {
6223
+ console.error("\u274C Update failed:", error);
6224
+ process.exit(1);
6225
+ }
6226
+ }
6227
+ if (false) {}
6228
+
6229
+ // src/lib/tree-sitter/index.ts
6230
+ function getTreeSitterClient() {
6231
+ const dataPathsManager = getDataPaths();
6232
+ const defaultOptions = {
6233
+ dataPath: dataPathsManager.globalDataPath
6234
+ };
6235
+ return singleton("tree-sitter-client", () => {
6236
+ const client2 = new TreeSitterClient(defaultOptions);
6237
+ dataPathsManager.on("paths:changed", (paths) => {
6238
+ client2.setDataPath(paths.globalDataPath);
6239
+ });
6240
+ return client2;
6241
+ });
6242
+ }
4977
6243
  // src/zig.ts
4978
6244
  import { dlopen, toArrayBuffer as toArrayBuffer2, JSCallback, ptr } from "bun:ffi";
4979
- import { existsSync } from "fs";
6245
+ import { existsSync as existsSync2 } from "fs";
4980
6246
 
4981
6247
  // src/buffer.ts
4982
6248
  import { toArrayBuffer } from "bun:ffi";
@@ -5177,7 +6443,10 @@ class OptimizedBuffer {
5177
6443
  // src/zig.ts
5178
6444
  var module = await import(`@opentui/core-${process.platform}-${process.arch}/index.ts`);
5179
6445
  var targetLibPath = module.default;
5180
- if (!existsSync(targetLibPath)) {
6446
+ if (/\$bunfs/.test(targetLibPath)) {
6447
+ targetLibPath = targetLibPath.replace("../", "");
6448
+ }
6449
+ if (!existsSync2(targetLibPath)) {
5181
6450
  throw new Error(`opentui is not supported on the current platform: ${process.platform}-${process.arch}`);
5182
6451
  }
5183
6452
  registerEnvVar({
@@ -6281,7 +7550,7 @@ class TextBuffer {
6281
7550
  }
6282
7551
 
6283
7552
  // src/Renderable.ts
6284
- import { EventEmitter as EventEmitter2 } from "events";
7553
+ import { EventEmitter as EventEmitter4 } from "events";
6285
7554
 
6286
7555
  // src/lib/renderable.validations.ts
6287
7556
  function validateOptions(id, options) {
@@ -6374,7 +7643,7 @@ function isRenderable(obj) {
6374
7643
  return !!obj?.[BrandedRenderable];
6375
7644
  }
6376
7645
 
6377
- class BaseRenderable extends EventEmitter2 {
7646
+ class BaseRenderable extends EventEmitter4 {
6378
7647
  [BrandedRenderable] = true;
6379
7648
  static renderableNumber = 1;
6380
7649
  _id;
@@ -6546,18 +7815,18 @@ class Renderable extends BaseRenderable {
6546
7815
  this.requestRender();
6547
7816
  this.keypressHandler = (key) => {
6548
7817
  this._keyListeners["down"]?.(key);
6549
- if (this.handleKeyPress) {
7818
+ if (!key.defaultPrevented && this.handleKeyPress) {
6550
7819
  this.handleKeyPress(key);
6551
7820
  }
6552
7821
  };
6553
- this.pasteHandler = (text) => {
6554
- this._pasteListener?.call(this, text);
6555
- if (this.handlePaste) {
6556
- this.handlePaste(text);
7822
+ this.pasteHandler = (event) => {
7823
+ this._pasteListener?.call(this, event.text);
7824
+ if (!event.defaultPrevented && this.handlePaste) {
7825
+ this.handlePaste(event.text);
6557
7826
  }
6558
7827
  };
6559
- this.ctx.keyInput.on("keypress", this.keypressHandler);
6560
- this.ctx.keyInput.on("paste", this.pasteHandler);
7828
+ this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler);
7829
+ this.ctx._internalKeyInput.onInternal("paste", this.pasteHandler);
6561
7830
  this.emit("focused" /* FOCUSED */);
6562
7831
  }
6563
7832
  blur() {
@@ -6566,11 +7835,11 @@ class Renderable extends BaseRenderable {
6566
7835
  this._focused = false;
6567
7836
  this.requestRender();
6568
7837
  if (this.keypressHandler) {
6569
- this.ctx.keyInput.off("keypress", this.keypressHandler);
7838
+ this.ctx._internalKeyInput.offInternal("keypress", this.keypressHandler);
6570
7839
  this.keypressHandler = null;
6571
7840
  }
6572
7841
  if (this.pasteHandler) {
6573
- this.ctx.keyInput.off("paste", this.pasteHandler);
7842
+ this.ctx._internalKeyInput.offInternal("paste", this.pasteHandler);
6574
7843
  this.pasteHandler = null;
6575
7844
  }
6576
7845
  this.emit("blurred" /* BLURRED */);
@@ -7171,10 +8440,11 @@ class Renderable extends BaseRenderable {
7171
8440
  if (renderable.parent === this) {
7172
8441
  this.yogaNode.removeChild(renderable.getLayoutNode());
7173
8442
  this._childrenInLayoutOrder.splice(this._childrenInLayoutOrder.indexOf(renderable), 1);
7174
- } else if (renderable.parent) {
8443
+ } else {
7175
8444
  this.replaceParent(renderable);
7176
8445
  this.needsZIndexSort = true;
7177
8446
  this.renderableMapById.set(renderable.id, renderable);
8447
+ this._childrenInZIndexOrder.push(renderable);
7178
8448
  if (typeof renderable.onLifecyclePass === "function") {
7179
8449
  this._ctx.registerLifecyclePass(renderable);
7180
8450
  }
@@ -7219,6 +8489,16 @@ class Renderable extends BaseRenderable {
7219
8489
  if (zIndexIndex !== -1) {
7220
8490
  this._childrenInZIndexOrder.splice(zIndexIndex, 1);
7221
8491
  }
8492
+ if (this._forceLayoutUpdateFor) {
8493
+ const forceIndex = this._forceLayoutUpdateFor.findIndex((obj2) => obj2.id === id);
8494
+ if (forceIndex !== -1) {
8495
+ this._forceLayoutUpdateFor?.splice(forceIndex, 1);
8496
+ }
8497
+ }
8498
+ const newChildIndex = this._newChildren.findIndex((obj2) => obj2.id === id);
8499
+ if (newChildIndex !== -1) {
8500
+ this._newChildren?.splice(newChildIndex, 1);
8501
+ }
7222
8502
  this.childrenPrimarySortDirty = true;
7223
8503
  }
7224
8504
  }
@@ -7327,7 +8607,8 @@ class Renderable extends BaseRenderable {
7327
8607
  } catch (e) {}
7328
8608
  }
7329
8609
  destroyRecursively() {
7330
- for (const child of this._childrenInLayoutOrder) {
8610
+ const children = [...this._childrenInLayoutOrder];
8611
+ for (const child of children) {
7331
8612
  child.destroyRecursively();
7332
8613
  }
7333
8614
  this.destroy();
@@ -7666,17 +8947,17 @@ function delegate(mapping, vnode) {
7666
8947
  }
7667
8948
 
7668
8949
  // src/console.ts
7669
- import { EventEmitter as EventEmitter4 } from "events";
8950
+ import { EventEmitter as EventEmitter6 } from "events";
7670
8951
  import { Console } from "console";
7671
8952
  import fs from "fs";
7672
- import path from "path";
8953
+ import path4 from "path";
7673
8954
  import util2 from "util";
7674
8955
 
7675
8956
  // src/lib/output.capture.ts
7676
8957
  import { Writable } from "stream";
7677
- import { EventEmitter as EventEmitter3 } from "events";
8958
+ import { EventEmitter as EventEmitter5 } from "events";
7678
8959
 
7679
- class Capture extends EventEmitter3 {
8960
+ class Capture extends EventEmitter5 {
7680
8961
  output = [];
7681
8962
  constructor() {
7682
8963
  super();
@@ -7752,7 +9033,7 @@ registerEnvVar({
7752
9033
  default: false
7753
9034
  });
7754
9035
 
7755
- class TerminalConsoleCache extends EventEmitter4 {
9036
+ class TerminalConsoleCache extends EventEmitter6 {
7756
9037
  _cachedLogs = [];
7757
9038
  MAX_CACHE_SIZE = 1000;
7758
9039
  _collectCallerInfo = false;
@@ -7873,7 +9154,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
7873
9154
  };
7874
9155
  var INDENT_WIDTH = 2;
7875
9156
 
7876
- class TerminalConsole extends EventEmitter4 {
9157
+ class TerminalConsole extends EventEmitter6 {
7877
9158
  isVisible = false;
7878
9159
  isFocused = false;
7879
9160
  renderer;
@@ -8312,7 +9593,7 @@ class TerminalConsole extends EventEmitter4 {
8312
9593
  try {
8313
9594
  const timestamp = Date.now();
8314
9595
  const filename = `_console_${timestamp}.log`;
8315
- const filepath = path.join(process.cwd(), filename);
9596
+ const filepath = path4.join(process.cwd(), filename);
8316
9597
  const allLogEntries = [...this._allLogEntries, ...terminalConsoleCache.cachedLogs];
8317
9598
  const logLines = [];
8318
9599
  for (const [date, level, args, callerInfo] of allLogEntries) {
@@ -8333,7 +9614,7 @@ class TerminalConsole extends EventEmitter4 {
8333
9614
  }
8334
9615
 
8335
9616
  // src/renderer.ts
8336
- import { EventEmitter as EventEmitter5 } from "events";
9617
+ import { EventEmitter as EventEmitter7 } from "events";
8337
9618
 
8338
9619
  // src/lib/objects-in-viewport.ts
8339
9620
  function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
@@ -8423,6 +9704,18 @@ registerEnvVar({
8423
9704
  type: "boolean",
8424
9705
  default: false
8425
9706
  });
9707
+ registerEnvVar({
9708
+ name: "OTUI_USE_ALTERNATE_SCREEN",
9709
+ description: "Whether to use the console. Will not capture console output if set to false.",
9710
+ type: "boolean",
9711
+ default: true
9712
+ });
9713
+ registerEnvVar({
9714
+ name: "OTUI_OVERRIDE_STDOUT",
9715
+ description: "Override the stdout stream. This is useful for debugging.",
9716
+ type: "boolean",
9717
+ default: true
9718
+ });
8426
9719
 
8427
9720
  class MouseEvent {
8428
9721
  type;
@@ -8485,13 +9778,17 @@ var rendererTracker = singleton("RendererTracker", () => {
8485
9778
  renderers.delete(renderer);
8486
9779
  if (renderers.size === 0) {
8487
9780
  process.stdin.pause();
9781
+ if (hasSingleton("tree-sitter-client")) {
9782
+ getTreeSitterClient().destroy();
9783
+ destroySingleton("tree-sitter-client");
9784
+ }
8488
9785
  }
8489
9786
  }
8490
9787
  };
8491
9788
  });
8492
9789
  async function createCliRenderer(config = {}) {
8493
9790
  if (process.argv.includes("--delay-start")) {
8494
- await new Promise((resolve) => setTimeout(resolve, 5000));
9791
+ await new Promise((resolve4) => setTimeout(resolve4, 5000));
8495
9792
  }
8496
9793
  const stdin = config.stdin || process.stdin;
8497
9794
  const stdout = config.stdout || process.stdout;
@@ -8518,14 +9815,14 @@ var CliRenderEvents;
8518
9815
  ((CliRenderEvents2) => {
8519
9816
  CliRenderEvents2["DEBUG_OVERLAY_TOGGLE"] = "debugOverlay:toggle";
8520
9817
  })(CliRenderEvents ||= {});
8521
- class CliRenderer extends EventEmitter5 {
9818
+ class CliRenderer extends EventEmitter7 {
8522
9819
  static animationFrameId = 0;
8523
9820
  lib;
8524
9821
  rendererPtr;
8525
9822
  stdin;
8526
9823
  stdout;
8527
9824
  exitOnCtrlC;
8528
- isDestroyed = false;
9825
+ _isDestroyed = false;
8529
9826
  nextRenderBuffer;
8530
9827
  currentRenderBuffer;
8531
9828
  _isRunning = false;
@@ -8579,7 +9876,7 @@ class CliRenderer extends EventEmitter5 {
8579
9876
  resizeDebounceDelay = 100;
8580
9877
  enableMouseMovement = false;
8581
9878
  _useMouse = true;
8582
- _useAlternateScreen = true;
9879
+ _useAlternateScreen = env.OTUI_USE_ALTERNATE_SCREEN;
8583
9880
  capturedRenderable;
8584
9881
  lastOverRenderableNum = 0;
8585
9882
  lastOverRenderable;
@@ -8610,9 +9907,9 @@ class CliRenderer extends EventEmitter5 {
8610
9907
  handleError = ((error) => {
8611
9908
  this.stop();
8612
9909
  this.destroy();
8613
- new Promise((resolve) => {
9910
+ new Promise((resolve4) => {
8614
9911
  setTimeout(() => {
8615
- resolve(true);
9912
+ resolve4(true);
8616
9913
  }, 100);
8617
9914
  }).then(() => {
8618
9915
  this.realStdoutWrite.call(this.stdout, `
@@ -8691,7 +9988,7 @@ Captured output:
8691
9988
  this.maxStatSamples = config.maxStatSamples || 300;
8692
9989
  this.enableMouseMovement = config.enableMouseMovement || true;
8693
9990
  this._useMouse = config.useMouse ?? true;
8694
- this._useAlternateScreen = config.useAlternateScreen ?? true;
9991
+ this._useAlternateScreen = config.useAlternateScreen ?? env.OTUI_USE_ALTERNATE_SCREEN;
8695
9992
  this.nextRenderBuffer = this.lib.getNextBuffer(this.rendererPtr);
8696
9993
  this.currentRenderBuffer = this.lib.getCurrentBuffer(this.rendererPtr);
8697
9994
  this.postProcessFns = config.postProcessFns || [];
@@ -8699,7 +9996,9 @@ Captured output:
8699
9996
  if (this.memorySnapshotInterval > 0) {
8700
9997
  this.startMemorySnapshotTimer();
8701
9998
  }
8702
- this.stdout.write = this.interceptStdoutWrite.bind(this);
9999
+ if (env.OTUI_OVERRIDE_STDOUT) {
10000
+ this.stdout.write = this.interceptStdoutWrite.bind(this);
10001
+ }
8703
10002
  process.on("SIGWINCH", this.sigwinchHandler);
8704
10003
  process.on("warning", this.warningHandler);
8705
10004
  process.on("uncaughtException", this.handleError);
@@ -8707,7 +10006,7 @@ Captured output:
8707
10006
  process.on("exit", this.exitHandler);
8708
10007
  this._console = new TerminalConsole(this, config.consoleOptions);
8709
10008
  this.useConsole = config.useConsole ?? true;
8710
- this._keyHandler = new KeyHandler(this.stdin, config.useKittyKeyboard ?? false);
10009
+ this._keyHandler = new InternalKeyHandler(this.stdin, config.useKittyKeyboard ?? false);
8711
10010
  global.requestAnimationFrame = (callback) => {
8712
10011
  const id = CliRenderer.animationFrameId++;
8713
10012
  this.animationRequest.set(id, callback);
@@ -8731,6 +10030,9 @@ Captured output:
8731
10030
  }
8732
10031
  this.setupInput();
8733
10032
  }
10033
+ get isDestroyed() {
10034
+ return this._isDestroyed;
10035
+ }
8734
10036
  registerLifecyclePass(renderable) {
8735
10037
  this.lifecyclePasses.add(renderable);
8736
10038
  }
@@ -8795,6 +10097,9 @@ Captured output:
8795
10097
  get keyInput() {
8796
10098
  return this._keyHandler;
8797
10099
  }
10100
+ get _internalKeyInput() {
10101
+ return this._keyHandler;
10102
+ }
8798
10103
  get terminalWidth() {
8799
10104
  return this._terminalWidth;
8800
10105
  }
@@ -8925,16 +10230,16 @@ Captured output:
8925
10230
  if (this._terminalIsSetup)
8926
10231
  return;
8927
10232
  this._terminalIsSetup = true;
8928
- await new Promise((resolve) => {
10233
+ await new Promise((resolve4) => {
8929
10234
  const timeout = setTimeout(() => {
8930
10235
  this.stdin.off("data", capListener);
8931
- resolve(true);
10236
+ resolve4(true);
8932
10237
  }, 100);
8933
10238
  const capListener = (str) => {
8934
10239
  clearTimeout(timeout);
8935
10240
  this.lib.processCapabilityResponse(this.rendererPtr, str);
8936
10241
  this.stdin.off("data", capListener);
8937
- resolve(true);
10242
+ resolve4(true);
8938
10243
  };
8939
10244
  this.stdin.on("data", capListener);
8940
10245
  this.lib.setupTerminal(this.rendererPtr, this._useAlternateScreen);
@@ -9091,7 +10396,7 @@ Captured output:
9091
10396
  return false;
9092
10397
  }
9093
10398
  takeMemorySnapshot() {
9094
- if (this.isDestroyed)
10399
+ if (this._isDestroyed)
9095
10400
  return;
9096
10401
  const memoryUsage = process.memoryUsage();
9097
10402
  this.lastMemorySnapshot = {
@@ -9124,7 +10429,7 @@ Captured output:
9124
10429
  }
9125
10430
  }
9126
10431
  handleResize(width, height) {
9127
- if (this.isDestroyed)
10432
+ if (this._isDestroyed)
9128
10433
  return;
9129
10434
  if (this._splitHeight > 0) {
9130
10435
  this.processResize(width, height);
@@ -9283,7 +10588,7 @@ Captured output:
9283
10588
  this.controlState = this._isRunning ? "auto_started" /* AUTO_STARTED */ : "idle" /* IDLE */;
9284
10589
  }
9285
10590
  internalStart() {
9286
- if (!this._isRunning && !this.isDestroyed) {
10591
+ if (!this._isRunning && !this._isDestroyed) {
9287
10592
  this._isRunning = true;
9288
10593
  if (this.memorySnapshotInterval > 0) {
9289
10594
  this.startMemorySnapshotTimer();
@@ -9303,7 +10608,7 @@ Captured output:
9303
10608
  this.internalStop();
9304
10609
  }
9305
10610
  internalStop() {
9306
- if (this.isRunning && !this.isDestroyed) {
10611
+ if (this.isRunning && !this._isDestroyed) {
9307
10612
  this._isRunning = false;
9308
10613
  if (this.memorySnapshotTimer) {
9309
10614
  clearInterval(this.memorySnapshotTimer);
@@ -9324,9 +10629,9 @@ Captured output:
9324
10629
  if (this.memorySnapshotTimer) {
9325
10630
  clearInterval(this.memorySnapshotTimer);
9326
10631
  }
9327
- if (this.isDestroyed)
10632
+ if (this._isDestroyed)
9328
10633
  return;
9329
- this.isDestroyed = true;
10634
+ this._isDestroyed = true;
9330
10635
  if (this.renderTimeout) {
9331
10636
  clearTimeout(this.renderTimeout);
9332
10637
  this.renderTimeout = null;
@@ -9334,7 +10639,11 @@ Captured output:
9334
10639
  this._isRunning = false;
9335
10640
  this.waitingForPixelResolution = false;
9336
10641
  this.capturedRenderable = undefined;
9337
- this.root.destroyRecursively();
10642
+ try {
10643
+ this.root.destroyRecursively();
10644
+ } catch (e) {
10645
+ console.error("Error destroying root renderable:", e instanceof Error ? e.stack : String(e));
10646
+ }
9338
10647
  this._keyHandler.destroy();
9339
10648
  this._console.deactivate();
9340
10649
  this.disableStdoutInterception();
@@ -9359,7 +10668,7 @@ Captured output:
9359
10668
  this.loop();
9360
10669
  }
9361
10670
  async loop() {
9362
- if (this.rendering || this.isDestroyed)
10671
+ if (this.rendering || this._isDestroyed)
9363
10672
  return;
9364
10673
  this.rendering = true;
9365
10674
  if (this.renderTimeout) {
@@ -9403,17 +10712,17 @@ Captured output:
9403
10712
  postProcessFn(this.nextRenderBuffer, deltaTime);
9404
10713
  }
9405
10714
  this._console.renderToBuffer(this.nextRenderBuffer);
9406
- if (!this.isDestroyed) {
10715
+ if (!this._isDestroyed) {
9407
10716
  this.renderNative();
9408
- }
9409
- const overallFrameTime = performance.now() - overallStart;
9410
- this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
9411
- if (this.gatherStats) {
9412
- this.collectStatSample(overallFrameTime);
9413
- }
9414
- if (this._isRunning) {
9415
- const delay = Math.max(1, this.targetFrameTime - Math.floor(overallFrameTime));
9416
- this.renderTimeout = setTimeout(() => this.loop(), delay);
10717
+ const overallFrameTime = performance.now() - overallStart;
10718
+ this.lib.updateStats(this.rendererPtr, overallFrameTime, this.renderStats.fps, this.renderStats.frameCallbackTime);
10719
+ if (this.gatherStats) {
10720
+ this.collectStatSample(overallFrameTime);
10721
+ }
10722
+ if (this._isRunning) {
10723
+ const delay = Math.max(1, this.targetFrameTime - Math.floor(overallFrameTime));
10724
+ this.renderTimeout = setTimeout(() => this.loop(), delay);
10725
+ }
9417
10726
  }
9418
10727
  this.rendering = false;
9419
10728
  if (this.immediateRerenderRequested) {
@@ -9572,7 +10881,7 @@ Captured output:
9572
10881
  }
9573
10882
  }
9574
10883
 
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 };
10884
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, KeyEvent, PasteEvent, KeyHandler, InternalKeyHandler, 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, convertThemeToStyles, SyntaxStyle, hastToStyledText, LinearScrollAccel, MacOSScrollAccel, parseAlign, parseBoxSizing, parseDimension, parseDirection, parseDisplay, parseEdge, parseFlexDirection, parseGutter, parseJustify, parseLogLevel, parseMeasureMode, parseOverflow, parsePositionType, parseUnit, parseWrap, MouseParser, Selection, convertGlobalToLocalSelection, ASCIIFontSelectionHelper, envRegistry, registerEnvVar, clearEnvCache, generateEnvMarkdown, generateEnvColored, env, treeSitterToTextChunks, treeSitterToStyledText, addDefaultParsers, TreeSitterClient, DataPathsManager, getDataPaths, extToFiletype, pathToFiletype, main, getTreeSitterClient, 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 };
9576
10885
 
9577
- //# debugId=FA47EE78BCA83E8664756E2164756E21
9578
- //# sourceMappingURL=index-6kvgbzah.js.map
10886
+ //# debugId=66FAF32C902A5E0B64756E2164756E21
10887
+ //# sourceMappingURL=index-pxa2sv92.js.map