@opentui/core 0.0.0-20251030-1c570263 → 0.0.0-20251102-23e7b561

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.
@@ -1896,6 +1896,7 @@ function parseKittyKeyboard(sequence) {
1896
1896
  sequence,
1897
1897
  raw: sequence,
1898
1898
  eventType: "press",
1899
+ source: "kitty",
1899
1900
  super: false,
1900
1901
  hyper: false,
1901
1902
  capsLock: false,
@@ -2107,10 +2108,11 @@ var parseKeypress = (s = "", options = {}) => {
2107
2108
  number: false,
2108
2109
  sequence: s,
2109
2110
  raw: s,
2110
- eventType: "press"
2111
+ eventType: "press",
2112
+ source: "raw"
2111
2113
  };
2112
2114
  key.sequence = key.sequence || s || key.name;
2113
- if (options.useKittyKeyboard && /^\x1b\[.*u$/.test(s)) {
2115
+ if (options.useKittyKeyboard) {
2114
2116
  const kittyResult = parseKittyKeyboard(s);
2115
2117
  if (kittyResult) {
2116
2118
  return kittyResult;
@@ -2135,6 +2137,9 @@ var parseKeypress = (s = "", options = {}) => {
2135
2137
  } else if (s === " " || s === "\x1B ") {
2136
2138
  key.name = "space";
2137
2139
  key.meta = s.length === 2;
2140
+ } else if (s === "\x00") {
2141
+ key.name = "space";
2142
+ key.ctrl = true;
2138
2143
  } else if (s.length === 1 && s <= "\x1A") {
2139
2144
  key.name = String.fromCharCode(s.charCodeAt(0) + 97 - 1);
2140
2145
  key.ctrl = true;
@@ -2185,8 +2190,184 @@ var parseKeypress = (s = "", options = {}) => {
2185
2190
  return key;
2186
2191
  };
2187
2192
 
2188
- // src/lib/KeyHandler.ts
2193
+ // src/lib/stdin-buffer.ts
2189
2194
  import { EventEmitter } from "events";
2195
+ var ESC = "\x1B";
2196
+ function isCompleteSequence(data) {
2197
+ if (!data.startsWith(ESC)) {
2198
+ return "not-escape";
2199
+ }
2200
+ if (data.length === 1) {
2201
+ return "incomplete";
2202
+ }
2203
+ const afterEsc = data.slice(1);
2204
+ if (afterEsc.startsWith("[")) {
2205
+ if (afterEsc.startsWith("[M")) {
2206
+ return data.length >= 6 ? "complete" : "incomplete";
2207
+ }
2208
+ return isCompleteCsiSequence(data);
2209
+ }
2210
+ if (afterEsc.startsWith("]")) {
2211
+ return isCompleteOscSequence(data);
2212
+ }
2213
+ if (afterEsc.startsWith("O")) {
2214
+ return afterEsc.length >= 2 ? "complete" : "incomplete";
2215
+ }
2216
+ if (afterEsc.length === 1) {
2217
+ return "complete";
2218
+ }
2219
+ return "complete";
2220
+ }
2221
+ function isCompleteCsiSequence(data) {
2222
+ if (!data.startsWith(ESC + "[")) {
2223
+ return "complete";
2224
+ }
2225
+ if (data.length < 3) {
2226
+ return "incomplete";
2227
+ }
2228
+ const payload = data.slice(2);
2229
+ const lastChar = payload[payload.length - 1];
2230
+ const lastCharCode = lastChar.charCodeAt(0);
2231
+ if (lastCharCode >= 64 && lastCharCode <= 126) {
2232
+ if (payload.startsWith("<")) {
2233
+ const mouseMatch = /^<\d+;\d+;\d+[Mm]$/.test(payload);
2234
+ if (mouseMatch) {
2235
+ return "complete";
2236
+ }
2237
+ if (lastChar === "M" || lastChar === "m") {
2238
+ const parts = payload.slice(1, -1).split(";");
2239
+ if (parts.length === 3 && parts.every((p) => /^\d+$/.test(p))) {
2240
+ return "complete";
2241
+ }
2242
+ }
2243
+ return "incomplete";
2244
+ }
2245
+ return "complete";
2246
+ }
2247
+ return "incomplete";
2248
+ }
2249
+ function isCompleteOscSequence(data) {
2250
+ if (!data.startsWith(ESC + "]")) {
2251
+ return "complete";
2252
+ }
2253
+ if (data.endsWith(ESC + "\\") || data.endsWith("\x07")) {
2254
+ return "complete";
2255
+ }
2256
+ return "incomplete";
2257
+ }
2258
+ function extractCompleteSequences(buffer) {
2259
+ const sequences = [];
2260
+ let pos = 0;
2261
+ while (pos < buffer.length) {
2262
+ const remaining = buffer.slice(pos);
2263
+ if (remaining.startsWith(ESC)) {
2264
+ let seqEnd = 1;
2265
+ while (seqEnd <= remaining.length) {
2266
+ const candidate = remaining.slice(0, seqEnd);
2267
+ const status = isCompleteSequence(candidate);
2268
+ if (status === "complete") {
2269
+ sequences.push(candidate);
2270
+ pos += seqEnd;
2271
+ break;
2272
+ } else if (status === "incomplete") {
2273
+ seqEnd++;
2274
+ } else {
2275
+ sequences.push(candidate);
2276
+ pos += seqEnd;
2277
+ break;
2278
+ }
2279
+ }
2280
+ if (seqEnd > remaining.length) {
2281
+ return { sequences, remainder: remaining };
2282
+ }
2283
+ } else {
2284
+ sequences.push(remaining[0]);
2285
+ pos++;
2286
+ }
2287
+ }
2288
+ return { sequences, remainder: "" };
2289
+ }
2290
+
2291
+ class StdinBuffer extends EventEmitter {
2292
+ buffer = "";
2293
+ timeout = null;
2294
+ timeoutMs;
2295
+ stdin;
2296
+ stdinListener;
2297
+ constructor(stdin, options = {}) {
2298
+ super();
2299
+ this.stdin = stdin;
2300
+ this.timeoutMs = options.timeout ?? 10;
2301
+ this.stdinListener = (data) => {
2302
+ this.handleData(data);
2303
+ };
2304
+ this.stdin.on("data", this.stdinListener);
2305
+ }
2306
+ handleData(data) {
2307
+ if (this.timeout) {
2308
+ clearTimeout(this.timeout);
2309
+ this.timeout = null;
2310
+ }
2311
+ let str;
2312
+ if (Buffer.isBuffer(data)) {
2313
+ if (data.length === 1 && data[0] > 127) {
2314
+ const byte = data[0] - 128;
2315
+ str = "\x1B" + String.fromCharCode(byte);
2316
+ } else {
2317
+ str = data.toString();
2318
+ }
2319
+ } else {
2320
+ str = data;
2321
+ }
2322
+ if (str.length === 0 && this.buffer.length === 0) {
2323
+ this.emit("data", "");
2324
+ return;
2325
+ }
2326
+ this.buffer += str;
2327
+ const result = extractCompleteSequences(this.buffer);
2328
+ this.buffer = result.remainder;
2329
+ for (const sequence of result.sequences) {
2330
+ this.emit("data", sequence);
2331
+ }
2332
+ if (this.buffer.length > 0) {
2333
+ this.timeout = setTimeout(() => {
2334
+ const flushed = this.flush();
2335
+ for (const sequence of flushed) {
2336
+ this.emit("data", sequence);
2337
+ }
2338
+ }, this.timeoutMs);
2339
+ }
2340
+ }
2341
+ flush() {
2342
+ if (this.timeout) {
2343
+ clearTimeout(this.timeout);
2344
+ this.timeout = null;
2345
+ }
2346
+ if (this.buffer.length === 0) {
2347
+ return [];
2348
+ }
2349
+ const sequences = [this.buffer];
2350
+ this.buffer = "";
2351
+ return sequences;
2352
+ }
2353
+ clear() {
2354
+ if (this.timeout) {
2355
+ clearTimeout(this.timeout);
2356
+ this.timeout = null;
2357
+ }
2358
+ this.buffer = "";
2359
+ }
2360
+ getBuffer() {
2361
+ return this.buffer;
2362
+ }
2363
+ destroy() {
2364
+ this.stdin.removeListener("data", this.stdinListener);
2365
+ this.clear();
2366
+ }
2367
+ }
2368
+
2369
+ // src/lib/KeyHandler.ts
2370
+ import { EventEmitter as EventEmitter2 } from "events";
2190
2371
 
2191
2372
  // src/ansi.ts
2192
2373
  var ANSI = {
@@ -2214,6 +2395,7 @@ class KeyEvent {
2214
2395
  number;
2215
2396
  raw;
2216
2397
  eventType;
2398
+ source;
2217
2399
  code;
2218
2400
  super;
2219
2401
  hyper;
@@ -2231,6 +2413,7 @@ class KeyEvent {
2231
2413
  this.number = key.number;
2232
2414
  this.raw = key.raw;
2233
2415
  this.eventType = key.eventType;
2416
+ this.source = key.source;
2234
2417
  this.code = key.code;
2235
2418
  this.super = key.super;
2236
2419
  this.hyper = key.hyper;
@@ -2260,65 +2443,70 @@ class PasteEvent {
2260
2443
  }
2261
2444
  }
2262
2445
 
2263
- class KeyHandler extends EventEmitter {
2446
+ class KeyHandler extends EventEmitter2 {
2264
2447
  stdin;
2265
2448
  useKittyKeyboard;
2266
- listener;
2267
2449
  pasteMode = false;
2268
2450
  pasteBuffer = [];
2269
2451
  suspended = false;
2452
+ stdinBuffer;
2453
+ dataListener;
2270
2454
  constructor(stdin, useKittyKeyboard = false) {
2271
2455
  super();
2272
2456
  this.stdin = stdin || process.stdin;
2273
2457
  this.useKittyKeyboard = useKittyKeyboard;
2274
- this.listener = (key) => {
2275
- let data = key.toString();
2276
- if (data.startsWith(ANSI.bracketedPasteStart)) {
2277
- this.pasteMode = true;
2278
- }
2279
- if (this.pasteMode) {
2280
- this.pasteBuffer.push(Bun.stripANSI(data));
2281
- if (data.endsWith(ANSI.bracketedPasteEnd)) {
2282
- this.pasteMode = false;
2283
- this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
2284
- this.pasteBuffer = [];
2285
- }
2286
- return;
2287
- }
2288
- const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2289
- if (!parsedKey) {
2290
- return;
2291
- }
2292
- switch (parsedKey.eventType) {
2293
- case "press":
2294
- this.emit("keypress", new KeyEvent(parsedKey));
2295
- break;
2296
- case "repeat":
2297
- this.emit("keyrepeat", new KeyEvent(parsedKey));
2298
- break;
2299
- case "release":
2300
- this.emit("keyrelease", new KeyEvent(parsedKey));
2301
- break;
2302
- default:
2303
- this.emit("keypress", new KeyEvent(parsedKey));
2304
- break;
2305
- }
2458
+ this.stdinBuffer = new StdinBuffer(this.stdin, { timeout: 5 });
2459
+ this.dataListener = (sequence) => {
2460
+ this.processSequence(sequence);
2306
2461
  };
2307
- this.stdin.on("data", this.listener);
2462
+ this.stdinBuffer.on("data", this.dataListener);
2463
+ }
2464
+ processSequence(data) {
2465
+ if (data.startsWith(ANSI.bracketedPasteStart)) {
2466
+ this.pasteMode = true;
2467
+ }
2468
+ if (this.pasteMode) {
2469
+ this.pasteBuffer.push(Bun.stripANSI(data));
2470
+ if (data.endsWith(ANSI.bracketedPasteEnd)) {
2471
+ this.pasteMode = false;
2472
+ this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
2473
+ this.pasteBuffer = [];
2474
+ }
2475
+ return;
2476
+ }
2477
+ const parsedKey = parseKeypress(data, { useKittyKeyboard: this.useKittyKeyboard });
2478
+ if (!parsedKey) {
2479
+ return;
2480
+ }
2481
+ switch (parsedKey.eventType) {
2482
+ case "press":
2483
+ this.emit("keypress", new KeyEvent(parsedKey));
2484
+ break;
2485
+ case "repeat":
2486
+ this.emit("keyrepeat", new KeyEvent(parsedKey));
2487
+ break;
2488
+ case "release":
2489
+ this.emit("keyrelease", new KeyEvent(parsedKey));
2490
+ break;
2491
+ default:
2492
+ this.emit("keypress", new KeyEvent(parsedKey));
2493
+ break;
2494
+ }
2308
2495
  }
2309
2496
  destroy() {
2310
- this.stdin.removeListener("data", this.listener);
2497
+ this.stdinBuffer.removeListener("data", this.dataListener);
2498
+ this.stdinBuffer.destroy();
2311
2499
  }
2312
2500
  suspend() {
2313
2501
  if (!this.suspended) {
2314
2502
  this.suspended = true;
2315
- this.stdin.removeListener("data", this.listener);
2503
+ this.stdinBuffer.removeListener("data", this.dataListener);
2316
2504
  }
2317
2505
  }
2318
2506
  resume() {
2319
2507
  if (this.suspended) {
2320
2508
  this.suspended = false;
2321
- this.stdin.on("data", this.listener);
2509
+ this.stdinBuffer.on("data", this.dataListener);
2322
2510
  }
2323
2511
  }
2324
2512
  }
@@ -5112,19 +5300,141 @@ var env = new Proxy({}, {
5112
5300
  });
5113
5301
 
5114
5302
  // src/lib/tree-sitter-styled-text.ts
5115
- function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5303
+ registerEnvVar({ name: "OTUI_TS_STYLE_WARN", default: false, description: "Enable warnings for missing syntax styles" });
5304
+ function getSpecificity(group) {
5305
+ return group.split(".").length;
5306
+ }
5307
+ function shouldSuppressInInjection(group, meta) {
5308
+ if (meta?.isInjection) {
5309
+ return false;
5310
+ }
5311
+ return group === "markup.raw.block";
5312
+ }
5313
+ function treeSitterToTextChunks(content, highlights, syntaxStyle, options) {
5116
5314
  const chunks = [];
5117
5315
  const defaultStyle = syntaxStyle.getStyle("default");
5118
- let currentIndex = 0;
5316
+ const concealEnabled = options?.enabled ?? true;
5317
+ const injectionContainerRanges = [];
5318
+ const boundaries = [];
5119
5319
  for (let i = 0;i < highlights.length; i++) {
5120
- const [startIndex, endIndex, group] = highlights[i];
5121
- if (startIndex < currentIndex)
5320
+ const [start, end, , meta] = highlights[i];
5321
+ if (start === end)
5122
5322
  continue;
5123
- if (currentIndex < startIndex) {
5124
- const text2 = content.slice(currentIndex, startIndex);
5323
+ if (meta?.containsInjection) {
5324
+ injectionContainerRanges.push({ start, end });
5325
+ }
5326
+ boundaries.push({ offset: start, type: "start", highlightIndex: i });
5327
+ boundaries.push({ offset: end, type: "end", highlightIndex: i });
5328
+ }
5329
+ boundaries.sort((a, b) => {
5330
+ if (a.offset !== b.offset)
5331
+ return a.offset - b.offset;
5332
+ if (a.type === "end" && b.type === "start")
5333
+ return -1;
5334
+ if (a.type === "start" && b.type === "end")
5335
+ return 1;
5336
+ return 0;
5337
+ });
5338
+ const activeHighlights = new Set;
5339
+ let currentOffset = 0;
5340
+ for (let i = 0;i < boundaries.length; i++) {
5341
+ const boundary = boundaries[i];
5342
+ if (currentOffset < boundary.offset && activeHighlights.size > 0) {
5343
+ const segmentText = content.slice(currentOffset, boundary.offset);
5344
+ const activeGroups = [];
5345
+ for (const idx of activeHighlights) {
5346
+ const [, , group, meta] = highlights[idx];
5347
+ activeGroups.push({ group, meta, index: idx });
5348
+ }
5349
+ const concealHighlight = concealEnabled ? activeGroups.find((h) => h.meta?.conceal !== undefined || h.group === "conceal" || h.group.startsWith("conceal.")) : undefined;
5350
+ if (concealHighlight) {
5351
+ let replacementText = "";
5352
+ if (concealHighlight.meta?.conceal !== undefined) {
5353
+ replacementText = concealHighlight.meta.conceal;
5354
+ } else if (concealHighlight.group === "conceal.with.space") {
5355
+ replacementText = " ";
5356
+ }
5357
+ if (replacementText) {
5358
+ chunks.push({
5359
+ __isChunk: true,
5360
+ text: replacementText,
5361
+ fg: defaultStyle?.fg,
5362
+ bg: defaultStyle?.bg,
5363
+ attributes: defaultStyle ? createTextAttributes({
5364
+ bold: defaultStyle.bold,
5365
+ italic: defaultStyle.italic,
5366
+ underline: defaultStyle.underline,
5367
+ dim: defaultStyle.dim
5368
+ }) : 0
5369
+ });
5370
+ }
5371
+ } else {
5372
+ const insideInjectionContainer = injectionContainerRanges.some((range) => currentOffset >= range.start && currentOffset < range.end);
5373
+ const validGroups = activeGroups.filter((h) => {
5374
+ if (insideInjectionContainer && shouldSuppressInInjection(h.group, h.meta)) {
5375
+ return false;
5376
+ }
5377
+ return true;
5378
+ });
5379
+ const sortedGroups = validGroups.sort((a, b) => {
5380
+ const aSpec = getSpecificity(a.group);
5381
+ const bSpec = getSpecificity(b.group);
5382
+ if (aSpec !== bSpec)
5383
+ return aSpec - bSpec;
5384
+ return a.index - b.index;
5385
+ });
5386
+ const mergedStyle = {};
5387
+ for (const { group } of sortedGroups) {
5388
+ let styleForGroup = syntaxStyle.getStyle(group);
5389
+ if (!styleForGroup && group.includes(".")) {
5390
+ const baseName = group.split(".")[0];
5391
+ styleForGroup = syntaxStyle.getStyle(baseName);
5392
+ }
5393
+ if (styleForGroup) {
5394
+ if (styleForGroup.fg !== undefined)
5395
+ mergedStyle.fg = styleForGroup.fg;
5396
+ if (styleForGroup.bg !== undefined)
5397
+ mergedStyle.bg = styleForGroup.bg;
5398
+ if (styleForGroup.bold !== undefined)
5399
+ mergedStyle.bold = styleForGroup.bold;
5400
+ if (styleForGroup.italic !== undefined)
5401
+ mergedStyle.italic = styleForGroup.italic;
5402
+ if (styleForGroup.underline !== undefined)
5403
+ mergedStyle.underline = styleForGroup.underline;
5404
+ if (styleForGroup.dim !== undefined)
5405
+ mergedStyle.dim = styleForGroup.dim;
5406
+ } else {
5407
+ if (group.includes(".")) {
5408
+ const baseName = group.split(".")[0];
5409
+ if (env.OTUI_TS_STYLE_WARN) {
5410
+ console.warn(`Syntax style not found for group "${group}" or base scope "${baseName}", using default style`);
5411
+ }
5412
+ } else {
5413
+ if (env.OTUI_TS_STYLE_WARN) {
5414
+ console.warn(`Syntax style not found for group "${group}", using default style`);
5415
+ }
5416
+ }
5417
+ }
5418
+ }
5419
+ const finalStyle = Object.keys(mergedStyle).length > 0 ? mergedStyle : defaultStyle;
5420
+ chunks.push({
5421
+ __isChunk: true,
5422
+ text: segmentText,
5423
+ fg: finalStyle?.fg,
5424
+ bg: finalStyle?.bg,
5425
+ attributes: finalStyle ? createTextAttributes({
5426
+ bold: finalStyle.bold,
5427
+ italic: finalStyle.italic,
5428
+ underline: finalStyle.underline,
5429
+ dim: finalStyle.dim
5430
+ }) : 0
5431
+ });
5432
+ }
5433
+ } else if (currentOffset < boundary.offset) {
5434
+ const text = content.slice(currentOffset, boundary.offset);
5125
5435
  chunks.push({
5126
5436
  __isChunk: true,
5127
- text: text2,
5437
+ text,
5128
5438
  fg: defaultStyle?.fg,
5129
5439
  bg: defaultStyle?.bg,
5130
5440
  attributes: defaultStyle ? createTextAttributes({
@@ -5134,37 +5444,39 @@ function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5134
5444
  dim: defaultStyle.dim
5135
5445
  }) : 0
5136
5446
  });
5137
- currentIndex = startIndex;
5138
5447
  }
5139
- let resolvedStyle = syntaxStyle.getStyle(group);
5140
- let j = i + 1;
5141
- while (j < highlights.length && highlights[j][0] === startIndex) {
5142
- const [, , nextGroup] = highlights[j];
5143
- const nextStyle = syntaxStyle.getStyle(nextGroup);
5144
- if (nextStyle) {
5145
- resolvedStyle = nextStyle;
5448
+ if (boundary.type === "start") {
5449
+ activeHighlights.add(boundary.highlightIndex);
5450
+ } else {
5451
+ activeHighlights.delete(boundary.highlightIndex);
5452
+ if (concealEnabled) {
5453
+ const [, , group, meta] = highlights[boundary.highlightIndex];
5454
+ if (meta?.concealLines !== undefined) {
5455
+ if (boundary.offset < content.length && content[boundary.offset] === `
5456
+ `) {
5457
+ currentOffset = boundary.offset + 1;
5458
+ continue;
5459
+ }
5460
+ }
5461
+ if (meta?.conceal !== undefined) {
5462
+ if (meta.conceal === " ") {
5463
+ if (boundary.offset < content.length && content[boundary.offset] === " ") {
5464
+ currentOffset = boundary.offset + 1;
5465
+ continue;
5466
+ }
5467
+ } else if (meta.conceal === "" && group === "conceal" && !meta.isInjection) {
5468
+ if (boundary.offset < content.length && content[boundary.offset] === " ") {
5469
+ currentOffset = boundary.offset + 1;
5470
+ continue;
5471
+ }
5472
+ }
5473
+ }
5146
5474
  }
5147
- j++;
5148
5475
  }
5149
- i = j - 1;
5150
- const text = content.slice(startIndex, endIndex);
5151
- const styleToUse = resolvedStyle || defaultStyle;
5152
- chunks.push({
5153
- __isChunk: true,
5154
- text,
5155
- fg: styleToUse?.fg,
5156
- bg: styleToUse?.bg,
5157
- attributes: styleToUse ? createTextAttributes({
5158
- bold: styleToUse.bold,
5159
- italic: styleToUse.italic,
5160
- underline: styleToUse.underline,
5161
- dim: styleToUse.dim
5162
- }) : 0
5163
- });
5164
- currentIndex = endIndex;
5476
+ currentOffset = boundary.offset;
5165
5477
  }
5166
- if (currentIndex < content.length) {
5167
- const text = content.slice(currentIndex);
5478
+ if (currentOffset < content.length) {
5479
+ const text = content.slice(currentOffset);
5168
5480
  chunks.push({
5169
5481
  __isChunk: true,
5170
5482
  text,
@@ -5180,10 +5492,10 @@ function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5180
5492
  }
5181
5493
  return chunks;
5182
5494
  }
5183
- async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
5495
+ async function treeSitterToStyledText(content, filetype, syntaxStyle, client, options) {
5184
5496
  const result = await client.highlightOnce(content, filetype);
5185
5497
  if (result.highlights && result.highlights.length > 0) {
5186
- const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle);
5498
+ const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle, options?.conceal);
5187
5499
  return new StyledText(chunks);
5188
5500
  } else {
5189
5501
  const defaultStyle = syntaxStyle.mergeStyles("default");
@@ -5201,7 +5513,7 @@ async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
5201
5513
  }
5202
5514
 
5203
5515
  // src/lib/tree-sitter/client.ts
5204
- import { EventEmitter as EventEmitter2 } from "events";
5516
+ import { EventEmitter as EventEmitter3 } from "events";
5205
5517
 
5206
5518
  // src/lib/debounce.ts
5207
5519
  var TIMERS_MAP = new Map;
@@ -5314,6 +5626,11 @@ import javascript_highlights from "./assets/javascript/highlights.scm" with { ty
5314
5626
  import javascript_language from "./assets/javascript/tree-sitter-javascript.wasm" with { type: "file" };
5315
5627
  import typescript_highlights from "./assets/typescript/highlights.scm" with { type: "file" };
5316
5628
  import typescript_language from "./assets/typescript/tree-sitter-typescript.wasm" with { type: "file" };
5629
+ import markdown_highlights from "./assets/markdown/highlights.scm" with { type: "file" };
5630
+ import markdown_language from "./assets/markdown/tree-sitter-markdown.wasm" with { type: "file" };
5631
+ import markdown_injections from "./assets/markdown/injections.scm" with { type: "file" };
5632
+ import markdown_inline_highlights from "./assets/markdown_inline/highlights.scm" with { type: "file" };
5633
+ import markdown_inline_language from "./assets/markdown_inline/tree-sitter-markdown_inline.wasm" with { type: "file" };
5317
5634
  var _cachedParsers;
5318
5635
  function getParsers() {
5319
5636
  if (!_cachedParsers) {
@@ -5331,6 +5648,35 @@ function getParsers() {
5331
5648
  highlights: [resolve(dirname(fileURLToPath(import.meta.url)), typescript_highlights)]
5332
5649
  },
5333
5650
  wasm: resolve(dirname(fileURLToPath(import.meta.url)), typescript_language)
5651
+ },
5652
+ {
5653
+ filetype: "markdown",
5654
+ queries: {
5655
+ highlights: [resolve(dirname(fileURLToPath(import.meta.url)), markdown_highlights)],
5656
+ injections: [resolve(dirname(fileURLToPath(import.meta.url)), markdown_injections)]
5657
+ },
5658
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), markdown_language),
5659
+ injectionMapping: {
5660
+ nodeTypes: {
5661
+ inline: "markdown_inline",
5662
+ pipe_table_cell: "markdown_inline"
5663
+ },
5664
+ infoStringMap: {
5665
+ javascript: "javascript",
5666
+ js: "javascript",
5667
+ typescript: "typescript",
5668
+ ts: "typescript",
5669
+ markdown: "markdown",
5670
+ md: "markdown"
5671
+ }
5672
+ }
5673
+ },
5674
+ {
5675
+ filetype: "markdown_inline",
5676
+ queries: {
5677
+ highlights: [resolve(dirname(fileURLToPath(import.meta.url)), markdown_inline_highlights)]
5678
+ },
5679
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), markdown_inline_language)
5334
5680
  }
5335
5681
  ];
5336
5682
  }
@@ -5338,9 +5684,8 @@ function getParsers() {
5338
5684
  }
5339
5685
 
5340
5686
  // src/lib/tree-sitter/client.ts
5341
- import { resolve as resolve2, isAbsolute } from "path";
5687
+ import { resolve as resolve2, isAbsolute, parse } from "path";
5342
5688
  import { existsSync } from "fs";
5343
- import { parse } from "path";
5344
5689
  registerEnvVar({
5345
5690
  name: "OTUI_TREE_SITTER_WORKER_PATH",
5346
5691
  description: "Path to the TreeSitter worker",
@@ -5360,7 +5705,7 @@ function addDefaultParsers(parsers) {
5360
5705
  }
5361
5706
  var isUrl = (path) => path.startsWith("http://") || path.startsWith("https://");
5362
5707
 
5363
- class TreeSitterClient extends EventEmitter2 {
5708
+ class TreeSitterClient extends EventEmitter3 {
5364
5709
  initialized = false;
5365
5710
  worker;
5366
5711
  buffers = new Map;
@@ -5393,9 +5738,9 @@ class TreeSitterClient extends EventEmitter2 {
5393
5738
  }
5394
5739
  let worker_path;
5395
5740
  if (env.OTUI_TREE_SITTER_WORKER_PATH) {
5396
- worker_path = env.OTUI_TREE_SITTER_WORKER_PATH;
5741
+ worker_path = resolve2(env.OTUI_TREE_SITTER_WORKER_PATH);
5397
5742
  } else if (typeof OTUI_TREE_SITTER_WORKER_PATH !== "undefined") {
5398
- worker_path = OTUI_TREE_SITTER_WORKER_PATH;
5743
+ worker_path = resolve2(OTUI_TREE_SITTER_WORKER_PATH);
5399
5744
  } else if (this.options.workerPath) {
5400
5745
  worker_path = this.options.workerPath;
5401
5746
  } else {
@@ -5475,7 +5820,8 @@ class TreeSitterClient extends EventEmitter2 {
5475
5820
  ...filetypeParser,
5476
5821
  wasm: this.resolvePath(filetypeParser.wasm),
5477
5822
  queries: {
5478
- highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path))
5823
+ highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path)),
5824
+ injections: filetypeParser.queries.injections?.map((path) => this.resolvePath(path))
5479
5825
  }
5480
5826
  };
5481
5827
  this.worker?.postMessage({ type: "ADD_FILETYPE_PARSER", filetypeParser: resolvedParser });
@@ -5581,6 +5927,14 @@ class TreeSitterClient extends EventEmitter2 {
5581
5927
  }
5582
5928
  return;
5583
5929
  }
5930
+ if (type === "CLEAR_CACHE_RESPONSE") {
5931
+ const callback = this.messageCallbacks.get(messageId);
5932
+ if (callback) {
5933
+ this.messageCallbacks.delete(messageId);
5934
+ callback({ error });
5935
+ }
5936
+ return;
5937
+ }
5584
5938
  if (warning) {
5585
5939
  this.emitWarning(warning, bufferId);
5586
5940
  return;
@@ -5594,9 +5948,11 @@ class TreeSitterClient extends EventEmitter2 {
5594
5948
  const message = data.join(" ");
5595
5949
  this.emit("worker:log", logType, message);
5596
5950
  if (logType === "log") {
5597
- console.log("Worker stdout:", ...data);
5951
+ console.log("TSWorker:", ...data);
5598
5952
  } else if (logType === "error") {
5599
- console.error("Worker stderr:", ...data);
5953
+ console.error("TSWorker:", ...data);
5954
+ } else if (logType === "warn") {
5955
+ console.warn("TSWorker:", ...data);
5600
5956
  }
5601
5957
  return;
5602
5958
  }
@@ -5776,12 +6132,31 @@ class TreeSitterClient extends EventEmitter2 {
5776
6132
  });
5777
6133
  }
5778
6134
  }
6135
+ async clearCache() {
6136
+ if (!this.initialized || !this.worker) {
6137
+ throw new Error("Cannot clear cache: client is not initialized");
6138
+ }
6139
+ const messageId = `clear_cache_${this.messageIdCounter++}`;
6140
+ return new Promise((resolve3, reject) => {
6141
+ this.messageCallbacks.set(messageId, (response) => {
6142
+ if (response.error) {
6143
+ reject(new Error(response.error));
6144
+ } else {
6145
+ resolve3();
6146
+ }
6147
+ });
6148
+ this.worker.postMessage({
6149
+ type: "CLEAR_CACHE",
6150
+ messageId
6151
+ });
6152
+ });
6153
+ }
5779
6154
  }
5780
6155
 
5781
6156
  // src/lib/data-paths.ts
5782
6157
  import os from "os";
5783
6158
  import path from "path";
5784
- import { EventEmitter as EventEmitter3 } from "events";
6159
+ import { EventEmitter as EventEmitter4 } from "events";
5785
6160
 
5786
6161
  // src/lib/validate-dir-name.ts
5787
6162
  function isValidDirectoryName(name) {
@@ -5845,7 +6220,7 @@ registerEnvVar({
5845
6220
  default: ""
5846
6221
  });
5847
6222
 
5848
- class DataPathsManager extends EventEmitter3 {
6223
+ class DataPathsManager extends EventEmitter4 {
5849
6224
  _appName;
5850
6225
  _globalConfigPath;
5851
6226
  _globalConfigFile;
@@ -5929,6 +6304,24 @@ function extToFiletype(extension) {
5929
6304
  ["rs", "rust"],
5930
6305
  ["c", "c"],
5931
6306
  ["cpp", "cpp"],
6307
+ ["c++", "cpp"],
6308
+ ["cs", "csharp"],
6309
+ ["java", "java"],
6310
+ ["kt", "kotlin"],
6311
+ ["swift", "swift"],
6312
+ ["php", "php"],
6313
+ ["sql", "sql"],
6314
+ ["pl", "perl"],
6315
+ ["lua", "lua"],
6316
+ ["erl", "erlang"],
6317
+ ["exs", "elixir"],
6318
+ ["ex", "elixir"],
6319
+ ["elm", "elm"],
6320
+ ["fsharp", "fsharp"],
6321
+ ["fs", "fsharp"],
6322
+ ["fsx", "fsharp"],
6323
+ ["fsscript", "fsharp"],
6324
+ ["fsi", "fsharp"],
5932
6325
  ["h", "c"],
5933
6326
  ["hpp", "cpp"],
5934
6327
  ["html", "html"],
@@ -6071,17 +6464,35 @@ class DownloadUtils {
6071
6464
  }
6072
6465
 
6073
6466
  // src/lib/tree-sitter/assets/update.ts
6467
+ import { readdir } from "fs/promises";
6074
6468
  var __dirname = "/Users/runner/work/opentui/opentui/packages/core/src/lib/tree-sitter/assets";
6075
6469
  function getDefaultOptions() {
6076
6470
  return {
6077
- configPath: path3.resolve(__dirname, "../parsers-config.json"),
6471
+ configPath: path3.resolve(__dirname, "../parsers-config"),
6078
6472
  assetsDir: path3.resolve(__dirname),
6079
6473
  outputPath: path3.resolve(__dirname, "../default-parsers.ts")
6080
6474
  };
6081
6475
  }
6082
6476
  async function loadConfig(configPath) {
6083
- const configContent = await readFile(configPath, "utf-8");
6084
- return JSON.parse(configContent);
6477
+ let ext = path3.extname(configPath);
6478
+ let resolvedConfigPath = configPath;
6479
+ if (ext === "") {
6480
+ const files = await readdir(path3.dirname(configPath));
6481
+ const file = files.find((file2) => file2.startsWith(path3.basename(configPath)) && (file2.endsWith(".json") || file2.endsWith(".ts") || file2.endsWith(".js")));
6482
+ if (!file) {
6483
+ throw new Error(`No config file found for ${configPath}`);
6484
+ }
6485
+ resolvedConfigPath = path3.join(path3.dirname(configPath), file);
6486
+ ext = path3.extname(resolvedConfigPath);
6487
+ }
6488
+ if (ext === ".json") {
6489
+ const configContent = await readFile(resolvedConfigPath, "utf-8");
6490
+ return JSON.parse(configContent);
6491
+ } else if (ext === ".ts" || ext === ".js") {
6492
+ const { default: configContent } = await import(resolvedConfigPath);
6493
+ return configContent;
6494
+ }
6495
+ throw new Error(`Unsupported config file extension: ${ext}`);
6085
6496
  }
6086
6497
  async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6087
6498
  const languageDir = path3.join(assetsDir, filetype);
@@ -6093,53 +6504,85 @@ async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6093
6504
  }
6094
6505
  return "./" + path3.relative(path3.dirname(outputPath), languagePath);
6095
6506
  }
6096
- async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath) {
6507
+ async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath, queryType, configPath) {
6097
6508
  const queriesDir = path3.join(assetsDir, filetype);
6098
- const highlightsPath = path3.join(queriesDir, "highlights.scm");
6509
+ const queryPath = path3.join(queriesDir, `${queryType}.scm`);
6099
6510
  const queryContents = [];
6100
6511
  for (let i = 0;i < queryUrls.length; i++) {
6101
6512
  const queryUrl = queryUrls[i];
6102
- console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6103
- try {
6104
- const response = await fetch(queryUrl);
6105
- if (!response.ok) {
6106
- console.warn(`Failed to download query from ${queryUrl}: ${response.statusText}`);
6513
+ if (queryUrl.startsWith("./")) {
6514
+ console.log(` Using local query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6515
+ try {
6516
+ const localPath = path3.resolve(path3.dirname(configPath), queryUrl);
6517
+ const content = await readFile(localPath, "utf-8");
6518
+ if (content.trim()) {
6519
+ queryContents.push(content);
6520
+ console.log(` \u2713 Loaded ${content.split(`
6521
+ `).length} lines from local file`);
6522
+ }
6523
+ } catch (error) {
6524
+ console.warn(`Failed to read local query from ${queryUrl}: ${error}`);
6107
6525
  continue;
6108
6526
  }
6109
- const content = await response.text();
6110
- if (content.trim()) {
6111
- queryContents.push(`; Query from: ${queryUrl}
6527
+ } else {
6528
+ console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6529
+ try {
6530
+ const response = await fetch(queryUrl);
6531
+ if (!response.ok) {
6532
+ console.warn(`Failed to download query from ${queryUrl}: ${response.statusText}`);
6533
+ continue;
6534
+ }
6535
+ const content = await response.text();
6536
+ if (content.trim()) {
6537
+ queryContents.push(`; Query from: ${queryUrl}
6112
6538
  ${content}`);
6113
- console.log(` \u2713 Downloaded ${content.split(`
6539
+ console.log(` \u2713 Downloaded ${content.split(`
6114
6540
  `).length} lines`);
6541
+ }
6542
+ } catch (error) {
6543
+ console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6544
+ continue;
6115
6545
  }
6116
- } catch (error) {
6117
- console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6118
- continue;
6119
6546
  }
6120
6547
  }
6121
6548
  const combinedContent = queryContents.join(`
6122
6549
 
6123
6550
  `);
6124
- await writeFile2(highlightsPath, combinedContent, "utf-8");
6125
- console.log(` Combined ${queryContents.length} queries into ${highlightsPath}`);
6126
- return "./" + path3.relative(path3.dirname(outputPath), highlightsPath);
6551
+ await writeFile2(queryPath, combinedContent, "utf-8");
6552
+ console.log(` Combined ${queryContents.length} queries into ${queryPath}`);
6553
+ return "./" + path3.relative(path3.dirname(outputPath), queryPath);
6127
6554
  }
6128
6555
  async function generateDefaultParsersFile(parsers, outputPath) {
6129
6556
  const imports = parsers.map((parser) => {
6130
6557
  const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6131
- return `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }
6132
- import ${safeFiletype}_language from "${parser.languagePath}" with { type: "file" }`;
6558
+ const lines = [
6559
+ `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }`,
6560
+ `import ${safeFiletype}_language from "${parser.languagePath}" with { type: "file" }`
6561
+ ];
6562
+ if (parser.injectionsPath) {
6563
+ lines.push(`import ${safeFiletype}_injections from "${parser.injectionsPath}" with { type: "file" }`);
6564
+ }
6565
+ return lines.join(`
6566
+ `);
6133
6567
  }).join(`
6134
6568
  `);
6135
6569
  const parserDefinitions = parsers.map((parser) => {
6136
6570
  const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6571
+ const queriesLines = [
6572
+ ` highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],`
6573
+ ];
6574
+ if (parser.injectionsPath) {
6575
+ queriesLines.push(` injections: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_injections)],`);
6576
+ }
6577
+ const injectionMappingLine = parser.injectionMapping ? ` injectionMapping: ${JSON.stringify(parser.injectionMapping, null, 10)},` : "";
6137
6578
  return ` {
6138
6579
  filetype: "${parser.filetype}",
6139
6580
  queries: {
6140
- highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],
6581
+ ${queriesLines.join(`
6582
+ `)}
6141
6583
  },
6142
- wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),
6584
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),${injectionMappingLine ? `
6585
+ ` + injectionMappingLine : ""}
6143
6586
  }`;
6144
6587
  }).join(`,
6145
6588
  `);
@@ -6184,11 +6627,18 @@ async function main(options) {
6184
6627
  console.log(` Downloading language...`);
6185
6628
  const languagePath = await downloadLanguage(parser.filetype, parser.wasm, opts.assetsDir, opts.outputPath);
6186
6629
  console.log(` Downloading ${parser.queries.highlights.length} highlight queries...`);
6187
- const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath);
6630
+ const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath, "highlights", opts.configPath);
6631
+ let injectionsPath;
6632
+ if (parser.queries.injections && parser.queries.injections.length > 0) {
6633
+ console.log(` Downloading ${parser.queries.injections.length} injection queries...`);
6634
+ injectionsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.injections, opts.assetsDir, opts.outputPath, "injections", opts.configPath);
6635
+ }
6188
6636
  generatedParsers.push({
6189
6637
  filetype: parser.filetype,
6190
6638
  languagePath,
6191
- highlightsPath
6639
+ highlightsPath,
6640
+ injectionsPath,
6641
+ injectionMapping: parser.injectionMapping
6192
6642
  });
6193
6643
  console.log(` \u2713 Completed ${parser.filetype}`);
6194
6644
  }
@@ -6893,7 +7343,7 @@ function createExtmarksController(editBuffer, editorView) {
6893
7343
  // src/zig.ts
6894
7344
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr3 } from "bun:ffi";
6895
7345
  import { existsSync as existsSync2 } from "fs";
6896
- import { EventEmitter as EventEmitter4 } from "events";
7346
+ import { EventEmitter as EventEmitter5 } from "events";
6897
7347
 
6898
7348
  // src/buffer.ts
6899
7349
  import { toArrayBuffer } from "bun:ffi";
@@ -8073,6 +8523,10 @@ function getOpenTUILib(libPath) {
8073
8523
  args: ["ptr", "usize"],
8074
8524
  returns: "void"
8075
8525
  },
8526
+ textBufferGetHighlightCount: {
8527
+ args: ["ptr"],
8528
+ returns: "u32"
8529
+ },
8076
8530
  createTextBufferView: {
8077
8531
  args: ["ptr"],
8078
8532
  returns: "ptr"
@@ -8570,7 +9024,7 @@ class FFIRenderLib {
8570
9024
  decoder = new TextDecoder;
8571
9025
  logCallbackWrapper;
8572
9026
  eventCallbackWrapper;
8573
- _nativeEvents = new EventEmitter4;
9027
+ _nativeEvents = new EventEmitter5;
8574
9028
  _anyEventHandlers = [];
8575
9029
  constructor(libPath) {
8576
9030
  this.opentui = getOpenTUILib(libPath);
@@ -9118,6 +9572,9 @@ class FFIRenderLib {
9118
9572
  this.opentui.symbols.textBufferFreeLineHighlights(nativePtr, count);
9119
9573
  return results;
9120
9574
  }
9575
+ textBufferGetHighlightCount(buffer) {
9576
+ return this.opentui.symbols.textBufferGetHighlightCount(buffer);
9577
+ }
9121
9578
  getArenaAllocatedBytes() {
9122
9579
  const result = this.opentui.symbols.getArenaAllocatedBytes();
9123
9580
  return typeof result === "bigint" ? Number(result) : result;
@@ -9657,6 +10114,10 @@ class TextBuffer {
9657
10114
  this.guard();
9658
10115
  return this.lib.textBufferGetLineHighlights(this.bufferPtr, lineIdx);
9659
10116
  }
10117
+ getHighlightCount() {
10118
+ this.guard();
10119
+ return this.lib.textBufferGetHighlightCount(this.bufferPtr);
10120
+ }
9660
10121
  setSyntaxStyle(style) {
9661
10122
  this.guard();
9662
10123
  this._syntaxStyle = style ?? undefined;
@@ -9700,7 +10161,7 @@ class TextBuffer {
9700
10161
  }
9701
10162
 
9702
10163
  // src/Renderable.ts
9703
- import { EventEmitter as EventEmitter5 } from "events";
10164
+ import { EventEmitter as EventEmitter6 } from "events";
9704
10165
 
9705
10166
  // src/lib/renderable.validations.ts
9706
10167
  function validateOptions(id, options) {
@@ -9793,7 +10254,7 @@ function isRenderable(obj) {
9793
10254
  return !!obj?.[BrandedRenderable];
9794
10255
  }
9795
10256
 
9796
- class BaseRenderable extends EventEmitter5 {
10257
+ class BaseRenderable extends EventEmitter6 {
9797
10258
  [BrandedRenderable] = true;
9798
10259
  static renderableNumber = 1;
9799
10260
  _id;
@@ -11114,7 +11575,7 @@ function delegate(mapping, vnode) {
11114
11575
  }
11115
11576
 
11116
11577
  // src/console.ts
11117
- import { EventEmitter as EventEmitter7 } from "events";
11578
+ import { EventEmitter as EventEmitter8 } from "events";
11118
11579
  import { Console } from "console";
11119
11580
  import fs from "fs";
11120
11581
  import path4 from "path";
@@ -11122,9 +11583,9 @@ import util2 from "util";
11122
11583
 
11123
11584
  // src/lib/output.capture.ts
11124
11585
  import { Writable } from "stream";
11125
- import { EventEmitter as EventEmitter6 } from "events";
11586
+ import { EventEmitter as EventEmitter7 } from "events";
11126
11587
 
11127
- class Capture extends EventEmitter6 {
11588
+ class Capture extends EventEmitter7 {
11128
11589
  output = [];
11129
11590
  constructor() {
11130
11591
  super();
@@ -11200,7 +11661,7 @@ registerEnvVar({
11200
11661
  default: false
11201
11662
  });
11202
11663
 
11203
- class TerminalConsoleCache extends EventEmitter7 {
11664
+ class TerminalConsoleCache extends EventEmitter8 {
11204
11665
  _cachedLogs = [];
11205
11666
  MAX_CACHE_SIZE = 1000;
11206
11667
  _collectCallerInfo = false;
@@ -11326,7 +11787,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
11326
11787
  };
11327
11788
  var INDENT_WIDTH = 2;
11328
11789
 
11329
- class TerminalConsole extends EventEmitter7 {
11790
+ class TerminalConsole extends EventEmitter8 {
11330
11791
  isVisible = false;
11331
11792
  isFocused = false;
11332
11793
  renderer;
@@ -11415,34 +11876,34 @@ class TerminalConsole extends EventEmitter7 {
11415
11876
  }
11416
11877
  this.markNeedsRerender();
11417
11878
  }
11418
- _updateConsoleDimensions() {
11419
- const termWidth = this.renderer.terminalWidth;
11420
- const termHeight = this.renderer.terminalHeight;
11879
+ _updateConsoleDimensions(termWidth, termHeight) {
11880
+ const width = termWidth ?? this.renderer.terminalWidth;
11881
+ const height = termHeight ?? this.renderer.terminalHeight;
11421
11882
  const sizePercent = this.options.sizePercent / 100;
11422
11883
  switch (this.options.position) {
11423
11884
  case "top" /* TOP */:
11424
11885
  this.consoleX = 0;
11425
11886
  this.consoleY = 0;
11426
- this.consoleWidth = termWidth;
11427
- this.consoleHeight = Math.max(1, Math.floor(termHeight * sizePercent));
11887
+ this.consoleWidth = width;
11888
+ this.consoleHeight = Math.max(1, Math.floor(height * sizePercent));
11428
11889
  break;
11429
11890
  case "bottom" /* BOTTOM */:
11430
- this.consoleHeight = Math.max(1, Math.floor(termHeight * sizePercent));
11431
- this.consoleWidth = termWidth;
11891
+ this.consoleHeight = Math.max(1, Math.floor(height * sizePercent));
11892
+ this.consoleWidth = width;
11432
11893
  this.consoleX = 0;
11433
- this.consoleY = termHeight - this.consoleHeight;
11894
+ this.consoleY = height - this.consoleHeight;
11434
11895
  break;
11435
11896
  case "left" /* LEFT */:
11436
- this.consoleWidth = Math.max(1, Math.floor(termWidth * sizePercent));
11437
- this.consoleHeight = termHeight;
11897
+ this.consoleWidth = Math.max(1, Math.floor(width * sizePercent));
11898
+ this.consoleHeight = height;
11438
11899
  this.consoleX = 0;
11439
11900
  this.consoleY = 0;
11440
11901
  break;
11441
11902
  case "right" /* RIGHT */:
11442
- this.consoleWidth = Math.max(1, Math.floor(termWidth * sizePercent));
11443
- this.consoleHeight = termHeight;
11903
+ this.consoleWidth = Math.max(1, Math.floor(width * sizePercent));
11904
+ this.consoleHeight = height;
11444
11905
  this.consoleY = 0;
11445
- this.consoleX = termWidth - this.consoleWidth;
11906
+ this.consoleX = width - this.consoleWidth;
11446
11907
  break;
11447
11908
  }
11448
11909
  this.currentLineIndex = Math.max(0, Math.min(this.currentLineIndex, this.consoleHeight - 1));
@@ -11564,7 +12025,7 @@ class TerminalConsole extends EventEmitter7 {
11564
12025
  }).join(" ");
11565
12026
  }
11566
12027
  resize(width, height) {
11567
- this._updateConsoleDimensions();
12028
+ this._updateConsoleDimensions(width, height);
11568
12029
  if (this.frameBuffer) {
11569
12030
  this.frameBuffer.resize(this.consoleWidth, this.consoleHeight);
11570
12031
  const displayLineCount = this._displayLines.length;
@@ -11786,7 +12247,7 @@ class TerminalConsole extends EventEmitter7 {
11786
12247
  }
11787
12248
 
11788
12249
  // src/renderer.ts
11789
- import { EventEmitter as EventEmitter8 } from "events";
12250
+ import { EventEmitter as EventEmitter9 } from "events";
11790
12251
 
11791
12252
  // src/lib/objects-in-viewport.ts
11792
12253
  function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
@@ -12012,7 +12473,7 @@ var RendererControlState;
12012
12473
  RendererControlState2["EXPLICIT_STOPPED"] = "explicit_stopped";
12013
12474
  })(RendererControlState ||= {});
12014
12475
 
12015
- class CliRenderer extends EventEmitter8 {
12476
+ class CliRenderer extends EventEmitter9 {
12016
12477
  static animationFrameId = 0;
12017
12478
  lib;
12018
12479
  rendererPtr;
@@ -12191,6 +12652,14 @@ Captured output:
12191
12652
  this._console = new TerminalConsole(this, config.consoleOptions);
12192
12653
  this.useConsole = config.useConsole ?? true;
12193
12654
  this._keyHandler = new InternalKeyHandler(this.stdin, config.useKittyKeyboard ?? false);
12655
+ this._keyHandler.on("keypress", (event) => {
12656
+ if (this.exitOnCtrlC && event.name === "c" && event.ctrl) {
12657
+ process.nextTick(() => {
12658
+ this.destroy();
12659
+ });
12660
+ return;
12661
+ }
12662
+ });
12194
12663
  global.requestAnimationFrame = (callback) => {
12195
12664
  const id = CliRenderer.animationFrameId++;
12196
12665
  this.animationRequest.set(id, callback);
@@ -12450,12 +12919,6 @@ Captured output:
12450
12919
  return;
12451
12920
  }
12452
12921
  }
12453
- if (this.exitOnCtrlC && str === "\x03") {
12454
- process.nextTick(() => {
12455
- this.destroy();
12456
- });
12457
- return;
12458
- }
12459
12922
  if (this._useMouse && this.handleMouseData(data)) {
12460
12923
  return;
12461
12924
  }
@@ -13095,7 +13558,7 @@ Captured output:
13095
13558
  }
13096
13559
  }
13097
13560
 
13098
- 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, 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, ExtmarksController, createExtmarksController, 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, RendererControlState, CliRenderer };
13561
+ export { __toESM, __commonJS, __export, __require, Edge, Gutter, exports_src, BorderChars, getBorderFromSides, getBorderSides, borderCharsToArray, BorderCharArrays, nonAlphanumericKeys, parseKeypress, ANSI, StdinBuffer, 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, 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, ExtmarksController, createExtmarksController, 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, RendererControlState, CliRenderer };
13099
13562
 
13100
- //# debugId=33BCB77A44B43F2164756E2164756E21
13101
- //# sourceMappingURL=index-xn9k0wzm.js.map
13563
+ //# debugId=4704E8A57986003964756E2164756E21
13564
+ //# sourceMappingURL=index-rzgaxyf4.js.map