@opentui/core 0.1.30 → 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.
Files changed (40) hide show
  1. package/3d.js +1 -1
  2. package/Renderable.d.ts +4 -4
  3. package/assets/markdown/highlights.scm +150 -0
  4. package/assets/markdown/injections.scm +27 -0
  5. package/assets/markdown/tree-sitter-markdown.wasm +0 -0
  6. package/assets/markdown_inline/highlights.scm +115 -0
  7. package/assets/markdown_inline/tree-sitter-markdown_inline.wasm +0 -0
  8. package/edit-buffer.d.ts +13 -12
  9. package/editor-view.d.ts +10 -0
  10. package/{index-0qmm1k4p.js → index-3f9h747j.js} +1424 -186
  11. package/index-3f9h747j.js.map +56 -0
  12. package/index.js +314 -83
  13. package/index.js.map +14 -14
  14. package/lib/KeyHandler.d.ts +4 -1
  15. package/lib/extmarks-history.d.ts +17 -0
  16. package/lib/extmarks.d.ts +88 -0
  17. package/lib/index.d.ts +2 -0
  18. package/lib/parse.keypress.d.ts +2 -1
  19. package/lib/stdin-buffer.d.ts +42 -0
  20. package/lib/tree-sitter/client.d.ts +1 -0
  21. package/lib/tree-sitter/parsers-config.d.ts +38 -0
  22. package/lib/tree-sitter/types.d.ts +18 -1
  23. package/lib/tree-sitter-styled-text.d.ts +9 -2
  24. package/package.json +9 -9
  25. package/parser.worker.js +250 -27
  26. package/parser.worker.js.map +3 -3
  27. package/renderables/Box.d.ts +1 -0
  28. package/renderables/Code.d.ts +14 -0
  29. package/renderables/EditBufferRenderable.d.ts +20 -4
  30. package/renderables/TextBufferRenderable.d.ts +10 -0
  31. package/renderables/Textarea.d.ts +21 -13
  32. package/renderer.d.ts +1 -0
  33. package/syntax-style.d.ts +2 -0
  34. package/testing/mock-keys.d.ts +22 -61
  35. package/testing.js +36 -78
  36. package/testing.js.map +3 -3
  37. package/text-buffer-view.d.ts +2 -0
  38. package/text-buffer.d.ts +3 -0
  39. package/zig.d.ts +29 -7
  40. package/index-0qmm1k4p.js.map +0 -53
@@ -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,
@@ -2092,6 +2093,12 @@ var parseKeypress = (s = "", options = {}) => {
2092
2093
  } else if (!s) {
2093
2094
  s = "";
2094
2095
  }
2096
+ if (/^\x1b\[<\d+;\d+;\d+[Mm]$/.test(s)) {
2097
+ return null;
2098
+ }
2099
+ if (s.startsWith("\x1B[M") && s.length >= 6) {
2100
+ return null;
2101
+ }
2095
2102
  const key = {
2096
2103
  name: "",
2097
2104
  ctrl: false,
@@ -2101,20 +2108,24 @@ var parseKeypress = (s = "", options = {}) => {
2101
2108
  number: false,
2102
2109
  sequence: s,
2103
2110
  raw: s,
2104
- eventType: "press"
2111
+ eventType: "press",
2112
+ source: "raw"
2105
2113
  };
2106
2114
  key.sequence = key.sequence || s || key.name;
2107
- if (options.useKittyKeyboard && /^\x1b\[.*u$/.test(s)) {
2115
+ if (options.useKittyKeyboard) {
2108
2116
  const kittyResult = parseKittyKeyboard(s);
2109
2117
  if (kittyResult) {
2110
2118
  return kittyResult;
2111
2119
  }
2112
2120
  }
2113
- if (s === "\r") {
2121
+ if (s === "\r" || s === "\x1B\r") {
2114
2122
  key.name = "return";
2123
+ key.meta = s.length === 2;
2115
2124
  } else if (s === `
2125
+ ` || s === `\x1B
2116
2126
  `) {
2117
- key.name = "enter";
2127
+ key.name = "linefeed";
2128
+ key.meta = s.length === 2;
2118
2129
  } else if (s === "\t") {
2119
2130
  key.name = "tab";
2120
2131
  } else if (s === "\b" || s === "\x1B\b" || s === "\x7F" || s === "\x1B\x7F") {
@@ -2126,6 +2137,9 @@ var parseKeypress = (s = "", options = {}) => {
2126
2137
  } else if (s === " " || s === "\x1B ") {
2127
2138
  key.name = "space";
2128
2139
  key.meta = s.length === 2;
2140
+ } else if (s === "\x00") {
2141
+ key.name = "space";
2142
+ key.ctrl = true;
2129
2143
  } else if (s.length === 1 && s <= "\x1A") {
2130
2144
  key.name = String.fromCharCode(s.charCodeAt(0) + 97 - 1);
2131
2145
  key.ctrl = true;
@@ -2176,8 +2190,184 @@ var parseKeypress = (s = "", options = {}) => {
2176
2190
  return key;
2177
2191
  };
2178
2192
 
2179
- // src/lib/KeyHandler.ts
2193
+ // src/lib/stdin-buffer.ts
2180
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";
2181
2371
 
2182
2372
  // src/ansi.ts
2183
2373
  var ANSI = {
@@ -2205,6 +2395,7 @@ class KeyEvent {
2205
2395
  number;
2206
2396
  raw;
2207
2397
  eventType;
2398
+ source;
2208
2399
  code;
2209
2400
  super;
2210
2401
  hyper;
@@ -2222,6 +2413,7 @@ class KeyEvent {
2222
2413
  this.number = key.number;
2223
2414
  this.raw = key.raw;
2224
2415
  this.eventType = key.eventType;
2416
+ this.source = key.source;
2225
2417
  this.code = key.code;
2226
2418
  this.super = key.super;
2227
2419
  this.hyper = key.hyper;
@@ -2251,62 +2443,70 @@ class PasteEvent {
2251
2443
  }
2252
2444
  }
2253
2445
 
2254
- class KeyHandler extends EventEmitter {
2446
+ class KeyHandler extends EventEmitter2 {
2255
2447
  stdin;
2256
2448
  useKittyKeyboard;
2257
- listener;
2258
2449
  pasteMode = false;
2259
2450
  pasteBuffer = [];
2260
2451
  suspended = false;
2452
+ stdinBuffer;
2453
+ dataListener;
2261
2454
  constructor(stdin, useKittyKeyboard = false) {
2262
2455
  super();
2263
2456
  this.stdin = stdin || process.stdin;
2264
2457
  this.useKittyKeyboard = useKittyKeyboard;
2265
- this.listener = (key) => {
2266
- let data = key.toString();
2267
- if (data.startsWith(ANSI.bracketedPasteStart)) {
2268
- this.pasteMode = true;
2269
- }
2270
- if (this.pasteMode) {
2271
- this.pasteBuffer.push(Bun.stripANSI(data));
2272
- if (data.endsWith(ANSI.bracketedPasteEnd)) {
2273
- this.pasteMode = false;
2274
- this.emit("paste", new PasteEvent(this.pasteBuffer.join("")));
2275
- this.pasteBuffer = [];
2276
- }
2277
- return;
2278
- }
2279
- const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2280
- switch (parsedKey.eventType) {
2281
- case "press":
2282
- this.emit("keypress", new KeyEvent(parsedKey));
2283
- break;
2284
- case "repeat":
2285
- this.emit("keyrepeat", new KeyEvent(parsedKey));
2286
- break;
2287
- case "release":
2288
- this.emit("keyrelease", new KeyEvent(parsedKey));
2289
- break;
2290
- default:
2291
- this.emit("keypress", new KeyEvent(parsedKey));
2292
- break;
2293
- }
2458
+ this.stdinBuffer = new StdinBuffer(this.stdin, { timeout: 5 });
2459
+ this.dataListener = (sequence) => {
2460
+ this.processSequence(sequence);
2294
2461
  };
2295
- 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
+ }
2296
2495
  }
2297
2496
  destroy() {
2298
- this.stdin.removeListener("data", this.listener);
2497
+ this.stdinBuffer.removeListener("data", this.dataListener);
2498
+ this.stdinBuffer.destroy();
2299
2499
  }
2300
2500
  suspend() {
2301
2501
  if (!this.suspended) {
2302
2502
  this.suspended = true;
2303
- this.stdin.removeListener("data", this.listener);
2503
+ this.stdinBuffer.removeListener("data", this.dataListener);
2304
2504
  }
2305
2505
  }
2306
2506
  resume() {
2307
2507
  if (this.suspended) {
2308
2508
  this.suspended = false;
2309
- this.stdin.on("data", this.listener);
2509
+ this.stdinBuffer.on("data", this.dataListener);
2310
2510
  }
2311
2511
  }
2312
2512
  }
@@ -5100,19 +5300,141 @@ var env = new Proxy({}, {
5100
5300
  });
5101
5301
 
5102
5302
  // src/lib/tree-sitter-styled-text.ts
5103
- 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) {
5104
5314
  const chunks = [];
5105
5315
  const defaultStyle = syntaxStyle.getStyle("default");
5106
- let currentIndex = 0;
5316
+ const concealEnabled = options?.enabled ?? true;
5317
+ const injectionContainerRanges = [];
5318
+ const boundaries = [];
5107
5319
  for (let i = 0;i < highlights.length; i++) {
5108
- const [startIndex, endIndex, group] = highlights[i];
5109
- if (startIndex < currentIndex)
5320
+ const [start, end, , meta] = highlights[i];
5321
+ if (start === end)
5110
5322
  continue;
5111
- if (currentIndex < startIndex) {
5112
- 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);
5113
5435
  chunks.push({
5114
5436
  __isChunk: true,
5115
- text: text2,
5437
+ text,
5116
5438
  fg: defaultStyle?.fg,
5117
5439
  bg: defaultStyle?.bg,
5118
5440
  attributes: defaultStyle ? createTextAttributes({
@@ -5122,37 +5444,39 @@ function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5122
5444
  dim: defaultStyle.dim
5123
5445
  }) : 0
5124
5446
  });
5125
- currentIndex = startIndex;
5126
5447
  }
5127
- let resolvedStyle = syntaxStyle.getStyle(group);
5128
- let j = i + 1;
5129
- while (j < highlights.length && highlights[j][0] === startIndex) {
5130
- const [, , nextGroup] = highlights[j];
5131
- const nextStyle = syntaxStyle.getStyle(nextGroup);
5132
- if (nextStyle) {
5133
- 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
+ }
5134
5474
  }
5135
- j++;
5136
5475
  }
5137
- i = j - 1;
5138
- const text = content.slice(startIndex, endIndex);
5139
- const styleToUse = resolvedStyle || defaultStyle;
5140
- chunks.push({
5141
- __isChunk: true,
5142
- text,
5143
- fg: styleToUse?.fg,
5144
- bg: styleToUse?.bg,
5145
- attributes: styleToUse ? createTextAttributes({
5146
- bold: styleToUse.bold,
5147
- italic: styleToUse.italic,
5148
- underline: styleToUse.underline,
5149
- dim: styleToUse.dim
5150
- }) : 0
5151
- });
5152
- currentIndex = endIndex;
5476
+ currentOffset = boundary.offset;
5153
5477
  }
5154
- if (currentIndex < content.length) {
5155
- const text = content.slice(currentIndex);
5478
+ if (currentOffset < content.length) {
5479
+ const text = content.slice(currentOffset);
5156
5480
  chunks.push({
5157
5481
  __isChunk: true,
5158
5482
  text,
@@ -5168,10 +5492,10 @@ function treeSitterToTextChunks(content, highlights, syntaxStyle) {
5168
5492
  }
5169
5493
  return chunks;
5170
5494
  }
5171
- async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
5495
+ async function treeSitterToStyledText(content, filetype, syntaxStyle, client, options) {
5172
5496
  const result = await client.highlightOnce(content, filetype);
5173
5497
  if (result.highlights && result.highlights.length > 0) {
5174
- const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle);
5498
+ const chunks = treeSitterToTextChunks(content, result.highlights, syntaxStyle, options?.conceal);
5175
5499
  return new StyledText(chunks);
5176
5500
  } else {
5177
5501
  const defaultStyle = syntaxStyle.mergeStyles("default");
@@ -5189,7 +5513,7 @@ async function treeSitterToStyledText(content, filetype, syntaxStyle, client) {
5189
5513
  }
5190
5514
 
5191
5515
  // src/lib/tree-sitter/client.ts
5192
- import { EventEmitter as EventEmitter2 } from "events";
5516
+ import { EventEmitter as EventEmitter3 } from "events";
5193
5517
 
5194
5518
  // src/lib/debounce.ts
5195
5519
  var TIMERS_MAP = new Map;
@@ -5302,6 +5626,11 @@ import javascript_highlights from "./assets/javascript/highlights.scm" with { ty
5302
5626
  import javascript_language from "./assets/javascript/tree-sitter-javascript.wasm" with { type: "file" };
5303
5627
  import typescript_highlights from "./assets/typescript/highlights.scm" with { type: "file" };
5304
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" };
5305
5634
  var _cachedParsers;
5306
5635
  function getParsers() {
5307
5636
  if (!_cachedParsers) {
@@ -5319,6 +5648,35 @@ function getParsers() {
5319
5648
  highlights: [resolve(dirname(fileURLToPath(import.meta.url)), typescript_highlights)]
5320
5649
  },
5321
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)
5322
5680
  }
5323
5681
  ];
5324
5682
  }
@@ -5348,7 +5706,7 @@ function addDefaultParsers(parsers) {
5348
5706
  }
5349
5707
  var isUrl = (path) => path.startsWith("http://") || path.startsWith("https://");
5350
5708
 
5351
- class TreeSitterClient extends EventEmitter2 {
5709
+ class TreeSitterClient extends EventEmitter3 {
5352
5710
  initialized = false;
5353
5711
  worker;
5354
5712
  buffers = new Map;
@@ -5463,7 +5821,8 @@ class TreeSitterClient extends EventEmitter2 {
5463
5821
  ...filetypeParser,
5464
5822
  wasm: this.resolvePath(filetypeParser.wasm),
5465
5823
  queries: {
5466
- 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))
5467
5826
  }
5468
5827
  };
5469
5828
  this.worker?.postMessage({ type: "ADD_FILETYPE_PARSER", filetypeParser: resolvedParser });
@@ -5569,6 +5928,14 @@ class TreeSitterClient extends EventEmitter2 {
5569
5928
  }
5570
5929
  return;
5571
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
+ }
5572
5939
  if (warning) {
5573
5940
  this.emitWarning(warning, bufferId);
5574
5941
  return;
@@ -5582,9 +5949,11 @@ class TreeSitterClient extends EventEmitter2 {
5582
5949
  const message = data.join(" ");
5583
5950
  this.emit("worker:log", logType, message);
5584
5951
  if (logType === "log") {
5585
- console.log("Worker stdout:", ...data);
5952
+ console.log("TSWorker:", ...data);
5586
5953
  } else if (logType === "error") {
5587
- console.error("Worker stderr:", ...data);
5954
+ console.error("TSWorker:", ...data);
5955
+ } else if (logType === "warn") {
5956
+ console.warn("TSWorker:", ...data);
5588
5957
  }
5589
5958
  return;
5590
5959
  }
@@ -5764,12 +6133,31 @@ class TreeSitterClient extends EventEmitter2 {
5764
6133
  });
5765
6134
  }
5766
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
+ }
5767
6155
  }
5768
6156
 
5769
6157
  // src/lib/data-paths.ts
5770
6158
  import os from "os";
5771
6159
  import path from "path";
5772
- import { EventEmitter as EventEmitter3 } from "events";
6160
+ import { EventEmitter as EventEmitter4 } from "events";
5773
6161
 
5774
6162
  // src/lib/validate-dir-name.ts
5775
6163
  function isValidDirectoryName(name) {
@@ -5833,7 +6221,7 @@ registerEnvVar({
5833
6221
  default: ""
5834
6222
  });
5835
6223
 
5836
- class DataPathsManager extends EventEmitter3 {
6224
+ class DataPathsManager extends EventEmitter4 {
5837
6225
  _appName;
5838
6226
  _globalConfigPath;
5839
6227
  _globalConfigFile;
@@ -5917,6 +6305,24 @@ function extToFiletype(extension) {
5917
6305
  ["rs", "rust"],
5918
6306
  ["c", "c"],
5919
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"],
5920
6326
  ["h", "c"],
5921
6327
  ["hpp", "cpp"],
5922
6328
  ["html", "html"],
@@ -6059,17 +6465,35 @@ class DownloadUtils {
6059
6465
  }
6060
6466
 
6061
6467
  // src/lib/tree-sitter/assets/update.ts
6468
+ import { readdir } from "fs/promises";
6062
6469
  var __dirname = "/Users/runner/work/opentui/opentui/packages/core/src/lib/tree-sitter/assets";
6063
6470
  function getDefaultOptions() {
6064
6471
  return {
6065
- configPath: path3.resolve(__dirname, "../parsers-config.json"),
6472
+ configPath: path3.resolve(__dirname, "../parsers-config"),
6066
6473
  assetsDir: path3.resolve(__dirname),
6067
6474
  outputPath: path3.resolve(__dirname, "../default-parsers.ts")
6068
6475
  };
6069
6476
  }
6070
6477
  async function loadConfig(configPath) {
6071
- const configContent = await readFile(configPath, "utf-8");
6072
- 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}`);
6073
6497
  }
6074
6498
  async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6075
6499
  const languageDir = path3.join(assetsDir, filetype);
@@ -6081,53 +6505,85 @@ async function downloadLanguage(filetype, languageUrl, assetsDir, outputPath) {
6081
6505
  }
6082
6506
  return "./" + path3.relative(path3.dirname(outputPath), languagePath);
6083
6507
  }
6084
- async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath) {
6508
+ async function downloadAndCombineQueries(filetype, queryUrls, assetsDir, outputPath, queryType, configPath) {
6085
6509
  const queriesDir = path3.join(assetsDir, filetype);
6086
- const highlightsPath = path3.join(queriesDir, "highlights.scm");
6510
+ const queryPath = path3.join(queriesDir, `${queryType}.scm`);
6087
6511
  const queryContents = [];
6088
6512
  for (let i = 0;i < queryUrls.length; i++) {
6089
6513
  const queryUrl = queryUrls[i];
6090
- console.log(` Downloading query ${i + 1}/${queryUrls.length}: ${queryUrl}`);
6091
- try {
6092
- const response = await fetch(queryUrl);
6093
- if (!response.ok) {
6094
- 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}`);
6095
6526
  continue;
6096
6527
  }
6097
- const content = await response.text();
6098
- if (content.trim()) {
6099
- 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}
6100
6539
  ${content}`);
6101
- console.log(` \u2713 Downloaded ${content.split(`
6540
+ console.log(` \u2713 Downloaded ${content.split(`
6102
6541
  `).length} lines`);
6542
+ }
6543
+ } catch (error) {
6544
+ console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6545
+ continue;
6103
6546
  }
6104
- } catch (error) {
6105
- console.warn(`Failed to download query from ${queryUrl}: ${error}`);
6106
- continue;
6107
6547
  }
6108
6548
  }
6109
6549
  const combinedContent = queryContents.join(`
6110
6550
 
6111
6551
  `);
6112
- await writeFile2(highlightsPath, combinedContent, "utf-8");
6113
- console.log(` Combined ${queryContents.length} queries into ${highlightsPath}`);
6114
- 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);
6115
6555
  }
6116
6556
  async function generateDefaultParsersFile(parsers, outputPath) {
6117
6557
  const imports = parsers.map((parser) => {
6118
6558
  const safeFiletype = parser.filetype.replace(/[^a-zA-Z0-9]/g, "_");
6119
- return `import ${safeFiletype}_highlights from "${parser.highlightsPath}" with { type: "file" }
6120
- 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
+ `);
6121
6568
  }).join(`
6122
6569
  `);
6123
6570
  const parserDefinitions = parsers.map((parser) => {
6124
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)},` : "";
6125
6579
  return ` {
6126
6580
  filetype: "${parser.filetype}",
6127
6581
  queries: {
6128
- highlights: [resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_highlights)],
6582
+ ${queriesLines.join(`
6583
+ `)}
6129
6584
  },
6130
- wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),
6585
+ wasm: resolve(dirname(fileURLToPath(import.meta.url)), ${safeFiletype}_language),${injectionMappingLine ? `
6586
+ ` + injectionMappingLine : ""}
6131
6587
  }`;
6132
6588
  }).join(`,
6133
6589
  `);
@@ -6172,11 +6628,18 @@ async function main(options) {
6172
6628
  console.log(` Downloading language...`);
6173
6629
  const languagePath = await downloadLanguage(parser.filetype, parser.wasm, opts.assetsDir, opts.outputPath);
6174
6630
  console.log(` Downloading ${parser.queries.highlights.length} highlight queries...`);
6175
- 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
+ }
6176
6637
  generatedParsers.push({
6177
6638
  filetype: parser.filetype,
6178
6639
  languagePath,
6179
- highlightsPath
6640
+ highlightsPath,
6641
+ injectionsPath,
6642
+ injectionMapping: parser.injectionMapping
6180
6643
  });
6181
6644
  console.log(` \u2713 Completed ${parser.filetype}`);
6182
6645
  }
@@ -6204,10 +6667,684 @@ function getTreeSitterClient() {
6204
6667
  return client2;
6205
6668
  });
6206
6669
  }
6670
+
6671
+ // src/lib/extmarks-history.ts
6672
+ class ExtmarksHistory {
6673
+ undoStack = [];
6674
+ redoStack = [];
6675
+ saveSnapshot(extmarks, nextId) {
6676
+ const snapshot = {
6677
+ extmarks: new Map(Array.from(extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
6678
+ nextId
6679
+ };
6680
+ this.undoStack.push(snapshot);
6681
+ this.redoStack = [];
6682
+ }
6683
+ undo() {
6684
+ if (this.undoStack.length === 0)
6685
+ return null;
6686
+ return this.undoStack.pop();
6687
+ }
6688
+ redo() {
6689
+ if (this.redoStack.length === 0)
6690
+ return null;
6691
+ return this.redoStack.pop();
6692
+ }
6693
+ pushRedo(snapshot) {
6694
+ this.redoStack.push(snapshot);
6695
+ }
6696
+ pushUndo(snapshot) {
6697
+ this.undoStack.push(snapshot);
6698
+ }
6699
+ clear() {
6700
+ this.undoStack = [];
6701
+ this.redoStack = [];
6702
+ }
6703
+ canUndo() {
6704
+ return this.undoStack.length > 0;
6705
+ }
6706
+ canRedo() {
6707
+ return this.redoStack.length > 0;
6708
+ }
6709
+ }
6710
+
6711
+ // src/lib/extmarks.ts
6712
+ class ExtmarksController {
6713
+ editBuffer;
6714
+ editorView;
6715
+ extmarks = new Map;
6716
+ extmarksByTypeId = new Map;
6717
+ metadata = new Map;
6718
+ nextId = 1;
6719
+ destroyed = false;
6720
+ history = new ExtmarksHistory;
6721
+ typeNameToId = new Map;
6722
+ typeIdToName = new Map;
6723
+ nextTypeId = 1;
6724
+ originalMoveCursorLeft;
6725
+ originalMoveCursorRight;
6726
+ originalSetCursorByOffset;
6727
+ originalMoveUpVisual;
6728
+ originalMoveDownVisual;
6729
+ originalDeleteCharBackward;
6730
+ originalDeleteChar;
6731
+ originalInsertText;
6732
+ originalInsertChar;
6733
+ originalDeleteRange;
6734
+ originalSetText;
6735
+ originalClear;
6736
+ originalNewLine;
6737
+ originalDeleteLine;
6738
+ originalEditorViewDeleteSelectedText;
6739
+ originalUndo;
6740
+ originalRedo;
6741
+ constructor(editBuffer, editorView) {
6742
+ this.editBuffer = editBuffer;
6743
+ this.editorView = editorView;
6744
+ this.originalMoveCursorLeft = editBuffer.moveCursorLeft.bind(editBuffer);
6745
+ this.originalMoveCursorRight = editBuffer.moveCursorRight.bind(editBuffer);
6746
+ this.originalSetCursorByOffset = editBuffer.setCursorByOffset.bind(editBuffer);
6747
+ this.originalMoveUpVisual = editorView.moveUpVisual.bind(editorView);
6748
+ this.originalMoveDownVisual = editorView.moveDownVisual.bind(editorView);
6749
+ this.originalDeleteCharBackward = editBuffer.deleteCharBackward.bind(editBuffer);
6750
+ this.originalDeleteChar = editBuffer.deleteChar.bind(editBuffer);
6751
+ this.originalInsertText = editBuffer.insertText.bind(editBuffer);
6752
+ this.originalInsertChar = editBuffer.insertChar.bind(editBuffer);
6753
+ this.originalDeleteRange = editBuffer.deleteRange.bind(editBuffer);
6754
+ this.originalSetText = editBuffer.setText.bind(editBuffer);
6755
+ this.originalClear = editBuffer.clear.bind(editBuffer);
6756
+ this.originalNewLine = editBuffer.newLine.bind(editBuffer);
6757
+ this.originalDeleteLine = editBuffer.deleteLine.bind(editBuffer);
6758
+ this.originalEditorViewDeleteSelectedText = editorView.deleteSelectedText.bind(editorView);
6759
+ this.originalUndo = editBuffer.undo.bind(editBuffer);
6760
+ this.originalRedo = editBuffer.redo.bind(editBuffer);
6761
+ this.wrapCursorMovement();
6762
+ this.wrapDeletion();
6763
+ this.wrapInsertion();
6764
+ this.wrapEditorViewDeleteSelectedText();
6765
+ this.wrapUndoRedo();
6766
+ this.setupContentChangeListener();
6767
+ }
6768
+ wrapCursorMovement() {
6769
+ this.editBuffer.moveCursorLeft = () => {
6770
+ if (this.destroyed) {
6771
+ this.originalMoveCursorLeft();
6772
+ return;
6773
+ }
6774
+ const currentOffset = this.editorView.getVisualCursor().offset;
6775
+ const hasSelection = this.editorView.hasSelection();
6776
+ if (hasSelection) {
6777
+ this.originalMoveCursorLeft();
6778
+ return;
6779
+ }
6780
+ const targetOffset = currentOffset - 1;
6781
+ if (targetOffset < 0) {
6782
+ this.originalMoveCursorLeft();
6783
+ return;
6784
+ }
6785
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6786
+ if (virtualExtmark && currentOffset >= virtualExtmark.end) {
6787
+ this.editBuffer.setCursorByOffset(virtualExtmark.start - 1);
6788
+ return;
6789
+ }
6790
+ this.originalMoveCursorLeft();
6791
+ };
6792
+ this.editBuffer.moveCursorRight = () => {
6793
+ if (this.destroyed) {
6794
+ this.originalMoveCursorRight();
6795
+ return;
6796
+ }
6797
+ const currentOffset = this.editorView.getVisualCursor().offset;
6798
+ const hasSelection = this.editorView.hasSelection();
6799
+ if (hasSelection) {
6800
+ this.originalMoveCursorRight();
6801
+ return;
6802
+ }
6803
+ const targetOffset = currentOffset + 1;
6804
+ const textLength = this.editBuffer.getText().length;
6805
+ if (targetOffset > textLength) {
6806
+ this.originalMoveCursorRight();
6807
+ return;
6808
+ }
6809
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6810
+ if (virtualExtmark && currentOffset <= virtualExtmark.start) {
6811
+ this.editBuffer.setCursorByOffset(virtualExtmark.end);
6812
+ return;
6813
+ }
6814
+ this.originalMoveCursorRight();
6815
+ };
6816
+ this.editorView.moveUpVisual = () => {
6817
+ if (this.destroyed) {
6818
+ this.originalMoveUpVisual();
6819
+ return;
6820
+ }
6821
+ const hasSelection = this.editorView.hasSelection();
6822
+ if (hasSelection) {
6823
+ this.originalMoveUpVisual();
6824
+ return;
6825
+ }
6826
+ const currentOffset = this.editorView.getVisualCursor().offset;
6827
+ this.originalMoveUpVisual();
6828
+ const newOffset = this.editorView.getVisualCursor().offset;
6829
+ const virtualExtmark = this.findVirtualExtmarkContaining(newOffset);
6830
+ if (virtualExtmark) {
6831
+ const distanceToStart = newOffset - virtualExtmark.start;
6832
+ const distanceToEnd = virtualExtmark.end - newOffset;
6833
+ if (distanceToStart < distanceToEnd) {
6834
+ this.editorView.setCursorByOffset(virtualExtmark.start - 1);
6835
+ } else {
6836
+ this.editorView.setCursorByOffset(virtualExtmark.end);
6837
+ }
6838
+ }
6839
+ };
6840
+ this.editorView.moveDownVisual = () => {
6841
+ if (this.destroyed) {
6842
+ this.originalMoveDownVisual();
6843
+ return;
6844
+ }
6845
+ const hasSelection = this.editorView.hasSelection();
6846
+ if (hasSelection) {
6847
+ this.originalMoveDownVisual();
6848
+ return;
6849
+ }
6850
+ this.originalMoveDownVisual();
6851
+ const newOffset = this.editorView.getVisualCursor().offset;
6852
+ const virtualExtmark = this.findVirtualExtmarkContaining(newOffset);
6853
+ if (virtualExtmark) {
6854
+ const distanceToStart = newOffset - virtualExtmark.start;
6855
+ const distanceToEnd = virtualExtmark.end - newOffset;
6856
+ if (distanceToStart < distanceToEnd) {
6857
+ this.editorView.setCursorByOffset(virtualExtmark.start - 1);
6858
+ } else {
6859
+ this.editorView.setCursorByOffset(virtualExtmark.end);
6860
+ }
6861
+ }
6862
+ };
6863
+ this.editBuffer.setCursorByOffset = (offset) => {
6864
+ if (this.destroyed) {
6865
+ this.originalSetCursorByOffset(offset);
6866
+ return;
6867
+ }
6868
+ const currentOffset = this.editorView.getVisualCursor().offset;
6869
+ const hasSelection = this.editorView.hasSelection();
6870
+ if (hasSelection) {
6871
+ this.originalSetCursorByOffset(offset);
6872
+ return;
6873
+ }
6874
+ const movingForward = offset > currentOffset;
6875
+ if (movingForward) {
6876
+ const virtualExtmark = this.findVirtualExtmarkContaining(offset);
6877
+ if (virtualExtmark && currentOffset <= virtualExtmark.start) {
6878
+ this.originalSetCursorByOffset(virtualExtmark.end);
6879
+ return;
6880
+ }
6881
+ } else {
6882
+ for (const extmark of this.extmarks.values()) {
6883
+ if (extmark.virtual && currentOffset >= extmark.end && offset < extmark.end && offset >= extmark.start) {
6884
+ this.originalSetCursorByOffset(extmark.start - 1);
6885
+ return;
6886
+ }
6887
+ }
6888
+ }
6889
+ this.originalSetCursorByOffset(offset);
6890
+ };
6891
+ }
6892
+ wrapDeletion() {
6893
+ this.editBuffer.deleteCharBackward = () => {
6894
+ if (this.destroyed) {
6895
+ this.originalDeleteCharBackward();
6896
+ return;
6897
+ }
6898
+ this.saveSnapshot();
6899
+ const currentOffset = this.editorView.getVisualCursor().offset;
6900
+ const hadSelection = this.editorView.hasSelection();
6901
+ if (currentOffset === 0) {
6902
+ this.originalDeleteCharBackward();
6903
+ return;
6904
+ }
6905
+ if (hadSelection) {
6906
+ this.originalDeleteCharBackward();
6907
+ return;
6908
+ }
6909
+ const targetOffset = currentOffset - 1;
6910
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6911
+ if (virtualExtmark && currentOffset === virtualExtmark.end) {
6912
+ const startCursor = this.offsetToPosition(virtualExtmark.start);
6913
+ const endCursor = this.offsetToPosition(virtualExtmark.end);
6914
+ const deleteOffset = virtualExtmark.start;
6915
+ const deleteLength = virtualExtmark.end - virtualExtmark.start;
6916
+ this.deleteExtmarkById(virtualExtmark.id);
6917
+ this.originalDeleteRange(startCursor.row, startCursor.col, endCursor.row, endCursor.col);
6918
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
6919
+ this.updateHighlights();
6920
+ return;
6921
+ }
6922
+ this.originalDeleteCharBackward();
6923
+ this.adjustExtmarksAfterDeletion(targetOffset, 1);
6924
+ };
6925
+ this.editBuffer.deleteChar = () => {
6926
+ if (this.destroyed) {
6927
+ this.originalDeleteChar();
6928
+ return;
6929
+ }
6930
+ this.saveSnapshot();
6931
+ const currentOffset = this.editorView.getVisualCursor().offset;
6932
+ const textLength = this.editBuffer.getText().length;
6933
+ const hadSelection = this.editorView.hasSelection();
6934
+ if (currentOffset >= textLength) {
6935
+ this.originalDeleteChar();
6936
+ return;
6937
+ }
6938
+ if (hadSelection) {
6939
+ this.originalDeleteChar();
6940
+ return;
6941
+ }
6942
+ const targetOffset = currentOffset;
6943
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6944
+ if (virtualExtmark && currentOffset === virtualExtmark.start) {
6945
+ const startCursor = this.offsetToPosition(virtualExtmark.start);
6946
+ const endCursor = this.offsetToPosition(virtualExtmark.end);
6947
+ const deleteOffset = virtualExtmark.start;
6948
+ const deleteLength = virtualExtmark.end - virtualExtmark.start;
6949
+ this.deleteExtmarkById(virtualExtmark.id);
6950
+ this.originalDeleteRange(startCursor.row, startCursor.col, endCursor.row, endCursor.col);
6951
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
6952
+ this.updateHighlights();
6953
+ return;
6954
+ }
6955
+ this.originalDeleteChar();
6956
+ this.adjustExtmarksAfterDeletion(targetOffset, 1);
6957
+ };
6958
+ this.editBuffer.deleteRange = (startLine, startCol, endLine, endCol) => {
6959
+ if (this.destroyed) {
6960
+ this.originalDeleteRange(startLine, startCol, endLine, endCol);
6961
+ return;
6962
+ }
6963
+ this.saveSnapshot();
6964
+ const startOffset = this.positionToOffset(startLine, startCol);
6965
+ const endOffset = this.positionToOffset(endLine, endCol);
6966
+ const length = endOffset - startOffset;
6967
+ this.originalDeleteRange(startLine, startCol, endLine, endCol);
6968
+ this.adjustExtmarksAfterDeletion(startOffset, length);
6969
+ };
6970
+ this.editBuffer.deleteLine = () => {
6971
+ if (this.destroyed) {
6972
+ this.originalDeleteLine();
6973
+ return;
6974
+ }
6975
+ this.saveSnapshot();
6976
+ const text = this.editBuffer.getText();
6977
+ const currentOffset = this.editorView.getVisualCursor().offset;
6978
+ let lineStart = 0;
6979
+ for (let i = currentOffset - 1;i >= 0; i--) {
6980
+ if (text[i] === `
6981
+ `) {
6982
+ lineStart = i + 1;
6983
+ break;
6984
+ }
6985
+ }
6986
+ let lineEnd = text.length;
6987
+ for (let i = currentOffset;i < text.length; i++) {
6988
+ if (text[i] === `
6989
+ `) {
6990
+ lineEnd = i + 1;
6991
+ break;
6992
+ }
6993
+ }
6994
+ const deleteLength = lineEnd - lineStart;
6995
+ this.originalDeleteLine();
6996
+ this.adjustExtmarksAfterDeletion(lineStart, deleteLength);
6997
+ };
6998
+ }
6999
+ wrapInsertion() {
7000
+ this.editBuffer.insertText = (text) => {
7001
+ if (this.destroyed) {
7002
+ this.originalInsertText(text);
7003
+ return;
7004
+ }
7005
+ this.saveSnapshot();
7006
+ const currentOffset = this.editorView.getVisualCursor().offset;
7007
+ this.originalInsertText(text);
7008
+ this.adjustExtmarksAfterInsertion(currentOffset, text.length);
7009
+ };
7010
+ this.editBuffer.insertChar = (char) => {
7011
+ if (this.destroyed) {
7012
+ this.originalInsertChar(char);
7013
+ return;
7014
+ }
7015
+ this.saveSnapshot();
7016
+ const currentOffset = this.editorView.getVisualCursor().offset;
7017
+ this.originalInsertChar(char);
7018
+ this.adjustExtmarksAfterInsertion(currentOffset, 1);
7019
+ };
7020
+ this.editBuffer.setText = (text, opts) => {
7021
+ if (this.destroyed) {
7022
+ this.originalSetText(text, opts);
7023
+ return;
7024
+ }
7025
+ if (opts?.history !== false) {
7026
+ this.saveSnapshot();
7027
+ }
7028
+ this.clear();
7029
+ this.originalSetText(text, opts);
7030
+ };
7031
+ this.editBuffer.clear = () => {
7032
+ if (this.destroyed) {
7033
+ this.originalClear();
7034
+ return;
7035
+ }
7036
+ this.saveSnapshot();
7037
+ this.clear();
7038
+ this.originalClear();
7039
+ };
7040
+ this.editBuffer.newLine = () => {
7041
+ if (this.destroyed) {
7042
+ this.originalNewLine();
7043
+ return;
7044
+ }
7045
+ this.saveSnapshot();
7046
+ const currentOffset = this.editorView.getVisualCursor().offset;
7047
+ this.originalNewLine();
7048
+ this.adjustExtmarksAfterInsertion(currentOffset, 1);
7049
+ };
7050
+ }
7051
+ wrapEditorViewDeleteSelectedText() {
7052
+ this.editorView.deleteSelectedText = () => {
7053
+ if (this.destroyed) {
7054
+ this.originalEditorViewDeleteSelectedText();
7055
+ return;
7056
+ }
7057
+ this.saveSnapshot();
7058
+ const selection = this.editorView.getSelection();
7059
+ if (!selection) {
7060
+ this.originalEditorViewDeleteSelectedText();
7061
+ return;
7062
+ }
7063
+ const deleteOffset = Math.min(selection.start, selection.end);
7064
+ const deleteLength = Math.abs(selection.end - selection.start);
7065
+ this.originalEditorViewDeleteSelectedText();
7066
+ if (deleteLength > 0) {
7067
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
7068
+ }
7069
+ };
7070
+ }
7071
+ setupContentChangeListener() {
7072
+ this.editBuffer.on("content-changed", () => {
7073
+ if (this.destroyed)
7074
+ return;
7075
+ this.updateHighlights();
7076
+ });
7077
+ }
7078
+ deleteExtmarkById(id) {
7079
+ const extmark = this.extmarks.get(id);
7080
+ if (extmark) {
7081
+ this.extmarks.delete(id);
7082
+ this.extmarksByTypeId.get(extmark.typeId)?.delete(id);
7083
+ this.metadata.delete(id);
7084
+ }
7085
+ }
7086
+ findVirtualExtmarkContaining(offset) {
7087
+ for (const extmark of this.extmarks.values()) {
7088
+ if (extmark.virtual && offset >= extmark.start && offset < extmark.end) {
7089
+ return extmark;
7090
+ }
7091
+ }
7092
+ return null;
7093
+ }
7094
+ adjustExtmarksAfterInsertion(insertOffset, length) {
7095
+ for (const extmark of this.extmarks.values()) {
7096
+ if (extmark.start >= insertOffset) {
7097
+ extmark.start += length;
7098
+ extmark.end += length;
7099
+ } else if (extmark.end > insertOffset) {
7100
+ extmark.end += length;
7101
+ }
7102
+ }
7103
+ this.updateHighlights();
7104
+ }
7105
+ adjustExtmarksAfterDeletion(deleteOffset, length) {
7106
+ const toDelete = [];
7107
+ for (const extmark of this.extmarks.values()) {
7108
+ if (extmark.end <= deleteOffset) {
7109
+ continue;
7110
+ }
7111
+ if (extmark.start >= deleteOffset + length) {
7112
+ extmark.start -= length;
7113
+ extmark.end -= length;
7114
+ } else if (extmark.start >= deleteOffset && extmark.end <= deleteOffset + length) {
7115
+ toDelete.push(extmark.id);
7116
+ } else if (extmark.start < deleteOffset && extmark.end > deleteOffset + length) {
7117
+ extmark.end -= length;
7118
+ } else if (extmark.start < deleteOffset && extmark.end > deleteOffset) {
7119
+ extmark.end -= Math.min(extmark.end, deleteOffset + length) - deleteOffset;
7120
+ } else if (extmark.start < deleteOffset + length && extmark.end > deleteOffset + length) {
7121
+ const overlap = deleteOffset + length - extmark.start;
7122
+ extmark.start = deleteOffset;
7123
+ extmark.end -= length;
7124
+ }
7125
+ }
7126
+ for (const id of toDelete) {
7127
+ this.deleteExtmarkById(id);
7128
+ }
7129
+ this.updateHighlights();
7130
+ }
7131
+ offsetToPosition(offset) {
7132
+ const result = this.editBuffer.offsetToPosition(offset);
7133
+ if (!result) {
7134
+ return { row: 0, col: 0 };
7135
+ }
7136
+ return result;
7137
+ }
7138
+ positionToOffset(row, col) {
7139
+ return this.editBuffer.positionToOffset(row, col);
7140
+ }
7141
+ updateHighlights() {
7142
+ this.editBuffer.clearAllHighlights();
7143
+ for (const extmark of this.extmarks.values()) {
7144
+ if (extmark.styleId !== undefined) {
7145
+ const startWithoutNewlines = this.offsetToCharOffset(extmark.start);
7146
+ const endWithoutNewlines = this.offsetToCharOffset(extmark.end);
7147
+ this.editBuffer.addHighlightByCharRange({
7148
+ start: startWithoutNewlines,
7149
+ end: endWithoutNewlines,
7150
+ styleId: extmark.styleId,
7151
+ priority: extmark.priority ?? 0,
7152
+ hlRef: extmark.id
7153
+ });
7154
+ }
7155
+ }
7156
+ }
7157
+ offsetToCharOffset(offset) {
7158
+ const text = this.editBuffer.getText();
7159
+ let charOffset = 0;
7160
+ for (let i = 0;i < offset && i < text.length; i++) {
7161
+ if (text[i] !== `
7162
+ `) {
7163
+ charOffset++;
7164
+ }
7165
+ }
7166
+ return charOffset;
7167
+ }
7168
+ create(options) {
7169
+ if (this.destroyed) {
7170
+ throw new Error("ExtmarksController is destroyed");
7171
+ }
7172
+ const id = this.nextId++;
7173
+ const typeId = options.typeId ?? 0;
7174
+ const extmark = {
7175
+ id,
7176
+ start: options.start,
7177
+ end: options.end,
7178
+ virtual: options.virtual ?? false,
7179
+ styleId: options.styleId,
7180
+ priority: options.priority,
7181
+ data: options.data,
7182
+ typeId
7183
+ };
7184
+ this.extmarks.set(id, extmark);
7185
+ if (!this.extmarksByTypeId.has(typeId)) {
7186
+ this.extmarksByTypeId.set(typeId, new Set);
7187
+ }
7188
+ this.extmarksByTypeId.get(typeId).add(id);
7189
+ if (options.metadata !== undefined) {
7190
+ this.metadata.set(id, options.metadata);
7191
+ }
7192
+ this.updateHighlights();
7193
+ return id;
7194
+ }
7195
+ delete(id) {
7196
+ if (this.destroyed) {
7197
+ throw new Error("ExtmarksController is destroyed");
7198
+ }
7199
+ const extmark = this.extmarks.get(id);
7200
+ if (!extmark)
7201
+ return false;
7202
+ this.deleteExtmarkById(id);
7203
+ this.updateHighlights();
7204
+ return true;
7205
+ }
7206
+ get(id) {
7207
+ if (this.destroyed)
7208
+ return null;
7209
+ return this.extmarks.get(id) ?? null;
7210
+ }
7211
+ getAll() {
7212
+ if (this.destroyed)
7213
+ return [];
7214
+ return Array.from(this.extmarks.values());
7215
+ }
7216
+ getVirtual() {
7217
+ if (this.destroyed)
7218
+ return [];
7219
+ return Array.from(this.extmarks.values()).filter((e) => e.virtual);
7220
+ }
7221
+ getAtOffset(offset) {
7222
+ if (this.destroyed)
7223
+ return [];
7224
+ return Array.from(this.extmarks.values()).filter((e) => offset >= e.start && offset < e.end);
7225
+ }
7226
+ getAllForTypeId(typeId) {
7227
+ if (this.destroyed)
7228
+ return [];
7229
+ const ids = this.extmarksByTypeId.get(typeId);
7230
+ if (!ids)
7231
+ return [];
7232
+ return Array.from(ids).map((id) => this.extmarks.get(id)).filter((e) => e !== undefined);
7233
+ }
7234
+ clear() {
7235
+ if (this.destroyed)
7236
+ return;
7237
+ this.extmarks.clear();
7238
+ this.extmarksByTypeId.clear();
7239
+ this.metadata.clear();
7240
+ this.updateHighlights();
7241
+ }
7242
+ saveSnapshot() {
7243
+ this.history.saveSnapshot(this.extmarks, this.nextId);
7244
+ }
7245
+ restoreSnapshot(snapshot) {
7246
+ this.extmarks = new Map(Array.from(snapshot.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }]));
7247
+ this.nextId = snapshot.nextId;
7248
+ this.updateHighlights();
7249
+ }
7250
+ wrapUndoRedo() {
7251
+ this.editBuffer.undo = () => {
7252
+ if (this.destroyed) {
7253
+ return this.originalUndo();
7254
+ }
7255
+ if (!this.history.canUndo()) {
7256
+ return this.originalUndo();
7257
+ }
7258
+ const currentSnapshot = {
7259
+ extmarks: new Map(Array.from(this.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
7260
+ nextId: this.nextId
7261
+ };
7262
+ this.history.pushRedo(currentSnapshot);
7263
+ const snapshot = this.history.undo();
7264
+ this.restoreSnapshot(snapshot);
7265
+ return this.originalUndo();
7266
+ };
7267
+ this.editBuffer.redo = () => {
7268
+ if (this.destroyed) {
7269
+ return this.originalRedo();
7270
+ }
7271
+ if (!this.history.canRedo()) {
7272
+ return this.originalRedo();
7273
+ }
7274
+ const currentSnapshot = {
7275
+ extmarks: new Map(Array.from(this.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
7276
+ nextId: this.nextId
7277
+ };
7278
+ this.history.pushUndo(currentSnapshot);
7279
+ const snapshot = this.history.redo();
7280
+ this.restoreSnapshot(snapshot);
7281
+ return this.originalRedo();
7282
+ };
7283
+ }
7284
+ registerType(typeName) {
7285
+ if (this.destroyed) {
7286
+ throw new Error("ExtmarksController is destroyed");
7287
+ }
7288
+ const existing = this.typeNameToId.get(typeName);
7289
+ if (existing !== undefined) {
7290
+ return existing;
7291
+ }
7292
+ const typeId = this.nextTypeId++;
7293
+ this.typeNameToId.set(typeName, typeId);
7294
+ this.typeIdToName.set(typeId, typeName);
7295
+ return typeId;
7296
+ }
7297
+ getTypeId(typeName) {
7298
+ if (this.destroyed)
7299
+ return null;
7300
+ return this.typeNameToId.get(typeName) ?? null;
7301
+ }
7302
+ getTypeName(typeId) {
7303
+ if (this.destroyed)
7304
+ return null;
7305
+ return this.typeIdToName.get(typeId) ?? null;
7306
+ }
7307
+ getMetadataFor(extmarkId) {
7308
+ if (this.destroyed)
7309
+ return;
7310
+ return this.metadata.get(extmarkId);
7311
+ }
7312
+ destroy() {
7313
+ if (this.destroyed)
7314
+ return;
7315
+ this.editBuffer.moveCursorLeft = this.originalMoveCursorLeft;
7316
+ this.editBuffer.moveCursorRight = this.originalMoveCursorRight;
7317
+ this.editBuffer.setCursorByOffset = this.originalSetCursorByOffset;
7318
+ this.editorView.moveUpVisual = this.originalMoveUpVisual;
7319
+ this.editorView.moveDownVisual = this.originalMoveDownVisual;
7320
+ this.editBuffer.deleteCharBackward = this.originalDeleteCharBackward;
7321
+ this.editBuffer.deleteChar = this.originalDeleteChar;
7322
+ this.editBuffer.insertText = this.originalInsertText;
7323
+ this.editBuffer.insertChar = this.originalInsertChar;
7324
+ this.editBuffer.deleteRange = this.originalDeleteRange;
7325
+ this.editBuffer.setText = this.originalSetText;
7326
+ this.editBuffer.clear = this.originalClear;
7327
+ this.editBuffer.newLine = this.originalNewLine;
7328
+ this.editBuffer.deleteLine = this.originalDeleteLine;
7329
+ this.editorView.deleteSelectedText = this.originalEditorViewDeleteSelectedText;
7330
+ this.editBuffer.undo = this.originalUndo;
7331
+ this.editBuffer.redo = this.originalRedo;
7332
+ this.extmarks.clear();
7333
+ this.extmarksByTypeId.clear();
7334
+ this.metadata.clear();
7335
+ this.typeNameToId.clear();
7336
+ this.typeIdToName.clear();
7337
+ this.history.clear();
7338
+ this.destroyed = true;
7339
+ }
7340
+ }
7341
+ function createExtmarksController(editBuffer, editorView) {
7342
+ return new ExtmarksController(editBuffer, editorView);
7343
+ }
6207
7344
  // src/zig.ts
6208
7345
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr3 } from "bun:ffi";
6209
7346
  import { existsSync as existsSync2 } from "fs";
6210
- import { EventEmitter as EventEmitter4 } from "events";
7347
+ import { EventEmitter as EventEmitter5 } from "events";
6211
7348
 
6212
7349
  // src/buffer.ts
6213
7350
  import { toArrayBuffer } from "bun:ffi";
@@ -7315,6 +8452,14 @@ function getOpenTUILib(libPath) {
7315
8452
  args: ["ptr"],
7316
8453
  returns: "void"
7317
8454
  },
8455
+ textBufferGetTabWidth: {
8456
+ args: ["ptr"],
8457
+ returns: "u8"
8458
+ },
8459
+ textBufferSetTabWidth: {
8460
+ args: ["ptr", "u8"],
8461
+ returns: "void"
8462
+ },
7318
8463
  textBufferRegisterMemBuffer: {
7319
8464
  args: ["ptr", "ptr", "usize", "bool"],
7320
8465
  returns: "u16"
@@ -7379,6 +8524,10 @@ function getOpenTUILib(libPath) {
7379
8524
  args: ["ptr", "usize"],
7380
8525
  returns: "void"
7381
8526
  },
8527
+ textBufferGetHighlightCount: {
8528
+ args: ["ptr"],
8529
+ returns: "u32"
8530
+ },
7382
8531
  createTextBufferView: {
7383
8532
  args: ["ptr"],
7384
8533
  returns: "ptr"
@@ -7439,6 +8588,14 @@ function getOpenTUILib(libPath) {
7439
8588
  args: ["ptr", "ptr", "usize"],
7440
8589
  returns: "usize"
7441
8590
  },
8591
+ textBufferViewSetTabIndicator: {
8592
+ args: ["ptr", "u32"],
8593
+ returns: "void"
8594
+ },
8595
+ textBufferViewSetTabIndicatorColor: {
8596
+ args: ["ptr", "ptr"],
8597
+ returns: "void"
8598
+ },
7442
8599
  bufferDrawTextBufferView: {
7443
8600
  args: ["ptr", "ptr", "i32", "i32"],
7444
8601
  returns: "void"
@@ -7483,6 +8640,14 @@ function getOpenTUILib(libPath) {
7483
8640
  args: ["ptr"],
7484
8641
  returns: "ptr"
7485
8642
  },
8643
+ editorViewGetLineInfoDirect: {
8644
+ args: ["ptr", "ptr", "ptr"],
8645
+ returns: "u32"
8646
+ },
8647
+ editorViewGetLogicalLineInfoDirect: {
8648
+ args: ["ptr", "ptr", "ptr"],
8649
+ returns: "u32"
8650
+ },
7486
8651
  createEditBuffer: {
7487
8652
  args: ["u8"],
7488
8653
  returns: "ptr"
@@ -7564,7 +8729,7 @@ function getOpenTUILib(libPath) {
7564
8729
  returns: "void"
7565
8730
  },
7566
8731
  editBufferGetCursorPosition: {
7567
- args: ["ptr", "ptr", "ptr", "ptr"],
8732
+ args: ["ptr", "ptr"],
7568
8733
  returns: "void"
7569
8734
  },
7570
8735
  editBufferGetId: {
@@ -7599,12 +8764,8 @@ function getOpenTUILib(libPath) {
7599
8764
  args: ["ptr"],
7600
8765
  returns: "void"
7601
8766
  },
7602
- editBufferSetPlaceholder: {
7603
- args: ["ptr", "ptr", "usize"],
7604
- returns: "void"
7605
- },
7606
- editBufferSetPlaceholderColor: {
7607
- args: ["ptr", "ptr"],
8767
+ editBufferClear: {
8768
+ args: ["ptr"],
7608
8769
  returns: "void"
7609
8770
  },
7610
8771
  editBufferGetNextWordBoundary: {
@@ -7619,6 +8780,18 @@ function getOpenTUILib(libPath) {
7619
8780
  args: ["ptr", "ptr"],
7620
8781
  returns: "void"
7621
8782
  },
8783
+ editBufferOffsetToPosition: {
8784
+ args: ["ptr", "u32", "ptr"],
8785
+ returns: "bool"
8786
+ },
8787
+ editBufferPositionToOffset: {
8788
+ args: ["ptr", "u32", "u32"],
8789
+ returns: "u32"
8790
+ },
8791
+ editBufferGetLineStartOffset: {
8792
+ args: ["ptr", "u32"],
8793
+ returns: "u32"
8794
+ },
7622
8795
  editorViewSetSelection: {
7623
8796
  args: ["ptr", "u32", "u32", "ptr", "ptr"],
7624
8797
  returns: "void"
@@ -7683,6 +8856,18 @@ function getOpenTUILib(libPath) {
7683
8856
  args: ["ptr", "ptr"],
7684
8857
  returns: "void"
7685
8858
  },
8859
+ editorViewSetPlaceholderStyledText: {
8860
+ args: ["ptr", "ptr", "usize"],
8861
+ returns: "void"
8862
+ },
8863
+ editorViewSetTabIndicator: {
8864
+ args: ["ptr", "u32"],
8865
+ returns: "void"
8866
+ },
8867
+ editorViewSetTabIndicatorColor: {
8868
+ args: ["ptr", "ptr"],
8869
+ returns: "void"
8870
+ },
7686
8871
  getArenaAllocatedBytes: {
7687
8872
  args: [],
7688
8873
  returns: "usize"
@@ -7840,7 +9025,7 @@ class FFIRenderLib {
7840
9025
  decoder = new TextDecoder;
7841
9026
  logCallbackWrapper;
7842
9027
  eventCallbackWrapper;
7843
- _nativeEvents = new EventEmitter4;
9028
+ _nativeEvents = new EventEmitter5;
7844
9029
  _anyEventHandlers = [];
7845
9030
  constructor(libPath) {
7846
9031
  this.opentui = getOpenTUILib(libPath);
@@ -8191,6 +9376,12 @@ class FFIRenderLib {
8191
9376
  textBufferResetDefaults(buffer) {
8192
9377
  this.opentui.symbols.textBufferResetDefaults(buffer);
8193
9378
  }
9379
+ textBufferGetTabWidth(buffer) {
9380
+ return this.opentui.symbols.textBufferGetTabWidth(buffer);
9381
+ }
9382
+ textBufferSetTabWidth(buffer, width) {
9383
+ this.opentui.symbols.textBufferSetTabWidth(buffer, width);
9384
+ }
8194
9385
  textBufferRegisterMemBuffer(buffer, bytes, owned = false) {
8195
9386
  const result = this.opentui.symbols.textBufferRegisterMemBuffer(buffer, bytes, bytes.length, owned);
8196
9387
  if (result === 65535) {
@@ -8344,6 +9535,12 @@ class FFIRenderLib {
8344
9535
  }
8345
9536
  return outBuffer.slice(0, actualLen);
8346
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
+ }
8347
9544
  textBufferAddHighlightByCharRange(buffer, highlight) {
8348
9545
  const packedHighlight = HighlightStruct.pack(highlight);
8349
9546
  this.opentui.symbols.textBufferAddHighlightByCharRange(buffer, ptr3(packedHighlight));
@@ -8376,6 +9573,9 @@ class FFIRenderLib {
8376
9573
  this.opentui.symbols.textBufferFreeLineHighlights(nativePtr, count);
8377
9574
  return results;
8378
9575
  }
9576
+ textBufferGetHighlightCount(buffer) {
9577
+ return this.opentui.symbols.textBufferGetHighlightCount(buffer);
9578
+ }
8379
9579
  getArenaAllocatedBytes() {
8380
9580
  const result = this.opentui.symbols.getArenaAllocatedBytes();
8381
9581
  return typeof result === "bigint" ? Number(result) : result;
@@ -8432,6 +9632,34 @@ class FFIRenderLib {
8432
9632
  }
8433
9633
  return result;
8434
9634
  }
9635
+ editorViewGetLineInfo(view) {
9636
+ const lineCount = this.editorViewGetVirtualLineCount(view);
9637
+ if (lineCount === 0) {
9638
+ return { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
9639
+ }
9640
+ const lineStarts = new Uint32Array(lineCount);
9641
+ const lineWidths = new Uint32Array(lineCount);
9642
+ const maxLineWidth = this.opentui.symbols.editorViewGetLineInfoDirect(view, ptr3(lineStarts), ptr3(lineWidths));
9643
+ return {
9644
+ maxLineWidth,
9645
+ lineStarts: Array.from(lineStarts),
9646
+ lineWidths: Array.from(lineWidths)
9647
+ };
9648
+ }
9649
+ editorViewGetLogicalLineInfo(view) {
9650
+ const lineCount = this.editorViewGetVirtualLineCount(view);
9651
+ if (lineCount === 0) {
9652
+ return { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
9653
+ }
9654
+ const lineStarts = new Uint32Array(lineCount);
9655
+ const lineWidths = new Uint32Array(lineCount);
9656
+ const maxLineWidth = this.opentui.symbols.editorViewGetLogicalLineInfoDirect(view, ptr3(lineStarts), ptr3(lineWidths));
9657
+ return {
9658
+ maxLineWidth,
9659
+ lineStarts: Array.from(lineStarts),
9660
+ lineWidths: Array.from(lineWidths)
9661
+ };
9662
+ }
8435
9663
  createEditBuffer(widthMethod) {
8436
9664
  const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1;
8437
9665
  const bufferPtr = this.opentui.symbols.createEditBuffer(widthMethodCode);
@@ -8505,15 +9733,9 @@ class FFIRenderLib {
8505
9733
  this.opentui.symbols.editBufferSetCursorByOffset(buffer, offset);
8506
9734
  }
8507
9735
  editBufferGetCursorPosition(buffer) {
8508
- const line = new Uint32Array(1);
8509
- const visualColumn = new Uint32Array(1);
8510
- const offset = new Uint32Array(1);
8511
- this.opentui.symbols.editBufferGetCursorPosition(buffer, ptr3(line), ptr3(visualColumn), ptr3(offset));
8512
- return {
8513
- line: line[0],
8514
- visualColumn: visualColumn[0],
8515
- offset: offset[0]
8516
- };
9736
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
9737
+ this.opentui.symbols.editBufferGetCursorPosition(buffer, ptr3(cursorBuffer));
9738
+ return LogicalCursorStruct.unpack(cursorBuffer);
8517
9739
  }
8518
9740
  editBufferGetId(buffer) {
8519
9741
  return this.opentui.symbols.editBufferGetId(buffer);
@@ -8553,16 +9775,8 @@ class FFIRenderLib {
8553
9775
  editBufferClearHistory(buffer) {
8554
9776
  this.opentui.symbols.editBufferClearHistory(buffer);
8555
9777
  }
8556
- editBufferSetPlaceholder(buffer, text) {
8557
- if (text === null) {
8558
- this.opentui.symbols.editBufferSetPlaceholder(buffer, null, 0);
8559
- } else {
8560
- const textBytes = this.encoder.encode(text);
8561
- this.opentui.symbols.editBufferSetPlaceholder(buffer, textBytes, textBytes.length);
8562
- }
8563
- }
8564
- editBufferSetPlaceholderColor(buffer, color) {
8565
- this.opentui.symbols.editBufferSetPlaceholderColor(buffer, color.buffer);
9778
+ editBufferClear(buffer) {
9779
+ this.opentui.symbols.editBufferClear(buffer);
8566
9780
  }
8567
9781
  editBufferGetNextWordBoundary(buffer) {
8568
9782
  const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
@@ -8579,6 +9793,19 @@ class FFIRenderLib {
8579
9793
  this.opentui.symbols.editBufferGetEOL(buffer, ptr3(cursorBuffer));
8580
9794
  return LogicalCursorStruct.unpack(cursorBuffer);
8581
9795
  }
9796
+ editBufferOffsetToPosition(buffer, offset) {
9797
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
9798
+ const success = this.opentui.symbols.editBufferOffsetToPosition(buffer, offset, ptr3(cursorBuffer));
9799
+ if (!success)
9800
+ return null;
9801
+ return LogicalCursorStruct.unpack(cursorBuffer);
9802
+ }
9803
+ editBufferPositionToOffset(buffer, row, col) {
9804
+ return this.opentui.symbols.editBufferPositionToOffset(buffer, row, col);
9805
+ }
9806
+ editBufferGetLineStartOffset(buffer, row) {
9807
+ return this.opentui.symbols.editBufferGetLineStartOffset(buffer, row);
9808
+ }
8582
9809
  editorViewSetSelection(view, start, end, bgColor, fgColor) {
8583
9810
  const bg2 = bgColor ? bgColor.buffer : null;
8584
9811
  const fg2 = fgColor ? fgColor.buffer : null;
@@ -8717,6 +9944,21 @@ class FFIRenderLib {
8717
9944
  const result = this.opentui.symbols.syntaxStyleGetStyleCount(style);
8718
9945
  return typeof result === "bigint" ? Number(result) : result;
8719
9946
  }
9947
+ editorViewSetPlaceholderStyledText(view, chunks) {
9948
+ const nonEmptyChunks = chunks.filter((c) => c.text.length > 0);
9949
+ if (nonEmptyChunks.length === 0) {
9950
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, null, 0);
9951
+ return;
9952
+ }
9953
+ const chunksBuffer = StyledChunkStruct.packList(nonEmptyChunks);
9954
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, ptr3(chunksBuffer), nonEmptyChunks.length);
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
+ }
8720
9962
  onNativeEvent(name, handler) {
8721
9963
  this._nativeEvents.on(name, handler);
8722
9964
  }
@@ -8873,6 +10115,10 @@ class TextBuffer {
8873
10115
  this.guard();
8874
10116
  return this.lib.textBufferGetLineHighlights(this.bufferPtr, lineIdx);
8875
10117
  }
10118
+ getHighlightCount() {
10119
+ this.guard();
10120
+ return this.lib.textBufferGetHighlightCount(this.bufferPtr);
10121
+ }
8876
10122
  setSyntaxStyle(style) {
8877
10123
  this.guard();
8878
10124
  this._syntaxStyle = style ?? undefined;
@@ -8882,6 +10128,14 @@ class TextBuffer {
8882
10128
  this.guard();
8883
10129
  return this._syntaxStyle ?? null;
8884
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
+ }
8885
10139
  clear() {
8886
10140
  this.guard();
8887
10141
  this.lib.textBufferClear(this.bufferPtr);
@@ -8908,7 +10162,7 @@ class TextBuffer {
8908
10162
  }
8909
10163
 
8910
10164
  // src/Renderable.ts
8911
- import { EventEmitter as EventEmitter5 } from "events";
10165
+ import { EventEmitter as EventEmitter6 } from "events";
8912
10166
 
8913
10167
  // src/lib/renderable.validations.ts
8914
10168
  function validateOptions(id, options) {
@@ -9001,7 +10255,7 @@ function isRenderable(obj) {
9001
10255
  return !!obj?.[BrandedRenderable];
9002
10256
  }
9003
10257
 
9004
- class BaseRenderable extends EventEmitter5 {
10258
+ class BaseRenderable extends EventEmitter6 {
9005
10259
  [BrandedRenderable] = true;
9006
10260
  static renderableNumber = 1;
9007
10261
  _id;
@@ -9179,9 +10433,9 @@ class Renderable extends BaseRenderable {
9179
10433
  }
9180
10434
  };
9181
10435
  this.pasteHandler = (event) => {
9182
- this._pasteListener?.call(this, event.text);
10436
+ this._pasteListener?.call(this, event);
9183
10437
  if (!event.defaultPrevented && this.handlePaste) {
9184
- this.handlePaste(event.text);
10438
+ this.handlePaste(event);
9185
10439
  }
9186
10440
  };
9187
10441
  this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler);
@@ -10322,7 +11576,7 @@ function delegate(mapping, vnode) {
10322
11576
  }
10323
11577
 
10324
11578
  // src/console.ts
10325
- import { EventEmitter as EventEmitter7 } from "events";
11579
+ import { EventEmitter as EventEmitter8 } from "events";
10326
11580
  import { Console } from "console";
10327
11581
  import fs from "fs";
10328
11582
  import path4 from "path";
@@ -10330,9 +11584,9 @@ import util2 from "util";
10330
11584
 
10331
11585
  // src/lib/output.capture.ts
10332
11586
  import { Writable } from "stream";
10333
- import { EventEmitter as EventEmitter6 } from "events";
11587
+ import { EventEmitter as EventEmitter7 } from "events";
10334
11588
 
10335
- class Capture extends EventEmitter6 {
11589
+ class Capture extends EventEmitter7 {
10336
11590
  output = [];
10337
11591
  constructor() {
10338
11592
  super();
@@ -10408,7 +11662,7 @@ registerEnvVar({
10408
11662
  default: false
10409
11663
  });
10410
11664
 
10411
- class TerminalConsoleCache extends EventEmitter7 {
11665
+ class TerminalConsoleCache extends EventEmitter8 {
10412
11666
  _cachedLogs = [];
10413
11667
  MAX_CACHE_SIZE = 1000;
10414
11668
  _collectCallerInfo = false;
@@ -10534,7 +11788,7 @@ var DEFAULT_CONSOLE_OPTIONS = {
10534
11788
  };
10535
11789
  var INDENT_WIDTH = 2;
10536
11790
 
10537
- class TerminalConsole extends EventEmitter7 {
11791
+ class TerminalConsole extends EventEmitter8 {
10538
11792
  isVisible = false;
10539
11793
  isFocused = false;
10540
11794
  renderer;
@@ -10994,7 +12248,7 @@ class TerminalConsole extends EventEmitter7 {
10994
12248
  }
10995
12249
 
10996
12250
  // src/renderer.ts
10997
- import { EventEmitter as EventEmitter8 } from "events";
12251
+ import { EventEmitter as EventEmitter9 } from "events";
10998
12252
 
10999
12253
  // src/lib/objects-in-viewport.ts
11000
12254
  function getObjectsInViewport(viewport, objects, direction = "column", padding = 10, minTriggerSize = 16) {
@@ -11220,7 +12474,7 @@ var RendererControlState;
11220
12474
  RendererControlState2["EXPLICIT_STOPPED"] = "explicit_stopped";
11221
12475
  })(RendererControlState ||= {});
11222
12476
 
11223
- class CliRenderer extends EventEmitter8 {
12477
+ class CliRenderer extends EventEmitter9 {
11224
12478
  static animationFrameId = 0;
11225
12479
  lib;
11226
12480
  rendererPtr;
@@ -11248,7 +12502,7 @@ class CliRenderer extends EventEmitter8 {
11248
12502
  frameTimes = [];
11249
12503
  maxStatSamples = 300;
11250
12504
  postProcessFns = [];
11251
- backgroundColor = RGBA.fromHex("#000000");
12505
+ backgroundColor = RGBA.fromInts(0, 0, 0, 0);
11252
12506
  waitingForPixelResolution = false;
11253
12507
  rendering = false;
11254
12508
  renderingNative = false;
@@ -11312,30 +12566,10 @@ class CliRenderer extends EventEmitter8 {
11312
12566
  _currentFocusedRenderable = null;
11313
12567
  lifecyclePasses = new Set;
11314
12568
  handleError = ((error) => {
11315
- this.stop();
11316
- this.destroy();
11317
- new Promise((resolve4) => {
11318
- setTimeout(() => {
11319
- resolve4(true);
11320
- }, 100);
11321
- }).then(() => {
11322
- this.realStdoutWrite.call(this.stdout, `
11323
- `.repeat(this._terminalHeight));
11324
- this.realStdoutWrite.call(this.stdout, `
11325
- === FATAL ERROR OCCURRED ===
11326
- `);
11327
- this.dumpOutputCache();
11328
- this.realStdoutWrite.call(this.stdout, `
11329
- Error details:
11330
- `);
11331
- this.realStdoutWrite.call(this.stdout, error.message || "unknown error");
11332
- this.realStdoutWrite.call(this.stdout, `
11333
- `);
11334
- this.realStdoutWrite.call(this.stdout, error.stack || error.toString());
11335
- this.realStdoutWrite.call(this.stdout, `
11336
- `);
11337
- process.exit(1);
11338
- });
12569
+ console.error(error);
12570
+ if (true) {
12571
+ this.console.show();
12572
+ }
11339
12573
  }).bind(this);
11340
12574
  dumpOutputCache(optionalMessage = "") {
11341
12575
  const cachedLogs = this.console.getCachedLogs();
@@ -11360,8 +12594,10 @@ Captured output:
11360
12594
  exitHandler = (() => {
11361
12595
  this.destroy();
11362
12596
  if (env.OTUI_DUMP_CAPTURES) {
11363
- this.dumpOutputCache(`=== CAPTURED OUTPUT ===
12597
+ Bun.sleep(100).then(() => {
12598
+ this.dumpOutputCache(`=== CAPTURED OUTPUT ===
11364
12599
  `);
12600
+ });
11365
12601
  }
11366
12602
  }).bind(this);
11367
12603
  warningHandler = ((warning) => {
@@ -11417,6 +12653,14 @@ Captured output:
11417
12653
  this._console = new TerminalConsole(this, config.consoleOptions);
11418
12654
  this.useConsole = config.useConsole ?? true;
11419
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
+ });
11420
12664
  global.requestAnimationFrame = (callback) => {
11421
12665
  const id = CliRenderer.animationFrameId++;
11422
12666
  this.animationRequest.set(id, callback);
@@ -11676,12 +12920,6 @@ Captured output:
11676
12920
  return;
11677
12921
  }
11678
12922
  }
11679
- if (this.exitOnCtrlC && str === "\x03") {
11680
- process.nextTick(() => {
11681
- this.destroy();
11682
- });
11683
- return;
11684
- }
11685
12923
  if (this._useMouse && this.handleMouseData(data)) {
11686
12924
  return;
11687
12925
  }
@@ -11878,7 +13116,7 @@ Captured output:
11878
13116
  this.renderOffset = height - this._splitHeight;
11879
13117
  this.width = width;
11880
13118
  this.height = this._splitHeight;
11881
- this.currentRenderBuffer.clear(RGBA.fromHex("#000000"));
13119
+ this.currentRenderBuffer.clear(this.backgroundColor);
11882
13120
  this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
11883
13121
  } else {
11884
13122
  this.width = width;
@@ -12321,7 +13559,7 @@ Captured output:
12321
13559
  }
12322
13560
  }
12323
13561
 
12324
- 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, 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 };
12325
13563
 
12326
- //# debugId=19E28318FF03F69E64756E2164756E21
12327
- //# sourceMappingURL=index-0qmm1k4p.js.map
13564
+ //# debugId=F6CF4AF7A66F05DD64756E2164756E21
13565
+ //# sourceMappingURL=index-3f9h747j.js.map