@opentui/core 0.1.81 → 0.1.83

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.
package/index.js CHANGED
@@ -153,7 +153,7 @@ import {
153
153
  white,
154
154
  wrapWithDelegates,
155
155
  yellow
156
- } from "./index-ve2seej0.js";
156
+ } from "./index-a215gqtt.js";
157
157
  // src/text-buffer-view.ts
158
158
  class TextBufferView {
159
159
  lib;
@@ -2748,6 +2748,7 @@ class TextBufferRenderable extends Renderable {
2748
2748
  _truncate = false;
2749
2749
  textBuffer;
2750
2750
  textBufferView;
2751
+ _textBufferSyntaxStyle;
2751
2752
  _defaultOptions = {
2752
2753
  fg: RGBA.fromValues(1, 1, 1, 1),
2753
2754
  bg: RGBA.fromValues(0, 0, 0, 0),
@@ -2774,8 +2775,8 @@ class TextBufferRenderable extends Renderable {
2774
2775
  this._truncate = options.truncate ?? this._defaultOptions.truncate;
2775
2776
  this.textBuffer = TextBuffer.create(this._ctx.widthMethod);
2776
2777
  this.textBufferView = TextBufferView.create(this.textBuffer);
2777
- const style = SyntaxStyle.create();
2778
- this.textBuffer.setSyntaxStyle(style);
2778
+ this._textBufferSyntaxStyle = SyntaxStyle.create();
2779
+ this.textBuffer.setSyntaxStyle(this._textBufferSyntaxStyle);
2779
2780
  this.textBufferView.setWrapMode(this._wrapMode);
2780
2781
  this.setupMeasureFunc();
2781
2782
  this.textBuffer.setDefaultFg(this._defaultFg);
@@ -3085,6 +3086,10 @@ class TextBufferRenderable extends Renderable {
3085
3086
  }
3086
3087
  }
3087
3088
  destroy() {
3089
+ if (this.isDestroyed)
3090
+ return;
3091
+ this.textBuffer.setSyntaxStyle(null);
3092
+ this._textBufferSyntaxStyle.destroy();
3088
3093
  this.textBufferView.destroy();
3089
3094
  this.textBuffer.destroy();
3090
3095
  super.destroy();
@@ -7159,6 +7164,907 @@ class InputRenderable extends TextareaRenderable {
7159
7164
  }
7160
7165
  set initialValue(value) {}
7161
7166
  }
7167
+ // src/renderables/TextTable.ts
7168
+ var MEASURE_HEIGHT = 1e4;
7169
+
7170
+ class TextTableRenderable extends Renderable {
7171
+ _content;
7172
+ _wrapMode;
7173
+ _columnWidthMode;
7174
+ _cellPadding;
7175
+ _showBorders;
7176
+ _border;
7177
+ _outerBorder;
7178
+ _hasExplicitOuterBorder;
7179
+ _borderStyle;
7180
+ _borderColor;
7181
+ _borderBackgroundColor;
7182
+ _backgroundColor;
7183
+ _defaultFg;
7184
+ _defaultBg;
7185
+ _defaultAttributes;
7186
+ _selectionBg;
7187
+ _selectionFg;
7188
+ _lastLocalSelection = null;
7189
+ _lastSelectionMode = null;
7190
+ _cells = [];
7191
+ _prevCellContent = [];
7192
+ _rowCount = 0;
7193
+ _columnCount = 0;
7194
+ _layout = this.createEmptyLayout();
7195
+ _layoutDirty = true;
7196
+ _rasterDirty = true;
7197
+ _cachedMeasureLayout = null;
7198
+ _cachedMeasureWidth = undefined;
7199
+ _defaultOptions = {
7200
+ content: [],
7201
+ wrapMode: "none",
7202
+ columnWidthMode: "content",
7203
+ cellPadding: 0,
7204
+ showBorders: true,
7205
+ border: true,
7206
+ outerBorder: true,
7207
+ selectable: true,
7208
+ selectionBg: undefined,
7209
+ selectionFg: undefined,
7210
+ borderStyle: "single",
7211
+ borderColor: "#FFFFFF",
7212
+ borderBackgroundColor: "transparent",
7213
+ backgroundColor: "transparent",
7214
+ fg: "#FFFFFF",
7215
+ bg: "transparent",
7216
+ attributes: 0
7217
+ };
7218
+ constructor(ctx, options = {}) {
7219
+ super(ctx, { ...options, buffered: true });
7220
+ this._content = options.content ?? this._defaultOptions.content;
7221
+ this._wrapMode = options.wrapMode ?? this._defaultOptions.wrapMode;
7222
+ this._columnWidthMode = options.columnWidthMode ?? this._defaultOptions.columnWidthMode;
7223
+ this._cellPadding = this.resolveCellPadding(options.cellPadding);
7224
+ this._showBorders = options.showBorders ?? this._defaultOptions.showBorders;
7225
+ this._border = options.border ?? this._defaultOptions.border;
7226
+ this._hasExplicitOuterBorder = options.outerBorder !== undefined;
7227
+ this._outerBorder = options.outerBorder ?? this._border;
7228
+ this.selectable = options.selectable ?? this._defaultOptions.selectable;
7229
+ this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : undefined;
7230
+ this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : undefined;
7231
+ this._borderStyle = parseBorderStyle(options.borderStyle, this._defaultOptions.borderStyle);
7232
+ this._borderColor = parseColor(options.borderColor ?? this._defaultOptions.borderColor);
7233
+ this._borderBackgroundColor = parseColor(options.borderBackgroundColor ?? this._defaultOptions.borderBackgroundColor);
7234
+ this._backgroundColor = parseColor(options.backgroundColor ?? this._defaultOptions.backgroundColor);
7235
+ this._defaultFg = parseColor(options.fg ?? this._defaultOptions.fg);
7236
+ this._defaultBg = parseColor(options.bg ?? this._defaultOptions.bg);
7237
+ this._defaultAttributes = options.attributes ?? this._defaultOptions.attributes;
7238
+ this.setupMeasureFunc();
7239
+ this.rebuildCells();
7240
+ }
7241
+ get content() {
7242
+ return this._content;
7243
+ }
7244
+ set content(value) {
7245
+ this._content = value ?? [];
7246
+ this.rebuildCells();
7247
+ }
7248
+ get wrapMode() {
7249
+ return this._wrapMode;
7250
+ }
7251
+ set wrapMode(value) {
7252
+ if (this._wrapMode === value)
7253
+ return;
7254
+ this._wrapMode = value;
7255
+ for (const row of this._cells) {
7256
+ for (const cell of row) {
7257
+ cell.textBufferView.setWrapMode(value);
7258
+ }
7259
+ }
7260
+ this.invalidateLayoutAndRaster();
7261
+ }
7262
+ get columnWidthMode() {
7263
+ return this._columnWidthMode;
7264
+ }
7265
+ set columnWidthMode(value) {
7266
+ if (this._columnWidthMode === value)
7267
+ return;
7268
+ this._columnWidthMode = value;
7269
+ this.invalidateLayoutAndRaster();
7270
+ }
7271
+ get cellPadding() {
7272
+ return this._cellPadding;
7273
+ }
7274
+ set cellPadding(value) {
7275
+ const next = this.resolveCellPadding(value);
7276
+ if (this._cellPadding === next)
7277
+ return;
7278
+ this._cellPadding = next;
7279
+ this.invalidateLayoutAndRaster();
7280
+ }
7281
+ get showBorders() {
7282
+ return this._showBorders;
7283
+ }
7284
+ set showBorders(value) {
7285
+ if (this._showBorders === value)
7286
+ return;
7287
+ this._showBorders = value;
7288
+ this.invalidateRasterOnly();
7289
+ }
7290
+ get outerBorder() {
7291
+ return this._outerBorder;
7292
+ }
7293
+ set outerBorder(value) {
7294
+ if (this._outerBorder === value)
7295
+ return;
7296
+ this._hasExplicitOuterBorder = true;
7297
+ this._outerBorder = value;
7298
+ this.invalidateLayoutAndRaster();
7299
+ }
7300
+ get border() {
7301
+ return this._border;
7302
+ }
7303
+ set border(value) {
7304
+ if (this._border === value)
7305
+ return;
7306
+ this._border = value;
7307
+ if (!this._hasExplicitOuterBorder) {
7308
+ this._outerBorder = value;
7309
+ }
7310
+ this.invalidateLayoutAndRaster();
7311
+ }
7312
+ get borderStyle() {
7313
+ return this._borderStyle;
7314
+ }
7315
+ set borderStyle(value) {
7316
+ const next = parseBorderStyle(value, this._defaultOptions.borderStyle);
7317
+ if (this._borderStyle === next)
7318
+ return;
7319
+ this._borderStyle = next;
7320
+ this.invalidateRasterOnly();
7321
+ }
7322
+ get borderColor() {
7323
+ return this._borderColor;
7324
+ }
7325
+ set borderColor(value) {
7326
+ const next = parseColor(value);
7327
+ if (this._borderColor === next)
7328
+ return;
7329
+ this._borderColor = next;
7330
+ this.invalidateRasterOnly();
7331
+ }
7332
+ shouldStartSelection(x, y) {
7333
+ if (!this.selectable)
7334
+ return false;
7335
+ this.ensureLayoutReady();
7336
+ const localX = x - this.x;
7337
+ const localY = y - this.y;
7338
+ return this.getCellAtLocalPosition(localX, localY) !== null;
7339
+ }
7340
+ onSelectionChanged(selection) {
7341
+ this.ensureLayoutReady();
7342
+ const previousLocalSelection = this._lastLocalSelection;
7343
+ const localSelection = convertGlobalToLocalSelection(selection, this.x, this.y);
7344
+ this._lastLocalSelection = localSelection;
7345
+ const dirtyRows = this.getDirtySelectionRowRange(previousLocalSelection, localSelection);
7346
+ if (!localSelection?.isActive) {
7347
+ this.resetCellSelections();
7348
+ this._lastSelectionMode = null;
7349
+ } else {
7350
+ this.applySelectionToCells(localSelection, selection?.isStart ?? false);
7351
+ }
7352
+ if (dirtyRows !== null) {
7353
+ this.redrawSelectionRows(dirtyRows.firstRow, dirtyRows.lastRow);
7354
+ }
7355
+ return this.hasSelection();
7356
+ }
7357
+ hasSelection() {
7358
+ for (const row of this._cells) {
7359
+ for (const cell of row) {
7360
+ if (cell.textBufferView.hasSelection()) {
7361
+ return true;
7362
+ }
7363
+ }
7364
+ }
7365
+ return false;
7366
+ }
7367
+ getSelection() {
7368
+ for (const row of this._cells) {
7369
+ for (const cell of row) {
7370
+ const selection = cell.textBufferView.getSelection();
7371
+ if (selection) {
7372
+ return selection;
7373
+ }
7374
+ }
7375
+ }
7376
+ return null;
7377
+ }
7378
+ getSelectedText() {
7379
+ const selectedRows = [];
7380
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7381
+ const rowSelections = [];
7382
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7383
+ const cell = this._cells[rowIdx]?.[colIdx];
7384
+ if (!cell || !cell.textBufferView.hasSelection())
7385
+ continue;
7386
+ const selectedText = cell.textBufferView.getSelectedText();
7387
+ if (selectedText.length > 0) {
7388
+ rowSelections.push(selectedText);
7389
+ }
7390
+ }
7391
+ if (rowSelections.length > 0) {
7392
+ selectedRows.push(rowSelections.join("\t"));
7393
+ }
7394
+ }
7395
+ return selectedRows.join(`
7396
+ `);
7397
+ }
7398
+ onResize(width, height) {
7399
+ this.invalidateLayoutAndRaster(false);
7400
+ super.onResize(width, height);
7401
+ }
7402
+ renderSelf(buffer) {
7403
+ if (!this.visible || this.isDestroyed)
7404
+ return;
7405
+ if (this._layoutDirty) {
7406
+ this.rebuildLayoutForCurrentWidth();
7407
+ }
7408
+ if (!this._rasterDirty)
7409
+ return;
7410
+ buffer.clear(this._backgroundColor);
7411
+ if (this._rowCount === 0 || this._columnCount === 0) {
7412
+ this._rasterDirty = false;
7413
+ return;
7414
+ }
7415
+ this.drawBorders(buffer);
7416
+ this.drawCells(buffer);
7417
+ this._rasterDirty = false;
7418
+ }
7419
+ destroySelf() {
7420
+ this.destroyCells();
7421
+ super.destroySelf();
7422
+ }
7423
+ setupMeasureFunc() {
7424
+ const measureFunc = (width, widthMode, height, heightMode) => {
7425
+ const hasWidthConstraint = widthMode !== MeasureMode.Undefined && Number.isFinite(width);
7426
+ const rawWidthConstraint = hasWidthConstraint ? Math.max(1, Math.floor(width)) : undefined;
7427
+ const widthConstraint = this.resolveLayoutWidthConstraint(rawWidthConstraint);
7428
+ const measuredLayout = this.computeLayout(widthConstraint);
7429
+ this._cachedMeasureLayout = measuredLayout;
7430
+ this._cachedMeasureWidth = widthConstraint;
7431
+ let measuredWidth = measuredLayout.tableWidth > 0 ? measuredLayout.tableWidth : 1;
7432
+ let measuredHeight = measuredLayout.tableHeight > 0 ? measuredLayout.tableHeight : 1;
7433
+ if (widthMode === MeasureMode.AtMost && rawWidthConstraint !== undefined && this._positionType !== "absolute") {
7434
+ measuredWidth = Math.min(rawWidthConstraint, measuredWidth);
7435
+ }
7436
+ if (heightMode === MeasureMode.AtMost && Number.isFinite(height) && this._positionType !== "absolute") {
7437
+ measuredHeight = Math.min(Math.max(1, Math.floor(height)), measuredHeight);
7438
+ }
7439
+ return {
7440
+ width: measuredWidth,
7441
+ height: measuredHeight
7442
+ };
7443
+ };
7444
+ this.yogaNode.setMeasureFunc(measureFunc);
7445
+ }
7446
+ rebuildCells() {
7447
+ const newRowCount = this._content.length;
7448
+ const newColumnCount = this._content.reduce((max, row) => Math.max(max, row.length), 0);
7449
+ if (this._cells.length === 0) {
7450
+ this._rowCount = newRowCount;
7451
+ this._columnCount = newColumnCount;
7452
+ this._cells = [];
7453
+ this._prevCellContent = [];
7454
+ for (let rowIdx = 0;rowIdx < newRowCount; rowIdx++) {
7455
+ const row = this._content[rowIdx] ?? [];
7456
+ const rowCells = [];
7457
+ const rowRefs = [];
7458
+ for (let colIdx = 0;colIdx < newColumnCount; colIdx++) {
7459
+ const cellContent = row[colIdx];
7460
+ rowCells.push(this.createCell(cellContent));
7461
+ rowRefs.push(cellContent);
7462
+ }
7463
+ this._cells.push(rowCells);
7464
+ this._prevCellContent.push(rowRefs);
7465
+ }
7466
+ this.invalidateLayoutAndRaster();
7467
+ return;
7468
+ }
7469
+ this.updateCellsDiff(newRowCount, newColumnCount);
7470
+ this.invalidateLayoutAndRaster();
7471
+ }
7472
+ updateCellsDiff(newRowCount, newColumnCount) {
7473
+ const oldRowCount = this._rowCount;
7474
+ const oldColumnCount = this._columnCount;
7475
+ const keepRows = Math.min(oldRowCount, newRowCount);
7476
+ const keepCols = Math.min(oldColumnCount, newColumnCount);
7477
+ for (let rowIdx = 0;rowIdx < keepRows; rowIdx++) {
7478
+ const newRow = this._content[rowIdx] ?? [];
7479
+ const cellRow = this._cells[rowIdx];
7480
+ const refRow = this._prevCellContent[rowIdx];
7481
+ for (let colIdx = 0;colIdx < keepCols; colIdx++) {
7482
+ const cellContent = newRow[colIdx];
7483
+ if (cellContent === refRow[colIdx])
7484
+ continue;
7485
+ const oldCell = cellRow[colIdx];
7486
+ oldCell.textBufferView.destroy();
7487
+ oldCell.textBuffer.destroy();
7488
+ oldCell.syntaxStyle.destroy();
7489
+ cellRow[colIdx] = this.createCell(cellContent);
7490
+ refRow[colIdx] = cellContent;
7491
+ }
7492
+ if (newColumnCount > oldColumnCount) {
7493
+ for (let colIdx = oldColumnCount;colIdx < newColumnCount; colIdx++) {
7494
+ const cellContent = newRow[colIdx];
7495
+ cellRow.push(this.createCell(cellContent));
7496
+ refRow.push(cellContent);
7497
+ }
7498
+ } else if (newColumnCount < oldColumnCount) {
7499
+ for (let colIdx = newColumnCount;colIdx < oldColumnCount; colIdx++) {
7500
+ const cell = cellRow[colIdx];
7501
+ cell.textBufferView.destroy();
7502
+ cell.textBuffer.destroy();
7503
+ cell.syntaxStyle.destroy();
7504
+ }
7505
+ cellRow.length = newColumnCount;
7506
+ refRow.length = newColumnCount;
7507
+ }
7508
+ }
7509
+ if (newRowCount > oldRowCount) {
7510
+ for (let rowIdx = oldRowCount;rowIdx < newRowCount; rowIdx++) {
7511
+ const newRow = this._content[rowIdx] ?? [];
7512
+ const rowCells = [];
7513
+ const rowRefs = [];
7514
+ for (let colIdx = 0;colIdx < newColumnCount; colIdx++) {
7515
+ const cellContent = newRow[colIdx];
7516
+ rowCells.push(this.createCell(cellContent));
7517
+ rowRefs.push(cellContent);
7518
+ }
7519
+ this._cells.push(rowCells);
7520
+ this._prevCellContent.push(rowRefs);
7521
+ }
7522
+ } else if (newRowCount < oldRowCount) {
7523
+ for (let rowIdx = newRowCount;rowIdx < oldRowCount; rowIdx++) {
7524
+ const row = this._cells[rowIdx];
7525
+ for (const cell of row) {
7526
+ cell.textBufferView.destroy();
7527
+ cell.textBuffer.destroy();
7528
+ cell.syntaxStyle.destroy();
7529
+ }
7530
+ }
7531
+ this._cells.length = newRowCount;
7532
+ this._prevCellContent.length = newRowCount;
7533
+ }
7534
+ this._rowCount = newRowCount;
7535
+ this._columnCount = newColumnCount;
7536
+ }
7537
+ createCell(content) {
7538
+ const styledText = this.toStyledText(content);
7539
+ const textBuffer = TextBuffer.create(this._ctx.widthMethod);
7540
+ const syntaxStyle = SyntaxStyle.create();
7541
+ textBuffer.setDefaultFg(this._defaultFg);
7542
+ textBuffer.setDefaultBg(this._defaultBg);
7543
+ textBuffer.setDefaultAttributes(this._defaultAttributes);
7544
+ textBuffer.setSyntaxStyle(syntaxStyle);
7545
+ textBuffer.setStyledText(styledText);
7546
+ const textBufferView = TextBufferView.create(textBuffer);
7547
+ textBufferView.setWrapMode(this._wrapMode);
7548
+ return { textBuffer, textBufferView, syntaxStyle };
7549
+ }
7550
+ toStyledText(content) {
7551
+ if (Array.isArray(content)) {
7552
+ return new StyledText(content);
7553
+ }
7554
+ if (content === null || content === undefined) {
7555
+ return stringToStyledText("");
7556
+ }
7557
+ return stringToStyledText(String(content));
7558
+ }
7559
+ destroyCells() {
7560
+ for (const row of this._cells) {
7561
+ for (const cell of row) {
7562
+ cell.textBufferView.destroy();
7563
+ cell.textBuffer.destroy();
7564
+ cell.syntaxStyle.destroy();
7565
+ }
7566
+ }
7567
+ this._cells = [];
7568
+ this._prevCellContent = [];
7569
+ this._rowCount = 0;
7570
+ this._columnCount = 0;
7571
+ this._layout = this.createEmptyLayout();
7572
+ }
7573
+ rebuildLayoutForCurrentWidth() {
7574
+ const maxTableWidth = this.resolveLayoutWidthConstraint(this.width);
7575
+ let layout;
7576
+ if (this._cachedMeasureLayout !== null && this._cachedMeasureWidth === maxTableWidth) {
7577
+ layout = this._cachedMeasureLayout;
7578
+ } else {
7579
+ layout = this.computeLayout(maxTableWidth);
7580
+ }
7581
+ this._cachedMeasureLayout = null;
7582
+ this._cachedMeasureWidth = undefined;
7583
+ this._layout = layout;
7584
+ this.applyLayoutToViews(layout);
7585
+ this._layoutDirty = false;
7586
+ if (this._lastLocalSelection?.isActive) {
7587
+ this.applySelectionToCells(this._lastLocalSelection, true);
7588
+ }
7589
+ }
7590
+ computeLayout(maxTableWidth) {
7591
+ if (this._rowCount === 0 || this._columnCount === 0) {
7592
+ return this.createEmptyLayout();
7593
+ }
7594
+ const borderLayout = this.resolveBorderLayout();
7595
+ const columnWidths = this.computeColumnWidths(maxTableWidth, borderLayout);
7596
+ const rowHeights = this.computeRowHeights(columnWidths);
7597
+ const columnOffsets = this.computeOffsets(columnWidths, borderLayout.left, borderLayout.right, borderLayout.innerVertical);
7598
+ const rowOffsets = this.computeOffsets(rowHeights, borderLayout.top, borderLayout.bottom, borderLayout.innerHorizontal);
7599
+ return {
7600
+ columnWidths,
7601
+ rowHeights,
7602
+ columnOffsets,
7603
+ rowOffsets,
7604
+ columnOffsetsI32: new Int32Array(columnOffsets),
7605
+ rowOffsetsI32: new Int32Array(rowOffsets),
7606
+ tableWidth: (columnOffsets[columnOffsets.length - 1] ?? 0) + 1,
7607
+ tableHeight: (rowOffsets[rowOffsets.length - 1] ?? 0) + 1
7608
+ };
7609
+ }
7610
+ computeColumnWidths(maxTableWidth, borderLayout) {
7611
+ const horizontalPadding = this.getHorizontalCellPadding();
7612
+ const intrinsicWidths = new Array(this._columnCount).fill(1 + horizontalPadding);
7613
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7614
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7615
+ const cell = this._cells[rowIdx]?.[colIdx];
7616
+ if (!cell)
7617
+ continue;
7618
+ const measure = cell.textBufferView.measureForDimensions(0, MEASURE_HEIGHT);
7619
+ const measuredWidth = Math.max(1, measure?.maxWidth ?? 0) + horizontalPadding;
7620
+ intrinsicWidths[colIdx] = Math.max(intrinsicWidths[colIdx], measuredWidth);
7621
+ }
7622
+ }
7623
+ if (maxTableWidth === undefined || !Number.isFinite(maxTableWidth) || maxTableWidth <= 0) {
7624
+ return intrinsicWidths;
7625
+ }
7626
+ const maxContentWidth = Math.max(1, Math.floor(maxTableWidth) - this.getVerticalBorderCount(borderLayout));
7627
+ const currentWidth = intrinsicWidths.reduce((sum, width) => sum + width, 0);
7628
+ if (currentWidth === maxContentWidth) {
7629
+ return intrinsicWidths;
7630
+ }
7631
+ if (currentWidth < maxContentWidth) {
7632
+ if (this._columnWidthMode === "fill") {
7633
+ return this.expandColumnWidths(intrinsicWidths, maxContentWidth);
7634
+ }
7635
+ return intrinsicWidths;
7636
+ }
7637
+ if (this._wrapMode === "none") {
7638
+ return intrinsicWidths;
7639
+ }
7640
+ return this.fitColumnWidths(intrinsicWidths, maxContentWidth);
7641
+ }
7642
+ expandColumnWidths(widths, targetContentWidth) {
7643
+ const baseWidths = widths.map((width) => Math.max(1, Math.floor(width)));
7644
+ const totalBaseWidth = baseWidths.reduce((sum, width) => sum + width, 0);
7645
+ if (totalBaseWidth >= targetContentWidth) {
7646
+ return baseWidths;
7647
+ }
7648
+ const expanded = [...baseWidths];
7649
+ const columns = expanded.length;
7650
+ const extraWidth = targetContentWidth - totalBaseWidth;
7651
+ const sharedWidth = Math.floor(extraWidth / columns);
7652
+ const remainder = extraWidth % columns;
7653
+ for (let idx = 0;idx < columns; idx++) {
7654
+ expanded[idx] += sharedWidth;
7655
+ if (idx < remainder) {
7656
+ expanded[idx] += 1;
7657
+ }
7658
+ }
7659
+ return expanded;
7660
+ }
7661
+ fitColumnWidths(widths, targetContentWidth) {
7662
+ const minWidth = 1 + this.getHorizontalCellPadding();
7663
+ const hardMinWidths = new Array(widths.length).fill(minWidth);
7664
+ const baseWidths = widths.map((width) => Math.max(1, Math.floor(width)));
7665
+ const preferredMinWidths = baseWidths.map((width) => Math.min(width, minWidth + 1));
7666
+ const preferredMinTotal = preferredMinWidths.reduce((sum, width) => sum + width, 0);
7667
+ const floorWidths = preferredMinTotal <= targetContentWidth ? preferredMinWidths : hardMinWidths;
7668
+ const floorTotal = floorWidths.reduce((sum, width) => sum + width, 0);
7669
+ const clampedTarget = Math.max(floorTotal, targetContentWidth);
7670
+ const totalBaseWidth = baseWidths.reduce((sum, width) => sum + width, 0);
7671
+ if (totalBaseWidth <= clampedTarget) {
7672
+ return baseWidths;
7673
+ }
7674
+ const shrinkable = baseWidths.map((width, idx) => width - floorWidths[idx]);
7675
+ const totalShrinkable = shrinkable.reduce((sum, value) => sum + value, 0);
7676
+ if (totalShrinkable <= 0) {
7677
+ return [...floorWidths];
7678
+ }
7679
+ const targetShrink = totalBaseWidth - clampedTarget;
7680
+ const integerShrink = new Array(baseWidths.length).fill(0);
7681
+ const fractions = new Array(baseWidths.length).fill(0);
7682
+ let usedShrink = 0;
7683
+ for (let idx = 0;idx < baseWidths.length; idx++) {
7684
+ if (shrinkable[idx] <= 0)
7685
+ continue;
7686
+ const exact = shrinkable[idx] / totalShrinkable * targetShrink;
7687
+ const whole = Math.min(shrinkable[idx], Math.floor(exact));
7688
+ integerShrink[idx] = whole;
7689
+ fractions[idx] = exact - whole;
7690
+ usedShrink += whole;
7691
+ }
7692
+ let remainingShrink = targetShrink - usedShrink;
7693
+ while (remainingShrink > 0) {
7694
+ let bestIdx = -1;
7695
+ let bestFraction = -1;
7696
+ for (let idx = 0;idx < baseWidths.length; idx++) {
7697
+ if (shrinkable[idx] - integerShrink[idx] <= 0)
7698
+ continue;
7699
+ if (fractions[idx] > bestFraction) {
7700
+ bestFraction = fractions[idx];
7701
+ bestIdx = idx;
7702
+ }
7703
+ }
7704
+ if (bestIdx === -1)
7705
+ break;
7706
+ integerShrink[bestIdx] += 1;
7707
+ fractions[bestIdx] = 0;
7708
+ remainingShrink -= 1;
7709
+ }
7710
+ return baseWidths.map((width, idx) => Math.max(floorWidths[idx], width - integerShrink[idx]));
7711
+ }
7712
+ computeRowHeights(columnWidths) {
7713
+ const horizontalPadding = this.getHorizontalCellPadding();
7714
+ const verticalPadding = this.getVerticalCellPadding();
7715
+ const rowHeights = new Array(this._rowCount).fill(1 + verticalPadding);
7716
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7717
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7718
+ const cell = this._cells[rowIdx]?.[colIdx];
7719
+ if (!cell)
7720
+ continue;
7721
+ const width = Math.max(1, (columnWidths[colIdx] ?? 1) - horizontalPadding);
7722
+ const measure = cell.textBufferView.measureForDimensions(width, MEASURE_HEIGHT);
7723
+ const lineCount = Math.max(1, measure?.lineCount ?? 1);
7724
+ rowHeights[rowIdx] = Math.max(rowHeights[rowIdx], lineCount + verticalPadding);
7725
+ }
7726
+ }
7727
+ return rowHeights;
7728
+ }
7729
+ computeOffsets(parts, startBoundary, endBoundary, includeInnerBoundaries) {
7730
+ const offsets = [startBoundary ? 0 : -1];
7731
+ let cursor = offsets[0] ?? 0;
7732
+ for (let idx = 0;idx < parts.length; idx++) {
7733
+ const size = parts[idx] ?? 1;
7734
+ const hasBoundaryAfter = idx < parts.length - 1 ? includeInnerBoundaries : endBoundary;
7735
+ cursor += size + (hasBoundaryAfter ? 1 : 0);
7736
+ offsets.push(cursor);
7737
+ }
7738
+ return offsets;
7739
+ }
7740
+ applyLayoutToViews(layout) {
7741
+ const horizontalPadding = this.getHorizontalCellPadding();
7742
+ const verticalPadding = this.getVerticalCellPadding();
7743
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7744
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7745
+ const cell = this._cells[rowIdx]?.[colIdx];
7746
+ if (!cell)
7747
+ continue;
7748
+ const colWidth = layout.columnWidths[colIdx] ?? 1;
7749
+ const rowHeight = layout.rowHeights[rowIdx] ?? 1;
7750
+ const contentWidth = Math.max(1, colWidth - horizontalPadding);
7751
+ const contentHeight = Math.max(1, rowHeight - verticalPadding);
7752
+ if (this._wrapMode === "none") {
7753
+ cell.textBufferView.setWrapWidth(null);
7754
+ } else {
7755
+ cell.textBufferView.setWrapWidth(contentWidth);
7756
+ }
7757
+ cell.textBufferView.setViewport(0, 0, contentWidth, contentHeight);
7758
+ }
7759
+ }
7760
+ }
7761
+ resolveBorderLayout() {
7762
+ return {
7763
+ left: this._outerBorder,
7764
+ right: this._outerBorder,
7765
+ top: this._outerBorder,
7766
+ bottom: this._outerBorder,
7767
+ innerVertical: this._border && this._columnCount > 1,
7768
+ innerHorizontal: this._border && this._rowCount > 1
7769
+ };
7770
+ }
7771
+ getVerticalBorderCount(borderLayout) {
7772
+ return (borderLayout.left ? 1 : 0) + (borderLayout.right ? 1 : 0) + (borderLayout.innerVertical ? Math.max(0, this._columnCount - 1) : 0);
7773
+ }
7774
+ getHorizontalBorderCount(borderLayout) {
7775
+ return (borderLayout.top ? 1 : 0) + (borderLayout.bottom ? 1 : 0) + (borderLayout.innerHorizontal ? Math.max(0, this._rowCount - 1) : 0);
7776
+ }
7777
+ drawBorders(buffer) {
7778
+ if (!this._showBorders) {
7779
+ return;
7780
+ }
7781
+ const borderLayout = this.resolveBorderLayout();
7782
+ if (this.getVerticalBorderCount(borderLayout) === 0 && this.getHorizontalBorderCount(borderLayout) === 0) {
7783
+ return;
7784
+ }
7785
+ buffer.drawGrid({
7786
+ borderChars: BorderCharArrays[this._borderStyle],
7787
+ borderFg: this._borderColor,
7788
+ borderBg: this._borderBackgroundColor,
7789
+ columnOffsets: this._layout.columnOffsetsI32,
7790
+ rowOffsets: this._layout.rowOffsetsI32,
7791
+ drawInner: this._border,
7792
+ drawOuter: this._outerBorder
7793
+ });
7794
+ }
7795
+ drawCells(buffer) {
7796
+ this.drawCellRange(buffer, 0, this._rowCount - 1);
7797
+ }
7798
+ drawCellRange(buffer, firstRow, lastRow) {
7799
+ const colOffsets = this._layout.columnOffsets;
7800
+ const rowOffsets = this._layout.rowOffsets;
7801
+ const cellPadding = this._cellPadding;
7802
+ for (let rowIdx = firstRow;rowIdx <= lastRow; rowIdx++) {
7803
+ const cellY = (rowOffsets[rowIdx] ?? 0) + 1 + cellPadding;
7804
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7805
+ const cell = this._cells[rowIdx]?.[colIdx];
7806
+ if (!cell)
7807
+ continue;
7808
+ buffer.drawTextBuffer(cell.textBufferView, (colOffsets[colIdx] ?? 0) + 1 + cellPadding, cellY);
7809
+ }
7810
+ }
7811
+ }
7812
+ redrawSelectionRows(firstRow, lastRow) {
7813
+ if (firstRow > lastRow)
7814
+ return;
7815
+ if (this._backgroundColor.a < 1) {
7816
+ this.invalidateRasterOnly();
7817
+ return;
7818
+ }
7819
+ const buffer = this.frameBuffer;
7820
+ if (!buffer)
7821
+ return;
7822
+ this.clearCellRange(buffer, firstRow, lastRow);
7823
+ this.drawCellRange(buffer, firstRow, lastRow);
7824
+ this.requestRender();
7825
+ }
7826
+ clearCellRange(buffer, firstRow, lastRow) {
7827
+ const colWidths = this._layout.columnWidths;
7828
+ const rowHeights = this._layout.rowHeights;
7829
+ const colOffsets = this._layout.columnOffsets;
7830
+ const rowOffsets = this._layout.rowOffsets;
7831
+ for (let rowIdx = firstRow;rowIdx <= lastRow; rowIdx++) {
7832
+ const cellY = (rowOffsets[rowIdx] ?? 0) + 1;
7833
+ const rowHeight = rowHeights[rowIdx] ?? 1;
7834
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7835
+ const cellX = (colOffsets[colIdx] ?? 0) + 1;
7836
+ const colWidth = colWidths[colIdx] ?? 1;
7837
+ buffer.fillRect(cellX, cellY, colWidth, rowHeight, this._backgroundColor);
7838
+ }
7839
+ }
7840
+ }
7841
+ ensureLayoutReady() {
7842
+ if (!this._layoutDirty)
7843
+ return;
7844
+ this.rebuildLayoutForCurrentWidth();
7845
+ }
7846
+ getCellAtLocalPosition(localX, localY) {
7847
+ if (this._rowCount === 0 || this._columnCount === 0)
7848
+ return null;
7849
+ if (localX < 0 || localY < 0 || localX >= this._layout.tableWidth || localY >= this._layout.tableHeight) {
7850
+ return null;
7851
+ }
7852
+ let rowIdx = -1;
7853
+ for (let idx = 0;idx < this._rowCount; idx++) {
7854
+ const top = (this._layout.rowOffsets[idx] ?? 0) + 1;
7855
+ const bottom = top + (this._layout.rowHeights[idx] ?? 1) - 1;
7856
+ if (localY >= top && localY <= bottom) {
7857
+ rowIdx = idx;
7858
+ break;
7859
+ }
7860
+ }
7861
+ if (rowIdx < 0)
7862
+ return null;
7863
+ let colIdx = -1;
7864
+ for (let idx = 0;idx < this._columnCount; idx++) {
7865
+ const left = (this._layout.columnOffsets[idx] ?? 0) + 1;
7866
+ const right = left + (this._layout.columnWidths[idx] ?? 1) - 1;
7867
+ if (localX >= left && localX <= right) {
7868
+ colIdx = idx;
7869
+ break;
7870
+ }
7871
+ }
7872
+ if (colIdx < 0)
7873
+ return null;
7874
+ return { rowIdx, colIdx };
7875
+ }
7876
+ applySelectionToCells(localSelection, isStart) {
7877
+ const minSelY = Math.min(localSelection.anchorY, localSelection.focusY);
7878
+ const maxSelY = Math.max(localSelection.anchorY, localSelection.focusY);
7879
+ const firstRow = this.findRowForLocalY(minSelY);
7880
+ const lastRow = this.findRowForLocalY(maxSelY);
7881
+ const selection = this.resolveSelectionResolution(localSelection);
7882
+ const modeChanged = this._lastSelectionMode !== selection.mode;
7883
+ this._lastSelectionMode = selection.mode;
7884
+ const lockToAnchorColumn = selection.mode === "column-locked" && selection.anchorColumn !== null;
7885
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7886
+ if (rowIdx < firstRow || rowIdx > lastRow) {
7887
+ this.resetRowSelection(rowIdx);
7888
+ continue;
7889
+ }
7890
+ const cellTop = (this._layout.rowOffsets[rowIdx] ?? 0) + 1 + this._cellPadding;
7891
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7892
+ const cell = this._cells[rowIdx]?.[colIdx];
7893
+ if (!cell)
7894
+ continue;
7895
+ if (lockToAnchorColumn && colIdx !== selection.anchorColumn) {
7896
+ cell.textBufferView.resetLocalSelection();
7897
+ continue;
7898
+ }
7899
+ const cellLeft = (this._layout.columnOffsets[colIdx] ?? 0) + 1 + this._cellPadding;
7900
+ let coords = {
7901
+ anchorX: localSelection.anchorX - cellLeft,
7902
+ anchorY: localSelection.anchorY - cellTop,
7903
+ focusX: localSelection.focusX - cellLeft,
7904
+ focusY: localSelection.focusY - cellTop
7905
+ };
7906
+ const isAnchorCell = selection.anchorCell !== null && selection.anchorCell.rowIdx === rowIdx && selection.anchorCell.colIdx === colIdx;
7907
+ const forceSet = isAnchorCell && selection.mode !== "single-cell";
7908
+ if (forceSet) {
7909
+ coords = this.getFullCellSelectionCoords(rowIdx, colIdx);
7910
+ }
7911
+ const shouldUseSet = isStart || modeChanged || forceSet;
7912
+ if (shouldUseSet) {
7913
+ cell.textBufferView.setLocalSelection(coords.anchorX, coords.anchorY, coords.focusX, coords.focusY, this._selectionBg, this._selectionFg);
7914
+ } else {
7915
+ cell.textBufferView.updateLocalSelection(coords.anchorX, coords.anchorY, coords.focusX, coords.focusY, this._selectionBg, this._selectionFg);
7916
+ }
7917
+ }
7918
+ }
7919
+ }
7920
+ resolveSelectionResolution(localSelection) {
7921
+ const anchorCell = this.getCellAtLocalPosition(localSelection.anchorX, localSelection.anchorY);
7922
+ const focusCell = this.getCellAtLocalPosition(localSelection.focusX, localSelection.focusY);
7923
+ const anchorColumn = anchorCell?.colIdx ?? this.getColumnAtLocalX(localSelection.anchorX);
7924
+ if (anchorCell !== null && focusCell !== null && anchorCell.rowIdx === focusCell.rowIdx && anchorCell.colIdx === focusCell.colIdx) {
7925
+ return {
7926
+ mode: "single-cell",
7927
+ anchorCell,
7928
+ anchorColumn
7929
+ };
7930
+ }
7931
+ const focusColumn = this.getColumnAtLocalX(localSelection.focusX);
7932
+ if (anchorColumn !== null && focusColumn === anchorColumn) {
7933
+ return {
7934
+ mode: "column-locked",
7935
+ anchorCell,
7936
+ anchorColumn
7937
+ };
7938
+ }
7939
+ return {
7940
+ mode: "grid",
7941
+ anchorCell,
7942
+ anchorColumn
7943
+ };
7944
+ }
7945
+ getColumnAtLocalX(localX) {
7946
+ if (this._columnCount === 0)
7947
+ return null;
7948
+ if (localX < 0 || localX >= this._layout.tableWidth)
7949
+ return null;
7950
+ for (let colIdx = 0;colIdx < this._columnCount; colIdx++) {
7951
+ const colStart = (this._layout.columnOffsets[colIdx] ?? 0) + 1;
7952
+ const colEnd = colStart + (this._layout.columnWidths[colIdx] ?? 1) - 1;
7953
+ if (localX >= colStart && localX <= colEnd) {
7954
+ return colIdx;
7955
+ }
7956
+ }
7957
+ return null;
7958
+ }
7959
+ getFullCellSelectionCoords(rowIdx, colIdx) {
7960
+ const colWidth = this._layout.columnWidths[colIdx] ?? 1;
7961
+ const rowHeight = this._layout.rowHeights[rowIdx] ?? 1;
7962
+ const contentWidth = Math.max(1, colWidth - this.getHorizontalCellPadding());
7963
+ const contentHeight = Math.max(1, rowHeight - this.getVerticalCellPadding());
7964
+ return {
7965
+ anchorX: -1,
7966
+ anchorY: 0,
7967
+ focusX: contentWidth,
7968
+ focusY: contentHeight
7969
+ };
7970
+ }
7971
+ findRowForLocalY(localY) {
7972
+ if (this._rowCount === 0)
7973
+ return 0;
7974
+ if (localY < 0)
7975
+ return 0;
7976
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
7977
+ const rowStart = (this._layout.rowOffsets[rowIdx] ?? 0) + 1;
7978
+ const rowEnd = rowStart + (this._layout.rowHeights[rowIdx] ?? 1) - 1;
7979
+ if (localY <= rowEnd)
7980
+ return rowIdx;
7981
+ }
7982
+ return this._rowCount - 1;
7983
+ }
7984
+ getSelectionRowRange(selection) {
7985
+ if (!selection?.isActive || this._rowCount === 0)
7986
+ return null;
7987
+ const minSelY = Math.min(selection.anchorY, selection.focusY);
7988
+ const maxSelY = Math.max(selection.anchorY, selection.focusY);
7989
+ return {
7990
+ firstRow: this.findRowForLocalY(minSelY),
7991
+ lastRow: this.findRowForLocalY(maxSelY)
7992
+ };
7993
+ }
7994
+ getDirtySelectionRowRange(previousSelection, currentSelection) {
7995
+ const previousRange = this.getSelectionRowRange(previousSelection);
7996
+ const currentRange = this.getSelectionRowRange(currentSelection);
7997
+ if (previousRange === null)
7998
+ return currentRange;
7999
+ if (currentRange === null)
8000
+ return previousRange;
8001
+ return {
8002
+ firstRow: Math.min(previousRange.firstRow, currentRange.firstRow),
8003
+ lastRow: Math.max(previousRange.lastRow, currentRange.lastRow)
8004
+ };
8005
+ }
8006
+ resetRowSelection(rowIdx) {
8007
+ const row = this._cells[rowIdx];
8008
+ if (!row)
8009
+ return;
8010
+ for (const cell of row) {
8011
+ cell.textBufferView.resetLocalSelection();
8012
+ }
8013
+ }
8014
+ resetCellSelections() {
8015
+ for (let rowIdx = 0;rowIdx < this._rowCount; rowIdx++) {
8016
+ this.resetRowSelection(rowIdx);
8017
+ }
8018
+ }
8019
+ createEmptyLayout() {
8020
+ return {
8021
+ columnWidths: [],
8022
+ rowHeights: [],
8023
+ columnOffsets: [0],
8024
+ rowOffsets: [0],
8025
+ columnOffsetsI32: new Int32Array([0]),
8026
+ rowOffsetsI32: new Int32Array([0]),
8027
+ tableWidth: 0,
8028
+ tableHeight: 0
8029
+ };
8030
+ }
8031
+ resolveLayoutWidthConstraint(width) {
8032
+ if (width === undefined || !Number.isFinite(width) || width <= 0) {
8033
+ return;
8034
+ }
8035
+ if (this._wrapMode !== "none" || this._columnWidthMode === "fill") {
8036
+ return Math.max(1, Math.floor(width));
8037
+ }
8038
+ return;
8039
+ }
8040
+ getHorizontalCellPadding() {
8041
+ return this._cellPadding * 2;
8042
+ }
8043
+ getVerticalCellPadding() {
8044
+ return this._cellPadding * 2;
8045
+ }
8046
+ resolveCellPadding(value) {
8047
+ if (value === undefined || !Number.isFinite(value)) {
8048
+ return this._defaultOptions.cellPadding;
8049
+ }
8050
+ return Math.max(0, Math.floor(value));
8051
+ }
8052
+ invalidateLayoutAndRaster(markYogaDirty = true) {
8053
+ this._layoutDirty = true;
8054
+ this._rasterDirty = true;
8055
+ this._cachedMeasureLayout = null;
8056
+ this._cachedMeasureWidth = undefined;
8057
+ if (markYogaDirty) {
8058
+ this.yogaNode.markDirty();
8059
+ }
8060
+ this.requestRender();
8061
+ }
8062
+ invalidateRasterOnly() {
8063
+ this._rasterDirty = true;
8064
+ this.requestRender();
8065
+ }
8066
+ }
8067
+
7162
8068
  // ../../node_modules/.bun/marked@17.0.1/node_modules/marked/lib/marked.esm.js
7163
8069
  function L() {
7164
8070
  return { async: false, breaks: false, extensions: null, gfm: true, hooks: null, pedantic: false, renderer: null, silent: false, tokenizer: null, walkTokens: null };
@@ -8437,10 +9343,10 @@ function parseMarkdownIncremental(newContent, prevState, trailingUnstable = 2) {
8437
9343
  let offset = 0;
8438
9344
  let reuseCount = 0;
8439
9345
  for (const token of prevState.tokens) {
8440
- const tokenEnd = offset + token.raw.length;
8441
- if (tokenEnd <= newContent.length && newContent.slice(offset, tokenEnd) === token.raw) {
9346
+ const tokenLength = token.raw.length;
9347
+ if (offset + tokenLength <= newContent.length && newContent.startsWith(token.raw, offset)) {
8442
9348
  reuseCount++;
8443
- offset = tokenEnd;
9349
+ offset += tokenLength;
8444
9350
  } else {
8445
9351
  break;
8446
9352
  }
@@ -8469,6 +9375,7 @@ class MarkdownRenderable extends Renderable {
8469
9375
  _syntaxStyle;
8470
9376
  _conceal;
8471
9377
  _treeSitterClient;
9378
+ _tableOptions;
8472
9379
  _renderNode;
8473
9380
  _parseState = null;
8474
9381
  _streaming = false;
@@ -8489,6 +9396,7 @@ class MarkdownRenderable extends Renderable {
8489
9396
  this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
8490
9397
  this._content = options.content ?? this._contentDefaultOptions.content;
8491
9398
  this._treeSitterClient = options.treeSitterClient;
9399
+ this._tableOptions = options.tableOptions;
8492
9400
  this._renderNode = options.renderNode;
8493
9401
  this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
8494
9402
  this.updateBlocks();
@@ -8530,6 +9438,13 @@ class MarkdownRenderable extends Renderable {
8530
9438
  this.clearCache();
8531
9439
  }
8532
9440
  }
9441
+ get tableOptions() {
9442
+ return this._tableOptions;
9443
+ }
9444
+ set tableOptions(value) {
9445
+ this._tableOptions = value;
9446
+ this.applyTableOptionsToBlocks();
9447
+ }
8533
9448
  getStyle(group) {
8534
9449
  if (!this._syntaxStyle)
8535
9450
  return;
@@ -8784,159 +9699,194 @@ class MarkdownRenderable extends Renderable {
8784
9699
  marginBottom
8785
9700
  });
8786
9701
  }
8787
- updateTableRenderable(tableBox, table, marginBottom) {
8788
- tableBox.marginBottom = marginBottom;
8789
- const borderColor = this.getStyle("conceal")?.fg ?? "#888888";
9702
+ getTableRowsToRender(table) {
9703
+ return this._streaming && table.rows.length > 0 ? table.rows.slice(0, -1) : table.rows;
9704
+ }
9705
+ hashString(value, seed) {
9706
+ let hash = seed >>> 0;
9707
+ for (let i = 0;i < value.length; i += 1) {
9708
+ hash ^= value.charCodeAt(i);
9709
+ hash = Math.imul(hash, 16777619);
9710
+ }
9711
+ return hash >>> 0;
9712
+ }
9713
+ hashTableToken(token, seed, depth = 0) {
9714
+ let hash = this.hashString(token.type, seed);
9715
+ if ("raw" in token && typeof token.raw === "string") {
9716
+ return this.hashString(token.raw, hash);
9717
+ }
9718
+ if ("text" in token && typeof token.text === "string") {
9719
+ hash = this.hashString(token.text, hash);
9720
+ }
9721
+ if (depth < 2 && "tokens" in token && Array.isArray(token.tokens)) {
9722
+ for (const child of token.tokens) {
9723
+ hash = this.hashTableToken(child, hash, depth + 1);
9724
+ }
9725
+ }
9726
+ return hash >>> 0;
9727
+ }
9728
+ getTableCellKey(cell, isHeader) {
9729
+ const seed = isHeader ? 2902232141 : 1371922141;
9730
+ if (!cell) {
9731
+ return seed;
9732
+ }
9733
+ if (typeof cell.text === "string") {
9734
+ return this.hashString(cell.text, seed);
9735
+ }
9736
+ if (Array.isArray(cell.tokens) && cell.tokens.length > 0) {
9737
+ let hash = seed ^ cell.tokens.length;
9738
+ for (const token of cell.tokens) {
9739
+ hash = this.hashTableToken(token, hash);
9740
+ }
9741
+ return hash >>> 0;
9742
+ }
9743
+ return (seed ^ 2654435769) >>> 0;
9744
+ }
9745
+ createTableDataCellChunks(cell) {
9746
+ const chunks = [];
9747
+ if (cell) {
9748
+ this.renderInlineContent(cell.tokens, chunks);
9749
+ }
9750
+ return chunks.length > 0 ? chunks : [this.createDefaultChunk(" ")];
9751
+ }
9752
+ createTableHeaderCellChunks(cell) {
9753
+ const chunks = [];
9754
+ this.renderInlineContent(cell.tokens, chunks);
9755
+ const baseChunks = chunks.length > 0 ? chunks : [this.createDefaultChunk(" ")];
8790
9756
  const headingStyle = this.getStyle("markup.heading") || this.getStyle("default");
8791
- const rowsToRender = this._streaming && table.rows.length > 0 ? table.rows.slice(0, -1) : table.rows;
9757
+ if (!headingStyle) {
9758
+ return baseChunks;
9759
+ }
9760
+ const headingAttributes = createTextAttributes({
9761
+ bold: headingStyle.bold,
9762
+ italic: headingStyle.italic,
9763
+ underline: headingStyle.underline,
9764
+ dim: headingStyle.dim
9765
+ });
9766
+ return baseChunks.map((chunk) => ({
9767
+ ...chunk,
9768
+ fg: headingStyle.fg ?? chunk.fg,
9769
+ bg: headingStyle.bg ?? chunk.bg,
9770
+ attributes: headingAttributes
9771
+ }));
9772
+ }
9773
+ buildTableContentCache(table, previous, forceRegenerate = false) {
8792
9774
  const colCount = table.header.length;
8793
- const columns = tableBox._childrenInLayoutOrder;
8794
- for (let col = 0;col < colCount; col++) {
8795
- const columnBox = columns[col];
8796
- if (!columnBox)
8797
- continue;
8798
- if (columnBox instanceof BoxRenderable) {
8799
- columnBox.borderColor = borderColor;
8800
- }
8801
- const columnChildren = columnBox._childrenInLayoutOrder;
8802
- const headerBox = columnChildren[0];
8803
- if (headerBox instanceof BoxRenderable) {
8804
- headerBox.borderColor = borderColor;
8805
- const headerChildren = headerBox._childrenInLayoutOrder;
8806
- const headerText = headerChildren[0];
8807
- if (headerText instanceof TextRenderable) {
8808
- const headerCell = table.header[col];
8809
- const headerChunks = [];
8810
- this.renderInlineContent(headerCell.tokens, headerChunks);
8811
- const styledHeaderChunks = headerChunks.map((chunk) => ({
8812
- ...chunk,
8813
- fg: headingStyle?.fg ?? chunk.fg,
8814
- bg: headingStyle?.bg ?? chunk.bg,
8815
- attributes: headingStyle ? createTextAttributes({
8816
- bold: headingStyle.bold,
8817
- italic: headingStyle.italic,
8818
- underline: headingStyle.underline,
8819
- dim: headingStyle.dim
8820
- }) : chunk.attributes
8821
- }));
8822
- headerText.content = new StyledText(styledHeaderChunks);
8823
- }
8824
- }
8825
- for (let row = 0;row < rowsToRender.length; row++) {
8826
- const childIndex = row + 1;
8827
- const cellContainer = columnChildren[childIndex];
8828
- let cellText;
8829
- if (cellContainer instanceof BoxRenderable) {
8830
- cellContainer.borderColor = borderColor;
8831
- const cellChildren = cellContainer._childrenInLayoutOrder;
8832
- cellText = cellChildren[0];
8833
- } else if (cellContainer instanceof TextRenderable) {
8834
- cellText = cellContainer;
8835
- }
8836
- if (cellText) {
8837
- const cell = rowsToRender[row][col];
8838
- const cellChunks = [];
8839
- if (cell) {
8840
- this.renderInlineContent(cell.tokens, cellChunks);
9775
+ const rowsToRender = this.getTableRowsToRender(table);
9776
+ if (colCount === 0 || rowsToRender.length === 0) {
9777
+ return { cache: null, changed: previous !== undefined };
9778
+ }
9779
+ const content = [];
9780
+ const cellKeys = [];
9781
+ const totalRows = rowsToRender.length + 1;
9782
+ let changed = forceRegenerate || !previous;
9783
+ for (let rowIndex = 0;rowIndex < totalRows; rowIndex += 1) {
9784
+ const rowContent = [];
9785
+ const rowKeys = new Uint32Array(colCount);
9786
+ for (let colIndex = 0;colIndex < colCount; colIndex += 1) {
9787
+ const isHeader = rowIndex === 0;
9788
+ const cell = isHeader ? table.header[colIndex] : rowsToRender[rowIndex - 1]?.[colIndex];
9789
+ const cellKey = this.getTableCellKey(cell, isHeader);
9790
+ rowKeys[colIndex] = cellKey;
9791
+ const previousCellKey = previous?.cellKeys[rowIndex]?.[colIndex];
9792
+ const previousCellContent = previous?.content[rowIndex]?.[colIndex];
9793
+ if (!forceRegenerate && previousCellKey === cellKey && Array.isArray(previousCellContent)) {
9794
+ rowContent.push(previousCellContent);
9795
+ continue;
9796
+ }
9797
+ changed = true;
9798
+ rowContent.push(isHeader ? this.createTableHeaderCellChunks(table.header[colIndex]) : this.createTableDataCellChunks(cell));
9799
+ }
9800
+ content.push(rowContent);
9801
+ cellKeys.push(rowKeys);
9802
+ }
9803
+ if (previous && !changed) {
9804
+ if (previous.content.length !== content.length) {
9805
+ changed = true;
9806
+ } else {
9807
+ for (let rowIndex = 0;rowIndex < content.length; rowIndex += 1) {
9808
+ if ((previous.content[rowIndex]?.length ?? 0) !== content[rowIndex].length) {
9809
+ changed = true;
9810
+ break;
8841
9811
  }
8842
- cellText.content = new StyledText(cellChunks.length > 0 ? cellChunks : [this.createDefaultChunk(" ")]);
8843
9812
  }
8844
9813
  }
8845
9814
  }
9815
+ return {
9816
+ cache: {
9817
+ content,
9818
+ cellKeys
9819
+ },
9820
+ changed
9821
+ };
8846
9822
  }
8847
- createTableRenderable(table, id, marginBottom = 0) {
8848
- const colCount = table.header.length;
8849
- const rowsToRender = this._streaming && table.rows.length > 0 ? table.rows.slice(0, -1) : table.rows;
8850
- if (colCount === 0 || rowsToRender.length === 0) {
8851
- return this.createTextRenderable([this.createDefaultChunk(table.raw)], id, marginBottom);
9823
+ resolveTableRenderableOptions() {
9824
+ const borders = this._tableOptions?.borders ?? true;
9825
+ return {
9826
+ columnWidthMode: this._tableOptions?.widthMode ?? "content",
9827
+ wrapMode: this._tableOptions?.wrapMode ?? "none",
9828
+ cellPadding: this._tableOptions?.cellPadding ?? 0,
9829
+ border: borders,
9830
+ outerBorder: this._tableOptions?.outerBorder ?? borders,
9831
+ showBorders: borders,
9832
+ borderStyle: this._tableOptions?.borderStyle ?? "single",
9833
+ borderColor: this._tableOptions?.borderColor ?? this.getStyle("conceal")?.fg ?? "#888888",
9834
+ selectable: this._tableOptions?.selectable ?? true
9835
+ };
9836
+ }
9837
+ applyTableRenderableOptions(tableRenderable, options) {
9838
+ tableRenderable.columnWidthMode = options.columnWidthMode;
9839
+ tableRenderable.wrapMode = options.wrapMode;
9840
+ tableRenderable.cellPadding = options.cellPadding;
9841
+ tableRenderable.border = options.border;
9842
+ tableRenderable.outerBorder = options.outerBorder;
9843
+ tableRenderable.showBorders = options.showBorders;
9844
+ tableRenderable.borderStyle = options.borderStyle;
9845
+ tableRenderable.borderColor = options.borderColor;
9846
+ tableRenderable.selectable = options.selectable;
9847
+ }
9848
+ applyTableOptionsToBlocks() {
9849
+ const options = this.resolveTableRenderableOptions();
9850
+ let updated = false;
9851
+ for (const state of this._blockStates) {
9852
+ if (state.renderable instanceof TextTableRenderable) {
9853
+ this.applyTableRenderableOptions(state.renderable, options);
9854
+ updated = true;
9855
+ }
8852
9856
  }
8853
- const tableBox = new BoxRenderable(this.ctx, {
9857
+ if (updated) {
9858
+ this.requestRender();
9859
+ }
9860
+ }
9861
+ createTextTableRenderable(content, id, marginBottom = 0) {
9862
+ const options = this.resolveTableRenderableOptions();
9863
+ return new TextTableRenderable(this.ctx, {
8854
9864
  id,
8855
- flexDirection: "row",
8856
- marginBottom
9865
+ content,
9866
+ width: "100%",
9867
+ marginBottom,
9868
+ columnWidthMode: options.columnWidthMode,
9869
+ wrapMode: options.wrapMode,
9870
+ cellPadding: options.cellPadding,
9871
+ border: options.border,
9872
+ outerBorder: options.outerBorder,
9873
+ showBorders: options.showBorders,
9874
+ borderStyle: options.borderStyle,
9875
+ borderColor: options.borderColor,
9876
+ selectable: options.selectable
8857
9877
  });
8858
- const borderColor = this.getStyle("conceal")?.fg ?? "#888888";
8859
- for (let col = 0;col < colCount; col++) {
8860
- const isFirstCol = col === 0;
8861
- const isLastCol = col === colCount - 1;
8862
- const columnBox = new BoxRenderable(this.ctx, {
8863
- id: `${id}-col-${col}`,
8864
- flexDirection: "column",
8865
- border: isLastCol ? true : ["top", "bottom", "left"],
8866
- borderColor,
8867
- customBorderChars: isFirstCol ? undefined : {
8868
- topLeft: "\u252C",
8869
- topRight: "\u2510",
8870
- bottomLeft: "\u2534",
8871
- bottomRight: "\u2518",
8872
- horizontal: "\u2500",
8873
- vertical: "\u2502",
8874
- topT: "\u252C",
8875
- bottomT: "\u2534",
8876
- leftT: "\u251C",
8877
- rightT: "\u2524",
8878
- cross: "\u253C"
8879
- }
8880
- });
8881
- const headerCell = table.header[col];
8882
- const headerChunks = [];
8883
- this.renderInlineContent(headerCell.tokens, headerChunks);
8884
- const headingStyle = this.getStyle("markup.heading") || this.getStyle("default");
8885
- const styledHeaderChunks = headerChunks.map((chunk) => ({
8886
- ...chunk,
8887
- fg: headingStyle?.fg ?? chunk.fg,
8888
- bg: headingStyle?.bg ?? chunk.bg,
8889
- attributes: headingStyle ? createTextAttributes({
8890
- bold: headingStyle.bold,
8891
- italic: headingStyle.italic,
8892
- underline: headingStyle.underline,
8893
- dim: headingStyle.dim
8894
- }) : chunk.attributes
8895
- }));
8896
- const headerBox = new BoxRenderable(this.ctx, {
8897
- id: `${id}-col-${col}-header-box`,
8898
- border: ["bottom"],
8899
- borderColor
8900
- });
8901
- headerBox.add(new TextRenderable(this.ctx, {
8902
- id: `${id}-col-${col}-header`,
8903
- content: new StyledText(styledHeaderChunks),
8904
- height: 1,
8905
- overflow: "hidden",
8906
- paddingLeft: 1,
8907
- paddingRight: 1
8908
- }));
8909
- columnBox.add(headerBox);
8910
- for (let row = 0;row < rowsToRender.length; row++) {
8911
- const cell = rowsToRender[row][col];
8912
- const cellChunks = [];
8913
- if (cell) {
8914
- this.renderInlineContent(cell.tokens, cellChunks);
8915
- }
8916
- const isLastRow = row === rowsToRender.length - 1;
8917
- const cellText = new TextRenderable(this.ctx, {
8918
- id: `${id}-col-${col}-row-${row}`,
8919
- content: new StyledText(cellChunks.length > 0 ? cellChunks : [this.createDefaultChunk(" ")]),
8920
- height: 1,
8921
- overflow: "hidden",
8922
- paddingLeft: 1,
8923
- paddingRight: 1
8924
- });
8925
- if (isLastRow) {
8926
- columnBox.add(cellText);
8927
- } else {
8928
- const cellBox = new BoxRenderable(this.ctx, {
8929
- id: `${id}-col-${col}-row-${row}-box`,
8930
- border: ["bottom"],
8931
- borderColor
8932
- });
8933
- cellBox.add(cellText);
8934
- columnBox.add(cellBox);
8935
- }
8936
- }
8937
- tableBox.add(columnBox);
9878
+ }
9879
+ createTableBlock(table, id, marginBottom = 0, previousCache, forceRegenerate = false) {
9880
+ const { cache } = this.buildTableContentCache(table, previousCache, forceRegenerate);
9881
+ if (!cache) {
9882
+ return {
9883
+ renderable: this.createTextRenderable([this.createDefaultChunk(table.raw)], id, marginBottom)
9884
+ };
8938
9885
  }
8939
- return tableBox;
9886
+ return {
9887
+ renderable: this.createTextTableRenderable(cache.content, id, marginBottom),
9888
+ tableContentCache: cache
9889
+ };
8940
9890
  }
8941
9891
  createDefaultRenderable(token, index, hasNextToken = false) {
8942
9892
  const id = `${this.id}-block-${index}`;
@@ -8945,7 +9895,7 @@ class MarkdownRenderable extends Renderable {
8945
9895
  return this.createCodeRenderable(token, id, marginBottom);
8946
9896
  }
8947
9897
  if (token.type === "table") {
8948
- return this.createTableRenderable(token, id, marginBottom);
9898
+ return this.createTableBlock(token, id, marginBottom).renderable;
8949
9899
  }
8950
9900
  if (token.type === "space") {
8951
9901
  return null;
@@ -8969,26 +9919,39 @@ class MarkdownRenderable extends Renderable {
8969
9919
  return;
8970
9920
  }
8971
9921
  if (token.type === "table") {
8972
- const prevTable = state.token;
8973
- const newTable = token;
8974
- if (this._streaming) {
8975
- const prevCompleteRows = Math.max(0, prevTable.rows.length - 1);
8976
- const newCompleteRows = Math.max(0, newTable.rows.length - 1);
8977
- const prevIsRawFallback = prevTable.header.length === 0 || prevCompleteRows === 0;
8978
- const newIsRawFallback = newTable.header.length === 0 || newCompleteRows === 0;
8979
- if (prevCompleteRows === newCompleteRows && prevTable.header.length === newTable.header.length) {
8980
- if (prevIsRawFallback && newIsRawFallback && prevTable.raw !== newTable.raw) {
8981
- const textRenderable2 = state.renderable;
8982
- textRenderable2.content = new StyledText([this.createDefaultChunk(newTable.raw)]);
8983
- textRenderable2.marginBottom = marginBottom;
9922
+ const tableToken = token;
9923
+ const { cache, changed } = this.buildTableContentCache(tableToken, state.tableContentCache);
9924
+ if (!cache) {
9925
+ const fallbackChunks = [this.createDefaultChunk(tableToken.raw)];
9926
+ if (state.renderable instanceof TextRenderable) {
9927
+ if (state.tokenRaw !== tableToken.raw) {
9928
+ state.renderable.content = new StyledText(fallbackChunks);
8984
9929
  }
9930
+ state.renderable.marginBottom = marginBottom;
9931
+ state.tableContentCache = undefined;
8985
9932
  return;
8986
9933
  }
9934
+ state.renderable.destroyRecursively();
9935
+ const fallbackRenderable = this.createTextRenderable(fallbackChunks, `${this.id}-block-${index}`, marginBottom);
9936
+ this.add(fallbackRenderable);
9937
+ state.renderable = fallbackRenderable;
9938
+ state.tableContentCache = undefined;
9939
+ return;
8987
9940
  }
8988
- this.remove(state.renderable.id);
8989
- const newRenderable = this.createTableRenderable(newTable, `${this.id}-block-${index}`, marginBottom);
8990
- this.add(newRenderable);
8991
- state.renderable = newRenderable;
9941
+ if (state.renderable instanceof TextTableRenderable) {
9942
+ if (changed) {
9943
+ state.renderable.content = cache.content;
9944
+ }
9945
+ this.applyTableRenderableOptions(state.renderable, this.resolveTableRenderableOptions());
9946
+ state.renderable.marginBottom = marginBottom;
9947
+ state.tableContentCache = cache;
9948
+ return;
9949
+ }
9950
+ state.renderable.destroyRecursively();
9951
+ const tableRenderable = this.createTextTableRenderable(cache.content, `${this.id}-block-${index}`, marginBottom);
9952
+ this.add(tableRenderable);
9953
+ state.renderable = tableRenderable;
9954
+ state.tableContentCache = cache;
8992
9955
  return;
8993
9956
  }
8994
9957
  const textRenderable = state.renderable;
@@ -8998,10 +9961,7 @@ class MarkdownRenderable extends Renderable {
8998
9961
  }
8999
9962
  updateBlocks() {
9000
9963
  if (!this._content) {
9001
- for (const state of this._blockStates) {
9002
- this.remove(state.renderable.id);
9003
- }
9004
- this._blockStates = [];
9964
+ this.clearBlockStates();
9005
9965
  this._parseState = null;
9006
9966
  return;
9007
9967
  }
@@ -9009,9 +9969,7 @@ class MarkdownRenderable extends Renderable {
9009
9969
  this._parseState = parseMarkdownIncremental(this._content, this._parseState, trailingUnstable);
9010
9970
  const tokens = this._parseState.tokens;
9011
9971
  if (tokens.length === 0 && this._content.length > 0) {
9012
- for (const state of this._blockStates) {
9013
- this.remove(state.renderable.id);
9014
- }
9972
+ this.clearBlockStates();
9015
9973
  const text = this.createTextRenderable([this.createDefaultChunk(this._content)], `${this.id}-fallback`);
9016
9974
  this.add(text);
9017
9975
  this._blockStates = [
@@ -9052,9 +10010,10 @@ class MarkdownRenderable extends Renderable {
9052
10010
  continue;
9053
10011
  }
9054
10012
  if (existing) {
9055
- this.remove(existing.renderable.id);
10013
+ existing.renderable.destroyRecursively();
9056
10014
  }
9057
10015
  let renderable;
10016
+ let tableContentCache;
9058
10017
  if (this._renderNode) {
9059
10018
  const context = {
9060
10019
  syntaxStyle: this._syntaxStyle,
@@ -9068,26 +10027,37 @@ class MarkdownRenderable extends Renderable {
9068
10027
  }
9069
10028
  }
9070
10029
  if (!renderable) {
9071
- renderable = this.createDefaultRenderable(token, blockIndex, hasNextToken) ?? undefined;
10030
+ if (token.type === "table") {
10031
+ const tableBlock = this.createTableBlock(token, `${this.id}-block-${blockIndex}`, hasNextToken ? 1 : 0);
10032
+ renderable = tableBlock.renderable;
10033
+ tableContentCache = tableBlock.tableContentCache;
10034
+ } else {
10035
+ renderable = this.createDefaultRenderable(token, blockIndex, hasNextToken) ?? undefined;
10036
+ }
10037
+ }
10038
+ if (token.type === "table" && !tableContentCache && renderable instanceof TextTableRenderable) {
10039
+ const { cache } = this.buildTableContentCache(token);
10040
+ tableContentCache = cache ?? undefined;
9072
10041
  }
9073
10042
  if (renderable) {
9074
10043
  this.add(renderable);
9075
10044
  this._blockStates[blockIndex] = {
9076
10045
  token,
9077
10046
  tokenRaw: token.raw,
9078
- renderable
10047
+ renderable,
10048
+ tableContentCache
9079
10049
  };
9080
10050
  }
9081
10051
  blockIndex++;
9082
10052
  }
9083
10053
  while (this._blockStates.length > blockIndex) {
9084
10054
  const removed = this._blockStates.pop();
9085
- this.remove(removed.renderable.id);
10055
+ removed.renderable.destroyRecursively();
9086
10056
  }
9087
10057
  }
9088
10058
  clearBlockStates() {
9089
10059
  for (const state of this._blockStates) {
9090
- this.remove(state.renderable.id);
10060
+ state.renderable.destroyRecursively();
9091
10061
  }
9092
10062
  this._blockStates = [];
9093
10063
  }
@@ -9100,8 +10070,32 @@ class MarkdownRenderable extends Renderable {
9100
10070
  codeRenderable.syntaxStyle = this._syntaxStyle;
9101
10071
  codeRenderable.conceal = this._conceal;
9102
10072
  } else if (state.token.type === "table") {
10073
+ const tableToken = state.token;
9103
10074
  const marginBottom = hasNextToken ? 1 : 0;
9104
- this.updateTableRenderable(state.renderable, state.token, marginBottom);
10075
+ const { cache } = this.buildTableContentCache(tableToken, state.tableContentCache, true);
10076
+ if (!cache) {
10077
+ if (state.renderable instanceof TextRenderable) {
10078
+ state.renderable.content = new StyledText([this.createDefaultChunk(tableToken.raw)]);
10079
+ state.renderable.marginBottom = marginBottom;
10080
+ } else {
10081
+ state.renderable.destroyRecursively();
10082
+ const fallbackRenderable = this.createTextRenderable([this.createDefaultChunk(tableToken.raw)], `${this.id}-block-${i}`, marginBottom);
10083
+ this.add(fallbackRenderable);
10084
+ state.renderable = fallbackRenderable;
10085
+ }
10086
+ state.tableContentCache = undefined;
10087
+ } else if (state.renderable instanceof TextTableRenderable) {
10088
+ state.renderable.content = cache.content;
10089
+ this.applyTableRenderableOptions(state.renderable, this.resolveTableRenderableOptions());
10090
+ state.renderable.marginBottom = marginBottom;
10091
+ state.tableContentCache = cache;
10092
+ } else {
10093
+ state.renderable.destroyRecursively();
10094
+ const tableRenderable = this.createTextTableRenderable(cache.content, `${this.id}-block-${i}`, marginBottom);
10095
+ this.add(tableRenderable);
10096
+ state.renderable = tableRenderable;
10097
+ state.tableContentCache = cache;
10098
+ }
9105
10099
  } else {
9106
10100
  const textRenderable = state.renderable;
9107
10101
  const chunks = this.renderTokenToChunks(state.token);
@@ -9117,6 +10111,11 @@ class MarkdownRenderable extends Renderable {
9117
10111
  this.updateBlocks();
9118
10112
  this.requestRender();
9119
10113
  }
10114
+ refreshStyles() {
10115
+ this._styleDirty = false;
10116
+ this.rerenderBlocks();
10117
+ this.requestRender();
10118
+ }
9120
10119
  renderSelf(buffer, deltaTime) {
9121
10120
  if (this._styleDirty) {
9122
10121
  this._styleDirty = false;
@@ -11128,6 +12127,7 @@ export {
11128
12127
  TreeSitterClient,
11129
12128
  Timeline,
11130
12129
  TextareaRenderable,
12130
+ TextTableRenderable,
11131
12131
  TextRenderable,
11132
12132
  TextNodeRenderable,
11133
12133
  TextBufferView,
@@ -11206,5 +12206,5 @@ export {
11206
12206
  ASCIIFont
11207
12207
  };
11208
12208
 
11209
- //# debugId=B77F27E92D33B1E964756E2164756E21
12209
+ //# debugId=0C8001DA726AC37664756E2164756E21
11210
12210
  //# sourceMappingURL=index.js.map