@opentui/core 0.1.31 → 0.1.32

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.
@@ -1769,10 +1769,10 @@ import { Buffer as Buffer2 } from "buffer";
1769
1769
  var kittyKeyMap = {
1770
1770
  27: "escape",
1771
1771
  9: "tab",
1772
- 13: "enter",
1772
+ 13: "return",
1773
1773
  127: "backspace",
1774
1774
  57344: "escape",
1775
- 57345: "enter",
1775
+ 57345: "return",
1776
1776
  57346: "tab",
1777
1777
  57347: "backspace",
1778
1778
  57348: "insert",
@@ -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;
@@ -2122,7 +2124,7 @@ var parseKeypress = (s = "", options = {}) => {
2122
2124
  } else if (s === `
2123
2125
  ` || s === `\x1B
2124
2126
  `) {
2125
- key.name = "enter";
2127
+ key.name = "linefeed";
2126
2128
  key.meta = s.length === 2;
2127
2129
  } else if (s === "\t") {
2128
2130
  key.name = "tab";
@@ -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
  }
@@ -5360,7 +5706,7 @@ function addDefaultParsers(parsers) {
5360
5706
  }
5361
5707
  var isUrl = (path) => path.startsWith("http://") || path.startsWith("https://");
5362
5708
 
5363
- class TreeSitterClient extends EventEmitter2 {
5709
+ class TreeSitterClient extends EventEmitter3 {
5364
5710
  initialized = false;
5365
5711
  worker;
5366
5712
  buffers = new Map;
@@ -5475,7 +5821,8 @@ class TreeSitterClient extends EventEmitter2 {
5475
5821
  ...filetypeParser,
5476
5822
  wasm: this.resolvePath(filetypeParser.wasm),
5477
5823
  queries: {
5478
- highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path))
5824
+ highlights: filetypeParser.queries.highlights.map((path) => this.resolvePath(path)),
5825
+ injections: filetypeParser.queries.injections?.map((path) => this.resolvePath(path))
5479
5826
  }
5480
5827
  };
5481
5828
  this.worker?.postMessage({ type: "ADD_FILETYPE_PARSER", filetypeParser: resolvedParser });
@@ -5581,6 +5928,14 @@ class TreeSitterClient extends EventEmitter2 {
5581
5928
  }
5582
5929
  return;
5583
5930
  }
5931
+ if (type === "CLEAR_CACHE_RESPONSE") {
5932
+ const callback = this.messageCallbacks.get(messageId);
5933
+ if (callback) {
5934
+ this.messageCallbacks.delete(messageId);
5935
+ callback({ error });
5936
+ }
5937
+ return;
5938
+ }
5584
5939
  if (warning) {
5585
5940
  this.emitWarning(warning, bufferId);
5586
5941
  return;
@@ -5594,9 +5949,11 @@ class TreeSitterClient extends EventEmitter2 {
5594
5949
  const message = data.join(" ");
5595
5950
  this.emit("worker:log", logType, message);
5596
5951
  if (logType === "log") {
5597
- console.log("Worker stdout:", ...data);
5952
+ console.log("TSWorker:", ...data);
5598
5953
  } else if (logType === "error") {
5599
- console.error("Worker stderr:", ...data);
5954
+ console.error("TSWorker:", ...data);
5955
+ } else if (logType === "warn") {
5956
+ console.warn("TSWorker:", ...data);
5600
5957
  }
5601
5958
  return;
5602
5959
  }
@@ -5776,12 +6133,31 @@ class TreeSitterClient extends EventEmitter2 {
5776
6133
  });
5777
6134
  }
5778
6135
  }
6136
+ async clearCache() {
6137
+ if (!this.initialized || !this.worker) {
6138
+ throw new Error("Cannot clear cache: client is not initialized");
6139
+ }
6140
+ const messageId = `clear_cache_${this.messageIdCounter++}`;
6141
+ return new Promise((resolve3, reject) => {
6142
+ this.messageCallbacks.set(messageId, (response) => {
6143
+ if (response.error) {
6144
+ reject(new Error(response.error));
6145
+ } else {
6146
+ resolve3();
6147
+ }
6148
+ });
6149
+ this.worker.postMessage({
6150
+ type: "CLEAR_CACHE",
6151
+ messageId
6152
+ });
6153
+ });
6154
+ }
5779
6155
  }
5780
6156
 
5781
6157
  // src/lib/data-paths.ts
5782
6158
  import os from "os";
5783
6159
  import path from "path";
5784
- import { EventEmitter as EventEmitter3 } from "events";
6160
+ import { EventEmitter as EventEmitter4 } from "events";
5785
6161
 
5786
6162
  // src/lib/validate-dir-name.ts
5787
6163
  function isValidDirectoryName(name) {
@@ -5845,7 +6221,7 @@ registerEnvVar({
5845
6221
  default: ""
5846
6222
  });
5847
6223
 
5848
- class DataPathsManager extends EventEmitter3 {
6224
+ class DataPathsManager extends EventEmitter4 {
5849
6225
  _appName;
5850
6226
  _globalConfigPath;
5851
6227
  _globalConfigFile;
@@ -5929,6 +6305,24 @@ function extToFiletype(extension) {
5929
6305
  ["rs", "rust"],
5930
6306
  ["c", "c"],
5931
6307
  ["cpp", "cpp"],
6308
+ ["c++", "cpp"],
6309
+ ["cs", "csharp"],
6310
+ ["java", "java"],
6311
+ ["kt", "kotlin"],
6312
+ ["swift", "swift"],
6313
+ ["php", "php"],
6314
+ ["sql", "sql"],
6315
+ ["pl", "perl"],
6316
+ ["lua", "lua"],
6317
+ ["erl", "erlang"],
6318
+ ["exs", "elixir"],
6319
+ ["ex", "elixir"],
6320
+ ["elm", "elm"],
6321
+ ["fsharp", "fsharp"],
6322
+ ["fs", "fsharp"],
6323
+ ["fsx", "fsharp"],
6324
+ ["fsscript", "fsharp"],
6325
+ ["fsi", "fsharp"],
5932
6326
  ["h", "c"],
5933
6327
  ["hpp", "cpp"],
5934
6328
  ["html", "html"],
@@ -6071,17 +6465,35 @@ class DownloadUtils {
6071
6465
  }
6072
6466
 
6073
6467
  // src/lib/tree-sitter/assets/update.ts
6468
+ import { readdir } from "fs/promises";
6074
6469
  var __dirname = "/Users/runner/work/opentui/opentui/packages/core/src/lib/tree-sitter/assets";
6075
6470
  function getDefaultOptions() {
6076
6471
  return {
6077
- configPath: path3.resolve(__dirname, "../parsers-config.json"),
6472
+ configPath: path3.resolve(__dirname, "../parsers-config"),
6078
6473
  assetsDir: path3.resolve(__dirname),
6079
6474
  outputPath: path3.resolve(__dirname, "../default-parsers.ts")
6080
6475
  };
6081
6476
  }
6082
6477
  async function loadConfig(configPath) {
6083
- const configContent = await readFile(configPath, "utf-8");
6084
- return JSON.parse(configContent);
6478
+ let ext = path3.extname(configPath);
6479
+ let resolvedConfigPath = configPath;
6480
+ if (ext === "") {
6481
+ const files = await readdir(path3.dirname(configPath));
6482
+ const file = files.find((file2) => file2.startsWith(path3.basename(configPath)) && (file2.endsWith(".json") || file2.endsWith(".ts") || file2.endsWith(".js")));
6483
+ if (!file) {
6484
+ throw new Error(`No config file found for ${configPath}`);
6485
+ }
6486
+ resolvedConfigPath = path3.join(path3.dirname(configPath), file);
6487
+ ext = path3.extname(resolvedConfigPath);
6488
+ }
6489
+ if (ext === ".json") {
6490
+ const configContent = await readFile(resolvedConfigPath, "utf-8");
6491
+ return JSON.parse(configContent);
6492
+ } else if (ext === ".ts" || ext === ".js") {
6493
+ const { default: configContent } = await import(resolvedConfigPath);
6494
+ return configContent;
6495
+ }
6496
+ throw new Error(`Unsupported config file extension: ${ext}`);
6085
6497
  }
6086
6498
  async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6087
6499
  const languageDir = path3.join(assetsDir, filetype);
@@ -6093,53 +6505,85 @@ async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6093
6505
  }
6094
6506
  return "./" + path3.relative(path3.dirname(outputPath), languagePath);
6095
6507
  }
6096
- async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath) {
6508
+ async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath, queryType, configPath) {
6097
6509
  const queriesDir = path3.join(assetsDir, filetype);
6098
- const highlightsPath = path3.join(queriesDir, "highlights.scm");
6510
+ const queryPath = path3.join(queriesDir, `${queryType}.scm`);
6099
6511
  const queryContents = [];
6100
6512
  for (let i = 0;i < queryUrls.length; i++) {
6101
6513
  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}`);
6514
+ if (queryUrl.startsWith("./")) {
6515
+ console.log(` Using local query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6516
+ try {
6517
+ const localPath = path3.resolve(path3.dirname(configPath), queryUrl);
6518
+ const content = await readFile(localPath, "utf-8");
6519
+ if (content.trim()) {
6520
+ queryContents.push(content);
6521
+ console.log(` \u2713 Loaded ${content.split(`
6522
+ `).length} lines from local file`);
6523
+ }
6524
+ } catch (error) {
6525
+ console.warn(`Failed to read local query from ${queryUrl}: ${error}`);
6107
6526
  continue;
6108
6527
  }
6109
- const content = await response.text();
6110
- if (content.trim()) {
6111
- queryContents.push(`; Query from: ${queryUrl}
6528
+ } else {
6529
+ console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6530
+ try {
6531
+ const response = await fetch(queryUrl);
6532
+ if (!response.ok) {
6533
+ console.warn(`Failed to download query from ${queryUrl}: ${response.statusText}`);
6534
+ continue;
6535
+ }
6536
+ const content = await response.text();
6537
+ if (content.trim()) {
6538
+ queryContents.push(`; Query from: ${queryUrl}
6112
6539
  ${content}`);
6113
- console.log(` \u2713 Downloaded ${content.split(`
6540
+ console.log(` \u2713 Downloaded ${content.split(`
6114
6541
  `).length} lines`);
6542
+ }
6543
+ } catch (error) {
6544
+ console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6545
+ continue;
6115
6546
  }
6116
- } catch (error) {
6117
- console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6118
- continue;
6119
6547
  }
6120
6548
  }
6121
6549
  const combinedContent = queryContents.join(`
6122
6550
 
6123
6551
  `);
6124
- await writeFile2(highlightsPath, combinedContent, "utf-8");
6125
- console.log(` Combined ${queryContents.length} queries into ${highlightsPath}`);
6126
- return "./" + path3.relative(path3.dirname(outputPath), highlightsPath);
6552
+ await writeFile2(queryPath, combinedContent, "utf-8");
6553
+ console.log(` Combined ${queryContents.length} queries into ${queryPath}`);
6554
+ return "./" + path3.relative(path3.dirname(outputPath), queryPath);
6127
6555
  }
6128
6556
  async function generateDefaultParsersFile(parsers, outputPath) {
6129
6557
  const imports = parsers.map((parser) => {
6130
6558
  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" }`;
6559
+ const lines = [
6560
+ `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }`,
6561
+ `import ${safeFiletype}_language from "${parser.languagePath}" with { type: "file" }`
6562
+ ];
6563
+ if (parser.injectionsPath) {
6564
+ lines.push(`import ${safeFiletype}_injections from "${parser.injectionsPath}" with { type: "file" }`);
6565
+ }
6566
+ return lines.join(`
6567
+ `);
6133
6568
  }).join(`
6134
6569
  `);
6135
6570
  const parserDefinitions = parsers.map((parser) => {
6136
6571
  const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6572
+ const queriesLines = [
6573
+ ` highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],`
6574
+ ];
6575
+ if (parser.injectionsPath) {
6576
+ queriesLines.push(` injections: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_injections)],`);
6577
+ }
6578
+ const injectionMappingLine = parser.injectionMapping ? ` injectionMapping: ${JSON.stringify(parser.injectionMapping, null, 10)},` : "";
6137
6579
  return ` {
6138
6580
  filetype: "${parser.filetype}",
6139
6581
  queries: {
6140
- highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],
6582
+ ${queriesLines.join(`
6583
+ `)}
6141
6584
  },
6142
- wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),
6585
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),${injectionMappingLine ? `
6586
+ ` + injectionMappingLine : ""}
6143
6587
  }`;
6144
6588
  }).join(`,
6145
6589
  `);
@@ -6184,11 +6628,18 @@ async function main(options) {
6184
6628
  console.log(` Downloading language...`);
6185
6629
  const languagePath = await downloadLanguage(parser.filetype, parser.wasm, opts.assetsDir, opts.outputPath);
6186
6630
  console.log(` Downloading ${parser.queries.highlights.length} highlight queries...`);
6187
- const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath);
6631
+ const highlightsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.highlights, opts.assetsDir, opts.outputPath, "highlights", opts.configPath);
6632
+ let injectionsPath;
6633
+ if (parser.queries.injections && parser.queries.injections.length > 0) {
6634
+ console.log(` Downloading ${parser.queries.injections.length} injection queries...`);
6635
+ injectionsPath = await downloadAndCombineQueries(parser.filetype, parser.queries.injections, opts.assetsDir, opts.outputPath, "injections", opts.configPath);
6636
+ }
6188
6637
  generatedParsers.push({
6189
6638
  filetype: parser.filetype,
6190
6639
  languagePath,
6191
- highlightsPath
6640
+ highlightsPath,
6641
+ injectionsPath,
6642
+ injectionMapping: parser.injectionMapping
6192
6643
  });
6193
6644
  console.log(` \u2713 Completed ${parser.filetype}`);
6194
6645
  }
@@ -6893,7 +7344,7 @@ function createExtmarksController(editBuffer, editorView) {
6893
7344
  // src/zig.ts
6894
7345
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr3 } from "bun:ffi";
6895
7346
  import { existsSync as existsSync2 } from "fs";
6896
- import { EventEmitter as EventEmitter4 } from "events";
7347
+ import { EventEmitter as EventEmitter5 } from "events";
6897
7348
 
6898
7349
  // src/buffer.ts
6899
7350
  import { toArrayBuffer } from "bun:ffi";
@@ -8001,6 +8452,14 @@ function getOpenTUILib(libPath) {
8001
8452
  args: ["ptr"],
8002
8453
  returns: "void"
8003
8454
  },
8455
+ textBufferGetTabWidth: {
8456
+ args: ["ptr"],
8457
+ returns: "u8"
8458
+ },
8459
+ textBufferSetTabWidth: {
8460
+ args: ["ptr", "u8"],
8461
+ returns: "void"
8462
+ },
8004
8463
  textBufferRegisterMemBuffer: {
8005
8464
  args: ["ptr", "ptr", "usize", "bool"],
8006
8465
  returns: "u16"
@@ -8065,6 +8524,10 @@ function getOpenTUILib(libPath) {
8065
8524
  args: ["ptr", "usize"],
8066
8525
  returns: "void"
8067
8526
  },
8527
+ textBufferGetHighlightCount: {
8528
+ args: ["ptr"],
8529
+ returns: "u32"
8530
+ },
8068
8531
  createTextBufferView: {
8069
8532
  args: ["ptr"],
8070
8533
  returns: "ptr"
@@ -8125,6 +8588,14 @@ function getOpenTUILib(libPath) {
8125
8588
  args: ["ptr", "ptr", "usize"],
8126
8589
  returns: "usize"
8127
8590
  },
8591
+ textBufferViewSetTabIndicator: {
8592
+ args: ["ptr", "u32"],
8593
+ returns: "void"
8594
+ },
8595
+ textBufferViewSetTabIndicatorColor: {
8596
+ args: ["ptr", "ptr"],
8597
+ returns: "void"
8598
+ },
8128
8599
  bufferDrawTextBufferView: {
8129
8600
  args: ["ptr", "ptr", "i32", "i32"],
8130
8601
  returns: "void"
@@ -8389,6 +8860,14 @@ function getOpenTUILib(libPath) {
8389
8860
  args: ["ptr", "ptr", "usize"],
8390
8861
  returns: "void"
8391
8862
  },
8863
+ editorViewSetTabIndicator: {
8864
+ args: ["ptr", "u32"],
8865
+ returns: "void"
8866
+ },
8867
+ editorViewSetTabIndicatorColor: {
8868
+ args: ["ptr", "ptr"],
8869
+ returns: "void"
8870
+ },
8392
8871
  getArenaAllocatedBytes: {
8393
8872
  args: [],
8394
8873
  returns: "usize"
@@ -8546,7 +9025,7 @@ class FFIRenderLib {
8546
9025
  decoder = new TextDecoder;
8547
9026
  logCallbackWrapper;
8548
9027
  eventCallbackWrapper;
8549
- _nativeEvents = new EventEmitter4;
9028
+ _nativeEvents = new EventEmitter5;
8550
9029
  _anyEventHandlers = [];
8551
9030
  constructor(libPath) {
8552
9031
  this.opentui = getOpenTUILib(libPath);
@@ -8897,6 +9376,12 @@ class FFIRenderLib {
8897
9376
  textBufferResetDefaults(buffer) {
8898
9377
  this.opentui.symbols.textBufferResetDefaults(buffer);
8899
9378
  }
9379
+ textBufferGetTabWidth(buffer) {
9380
+ return this.opentui.symbols.textBufferGetTabWidth(buffer);
9381
+ }
9382
+ textBufferSetTabWidth(buffer, width) {
9383
+ this.opentui.symbols.textBufferSetTabWidth(buffer, width);
9384
+ }
8900
9385
  textBufferRegisterMemBuffer(buffer, bytes, owned = false) {
8901
9386
  const result = this.opentui.symbols.textBufferRegisterMemBuffer(buffer, bytes, bytes.length, owned);
8902
9387
  if (result === 65535) {
@@ -9050,6 +9535,12 @@ class FFIRenderLib {
9050
9535
  }
9051
9536
  return outBuffer.slice(0, actualLen);
9052
9537
  }
9538
+ textBufferViewSetTabIndicator(view, indicator) {
9539
+ this.opentui.symbols.textBufferViewSetTabIndicator(view, indicator);
9540
+ }
9541
+ textBufferViewSetTabIndicatorColor(view, color) {
9542
+ this.opentui.symbols.textBufferViewSetTabIndicatorColor(view, color.buffer);
9543
+ }
9053
9544
  textBufferAddHighlightByCharRange(buffer, highlight) {
9054
9545
  const packedHighlight = HighlightStruct.pack(highlight);
9055
9546
  this.opentui.symbols.textBufferAddHighlightByCharRange(buffer, ptr3(packedHighlight));
@@ -9082,6 +9573,9 @@ class FFIRenderLib {
9082
9573
  this.opentui.symbols.textBufferFreeLineHighlights(nativePtr, count);
9083
9574
  return results;
9084
9575
  }
9576
+ textBufferGetHighlightCount(buffer) {
9577
+ return this.opentui.symbols.textBufferGetHighlightCount(buffer);
9578
+ }
9085
9579
  getArenaAllocatedBytes() {
9086
9580
  const result = this.opentui.symbols.getArenaAllocatedBytes();
9087
9581
  return typeof result === "bigint" ? Number(result) : result;
@@ -9459,6 +9953,12 @@ class FFIRenderLib {
9459
9953
  const chunksBuffer = StyledChunkStruct.packList(nonEmptyChunks);
9460
9954
  this.opentui.symbols.editorViewSetPlaceholderStyledText(view, ptr3(chunksBuffer), nonEmptyChunks.length);
9461
9955
  }
9956
+ editorViewSetTabIndicator(view, indicator) {
9957
+ this.opentui.symbols.editorViewSetTabIndicator(view, indicator);
9958
+ }
9959
+ editorViewSetTabIndicatorColor(view, color) {
9960
+ this.opentui.symbols.editorViewSetTabIndicatorColor(view, color.buffer);
9961
+ }
9462
9962
  onNativeEvent(name, handler) {
9463
9963
  this._nativeEvents.on(name, handler);
9464
9964
  }
@@ -9615,6 +10115,10 @@ class TextBuffer {
9615
10115
  this.guard();
9616
10116
  return this.lib.textBufferGetLineHighlights(this.bufferPtr, lineIdx);
9617
10117
  }
10118
+ getHighlightCount() {
10119
+ this.guard();
10120
+ return this.lib.textBufferGetHighlightCount(this.bufferPtr);
10121
+ }
9618
10122
  setSyntaxStyle(style) {
9619
10123
  this.guard();
9620
10124
  this._syntaxStyle = style ?? undefined;
@@ -9624,6 +10128,14 @@ class TextBuffer {
9624
10128
  this.guard();
9625
10129
  return this._syntaxStyle ?? null;
9626
10130
  }
10131
+ setTabWidth(width) {
10132
+ this.guard();
10133
+ this.lib.textBufferSetTabWidth(this.bufferPtr, width);
10134
+ }
10135
+ getTabWidth() {
10136
+ this.guard();
10137
+ return this.lib.textBufferGetTabWidth(this.bufferPtr);
10138
+ }
9627
10139
  clear() {
9628
10140
  this.guard();
9629
10141
  this.lib.textBufferClear(this.bufferPtr);
@@ -9650,7 +10162,7 @@ class TextBuffer {
9650
10162
  }
9651
10163
 
9652
10164
  // src/Renderable.ts
9653
- import { EventEmitter as EventEmitter5 } from "events";
10165
+ import { EventEmitter as EventEmitter6 } from "events";
9654
10166
 
9655
10167
  // src/lib/renderable.validations.ts
9656
10168
  function validateOptions(id, options) {
@@ -9743,7 +10255,7 @@ function isRenderable(obj) {
9743
10255
  return !!obj?.[BrandedRenderable];
9744
10256
  }
9745
10257
 
9746
- class BaseRenderable extends EventEmitter5 {
10258
+ class BaseRenderable extends EventEmitter6 {
9747
10259
  [BrandedRenderable] = true;
9748
10260
  static renderableNumber = 1;
9749
10261
  _id;
@@ -11064,7 +11576,7 @@ function delegate(mapping, vnode) {
11064
11576
  }
11065
11577
 
11066
11578
  // src/console.ts
11067
- import { EventEmitter as EventEmitter7 } from "events";
11579
+ import { EventEmitter as EventEmitter8 } from "events";
11068
11580
  import { Console } from "console";
11069
11581
  import fs from "fs";
11070
11582
  import path4 from "path";
@@ -11072,9 +11584,9 @@ import util2 from "util";
11072
11584
 
11073
11585
  // src/lib/output.capture.ts
11074
11586
  import { Writable } from "stream";
11075
- import { EventEmitter as EventEmitter6 } from "events";
11587
+ import { EventEmitter as EventEmitter7 } from "events";
11076
11588
 
11077
- class Capture extends EventEmitter6 {
11589
+ class Capture extends EventEmitter7 {
11078
11590
  output = [];
11079
11591
  constructor() {
11080
11592
  super();
@@ -11150,7 +11662,7 @@ registerEnvVar({
11150
11662
  default: false
11151
11663
  });
11152
11664
 
11153
- class TerminalConsoleCache extends EventEmitter7 {
11665
+ class TerminalConsoleCache extends EventEmitter8 {
11154
11666
  _cachedLogs = [];
11155
11667
  MAX_CACHE_SIZE = 1000;
11156
11668
  _collectCallerInfo = false;
@@ -11276,7 +11788,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
11276
11788
  };
11277
11789
  var INDENT_WIDTH = 2;
11278
11790
 
11279
- class TerminalConsole extends EventEmitter7 {
11791
+ class TerminalConsole extends EventEmitter8 {
11280
11792
  isVisible = false;
11281
11793
  isFocused = false;
11282
11794
  renderer;
@@ -11736,7 +12248,7 @@ class TerminalConsole extends EventEmitter7 {
11736
12248
  }
11737
12249
 
11738
12250
  // src/renderer.ts
11739
- import { EventEmitter as EventEmitter8 } from "events";
12251
+ import { EventEmitter as EventEmitter9 } from "events";
11740
12252
 
11741
12253
  // src/lib/objects-in-viewport.ts
11742
12254
  function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
@@ -11962,7 +12474,7 @@ var RendererControlState;
11962
12474
  RendererControlState2["EXPLICIT_STOPPED"] = "explicit_stopped";
11963
12475
  })(RendererControlState ||= {});
11964
12476
 
11965
- class CliRenderer extends EventEmitter8 {
12477
+ class CliRenderer extends EventEmitter9 {
11966
12478
  static animationFrameId = 0;
11967
12479
  lib;
11968
12480
  rendererPtr;
@@ -12141,6 +12653,14 @@ Captured output:
12141
12653
  this._console = new TerminalConsole(this, config.consoleOptions);
12142
12654
  this.useConsole = config.useConsole ?? true;
12143
12655
  this._keyHandler = new InternalKeyHandler(this.stdin, config.useKittyKeyboard ?? false);
12656
+ this._keyHandler.on("keypress", (event) => {
12657
+ if (this.exitOnCtrlC && event.name === "c" && event.ctrl) {
12658
+ process.nextTick(() => {
12659
+ this.destroy();
12660
+ });
12661
+ return;
12662
+ }
12663
+ });
12144
12664
  global.requestAnimationFrame = (callback) => {
12145
12665
  const id = CliRenderer.animationFrameId++;
12146
12666
  this.animationRequest.set(id, callback);
@@ -12400,12 +12920,6 @@ Captured output:
12400
12920
  return;
12401
12921
  }
12402
12922
  }
12403
- if (this.exitOnCtrlC && str === "\x03") {
12404
- process.nextTick(() => {
12405
- this.destroy();
12406
- });
12407
- return;
12408
- }
12409
12923
  if (this._useMouse && this.handleMouseData(data)) {
12410
12924
  return;
12411
12925
  }
@@ -13045,7 +13559,7 @@ Captured output:
13045
13559
  }
13046
13560
  }
13047
13561
 
13048
- 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 };
13562
+ 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 };
13049
13563
 
13050
- //# debugId=6145BB5C85305CD464756E2164756E21
13051
- //# sourceMappingURL=index-91qheh74.js.map
13564
+ //# debugId=F6CF4AF7A66F05DD64756E2164756E21
13565
+ //# sourceMappingURL=index-3f9h747j.js.map