@opentui/core 0.1.100 → 0.1.102

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.
@@ -6,18 +6,18 @@ import {
6
6
  BaseRenderable,
7
7
  BorderCharArrays,
8
8
  BorderChars,
9
+ BoxRenderable,
9
10
  CliRenderEvents,
10
11
  CliRenderer,
12
+ CodeRenderable,
11
13
  ConsolePosition,
12
14
  DataPathsManager,
13
15
  DebugOverlayCorner,
14
- Edge,
15
16
  EditBuffer,
16
17
  EditBufferRenderable,
17
18
  EditBufferRenderableEvents,
18
19
  EditorView,
19
20
  ExtmarksController,
20
- Gutter,
21
21
  InternalKeyHandler,
22
22
  KeyEvent,
23
23
  KeyHandler,
@@ -36,16 +36,22 @@ import {
36
36
  RenderableEvents,
37
37
  RendererControlState,
38
38
  RootRenderable,
39
+ RootTextNodeRenderable,
39
40
  Selection,
40
41
  SpanInfoStruct,
41
42
  StdinParser,
42
43
  StyledText,
44
+ SyntaxStyle,
43
45
  SystemClock,
44
46
  TargetChannel,
45
47
  TerminalConsole,
46
48
  TerminalPalette,
47
49
  TextAttributes,
48
50
  TextBuffer,
51
+ TextBufferRenderable,
52
+ TextBufferView,
53
+ TextNodeRenderable,
54
+ TextRenderable,
49
55
  TreeSitterClient,
50
56
  __export,
51
57
  addDefaultParsers,
@@ -78,6 +84,7 @@ import {
78
84
  capture,
79
85
  clearEnvCache,
80
86
  convertGlobalToLocalSelection,
87
+ convertThemeToStyles,
81
88
  coordinateToCharacterIndex,
82
89
  createCliRenderer,
83
90
  createExtmarksController,
@@ -117,9 +124,9 @@ import {
117
124
  isEditBufferRenderable,
118
125
  isRenderable,
119
126
  isStyledText,
127
+ isTextNodeRenderable,
120
128
  isVNode,
121
129
  isValidBorderStyle,
122
- isValidPercentage,
123
130
  italic,
124
131
  link,
125
132
  magenta,
@@ -167,7 +174,7 @@ import {
167
174
  white,
168
175
  wrapWithDelegates,
169
176
  yellow
170
- } from "./index-zkcykvp8.js";
177
+ } from "./index-qpcsqve6.js";
171
178
 
172
179
  // src/index.ts
173
180
  var exports_src2 = {};
@@ -408,326 +415,6 @@ __export(exports_src2, {
408
415
  ACHROMATOPSIA_MATRIX: () => ACHROMATOPSIA_MATRIX
409
416
  });
410
417
 
411
- // src/text-buffer-view.ts
412
- class TextBufferView {
413
- lib;
414
- viewPtr;
415
- textBuffer;
416
- _destroyed = false;
417
- constructor(lib, ptr, textBuffer) {
418
- this.lib = lib;
419
- this.viewPtr = ptr;
420
- this.textBuffer = textBuffer;
421
- }
422
- static create(textBuffer) {
423
- const lib = resolveRenderLib();
424
- const viewPtr = lib.createTextBufferView(textBuffer.ptr);
425
- return new TextBufferView(lib, viewPtr, textBuffer);
426
- }
427
- guard() {
428
- if (this._destroyed)
429
- throw new Error("TextBufferView is destroyed");
430
- }
431
- get ptr() {
432
- this.guard();
433
- return this.viewPtr;
434
- }
435
- setSelection(start, end, bgColor, fgColor) {
436
- this.guard();
437
- this.lib.textBufferViewSetSelection(this.viewPtr, start, end, bgColor || null, fgColor || null);
438
- }
439
- updateSelection(end, bgColor, fgColor) {
440
- this.guard();
441
- this.lib.textBufferViewUpdateSelection(this.viewPtr, end, bgColor || null, fgColor || null);
442
- }
443
- resetSelection() {
444
- this.guard();
445
- this.lib.textBufferViewResetSelection(this.viewPtr);
446
- }
447
- getSelection() {
448
- this.guard();
449
- return this.lib.textBufferViewGetSelection(this.viewPtr);
450
- }
451
- hasSelection() {
452
- this.guard();
453
- return this.getSelection() !== null;
454
- }
455
- setLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
456
- this.guard();
457
- return this.lib.textBufferViewSetLocalSelection(this.viewPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
458
- }
459
- updateLocalSelection(anchorX, anchorY, focusX, focusY, bgColor, fgColor) {
460
- this.guard();
461
- return this.lib.textBufferViewUpdateLocalSelection(this.viewPtr, anchorX, anchorY, focusX, focusY, bgColor || null, fgColor || null);
462
- }
463
- resetLocalSelection() {
464
- this.guard();
465
- this.lib.textBufferViewResetLocalSelection(this.viewPtr);
466
- }
467
- setWrapWidth(width) {
468
- this.guard();
469
- this.lib.textBufferViewSetWrapWidth(this.viewPtr, width ?? 0);
470
- }
471
- setWrapMode(mode) {
472
- this.guard();
473
- this.lib.textBufferViewSetWrapMode(this.viewPtr, mode);
474
- }
475
- setViewportSize(width, height) {
476
- this.guard();
477
- this.lib.textBufferViewSetViewportSize(this.viewPtr, width, height);
478
- }
479
- setViewport(x, y, width, height) {
480
- this.guard();
481
- this.lib.textBufferViewSetViewport(this.viewPtr, x, y, width, height);
482
- }
483
- get lineInfo() {
484
- this.guard();
485
- return this.lib.textBufferViewGetLineInfo(this.viewPtr);
486
- }
487
- get logicalLineInfo() {
488
- this.guard();
489
- return this.lib.textBufferViewGetLogicalLineInfo(this.viewPtr);
490
- }
491
- getSelectedText() {
492
- this.guard();
493
- const byteSize = this.textBuffer.byteSize;
494
- if (byteSize === 0)
495
- return "";
496
- const selectedBytes = this.lib.textBufferViewGetSelectedTextBytes(this.viewPtr, byteSize);
497
- if (!selectedBytes)
498
- return "";
499
- return this.lib.decoder.decode(selectedBytes);
500
- }
501
- getPlainText() {
502
- this.guard();
503
- const byteSize = this.textBuffer.byteSize;
504
- if (byteSize === 0)
505
- return "";
506
- const plainBytes = this.lib.textBufferViewGetPlainTextBytes(this.viewPtr, byteSize);
507
- if (!plainBytes)
508
- return "";
509
- return this.lib.decoder.decode(plainBytes);
510
- }
511
- setTabIndicator(indicator) {
512
- this.guard();
513
- const codePoint = typeof indicator === "string" ? indicator.codePointAt(0) ?? 0 : indicator;
514
- this.lib.textBufferViewSetTabIndicator(this.viewPtr, codePoint);
515
- }
516
- setTabIndicatorColor(color) {
517
- this.guard();
518
- this.lib.textBufferViewSetTabIndicatorColor(this.viewPtr, color);
519
- }
520
- setTruncate(truncate) {
521
- this.guard();
522
- this.lib.textBufferViewSetTruncate(this.viewPtr, truncate);
523
- }
524
- measureForDimensions(width, height) {
525
- this.guard();
526
- return this.lib.textBufferViewMeasureForDimensions(this.viewPtr, width, height);
527
- }
528
- getVirtualLineCount() {
529
- this.guard();
530
- return this.lib.textBufferViewGetVirtualLineCount(this.viewPtr);
531
- }
532
- destroy() {
533
- if (this._destroyed)
534
- return;
535
- this._destroyed = true;
536
- this.lib.destroyTextBufferView(this.viewPtr);
537
- }
538
- }
539
- // src/syntax-style.ts
540
- function convertThemeToStyles(theme) {
541
- const flatStyles = {};
542
- for (const tokenStyle of theme) {
543
- const styleDefinition = {};
544
- if (tokenStyle.style.foreground) {
545
- styleDefinition.fg = parseColor(tokenStyle.style.foreground);
546
- }
547
- if (tokenStyle.style.background) {
548
- styleDefinition.bg = parseColor(tokenStyle.style.background);
549
- }
550
- if (tokenStyle.style.bold !== undefined) {
551
- styleDefinition.bold = tokenStyle.style.bold;
552
- }
553
- if (tokenStyle.style.italic !== undefined) {
554
- styleDefinition.italic = tokenStyle.style.italic;
555
- }
556
- if (tokenStyle.style.underline !== undefined) {
557
- styleDefinition.underline = tokenStyle.style.underline;
558
- }
559
- if (tokenStyle.style.dim !== undefined) {
560
- styleDefinition.dim = tokenStyle.style.dim;
561
- }
562
- for (const scope of tokenStyle.scope) {
563
- flatStyles[scope] = styleDefinition;
564
- }
565
- }
566
- return flatStyles;
567
- }
568
-
569
- class SyntaxStyle {
570
- lib;
571
- stylePtr;
572
- _destroyed = false;
573
- nameCache = new Map;
574
- styleDefs = new Map;
575
- mergedCache = new Map;
576
- constructor(lib, ptr) {
577
- this.lib = lib;
578
- this.stylePtr = ptr;
579
- }
580
- static create() {
581
- const lib = resolveRenderLib();
582
- const ptr = lib.createSyntaxStyle();
583
- return new SyntaxStyle(lib, ptr);
584
- }
585
- static fromTheme(theme) {
586
- const style = SyntaxStyle.create();
587
- const flatStyles = convertThemeToStyles(theme);
588
- for (const [name, styleDef] of Object.entries(flatStyles)) {
589
- style.registerStyle(name, styleDef);
590
- }
591
- return style;
592
- }
593
- static fromStyles(styles) {
594
- const style = SyntaxStyle.create();
595
- for (const [name, styleDef] of Object.entries(styles)) {
596
- style.registerStyle(name, styleDef);
597
- }
598
- return style;
599
- }
600
- guard() {
601
- if (this._destroyed)
602
- throw new Error("NativeSyntaxStyle is destroyed");
603
- }
604
- registerStyle(name, style) {
605
- this.guard();
606
- const attributes = createTextAttributes({
607
- bold: style.bold,
608
- italic: style.italic,
609
- underline: style.underline,
610
- dim: style.dim
611
- });
612
- const id = this.lib.syntaxStyleRegister(this.stylePtr, name, style.fg || null, style.bg || null, attributes);
613
- this.nameCache.set(name, id);
614
- this.styleDefs.set(name, style);
615
- return id;
616
- }
617
- resolveStyleId(name) {
618
- this.guard();
619
- const cached = this.nameCache.get(name);
620
- if (cached !== undefined)
621
- return cached;
622
- const id = this.lib.syntaxStyleResolveByName(this.stylePtr, name);
623
- if (id !== null) {
624
- this.nameCache.set(name, id);
625
- }
626
- return id;
627
- }
628
- getStyleId(name) {
629
- this.guard();
630
- const id = this.resolveStyleId(name);
631
- if (id !== null)
632
- return id;
633
- if (name.includes(".")) {
634
- const baseName = name.split(".")[0];
635
- return this.resolveStyleId(baseName);
636
- }
637
- return null;
638
- }
639
- get ptr() {
640
- this.guard();
641
- return this.stylePtr;
642
- }
643
- getStyleCount() {
644
- this.guard();
645
- return this.lib.syntaxStyleGetStyleCount(this.stylePtr);
646
- }
647
- clearNameCache() {
648
- this.nameCache.clear();
649
- }
650
- getStyle(name) {
651
- this.guard();
652
- if (Object.prototype.hasOwnProperty.call(this.styleDefs, name)) {
653
- return;
654
- }
655
- const style = this.styleDefs.get(name);
656
- if (style)
657
- return style;
658
- if (name.includes(".")) {
659
- const baseName = name.split(".")[0];
660
- if (Object.prototype.hasOwnProperty.call(this.styleDefs, baseName)) {
661
- return;
662
- }
663
- return this.styleDefs.get(baseName);
664
- }
665
- return;
666
- }
667
- mergeStyles(...styleNames) {
668
- this.guard();
669
- const cacheKey = styleNames.join(":");
670
- const cached = this.mergedCache.get(cacheKey);
671
- if (cached)
672
- return cached;
673
- const styleDefinition = {};
674
- for (const name of styleNames) {
675
- const style = this.getStyle(name);
676
- if (!style)
677
- continue;
678
- if (style.fg)
679
- styleDefinition.fg = style.fg;
680
- if (style.bg)
681
- styleDefinition.bg = style.bg;
682
- if (style.bold !== undefined)
683
- styleDefinition.bold = style.bold;
684
- if (style.italic !== undefined)
685
- styleDefinition.italic = style.italic;
686
- if (style.underline !== undefined)
687
- styleDefinition.underline = style.underline;
688
- if (style.dim !== undefined)
689
- styleDefinition.dim = style.dim;
690
- }
691
- const attributes = createTextAttributes({
692
- bold: styleDefinition.bold,
693
- italic: styleDefinition.italic,
694
- underline: styleDefinition.underline,
695
- dim: styleDefinition.dim
696
- });
697
- const merged = {
698
- fg: styleDefinition.fg,
699
- bg: styleDefinition.bg,
700
- attributes
701
- };
702
- this.mergedCache.set(cacheKey, merged);
703
- return merged;
704
- }
705
- clearCache() {
706
- this.guard();
707
- this.mergedCache.clear();
708
- }
709
- getCacheSize() {
710
- this.guard();
711
- return this.mergedCache.size;
712
- }
713
- getAllStyles() {
714
- this.guard();
715
- return new Map(this.styleDefs);
716
- }
717
- getRegisteredNames() {
718
- this.guard();
719
- return Array.from(this.styleDefs.keys());
720
- }
721
- destroy() {
722
- if (this._destroyed)
723
- return;
724
- this._destroyed = true;
725
- this.nameCache.clear();
726
- this.styleDefs.clear();
727
- this.mergedCache.clear();
728
- this.lib.destroySyntaxStyle(this.stylePtr);
729
- }
730
- }
731
418
  // src/post/effects.ts
732
419
  class DistortionEffect {
733
420
  glitchChancePerSecond = 0.5;
@@ -3385,1264 +3072,124 @@ class ASCIIFontRenderable extends FrameBufferRenderable {
3385
3072
  this._backgroundColor = options.backgroundColor || defaultOptions.backgroundColor;
3386
3073
  this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : undefined;
3387
3074
  this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : undefined;
3388
- this.selectable = options.selectable ?? true;
3389
- this.selectionHelper = new ASCIIFontSelectionHelper(() => this._text, () => this._font);
3390
- this.renderFontToBuffer();
3391
- }
3392
- get text() {
3393
- return this._text;
3394
- }
3395
- set text(value) {
3396
- this._text = value;
3397
- this.updateDimensions();
3398
- if (this.lastLocalSelection) {
3399
- this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
3400
- }
3401
- this.renderFontToBuffer();
3402
- this.requestRender();
3403
- }
3404
- get font() {
3405
- return this._font;
3406
- }
3407
- set font(value) {
3408
- this._font = value;
3409
- this.updateDimensions();
3410
- if (this.lastLocalSelection) {
3411
- this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
3412
- }
3413
- this.renderFontToBuffer();
3414
- this.requestRender();
3415
- }
3416
- get color() {
3417
- return this._color;
3418
- }
3419
- set color(value) {
3420
- this._color = value;
3421
- this.renderFontToBuffer();
3422
- this.requestRender();
3423
- }
3424
- get backgroundColor() {
3425
- return this._backgroundColor;
3426
- }
3427
- set backgroundColor(value) {
3428
- this._backgroundColor = value;
3429
- this.renderFontToBuffer();
3430
- this.requestRender();
3431
- }
3432
- updateDimensions() {
3433
- const measurements = measureText({ text: this._text, font: this._font });
3434
- this.width = measurements.width;
3435
- this.height = measurements.height;
3436
- }
3437
- shouldStartSelection(x, y) {
3438
- const localX = x - this.x;
3439
- const localY = y - this.y;
3440
- return this.selectionHelper.shouldStartSelection(localX, localY, this.width, this.height);
3441
- }
3442
- onSelectionChanged(selection) {
3443
- const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
3444
- this.lastLocalSelection = localSelection;
3445
- const changed = this.selectionHelper.onLocalSelectionChanged(localSelection, this.width, this.height);
3446
- if (changed) {
3447
- this.renderFontToBuffer();
3448
- this.requestRender();
3449
- }
3450
- return changed;
3451
- }
3452
- getSelectedText() {
3453
- const selection = this.selectionHelper.getSelection();
3454
- if (!selection)
3455
- return "";
3456
- return this._text.slice(selection.start, selection.end);
3457
- }
3458
- hasSelection() {
3459
- return this.selectionHelper.hasSelection();
3460
- }
3461
- onResize(width, height) {
3462
- super.onResize(width, height);
3463
- this.renderFontToBuffer();
3464
- }
3465
- renderFontToBuffer() {
3466
- if (this.isDestroyed)
3467
- return;
3468
- this.frameBuffer.clear(parseColor(this._backgroundColor));
3469
- renderFontToFrameBuffer(this.frameBuffer, {
3470
- text: this._text,
3471
- x: 0,
3472
- y: 0,
3473
- color: this.color,
3474
- backgroundColor: this._backgroundColor,
3475
- font: this._font
3476
- });
3477
- const selection = this.selectionHelper.getSelection();
3478
- if (selection && (this._selectionBg || this._selectionFg)) {
3479
- this.renderSelectionHighlight(selection);
3480
- }
3481
- }
3482
- renderSelectionHighlight(selection) {
3483
- if (!this._selectionBg && !this._selectionFg)
3484
- return;
3485
- const selectedText = this._text.slice(selection.start, selection.end);
3486
- if (!selectedText)
3487
- return;
3488
- const positions = getCharacterPositions(this._text, this._font);
3489
- const startX = positions[selection.start] || 0;
3490
- const endX = selection.end < positions.length ? positions[selection.end] : measureText({ text: this._text, font: this._font }).width;
3491
- if (this._selectionBg) {
3492
- this.frameBuffer.fillRect(startX, 0, endX - startX, this.height, parseColor(this._selectionBg));
3493
- }
3494
- if (this._selectionFg || this._selectionBg) {
3495
- renderFontToFrameBuffer(this.frameBuffer, {
3496
- text: selectedText,
3497
- x: startX,
3498
- y: 0,
3499
- color: this._selectionFg ? this._selectionFg : this._color,
3500
- backgroundColor: this._selectionBg ? this._selectionBg : this._backgroundColor,
3501
- font: this._font
3502
- });
3503
- }
3504
- }
3505
- }
3506
- // src/renderables/Box.ts
3507
- function isGapType(value) {
3508
- if (value === undefined) {
3509
- return true;
3510
- }
3511
- if (typeof value === "number" && !Number.isNaN(value)) {
3512
- return true;
3513
- }
3514
- return isValidPercentage(value);
3515
- }
3516
-
3517
- class BoxRenderable extends Renderable {
3518
- _backgroundColor;
3519
- _border;
3520
- _borderStyle;
3521
- _borderColor;
3522
- _focusedBorderColor;
3523
- _customBorderCharsObj;
3524
- _customBorderChars;
3525
- borderSides;
3526
- shouldFill;
3527
- _title;
3528
- _titleAlignment;
3529
- _bottomTitle;
3530
- _bottomTitleAlignment;
3531
- _defaultOptions = {
3532
- backgroundColor: "transparent",
3533
- borderStyle: "single",
3534
- border: false,
3535
- borderColor: "#FFFFFF",
3536
- shouldFill: true,
3537
- titleAlignment: "left",
3538
- bottomTitleAlignment: "left",
3539
- focusedBorderColor: "#00AAFF"
3540
- };
3541
- constructor(ctx, options) {
3542
- super(ctx, options);
3543
- if (options.focusable === true) {
3544
- this._focusable = true;
3545
- }
3546
- this._backgroundColor = parseColor(options.backgroundColor || this._defaultOptions.backgroundColor);
3547
- this._border = options.border ?? this._defaultOptions.border;
3548
- if (!options.border && (options.borderStyle || options.borderColor || options.focusedBorderColor || options.customBorderChars)) {
3549
- this._border = true;
3550
- }
3551
- this._borderStyle = parseBorderStyle(options.borderStyle, this._defaultOptions.borderStyle);
3552
- this._borderColor = parseColor(options.borderColor || this._defaultOptions.borderColor);
3553
- this._focusedBorderColor = parseColor(options.focusedBorderColor || this._defaultOptions.focusedBorderColor);
3554
- this._customBorderCharsObj = options.customBorderChars;
3555
- this._customBorderChars = this._customBorderCharsObj ? borderCharsToArray(this._customBorderCharsObj) : undefined;
3556
- this.borderSides = getBorderSides(this._border);
3557
- this.shouldFill = options.shouldFill ?? this._defaultOptions.shouldFill;
3558
- this._title = options.title;
3559
- this._titleAlignment = options.titleAlignment || this._defaultOptions.titleAlignment;
3560
- this._bottomTitle = options.bottomTitle;
3561
- this._bottomTitleAlignment = options.bottomTitleAlignment || this._defaultOptions.bottomTitleAlignment;
3562
- this.applyYogaBorders();
3563
- const hasInitialGapProps = options.gap !== undefined || options.rowGap !== undefined || options.columnGap !== undefined;
3564
- if (hasInitialGapProps) {
3565
- this.applyYogaGap(options);
3566
- }
3567
- }
3568
- initializeBorder() {
3569
- if (this._border === false) {
3570
- this._border = true;
3571
- this.borderSides = getBorderSides(this._border);
3572
- this.applyYogaBorders();
3573
- }
3574
- }
3575
- get customBorderChars() {
3576
- return this._customBorderCharsObj;
3577
- }
3578
- set customBorderChars(value) {
3579
- this._customBorderCharsObj = value;
3580
- this._customBorderChars = value ? borderCharsToArray(value) : undefined;
3581
- this.requestRender();
3582
- }
3583
- get backgroundColor() {
3584
- return this._backgroundColor;
3585
- }
3586
- set backgroundColor(value) {
3587
- const newColor = parseColor(value ?? this._defaultOptions.backgroundColor);
3588
- if (this._backgroundColor !== newColor) {
3589
- this._backgroundColor = newColor;
3590
- this.requestRender();
3591
- }
3592
- }
3593
- get border() {
3594
- return this._border;
3595
- }
3596
- set border(value) {
3597
- if (this._border !== value) {
3598
- this._border = value;
3599
- this.borderSides = getBorderSides(value);
3600
- this.applyYogaBorders();
3601
- this.requestRender();
3602
- }
3603
- }
3604
- get borderStyle() {
3605
- return this._borderStyle;
3606
- }
3607
- set borderStyle(value) {
3608
- const _value = parseBorderStyle(value, this._defaultOptions.borderStyle);
3609
- if (this._borderStyle !== _value || !this._border) {
3610
- this._borderStyle = _value;
3611
- this._customBorderChars = undefined;
3612
- this.initializeBorder();
3613
- this.requestRender();
3614
- }
3615
- }
3616
- get borderColor() {
3617
- return this._borderColor;
3618
- }
3619
- set borderColor(value) {
3620
- const newColor = parseColor(value ?? this._defaultOptions.borderColor);
3621
- if (this._borderColor !== newColor) {
3622
- this._borderColor = newColor;
3623
- this.initializeBorder();
3624
- this.requestRender();
3625
- }
3626
- }
3627
- get focusedBorderColor() {
3628
- return this._focusedBorderColor;
3629
- }
3630
- set focusedBorderColor(value) {
3631
- const newColor = parseColor(value ?? this._defaultOptions.focusedBorderColor);
3632
- if (this._focusedBorderColor !== newColor) {
3633
- this._focusedBorderColor = newColor;
3634
- this.initializeBorder();
3635
- if (this._focused) {
3636
- this.requestRender();
3637
- }
3638
- }
3639
- }
3640
- get title() {
3641
- return this._title;
3642
- }
3643
- set title(value) {
3644
- if (this._title !== value) {
3645
- this._title = value;
3646
- this.requestRender();
3647
- }
3648
- }
3649
- get titleAlignment() {
3650
- return this._titleAlignment;
3651
- }
3652
- set titleAlignment(value) {
3653
- if (this._titleAlignment !== value) {
3654
- this._titleAlignment = value;
3655
- this.requestRender();
3656
- }
3657
- }
3658
- get bottomTitle() {
3659
- return this._bottomTitle;
3660
- }
3661
- set bottomTitle(value) {
3662
- if (this._bottomTitle !== value) {
3663
- this._bottomTitle = value;
3664
- this.requestRender();
3665
- }
3666
- }
3667
- get bottomTitleAlignment() {
3668
- return this._bottomTitleAlignment;
3669
- }
3670
- set bottomTitleAlignment(value) {
3671
- if (this._bottomTitleAlignment !== value) {
3672
- this._bottomTitleAlignment = value;
3673
- this.requestRender();
3674
- }
3675
- }
3676
- renderSelf(buffer) {
3677
- const hasBorder = this.borderSides.top || this.borderSides.right || this.borderSides.bottom || this.borderSides.left;
3678
- const hasVisibleFill = this.shouldFill && this._backgroundColor.a > 0;
3679
- if (!hasBorder && !hasVisibleFill) {
3680
- return;
3681
- }
3682
- const hasFocusWithin = this._focusable && (this._focused || this._hasFocusedDescendant);
3683
- const currentBorderColor = hasFocusWithin ? this._focusedBorderColor : this._borderColor;
3684
- const screenX = this._screenX;
3685
- const screenY = this._screenY;
3686
- buffer.drawBox({
3687
- x: screenX,
3688
- y: screenY,
3689
- width: this.width,
3690
- height: this.height,
3691
- borderStyle: this._borderStyle,
3692
- customBorderChars: this._customBorderChars,
3693
- border: this._border,
3694
- borderColor: currentBorderColor,
3695
- backgroundColor: this._backgroundColor,
3696
- shouldFill: this.shouldFill,
3697
- title: this._title,
3698
- titleAlignment: this._titleAlignment,
3699
- bottomTitle: this._bottomTitle,
3700
- bottomTitleAlignment: this._bottomTitleAlignment
3701
- });
3702
- }
3703
- getScissorRect() {
3704
- const baseRect = super.getScissorRect();
3705
- if (!this.borderSides.top && !this.borderSides.right && !this.borderSides.bottom && !this.borderSides.left) {
3706
- return baseRect;
3707
- }
3708
- const leftInset = this.borderSides.left ? 1 : 0;
3709
- const rightInset = this.borderSides.right ? 1 : 0;
3710
- const topInset = this.borderSides.top ? 1 : 0;
3711
- const bottomInset = this.borderSides.bottom ? 1 : 0;
3712
- return {
3713
- x: baseRect.x + leftInset,
3714
- y: baseRect.y + topInset,
3715
- width: Math.max(0, baseRect.width - leftInset - rightInset),
3716
- height: Math.max(0, baseRect.height - topInset - bottomInset)
3717
- };
3718
- }
3719
- applyYogaBorders() {
3720
- const node = this.yogaNode;
3721
- node.setBorder(Edge.Left, this.borderSides.left ? 1 : 0);
3722
- node.setBorder(Edge.Right, this.borderSides.right ? 1 : 0);
3723
- node.setBorder(Edge.Top, this.borderSides.top ? 1 : 0);
3724
- node.setBorder(Edge.Bottom, this.borderSides.bottom ? 1 : 0);
3725
- this.requestRender();
3726
- }
3727
- applyYogaGap(options) {
3728
- const node = this.yogaNode;
3729
- if (isGapType(options.gap)) {
3730
- node.setGap(Gutter.All, options.gap);
3731
- }
3732
- if (isGapType(options.rowGap)) {
3733
- node.setGap(Gutter.Row, options.rowGap);
3734
- }
3735
- if (isGapType(options.columnGap)) {
3736
- node.setGap(Gutter.Column, options.columnGap);
3737
- }
3738
- }
3739
- set gap(gap) {
3740
- if (isGapType(gap)) {
3741
- this.yogaNode.setGap(Gutter.All, gap);
3742
- this.requestRender();
3743
- }
3744
- }
3745
- set rowGap(rowGap) {
3746
- if (isGapType(rowGap)) {
3747
- this.yogaNode.setGap(Gutter.Row, rowGap);
3748
- this.requestRender();
3749
- }
3750
- }
3751
- set columnGap(columnGap) {
3752
- if (isGapType(columnGap)) {
3753
- this.yogaNode.setGap(Gutter.Column, columnGap);
3754
- this.requestRender();
3755
- }
3756
- }
3757
- }
3758
- // src/renderables/TextBufferRenderable.ts
3759
- class TextBufferRenderable extends Renderable {
3760
- selectable = true;
3761
- _defaultFg;
3762
- _defaultBg;
3763
- _defaultAttributes;
3764
- _selectionBg;
3765
- _selectionFg;
3766
- _wrapMode = "word";
3767
- lastLocalSelection = null;
3768
- _tabIndicator;
3769
- _tabIndicatorColor;
3770
- _scrollX = 0;
3771
- _scrollY = 0;
3772
- _truncate = false;
3773
- textBuffer;
3774
- textBufferView;
3775
- _textBufferSyntaxStyle;
3776
- _defaultOptions = {
3777
- fg: RGBA.fromValues(1, 1, 1, 1),
3778
- bg: RGBA.fromValues(0, 0, 0, 0),
3779
- selectionBg: undefined,
3780
- selectionFg: undefined,
3781
- selectable: true,
3782
- attributes: 0,
3783
- wrapMode: "word",
3784
- tabIndicator: undefined,
3785
- tabIndicatorColor: undefined,
3786
- truncate: false
3787
- };
3788
- constructor(ctx, options) {
3789
- super(ctx, options);
3790
- this._defaultFg = parseColor(options.fg ?? this._defaultOptions.fg);
3791
- this._defaultBg = parseColor(options.bg ?? this._defaultOptions.bg);
3792
- this._defaultAttributes = options.attributes ?? this._defaultOptions.attributes;
3793
- this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : this._defaultOptions.selectionBg;
3794
- this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : this._defaultOptions.selectionFg;
3795
- this.selectable = options.selectable ?? this._defaultOptions.selectable;
3796
- this._wrapMode = options.wrapMode ?? this._defaultOptions.wrapMode;
3797
- this._tabIndicator = options.tabIndicator ?? this._defaultOptions.tabIndicator;
3798
- this._tabIndicatorColor = options.tabIndicatorColor ? parseColor(options.tabIndicatorColor) : this._defaultOptions.tabIndicatorColor;
3799
- this._truncate = options.truncate ?? this._defaultOptions.truncate;
3800
- this.textBuffer = TextBuffer.create(this._ctx.widthMethod);
3801
- this.textBufferView = TextBufferView.create(this.textBuffer);
3802
- this._textBufferSyntaxStyle = SyntaxStyle.create();
3803
- this.textBuffer.setSyntaxStyle(this._textBufferSyntaxStyle);
3804
- this.textBufferView.setWrapMode(this._wrapMode);
3805
- this.setupMeasureFunc();
3806
- this.textBuffer.setDefaultFg(this._defaultFg);
3807
- this.textBuffer.setDefaultBg(this._defaultBg);
3808
- this.textBuffer.setDefaultAttributes(this._defaultAttributes);
3809
- if (this._tabIndicator !== undefined) {
3810
- this.textBufferView.setTabIndicator(this._tabIndicator);
3811
- }
3812
- if (this._tabIndicatorColor !== undefined) {
3813
- this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor);
3814
- }
3815
- if (this._wrapMode !== "none" && this.width > 0) {
3816
- this.textBufferView.setWrapWidth(this.width);
3817
- }
3818
- if (this.width > 0 && this.height > 0) {
3819
- this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
3820
- }
3821
- this.textBufferView.setTruncate(this._truncate);
3822
- this.updateTextInfo();
3823
- }
3824
- onMouseEvent(event) {
3825
- if (event.type === "scroll") {
3826
- this.handleScroll(event);
3827
- }
3828
- }
3829
- handleScroll(event) {
3830
- if (!event.scroll)
3831
- return;
3832
- const { direction, delta } = event.scroll;
3833
- if (direction === "up") {
3834
- this.scrollY -= delta;
3835
- } else if (direction === "down") {
3836
- this.scrollY += delta;
3837
- }
3838
- if (this._wrapMode === "none") {
3839
- if (direction === "left") {
3840
- this.scrollX -= delta;
3841
- } else if (direction === "right") {
3842
- this.scrollX += delta;
3843
- }
3844
- }
3845
- }
3846
- get lineInfo() {
3847
- return this.textBufferView.logicalLineInfo;
3848
- }
3849
- get lineCount() {
3850
- return this.textBuffer.getLineCount();
3851
- }
3852
- get virtualLineCount() {
3853
- return this.textBufferView.getVirtualLineCount();
3854
- }
3855
- get scrollY() {
3856
- return this._scrollY;
3857
- }
3858
- set scrollY(value) {
3859
- const maxScrollY = Math.max(0, this.scrollHeight - this.height);
3860
- const clamped = Math.max(0, Math.min(value, maxScrollY));
3861
- if (this._scrollY !== clamped) {
3862
- this._scrollY = clamped;
3863
- this.updateViewportOffset();
3864
- this.requestRender();
3865
- }
3866
- }
3867
- get scrollX() {
3868
- return this._scrollX;
3869
- }
3870
- set scrollX(value) {
3871
- const maxScrollX = Math.max(0, this.scrollWidth - this.width);
3872
- const clamped = Math.max(0, Math.min(value, maxScrollX));
3873
- if (this._scrollX !== clamped) {
3874
- this._scrollX = clamped;
3875
- this.updateViewportOffset();
3876
- this.requestRender();
3877
- }
3878
- }
3879
- get scrollWidth() {
3880
- return this.lineInfo.lineWidthColsMax;
3881
- }
3882
- get scrollHeight() {
3883
- return this.lineInfo.lineStartCols.length;
3884
- }
3885
- get maxScrollY() {
3886
- return Math.max(0, this.scrollHeight - this.height);
3887
- }
3888
- get maxScrollX() {
3889
- return Math.max(0, this.scrollWidth - this.width);
3890
- }
3891
- updateViewportOffset() {
3892
- if (this.width > 0 && this.height > 0) {
3893
- this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
3894
- }
3895
- }
3896
- get plainText() {
3897
- return this.textBuffer.getPlainText();
3898
- }
3899
- get textLength() {
3900
- return this.textBuffer.length;
3901
- }
3902
- get fg() {
3903
- return this._defaultFg;
3904
- }
3905
- set fg(value) {
3906
- const newColor = parseColor(value ?? this._defaultOptions.fg);
3907
- if (this._defaultFg !== newColor) {
3908
- this._defaultFg = newColor;
3909
- this.textBuffer.setDefaultFg(this._defaultFg);
3910
- this.onFgChanged(newColor);
3911
- this.requestRender();
3912
- }
3913
- }
3914
- get selectionBg() {
3915
- return this._selectionBg;
3916
- }
3917
- set selectionBg(value) {
3918
- const newColor = value ? parseColor(value) : this._defaultOptions.selectionBg;
3919
- if (this._selectionBg !== newColor) {
3920
- this._selectionBg = newColor;
3921
- if (this.lastLocalSelection) {
3922
- this.updateLocalSelection(this.lastLocalSelection);
3923
- }
3924
- this.requestRender();
3925
- }
3926
- }
3927
- get selectionFg() {
3928
- return this._selectionFg;
3929
- }
3930
- set selectionFg(value) {
3931
- const newColor = value ? parseColor(value) : this._defaultOptions.selectionFg;
3932
- if (this._selectionFg !== newColor) {
3933
- this._selectionFg = newColor;
3934
- if (this.lastLocalSelection) {
3935
- this.updateLocalSelection(this.lastLocalSelection);
3936
- }
3937
- this.requestRender();
3938
- }
3939
- }
3940
- get bg() {
3941
- return this._defaultBg;
3942
- }
3943
- set bg(value) {
3944
- const newColor = parseColor(value ?? this._defaultOptions.bg);
3945
- if (this._defaultBg !== newColor) {
3946
- this._defaultBg = newColor;
3947
- this.textBuffer.setDefaultBg(this._defaultBg);
3948
- this.onBgChanged(newColor);
3949
- this.requestRender();
3950
- }
3951
- }
3952
- get attributes() {
3953
- return this._defaultAttributes;
3954
- }
3955
- set attributes(value) {
3956
- if (this._defaultAttributes !== value) {
3957
- this._defaultAttributes = value;
3958
- this.textBuffer.setDefaultAttributes(this._defaultAttributes);
3959
- this.onAttributesChanged(value);
3960
- this.requestRender();
3961
- }
3962
- }
3963
- get wrapMode() {
3964
- return this._wrapMode;
3965
- }
3966
- set wrapMode(value) {
3967
- if (this._wrapMode !== value) {
3968
- this._wrapMode = value;
3969
- this.textBufferView.setWrapMode(this._wrapMode);
3970
- if (value !== "none" && this.width > 0) {
3971
- this.textBufferView.setWrapWidth(this.width);
3972
- }
3973
- this.yogaNode.markDirty();
3974
- this.requestRender();
3975
- }
3976
- }
3977
- get tabIndicator() {
3978
- return this._tabIndicator;
3979
- }
3980
- set tabIndicator(value) {
3981
- if (this._tabIndicator !== value) {
3982
- this._tabIndicator = value;
3983
- if (value !== undefined) {
3984
- this.textBufferView.setTabIndicator(value);
3985
- }
3986
- this.requestRender();
3987
- }
3988
- }
3989
- get tabIndicatorColor() {
3990
- return this._tabIndicatorColor;
3991
- }
3992
- set tabIndicatorColor(value) {
3993
- const newColor = value ? parseColor(value) : undefined;
3994
- if (this._tabIndicatorColor !== newColor) {
3995
- this._tabIndicatorColor = newColor;
3996
- if (newColor !== undefined) {
3997
- this.textBufferView.setTabIndicatorColor(newColor);
3998
- }
3999
- this.requestRender();
4000
- }
4001
- }
4002
- get truncate() {
4003
- return this._truncate;
4004
- }
4005
- set truncate(value) {
4006
- if (this._truncate !== value) {
4007
- this._truncate = value;
4008
- this.textBufferView.setTruncate(value);
4009
- this.requestRender();
4010
- }
4011
- }
4012
- onResize(width, height) {
4013
- this.textBufferView.setViewport(this._scrollX, this._scrollY, width, height);
4014
- this.yogaNode.markDirty();
4015
- this.requestRender();
4016
- this.emit("line-info-change");
4017
- }
4018
- refreshLocalSelection() {
4019
- if (this.lastLocalSelection) {
4020
- return this.updateLocalSelection(this.lastLocalSelection);
4021
- }
4022
- return false;
4023
- }
4024
- updateLocalSelection(localSelection) {
4025
- if (!localSelection?.isActive) {
4026
- this.textBufferView.resetLocalSelection();
4027
- return true;
4028
- }
4029
- return this.textBufferView.setLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
4030
- }
4031
- updateTextInfo() {
4032
- if (this.lastLocalSelection) {
4033
- this.updateLocalSelection(this.lastLocalSelection);
4034
- }
4035
- this.yogaNode.markDirty();
4036
- this.requestRender();
4037
- this.emit("line-info-change");
4038
- }
4039
- setupMeasureFunc() {
4040
- const measureFunc = (width, widthMode, height, heightMode) => {
4041
- let effectiveWidth;
4042
- if (widthMode === MeasureMode.Undefined || isNaN(width)) {
4043
- effectiveWidth = 0;
4044
- } else {
4045
- effectiveWidth = width;
4046
- }
4047
- const effectiveHeight = isNaN(height) ? 1 : height;
4048
- const measureResult = this.textBufferView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
4049
- const measuredWidth = measureResult ? Math.max(1, measureResult.widthColsMax) : 1;
4050
- const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
4051
- if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
4052
- return {
4053
- width: Math.min(effectiveWidth, measuredWidth),
4054
- height: Math.min(effectiveHeight, measuredHeight)
4055
- };
4056
- }
4057
- return {
4058
- width: measuredWidth,
4059
- height: measuredHeight
4060
- };
4061
- };
4062
- this.yogaNode.setMeasureFunc(measureFunc);
4063
- }
4064
- shouldStartSelection(x, y) {
4065
- if (!this.selectable)
4066
- return false;
4067
- const localX = x - this.x;
4068
- const localY = y - this.y;
4069
- return localX >= 0 && localX < this.width && localY >= 0 && localY < this.height;
4070
- }
4071
- onSelectionChanged(selection) {
4072
- const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
4073
- this.lastLocalSelection = localSelection;
4074
- let changed;
4075
- if (!localSelection?.isActive) {
4076
- this.textBufferView.resetLocalSelection();
4077
- changed = true;
4078
- } else if (selection?.isStart) {
4079
- changed = this.textBufferView.setLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
4080
- } else {
4081
- changed = this.textBufferView.updateLocalSelection(localSelection.anchorX, localSelection.anchorY, localSelection.focusX, localSelection.focusY, this._selectionBg, this._selectionFg);
4082
- }
4083
- if (changed) {
4084
- this.requestRender();
4085
- }
4086
- return this.hasSelection();
4087
- }
4088
- getSelectedText() {
4089
- return this.textBufferView.getSelectedText();
4090
- }
4091
- hasSelection() {
4092
- return this.textBufferView.hasSelection();
4093
- }
4094
- getSelection() {
4095
- return this.textBufferView.getSelection();
4096
- }
4097
- render(buffer, deltaTime) {
4098
- if (!this.visible)
4099
- return;
4100
- const screenX = this._screenX;
4101
- const screenY = this._screenY;
4102
- this.markClean();
4103
- this._ctx.addToHitGrid(screenX, screenY, this.width, this.height, this.num);
4104
- this.renderSelf(buffer);
4105
- if (this.buffered && this.frameBuffer) {
4106
- buffer.drawFrameBuffer(screenX, screenY, this.frameBuffer);
4107
- }
4108
- }
4109
- renderSelf(buffer) {
4110
- if (this.textBuffer.ptr) {
4111
- buffer.drawTextBuffer(this.textBufferView, this._screenX, this._screenY);
4112
- }
4113
- }
4114
- destroy() {
4115
- if (this.isDestroyed)
4116
- return;
4117
- this.textBuffer.setSyntaxStyle(null);
4118
- this._textBufferSyntaxStyle.destroy();
4119
- this.textBufferView.destroy();
4120
- this.textBuffer.destroy();
4121
- super.destroy();
4122
- }
4123
- onFgChanged(newColor) {}
4124
- onBgChanged(newColor) {}
4125
- onAttributesChanged(newAttributes) {}
4126
- }
4127
-
4128
- // src/renderables/Code.ts
4129
- class CodeRenderable extends TextBufferRenderable {
4130
- _content;
4131
- _filetype;
4132
- _syntaxStyle;
4133
- _isHighlighting = false;
4134
- _treeSitterClient;
4135
- _highlightsDirty = false;
4136
- _highlightSnapshotId = 0;
4137
- _conceal;
4138
- _drawUnstyledText;
4139
- _shouldRenderTextBuffer = true;
4140
- _streaming;
4141
- _hadInitialContent = false;
4142
- _lastHighlights = [];
4143
- _onHighlight;
4144
- _onChunks;
4145
- _highlightingPromise = Promise.resolve();
4146
- _contentDefaultOptions = {
4147
- content: "",
4148
- conceal: true,
4149
- drawUnstyledText: true,
4150
- streaming: false
4151
- };
4152
- constructor(ctx, options) {
4153
- super(ctx, options);
4154
- this._content = options.content ?? this._contentDefaultOptions.content;
4155
- this._filetype = options.filetype;
4156
- this._syntaxStyle = options.syntaxStyle;
4157
- this._treeSitterClient = options.treeSitterClient ?? getTreeSitterClient();
4158
- this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
4159
- this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
4160
- this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
4161
- this._onHighlight = options.onHighlight;
4162
- this._onChunks = options.onChunks;
4163
- if (this._content.length > 0) {
4164
- this.textBuffer.setText(this._content);
4165
- this.updateTextInfo();
4166
- this._shouldRenderTextBuffer = this._drawUnstyledText || !this._filetype;
4167
- }
4168
- this._highlightsDirty = this._content.length > 0;
4169
- }
4170
- get content() {
4171
- return this._content;
4172
- }
4173
- set content(value) {
4174
- if (this._content !== value) {
4175
- this._content = value;
4176
- this._highlightsDirty = true;
4177
- this._highlightSnapshotId++;
4178
- if (this._streaming && !this._drawUnstyledText && this._filetype) {
4179
- return;
4180
- }
4181
- this.textBuffer.setText(value);
4182
- this.updateTextInfo();
4183
- }
4184
- }
4185
- get filetype() {
4186
- return this._filetype;
4187
- }
4188
- set filetype(value) {
4189
- if (this._filetype !== value) {
4190
- this._filetype = value;
4191
- this._highlightsDirty = true;
4192
- }
4193
- }
4194
- get syntaxStyle() {
4195
- return this._syntaxStyle;
4196
- }
4197
- set syntaxStyle(value) {
4198
- if (this._syntaxStyle !== value) {
4199
- this._syntaxStyle = value;
4200
- this._highlightsDirty = true;
4201
- }
4202
- }
4203
- get conceal() {
4204
- return this._conceal;
4205
- }
4206
- set conceal(value) {
4207
- if (this._conceal !== value) {
4208
- this._conceal = value;
4209
- this._highlightsDirty = true;
4210
- }
4211
- }
4212
- get drawUnstyledText() {
4213
- return this._drawUnstyledText;
4214
- }
4215
- set drawUnstyledText(value) {
4216
- if (this._drawUnstyledText !== value) {
4217
- this._drawUnstyledText = value;
4218
- this._highlightsDirty = true;
4219
- }
4220
- }
4221
- get streaming() {
4222
- return this._streaming;
4223
- }
4224
- set streaming(value) {
4225
- if (this._streaming !== value) {
4226
- this._streaming = value;
4227
- this._hadInitialContent = false;
4228
- this._lastHighlights = [];
4229
- this._highlightsDirty = true;
4230
- }
4231
- }
4232
- get treeSitterClient() {
4233
- return this._treeSitterClient;
4234
- }
4235
- set treeSitterClient(value) {
4236
- if (this._treeSitterClient !== value) {
4237
- this._treeSitterClient = value;
4238
- this._highlightsDirty = true;
4239
- }
4240
- }
4241
- get onHighlight() {
4242
- return this._onHighlight;
4243
- }
4244
- set onHighlight(value) {
4245
- if (this._onHighlight !== value) {
4246
- this._onHighlight = value;
4247
- this._highlightsDirty = true;
4248
- }
4249
- }
4250
- get onChunks() {
4251
- return this._onChunks;
4252
- }
4253
- set onChunks(value) {
4254
- if (this._onChunks !== value) {
4255
- this._onChunks = value;
4256
- this._highlightsDirty = true;
4257
- }
4258
- }
4259
- get isHighlighting() {
4260
- return this._isHighlighting;
4261
- }
4262
- get highlightingDone() {
4263
- return this._highlightingPromise;
4264
- }
4265
- async transformChunks(chunks, context) {
4266
- if (!this._onChunks)
4267
- return chunks;
4268
- const modified = await this._onChunks(chunks, context);
4269
- return modified ?? chunks;
4270
- }
4271
- ensureVisibleTextBeforeHighlight() {
4272
- if (this.isDestroyed)
4273
- return;
4274
- const content = this._content;
4275
- if (!this._filetype) {
4276
- this._shouldRenderTextBuffer = true;
4277
- return;
4278
- }
4279
- const isInitialContent = this._streaming && !this._hadInitialContent;
4280
- const shouldDrawUnstyledNow = this._streaming ? isInitialContent && this._drawUnstyledText : this._drawUnstyledText;
4281
- if (this._streaming && !isInitialContent) {
4282
- this._shouldRenderTextBuffer = true;
4283
- } else if (shouldDrawUnstyledNow) {
4284
- this.textBuffer.setText(content);
4285
- this._shouldRenderTextBuffer = true;
4286
- } else {
4287
- this._shouldRenderTextBuffer = false;
4288
- }
4289
- }
4290
- async startHighlight() {
4291
- const content = this._content;
4292
- const filetype = this._filetype;
4293
- const snapshotId = ++this._highlightSnapshotId;
4294
- if (!filetype)
4295
- return;
4296
- const isInitialContent = this._streaming && !this._hadInitialContent;
4297
- if (isInitialContent) {
4298
- this._hadInitialContent = true;
4299
- }
4300
- this._isHighlighting = true;
4301
- try {
4302
- const result = await this._treeSitterClient.highlightOnce(content, filetype);
4303
- if (snapshotId !== this._highlightSnapshotId) {
4304
- return;
4305
- }
4306
- if (this.isDestroyed)
4307
- return;
4308
- let highlights = result.highlights ?? [];
4309
- if (this._onHighlight && highlights.length >= 0) {
4310
- const context = {
4311
- content,
4312
- filetype,
4313
- syntaxStyle: this._syntaxStyle
4314
- };
4315
- const modified = await this._onHighlight(highlights, context);
4316
- if (modified !== undefined) {
4317
- highlights = modified;
4318
- }
4319
- }
4320
- if (snapshotId !== this._highlightSnapshotId) {
4321
- return;
4322
- }
4323
- if (this.isDestroyed)
4324
- return;
4325
- if (highlights.length > 0) {
4326
- if (this._streaming) {
4327
- this._lastHighlights = highlights;
4328
- }
4329
- }
4330
- if (highlights.length > 0 || this._onChunks) {
4331
- const context = {
4332
- content,
4333
- filetype,
4334
- syntaxStyle: this._syntaxStyle,
4335
- highlights
4336
- };
4337
- let chunks = treeSitterToTextChunks(content, highlights, this._syntaxStyle, {
4338
- enabled: this._conceal
4339
- });
4340
- chunks = await this.transformChunks(chunks, context);
4341
- if (snapshotId !== this._highlightSnapshotId) {
4342
- return;
4343
- }
4344
- if (this.isDestroyed)
4345
- return;
4346
- const styledText = new StyledText(chunks);
4347
- this.textBuffer.setStyledText(styledText);
4348
- } else {
4349
- this.textBuffer.setText(content);
4350
- }
4351
- this._shouldRenderTextBuffer = true;
4352
- this._isHighlighting = false;
4353
- this._highlightsDirty = false;
4354
- this.updateTextInfo();
4355
- this.requestRender();
4356
- } catch (error) {
4357
- if (snapshotId !== this._highlightSnapshotId) {
4358
- return;
4359
- }
4360
- console.warn("Code highlighting failed, falling back to plain text:", error);
4361
- if (this.isDestroyed)
4362
- return;
4363
- this.textBuffer.setText(content);
4364
- this._shouldRenderTextBuffer = true;
4365
- this._isHighlighting = false;
4366
- this._highlightsDirty = false;
4367
- this.updateTextInfo();
4368
- this.requestRender();
4369
- }
4370
- }
4371
- getLineHighlights(lineIdx) {
4372
- return this.textBuffer.getLineHighlights(lineIdx);
4373
- }
4374
- renderSelf(buffer) {
4375
- if (this._highlightsDirty) {
4376
- if (this.isDestroyed)
4377
- return;
4378
- if (this._content.length === 0) {
4379
- this._shouldRenderTextBuffer = false;
4380
- this._highlightsDirty = false;
4381
- } else if (!this._filetype) {
4382
- this._shouldRenderTextBuffer = true;
4383
- this._highlightsDirty = false;
4384
- } else {
4385
- this.ensureVisibleTextBeforeHighlight();
4386
- this._highlightsDirty = false;
4387
- this._highlightingPromise = this.startHighlight();
4388
- }
4389
- }
4390
- if (!this._shouldRenderTextBuffer)
4391
- return;
4392
- super.renderSelf(buffer);
4393
- }
4394
- }
4395
- // src/renderables/TextNode.ts
4396
- var BrandedTextNodeRenderable = Symbol.for("@opentui/core/TextNodeRenderable");
4397
- function isTextNodeRenderable(obj) {
4398
- return !!obj?.[BrandedTextNodeRenderable];
4399
- }
4400
- function styledTextToTextNodes(styledText) {
4401
- return styledText.chunks.map((chunk) => {
4402
- const node = new TextNodeRenderable({
4403
- fg: chunk.fg,
4404
- bg: chunk.bg,
4405
- attributes: chunk.attributes,
4406
- link: chunk.link
4407
- });
4408
- node.add(chunk.text);
4409
- return node;
4410
- });
4411
- }
4412
-
4413
- class TextNodeRenderable extends BaseRenderable {
4414
- [BrandedTextNodeRenderable] = true;
4415
- _fg;
4416
- _bg;
4417
- _attributes;
4418
- _link;
4419
- _children = [];
4420
- parent = null;
4421
- constructor(options) {
4422
- super(options);
4423
- this._fg = options.fg ? parseColor(options.fg) : undefined;
4424
- this._bg = options.bg ? parseColor(options.bg) : undefined;
4425
- this._attributes = options.attributes ?? 0;
4426
- this._link = options.link;
4427
- }
4428
- get children() {
4429
- return this._children;
4430
- }
4431
- set children(children) {
4432
- this._children = children;
4433
- this.requestRender();
4434
- }
4435
- requestRender() {
4436
- this.markDirty();
4437
- this.parent?.requestRender();
4438
- }
4439
- add(obj, index) {
4440
- if (typeof obj === "string") {
4441
- if (index !== undefined) {
4442
- this._children.splice(index, 0, obj);
4443
- this.requestRender();
4444
- return index;
4445
- }
4446
- const insertIndex = this._children.length;
4447
- this._children.push(obj);
4448
- this.requestRender();
4449
- return insertIndex;
4450
- }
4451
- if (isTextNodeRenderable(obj)) {
4452
- if (index !== undefined) {
4453
- this._children.splice(index, 0, obj);
4454
- obj.parent = this;
4455
- this.requestRender();
4456
- return index;
4457
- }
4458
- const insertIndex = this._children.length;
4459
- this._children.push(obj);
4460
- obj.parent = this;
4461
- this.requestRender();
4462
- return insertIndex;
4463
- }
4464
- if (isStyledText(obj)) {
4465
- const textNodes = styledTextToTextNodes(obj);
4466
- if (index !== undefined) {
4467
- this._children.splice(index, 0, ...textNodes);
4468
- textNodes.forEach((node) => node.parent = this);
4469
- this.requestRender();
4470
- return index;
4471
- }
4472
- const insertIndex = this._children.length;
4473
- this._children.push(...textNodes);
4474
- textNodes.forEach((node) => node.parent = this);
4475
- this.requestRender();
4476
- return insertIndex;
4477
- }
4478
- throw new Error("TextNodeRenderable only accepts strings, TextNodeRenderable instances, or StyledText instances");
3075
+ this.selectable = options.selectable ?? true;
3076
+ this.selectionHelper = new ASCIIFontSelectionHelper(() => this._text, () => this._font);
3077
+ this.renderFontToBuffer();
4479
3078
  }
4480
- replace(obj, index) {
4481
- this._children[index] = obj;
4482
- if (typeof obj !== "string") {
4483
- obj.parent = this;
4484
- }
4485
- this.requestRender();
3079
+ get text() {
3080
+ return this._text;
4486
3081
  }
4487
- insertBefore(child, anchorNode) {
4488
- if (!anchorNode || !isTextNodeRenderable(anchorNode)) {
4489
- throw new Error("Anchor must be a TextNodeRenderable");
4490
- }
4491
- const anchorIndex = this._children.indexOf(anchorNode);
4492
- if (anchorIndex === -1) {
4493
- throw new Error("Anchor node not found in children");
4494
- }
4495
- if (typeof child === "string") {
4496
- this._children.splice(anchorIndex, 0, child);
4497
- } else if (isTextNodeRenderable(child)) {
4498
- this._children.splice(anchorIndex, 0, child);
4499
- child.parent = this;
4500
- } else if (child instanceof StyledText) {
4501
- const textNodes = styledTextToTextNodes(child);
4502
- this._children.splice(anchorIndex, 0, ...textNodes);
4503
- textNodes.forEach((node) => node.parent = this);
4504
- } else {
4505
- throw new Error("Child must be a string, TextNodeRenderable, or StyledText instance");
3082
+ set text(value) {
3083
+ this._text = value;
3084
+ this.updateDimensions();
3085
+ if (this.lastLocalSelection) {
3086
+ this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
4506
3087
  }
3088
+ this.renderFontToBuffer();
4507
3089
  this.requestRender();
4508
- return this;
4509
3090
  }
4510
- remove(id) {
4511
- const childIndex = this.getRenderableIndex(id);
4512
- if (childIndex === -1) {
4513
- throw new Error("Child not found in children");
4514
- }
4515
- const child = this._children[childIndex];
4516
- this._children.splice(childIndex, 1);
4517
- child.parent = null;
4518
- this.requestRender();
4519
- return this;
3091
+ get font() {
3092
+ return this._font;
4520
3093
  }
4521
- clear() {
4522
- this._children = [];
3094
+ set font(value) {
3095
+ this._font = value;
3096
+ this.updateDimensions();
3097
+ if (this.lastLocalSelection) {
3098
+ this.selectionHelper.onLocalSelectionChanged(this.lastLocalSelection, this.width, this.height);
3099
+ }
3100
+ this.renderFontToBuffer();
4523
3101
  this.requestRender();
4524
3102
  }
4525
- mergeStyles(parentStyle) {
4526
- return {
4527
- fg: this._fg ?? parentStyle.fg,
4528
- bg: this._bg ?? parentStyle.bg,
4529
- attributes: this._attributes | parentStyle.attributes,
4530
- link: this._link ?? parentStyle.link
4531
- };
3103
+ get color() {
3104
+ return this._color;
4532
3105
  }
4533
- gatherWithInheritedStyle(parentStyle = {
4534
- fg: undefined,
4535
- bg: undefined,
4536
- attributes: 0
4537
- }) {
4538
- const currentStyle = this.mergeStyles(parentStyle);
4539
- const chunks = [];
4540
- for (const child of this._children) {
4541
- if (typeof child === "string") {
4542
- chunks.push({
4543
- __isChunk: true,
4544
- text: child,
4545
- fg: currentStyle.fg,
4546
- bg: currentStyle.bg,
4547
- attributes: currentStyle.attributes,
4548
- link: currentStyle.link
4549
- });
4550
- } else {
4551
- const childChunks = child.gatherWithInheritedStyle(currentStyle);
4552
- chunks.push(...childChunks);
4553
- }
4554
- }
4555
- this.markClean();
4556
- return chunks;
3106
+ set color(value) {
3107
+ this._color = value;
3108
+ this.renderFontToBuffer();
3109
+ this.requestRender();
4557
3110
  }
4558
- static fromString(text, options = {}) {
4559
- const node = new TextNodeRenderable(options);
4560
- node.add(text);
4561
- return node;
3111
+ get backgroundColor() {
3112
+ return this._backgroundColor;
4562
3113
  }
4563
- static fromNodes(nodes, options = {}) {
4564
- const node = new TextNodeRenderable(options);
4565
- for (const childNode of nodes) {
4566
- node.add(childNode);
4567
- }
4568
- return node;
3114
+ set backgroundColor(value) {
3115
+ this._backgroundColor = value;
3116
+ this.renderFontToBuffer();
3117
+ this.requestRender();
4569
3118
  }
4570
- toChunks(parentStyle = {
4571
- fg: undefined,
4572
- bg: undefined,
4573
- attributes: 0
4574
- }) {
4575
- return this.gatherWithInheritedStyle(parentStyle);
3119
+ updateDimensions() {
3120
+ const measurements = measureText({ text: this._text, font: this._font });
3121
+ this.width = measurements.width;
3122
+ this.height = measurements.height;
4576
3123
  }
4577
- getChildren() {
4578
- return this._children.filter((child) => typeof child !== "string");
3124
+ shouldStartSelection(x, y) {
3125
+ const localX = x - this.x;
3126
+ const localY = y - this.y;
3127
+ return this.selectionHelper.shouldStartSelection(localX, localY, this.width, this.height);
4579
3128
  }
4580
- getChildrenCount() {
4581
- return this._children.length;
3129
+ onSelectionChanged(selection) {
3130
+ const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
3131
+ this.lastLocalSelection = localSelection;
3132
+ const changed = this.selectionHelper.onLocalSelectionChanged(localSelection, this.width, this.height);
3133
+ if (changed) {
3134
+ this.renderFontToBuffer();
3135
+ this.requestRender();
3136
+ }
3137
+ return changed;
4582
3138
  }
4583
- getRenderable(id) {
4584
- return this._children.find((child) => typeof child !== "string" && child.id === id);
3139
+ getSelectedText() {
3140
+ const selection = this.selectionHelper.getSelection();
3141
+ if (!selection)
3142
+ return "";
3143
+ return this._text.slice(selection.start, selection.end);
4585
3144
  }
4586
- getRenderableIndex(id) {
4587
- return this._children.findIndex((child) => isTextNodeRenderable(child) && child.id === id);
3145
+ hasSelection() {
3146
+ return this.selectionHelper.hasSelection();
4588
3147
  }
4589
- get fg() {
4590
- return this._fg;
3148
+ onResize(width, height) {
3149
+ super.onResize(width, height);
3150
+ this.renderFontToBuffer();
4591
3151
  }
4592
- set fg(fg2) {
4593
- if (!fg2) {
4594
- this._fg = undefined;
4595
- this.requestRender();
3152
+ renderFontToBuffer() {
3153
+ if (this.isDestroyed)
4596
3154
  return;
3155
+ this.frameBuffer.clear(parseColor(this._backgroundColor));
3156
+ renderFontToFrameBuffer(this.frameBuffer, {
3157
+ text: this._text,
3158
+ x: 0,
3159
+ y: 0,
3160
+ color: this.color,
3161
+ backgroundColor: this._backgroundColor,
3162
+ font: this._font
3163
+ });
3164
+ const selection = this.selectionHelper.getSelection();
3165
+ if (selection && (this._selectionBg || this._selectionFg)) {
3166
+ this.renderSelectionHighlight(selection);
4597
3167
  }
4598
- this._fg = parseColor(fg2);
4599
- this.requestRender();
4600
3168
  }
4601
- set bg(bg2) {
4602
- if (!bg2) {
4603
- this._bg = undefined;
4604
- this.requestRender();
3169
+ renderSelectionHighlight(selection) {
3170
+ if (!this._selectionBg && !this._selectionFg)
4605
3171
  return;
3172
+ const selectedText = this._text.slice(selection.start, selection.end);
3173
+ if (!selectedText)
3174
+ return;
3175
+ const positions = getCharacterPositions(this._text, this._font);
3176
+ const startX = positions[selection.start] || 0;
3177
+ const endX = selection.end < positions.length ? positions[selection.end] : measureText({ text: this._text, font: this._font }).width;
3178
+ if (this._selectionBg) {
3179
+ this.frameBuffer.fillRect(startX, 0, endX - startX, this.height, parseColor(this._selectionBg));
3180
+ }
3181
+ if (this._selectionFg || this._selectionBg) {
3182
+ renderFontToFrameBuffer(this.frameBuffer, {
3183
+ text: selectedText,
3184
+ x: startX,
3185
+ y: 0,
3186
+ color: this._selectionFg ? this._selectionFg : this._color,
3187
+ backgroundColor: this._selectionBg ? this._selectionBg : this._backgroundColor,
3188
+ font: this._font
3189
+ });
4606
3190
  }
4607
- this._bg = parseColor(bg2);
4608
- this.requestRender();
4609
- }
4610
- get bg() {
4611
- return this._bg;
4612
- }
4613
- set attributes(attributes) {
4614
- this._attributes = attributes;
4615
- this.requestRender();
4616
- }
4617
- get attributes() {
4618
- return this._attributes;
4619
- }
4620
- set link(link2) {
4621
- this._link = link2;
4622
- this.requestRender();
4623
- }
4624
- get link() {
4625
- return this._link;
4626
- }
4627
- findDescendantById(id) {
4628
- return;
4629
- }
4630
- }
4631
-
4632
- class RootTextNodeRenderable extends TextNodeRenderable {
4633
- ctx;
4634
- textParent;
4635
- constructor(ctx, options, textParent) {
4636
- super(options);
4637
- this.ctx = ctx;
4638
- this.textParent = textParent;
4639
- }
4640
- requestRender() {
4641
- this.markDirty();
4642
- this.ctx.requestRender();
4643
3191
  }
4644
3192
  }
4645
-
4646
3193
  // src/renderables/composition/constructs.ts
4647
3194
  function Generic(props, ...children) {
4648
3195
  return h(VRenderable, props || {}, ...children);
@@ -5346,103 +3893,6 @@ function parsePatch(uniDiff) {
5346
3893
  }
5347
3894
  return list;
5348
3895
  }
5349
- // src/renderables/Text.ts
5350
- class TextRenderable extends TextBufferRenderable {
5351
- _text;
5352
- _hasManualStyledText = false;
5353
- rootTextNode;
5354
- _contentDefaultOptions = {
5355
- content: ""
5356
- };
5357
- constructor(ctx, options) {
5358
- super(ctx, options);
5359
- const content = options.content ?? this._contentDefaultOptions.content;
5360
- const styledText = typeof content === "string" ? stringToStyledText(content) : content;
5361
- this._text = styledText;
5362
- this._hasManualStyledText = options.content !== undefined && content !== "";
5363
- this.rootTextNode = new RootTextNodeRenderable(ctx, {
5364
- id: `${this.id}-root`,
5365
- fg: this._defaultFg,
5366
- bg: this._defaultBg,
5367
- attributes: this._defaultAttributes
5368
- }, this);
5369
- this.updateTextBuffer(styledText);
5370
- }
5371
- updateTextBuffer(styledText) {
5372
- this.textBuffer.setStyledText(styledText);
5373
- this.clearChunks(styledText);
5374
- }
5375
- clearChunks(styledText) {}
5376
- get content() {
5377
- return this._text;
5378
- }
5379
- get chunks() {
5380
- return this._text.chunks;
5381
- }
5382
- get textNode() {
5383
- return this.rootTextNode;
5384
- }
5385
- set content(value) {
5386
- this._hasManualStyledText = true;
5387
- const styledText = typeof value === "string" ? stringToStyledText(value) : value;
5388
- if (this._text !== styledText) {
5389
- this._text = styledText;
5390
- this.updateTextBuffer(styledText);
5391
- this.updateTextInfo();
5392
- }
5393
- }
5394
- updateTextFromNodes() {
5395
- if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
5396
- const chunks = this.rootTextNode.gatherWithInheritedStyle({
5397
- fg: this._defaultFg,
5398
- bg: this._defaultBg,
5399
- attributes: this._defaultAttributes,
5400
- link: undefined
5401
- });
5402
- this.textBuffer.setStyledText(new StyledText(chunks));
5403
- this.refreshLocalSelection();
5404
- this.yogaNode.markDirty();
5405
- }
5406
- }
5407
- add(obj, index) {
5408
- return this.rootTextNode.add(obj, index);
5409
- }
5410
- remove(id) {
5411
- this.rootTextNode.remove(id);
5412
- }
5413
- insertBefore(obj, anchor) {
5414
- this.rootTextNode.insertBefore(obj, anchor);
5415
- return this.rootTextNode.children.indexOf(obj);
5416
- }
5417
- getTextChildren() {
5418
- return this.rootTextNode.getChildren();
5419
- }
5420
- clear() {
5421
- this.rootTextNode.clear();
5422
- const emptyStyledText = stringToStyledText("");
5423
- this._text = emptyStyledText;
5424
- this.updateTextBuffer(emptyStyledText);
5425
- this.updateTextInfo();
5426
- this.requestRender();
5427
- }
5428
- onLifecyclePass = () => {
5429
- this.updateTextFromNodes();
5430
- };
5431
- onFgChanged(newColor) {
5432
- this.rootTextNode.fg = newColor;
5433
- }
5434
- onBgChanged(newColor) {
5435
- this.rootTextNode.bg = newColor;
5436
- }
5437
- onAttributesChanged(newAttributes) {
5438
- this.rootTextNode.attributes = newAttributes;
5439
- }
5440
- destroy() {
5441
- this.rootTextNode.children.length = 0;
5442
- super.destroy();
5443
- }
5444
- }
5445
-
5446
3896
  // src/renderables/Diff.ts
5447
3897
  class DiffRenderable extends Renderable {
5448
3898
  _diff;
@@ -6895,6 +5345,7 @@ class TextTableRenderable extends Renderable {
6895
5345
  _columnWidthMode;
6896
5346
  _columnFitter;
6897
5347
  _cellPadding;
5348
+ _columnGap;
6898
5349
  _showBorders;
6899
5350
  _border;
6900
5351
  _outerBorder;
@@ -6925,6 +5376,7 @@ class TextTableRenderable extends Renderable {
6925
5376
  columnWidthMode: "full",
6926
5377
  columnFitter: "proportional",
6927
5378
  cellPadding: 0,
5379
+ columnGap: 0,
6928
5380
  showBorders: true,
6929
5381
  border: true,
6930
5382
  outerBorder: true,
@@ -6946,6 +5398,7 @@ class TextTableRenderable extends Renderable {
6946
5398
  this._columnWidthMode = options.columnWidthMode ?? this._defaultOptions.columnWidthMode;
6947
5399
  this._columnFitter = this.resolveColumnFitter(options.columnFitter);
6948
5400
  this._cellPadding = this.resolveCellPadding(options.cellPadding);
5401
+ this._columnGap = this.resolveColumnGap(options.columnGap);
6949
5402
  this._showBorders = options.showBorders ?? this._defaultOptions.showBorders;
6950
5403
  this._border = options.border ?? this._defaultOptions.border;
6951
5404
  this._hasExplicitOuterBorder = options.outerBorder !== undefined;
@@ -7013,6 +5466,16 @@ class TextTableRenderable extends Renderable {
7013
5466
  this._cellPadding = next;
7014
5467
  this.invalidateLayoutAndRaster();
7015
5468
  }
5469
+ get columnGap() {
5470
+ return this._columnGap;
5471
+ }
5472
+ set columnGap(value) {
5473
+ const next = this.resolveColumnGap(value);
5474
+ if (this._columnGap === next)
5475
+ return;
5476
+ this._columnGap = next;
5477
+ this.invalidateLayoutAndRaster();
5478
+ }
7016
5479
  get showBorders() {
7017
5480
  return this._showBorders;
7018
5481
  }
@@ -7326,7 +5789,7 @@ class TextTableRenderable extends Renderable {
7326
5789
  const borderLayout = this.resolveBorderLayout();
7327
5790
  const columnWidths = this.computeColumnWidths(maxTableWidth, borderLayout);
7328
5791
  const rowHeights = this.computeRowHeights(columnWidths);
7329
- const columnOffsets = this.computeOffsets(columnWidths, borderLayout.left, borderLayout.right, borderLayout.innerVertical);
5792
+ const columnOffsets = this.computeOffsets(columnWidths, borderLayout.left, borderLayout.right, borderLayout.innerVertical, this.getInterColumnGap(borderLayout));
7330
5793
  const rowOffsets = this.computeOffsets(rowHeights, borderLayout.top, borderLayout.bottom, borderLayout.innerHorizontal);
7331
5794
  return {
7332
5795
  columnWidths,
@@ -7358,7 +5821,7 @@ class TextTableRenderable extends Renderable {
7358
5821
  if (maxTableWidth === undefined || !Number.isFinite(maxTableWidth) || maxTableWidth <= 0) {
7359
5822
  return intrinsicWidths;
7360
5823
  }
7361
- const maxContentWidth = Math.max(1, Math.floor(maxTableWidth) - this.getVerticalBorderCount(borderLayout));
5824
+ const maxContentWidth = Math.max(1, Math.floor(maxTableWidth) - this.getVerticalBorderCount(borderLayout) - this.getTotalInterColumnGap(borderLayout));
7362
5825
  const currentWidth = intrinsicWidths.reduce((sum, width) => sum + width, 0);
7363
5826
  if (currentWidth === maxContentWidth) {
7364
5827
  return intrinsicWidths;
@@ -7541,17 +6004,26 @@ class TextTableRenderable extends Renderable {
7541
6004
  }
7542
6005
  return rowHeights;
7543
6006
  }
7544
- computeOffsets(parts, startBoundary, endBoundary, includeInnerBoundaries) {
6007
+ computeOffsets(parts, startBoundary, endBoundary, includeInnerBoundaries, innerGap = 0) {
7545
6008
  const offsets = [startBoundary ? 0 : -1];
7546
6009
  let cursor = offsets[0] ?? 0;
7547
6010
  for (let idx = 0;idx < parts.length; idx++) {
7548
6011
  const size = parts[idx] ?? 1;
7549
- const hasBoundaryAfter = idx < parts.length - 1 ? includeInnerBoundaries : endBoundary;
7550
- cursor += size + (hasBoundaryAfter ? 1 : 0);
6012
+ const separatorAfter = idx < parts.length - 1 ? includeInnerBoundaries ? 1 : innerGap : endBoundary ? 1 : 0;
6013
+ cursor += size + separatorAfter;
7551
6014
  offsets.push(cursor);
7552
6015
  }
7553
6016
  return offsets;
7554
6017
  }
6018
+ getInterColumnGap(borderLayout) {
6019
+ if (borderLayout.innerVertical) {
6020
+ return 0;
6021
+ }
6022
+ return this._columnGap;
6023
+ }
6024
+ getTotalInterColumnGap(borderLayout) {
6025
+ return Math.max(0, this._columnCount - 1) * this.getInterColumnGap(borderLayout);
6026
+ }
7555
6027
  applyLayoutToViews(layout) {
7556
6028
  const horizontalPadding = this.getHorizontalCellPadding();
7557
6029
  const verticalPadding = this.getVerticalCellPadding();
@@ -7870,6 +6342,12 @@ class TextTableRenderable extends Renderable {
7870
6342
  }
7871
6343
  return Math.max(0, Math.floor(value));
7872
6344
  }
6345
+ resolveColumnGap(value) {
6346
+ if (value === undefined || !Number.isFinite(value)) {
6347
+ return this._defaultOptions.columnGap;
6348
+ }
6349
+ return Math.max(0, Math.floor(value));
6350
+ }
7873
6351
  invalidateLayoutAndRaster(markYogaDirty = true) {
7874
6352
  this._layoutDirty = true;
7875
6353
  this._rasterDirty = true;
@@ -9156,9 +7634,13 @@ function parseMarkdownIncremental(newContent, prevState, trailingUnstable = 2) {
9156
7634
  if (!prevState || prevState.tokens.length === 0) {
9157
7635
  try {
9158
7636
  const tokens = x.lex(newContent, { gfm: true });
9159
- return { content: newContent, tokens };
7637
+ return {
7638
+ content: newContent,
7639
+ tokens,
7640
+ stableTokenCount: Math.max(0, tokens.length - trailingUnstable)
7641
+ };
9160
7642
  } catch {
9161
- return { content: newContent, tokens: [] };
7643
+ return { content: newContent, tokens: [], stableTokenCount: 0 };
9162
7644
  }
9163
7645
  }
9164
7646
  let offset = 0;
@@ -9180,23 +7662,32 @@ function parseMarkdownIncremental(newContent, prevState, trailingUnstable = 2) {
9180
7662
  const stableTokens = prevState.tokens.slice(0, reuseCount);
9181
7663
  const remainingContent = newContent.slice(offset);
9182
7664
  if (!remainingContent) {
9183
- return { content: newContent, tokens: stableTokens };
7665
+ return {
7666
+ content: newContent,
7667
+ tokens: stableTokens,
7668
+ stableTokenCount: stableTokens.length
7669
+ };
9184
7670
  }
9185
7671
  try {
9186
7672
  const newTokens = x.lex(remainingContent, { gfm: true });
9187
- return { content: newContent, tokens: [...stableTokens, ...newTokens] };
7673
+ return {
7674
+ content: newContent,
7675
+ tokens: [...stableTokens, ...newTokens],
7676
+ stableTokenCount: trailingUnstable === 0 ? stableTokens.length + newTokens.length : stableTokens.length
7677
+ };
9188
7678
  } catch {
9189
7679
  try {
9190
7680
  const fullTokens = x.lex(newContent, { gfm: true });
9191
- return { content: newContent, tokens: fullTokens };
7681
+ return { content: newContent, tokens: fullTokens, stableTokenCount: 0 };
9192
7682
  } catch {
9193
- return { content: newContent, tokens: [] };
7683
+ return { content: newContent, tokens: [], stableTokenCount: 0 };
9194
7684
  }
9195
7685
  }
9196
7686
  }
9197
7687
 
9198
7688
  // src/renderables/Markdown.ts
9199
7689
  var TRAILING_MARKDOWN_BLOCK_BREAKS_RE = /(?:\r?\n){2,}$/;
7690
+ var TRAILING_MARKDOWN_BLOCK_NEWLINES_RE = /(?:\r?\n)+$/;
9200
7691
  function colorsEqual(left, right) {
9201
7692
  if (!left || !right)
9202
7693
  return left === right;
@@ -9213,9 +7704,11 @@ class MarkdownRenderable extends Renderable {
9213
7704
  _treeSitterClient;
9214
7705
  _tableOptions;
9215
7706
  _renderNode;
7707
+ _internalBlockMode;
9216
7708
  _parseState = null;
9217
7709
  _streaming = false;
9218
7710
  _blockStates = [];
7711
+ _stableBlockCount = 0;
9219
7712
  _styleDirty = false;
9220
7713
  _linkifyMarkdownChunks = (chunks, context) => detectLinks(chunks, {
9221
7714
  content: context.content,
@@ -9225,7 +7718,8 @@ class MarkdownRenderable extends Renderable {
9225
7718
  content: "",
9226
7719
  conceal: true,
9227
7720
  concealCode: false,
9228
- streaming: false
7721
+ streaming: false,
7722
+ internalBlockMode: "coalesced"
9229
7723
  };
9230
7724
  constructor(ctx, options) {
9231
7725
  super(ctx, {
@@ -9243,6 +7737,7 @@ class MarkdownRenderable extends Renderable {
9243
7737
  this._tableOptions = options.tableOptions;
9244
7738
  this._renderNode = options.renderNode;
9245
7739
  this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
7740
+ this._internalBlockMode = options.internalBlockMode ?? this._contentDefaultOptions.internalBlockMode;
9246
7741
  this.updateBlocks();
9247
7742
  }
9248
7743
  get content() {
@@ -9474,6 +7969,10 @@ class MarkdownRenderable extends Renderable {
9474
7969
  break;
9475
7970
  }
9476
7971
  }
7972
+ applyMargins(renderable, marginTop, marginBottom) {
7973
+ renderable.marginTop = marginTop;
7974
+ renderable.marginBottom = marginBottom;
7975
+ }
9477
7976
  createMarkdownCodeRenderable(content, id, marginBottom = 0) {
9478
7977
  return new CodeRenderable(this.ctx, {
9479
7978
  id,
@@ -9549,6 +8048,9 @@ class MarkdownRenderable extends Renderable {
9549
8048
  return raw.replace(TRAILING_MARKDOWN_BLOCK_BREAKS_RE, `
9550
8049
  `);
9551
8050
  }
8051
+ normalizeScrollbackMarkdownBlockRaw(raw) {
8052
+ return raw.replace(TRAILING_MARKDOWN_BLOCK_NEWLINES_RE, "");
8053
+ }
9552
8054
  buildRenderableTokens(tokens) {
9553
8055
  if (this._renderNode) {
9554
8056
  return tokens.filter((token) => token.type !== "space");
@@ -9590,6 +8092,26 @@ class MarkdownRenderable extends Renderable {
9590
8092
  flushMarkdownRaw();
9591
8093
  return renderTokens;
9592
8094
  }
8095
+ buildTopLevelRenderBlocks(tokens) {
8096
+ const blocks = [];
8097
+ let gapBefore = "";
8098
+ for (let i = 0;i < tokens.length; i += 1) {
8099
+ const token = tokens[i];
8100
+ if (token.type === "space") {
8101
+ gapBefore += token.raw;
8102
+ continue;
8103
+ }
8104
+ const prev = blocks[blocks.length - 1];
8105
+ const marginTop = prev && (this.shouldRenderSeparately(prev.token) || TRAILING_MARKDOWN_BLOCK_BREAKS_RE.test(prev.token.raw + gapBefore)) ? 1 : 0;
8106
+ blocks.push({
8107
+ token,
8108
+ sourceTokenEnd: i + 1,
8109
+ marginTop
8110
+ });
8111
+ gapBefore = "";
8112
+ }
8113
+ return blocks;
8114
+ }
9593
8115
  getTableRowsToRender(table) {
9594
8116
  return table.rows;
9595
8117
  }
@@ -9711,13 +8233,29 @@ class MarkdownRenderable extends Renderable {
9711
8233
  changed
9712
8234
  };
9713
8235
  }
8236
+ resolveTableStyle(options = this._tableOptions) {
8237
+ if (options?.style === "columns") {
8238
+ return "columns";
8239
+ }
8240
+ if (options?.style === "grid") {
8241
+ return "grid";
8242
+ }
8243
+ return this._internalBlockMode === "top-level" ? "columns" : "grid";
8244
+ }
8245
+ usesBorderlessColumnSpacing(options = this._tableOptions) {
8246
+ const style = this.resolveTableStyle(options);
8247
+ const borders = options?.borders ?? style === "grid";
8248
+ return style === "columns" && !borders;
8249
+ }
9714
8250
  resolveTableRenderableOptions() {
9715
- const borders = this._tableOptions?.borders ?? true;
8251
+ const style = this.resolveTableStyle();
8252
+ const borders = this._tableOptions?.borders ?? style === "grid";
9716
8253
  return {
9717
- columnWidthMode: this._tableOptions?.widthMode ?? "full",
8254
+ columnWidthMode: this._tableOptions?.widthMode ?? (style === "columns" ? "content" : "full"),
9718
8255
  columnFitter: this._tableOptions?.columnFitter ?? "proportional",
9719
8256
  wrapMode: this._tableOptions?.wrapMode ?? "word",
9720
8257
  cellPadding: this._tableOptions?.cellPadding ?? 0,
8258
+ columnGap: this.usesBorderlessColumnSpacing() ? 2 : 0,
9721
8259
  border: borders,
9722
8260
  outerBorder: this._tableOptions?.outerBorder ?? borders,
9723
8261
  showBorders: borders,
@@ -9731,6 +8269,7 @@ class MarkdownRenderable extends Renderable {
9731
8269
  tableRenderable.columnFitter = options.columnFitter;
9732
8270
  tableRenderable.wrapMode = options.wrapMode;
9733
8271
  tableRenderable.cellPadding = options.cellPadding;
8272
+ tableRenderable.columnGap = options.columnGap;
9734
8273
  tableRenderable.border = options.border;
9735
8274
  tableRenderable.outerBorder = options.outerBorder;
9736
8275
  tableRenderable.showBorders = options.showBorders;
@@ -9762,6 +8301,7 @@ class MarkdownRenderable extends Renderable {
9762
8301
  columnFitter: options.columnFitter,
9763
8302
  wrapMode: options.wrapMode,
9764
8303
  cellPadding: options.cellPadding,
8304
+ columnGap: options.columnGap,
9765
8305
  border: options.border,
9766
8306
  outerBorder: options.outerBorder,
9767
8307
  showBorders: options.showBorders,
@@ -9782,6 +8322,75 @@ class MarkdownRenderable extends Renderable {
9782
8322
  tableContentCache: cache
9783
8323
  };
9784
8324
  }
8325
+ getStableBlockCount(blocks, stableTokenCount) {
8326
+ if (this._internalBlockMode !== "top-level") {
8327
+ return 0;
8328
+ }
8329
+ let stableBlockCount = 0;
8330
+ for (const block of blocks) {
8331
+ if (block.sourceTokenEnd <= stableTokenCount) {
8332
+ stableBlockCount += 1;
8333
+ continue;
8334
+ }
8335
+ break;
8336
+ }
8337
+ return stableBlockCount;
8338
+ }
8339
+ syncTopLevelBlockState(state, block, tableContentCache = state.tableContentCache) {
8340
+ state.token = block.token;
8341
+ state.tokenRaw = block.token.raw;
8342
+ state.marginTop = block.marginTop;
8343
+ state.tableContentCache = tableContentCache;
8344
+ }
8345
+ getTopLevelBlockRaw(token) {
8346
+ if (!token.raw) {
8347
+ return;
8348
+ }
8349
+ return this.shouldRenderSeparately(token) ? token.raw : this.normalizeScrollbackMarkdownBlockRaw(token.raw);
8350
+ }
8351
+ createTopLevelDefaultRenderable(block, index) {
8352
+ const { token, marginTop } = block;
8353
+ const id = `${this.id}-block-${index}`;
8354
+ if (token.type === "code") {
8355
+ const renderable2 = this.createCodeRenderable(token, id);
8356
+ renderable2.marginTop = marginTop;
8357
+ return { renderable: renderable2 };
8358
+ }
8359
+ if (token.type === "table") {
8360
+ const next = this.createTableBlock(token, id);
8361
+ next.renderable.marginTop = marginTop;
8362
+ return next;
8363
+ }
8364
+ const markdownRaw = this.getTopLevelBlockRaw(token);
8365
+ if (!markdownRaw) {
8366
+ return { renderable: undefined };
8367
+ }
8368
+ const renderable = this.createMarkdownCodeRenderable(markdownRaw, id);
8369
+ renderable.marginTop = marginTop;
8370
+ return { renderable };
8371
+ }
8372
+ createTopLevelRenderable(block, index) {
8373
+ if (!this._renderNode) {
8374
+ return this.createTopLevelDefaultRenderable(block, index);
8375
+ }
8376
+ let next;
8377
+ const context = {
8378
+ syntaxStyle: this._syntaxStyle,
8379
+ conceal: this._conceal,
8380
+ concealCode: this._concealCode,
8381
+ treeSitterClient: this._treeSitterClient,
8382
+ defaultRender: () => {
8383
+ next = this.createTopLevelDefaultRenderable(block, index);
8384
+ return next.renderable ?? null;
8385
+ }
8386
+ };
8387
+ const custom = this._renderNode(block.token, context);
8388
+ if (custom) {
8389
+ this.applyMargins(custom, block.marginTop, 0);
8390
+ return { renderable: custom };
8391
+ }
8392
+ return next ?? this.createTopLevelDefaultRenderable(block, index);
8393
+ }
9785
8394
  createDefaultRenderable(token, index, hasNextToken = false) {
9786
8395
  const id = `${this.id}-block-${index}`;
9787
8396
  const marginBottom = this.getInterBlockMargin(token, hasNextToken);
@@ -9846,12 +8455,57 @@ class MarkdownRenderable extends Renderable {
9846
8455
  this.add(markdownRenderable);
9847
8456
  state.renderable = markdownRenderable;
9848
8457
  }
8458
+ updateTopLevelBlocks(tokens, forceTableRefresh) {
8459
+ const blocks = this.buildTopLevelRenderBlocks(tokens);
8460
+ this._stableBlockCount = this.getStableBlockCount(blocks, this._parseState?.stableTokenCount ?? 0);
8461
+ let blockIndex = 0;
8462
+ for (let i = 0;i < blocks.length; i += 1) {
8463
+ const block = blocks[i];
8464
+ const existing = this._blockStates[blockIndex];
8465
+ if (existing && existing.token === block.token && !forceTableRefresh) {
8466
+ if (existing.marginTop !== block.marginTop) {
8467
+ this.applyMargins(existing.renderable, block.marginTop, 0);
8468
+ }
8469
+ this.syncTopLevelBlockState(existing, block);
8470
+ blockIndex++;
8471
+ continue;
8472
+ }
8473
+ if (existing && existing.tokenRaw === block.token.raw && existing.token.type === block.token.type && !forceTableRefresh) {
8474
+ if (existing.marginTop !== block.marginTop) {
8475
+ this.applyMargins(existing.renderable, block.marginTop, 0);
8476
+ }
8477
+ this.syncTopLevelBlockState(existing, block);
8478
+ blockIndex++;
8479
+ continue;
8480
+ }
8481
+ if (existing) {
8482
+ existing.renderable.destroyRecursively();
8483
+ }
8484
+ const next = this.createTopLevelRenderable(block, blockIndex);
8485
+ if (next.renderable) {
8486
+ this.add(next.renderable);
8487
+ this._blockStates[blockIndex] = {
8488
+ token: block.token,
8489
+ tokenRaw: block.token.raw,
8490
+ marginTop: block.marginTop,
8491
+ renderable: next.renderable,
8492
+ tableContentCache: next.tableContentCache
8493
+ };
8494
+ }
8495
+ blockIndex++;
8496
+ }
8497
+ while (this._blockStates.length > blockIndex) {
8498
+ const removed = this._blockStates.pop();
8499
+ removed.renderable.destroyRecursively();
8500
+ }
8501
+ }
9849
8502
  updateBlocks(forceTableRefresh = false) {
9850
8503
  if (this.isDestroyed)
9851
8504
  return;
9852
8505
  if (!this._content) {
9853
8506
  this.clearBlockStates();
9854
8507
  this._parseState = null;
8508
+ this._stableBlockCount = 0;
9855
8509
  return;
9856
8510
  }
9857
8511
  const trailingUnstable = this._streaming ? 2 : 0;
@@ -9859,17 +8513,24 @@ class MarkdownRenderable extends Renderable {
9859
8513
  const tokens = this._parseState.tokens;
9860
8514
  if (tokens.length === 0 && this._content.length > 0) {
9861
8515
  this.clearBlockStates();
8516
+ this._stableBlockCount = 0;
9862
8517
  const fallback = this.createMarkdownCodeRenderable(this._content, `${this.id}-fallback`);
9863
8518
  this.add(fallback);
9864
8519
  this._blockStates = [
9865
8520
  {
9866
8521
  token: { type: "text", raw: this._content, text: this._content },
9867
8522
  tokenRaw: this._content,
8523
+ marginTop: 0,
9868
8524
  renderable: fallback
9869
8525
  }
9870
8526
  ];
9871
8527
  return;
9872
8528
  }
8529
+ if (this._internalBlockMode === "top-level") {
8530
+ this.updateTopLevelBlocks(tokens, forceTableRefresh);
8531
+ return;
8532
+ }
8533
+ this._stableBlockCount = 0;
9873
8534
  const blockTokens = this.buildRenderableTokens(tokens);
9874
8535
  const lastBlockIndex = blockTokens.length - 1;
9875
8536
  let blockIndex = 0;
@@ -9954,8 +8615,13 @@ class MarkdownRenderable extends Renderable {
9954
8615
  state.renderable.destroyRecursively();
9955
8616
  }
9956
8617
  this._blockStates = [];
8618
+ this._stableBlockCount = 0;
9957
8619
  }
9958
8620
  rerenderBlocks() {
8621
+ if (this._internalBlockMode === "top-level") {
8622
+ this.updateBlocks(true);
8623
+ return;
8624
+ }
9959
8625
  for (let i = 0;i < this._blockStates.length; i++) {
9960
8626
  const state = this._blockStates[i];
9961
8627
  const hasNextToken = i < this._blockStates.length - 1;
@@ -12061,7 +10727,7 @@ class TimeToFirstDrawRenderable extends Renderable {
12061
10727
  return Math.max(0, Math.floor(value));
12062
10728
  }
12063
10729
  }
12064
- export { TextBufferView, convertThemeToStyles, SyntaxStyle, DistortionEffect, VignetteEffect, CloudsEffect, FlamesEffect, CRTRollingBarEffect, RainbowTextEffect, applyScanlines, applyInvert, applyNoise, applyChromaticAberration, applyAsciiArt, applyBrightness, applyGain, applySaturation, BloomEffect, SEPIA_MATRIX, PROTANOPIA_SIM_MATRIX, DEUTERANOPIA_SIM_MATRIX, TRITANOPIA_SIM_MATRIX, ACHROMATOPSIA_MATRIX, PROTANOPIA_COMP_MATRIX, DEUTERANOPIA_COMP_MATRIX, TRITANOPIA_COMP_MATRIX, TECHNICOLOR_MATRIX, SOLARIZATION_MATRIX, SYNTHWAVE_MATRIX, GREENSCALE_MATRIX, GRAYSCALE_MATRIX, INVERT_MATRIX, Timeline, engine, createTimeline, SlotRegistry, createSlotRegistry, createCoreSlotRegistry, registerCorePlugin, resolveCoreSlot, SlotRenderable, NativeSpanFeed, FrameBufferRenderable, ASCIIFontRenderable, BoxRenderable, TextBufferRenderable, CodeRenderable, isTextNodeRenderable, TextNodeRenderable, RootTextNodeRenderable, Generic, Box, Text, ASCIIFont, Input, Select, TabSelect, FrameBuffer, Code, ScrollBox, vstyles, VRenderable, LineNumberRenderable, TextRenderable, DiffRenderable, TextareaRenderable, InputRenderableEvents, InputRenderable, TextTableRenderable, MarkdownRenderable, SliderRenderable, ScrollBarRenderable, ArrowRenderable, ScrollBoxRenderable, SelectRenderableEvents, SelectRenderable, TabSelectRenderableEvents, TabSelectRenderable, TimeToFirstDrawRenderable, exports_src2 as exports_src };
10730
+ export { DistortionEffect, VignetteEffect, CloudsEffect, FlamesEffect, CRTRollingBarEffect, RainbowTextEffect, applyScanlines, applyInvert, applyNoise, applyChromaticAberration, applyAsciiArt, applyBrightness, applyGain, applySaturation, BloomEffect, SEPIA_MATRIX, PROTANOPIA_SIM_MATRIX, DEUTERANOPIA_SIM_MATRIX, TRITANOPIA_SIM_MATRIX, ACHROMATOPSIA_MATRIX, PROTANOPIA_COMP_MATRIX, DEUTERANOPIA_COMP_MATRIX, TRITANOPIA_COMP_MATRIX, TECHNICOLOR_MATRIX, SOLARIZATION_MATRIX, SYNTHWAVE_MATRIX, GREENSCALE_MATRIX, GRAYSCALE_MATRIX, INVERT_MATRIX, Timeline, engine, createTimeline, SlotRegistry, createSlotRegistry, createCoreSlotRegistry, registerCorePlugin, resolveCoreSlot, SlotRenderable, NativeSpanFeed, FrameBufferRenderable, ASCIIFontRenderable, Generic, Box, Text, ASCIIFont, Input, Select, TabSelect, FrameBuffer, Code, ScrollBox, vstyles, VRenderable, LineNumberRenderable, DiffRenderable, TextareaRenderable, InputRenderableEvents, InputRenderable, TextTableRenderable, MarkdownRenderable, SliderRenderable, ScrollBarRenderable, ArrowRenderable, ScrollBoxRenderable, SelectRenderableEvents, SelectRenderable, TabSelectRenderableEvents, TabSelectRenderable, TimeToFirstDrawRenderable, exports_src2 as exports_src };
12065
10731
 
12066
- //# debugId=B00F19B858C15EFD64756E2164756E21
12067
- //# sourceMappingURL=index-86ppjrgv.js.map
10732
+ //# debugId=B42913B7AA35E90164756E2164756E21
10733
+ //# sourceMappingURL=index-r3mexem1.js.map