@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
package/index.js CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  DataPathsManager,
11
11
  DebugOverlayCorner,
12
12
  Edge,
13
+ ExtmarksController,
13
14
  Gutter,
14
15
  InternalKeyHandler,
15
16
  KeyEvent,
@@ -29,6 +30,7 @@ import {
29
30
  RendererControlState,
30
31
  RootRenderable,
31
32
  Selection,
33
+ StdinBuffer,
32
34
  StyledText,
33
35
  TerminalConsole,
34
36
  TextAttributes,
@@ -62,6 +64,7 @@ import {
62
64
  convertGlobalToLocalSelection,
63
65
  coordinateToCharacterIndex,
64
66
  createCliRenderer,
67
+ createExtmarksController,
65
68
  createTextAttributes,
66
69
  cyan,
67
70
  delegate,
@@ -131,7 +134,7 @@ import {
131
134
  white,
132
135
  wrapWithDelegates,
133
136
  yellow
134
- } from "./index-0qmm1k4p.js";
137
+ } from "./index-3f9h747j.js";
135
138
  // src/text-buffer-view.ts
136
139
  class TextBufferView {
137
140
  lib;
@@ -220,6 +223,15 @@ class TextBufferView {
220
223
  return "";
221
224
  return this.lib.decoder.decode(plainBytes);
222
225
  }
226
+ setTabIndicator(indicator) {
227
+ this.guard();
228
+ const codePoint = typeof indicator === "string" ? indicator.codePointAt(0) ?? 0 : indicator;
229
+ this.lib.textBufferViewSetTabIndicator(this.viewPtr, codePoint);
230
+ }
231
+ setTabIndicatorColor(color) {
232
+ this.guard();
233
+ this.lib.textBufferViewSetTabIndicatorColor(this.viewPtr, color);
234
+ }
223
235
  destroy() {
224
236
  if (this._destroyed)
225
237
  return;
@@ -381,8 +393,8 @@ class EditBuffer extends EventEmitter {
381
393
  this.guard();
382
394
  const boundary = this.lib.editBufferGetNextWordBoundary(this.bufferPtr);
383
395
  return {
384
- line: boundary.row,
385
- visualColumn: boundary.col,
396
+ row: boundary.row,
397
+ col: boundary.col,
386
398
  offset: boundary.offset
387
399
  };
388
400
  }
@@ -390,8 +402,8 @@ class EditBuffer extends EventEmitter {
390
402
  this.guard();
391
403
  const boundary = this.lib.editBufferGetPrevWordBoundary(this.bufferPtr);
392
404
  return {
393
- line: boundary.row,
394
- visualColumn: boundary.col,
405
+ row: boundary.row,
406
+ col: boundary.col,
395
407
  offset: boundary.offset
396
408
  };
397
409
  }
@@ -399,11 +411,26 @@ class EditBuffer extends EventEmitter {
399
411
  this.guard();
400
412
  const boundary = this.lib.editBufferGetEOL(this.bufferPtr);
401
413
  return {
402
- line: boundary.row,
403
- visualColumn: boundary.col,
414
+ row: boundary.row,
415
+ col: boundary.col,
404
416
  offset: boundary.offset
405
417
  };
406
418
  }
419
+ offsetToPosition(offset) {
420
+ this.guard();
421
+ const result = this.lib.editBufferOffsetToPosition(this.bufferPtr, offset);
422
+ if (!result)
423
+ return null;
424
+ return { row: result.row, col: result.col };
425
+ }
426
+ positionToOffset(row, col) {
427
+ this.guard();
428
+ return this.lib.editBufferPositionToOffset(this.bufferPtr, row, col);
429
+ }
430
+ getLineStartOffset(row) {
431
+ this.guard();
432
+ return this.lib.editBufferGetLineStartOffset(this.bufferPtr, row);
433
+ }
407
434
  debugLogRope() {
408
435
  this.guard();
409
436
  this.lib.editBufferDebugLogRope(this.bufferPtr);
@@ -452,14 +479,6 @@ class EditBuffer extends EventEmitter {
452
479
  this.guard();
453
480
  this.lib.textBufferResetDefaults(this.textBufferPtr);
454
481
  }
455
- setPlaceholder(text) {
456
- this.guard();
457
- this.lib.editBufferSetPlaceholder(this.bufferPtr, text);
458
- }
459
- setPlaceholderColor(color) {
460
- this.guard();
461
- this.lib.editBufferSetPlaceholderColor(this.bufferPtr, color);
462
- }
463
482
  setSyntaxStyle(style) {
464
483
  this.guard();
465
484
  this._syntaxStyle = style ?? undefined;
@@ -493,6 +512,10 @@ class EditBuffer extends EventEmitter {
493
512
  this.guard();
494
513
  return this.lib.textBufferGetLineHighlights(this.textBufferPtr, lineIdx);
495
514
  }
515
+ clear() {
516
+ this.guard();
517
+ this.lib.editBufferClear(this.bufferPtr);
518
+ }
496
519
  destroy() {
497
520
  if (this._destroyed)
498
521
  return;
@@ -507,6 +530,7 @@ class EditorView {
507
530
  viewPtr;
508
531
  editBuffer;
509
532
  _destroyed = false;
533
+ _extmarksController;
510
534
  constructor(lib, ptr, editBuffer) {
511
535
  this.lib = lib;
512
536
  this.viewPtr = ptr;
@@ -627,17 +651,38 @@ class EditorView {
627
651
  }
628
652
  getLineInfo() {
629
653
  this.guard();
630
- const textBufferViewPtr = this.lib.editorViewGetTextBufferView(this.viewPtr);
631
- return this.lib.textBufferViewGetLineInfo(textBufferViewPtr);
654
+ return this.lib.editorViewGetLineInfo(this.viewPtr);
632
655
  }
633
656
  getLogicalLineInfo() {
634
657
  this.guard();
635
- const textBufferViewPtr = this.lib.editorViewGetTextBufferView(this.viewPtr);
636
- return this.lib.textBufferViewGetLogicalLineInfo(textBufferViewPtr);
658
+ return this.lib.editorViewGetLogicalLineInfo(this.viewPtr);
659
+ }
660
+ get extmarks() {
661
+ if (!this._extmarksController) {
662
+ this._extmarksController = createExtmarksController(this.editBuffer, this);
663
+ }
664
+ return this._extmarksController;
665
+ }
666
+ setPlaceholderStyledText(chunks) {
667
+ this.guard();
668
+ this.lib.editorViewSetPlaceholderStyledText(this.viewPtr, chunks);
669
+ }
670
+ setTabIndicator(indicator) {
671
+ this.guard();
672
+ const codePoint = typeof indicator === "string" ? indicator.codePointAt(0) ?? 0 : indicator;
673
+ this.lib.editorViewSetTabIndicator(this.viewPtr, codePoint);
674
+ }
675
+ setTabIndicatorColor(color) {
676
+ this.guard();
677
+ this.lib.editorViewSetTabIndicatorColor(this.viewPtr, color);
637
678
  }
638
679
  destroy() {
639
680
  if (this._destroyed)
640
681
  return;
682
+ if (this._extmarksController) {
683
+ this._extmarksController.destroy();
684
+ this._extmarksController = undefined;
685
+ }
641
686
  this._destroyed = true;
642
687
  this.lib.destroyEditorView(this.viewPtr);
643
688
  }
@@ -816,6 +861,14 @@ class SyntaxStyle {
816
861
  this.guard();
817
862
  return this.mergedCache.size;
818
863
  }
864
+ getAllStyles() {
865
+ this.guard();
866
+ return new Map(this.styleDefs);
867
+ }
868
+ getRegisteredNames() {
869
+ this.guard();
870
+ return Array.from(this.styleDefs.keys());
871
+ }
819
872
  destroy() {
820
873
  if (this._destroyed)
821
874
  return;
@@ -2150,6 +2203,13 @@ class BoxRenderable extends Renderable {
2150
2203
  this.applyYogaGap(options);
2151
2204
  }
2152
2205
  }
2206
+ initializeBorder() {
2207
+ if (this._border === false) {
2208
+ this._border = true;
2209
+ this.borderSides = getBorderSides(this._border);
2210
+ this.applyYogaBorders();
2211
+ }
2212
+ }
2153
2213
  get customBorderChars() {
2154
2214
  return this._customBorderCharsObj;
2155
2215
  }
@@ -2184,9 +2244,10 @@ class BoxRenderable extends Renderable {
2184
2244
  }
2185
2245
  set borderStyle(value) {
2186
2246
  let _value = value ?? this._defaultOptions.borderStyle;
2187
- if (this._borderStyle !== _value) {
2247
+ if (this._borderStyle !== _value || !this._border) {
2188
2248
  this._borderStyle = _value;
2189
2249
  this._customBorderChars = undefined;
2250
+ this.initializeBorder();
2190
2251
  this.requestRender();
2191
2252
  }
2192
2253
  }
@@ -2197,6 +2258,7 @@ class BoxRenderable extends Renderable {
2197
2258
  const newColor = parseColor(value ?? this._defaultOptions.borderColor);
2198
2259
  if (this._borderColor !== newColor) {
2199
2260
  this._borderColor = newColor;
2261
+ this.initializeBorder();
2200
2262
  this.requestRender();
2201
2263
  }
2202
2264
  }
@@ -2207,6 +2269,7 @@ class BoxRenderable extends Renderable {
2207
2269
  const newColor = parseColor(value ?? this._defaultOptions.focusedBorderColor);
2208
2270
  if (this._focusedBorderColor !== newColor) {
2209
2271
  this._focusedBorderColor = newColor;
2272
+ this.initializeBorder();
2210
2273
  if (this._focused) {
2211
2274
  this.requestRender();
2212
2275
  }
@@ -2312,6 +2375,8 @@ class TextBufferRenderable extends Renderable {
2312
2375
  _selectionFg;
2313
2376
  _wrapMode = "word";
2314
2377
  lastLocalSelection = null;
2378
+ _tabIndicator;
2379
+ _tabIndicatorColor;
2315
2380
  textBuffer;
2316
2381
  textBufferView;
2317
2382
  _lineInfo = { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
@@ -2322,7 +2387,9 @@ class TextBufferRenderable extends Renderable {
2322
2387
  selectionFg: undefined,
2323
2388
  selectable: true,
2324
2389
  attributes: 0,
2325
- wrapMode: "word"
2390
+ wrapMode: "word",
2391
+ tabIndicator: undefined,
2392
+ tabIndicatorColor: undefined
2326
2393
  };
2327
2394
  constructor(ctx, options) {
2328
2395
  super(ctx, options);
@@ -2333,6 +2400,8 @@ class TextBufferRenderable extends Renderable {
2333
2400
  this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : this._defaultOptions.selectionFg;
2334
2401
  this.selectable = options.selectable ?? this._defaultOptions.selectable;
2335
2402
  this._wrapMode = options.wrapMode ?? this._defaultOptions.wrapMode;
2403
+ this._tabIndicator = options.tabIndicator ?? this._defaultOptions.tabIndicator;
2404
+ this._tabIndicatorColor = options.tabIndicatorColor ? parseColor(options.tabIndicatorColor) : this._defaultOptions.tabIndicatorColor;
2336
2405
  this.textBuffer = TextBuffer.create(this._ctx.widthMethod);
2337
2406
  this.textBufferView = TextBufferView.create(this.textBuffer);
2338
2407
  const style = SyntaxStyle.create();
@@ -2342,6 +2411,12 @@ class TextBufferRenderable extends Renderable {
2342
2411
  this.textBuffer.setDefaultFg(this._defaultFg);
2343
2412
  this.textBuffer.setDefaultBg(this._defaultBg);
2344
2413
  this.textBuffer.setDefaultAttributes(this._defaultAttributes);
2414
+ if (this._tabIndicator !== undefined) {
2415
+ this.textBufferView.setTabIndicator(this._tabIndicator);
2416
+ }
2417
+ if (this._tabIndicatorColor !== undefined) {
2418
+ this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor);
2419
+ }
2345
2420
  if (this._wrapMode !== "none" && this.width > 0) {
2346
2421
  this.updateWrapWidth(this.width);
2347
2422
  }
@@ -2428,6 +2503,31 @@ class TextBufferRenderable extends Renderable {
2428
2503
  this.requestRender();
2429
2504
  }
2430
2505
  }
2506
+ get tabIndicator() {
2507
+ return this._tabIndicator;
2508
+ }
2509
+ set tabIndicator(value) {
2510
+ if (this._tabIndicator !== value) {
2511
+ this._tabIndicator = value;
2512
+ if (value !== undefined) {
2513
+ this.textBufferView.setTabIndicator(value);
2514
+ }
2515
+ this.requestRender();
2516
+ }
2517
+ }
2518
+ get tabIndicatorColor() {
2519
+ return this._tabIndicatorColor;
2520
+ }
2521
+ set tabIndicatorColor(value) {
2522
+ const newColor = value ? parseColor(value) : undefined;
2523
+ if (this._tabIndicatorColor !== newColor) {
2524
+ this._tabIndicatorColor = newColor;
2525
+ if (newColor !== undefined) {
2526
+ this.textBufferView.setTabIndicatorColor(newColor);
2527
+ }
2528
+ this.requestRender();
2529
+ }
2530
+ }
2431
2531
  onResize(width, height) {
2432
2532
  this.textBufferView.setViewportSize(width, height);
2433
2533
  if (this.lastLocalSelection) {
@@ -2472,8 +2572,9 @@ class TextBufferRenderable extends Renderable {
2472
2572
  }
2473
2573
  setupMeasureFunc() {
2474
2574
  const measureFunc = (width, widthMode, height, heightMode) => {
2475
- if (this._wrapMode !== "none" && this.width !== width) {
2476
- this.updateWrapWidth(width);
2575
+ const effectiveWidth = isNaN(width) ? 1 : width;
2576
+ if (this._wrapMode !== "none" && this.width !== effectiveWidth) {
2577
+ this.updateWrapWidth(effectiveWidth);
2477
2578
  } else {
2478
2579
  this.updateLineInfo();
2479
2580
  }
@@ -2541,8 +2642,14 @@ class CodeRenderable extends TextBufferRenderable {
2541
2642
  _isHighlighting = false;
2542
2643
  _treeSitterClient;
2543
2644
  _pendingRehighlight = false;
2645
+ _pendingUpdate = false;
2646
+ _currentHighlightId = 0;
2647
+ _conceal;
2648
+ _drawUnstyledText;
2544
2649
  _contentDefaultOptions = {
2545
- content: ""
2650
+ content: "",
2651
+ conceal: true,
2652
+ drawUnstyledText: true
2546
2653
  };
2547
2654
  constructor(ctx, options) {
2548
2655
  super(ctx, options);
@@ -2550,6 +2657,8 @@ class CodeRenderable extends TextBufferRenderable {
2550
2657
  this._filetype = options.filetype;
2551
2658
  this._syntaxStyle = options.syntaxStyle;
2552
2659
  this._treeSitterClient = options.treeSitterClient ?? getTreeSitterClient();
2660
+ this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
2661
+ this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
2553
2662
  this.updateContent(this._content);
2554
2663
  }
2555
2664
  get content() {
@@ -2558,7 +2667,7 @@ class CodeRenderable extends TextBufferRenderable {
2558
2667
  set content(value) {
2559
2668
  if (this._content !== value) {
2560
2669
  this._content = value;
2561
- this.updateContent(value);
2670
+ this.scheduleUpdate();
2562
2671
  }
2563
2672
  }
2564
2673
  get filetype() {
@@ -2567,7 +2676,7 @@ class CodeRenderable extends TextBufferRenderable {
2567
2676
  set filetype(value) {
2568
2677
  if (this._filetype !== value) {
2569
2678
  this._filetype = value;
2570
- this.updateContent(this._content);
2679
+ this.scheduleUpdate();
2571
2680
  }
2572
2681
  }
2573
2682
  get syntaxStyle() {
@@ -2576,36 +2685,70 @@ class CodeRenderable extends TextBufferRenderable {
2576
2685
  set syntaxStyle(value) {
2577
2686
  if (this._syntaxStyle !== value) {
2578
2687
  this._syntaxStyle = value;
2579
- this.updateContent(this._content);
2688
+ this.scheduleUpdate();
2689
+ }
2690
+ }
2691
+ get conceal() {
2692
+ return this._conceal;
2693
+ }
2694
+ set conceal(value) {
2695
+ if (this._conceal !== value) {
2696
+ this._conceal = value;
2697
+ this.scheduleUpdate();
2698
+ }
2699
+ }
2700
+ get drawUnstyledText() {
2701
+ return this._drawUnstyledText;
2702
+ }
2703
+ set drawUnstyledText(value) {
2704
+ if (this._drawUnstyledText !== value) {
2705
+ this._drawUnstyledText = value;
2706
+ this.scheduleUpdate();
2580
2707
  }
2581
2708
  }
2709
+ scheduleUpdate() {
2710
+ if (this._pendingUpdate)
2711
+ return;
2712
+ this._pendingUpdate = true;
2713
+ queueMicrotask(() => {
2714
+ this._pendingUpdate = false;
2715
+ this.updateContent(this._content);
2716
+ });
2717
+ }
2582
2718
  async updateContent(content) {
2583
2719
  if (content.length === 0)
2584
2720
  return;
2585
- if (this._isHighlighting) {
2586
- this._pendingRehighlight = true;
2587
- return;
2588
- }
2589
2721
  if (!this._filetype) {
2590
2722
  this.fallback(content);
2591
2723
  return;
2592
2724
  }
2593
- this.fallback(content);
2725
+ this._currentHighlightId++;
2726
+ const highlightId = this._currentHighlightId;
2727
+ if (this._drawUnstyledText) {
2728
+ this.fallback(content);
2729
+ }
2594
2730
  this._isHighlighting = true;
2731
+ this._pendingRehighlight = false;
2595
2732
  try {
2596
- const styledText = await treeSitterToStyledText(content, this._filetype, this._syntaxStyle, this._treeSitterClient);
2733
+ const styledText = await treeSitterToStyledText(content, this._filetype, this._syntaxStyle, this._treeSitterClient, {
2734
+ conceal: { enabled: this._conceal }
2735
+ });
2736
+ if (highlightId !== this._currentHighlightId) {
2737
+ return;
2738
+ }
2597
2739
  if (this.isDestroyed)
2598
2740
  return;
2599
2741
  this.textBuffer.setStyledText(styledText);
2600
2742
  this.updateTextInfo();
2601
2743
  } catch (error) {
2744
+ if (highlightId !== this._currentHighlightId) {
2745
+ return;
2746
+ }
2602
2747
  console.warn("Code highlighting failed, falling back to plain text:", error);
2603
2748
  this.fallback(content);
2604
2749
  } finally {
2605
- this._isHighlighting = false;
2606
- if (this._pendingRehighlight) {
2607
- this._pendingRehighlight = false;
2608
- process.nextTick(() => this.updateContent(this._content));
2750
+ if (highlightId === this._currentHighlightId) {
2751
+ this._isHighlighting = false;
2609
2752
  }
2610
2753
  }
2611
2754
  }
@@ -2628,6 +2771,9 @@ class CodeRenderable extends TextBufferRenderable {
2628
2771
  ];
2629
2772
  return new StyledText(chunks);
2630
2773
  }
2774
+ getLineHighlights(lineIdx) {
2775
+ return this.textBuffer.getLineHighlights(lineIdx);
2776
+ }
2631
2777
  }
2632
2778
  // src/renderables/TextNode.ts
2633
2779
  var BrandedTextNodeRenderable = Symbol.for("@opentui/core/TextNodeRenderable");
@@ -3124,7 +3270,7 @@ class InputRenderable extends Renderable {
3124
3270
  this.deleteCharacter("forward");
3125
3271
  return true;
3126
3272
  case "return":
3127
- case "enter":
3273
+ case "linefeed":
3128
3274
  if (this._value !== this._lastCommittedValue) {
3129
3275
  this._lastCommittedValue = this._value;
3130
3276
  this.emit("change" /* CHANGE */, this._value);
@@ -4479,7 +4625,7 @@ class SelectRenderable extends Renderable {
4479
4625
  this.moveDown(isShift ? this._fastScrollStep : 1);
4480
4626
  return true;
4481
4627
  case "return":
4482
- case "enter":
4628
+ case "linefeed":
4483
4629
  this.selectCurrent();
4484
4630
  return true;
4485
4631
  }
@@ -4798,7 +4944,7 @@ class TabSelectRenderable extends Renderable {
4798
4944
  this.moveRight();
4799
4945
  return true;
4800
4946
  case "return":
4801
- case "enter":
4947
+ case "linefeed":
4802
4948
  this.selectCurrent();
4803
4949
  return true;
4804
4950
  }
@@ -4999,6 +5145,8 @@ class EditBufferRenderable extends Renderable {
4999
5145
  _showCursor = true;
5000
5146
  _cursorColor;
5001
5147
  lastLocalSelection = null;
5148
+ _tabIndicator;
5149
+ _tabIndicatorColor;
5002
5150
  _cursorChangeListener = undefined;
5003
5151
  _contentChangeListener = undefined;
5004
5152
  editBuffer;
@@ -5013,7 +5161,9 @@ class EditBufferRenderable extends Renderable {
5013
5161
  wrapMode: "word",
5014
5162
  scrollMargin: 0.2,
5015
5163
  showCursor: true,
5016
- cursorColor: RGBA.fromValues(1, 1, 1, 1)
5164
+ cursorColor: RGBA.fromValues(1, 1, 1, 1),
5165
+ tabIndicator: undefined,
5166
+ tabIndicatorColor: undefined
5017
5167
  };
5018
5168
  constructor(ctx, options) {
5019
5169
  super(ctx, options);
@@ -5027,6 +5177,8 @@ class EditBufferRenderable extends Renderable {
5027
5177
  this._scrollMargin = options.scrollMargin ?? this._defaultOptions.scrollMargin;
5028
5178
  this._showCursor = options.showCursor ?? this._defaultOptions.showCursor;
5029
5179
  this._cursorColor = parseColor(options.cursorColor ?? this._defaultOptions.cursorColor);
5180
+ this._tabIndicator = options.tabIndicator ?? this._defaultOptions.tabIndicator;
5181
+ this._tabIndicatorColor = options.tabIndicatorColor ? parseColor(options.tabIndicatorColor) : this._defaultOptions.tabIndicatorColor;
5030
5182
  this.editBuffer = EditBuffer.create(this._ctx.widthMethod);
5031
5183
  this.editorView = EditorView.create(this.editBuffer, this.width || 80, this.height || 24);
5032
5184
  this.editorView.setWrapMode(this._wrapMode);
@@ -5037,6 +5189,12 @@ class EditBufferRenderable extends Renderable {
5037
5189
  if (options.syntaxStyle) {
5038
5190
  this.editBuffer.setSyntaxStyle(options.syntaxStyle);
5039
5191
  }
5192
+ if (this._tabIndicator !== undefined) {
5193
+ this.editorView.setTabIndicator(this._tabIndicator);
5194
+ }
5195
+ if (this._tabIndicatorColor !== undefined) {
5196
+ this.editorView.setTabIndicatorColor(this._tabIndicatorColor);
5197
+ }
5040
5198
  this.setupMeasureFunc();
5041
5199
  this.setupEventListeners(options);
5042
5200
  }
@@ -5047,8 +5205,8 @@ class EditBufferRenderable extends Renderable {
5047
5205
  if (this._cursorChangeListener) {
5048
5206
  const cursor = this.editBuffer.getCursorPosition();
5049
5207
  this._cursorChangeListener({
5050
- line: cursor.line,
5051
- visualColumn: cursor.visualColumn
5208
+ line: cursor.row,
5209
+ visualColumn: cursor.col
5052
5210
  });
5053
5211
  }
5054
5212
  });
@@ -5063,7 +5221,7 @@ class EditBufferRenderable extends Renderable {
5063
5221
  get plainText() {
5064
5222
  return this.editBuffer.getText();
5065
5223
  }
5066
- get cursor() {
5224
+ get logicalCursor() {
5067
5225
  return this.editBuffer.getCursorPosition();
5068
5226
  }
5069
5227
  get visualCursor() {
@@ -5164,6 +5322,31 @@ class EditBufferRenderable extends Renderable {
5164
5322
  this.requestRender();
5165
5323
  }
5166
5324
  }
5325
+ get tabIndicator() {
5326
+ return this._tabIndicator;
5327
+ }
5328
+ set tabIndicator(value) {
5329
+ if (this._tabIndicator !== value) {
5330
+ this._tabIndicator = value;
5331
+ if (value !== undefined) {
5332
+ this.editorView.setTabIndicator(value);
5333
+ }
5334
+ this.requestRender();
5335
+ }
5336
+ }
5337
+ get tabIndicatorColor() {
5338
+ return this._tabIndicatorColor;
5339
+ }
5340
+ set tabIndicatorColor(value) {
5341
+ const newColor = value ? parseColor(value) : undefined;
5342
+ if (this._tabIndicatorColor !== newColor) {
5343
+ this._tabIndicatorColor = newColor;
5344
+ if (newColor !== undefined) {
5345
+ this.editorView.setTabIndicatorColor(newColor);
5346
+ }
5347
+ this.requestRender();
5348
+ }
5349
+ }
5167
5350
  onResize(width, height) {
5168
5351
  this.editorView.setViewportSize(width, height);
5169
5352
  if (this.lastLocalSelection) {
@@ -5213,10 +5396,12 @@ class EditBufferRenderable extends Renderable {
5213
5396
  }
5214
5397
  setupMeasureFunc() {
5215
5398
  const measureFunc = (width, widthMode, height, heightMode) => {
5216
- if (this._wrapMode !== "none" && this.width !== width) {
5217
- this.editorView.setViewportSize(width, height);
5399
+ const effectiveHeight = isNaN(height) ? 1 : height;
5400
+ const effectiveWidth = isNaN(width) ? 1 : width;
5401
+ if (this._wrapMode !== "none" && this.width !== effectiveWidth) {
5402
+ this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
5218
5403
  } else {
5219
- this.editorView.setViewportSize(width, height);
5404
+ this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
5220
5405
  }
5221
5406
  const lineInfo = this.editorView.getLogicalLineInfo();
5222
5407
  const measuredWidth = lineInfo.maxLineWidth;
@@ -5317,6 +5502,27 @@ class EditBufferRenderable extends Renderable {
5317
5502
  getLineHighlights(lineIdx) {
5318
5503
  return this.editBuffer.getLineHighlights(lineIdx);
5319
5504
  }
5505
+ setText(text, opts) {
5506
+ this.editBuffer.setText(text, opts);
5507
+ this.yogaNode.markDirty();
5508
+ this.requestRender();
5509
+ }
5510
+ clear() {
5511
+ this.editBuffer.clear();
5512
+ this.editBuffer.clearAllHighlights();
5513
+ this.yogaNode.markDirty();
5514
+ this.requestRender();
5515
+ }
5516
+ deleteRange(startLine, startCol, endLine, endCol) {
5517
+ this.editBuffer.deleteRange(startLine, startCol, endLine, endCol);
5518
+ this.yogaNode.markDirty();
5519
+ this.requestRender();
5520
+ }
5521
+ insertText(text) {
5522
+ this.editBuffer.insertText(text);
5523
+ this.yogaNode.markDirty();
5524
+ this.requestRender();
5525
+ }
5320
5526
  }
5321
5527
 
5322
5528
  // src/lib/keymapping.ts
@@ -5365,7 +5571,8 @@ var defaultTextareaKeybindings = [
5365
5571
  { name: "backspace", action: "backspace" },
5366
5572
  { name: "delete", action: "delete" },
5367
5573
  { name: "return", action: "newline" },
5368
- { name: "enter", action: "newline" },
5574
+ { name: "linefeed", action: "newline" },
5575
+ { name: "return", meta: true, action: "submit" },
5369
5576
  { name: "z", ctrl: true, action: "undo" },
5370
5577
  { name: "Z", ctrl: true, shift: true, action: "redo" },
5371
5578
  { name: "y", ctrl: true, action: "redo" },
@@ -5388,17 +5595,16 @@ class TextareaRenderable extends EditBufferRenderable {
5388
5595
  _unfocusedTextColor;
5389
5596
  _focusedBackgroundColor;
5390
5597
  _focusedTextColor;
5391
- _placeholderColor;
5392
5598
  _keyBindingsMap;
5393
5599
  _actionHandlers;
5600
+ _initialValueSet = false;
5601
+ _submitListener = undefined;
5394
5602
  static defaults = {
5395
- value: "",
5396
5603
  backgroundColor: "transparent",
5397
5604
  textColor: "#FFFFFF",
5398
5605
  focusedBackgroundColor: "transparent",
5399
5606
  focusedTextColor: "#FFFFFF",
5400
- placeholder: null,
5401
- placeholderColor: "#666666"
5607
+ placeholder: null
5402
5608
  };
5403
5609
  constructor(ctx, options) {
5404
5610
  const defaults = TextareaRenderable.defaults;
@@ -5413,14 +5619,29 @@ class TextareaRenderable extends EditBufferRenderable {
5413
5619
  this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || defaults.focusedBackgroundColor);
5414
5620
  this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || defaults.focusedTextColor);
5415
5621
  this._placeholder = options.placeholder ?? defaults.placeholder;
5416
- this._placeholderColor = parseColor(options.placeholderColor || defaults.placeholderColor);
5417
5622
  const mergedBindings = mergeKeyBindings(defaultTextareaKeybindings, options.keyBindings || []);
5418
5623
  this._keyBindingsMap = buildKeyBindingsMap(mergedBindings);
5419
5624
  this._actionHandlers = this.buildActionHandlers();
5420
- this.updateValue(options.value ?? defaults.value);
5625
+ this._submitListener = options.onSubmit;
5626
+ if (options.initialValue) {
5627
+ this.setText(options.initialValue);
5628
+ this._initialValueSet = true;
5629
+ }
5421
5630
  this.updateColors();
5422
- this.editBuffer.setPlaceholder(this._placeholder);
5423
- this.editBuffer.setPlaceholderColor(this._placeholderColor);
5631
+ this.applyPlaceholder(this._placeholder);
5632
+ }
5633
+ applyPlaceholder(placeholder) {
5634
+ if (placeholder === null) {
5635
+ this.editorView.setPlaceholderStyledText([]);
5636
+ return;
5637
+ }
5638
+ if (typeof placeholder === "string") {
5639
+ const defaultGray = fg("#666666");
5640
+ const chunks = [defaultGray(placeholder)];
5641
+ this.editorView.setPlaceholderStyledText(chunks);
5642
+ } else {
5643
+ this.editorView.setPlaceholderStyledText(placeholder.chunks);
5644
+ }
5424
5645
  }
5425
5646
  buildActionHandlers() {
5426
5647
  return new Map([
@@ -5450,11 +5671,12 @@ class TextareaRenderable extends EditBufferRenderable {
5450
5671
  ["select-word-forward", () => this.moveWordForward({ select: true })],
5451
5672
  ["select-word-backward", () => this.moveWordBackward({ select: true })],
5452
5673
  ["delete-word-forward", () => this.deleteWordForward()],
5453
- ["delete-word-backward", () => this.deleteWordBackward()]
5674
+ ["delete-word-backward", () => this.deleteWordBackward()],
5675
+ ["submit", () => this.submit()]
5454
5676
  ]);
5455
5677
  }
5456
- handlePaste(text) {
5457
- this.insertText(text);
5678
+ handlePaste(event) {
5679
+ this.insertText(event.text);
5458
5680
  }
5459
5681
  handleKeyPress(key) {
5460
5682
  const keyName = typeof key === "string" ? key : key.name;
@@ -5489,17 +5711,6 @@ class TextareaRenderable extends EditBufferRenderable {
5489
5711
  }
5490
5712
  return false;
5491
5713
  }
5492
- get value() {
5493
- return this.editBuffer.getText();
5494
- }
5495
- set value(value) {
5496
- this.updateValue(value);
5497
- }
5498
- updateValue(value) {
5499
- this.editBuffer.setText(value, { history: false });
5500
- this.yogaNode.markDirty();
5501
- this.requestRender();
5502
- }
5503
5714
  updateColors() {
5504
5715
  const effectiveBg = this._focused ? this._focusedBackgroundColor : this._unfocusedBackgroundColor;
5505
5716
  const effectiveFg = this._focused ? this._focusedTextColor : this._unfocusedTextColor;
@@ -5606,7 +5817,7 @@ class TextareaRenderable extends EditBufferRenderable {
5606
5817
  const select = options?.select ?? false;
5607
5818
  this.handleShiftSelection(select, true);
5608
5819
  const eol = this.editBuffer.getEOL();
5609
- this.editBuffer.setCursor(eol.line, eol.visualColumn);
5820
+ this.editBuffer.setCursor(eol.row, eol.col);
5610
5821
  this.handleShiftSelection(select, false);
5611
5822
  this.requestRender();
5612
5823
  return true;
@@ -5624,8 +5835,8 @@ class TextareaRenderable extends EditBufferRenderable {
5624
5835
  deleteToLineEnd() {
5625
5836
  const cursor = this.editorView.getCursor();
5626
5837
  const eol = this.editBuffer.getEOL();
5627
- if (eol.visualColumn > cursor.col) {
5628
- this.editBuffer.deleteRange(cursor.row, cursor.col, eol.line, eol.visualColumn);
5838
+ if (eol.col > cursor.col) {
5839
+ this.editBuffer.deleteRange(cursor.row, cursor.col, eol.row, eol.col);
5629
5840
  }
5630
5841
  this.requestRender();
5631
5842
  return true;
@@ -5668,7 +5879,7 @@ class TextareaRenderable extends EditBufferRenderable {
5668
5879
  const currentCursor = this.editBuffer.getCursorPosition();
5669
5880
  const nextWord = this.editBuffer.getNextWordBoundary();
5670
5881
  if (nextWord.offset > currentCursor.offset) {
5671
- this.editBuffer.deleteRange(currentCursor.line, currentCursor.visualColumn, nextWord.line, nextWord.visualColumn);
5882
+ this.editBuffer.deleteRange(currentCursor.row, currentCursor.col, nextWord.row, nextWord.col);
5672
5883
  }
5673
5884
  this._ctx.clearSelection();
5674
5885
  this.requestRender();
@@ -5682,7 +5893,7 @@ class TextareaRenderable extends EditBufferRenderable {
5682
5893
  const currentCursor = this.editBuffer.getCursorPosition();
5683
5894
  const prevWord = this.editBuffer.getPrevWordBoundary();
5684
5895
  if (prevWord.offset < currentCursor.offset) {
5685
- this.editBuffer.deleteRange(prevWord.line, prevWord.visualColumn, currentCursor.line, currentCursor.visualColumn);
5896
+ this.editBuffer.deleteRange(prevWord.row, prevWord.col, currentCursor.row, currentCursor.col);
5686
5897
  }
5687
5898
  this._ctx.clearSelection();
5688
5899
  this.requestRender();
@@ -5721,7 +5932,7 @@ class TextareaRenderable extends EditBufferRenderable {
5721
5932
  set placeholder(value) {
5722
5933
  if (this._placeholder !== value) {
5723
5934
  this._placeholder = value;
5724
- this.editBuffer.setPlaceholder(value);
5935
+ this.applyPlaceholder(value);
5725
5936
  this.requestRender();
5726
5937
  }
5727
5938
  }
@@ -5759,14 +5970,31 @@ class TextareaRenderable extends EditBufferRenderable {
5759
5970
  this.updateColors();
5760
5971
  }
5761
5972
  }
5762
- set placeholderColor(value) {
5763
- const newColor = parseColor(value ?? TextareaRenderable.defaults.placeholderColor);
5764
- if (this._placeholderColor !== newColor) {
5765
- this._placeholderColor = newColor;
5766
- this.editBuffer.setPlaceholderColor(newColor);
5767
- this.requestRender();
5973
+ set initialValue(value) {
5974
+ if (!this._initialValueSet) {
5975
+ this.setText(value);
5976
+ this._initialValueSet = true;
5768
5977
  }
5769
5978
  }
5979
+ submit() {
5980
+ if (this._submitListener) {
5981
+ this._submitListener({});
5982
+ }
5983
+ return true;
5984
+ }
5985
+ set onSubmit(handler) {
5986
+ this._submitListener = handler;
5987
+ }
5988
+ get onSubmit() {
5989
+ return this._submitListener;
5990
+ }
5991
+ set keyBindings(bindings) {
5992
+ const mergedBindings = mergeKeyBindings(defaultTextareaKeybindings, bindings);
5993
+ this._keyBindingsMap = buildKeyBindingsMap(mergedBindings);
5994
+ }
5995
+ get extmarks() {
5996
+ return this.editorView.extmarks;
5997
+ }
5770
5998
  }
5771
5999
  export {
5772
6000
  yellow,
@@ -5839,6 +6067,7 @@ export {
5839
6067
  cyan,
5840
6068
  createTimeline,
5841
6069
  createTextAttributes,
6070
+ createExtmarksController,
5842
6071
  createCliRenderer,
5843
6072
  coordinateToCharacterIndex,
5844
6073
  convertThemeToStyles,
@@ -5894,6 +6123,7 @@ export {
5894
6123
  TabSelect,
5895
6124
  SyntaxStyle,
5896
6125
  StyledText,
6126
+ StdinBuffer,
5897
6127
  SliderRenderable,
5898
6128
  Selection,
5899
6129
  SelectRenderableEvents,
@@ -5925,6 +6155,7 @@ export {
5925
6155
  Generic,
5926
6156
  FrameBufferRenderable,
5927
6157
  FrameBuffer,
6158
+ ExtmarksController,
5928
6159
  EditorView,
5929
6160
  EditBuffer,
5930
6161
  DistortionEffect,
@@ -5948,5 +6179,5 @@ export {
5948
6179
  ASCIIFont
5949
6180
  };
5950
6181
 
5951
- //# debugId=C45C47BFE87C68C464756E2164756E21
6182
+ //# debugId=52657F382323749F64756E2164756E21
5952
6183
  //# sourceMappingURL=index.js.map