@opentui/core 0.1.30 → 0.1.31

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.
@@ -2092,6 +2092,12 @@ var parseKeypress = (s = "", options = {}) => {
2092
2092
  } else if (!s) {
2093
2093
  s = "";
2094
2094
  }
2095
+ if (/^\x1b\[<\d+;\d+;\d+[Mm]$/.test(s)) {
2096
+ return null;
2097
+ }
2098
+ if (s.startsWith("\x1B[M") && s.length >= 6) {
2099
+ return null;
2100
+ }
2095
2101
  const key = {
2096
2102
  name: "",
2097
2103
  ctrl: false,
@@ -2110,11 +2116,14 @@ var parseKeypress = (s = "", options = {}) => {
2110
2116
  return kittyResult;
2111
2117
  }
2112
2118
  }
2113
- if (s === "\r") {
2119
+ if (s === "\r" || s === "\x1B\r") {
2114
2120
  key.name = "return";
2121
+ key.meta = s.length === 2;
2115
2122
  } else if (s === `
2123
+ ` || s === `\x1B
2116
2124
  `) {
2117
2125
  key.name = "enter";
2126
+ key.meta = s.length === 2;
2118
2127
  } else if (s === "\t") {
2119
2128
  key.name = "tab";
2120
2129
  } else if (s === "\b" || s === "\x1B\b" || s === "\x7F" || s === "\x1B\x7F") {
@@ -2277,6 +2286,9 @@ class KeyHandler extends EventEmitter {
2277
2286
  return;
2278
2287
  }
2279
2288
  const parsedKey = parseKeypress(key, { useKittyKeyboard: this.useKittyKeyboard });
2289
+ if (!parsedKey) {
2290
+ return;
2291
+ }
2280
2292
  switch (parsedKey.eventType) {
2281
2293
  case "press":
2282
2294
  this.emit("keypress", new KeyEvent(parsedKey));
@@ -6204,6 +6216,680 @@ function getTreeSitterClient() {
6204
6216
  return client2;
6205
6217
  });
6206
6218
  }
6219
+
6220
+ // src/lib/extmarks-history.ts
6221
+ class ExtmarksHistory {
6222
+ undoStack = [];
6223
+ redoStack = [];
6224
+ saveSnapshot(extmarks, nextId) {
6225
+ const snapshot = {
6226
+ extmarks: new Map(Array.from(extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
6227
+ nextId
6228
+ };
6229
+ this.undoStack.push(snapshot);
6230
+ this.redoStack = [];
6231
+ }
6232
+ undo() {
6233
+ if (this.undoStack.length === 0)
6234
+ return null;
6235
+ return this.undoStack.pop();
6236
+ }
6237
+ redo() {
6238
+ if (this.redoStack.length === 0)
6239
+ return null;
6240
+ return this.redoStack.pop();
6241
+ }
6242
+ pushRedo(snapshot) {
6243
+ this.redoStack.push(snapshot);
6244
+ }
6245
+ pushUndo(snapshot) {
6246
+ this.undoStack.push(snapshot);
6247
+ }
6248
+ clear() {
6249
+ this.undoStack = [];
6250
+ this.redoStack = [];
6251
+ }
6252
+ canUndo() {
6253
+ return this.undoStack.length > 0;
6254
+ }
6255
+ canRedo() {
6256
+ return this.redoStack.length > 0;
6257
+ }
6258
+ }
6259
+
6260
+ // src/lib/extmarks.ts
6261
+ class ExtmarksController {
6262
+ editBuffer;
6263
+ editorView;
6264
+ extmarks = new Map;
6265
+ extmarksByTypeId = new Map;
6266
+ metadata = new Map;
6267
+ nextId = 1;
6268
+ destroyed = false;
6269
+ history = new ExtmarksHistory;
6270
+ typeNameToId = new Map;
6271
+ typeIdToName = new Map;
6272
+ nextTypeId = 1;
6273
+ originalMoveCursorLeft;
6274
+ originalMoveCursorRight;
6275
+ originalSetCursorByOffset;
6276
+ originalMoveUpVisual;
6277
+ originalMoveDownVisual;
6278
+ originalDeleteCharBackward;
6279
+ originalDeleteChar;
6280
+ originalInsertText;
6281
+ originalInsertChar;
6282
+ originalDeleteRange;
6283
+ originalSetText;
6284
+ originalClear;
6285
+ originalNewLine;
6286
+ originalDeleteLine;
6287
+ originalEditorViewDeleteSelectedText;
6288
+ originalUndo;
6289
+ originalRedo;
6290
+ constructor(editBuffer, editorView) {
6291
+ this.editBuffer = editBuffer;
6292
+ this.editorView = editorView;
6293
+ this.originalMoveCursorLeft = editBuffer.moveCursorLeft.bind(editBuffer);
6294
+ this.originalMoveCursorRight = editBuffer.moveCursorRight.bind(editBuffer);
6295
+ this.originalSetCursorByOffset = editBuffer.setCursorByOffset.bind(editBuffer);
6296
+ this.originalMoveUpVisual = editorView.moveUpVisual.bind(editorView);
6297
+ this.originalMoveDownVisual = editorView.moveDownVisual.bind(editorView);
6298
+ this.originalDeleteCharBackward = editBuffer.deleteCharBackward.bind(editBuffer);
6299
+ this.originalDeleteChar = editBuffer.deleteChar.bind(editBuffer);
6300
+ this.originalInsertText = editBuffer.insertText.bind(editBuffer);
6301
+ this.originalInsertChar = editBuffer.insertChar.bind(editBuffer);
6302
+ this.originalDeleteRange = editBuffer.deleteRange.bind(editBuffer);
6303
+ this.originalSetText = editBuffer.setText.bind(editBuffer);
6304
+ this.originalClear = editBuffer.clear.bind(editBuffer);
6305
+ this.originalNewLine = editBuffer.newLine.bind(editBuffer);
6306
+ this.originalDeleteLine = editBuffer.deleteLine.bind(editBuffer);
6307
+ this.originalEditorViewDeleteSelectedText = editorView.deleteSelectedText.bind(editorView);
6308
+ this.originalUndo = editBuffer.undo.bind(editBuffer);
6309
+ this.originalRedo = editBuffer.redo.bind(editBuffer);
6310
+ this.wrapCursorMovement();
6311
+ this.wrapDeletion();
6312
+ this.wrapInsertion();
6313
+ this.wrapEditorViewDeleteSelectedText();
6314
+ this.wrapUndoRedo();
6315
+ this.setupContentChangeListener();
6316
+ }
6317
+ wrapCursorMovement() {
6318
+ this.editBuffer.moveCursorLeft = () => {
6319
+ if (this.destroyed) {
6320
+ this.originalMoveCursorLeft();
6321
+ return;
6322
+ }
6323
+ const currentOffset = this.editorView.getVisualCursor().offset;
6324
+ const hasSelection = this.editorView.hasSelection();
6325
+ if (hasSelection) {
6326
+ this.originalMoveCursorLeft();
6327
+ return;
6328
+ }
6329
+ const targetOffset = currentOffset - 1;
6330
+ if (targetOffset < 0) {
6331
+ this.originalMoveCursorLeft();
6332
+ return;
6333
+ }
6334
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6335
+ if (virtualExtmark && currentOffset >= virtualExtmark.end) {
6336
+ this.editBuffer.setCursorByOffset(virtualExtmark.start - 1);
6337
+ return;
6338
+ }
6339
+ this.originalMoveCursorLeft();
6340
+ };
6341
+ this.editBuffer.moveCursorRight = () => {
6342
+ if (this.destroyed) {
6343
+ this.originalMoveCursorRight();
6344
+ return;
6345
+ }
6346
+ const currentOffset = this.editorView.getVisualCursor().offset;
6347
+ const hasSelection = this.editorView.hasSelection();
6348
+ if (hasSelection) {
6349
+ this.originalMoveCursorRight();
6350
+ return;
6351
+ }
6352
+ const targetOffset = currentOffset + 1;
6353
+ const textLength = this.editBuffer.getText().length;
6354
+ if (targetOffset > textLength) {
6355
+ this.originalMoveCursorRight();
6356
+ return;
6357
+ }
6358
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6359
+ if (virtualExtmark && currentOffset <= virtualExtmark.start) {
6360
+ this.editBuffer.setCursorByOffset(virtualExtmark.end);
6361
+ return;
6362
+ }
6363
+ this.originalMoveCursorRight();
6364
+ };
6365
+ this.editorView.moveUpVisual = () => {
6366
+ if (this.destroyed) {
6367
+ this.originalMoveUpVisual();
6368
+ return;
6369
+ }
6370
+ const hasSelection = this.editorView.hasSelection();
6371
+ if (hasSelection) {
6372
+ this.originalMoveUpVisual();
6373
+ return;
6374
+ }
6375
+ const currentOffset = this.editorView.getVisualCursor().offset;
6376
+ this.originalMoveUpVisual();
6377
+ const newOffset = this.editorView.getVisualCursor().offset;
6378
+ const virtualExtmark = this.findVirtualExtmarkContaining(newOffset);
6379
+ if (virtualExtmark) {
6380
+ const distanceToStart = newOffset - virtualExtmark.start;
6381
+ const distanceToEnd = virtualExtmark.end - newOffset;
6382
+ if (distanceToStart < distanceToEnd) {
6383
+ this.editorView.setCursorByOffset(virtualExtmark.start - 1);
6384
+ } else {
6385
+ this.editorView.setCursorByOffset(virtualExtmark.end);
6386
+ }
6387
+ }
6388
+ };
6389
+ this.editorView.moveDownVisual = () => {
6390
+ if (this.destroyed) {
6391
+ this.originalMoveDownVisual();
6392
+ return;
6393
+ }
6394
+ const hasSelection = this.editorView.hasSelection();
6395
+ if (hasSelection) {
6396
+ this.originalMoveDownVisual();
6397
+ return;
6398
+ }
6399
+ this.originalMoveDownVisual();
6400
+ const newOffset = this.editorView.getVisualCursor().offset;
6401
+ const virtualExtmark = this.findVirtualExtmarkContaining(newOffset);
6402
+ if (virtualExtmark) {
6403
+ const distanceToStart = newOffset - virtualExtmark.start;
6404
+ const distanceToEnd = virtualExtmark.end - newOffset;
6405
+ if (distanceToStart < distanceToEnd) {
6406
+ this.editorView.setCursorByOffset(virtualExtmark.start - 1);
6407
+ } else {
6408
+ this.editorView.setCursorByOffset(virtualExtmark.end);
6409
+ }
6410
+ }
6411
+ };
6412
+ this.editBuffer.setCursorByOffset = (offset) => {
6413
+ if (this.destroyed) {
6414
+ this.originalSetCursorByOffset(offset);
6415
+ return;
6416
+ }
6417
+ const currentOffset = this.editorView.getVisualCursor().offset;
6418
+ const hasSelection = this.editorView.hasSelection();
6419
+ if (hasSelection) {
6420
+ this.originalSetCursorByOffset(offset);
6421
+ return;
6422
+ }
6423
+ const movingForward = offset > currentOffset;
6424
+ if (movingForward) {
6425
+ const virtualExtmark = this.findVirtualExtmarkContaining(offset);
6426
+ if (virtualExtmark && currentOffset <= virtualExtmark.start) {
6427
+ this.originalSetCursorByOffset(virtualExtmark.end);
6428
+ return;
6429
+ }
6430
+ } else {
6431
+ for (const extmark of this.extmarks.values()) {
6432
+ if (extmark.virtual && currentOffset >= extmark.end && offset < extmark.end && offset >= extmark.start) {
6433
+ this.originalSetCursorByOffset(extmark.start - 1);
6434
+ return;
6435
+ }
6436
+ }
6437
+ }
6438
+ this.originalSetCursorByOffset(offset);
6439
+ };
6440
+ }
6441
+ wrapDeletion() {
6442
+ this.editBuffer.deleteCharBackward = () => {
6443
+ if (this.destroyed) {
6444
+ this.originalDeleteCharBackward();
6445
+ return;
6446
+ }
6447
+ this.saveSnapshot();
6448
+ const currentOffset = this.editorView.getVisualCursor().offset;
6449
+ const hadSelection = this.editorView.hasSelection();
6450
+ if (currentOffset === 0) {
6451
+ this.originalDeleteCharBackward();
6452
+ return;
6453
+ }
6454
+ if (hadSelection) {
6455
+ this.originalDeleteCharBackward();
6456
+ return;
6457
+ }
6458
+ const targetOffset = currentOffset - 1;
6459
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6460
+ if (virtualExtmark && currentOffset === virtualExtmark.end) {
6461
+ const startCursor = this.offsetToPosition(virtualExtmark.start);
6462
+ const endCursor = this.offsetToPosition(virtualExtmark.end);
6463
+ const deleteOffset = virtualExtmark.start;
6464
+ const deleteLength = virtualExtmark.end - virtualExtmark.start;
6465
+ this.deleteExtmarkById(virtualExtmark.id);
6466
+ this.originalDeleteRange(startCursor.row, startCursor.col, endCursor.row, endCursor.col);
6467
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
6468
+ this.updateHighlights();
6469
+ return;
6470
+ }
6471
+ this.originalDeleteCharBackward();
6472
+ this.adjustExtmarksAfterDeletion(targetOffset, 1);
6473
+ };
6474
+ this.editBuffer.deleteChar = () => {
6475
+ if (this.destroyed) {
6476
+ this.originalDeleteChar();
6477
+ return;
6478
+ }
6479
+ this.saveSnapshot();
6480
+ const currentOffset = this.editorView.getVisualCursor().offset;
6481
+ const textLength = this.editBuffer.getText().length;
6482
+ const hadSelection = this.editorView.hasSelection();
6483
+ if (currentOffset >= textLength) {
6484
+ this.originalDeleteChar();
6485
+ return;
6486
+ }
6487
+ if (hadSelection) {
6488
+ this.originalDeleteChar();
6489
+ return;
6490
+ }
6491
+ const targetOffset = currentOffset;
6492
+ const virtualExtmark = this.findVirtualExtmarkContaining(targetOffset);
6493
+ if (virtualExtmark && currentOffset === virtualExtmark.start) {
6494
+ const startCursor = this.offsetToPosition(virtualExtmark.start);
6495
+ const endCursor = this.offsetToPosition(virtualExtmark.end);
6496
+ const deleteOffset = virtualExtmark.start;
6497
+ const deleteLength = virtualExtmark.end - virtualExtmark.start;
6498
+ this.deleteExtmarkById(virtualExtmark.id);
6499
+ this.originalDeleteRange(startCursor.row, startCursor.col, endCursor.row, endCursor.col);
6500
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
6501
+ this.updateHighlights();
6502
+ return;
6503
+ }
6504
+ this.originalDeleteChar();
6505
+ this.adjustExtmarksAfterDeletion(targetOffset, 1);
6506
+ };
6507
+ this.editBuffer.deleteRange = (startLine, startCol, endLine, endCol) => {
6508
+ if (this.destroyed) {
6509
+ this.originalDeleteRange(startLine, startCol, endLine, endCol);
6510
+ return;
6511
+ }
6512
+ this.saveSnapshot();
6513
+ const startOffset = this.positionToOffset(startLine, startCol);
6514
+ const endOffset = this.positionToOffset(endLine, endCol);
6515
+ const length = endOffset - startOffset;
6516
+ this.originalDeleteRange(startLine, startCol, endLine, endCol);
6517
+ this.adjustExtmarksAfterDeletion(startOffset, length);
6518
+ };
6519
+ this.editBuffer.deleteLine = () => {
6520
+ if (this.destroyed) {
6521
+ this.originalDeleteLine();
6522
+ return;
6523
+ }
6524
+ this.saveSnapshot();
6525
+ const text = this.editBuffer.getText();
6526
+ const currentOffset = this.editorView.getVisualCursor().offset;
6527
+ let lineStart = 0;
6528
+ for (let i = currentOffset - 1;i >= 0; i--) {
6529
+ if (text[i] === `
6530
+ `) {
6531
+ lineStart = i + 1;
6532
+ break;
6533
+ }
6534
+ }
6535
+ let lineEnd = text.length;
6536
+ for (let i = currentOffset;i < text.length; i++) {
6537
+ if (text[i] === `
6538
+ `) {
6539
+ lineEnd = i + 1;
6540
+ break;
6541
+ }
6542
+ }
6543
+ const deleteLength = lineEnd - lineStart;
6544
+ this.originalDeleteLine();
6545
+ this.adjustExtmarksAfterDeletion(lineStart, deleteLength);
6546
+ };
6547
+ }
6548
+ wrapInsertion() {
6549
+ this.editBuffer.insertText = (text) => {
6550
+ if (this.destroyed) {
6551
+ this.originalInsertText(text);
6552
+ return;
6553
+ }
6554
+ this.saveSnapshot();
6555
+ const currentOffset = this.editorView.getVisualCursor().offset;
6556
+ this.originalInsertText(text);
6557
+ this.adjustExtmarksAfterInsertion(currentOffset, text.length);
6558
+ };
6559
+ this.editBuffer.insertChar = (char) => {
6560
+ if (this.destroyed) {
6561
+ this.originalInsertChar(char);
6562
+ return;
6563
+ }
6564
+ this.saveSnapshot();
6565
+ const currentOffset = this.editorView.getVisualCursor().offset;
6566
+ this.originalInsertChar(char);
6567
+ this.adjustExtmarksAfterInsertion(currentOffset, 1);
6568
+ };
6569
+ this.editBuffer.setText = (text, opts) => {
6570
+ if (this.destroyed) {
6571
+ this.originalSetText(text, opts);
6572
+ return;
6573
+ }
6574
+ if (opts?.history !== false) {
6575
+ this.saveSnapshot();
6576
+ }
6577
+ this.clear();
6578
+ this.originalSetText(text, opts);
6579
+ };
6580
+ this.editBuffer.clear = () => {
6581
+ if (this.destroyed) {
6582
+ this.originalClear();
6583
+ return;
6584
+ }
6585
+ this.saveSnapshot();
6586
+ this.clear();
6587
+ this.originalClear();
6588
+ };
6589
+ this.editBuffer.newLine = () => {
6590
+ if (this.destroyed) {
6591
+ this.originalNewLine();
6592
+ return;
6593
+ }
6594
+ this.saveSnapshot();
6595
+ const currentOffset = this.editorView.getVisualCursor().offset;
6596
+ this.originalNewLine();
6597
+ this.adjustExtmarksAfterInsertion(currentOffset, 1);
6598
+ };
6599
+ }
6600
+ wrapEditorViewDeleteSelectedText() {
6601
+ this.editorView.deleteSelectedText = () => {
6602
+ if (this.destroyed) {
6603
+ this.originalEditorViewDeleteSelectedText();
6604
+ return;
6605
+ }
6606
+ this.saveSnapshot();
6607
+ const selection = this.editorView.getSelection();
6608
+ if (!selection) {
6609
+ this.originalEditorViewDeleteSelectedText();
6610
+ return;
6611
+ }
6612
+ const deleteOffset = Math.min(selection.start, selection.end);
6613
+ const deleteLength = Math.abs(selection.end - selection.start);
6614
+ this.originalEditorViewDeleteSelectedText();
6615
+ if (deleteLength > 0) {
6616
+ this.adjustExtmarksAfterDeletion(deleteOffset, deleteLength);
6617
+ }
6618
+ };
6619
+ }
6620
+ setupContentChangeListener() {
6621
+ this.editBuffer.on("content-changed", () => {
6622
+ if (this.destroyed)
6623
+ return;
6624
+ this.updateHighlights();
6625
+ });
6626
+ }
6627
+ deleteExtmarkById(id) {
6628
+ const extmark = this.extmarks.get(id);
6629
+ if (extmark) {
6630
+ this.extmarks.delete(id);
6631
+ this.extmarksByTypeId.get(extmark.typeId)?.delete(id);
6632
+ this.metadata.delete(id);
6633
+ }
6634
+ }
6635
+ findVirtualExtmarkContaining(offset) {
6636
+ for (const extmark of this.extmarks.values()) {
6637
+ if (extmark.virtual && offset >= extmark.start && offset < extmark.end) {
6638
+ return extmark;
6639
+ }
6640
+ }
6641
+ return null;
6642
+ }
6643
+ adjustExtmarksAfterInsertion(insertOffset, length) {
6644
+ for (const extmark of this.extmarks.values()) {
6645
+ if (extmark.start >= insertOffset) {
6646
+ extmark.start += length;
6647
+ extmark.end += length;
6648
+ } else if (extmark.end > insertOffset) {
6649
+ extmark.end += length;
6650
+ }
6651
+ }
6652
+ this.updateHighlights();
6653
+ }
6654
+ adjustExtmarksAfterDeletion(deleteOffset, length) {
6655
+ const toDelete = [];
6656
+ for (const extmark of this.extmarks.values()) {
6657
+ if (extmark.end <= deleteOffset) {
6658
+ continue;
6659
+ }
6660
+ if (extmark.start >= deleteOffset + length) {
6661
+ extmark.start -= length;
6662
+ extmark.end -= length;
6663
+ } else if (extmark.start >= deleteOffset && extmark.end <= deleteOffset + length) {
6664
+ toDelete.push(extmark.id);
6665
+ } else if (extmark.start < deleteOffset && extmark.end > deleteOffset + length) {
6666
+ extmark.end -= length;
6667
+ } else if (extmark.start < deleteOffset && extmark.end > deleteOffset) {
6668
+ extmark.end -= Math.min(extmark.end, deleteOffset + length) - deleteOffset;
6669
+ } else if (extmark.start < deleteOffset + length && extmark.end > deleteOffset + length) {
6670
+ const overlap = deleteOffset + length - extmark.start;
6671
+ extmark.start = deleteOffset;
6672
+ extmark.end -= length;
6673
+ }
6674
+ }
6675
+ for (const id of toDelete) {
6676
+ this.deleteExtmarkById(id);
6677
+ }
6678
+ this.updateHighlights();
6679
+ }
6680
+ offsetToPosition(offset) {
6681
+ const result = this.editBuffer.offsetToPosition(offset);
6682
+ if (!result) {
6683
+ return { row: 0, col: 0 };
6684
+ }
6685
+ return result;
6686
+ }
6687
+ positionToOffset(row, col) {
6688
+ return this.editBuffer.positionToOffset(row, col);
6689
+ }
6690
+ updateHighlights() {
6691
+ this.editBuffer.clearAllHighlights();
6692
+ for (const extmark of this.extmarks.values()) {
6693
+ if (extmark.styleId !== undefined) {
6694
+ const startWithoutNewlines = this.offsetToCharOffset(extmark.start);
6695
+ const endWithoutNewlines = this.offsetToCharOffset(extmark.end);
6696
+ this.editBuffer.addHighlightByCharRange({
6697
+ start: startWithoutNewlines,
6698
+ end: endWithoutNewlines,
6699
+ styleId: extmark.styleId,
6700
+ priority: extmark.priority ?? 0,
6701
+ hlRef: extmark.id
6702
+ });
6703
+ }
6704
+ }
6705
+ }
6706
+ offsetToCharOffset(offset) {
6707
+ const text = this.editBuffer.getText();
6708
+ let charOffset = 0;
6709
+ for (let i = 0;i < offset && i < text.length; i++) {
6710
+ if (text[i] !== `
6711
+ `) {
6712
+ charOffset++;
6713
+ }
6714
+ }
6715
+ return charOffset;
6716
+ }
6717
+ create(options) {
6718
+ if (this.destroyed) {
6719
+ throw new Error("ExtmarksController is destroyed");
6720
+ }
6721
+ const id = this.nextId++;
6722
+ const typeId = options.typeId ?? 0;
6723
+ const extmark = {
6724
+ id,
6725
+ start: options.start,
6726
+ end: options.end,
6727
+ virtual: options.virtual ?? false,
6728
+ styleId: options.styleId,
6729
+ priority: options.priority,
6730
+ data: options.data,
6731
+ typeId
6732
+ };
6733
+ this.extmarks.set(id, extmark);
6734
+ if (!this.extmarksByTypeId.has(typeId)) {
6735
+ this.extmarksByTypeId.set(typeId, new Set);
6736
+ }
6737
+ this.extmarksByTypeId.get(typeId).add(id);
6738
+ if (options.metadata !== undefined) {
6739
+ this.metadata.set(id, options.metadata);
6740
+ }
6741
+ this.updateHighlights();
6742
+ return id;
6743
+ }
6744
+ delete(id) {
6745
+ if (this.destroyed) {
6746
+ throw new Error("ExtmarksController is destroyed");
6747
+ }
6748
+ const extmark = this.extmarks.get(id);
6749
+ if (!extmark)
6750
+ return false;
6751
+ this.deleteExtmarkById(id);
6752
+ this.updateHighlights();
6753
+ return true;
6754
+ }
6755
+ get(id) {
6756
+ if (this.destroyed)
6757
+ return null;
6758
+ return this.extmarks.get(id) ?? null;
6759
+ }
6760
+ getAll() {
6761
+ if (this.destroyed)
6762
+ return [];
6763
+ return Array.from(this.extmarks.values());
6764
+ }
6765
+ getVirtual() {
6766
+ if (this.destroyed)
6767
+ return [];
6768
+ return Array.from(this.extmarks.values()).filter((e) => e.virtual);
6769
+ }
6770
+ getAtOffset(offset) {
6771
+ if (this.destroyed)
6772
+ return [];
6773
+ return Array.from(this.extmarks.values()).filter((e) => offset >= e.start && offset < e.end);
6774
+ }
6775
+ getAllForTypeId(typeId) {
6776
+ if (this.destroyed)
6777
+ return [];
6778
+ const ids = this.extmarksByTypeId.get(typeId);
6779
+ if (!ids)
6780
+ return [];
6781
+ return Array.from(ids).map((id) => this.extmarks.get(id)).filter((e) => e !== undefined);
6782
+ }
6783
+ clear() {
6784
+ if (this.destroyed)
6785
+ return;
6786
+ this.extmarks.clear();
6787
+ this.extmarksByTypeId.clear();
6788
+ this.metadata.clear();
6789
+ this.updateHighlights();
6790
+ }
6791
+ saveSnapshot() {
6792
+ this.history.saveSnapshot(this.extmarks, this.nextId);
6793
+ }
6794
+ restoreSnapshot(snapshot) {
6795
+ this.extmarks = new Map(Array.from(snapshot.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }]));
6796
+ this.nextId = snapshot.nextId;
6797
+ this.updateHighlights();
6798
+ }
6799
+ wrapUndoRedo() {
6800
+ this.editBuffer.undo = () => {
6801
+ if (this.destroyed) {
6802
+ return this.originalUndo();
6803
+ }
6804
+ if (!this.history.canUndo()) {
6805
+ return this.originalUndo();
6806
+ }
6807
+ const currentSnapshot = {
6808
+ extmarks: new Map(Array.from(this.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
6809
+ nextId: this.nextId
6810
+ };
6811
+ this.history.pushRedo(currentSnapshot);
6812
+ const snapshot = this.history.undo();
6813
+ this.restoreSnapshot(snapshot);
6814
+ return this.originalUndo();
6815
+ };
6816
+ this.editBuffer.redo = () => {
6817
+ if (this.destroyed) {
6818
+ return this.originalRedo();
6819
+ }
6820
+ if (!this.history.canRedo()) {
6821
+ return this.originalRedo();
6822
+ }
6823
+ const currentSnapshot = {
6824
+ extmarks: new Map(Array.from(this.extmarks.entries()).map(([id, extmark]) => [id, { ...extmark }])),
6825
+ nextId: this.nextId
6826
+ };
6827
+ this.history.pushUndo(currentSnapshot);
6828
+ const snapshot = this.history.redo();
6829
+ this.restoreSnapshot(snapshot);
6830
+ return this.originalRedo();
6831
+ };
6832
+ }
6833
+ registerType(typeName) {
6834
+ if (this.destroyed) {
6835
+ throw new Error("ExtmarksController is destroyed");
6836
+ }
6837
+ const existing = this.typeNameToId.get(typeName);
6838
+ if (existing !== undefined) {
6839
+ return existing;
6840
+ }
6841
+ const typeId = this.nextTypeId++;
6842
+ this.typeNameToId.set(typeName, typeId);
6843
+ this.typeIdToName.set(typeId, typeName);
6844
+ return typeId;
6845
+ }
6846
+ getTypeId(typeName) {
6847
+ if (this.destroyed)
6848
+ return null;
6849
+ return this.typeNameToId.get(typeName) ?? null;
6850
+ }
6851
+ getTypeName(typeId) {
6852
+ if (this.destroyed)
6853
+ return null;
6854
+ return this.typeIdToName.get(typeId) ?? null;
6855
+ }
6856
+ getMetadataFor(extmarkId) {
6857
+ if (this.destroyed)
6858
+ return;
6859
+ return this.metadata.get(extmarkId);
6860
+ }
6861
+ destroy() {
6862
+ if (this.destroyed)
6863
+ return;
6864
+ this.editBuffer.moveCursorLeft = this.originalMoveCursorLeft;
6865
+ this.editBuffer.moveCursorRight = this.originalMoveCursorRight;
6866
+ this.editBuffer.setCursorByOffset = this.originalSetCursorByOffset;
6867
+ this.editorView.moveUpVisual = this.originalMoveUpVisual;
6868
+ this.editorView.moveDownVisual = this.originalMoveDownVisual;
6869
+ this.editBuffer.deleteCharBackward = this.originalDeleteCharBackward;
6870
+ this.editBuffer.deleteChar = this.originalDeleteChar;
6871
+ this.editBuffer.insertText = this.originalInsertText;
6872
+ this.editBuffer.insertChar = this.originalInsertChar;
6873
+ this.editBuffer.deleteRange = this.originalDeleteRange;
6874
+ this.editBuffer.setText = this.originalSetText;
6875
+ this.editBuffer.clear = this.originalClear;
6876
+ this.editBuffer.newLine = this.originalNewLine;
6877
+ this.editBuffer.deleteLine = this.originalDeleteLine;
6878
+ this.editorView.deleteSelectedText = this.originalEditorViewDeleteSelectedText;
6879
+ this.editBuffer.undo = this.originalUndo;
6880
+ this.editBuffer.redo = this.originalRedo;
6881
+ this.extmarks.clear();
6882
+ this.extmarksByTypeId.clear();
6883
+ this.metadata.clear();
6884
+ this.typeNameToId.clear();
6885
+ this.typeIdToName.clear();
6886
+ this.history.clear();
6887
+ this.destroyed = true;
6888
+ }
6889
+ }
6890
+ function createExtmarksController(editBuffer, editorView) {
6891
+ return new ExtmarksController(editBuffer, editorView);
6892
+ }
6207
6893
  // src/zig.ts
6208
6894
  import { dlopen, toArrayBuffer as toArrayBuffer4, JSCallback, ptr as ptr3 } from "bun:ffi";
6209
6895
  import { existsSync as existsSync2 } from "fs";
@@ -7483,6 +8169,14 @@ function getOpenTUILib(libPath) {
7483
8169
  args: ["ptr"],
7484
8170
  returns: "ptr"
7485
8171
  },
8172
+ editorViewGetLineInfoDirect: {
8173
+ args: ["ptr", "ptr", "ptr"],
8174
+ returns: "u32"
8175
+ },
8176
+ editorViewGetLogicalLineInfoDirect: {
8177
+ args: ["ptr", "ptr", "ptr"],
8178
+ returns: "u32"
8179
+ },
7486
8180
  createEditBuffer: {
7487
8181
  args: ["u8"],
7488
8182
  returns: "ptr"
@@ -7564,7 +8258,7 @@ function getOpenTUILib(libPath) {
7564
8258
  returns: "void"
7565
8259
  },
7566
8260
  editBufferGetCursorPosition: {
7567
- args: ["ptr", "ptr", "ptr", "ptr"],
8261
+ args: ["ptr", "ptr"],
7568
8262
  returns: "void"
7569
8263
  },
7570
8264
  editBufferGetId: {
@@ -7599,12 +8293,8 @@ function getOpenTUILib(libPath) {
7599
8293
  args: ["ptr"],
7600
8294
  returns: "void"
7601
8295
  },
7602
- editBufferSetPlaceholder: {
7603
- args: ["ptr", "ptr", "usize"],
7604
- returns: "void"
7605
- },
7606
- editBufferSetPlaceholderColor: {
7607
- args: ["ptr", "ptr"],
8296
+ editBufferClear: {
8297
+ args: ["ptr"],
7608
8298
  returns: "void"
7609
8299
  },
7610
8300
  editBufferGetNextWordBoundary: {
@@ -7619,6 +8309,18 @@ function getOpenTUILib(libPath) {
7619
8309
  args: ["ptr", "ptr"],
7620
8310
  returns: "void"
7621
8311
  },
8312
+ editBufferOffsetToPosition: {
8313
+ args: ["ptr", "u32", "ptr"],
8314
+ returns: "bool"
8315
+ },
8316
+ editBufferPositionToOffset: {
8317
+ args: ["ptr", "u32", "u32"],
8318
+ returns: "u32"
8319
+ },
8320
+ editBufferGetLineStartOffset: {
8321
+ args: ["ptr", "u32"],
8322
+ returns: "u32"
8323
+ },
7622
8324
  editorViewSetSelection: {
7623
8325
  args: ["ptr", "u32", "u32", "ptr", "ptr"],
7624
8326
  returns: "void"
@@ -7683,6 +8385,10 @@ function getOpenTUILib(libPath) {
7683
8385
  args: ["ptr", "ptr"],
7684
8386
  returns: "void"
7685
8387
  },
8388
+ editorViewSetPlaceholderStyledText: {
8389
+ args: ["ptr", "ptr", "usize"],
8390
+ returns: "void"
8391
+ },
7686
8392
  getArenaAllocatedBytes: {
7687
8393
  args: [],
7688
8394
  returns: "usize"
@@ -8432,6 +9138,34 @@ class FFIRenderLib {
8432
9138
  }
8433
9139
  return result;
8434
9140
  }
9141
+ editorViewGetLineInfo(view) {
9142
+ const lineCount = this.editorViewGetVirtualLineCount(view);
9143
+ if (lineCount === 0) {
9144
+ return { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
9145
+ }
9146
+ const lineStarts = new Uint32Array(lineCount);
9147
+ const lineWidths = new Uint32Array(lineCount);
9148
+ const maxLineWidth = this.opentui.symbols.editorViewGetLineInfoDirect(view, ptr3(lineStarts), ptr3(lineWidths));
9149
+ return {
9150
+ maxLineWidth,
9151
+ lineStarts: Array.from(lineStarts),
9152
+ lineWidths: Array.from(lineWidths)
9153
+ };
9154
+ }
9155
+ editorViewGetLogicalLineInfo(view) {
9156
+ const lineCount = this.editorViewGetVirtualLineCount(view);
9157
+ if (lineCount === 0) {
9158
+ return { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
9159
+ }
9160
+ const lineStarts = new Uint32Array(lineCount);
9161
+ const lineWidths = new Uint32Array(lineCount);
9162
+ const maxLineWidth = this.opentui.symbols.editorViewGetLogicalLineInfoDirect(view, ptr3(lineStarts), ptr3(lineWidths));
9163
+ return {
9164
+ maxLineWidth,
9165
+ lineStarts: Array.from(lineStarts),
9166
+ lineWidths: Array.from(lineWidths)
9167
+ };
9168
+ }
8435
9169
  createEditBuffer(widthMethod) {
8436
9170
  const widthMethodCode = widthMethod === "wcwidth" ? 0 : 1;
8437
9171
  const bufferPtr = this.opentui.symbols.createEditBuffer(widthMethodCode);
@@ -8505,15 +9239,9 @@ class FFIRenderLib {
8505
9239
  this.opentui.symbols.editBufferSetCursorByOffset(buffer, offset);
8506
9240
  }
8507
9241
  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
- };
9242
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
9243
+ this.opentui.symbols.editBufferGetCursorPosition(buffer, ptr3(cursorBuffer));
9244
+ return LogicalCursorStruct.unpack(cursorBuffer);
8517
9245
  }
8518
9246
  editBufferGetId(buffer) {
8519
9247
  return this.opentui.symbols.editBufferGetId(buffer);
@@ -8553,16 +9281,8 @@ class FFIRenderLib {
8553
9281
  editBufferClearHistory(buffer) {
8554
9282
  this.opentui.symbols.editBufferClearHistory(buffer);
8555
9283
  }
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);
9284
+ editBufferClear(buffer) {
9285
+ this.opentui.symbols.editBufferClear(buffer);
8566
9286
  }
8567
9287
  editBufferGetNextWordBoundary(buffer) {
8568
9288
  const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
@@ -8579,6 +9299,19 @@ class FFIRenderLib {
8579
9299
  this.opentui.symbols.editBufferGetEOL(buffer, ptr3(cursorBuffer));
8580
9300
  return LogicalCursorStruct.unpack(cursorBuffer);
8581
9301
  }
9302
+ editBufferOffsetToPosition(buffer, offset) {
9303
+ const cursorBuffer = new ArrayBuffer(LogicalCursorStruct.size);
9304
+ const success = this.opentui.symbols.editBufferOffsetToPosition(buffer, offset, ptr3(cursorBuffer));
9305
+ if (!success)
9306
+ return null;
9307
+ return LogicalCursorStruct.unpack(cursorBuffer);
9308
+ }
9309
+ editBufferPositionToOffset(buffer, row, col) {
9310
+ return this.opentui.symbols.editBufferPositionToOffset(buffer, row, col);
9311
+ }
9312
+ editBufferGetLineStartOffset(buffer, row) {
9313
+ return this.opentui.symbols.editBufferGetLineStartOffset(buffer, row);
9314
+ }
8582
9315
  editorViewSetSelection(view, start, end, bgColor, fgColor) {
8583
9316
  const bg2 = bgColor ? bgColor.buffer : null;
8584
9317
  const fg2 = fgColor ? fgColor.buffer : null;
@@ -8717,6 +9450,15 @@ class FFIRenderLib {
8717
9450
  const result = this.opentui.symbols.syntaxStyleGetStyleCount(style);
8718
9451
  return typeof result === "bigint" ? Number(result) : result;
8719
9452
  }
9453
+ editorViewSetPlaceholderStyledText(view, chunks) {
9454
+ const nonEmptyChunks = chunks.filter((c) => c.text.length > 0);
9455
+ if (nonEmptyChunks.length === 0) {
9456
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, null, 0);
9457
+ return;
9458
+ }
9459
+ const chunksBuffer = StyledChunkStruct.packList(nonEmptyChunks);
9460
+ this.opentui.symbols.editorViewSetPlaceholderStyledText(view, ptr3(chunksBuffer), nonEmptyChunks.length);
9461
+ }
8720
9462
  onNativeEvent(name, handler) {
8721
9463
  this._nativeEvents.on(name, handler);
8722
9464
  }
@@ -9179,9 +9921,9 @@ class Renderable extends BaseRenderable {
9179
9921
  }
9180
9922
  };
9181
9923
  this.pasteHandler = (event) => {
9182
- this._pasteListener?.call(this, event.text);
9924
+ this._pasteListener?.call(this, event);
9183
9925
  if (!event.defaultPrevented && this.handlePaste) {
9184
- this.handlePaste(event.text);
9926
+ this.handlePaste(event);
9185
9927
  }
9186
9928
  };
9187
9929
  this.ctx._internalKeyInput.onInternal("keypress", this.keypressHandler);
@@ -11248,7 +11990,7 @@ class CliRenderer extends EventEmitter8 {
11248
11990
  frameTimes = [];
11249
11991
  maxStatSamples = 300;
11250
11992
  postProcessFns = [];
11251
- backgroundColor = RGBA.fromHex("#000000");
11993
+ backgroundColor = RGBA.fromInts(0, 0, 0, 0);
11252
11994
  waitingForPixelResolution = false;
11253
11995
  rendering = false;
11254
11996
  renderingNative = false;
@@ -11312,30 +12054,10 @@ class CliRenderer extends EventEmitter8 {
11312
12054
  _currentFocusedRenderable = null;
11313
12055
  lifecyclePasses = new Set;
11314
12056
  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
- });
12057
+ console.error(error);
12058
+ if (true) {
12059
+ this.console.show();
12060
+ }
11339
12061
  }).bind(this);
11340
12062
  dumpOutputCache(optionalMessage = "") {
11341
12063
  const cachedLogs = this.console.getCachedLogs();
@@ -11360,8 +12082,10 @@ Captured output:
11360
12082
  exitHandler = (() => {
11361
12083
  this.destroy();
11362
12084
  if (env.OTUI_DUMP_CAPTURES) {
11363
- this.dumpOutputCache(`=== CAPTURED OUTPUT ===
12085
+ Bun.sleep(100).then(() => {
12086
+ this.dumpOutputCache(`=== CAPTURED OUTPUT ===
11364
12087
  `);
12088
+ });
11365
12089
  }
11366
12090
  }).bind(this);
11367
12091
  warningHandler = ((warning) => {
@@ -11878,7 +12602,7 @@ Captured output:
11878
12602
  this.renderOffset = height - this._splitHeight;
11879
12603
  this.width = width;
11880
12604
  this.height = this._splitHeight;
11881
- this.currentRenderBuffer.clear(RGBA.fromHex("#000000"));
12605
+ this.currentRenderBuffer.clear(this.backgroundColor);
11882
12606
  this.lib.setRenderOffset(this.rendererPtr, this.renderOffset);
11883
12607
  } else {
11884
12608
  this.width = width;
@@ -12321,7 +13045,7 @@ Captured output:
12321
13045
  }
12322
13046
  }
12323
13047
 
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 };
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 };
12325
13049
 
12326
- //# debugId=19E28318FF03F69E64756E2164756E21
12327
- //# sourceMappingURL=index-0qmm1k4p.js.map
13050
+ //# debugId=6145BB5C85305CD464756E2164756E21
13051
+ //# sourceMappingURL=index-91qheh74.js.map