@opentui/core 0.0.0-20251112-613689c1 → 0.0.0-20251201-fe4cc80e

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/3d/WGPURenderer.d.ts +2 -0
  2. package/3d/canvas.d.ts +2 -0
  3. package/3d.js +33 -2
  4. package/3d.js.map +4 -4
  5. package/README.md +5 -3
  6. package/Renderable.d.ts +2 -2
  7. package/buffer.d.ts +18 -0
  8. package/console.d.ts +2 -0
  9. package/edit-buffer.d.ts +1 -0
  10. package/editor-view.d.ts +5 -0
  11. package/{index-y49e47t2.js → index-533e9nca.js} +3616 -2552
  12. package/index-533e9nca.js.map +55 -0
  13. package/index.d.ts +1 -1
  14. package/index.js +2542 -309
  15. package/index.js.map +27 -15
  16. package/lib/KeyHandler.d.ts +1 -4
  17. package/lib/ascii.font.d.ts +208 -1
  18. package/lib/parse.keypress.d.ts +1 -0
  19. package/lib/terminal-palette.d.ts +7 -2
  20. package/lib/yoga.options.d.ts +1 -1
  21. package/libyoga-2ksztx35.dylib +0 -0
  22. package/libyoga-gh2tjwb7.so +0 -0
  23. package/libyoga-j5nt7np1.dylib +0 -0
  24. package/libyoga-wnbqxxhv.so +0 -0
  25. package/package.json +11 -10
  26. package/parser.worker.js +4 -3
  27. package/parser.worker.js.map +3 -3
  28. package/renderables/Diff.d.ts +127 -0
  29. package/renderables/EditBufferRenderable.d.ts +8 -2
  30. package/renderables/LineNumberRenderable.d.ts +72 -0
  31. package/renderables/ScrollBox.d.ts +3 -0
  32. package/renderables/TextBufferRenderable.d.ts +18 -5
  33. package/renderables/Textarea.d.ts +7 -4
  34. package/renderables/index.d.ts +2 -0
  35. package/renderer.d.ts +2 -1
  36. package/testing/mock-tree-sitter-client.d.ts +4 -1
  37. package/testing.js +29 -7
  38. package/testing.js.map +5 -5
  39. package/text-buffer-view.d.ts +6 -0
  40. package/text-buffer.d.ts +1 -0
  41. package/types.d.ts +13 -0
  42. package/yoga-jkgc6c1f.dll +0 -0
  43. package/zig-structs.d.ts +11 -0
  44. package/zig.d.ts +25 -6
  45. package/index-y49e47t2.js.map +0 -58
package/index.js CHANGED
@@ -19,6 +19,7 @@ import {
19
19
  LinearScrollAccel,
20
20
  LogLevel,
21
21
  MacOSScrollAccel,
22
+ MeasureMode,
22
23
  MouseButton,
23
24
  MouseEvent,
24
25
  MouseParser,
@@ -73,7 +74,7 @@ import {
73
74
  dim,
74
75
  env,
75
76
  envRegistry,
76
- exports_src,
77
+ exports_dist,
77
78
  extToFiletype,
78
79
  fg,
79
80
  fonts,
@@ -136,7 +137,7 @@ import {
136
137
  white,
137
138
  wrapWithDelegates,
138
139
  yellow
139
- } from "./index-y49e47t2.js";
140
+ } from "./index-533e9nca.js";
140
141
  // src/text-buffer-view.ts
141
142
  class TextBufferView {
142
143
  lib;
@@ -197,6 +198,10 @@ class TextBufferView {
197
198
  this.guard();
198
199
  this.lib.textBufferViewSetViewportSize(this.viewPtr, width, height);
199
200
  }
201
+ setViewport(x, y, width, height) {
202
+ this.guard();
203
+ this.lib.textBufferViewSetViewport(this.viewPtr, x, y, width, height);
204
+ }
200
205
  get lineInfo() {
201
206
  this.guard();
202
207
  return this.lib.textBufferViewGetLineInfo(this.viewPtr);
@@ -234,6 +239,14 @@ class TextBufferView {
234
239
  this.guard();
235
240
  this.lib.textBufferViewSetTabIndicatorColor(this.viewPtr, color);
236
241
  }
242
+ measureForDimensions(width, height) {
243
+ this.guard();
244
+ return this.lib.textBufferViewMeasureForDimensions(this.viewPtr, width, height);
245
+ }
246
+ getVirtualLineCount() {
247
+ this.guard();
248
+ return this.lib.textBufferViewGetVirtualLineCount(this.viewPtr);
249
+ }
237
250
  destroy() {
238
251
  if (this._destroyed)
239
252
  return;
@@ -319,6 +332,10 @@ class EditBuffer extends EventEmitter {
319
332
  const textBytes = this.lib.encoder.encode(text);
320
333
  this.lib.editBufferSetText(this.bufferPtr, textBytes, history);
321
334
  }
335
+ getLineCount() {
336
+ this.guard();
337
+ return this.lib.textBufferGetLineCount(this.textBufferPtr);
338
+ }
322
339
  getText() {
323
340
  this.guard();
324
341
  const maxSize = 1024 * 1024;
@@ -551,6 +568,7 @@ class EditorView {
551
568
  editBuffer;
552
569
  _destroyed = false;
553
570
  _extmarksController;
571
+ _textBufferViewPtr;
554
572
  constructor(lib, ptr, editBuffer) {
555
573
  this.lib = lib;
556
574
  this.viewPtr = ptr;
@@ -696,6 +714,13 @@ class EditorView {
696
714
  this.guard();
697
715
  this.lib.editorViewSetTabIndicatorColor(this.viewPtr, color);
698
716
  }
717
+ measureForDimensions(width, height) {
718
+ this.guard();
719
+ if (!this._textBufferViewPtr) {
720
+ this._textBufferViewPtr = this.lib.editorViewGetTextBufferView(this.viewPtr);
721
+ }
722
+ return this.lib.textBufferViewMeasureForDimensions(this._textBufferViewPtr, width, height);
723
+ }
699
724
  destroy() {
700
725
  if (this._destroyed)
701
726
  return;
@@ -2403,9 +2428,10 @@ class TextBufferRenderable extends Renderable {
2403
2428
  lastLocalSelection = null;
2404
2429
  _tabIndicator;
2405
2430
  _tabIndicatorColor;
2431
+ _scrollX = 0;
2432
+ _scrollY = 0;
2406
2433
  textBuffer;
2407
2434
  textBufferView;
2408
- _lineInfo = { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
2409
2435
  _defaultOptions = {
2410
2436
  fg: RGBA.fromValues(1, 1, 1, 1),
2411
2437
  bg: RGBA.fromValues(0, 0, 0, 0),
@@ -2444,10 +2470,85 @@ class TextBufferRenderable extends Renderable {
2444
2470
  this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor);
2445
2471
  }
2446
2472
  if (this._wrapMode !== "none" && this.width > 0) {
2447
- this.updateWrapWidth(this.width);
2473
+ this.textBufferView.setWrapWidth(this.width);
2474
+ }
2475
+ if (this.width > 0 && this.height > 0) {
2476
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
2448
2477
  }
2449
2478
  this.updateTextInfo();
2450
2479
  }
2480
+ onMouseEvent(event) {
2481
+ if (event.type === "scroll") {
2482
+ this.handleScroll(event);
2483
+ }
2484
+ }
2485
+ handleScroll(event) {
2486
+ if (!event.scroll)
2487
+ return;
2488
+ const { direction, delta } = event.scroll;
2489
+ if (direction === "up") {
2490
+ this.scrollY -= delta;
2491
+ } else if (direction === "down") {
2492
+ this.scrollY += delta;
2493
+ }
2494
+ if (this._wrapMode === "none") {
2495
+ if (direction === "left") {
2496
+ this.scrollX -= delta;
2497
+ } else if (direction === "right") {
2498
+ this.scrollX += delta;
2499
+ }
2500
+ }
2501
+ }
2502
+ get lineInfo() {
2503
+ return this.textBufferView.logicalLineInfo;
2504
+ }
2505
+ get lineCount() {
2506
+ return this.textBuffer.getLineCount();
2507
+ }
2508
+ get virtualLineCount() {
2509
+ return this.textBufferView.getVirtualLineCount();
2510
+ }
2511
+ get scrollY() {
2512
+ return this._scrollY;
2513
+ }
2514
+ set scrollY(value) {
2515
+ const maxScrollY = Math.max(0, this.scrollHeight - this.height);
2516
+ const clamped = Math.max(0, Math.min(value, maxScrollY));
2517
+ if (this._scrollY !== clamped) {
2518
+ this._scrollY = clamped;
2519
+ this.updateViewportOffset();
2520
+ this.requestRender();
2521
+ }
2522
+ }
2523
+ get scrollX() {
2524
+ return this._scrollX;
2525
+ }
2526
+ set scrollX(value) {
2527
+ const maxScrollX = Math.max(0, this.scrollWidth - this.width);
2528
+ const clamped = Math.max(0, Math.min(value, maxScrollX));
2529
+ if (this._scrollX !== clamped) {
2530
+ this._scrollX = clamped;
2531
+ this.updateViewportOffset();
2532
+ this.requestRender();
2533
+ }
2534
+ }
2535
+ get scrollWidth() {
2536
+ return this.lineInfo.maxLineWidth;
2537
+ }
2538
+ get scrollHeight() {
2539
+ return this.lineInfo.lineStarts.length;
2540
+ }
2541
+ get maxScrollY() {
2542
+ return Math.max(0, this.scrollHeight - this.height);
2543
+ }
2544
+ get maxScrollX() {
2545
+ return Math.max(0, this.scrollWidth - this.width);
2546
+ }
2547
+ updateViewportOffset() {
2548
+ if (this.width > 0 && this.height > 0) {
2549
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
2550
+ }
2551
+ }
2451
2552
  get plainText() {
2452
2553
  return this.textBuffer.getPlainText();
2453
2554
  }
@@ -2523,7 +2624,7 @@ class TextBufferRenderable extends Renderable {
2523
2624
  this._wrapMode = value;
2524
2625
  this.textBufferView.setWrapMode(this._wrapMode);
2525
2626
  if (value !== "none" && this.width > 0) {
2526
- this.updateWrapWidth(this.width);
2627
+ this.textBufferView.setWrapWidth(this.width);
2527
2628
  }
2528
2629
  this.yogaNode.markDirty();
2529
2630
  this.requestRender();
@@ -2555,7 +2656,8 @@ class TextBufferRenderable extends Renderable {
2555
2656
  }
2556
2657
  }
2557
2658
  onResize(width, height) {
2558
- this.textBufferView.setViewportSize(width, height);
2659
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, width, height);
2660
+ this.updateTextInfo();
2559
2661
  if (this.lastLocalSelection) {
2560
2662
  const changed = this.updateLocalSelection(this.lastLocalSelection);
2561
2663
  if (changed) {
@@ -2582,30 +2684,29 @@ class TextBufferRenderable extends Renderable {
2582
2684
  }
2583
2685
  this.yogaNode.markDirty();
2584
2686
  this.requestRender();
2585
- }
2586
- updateLineInfo() {
2587
- const lineInfo = this.textBufferView.logicalLineInfo;
2588
- this._lineInfo.lineStarts = lineInfo.lineStarts;
2589
- this._lineInfo.lineWidths = lineInfo.lineWidths;
2590
- this._lineInfo.maxLineWidth = lineInfo.maxLineWidth;
2591
- }
2592
- updateWrapWidth(width) {
2593
- this.textBufferView.setWrapWidth(width);
2594
- this.updateLineInfo();
2687
+ this.emit("line-info-change");
2595
2688
  }
2596
2689
  setupMeasureFunc() {
2597
2690
  const measureFunc = (width, widthMode, height, heightMode) => {
2598
- const effectiveWidth = isNaN(width) ? 1 : width;
2599
- if (this._wrapMode !== "none" && this.width !== effectiveWidth) {
2600
- this.updateWrapWidth(effectiveWidth);
2691
+ let effectiveWidth;
2692
+ if (widthMode === MeasureMode.Undefined || isNaN(width)) {
2693
+ effectiveWidth = 0;
2601
2694
  } else {
2602
- this.updateLineInfo();
2695
+ effectiveWidth = width;
2696
+ }
2697
+ const effectiveHeight = isNaN(height) ? 1 : height;
2698
+ const measureResult = this.textBufferView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
2699
+ const measuredWidth = measureResult ? Math.max(1, measureResult.maxWidth) : 1;
2700
+ const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
2701
+ if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
2702
+ return {
2703
+ width: Math.min(effectiveWidth, measuredWidth),
2704
+ height: Math.min(effectiveHeight, measuredHeight)
2705
+ };
2603
2706
  }
2604
- const measuredWidth = this._lineInfo.maxLineWidth;
2605
- const measuredHeight = this._lineInfo.lineStarts.length;
2606
2707
  return {
2607
- width: Math.max(1, measuredWidth),
2608
- height: Math.max(1, measuredHeight)
2708
+ width: measuredWidth,
2709
+ height: measuredHeight
2609
2710
  };
2610
2711
  };
2611
2712
  this.yogaNode.setMeasureFunc(measureFunc);
@@ -2690,6 +2791,10 @@ class CodeRenderable extends TextBufferRenderable {
2690
2791
  this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
2691
2792
  this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
2692
2793
  this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
2794
+ if (this._content.length > 0 && (this._drawUnstyledText || !this._filetype)) {
2795
+ this.textBuffer.setText(this._content);
2796
+ this.updateTextInfo();
2797
+ }
2693
2798
  this._highlightsDirty = this._content.length > 0;
2694
2799
  }
2695
2800
  get content() {
@@ -2699,6 +2804,10 @@ class CodeRenderable extends TextBufferRenderable {
2699
2804
  if (this._content !== value) {
2700
2805
  this._content = value;
2701
2806
  this._highlightsDirty = true;
2807
+ if (this._drawUnstyledText || !this._filetype) {
2808
+ this.textBuffer.setText(value);
2809
+ this.updateTextInfo();
2810
+ }
2702
2811
  }
2703
2812
  }
2704
2813
  get filetype() {
@@ -3180,156 +3289,2280 @@ class VRenderable extends Renderable {
3180
3289
  }
3181
3290
  }
3182
3291
  }
3183
- // src/renderables/Input.ts
3184
- var InputRenderableEvents;
3185
- ((InputRenderableEvents2) => {
3186
- InputRenderableEvents2["INPUT"] = "input";
3187
- InputRenderableEvents2["CHANGE"] = "change";
3188
- InputRenderableEvents2["ENTER"] = "enter";
3189
- })(InputRenderableEvents ||= {});
3190
-
3191
- class InputRenderable extends Renderable {
3192
- _focusable = true;
3193
- _value = "";
3194
- _cursorPosition = 0;
3195
- _placeholder;
3196
- _backgroundColor;
3197
- _textColor;
3198
- _focusedBackgroundColor;
3199
- _focusedTextColor;
3200
- _placeholderColor;
3201
- _cursorColor;
3202
- _cursorStyle;
3203
- _maxLength;
3204
- _lastCommittedValue = "";
3205
- _defaultOptions = {
3206
- backgroundColor: "transparent",
3207
- textColor: "#FFFFFF",
3208
- focusedBackgroundColor: "#1a1a1a",
3209
- focusedTextColor: "#FFFFFF",
3210
- placeholder: "",
3211
- placeholderColor: "#666666",
3212
- cursorColor: "#FFFFFF",
3213
- cursorStyle: {
3214
- style: "block",
3215
- blinking: true
3216
- },
3217
- maxLength: 1000,
3218
- value: ""
3219
- };
3220
- constructor(ctx, options) {
3221
- super(ctx, { ...options, buffered: true });
3222
- this._backgroundColor = parseColor(options.backgroundColor || this._defaultOptions.backgroundColor);
3223
- this._textColor = parseColor(options.textColor || this._defaultOptions.textColor);
3224
- this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || this._defaultOptions.focusedBackgroundColor);
3225
- this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || this._defaultOptions.focusedTextColor);
3226
- this._placeholder = options.placeholder || this._defaultOptions.placeholder;
3227
- this._value = options.value || this._defaultOptions.value;
3228
- this._lastCommittedValue = this._value;
3229
- this._cursorPosition = this._value.length;
3230
- this._maxLength = options.maxLength || this._defaultOptions.maxLength;
3231
- this._placeholderColor = parseColor(options.placeholderColor || this._defaultOptions.placeholderColor);
3232
- this._cursorColor = parseColor(options.cursorColor || this._defaultOptions.cursorColor);
3233
- this._cursorStyle = options.cursorStyle || this._defaultOptions.cursorStyle;
3292
+ // src/renderables/LineNumberRenderable.ts
3293
+ class GutterRenderable extends Renderable {
3294
+ target;
3295
+ _fg;
3296
+ _bg;
3297
+ _minWidth;
3298
+ _paddingRight;
3299
+ _lineColorsGutter;
3300
+ _lineColorsContent;
3301
+ _lineSigns;
3302
+ _lineNumberOffset;
3303
+ _hideLineNumbers;
3304
+ _lineNumbers;
3305
+ _maxBeforeWidth = 0;
3306
+ _maxAfterWidth = 0;
3307
+ _lastKnownLineCount = 0;
3308
+ _lastKnownScrollY = 0;
3309
+ constructor(ctx, target, options) {
3310
+ super(ctx, {
3311
+ id: options.id,
3312
+ width: "auto",
3313
+ height: "auto",
3314
+ flexGrow: 0,
3315
+ flexShrink: 0,
3316
+ buffered: options.buffered
3317
+ });
3318
+ this.target = target;
3319
+ this._fg = options.fg;
3320
+ this._bg = options.bg;
3321
+ this._minWidth = options.minWidth;
3322
+ this._paddingRight = options.paddingRight;
3323
+ this._lineColorsGutter = options.lineColorsGutter;
3324
+ this._lineColorsContent = options.lineColorsContent;
3325
+ this._lineSigns = options.lineSigns;
3326
+ this._lineNumberOffset = options.lineNumberOffset;
3327
+ this._hideLineNumbers = options.hideLineNumbers;
3328
+ this._lineNumbers = options.lineNumbers ?? new Map;
3329
+ this._lastKnownLineCount = this.target.virtualLineCount;
3330
+ this._lastKnownScrollY = this.target.scrollY;
3331
+ this.calculateSignWidths();
3332
+ this.setupMeasureFunc();
3333
+ this.onLifecyclePass = () => {
3334
+ const currentLineCount = this.target.virtualLineCount;
3335
+ if (currentLineCount !== this._lastKnownLineCount) {
3336
+ this._lastKnownLineCount = currentLineCount;
3337
+ this.yogaNode.markDirty();
3338
+ this.requestRender();
3339
+ }
3340
+ };
3234
3341
  }
3235
- updateCursorPosition() {
3236
- if (!this._focused)
3237
- return;
3238
- const contentX = 0;
3239
- const contentY = 0;
3240
- const contentWidth = this.width;
3241
- const maxVisibleChars = contentWidth - 1;
3242
- let displayStartIndex = 0;
3243
- if (this._cursorPosition >= maxVisibleChars) {
3244
- displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
3342
+ setupMeasureFunc() {
3343
+ const measureFunc = (width, widthMode, height, heightMode) => {
3344
+ const gutterWidth = this.calculateWidth();
3345
+ const gutterHeight = this.target.virtualLineCount;
3346
+ return {
3347
+ width: gutterWidth,
3348
+ height: gutterHeight
3349
+ };
3350
+ };
3351
+ this.yogaNode.setMeasureFunc(measureFunc);
3352
+ }
3353
+ remeasure() {
3354
+ this.yogaNode.markDirty();
3355
+ }
3356
+ setLineNumberOffset(offset) {
3357
+ if (this._lineNumberOffset !== offset) {
3358
+ this._lineNumberOffset = offset;
3359
+ this.yogaNode.markDirty();
3360
+ this.requestRender();
3245
3361
  }
3246
- const cursorDisplayX = this._cursorPosition - displayStartIndex;
3247
- if (cursorDisplayX >= 0 && cursorDisplayX < contentWidth) {
3248
- const absoluteCursorX = this.x + contentX + cursorDisplayX + 1;
3249
- const absoluteCursorY = this.y + contentY + 1;
3250
- this._ctx.setCursorPosition(absoluteCursorX, absoluteCursorY, true);
3251
- this._ctx.setCursorColor(this._cursorColor);
3362
+ }
3363
+ setHideLineNumbers(hideLineNumbers) {
3364
+ this._hideLineNumbers = hideLineNumbers;
3365
+ this.yogaNode.markDirty();
3366
+ this.requestRender();
3367
+ }
3368
+ setLineNumbers(lineNumbers) {
3369
+ this._lineNumbers = lineNumbers;
3370
+ this.yogaNode.markDirty();
3371
+ this.requestRender();
3372
+ }
3373
+ calculateSignWidths() {
3374
+ this._maxBeforeWidth = 0;
3375
+ this._maxAfterWidth = 0;
3376
+ for (const sign of this._lineSigns.values()) {
3377
+ if (sign.before) {
3378
+ const width = Bun.stringWidth(sign.before);
3379
+ this._maxBeforeWidth = Math.max(this._maxBeforeWidth, width);
3380
+ }
3381
+ if (sign.after) {
3382
+ const width = Bun.stringWidth(sign.after);
3383
+ this._maxAfterWidth = Math.max(this._maxAfterWidth, width);
3384
+ }
3252
3385
  }
3253
3386
  }
3254
- focus() {
3255
- super.focus();
3256
- this._ctx.setCursorStyle(this._cursorStyle.style, this._cursorStyle.blinking);
3257
- this._ctx.setCursorColor(this._cursorColor);
3258
- this.updateCursorPosition();
3387
+ calculateWidth() {
3388
+ const totalLines = this.target.virtualLineCount;
3389
+ let maxLineNumber = totalLines + this._lineNumberOffset;
3390
+ if (this._lineNumbers.size > 0) {
3391
+ for (const customLineNum of this._lineNumbers.values()) {
3392
+ maxLineNumber = Math.max(maxLineNumber, customLineNum);
3393
+ }
3394
+ }
3395
+ const digits = maxLineNumber > 0 ? Math.floor(Math.log10(maxLineNumber)) + 1 : 1;
3396
+ const baseWidth = Math.max(this._minWidth, digits + this._paddingRight + 1);
3397
+ return baseWidth + this._maxBeforeWidth + this._maxAfterWidth;
3259
3398
  }
3260
- blur() {
3261
- super.blur();
3262
- this._ctx.setCursorPosition(0, 0, false);
3263
- if (this._value !== this._lastCommittedValue) {
3264
- this._lastCommittedValue = this._value;
3265
- this.emit("change" /* CHANGE */, this._value);
3399
+ setLineColors(lineColorsGutter, lineColorsContent) {
3400
+ this._lineColorsGutter = lineColorsGutter;
3401
+ this._lineColorsContent = lineColorsContent;
3402
+ this.requestRender();
3403
+ }
3404
+ getLineColors() {
3405
+ return {
3406
+ gutter: this._lineColorsGutter,
3407
+ content: this._lineColorsContent
3408
+ };
3409
+ }
3410
+ setLineSigns(lineSigns) {
3411
+ const oldMaxBefore = this._maxBeforeWidth;
3412
+ const oldMaxAfter = this._maxAfterWidth;
3413
+ this._lineSigns = lineSigns;
3414
+ this.calculateSignWidths();
3415
+ if (this._maxBeforeWidth !== oldMaxBefore || this._maxAfterWidth !== oldMaxAfter) {
3416
+ this.yogaNode.markDirty();
3266
3417
  }
3418
+ this.requestRender();
3267
3419
  }
3268
- renderSelf(buffer, deltaTime) {
3269
- if (!this.visible || !this.frameBuffer)
3420
+ getLineSigns() {
3421
+ return this._lineSigns;
3422
+ }
3423
+ renderSelf(buffer) {
3424
+ const currentScrollY = this.target.scrollY;
3425
+ const scrollChanged = currentScrollY !== this._lastKnownScrollY;
3426
+ if (this.buffered && !this.isDirty && !scrollChanged) {
3270
3427
  return;
3271
- if (this.isDirty) {
3272
- this.refreshFrameBuffer();
3273
3428
  }
3429
+ this._lastKnownScrollY = currentScrollY;
3430
+ this.refreshFrameBuffer(buffer);
3274
3431
  }
3275
- refreshFrameBuffer() {
3276
- if (!this.frameBuffer)
3432
+ refreshFrameBuffer(buffer) {
3433
+ const startX = this.buffered ? 0 : this.x;
3434
+ const startY = this.buffered ? 0 : this.y;
3435
+ if (this.buffered) {
3436
+ buffer.clear(this._bg);
3437
+ } else if (this._bg.a > 0) {
3438
+ buffer.fillRect(startX, startY, this.width, this.height, this._bg);
3439
+ }
3440
+ const lineInfo = this.target.lineInfo;
3441
+ if (!lineInfo || !lineInfo.lineSources)
3277
3442
  return;
3278
- const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
3279
- this.frameBuffer.clear(bgColor);
3280
- const contentX = 0;
3281
- const contentY = 0;
3282
- const contentWidth = this.width;
3283
- const contentHeight = this.height;
3284
- const displayText = this._value || this._placeholder;
3285
- const isPlaceholder = !this._value && this._placeholder;
3286
- const baseTextColor = this._focused ? this._focusedTextColor : this._textColor;
3287
- const textColor = isPlaceholder ? this._placeholderColor : baseTextColor;
3288
- const maxVisibleChars = contentWidth - 1;
3289
- let displayStartIndex = 0;
3290
- if (this._cursorPosition >= maxVisibleChars) {
3291
- displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
3443
+ const sources = lineInfo.lineSources;
3444
+ let lastSource = -1;
3445
+ const startLine = this.target.scrollY;
3446
+ if (startLine >= sources.length)
3447
+ return;
3448
+ lastSource = startLine > 0 ? sources[startLine - 1] : -1;
3449
+ for (let i = 0;i < this.height; i++) {
3450
+ const visualLineIndex = startLine + i;
3451
+ if (visualLineIndex >= sources.length)
3452
+ break;
3453
+ const logicalLine = sources[visualLineIndex];
3454
+ const lineBg = this._lineColorsGutter.get(logicalLine) ?? this._bg;
3455
+ if (lineBg !== this._bg) {
3456
+ buffer.fillRect(startX, startY + i, this.width, 1, lineBg);
3457
+ }
3458
+ if (logicalLine === lastSource) {} else {
3459
+ let currentX = startX;
3460
+ const sign = this._lineSigns.get(logicalLine);
3461
+ if (sign?.before) {
3462
+ const beforeWidth = Bun.stringWidth(sign.before);
3463
+ const padding = this._maxBeforeWidth - beforeWidth;
3464
+ currentX += padding;
3465
+ const beforeColor = sign.beforeColor ? parseColor(sign.beforeColor) : this._fg;
3466
+ buffer.drawText(sign.before, currentX, startY + i, beforeColor, lineBg);
3467
+ currentX += beforeWidth;
3468
+ } else if (this._maxBeforeWidth > 0) {
3469
+ currentX += this._maxBeforeWidth;
3470
+ }
3471
+ if (!this._hideLineNumbers.has(logicalLine)) {
3472
+ const customLineNum = this._lineNumbers.get(logicalLine);
3473
+ const lineNum = customLineNum !== undefined ? customLineNum : logicalLine + 1 + this._lineNumberOffset;
3474
+ const lineNumStr = lineNum.toString();
3475
+ const lineNumWidth = lineNumStr.length;
3476
+ const availableSpace = this.width - this._maxBeforeWidth - this._maxAfterWidth - this._paddingRight;
3477
+ const lineNumX = startX + this._maxBeforeWidth + 1 + availableSpace - lineNumWidth - 1;
3478
+ if (lineNumX >= startX + this._maxBeforeWidth + 1) {
3479
+ buffer.drawText(lineNumStr, lineNumX, startY + i, this._fg, lineBg);
3480
+ }
3481
+ }
3482
+ if (sign?.after) {
3483
+ const afterX = startX + this.width - this._paddingRight - this._maxAfterWidth;
3484
+ const afterColor = sign.afterColor ? parseColor(sign.afterColor) : this._fg;
3485
+ buffer.drawText(sign.after, afterX, startY + i, afterColor, lineBg);
3486
+ }
3487
+ }
3488
+ lastSource = logicalLine;
3292
3489
  }
3293
- const visibleText = displayText.substring(displayStartIndex, displayStartIndex + maxVisibleChars);
3294
- if (visibleText) {
3295
- this.frameBuffer.drawText(visibleText, contentX, contentY, textColor);
3490
+ }
3491
+ }
3492
+ function darkenColor(color) {
3493
+ return RGBA.fromValues(color.r * 0.8, color.g * 0.8, color.b * 0.8, color.a);
3494
+ }
3495
+
3496
+ class LineNumberRenderable extends Renderable {
3497
+ gutter = null;
3498
+ target = null;
3499
+ _lineColorsGutter;
3500
+ _lineColorsContent;
3501
+ _lineSigns;
3502
+ _fg;
3503
+ _bg;
3504
+ _minWidth;
3505
+ _paddingRight;
3506
+ _lineNumberOffset;
3507
+ _hideLineNumbers;
3508
+ _lineNumbers;
3509
+ _isDestroying = false;
3510
+ handleLineInfoChange = () => {
3511
+ this.gutter?.remeasure();
3512
+ this.requestRender();
3513
+ };
3514
+ parseLineColor(line, color) {
3515
+ if (typeof color === "object" && "gutter" in color) {
3516
+ const config = color;
3517
+ if (config.gutter) {
3518
+ this._lineColorsGutter.set(line, parseColor(config.gutter));
3519
+ }
3520
+ if (config.content) {
3521
+ this._lineColorsContent.set(line, parseColor(config.content));
3522
+ } else if (config.gutter) {
3523
+ this._lineColorsContent.set(line, darkenColor(parseColor(config.gutter)));
3524
+ }
3525
+ } else {
3526
+ const parsedColor = parseColor(color);
3527
+ this._lineColorsGutter.set(line, parsedColor);
3528
+ this._lineColorsContent.set(line, darkenColor(parsedColor));
3296
3529
  }
3297
- if (this._focused) {
3298
- this.updateCursorPosition();
3530
+ }
3531
+ constructor(ctx, options) {
3532
+ super(ctx, {
3533
+ ...options,
3534
+ flexDirection: "row",
3535
+ height: "auto"
3536
+ });
3537
+ this._fg = parseColor(options.fg ?? "#888888");
3538
+ this._bg = parseColor(options.bg ?? "transparent");
3539
+ this._minWidth = options.minWidth ?? 3;
3540
+ this._paddingRight = options.paddingRight ?? 1;
3541
+ this._lineNumberOffset = options.lineNumberOffset ?? 0;
3542
+ this._hideLineNumbers = options.hideLineNumbers ?? new Set;
3543
+ this._lineNumbers = options.lineNumbers ?? new Map;
3544
+ this._lineColorsGutter = new Map;
3545
+ this._lineColorsContent = new Map;
3546
+ if (options.lineColors) {
3547
+ for (const [line, color] of options.lineColors) {
3548
+ this.parseLineColor(line, color);
3549
+ }
3550
+ }
3551
+ this._lineSigns = new Map;
3552
+ if (options.lineSigns) {
3553
+ for (const [line, sign] of options.lineSigns) {
3554
+ this._lineSigns.set(line, sign);
3555
+ }
3556
+ }
3557
+ if (options.target) {
3558
+ this.setTarget(options.target);
3299
3559
  }
3300
3560
  }
3301
- get value() {
3302
- return this._value;
3561
+ setTarget(target) {
3562
+ if (this.target === target)
3563
+ return;
3564
+ if (this.target) {
3565
+ this.target.off("line-info-change", this.handleLineInfoChange);
3566
+ super.remove(this.target.id);
3567
+ }
3568
+ if (this.gutter) {
3569
+ super.remove(this.gutter.id);
3570
+ this.gutter = null;
3571
+ }
3572
+ this.target = target;
3573
+ this.target.on("line-info-change", this.handleLineInfoChange);
3574
+ this.gutter = new GutterRenderable(this.ctx, this.target, {
3575
+ fg: this._fg,
3576
+ bg: this._bg,
3577
+ minWidth: this._minWidth,
3578
+ paddingRight: this._paddingRight,
3579
+ lineColorsGutter: this._lineColorsGutter,
3580
+ lineColorsContent: this._lineColorsContent,
3581
+ lineSigns: this._lineSigns,
3582
+ lineNumberOffset: this._lineNumberOffset,
3583
+ hideLineNumbers: this._hideLineNumbers,
3584
+ lineNumbers: this._lineNumbers,
3585
+ id: this.id ? `${this.id}-gutter` : undefined,
3586
+ buffered: true
3587
+ });
3588
+ super.add(this.gutter);
3589
+ super.add(this.target);
3303
3590
  }
3304
- set value(value) {
3305
- const newValue = value.substring(0, this._maxLength);
3306
- if (this._value !== newValue) {
3307
- this._value = newValue;
3308
- this._cursorPosition = Math.min(this._cursorPosition, this._value.length);
3309
- this.requestRender();
3310
- this.updateCursorPosition();
3311
- this.emit("input" /* INPUT */, this._value);
3591
+ add(child) {
3592
+ if (!this.target && "lineInfo" in child && "lineCount" in child && "virtualLineCount" in child && "scrollY" in child) {
3593
+ this.setTarget(child);
3594
+ return this.getChildrenCount() - 1;
3312
3595
  }
3596
+ return -1;
3313
3597
  }
3314
- set placeholder(placeholder) {
3315
- if (this._placeholder !== placeholder) {
3316
- this._placeholder = placeholder;
3317
- this.requestRender();
3598
+ remove(id) {
3599
+ if (this._isDestroying) {
3600
+ super.remove(id);
3601
+ return;
3602
+ }
3603
+ if (this.gutter && id === this.gutter.id) {
3604
+ throw new Error("LineNumberRenderable: Cannot remove gutter directly.");
3318
3605
  }
3606
+ if (this.target && id === this.target.id) {
3607
+ throw new Error("LineNumberRenderable: Cannot remove target directly. Use clearTarget() instead.");
3608
+ }
3609
+ super.remove(id);
3319
3610
  }
3320
- get cursorPosition() {
3321
- return this._cursorPosition;
3611
+ destroyRecursively() {
3612
+ this._isDestroying = true;
3613
+ if (this.target) {
3614
+ this.target.off("line-info-change", this.handleLineInfoChange);
3615
+ }
3616
+ super.destroyRecursively();
3617
+ this.gutter = null;
3618
+ this.target = null;
3322
3619
  }
3323
- set cursorPosition(position) {
3324
- const newPosition = Math.max(0, Math.min(position, this._value.length));
3325
- if (this._cursorPosition !== newPosition) {
3326
- this._cursorPosition = newPosition;
3327
- this.requestRender();
3328
- this.updateCursorPosition();
3620
+ clearTarget() {
3621
+ if (this.target) {
3622
+ this.target.off("line-info-change", this.handleLineInfoChange);
3623
+ super.remove(this.target.id);
3624
+ this.target = null;
3625
+ }
3626
+ if (this.gutter) {
3627
+ super.remove(this.gutter.id);
3628
+ this.gutter = null;
3329
3629
  }
3330
3630
  }
3331
- insertText(text) {
3332
- if (this._value.length + text.length > this._maxLength) {
3631
+ renderSelf(buffer) {
3632
+ if (!this.target || !this.gutter)
3633
+ return;
3634
+ const lineInfo = this.target.lineInfo;
3635
+ if (!lineInfo || !lineInfo.lineSources)
3636
+ return;
3637
+ const sources = lineInfo.lineSources;
3638
+ const startLine = this.target.scrollY;
3639
+ if (startLine >= sources.length)
3640
+ return;
3641
+ const gutterWidth = this.gutter.visible ? this.gutter.width : 0;
3642
+ const contentWidth = this.width - gutterWidth;
3643
+ for (let i = 0;i < this.height; i++) {
3644
+ const visualLineIndex = startLine + i;
3645
+ if (visualLineIndex >= sources.length)
3646
+ break;
3647
+ const logicalLine = sources[visualLineIndex];
3648
+ const lineBg = this._lineColorsContent.get(logicalLine);
3649
+ if (lineBg) {
3650
+ buffer.fillRect(this.x + gutterWidth, this.y + i, contentWidth, 1, lineBg);
3651
+ }
3652
+ }
3653
+ }
3654
+ set showLineNumbers(value) {
3655
+ if (this.gutter) {
3656
+ this.gutter.visible = value;
3657
+ }
3658
+ }
3659
+ get showLineNumbers() {
3660
+ return this.gutter?.visible ?? false;
3661
+ }
3662
+ setLineColor(line, color) {
3663
+ this.parseLineColor(line, color);
3664
+ if (this.gutter) {
3665
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3666
+ }
3667
+ }
3668
+ clearLineColor(line) {
3669
+ this._lineColorsGutter.delete(line);
3670
+ this._lineColorsContent.delete(line);
3671
+ if (this.gutter) {
3672
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3673
+ }
3674
+ }
3675
+ clearAllLineColors() {
3676
+ this._lineColorsGutter.clear();
3677
+ this._lineColorsContent.clear();
3678
+ if (this.gutter) {
3679
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3680
+ }
3681
+ }
3682
+ setLineColors(lineColors) {
3683
+ this._lineColorsGutter.clear();
3684
+ this._lineColorsContent.clear();
3685
+ for (const [line, color] of lineColors) {
3686
+ this.parseLineColor(line, color);
3687
+ }
3688
+ if (this.gutter) {
3689
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3690
+ }
3691
+ }
3692
+ getLineColors() {
3693
+ return {
3694
+ gutter: this._lineColorsGutter,
3695
+ content: this._lineColorsContent
3696
+ };
3697
+ }
3698
+ setLineSign(line, sign) {
3699
+ this._lineSigns.set(line, sign);
3700
+ if (this.gutter) {
3701
+ this.gutter.setLineSigns(this._lineSigns);
3702
+ }
3703
+ }
3704
+ clearLineSign(line) {
3705
+ this._lineSigns.delete(line);
3706
+ if (this.gutter) {
3707
+ this.gutter.setLineSigns(this._lineSigns);
3708
+ }
3709
+ }
3710
+ clearAllLineSigns() {
3711
+ this._lineSigns.clear();
3712
+ if (this.gutter) {
3713
+ this.gutter.setLineSigns(this._lineSigns);
3714
+ }
3715
+ }
3716
+ setLineSigns(lineSigns) {
3717
+ this._lineSigns.clear();
3718
+ for (const [line, sign] of lineSigns) {
3719
+ this._lineSigns.set(line, sign);
3720
+ }
3721
+ if (this.gutter) {
3722
+ this.gutter.setLineSigns(this._lineSigns);
3723
+ }
3724
+ }
3725
+ getLineSigns() {
3726
+ return this._lineSigns;
3727
+ }
3728
+ set lineNumberOffset(value) {
3729
+ if (this._lineNumberOffset !== value) {
3730
+ this._lineNumberOffset = value;
3731
+ if (this.gutter) {
3732
+ this.gutter.setLineNumberOffset(value);
3733
+ }
3734
+ }
3735
+ }
3736
+ get lineNumberOffset() {
3737
+ return this._lineNumberOffset;
3738
+ }
3739
+ setHideLineNumbers(hideLineNumbers) {
3740
+ this._hideLineNumbers = hideLineNumbers;
3741
+ if (this.gutter) {
3742
+ this.gutter.setHideLineNumbers(hideLineNumbers);
3743
+ }
3744
+ }
3745
+ getHideLineNumbers() {
3746
+ return this._hideLineNumbers;
3747
+ }
3748
+ setLineNumbers(lineNumbers) {
3749
+ this._lineNumbers = lineNumbers;
3750
+ if (this.gutter) {
3751
+ this.gutter.setLineNumbers(lineNumbers);
3752
+ }
3753
+ }
3754
+ getLineNumbers() {
3755
+ return this._lineNumbers;
3756
+ }
3757
+ }
3758
+
3759
+ // ../../node_modules/diff/libesm/diff/base.js
3760
+ class Diff {
3761
+ diff(oldStr, newStr, options = {}) {
3762
+ let callback;
3763
+ if (typeof options === "function") {
3764
+ callback = options;
3765
+ options = {};
3766
+ } else if ("callback" in options) {
3767
+ callback = options.callback;
3768
+ }
3769
+ const oldString = this.castInput(oldStr, options);
3770
+ const newString = this.castInput(newStr, options);
3771
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
3772
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
3773
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
3774
+ }
3775
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
3776
+ var _a;
3777
+ const done = (value) => {
3778
+ value = this.postProcess(value, options);
3779
+ if (callback) {
3780
+ setTimeout(function() {
3781
+ callback(value);
3782
+ }, 0);
3783
+ return;
3784
+ } else {
3785
+ return value;
3786
+ }
3787
+ };
3788
+ const newLen = newTokens.length, oldLen = oldTokens.length;
3789
+ let editLength = 1;
3790
+ let maxEditLength = newLen + oldLen;
3791
+ if (options.maxEditLength != null) {
3792
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
3793
+ }
3794
+ const maxExecutionTime = (_a = options.timeout) !== null && _a !== undefined ? _a : Infinity;
3795
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
3796
+ const bestPath = [{ oldPos: -1, lastComponent: undefined }];
3797
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
3798
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3799
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
3800
+ }
3801
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
3802
+ const execEditLength = () => {
3803
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength);diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
3804
+ let basePath;
3805
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
3806
+ if (removePath) {
3807
+ bestPath[diagonalPath - 1] = undefined;
3808
+ }
3809
+ let canAdd = false;
3810
+ if (addPath) {
3811
+ const addPathNewPos = addPath.oldPos - diagonalPath;
3812
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
3813
+ }
3814
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
3815
+ if (!canAdd && !canRemove) {
3816
+ bestPath[diagonalPath] = undefined;
3817
+ continue;
3818
+ }
3819
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
3820
+ basePath = this.addToPath(addPath, true, false, 0, options);
3821
+ } else {
3822
+ basePath = this.addToPath(removePath, false, true, 1, options);
3823
+ }
3824
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
3825
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3826
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
3827
+ } else {
3828
+ bestPath[diagonalPath] = basePath;
3829
+ if (basePath.oldPos + 1 >= oldLen) {
3830
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
3831
+ }
3832
+ if (newPos + 1 >= newLen) {
3833
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
3834
+ }
3835
+ }
3836
+ }
3837
+ editLength++;
3838
+ };
3839
+ if (callback) {
3840
+ (function exec() {
3841
+ setTimeout(function() {
3842
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
3843
+ return callback(undefined);
3844
+ }
3845
+ if (!execEditLength()) {
3846
+ exec();
3847
+ }
3848
+ }, 0);
3849
+ })();
3850
+ } else {
3851
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
3852
+ const ret = execEditLength();
3853
+ if (ret) {
3854
+ return ret;
3855
+ }
3856
+ }
3857
+ }
3858
+ }
3859
+ addToPath(path, added, removed, oldPosInc, options) {
3860
+ const last = path.lastComponent;
3861
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
3862
+ return {
3863
+ oldPos: path.oldPos + oldPosInc,
3864
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
3865
+ };
3866
+ } else {
3867
+ return {
3868
+ oldPos: path.oldPos + oldPosInc,
3869
+ lastComponent: { count: 1, added, removed, previousComponent: last }
3870
+ };
3871
+ }
3872
+ }
3873
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
3874
+ const newLen = newTokens.length, oldLen = oldTokens.length;
3875
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
3876
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
3877
+ newPos++;
3878
+ oldPos++;
3879
+ commonCount++;
3880
+ if (options.oneChangePerToken) {
3881
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
3882
+ }
3883
+ }
3884
+ if (commonCount && !options.oneChangePerToken) {
3885
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
3886
+ }
3887
+ basePath.oldPos = oldPos;
3888
+ return newPos;
3889
+ }
3890
+ equals(left, right, options) {
3891
+ if (options.comparator) {
3892
+ return options.comparator(left, right);
3893
+ } else {
3894
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
3895
+ }
3896
+ }
3897
+ removeEmpty(array) {
3898
+ const ret = [];
3899
+ for (let i = 0;i < array.length; i++) {
3900
+ if (array[i]) {
3901
+ ret.push(array[i]);
3902
+ }
3903
+ }
3904
+ return ret;
3905
+ }
3906
+ castInput(value, options) {
3907
+ return value;
3908
+ }
3909
+ tokenize(value, options) {
3910
+ return Array.from(value);
3911
+ }
3912
+ join(chars) {
3913
+ return chars.join("");
3914
+ }
3915
+ postProcess(changeObjects, options) {
3916
+ return changeObjects;
3917
+ }
3918
+ get useLongestToken() {
3919
+ return false;
3920
+ }
3921
+ buildValues(lastComponent, newTokens, oldTokens) {
3922
+ const components = [];
3923
+ let nextComponent;
3924
+ while (lastComponent) {
3925
+ components.push(lastComponent);
3926
+ nextComponent = lastComponent.previousComponent;
3927
+ delete lastComponent.previousComponent;
3928
+ lastComponent = nextComponent;
3929
+ }
3930
+ components.reverse();
3931
+ const componentLen = components.length;
3932
+ let componentPos = 0, newPos = 0, oldPos = 0;
3933
+ for (;componentPos < componentLen; componentPos++) {
3934
+ const component = components[componentPos];
3935
+ if (!component.removed) {
3936
+ if (!component.added && this.useLongestToken) {
3937
+ let value = newTokens.slice(newPos, newPos + component.count);
3938
+ value = value.map(function(value2, i) {
3939
+ const oldValue = oldTokens[oldPos + i];
3940
+ return oldValue.length > value2.length ? oldValue : value2;
3941
+ });
3942
+ component.value = this.join(value);
3943
+ } else {
3944
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
3945
+ }
3946
+ newPos += component.count;
3947
+ if (!component.added) {
3948
+ oldPos += component.count;
3949
+ }
3950
+ } else {
3951
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
3952
+ oldPos += component.count;
3953
+ }
3954
+ }
3955
+ return components;
3956
+ }
3957
+ }
3958
+
3959
+ // ../../node_modules/diff/libesm/diff/character.js
3960
+ class CharacterDiff extends Diff {
3961
+ }
3962
+ var characterDiff = new CharacterDiff;
3963
+
3964
+ // ../../node_modules/diff/libesm/util/string.js
3965
+ function longestCommonPrefix(str1, str2) {
3966
+ let i;
3967
+ for (i = 0;i < str1.length && i < str2.length; i++) {
3968
+ if (str1[i] != str2[i]) {
3969
+ return str1.slice(0, i);
3970
+ }
3971
+ }
3972
+ return str1.slice(0, i);
3973
+ }
3974
+ function longestCommonSuffix(str1, str2) {
3975
+ let i;
3976
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {
3977
+ return "";
3978
+ }
3979
+ for (i = 0;i < str1.length && i < str2.length; i++) {
3980
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {
3981
+ return str1.slice(-i);
3982
+ }
3983
+ }
3984
+ return str1.slice(-i);
3985
+ }
3986
+ function replacePrefix(string, oldPrefix, newPrefix) {
3987
+ if (string.slice(0, oldPrefix.length) != oldPrefix) {
3988
+ throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
3989
+ }
3990
+ return newPrefix + string.slice(oldPrefix.length);
3991
+ }
3992
+ function replaceSuffix(string, oldSuffix, newSuffix) {
3993
+ if (!oldSuffix) {
3994
+ return string + newSuffix;
3995
+ }
3996
+ if (string.slice(-oldSuffix.length) != oldSuffix) {
3997
+ throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
3998
+ }
3999
+ return string.slice(0, -oldSuffix.length) + newSuffix;
4000
+ }
4001
+ function removePrefix(string, oldPrefix) {
4002
+ return replacePrefix(string, oldPrefix, "");
4003
+ }
4004
+ function removeSuffix(string, oldSuffix) {
4005
+ return replaceSuffix(string, oldSuffix, "");
4006
+ }
4007
+ function maximumOverlap(string1, string2) {
4008
+ return string2.slice(0, overlapCount(string1, string2));
4009
+ }
4010
+ function overlapCount(a, b) {
4011
+ let startA = 0;
4012
+ if (a.length > b.length) {
4013
+ startA = a.length - b.length;
4014
+ }
4015
+ let endB = b.length;
4016
+ if (a.length < b.length) {
4017
+ endB = a.length;
4018
+ }
4019
+ const map = Array(endB);
4020
+ let k = 0;
4021
+ map[0] = 0;
4022
+ for (let j = 1;j < endB; j++) {
4023
+ if (b[j] == b[k]) {
4024
+ map[j] = map[k];
4025
+ } else {
4026
+ map[j] = k;
4027
+ }
4028
+ while (k > 0 && b[j] != b[k]) {
4029
+ k = map[k];
4030
+ }
4031
+ if (b[j] == b[k]) {
4032
+ k++;
4033
+ }
4034
+ }
4035
+ k = 0;
4036
+ for (let i = startA;i < a.length; i++) {
4037
+ while (k > 0 && a[i] != b[k]) {
4038
+ k = map[k];
4039
+ }
4040
+ if (a[i] == b[k]) {
4041
+ k++;
4042
+ }
4043
+ }
4044
+ return k;
4045
+ }
4046
+ function trailingWs(string) {
4047
+ let i;
4048
+ for (i = string.length - 1;i >= 0; i--) {
4049
+ if (!string[i].match(/\s/)) {
4050
+ break;
4051
+ }
4052
+ }
4053
+ return string.substring(i + 1);
4054
+ }
4055
+ function leadingWs(string) {
4056
+ const match = string.match(/^\s*/);
4057
+ return match ? match[0] : "";
4058
+ }
4059
+
4060
+ // ../../node_modules/diff/libesm/diff/word.js
4061
+ var extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
4062
+ var tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug");
4063
+
4064
+ class WordDiff extends Diff {
4065
+ equals(left, right, options) {
4066
+ if (options.ignoreCase) {
4067
+ left = left.toLowerCase();
4068
+ right = right.toLowerCase();
4069
+ }
4070
+ return left.trim() === right.trim();
4071
+ }
4072
+ tokenize(value, options = {}) {
4073
+ let parts;
4074
+ if (options.intlSegmenter) {
4075
+ const segmenter = options.intlSegmenter;
4076
+ if (segmenter.resolvedOptions().granularity != "word") {
4077
+ throw new Error('The segmenter passed must have a granularity of "word"');
4078
+ }
4079
+ parts = Array.from(segmenter.segment(value), (segment) => segment.segment);
4080
+ } else {
4081
+ parts = value.match(tokenizeIncludingWhitespace) || [];
4082
+ }
4083
+ const tokens = [];
4084
+ let prevPart = null;
4085
+ parts.forEach((part) => {
4086
+ if (/\s/.test(part)) {
4087
+ if (prevPart == null) {
4088
+ tokens.push(part);
4089
+ } else {
4090
+ tokens.push(tokens.pop() + part);
4091
+ }
4092
+ } else if (prevPart != null && /\s/.test(prevPart)) {
4093
+ if (tokens[tokens.length - 1] == prevPart) {
4094
+ tokens.push(tokens.pop() + part);
4095
+ } else {
4096
+ tokens.push(prevPart + part);
4097
+ }
4098
+ } else {
4099
+ tokens.push(part);
4100
+ }
4101
+ prevPart = part;
4102
+ });
4103
+ return tokens;
4104
+ }
4105
+ join(tokens) {
4106
+ return tokens.map((token, i) => {
4107
+ if (i == 0) {
4108
+ return token;
4109
+ } else {
4110
+ return token.replace(/^\s+/, "");
4111
+ }
4112
+ }).join("");
4113
+ }
4114
+ postProcess(changes, options) {
4115
+ if (!changes || options.oneChangePerToken) {
4116
+ return changes;
4117
+ }
4118
+ let lastKeep = null;
4119
+ let insertion = null;
4120
+ let deletion = null;
4121
+ changes.forEach((change) => {
4122
+ if (change.added) {
4123
+ insertion = change;
4124
+ } else if (change.removed) {
4125
+ deletion = change;
4126
+ } else {
4127
+ if (insertion || deletion) {
4128
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
4129
+ }
4130
+ lastKeep = change;
4131
+ insertion = null;
4132
+ deletion = null;
4133
+ }
4134
+ });
4135
+ if (insertion || deletion) {
4136
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
4137
+ }
4138
+ return changes;
4139
+ }
4140
+ }
4141
+ var wordDiff = new WordDiff;
4142
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
4143
+ if (deletion && insertion) {
4144
+ const oldWsPrefix = leadingWs(deletion.value);
4145
+ const oldWsSuffix = trailingWs(deletion.value);
4146
+ const newWsPrefix = leadingWs(insertion.value);
4147
+ const newWsSuffix = trailingWs(insertion.value);
4148
+ if (startKeep) {
4149
+ const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
4150
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
4151
+ deletion.value = removePrefix(deletion.value, commonWsPrefix);
4152
+ insertion.value = removePrefix(insertion.value, commonWsPrefix);
4153
+ }
4154
+ if (endKeep) {
4155
+ const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
4156
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
4157
+ deletion.value = removeSuffix(deletion.value, commonWsSuffix);
4158
+ insertion.value = removeSuffix(insertion.value, commonWsSuffix);
4159
+ }
4160
+ } else if (insertion) {
4161
+ if (startKeep) {
4162
+ const ws = leadingWs(insertion.value);
4163
+ insertion.value = insertion.value.substring(ws.length);
4164
+ }
4165
+ if (endKeep) {
4166
+ const ws = leadingWs(endKeep.value);
4167
+ endKeep.value = endKeep.value.substring(ws.length);
4168
+ }
4169
+ } else if (startKeep && endKeep) {
4170
+ const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);
4171
+ const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
4172
+ deletion.value = removePrefix(deletion.value, newWsStart);
4173
+ const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
4174
+ deletion.value = removeSuffix(deletion.value, newWsEnd);
4175
+ endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
4176
+ startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
4177
+ } else if (endKeep) {
4178
+ const endKeepWsPrefix = leadingWs(endKeep.value);
4179
+ const deletionWsSuffix = trailingWs(deletion.value);
4180
+ const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
4181
+ deletion.value = removeSuffix(deletion.value, overlap);
4182
+ } else if (startKeep) {
4183
+ const startKeepWsSuffix = trailingWs(startKeep.value);
4184
+ const deletionWsPrefix = leadingWs(deletion.value);
4185
+ const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
4186
+ deletion.value = removePrefix(deletion.value, overlap);
4187
+ }
4188
+ }
4189
+
4190
+ class WordsWithSpaceDiff extends Diff {
4191
+ tokenize(value) {
4192
+ const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
4193
+ return value.match(regex) || [];
4194
+ }
4195
+ }
4196
+ var wordsWithSpaceDiff = new WordsWithSpaceDiff;
4197
+
4198
+ // ../../node_modules/diff/libesm/diff/line.js
4199
+ class LineDiff extends Diff {
4200
+ constructor() {
4201
+ super(...arguments);
4202
+ this.tokenize = tokenize;
4203
+ }
4204
+ equals(left, right, options) {
4205
+ if (options.ignoreWhitespace) {
4206
+ if (!options.newlineIsToken || !left.includes(`
4207
+ `)) {
4208
+ left = left.trim();
4209
+ }
4210
+ if (!options.newlineIsToken || !right.includes(`
4211
+ `)) {
4212
+ right = right.trim();
4213
+ }
4214
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
4215
+ if (left.endsWith(`
4216
+ `)) {
4217
+ left = left.slice(0, -1);
4218
+ }
4219
+ if (right.endsWith(`
4220
+ `)) {
4221
+ right = right.slice(0, -1);
4222
+ }
4223
+ }
4224
+ return super.equals(left, right, options);
4225
+ }
4226
+ }
4227
+ var lineDiff = new LineDiff;
4228
+ function tokenize(value, options) {
4229
+ if (options.stripTrailingCr) {
4230
+ value = value.replace(/\r\n/g, `
4231
+ `);
4232
+ }
4233
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
4234
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
4235
+ linesAndNewlines.pop();
4236
+ }
4237
+ for (let i = 0;i < linesAndNewlines.length; i++) {
4238
+ const line = linesAndNewlines[i];
4239
+ if (i % 2 && !options.newlineIsToken) {
4240
+ retLines[retLines.length - 1] += line;
4241
+ } else {
4242
+ retLines.push(line);
4243
+ }
4244
+ }
4245
+ return retLines;
4246
+ }
4247
+
4248
+ // ../../node_modules/diff/libesm/diff/sentence.js
4249
+ function isSentenceEndPunct(char) {
4250
+ return char == "." || char == "!" || char == "?";
4251
+ }
4252
+
4253
+ class SentenceDiff extends Diff {
4254
+ tokenize(value) {
4255
+ var _a;
4256
+ const result = [];
4257
+ let tokenStartI = 0;
4258
+ for (let i = 0;i < value.length; i++) {
4259
+ if (i == value.length - 1) {
4260
+ result.push(value.slice(tokenStartI));
4261
+ break;
4262
+ }
4263
+ if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) {
4264
+ result.push(value.slice(tokenStartI, i + 1));
4265
+ i = tokenStartI = i + 1;
4266
+ while ((_a = value[i + 1]) === null || _a === undefined ? undefined : _a.match(/\s/)) {
4267
+ i++;
4268
+ }
4269
+ result.push(value.slice(tokenStartI, i + 1));
4270
+ tokenStartI = i + 1;
4271
+ }
4272
+ }
4273
+ return result;
4274
+ }
4275
+ }
4276
+ var sentenceDiff = new SentenceDiff;
4277
+
4278
+ // ../../node_modules/diff/libesm/diff/css.js
4279
+ class CssDiff extends Diff {
4280
+ tokenize(value) {
4281
+ return value.split(/([{}:;,]|\s+)/);
4282
+ }
4283
+ }
4284
+ var cssDiff = new CssDiff;
4285
+
4286
+ // ../../node_modules/diff/libesm/diff/json.js
4287
+ class JsonDiff extends Diff {
4288
+ constructor() {
4289
+ super(...arguments);
4290
+ this.tokenize = tokenize;
4291
+ }
4292
+ get useLongestToken() {
4293
+ return true;
4294
+ }
4295
+ castInput(value, options) {
4296
+ const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options;
4297
+ return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " ");
4298
+ }
4299
+ equals(left, right, options) {
4300
+ return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
4301
+ }
4302
+ }
4303
+ var jsonDiff = new JsonDiff;
4304
+ function canonicalize(obj, stack, replacementStack, replacer, key) {
4305
+ stack = stack || [];
4306
+ replacementStack = replacementStack || [];
4307
+ if (replacer) {
4308
+ obj = replacer(key === undefined ? "" : key, obj);
4309
+ }
4310
+ let i;
4311
+ for (i = 0;i < stack.length; i += 1) {
4312
+ if (stack[i] === obj) {
4313
+ return replacementStack[i];
4314
+ }
4315
+ }
4316
+ let canonicalizedObj;
4317
+ if (Object.prototype.toString.call(obj) === "[object Array]") {
4318
+ stack.push(obj);
4319
+ canonicalizedObj = new Array(obj.length);
4320
+ replacementStack.push(canonicalizedObj);
4321
+ for (i = 0;i < obj.length; i += 1) {
4322
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, String(i));
4323
+ }
4324
+ stack.pop();
4325
+ replacementStack.pop();
4326
+ return canonicalizedObj;
4327
+ }
4328
+ if (obj && obj.toJSON) {
4329
+ obj = obj.toJSON();
4330
+ }
4331
+ if (typeof obj === "object" && obj !== null) {
4332
+ stack.push(obj);
4333
+ canonicalizedObj = {};
4334
+ replacementStack.push(canonicalizedObj);
4335
+ const sortedKeys = [];
4336
+ let key2;
4337
+ for (key2 in obj) {
4338
+ if (Object.prototype.hasOwnProperty.call(obj, key2)) {
4339
+ sortedKeys.push(key2);
4340
+ }
4341
+ }
4342
+ sortedKeys.sort();
4343
+ for (i = 0;i < sortedKeys.length; i += 1) {
4344
+ key2 = sortedKeys[i];
4345
+ canonicalizedObj[key2] = canonicalize(obj[key2], stack, replacementStack, replacer, key2);
4346
+ }
4347
+ stack.pop();
4348
+ replacementStack.pop();
4349
+ } else {
4350
+ canonicalizedObj = obj;
4351
+ }
4352
+ return canonicalizedObj;
4353
+ }
4354
+
4355
+ // ../../node_modules/diff/libesm/diff/array.js
4356
+ class ArrayDiff extends Diff {
4357
+ tokenize(value) {
4358
+ return value.slice();
4359
+ }
4360
+ join(value) {
4361
+ return value;
4362
+ }
4363
+ removeEmpty(value) {
4364
+ return value;
4365
+ }
4366
+ }
4367
+ var arrayDiff = new ArrayDiff;
4368
+
4369
+ // ../../node_modules/diff/libesm/patch/parse.js
4370
+ function parsePatch(uniDiff) {
4371
+ const diffstr = uniDiff.split(/\n/), list = [];
4372
+ let i = 0;
4373
+ function parseIndex() {
4374
+ const index = {};
4375
+ list.push(index);
4376
+ while (i < diffstr.length) {
4377
+ const line = diffstr[i];
4378
+ if (/^(---|\+\+\+|@@)\s/.test(line)) {
4379
+ break;
4380
+ }
4381
+ const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
4382
+ if (header) {
4383
+ index.index = header[1];
4384
+ }
4385
+ i++;
4386
+ }
4387
+ parseFileHeader(index);
4388
+ parseFileHeader(index);
4389
+ index.hunks = [];
4390
+ while (i < diffstr.length) {
4391
+ const line = diffstr[i];
4392
+ if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
4393
+ break;
4394
+ } else if (/^@@/.test(line)) {
4395
+ index.hunks.push(parseHunk());
4396
+ } else if (line) {
4397
+ throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
4398
+ } else {
4399
+ i++;
4400
+ }
4401
+ }
4402
+ }
4403
+ function parseFileHeader(index) {
4404
+ const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
4405
+ if (fileHeader) {
4406
+ const data = fileHeader[2].split("\t", 2), header = (data[1] || "").trim();
4407
+ let fileName = data[0].replace(/\\\\/g, "\\");
4408
+ if (/^".*"$/.test(fileName)) {
4409
+ fileName = fileName.substr(1, fileName.length - 2);
4410
+ }
4411
+ if (fileHeader[1] === "---") {
4412
+ index.oldFileName = fileName;
4413
+ index.oldHeader = header;
4414
+ } else {
4415
+ index.newFileName = fileName;
4416
+ index.newHeader = header;
4417
+ }
4418
+ i++;
4419
+ }
4420
+ }
4421
+ function parseHunk() {
4422
+ var _a;
4423
+ const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
4424
+ const hunk = {
4425
+ oldStart: +chunkHeader[1],
4426
+ oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
4427
+ newStart: +chunkHeader[3],
4428
+ newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
4429
+ lines: []
4430
+ };
4431
+ if (hunk.oldLines === 0) {
4432
+ hunk.oldStart += 1;
4433
+ }
4434
+ if (hunk.newLines === 0) {
4435
+ hunk.newStart += 1;
4436
+ }
4437
+ let addCount = 0, removeCount = 0;
4438
+ for (;i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === undefined ? undefined : _a.startsWith("\\"))); i++) {
4439
+ const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
4440
+ if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
4441
+ hunk.lines.push(diffstr[i]);
4442
+ if (operation === "+") {
4443
+ addCount++;
4444
+ } else if (operation === "-") {
4445
+ removeCount++;
4446
+ } else if (operation === " ") {
4447
+ addCount++;
4448
+ removeCount++;
4449
+ }
4450
+ } else {
4451
+ throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
4452
+ }
4453
+ }
4454
+ if (!addCount && hunk.newLines === 1) {
4455
+ hunk.newLines = 0;
4456
+ }
4457
+ if (!removeCount && hunk.oldLines === 1) {
4458
+ hunk.oldLines = 0;
4459
+ }
4460
+ if (addCount !== hunk.newLines) {
4461
+ throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
4462
+ }
4463
+ if (removeCount !== hunk.oldLines) {
4464
+ throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
4465
+ }
4466
+ return hunk;
4467
+ }
4468
+ while (i < diffstr.length) {
4469
+ parseIndex();
4470
+ }
4471
+ return list;
4472
+ }
4473
+
4474
+ // src/renderables/Text.ts
4475
+ class TextRenderable extends TextBufferRenderable {
4476
+ _text;
4477
+ _hasManualStyledText = false;
4478
+ rootTextNode;
4479
+ _contentDefaultOptions = {
4480
+ content: ""
4481
+ };
4482
+ constructor(ctx, options) {
4483
+ super(ctx, options);
4484
+ const content = options.content ?? this._contentDefaultOptions.content;
4485
+ const styledText = typeof content === "string" ? stringToStyledText(content) : content;
4486
+ this._text = styledText;
4487
+ this._hasManualStyledText = options.content !== undefined && content !== "";
4488
+ this.rootTextNode = new RootTextNodeRenderable(ctx, {
4489
+ id: `${this.id}-root`,
4490
+ fg: this._defaultFg,
4491
+ bg: this._defaultBg,
4492
+ attributes: this._defaultAttributes
4493
+ }, this);
4494
+ this.updateTextBuffer(styledText);
4495
+ }
4496
+ updateTextBuffer(styledText) {
4497
+ this.textBuffer.setStyledText(styledText);
4498
+ this.clearChunks(styledText);
4499
+ }
4500
+ clearChunks(styledText) {}
4501
+ get content() {
4502
+ return this._text;
4503
+ }
4504
+ get chunks() {
4505
+ return this._text.chunks;
4506
+ }
4507
+ get textNode() {
4508
+ return this.rootTextNode;
4509
+ }
4510
+ set content(value) {
4511
+ this._hasManualStyledText = true;
4512
+ const styledText = typeof value === "string" ? stringToStyledText(value) : value;
4513
+ if (this._text !== styledText) {
4514
+ this._text = styledText;
4515
+ this.updateTextBuffer(styledText);
4516
+ this.updateTextInfo();
4517
+ }
4518
+ }
4519
+ updateTextFromNodes() {
4520
+ if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
4521
+ const chunks = this.rootTextNode.gatherWithInheritedStyle({
4522
+ fg: this._defaultFg,
4523
+ bg: this._defaultBg,
4524
+ attributes: this._defaultAttributes
4525
+ });
4526
+ this.textBuffer.setStyledText(new StyledText(chunks));
4527
+ this.refreshLocalSelection();
4528
+ this.yogaNode.markDirty();
4529
+ }
4530
+ }
4531
+ add(obj, index) {
4532
+ return this.rootTextNode.add(obj, index);
4533
+ }
4534
+ remove(id) {
4535
+ this.rootTextNode.remove(id);
4536
+ }
4537
+ insertBefore(obj, anchor) {
4538
+ this.rootTextNode.insertBefore(obj, anchor);
4539
+ return this.rootTextNode.children.indexOf(obj);
4540
+ }
4541
+ getTextChildren() {
4542
+ return this.rootTextNode.getChildren();
4543
+ }
4544
+ clear() {
4545
+ this.rootTextNode.clear();
4546
+ const emptyStyledText = stringToStyledText("");
4547
+ this._text = emptyStyledText;
4548
+ this.updateTextBuffer(emptyStyledText);
4549
+ this.updateTextInfo();
4550
+ this.requestRender();
4551
+ }
4552
+ onLifecyclePass = () => {
4553
+ this.updateTextFromNodes();
4554
+ };
4555
+ onFgChanged(newColor) {
4556
+ this.rootTextNode.fg = newColor;
4557
+ }
4558
+ onBgChanged(newColor) {
4559
+ this.rootTextNode.bg = newColor;
4560
+ }
4561
+ onAttributesChanged(newAttributes) {
4562
+ this.rootTextNode.attributes = newAttributes;
4563
+ }
4564
+ destroy() {
4565
+ this.rootTextNode.children.length = 0;
4566
+ super.destroy();
4567
+ }
4568
+ }
4569
+
4570
+ // src/renderables/Diff.ts
4571
+ class DiffRenderable extends Renderable {
4572
+ _diff;
4573
+ _view;
4574
+ _parsedDiff = null;
4575
+ _parseError = null;
4576
+ _filetype;
4577
+ _syntaxStyle;
4578
+ _wrapMode;
4579
+ _conceal;
4580
+ _selectionBg;
4581
+ _selectionFg;
4582
+ _treeSitterClient;
4583
+ _showLineNumbers;
4584
+ _lineNumberFg;
4585
+ _lineNumberBg;
4586
+ _addedBg;
4587
+ _removedBg;
4588
+ _contextBg;
4589
+ _addedContentBg;
4590
+ _removedContentBg;
4591
+ _contextContentBg;
4592
+ _addedSignColor;
4593
+ _removedSignColor;
4594
+ _addedLineNumberBg;
4595
+ _removedLineNumberBg;
4596
+ leftSide = null;
4597
+ rightSide = null;
4598
+ leftSideAdded = false;
4599
+ rightSideAdded = false;
4600
+ leftCodeRenderable = null;
4601
+ rightCodeRenderable = null;
4602
+ pendingRebuild = false;
4603
+ _lastWidth = 0;
4604
+ errorTextRenderable = null;
4605
+ errorCodeRenderable = null;
4606
+ constructor(ctx, options) {
4607
+ super(ctx, {
4608
+ ...options,
4609
+ flexDirection: options.view === "split" ? "row" : "column"
4610
+ });
4611
+ this._diff = options.diff ?? "";
4612
+ this._view = options.view ?? "unified";
4613
+ this._filetype = options.filetype;
4614
+ this._syntaxStyle = options.syntaxStyle;
4615
+ this._wrapMode = options.wrapMode;
4616
+ this._conceal = options.conceal ?? false;
4617
+ this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : undefined;
4618
+ this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : undefined;
4619
+ this._treeSitterClient = options.treeSitterClient;
4620
+ this._showLineNumbers = options.showLineNumbers ?? true;
4621
+ this._lineNumberFg = parseColor(options.lineNumberFg ?? "#888888");
4622
+ this._lineNumberBg = parseColor(options.lineNumberBg ?? "transparent");
4623
+ this._addedBg = parseColor(options.addedBg ?? "#1a4d1a");
4624
+ this._removedBg = parseColor(options.removedBg ?? "#4d1a1a");
4625
+ this._contextBg = parseColor(options.contextBg ?? "transparent");
4626
+ this._addedContentBg = options.addedContentBg ? parseColor(options.addedContentBg) : null;
4627
+ this._removedContentBg = options.removedContentBg ? parseColor(options.removedContentBg) : null;
4628
+ this._contextContentBg = options.contextContentBg ? parseColor(options.contextContentBg) : null;
4629
+ this._addedSignColor = parseColor(options.addedSignColor ?? "#22c55e");
4630
+ this._removedSignColor = parseColor(options.removedSignColor ?? "#ef4444");
4631
+ this._addedLineNumberBg = parseColor(options.addedLineNumberBg ?? "transparent");
4632
+ this._removedLineNumberBg = parseColor(options.removedLineNumberBg ?? "transparent");
4633
+ if (this._diff) {
4634
+ this.parseDiff();
4635
+ this.buildView();
4636
+ }
4637
+ }
4638
+ parseDiff() {
4639
+ if (!this._diff) {
4640
+ this._parsedDiff = null;
4641
+ this._parseError = null;
4642
+ return;
4643
+ }
4644
+ try {
4645
+ const patches = parsePatch(this._diff);
4646
+ if (patches.length === 0) {
4647
+ this._parsedDiff = null;
4648
+ this._parseError = null;
4649
+ return;
4650
+ }
4651
+ this._parsedDiff = patches[0];
4652
+ this._parseError = null;
4653
+ } catch (error) {
4654
+ this._parsedDiff = null;
4655
+ this._parseError = error instanceof Error ? error : new Error(String(error));
4656
+ }
4657
+ }
4658
+ buildView() {
4659
+ if (this._parseError) {
4660
+ this.buildErrorView();
4661
+ return;
4662
+ }
4663
+ if (!this._parsedDiff || this._parsedDiff.hunks.length === 0) {
4664
+ return;
4665
+ }
4666
+ if (this._view === "unified") {
4667
+ this.buildUnifiedView();
4668
+ } else {
4669
+ this.buildSplitView();
4670
+ }
4671
+ }
4672
+ onResize(width, height) {
4673
+ super.onResize(width, height);
4674
+ if (this._view === "split" && this._wrapMode !== "none" && this._wrapMode !== undefined) {
4675
+ if (this._lastWidth !== width) {
4676
+ this._lastWidth = width;
4677
+ this.requestRebuild();
4678
+ }
4679
+ }
4680
+ }
4681
+ requestRebuild() {
4682
+ if (this.pendingRebuild) {
4683
+ return;
4684
+ }
4685
+ this.pendingRebuild = true;
4686
+ queueMicrotask(() => {
4687
+ if (!this.isDestroyed && this.pendingRebuild) {
4688
+ this.pendingRebuild = false;
4689
+ this.buildView();
4690
+ this.requestRender();
4691
+ }
4692
+ });
4693
+ }
4694
+ rebuildView() {
4695
+ if (this._view === "split") {
4696
+ this.requestRebuild();
4697
+ } else {
4698
+ this.buildView();
4699
+ }
4700
+ }
4701
+ destroyRecursively() {
4702
+ this.pendingRebuild = false;
4703
+ this.leftSideAdded = false;
4704
+ this.rightSideAdded = false;
4705
+ super.destroyRecursively();
4706
+ }
4707
+ buildErrorView() {
4708
+ this.flexDirection = "column";
4709
+ if (this.leftSide && this.leftSideAdded) {
4710
+ super.remove(this.leftSide.id);
4711
+ this.leftSideAdded = false;
4712
+ }
4713
+ if (this.rightSide && this.rightSideAdded) {
4714
+ super.remove(this.rightSide.id);
4715
+ this.rightSideAdded = false;
4716
+ }
4717
+ const errorMessage = `Error parsing diff: ${this._parseError?.message || "Unknown error"}
4718
+ `;
4719
+ if (!this.errorTextRenderable) {
4720
+ this.errorTextRenderable = new TextRenderable(this.ctx, {
4721
+ id: this.id ? `${this.id}-error-text` : undefined,
4722
+ content: errorMessage,
4723
+ fg: "#ef4444",
4724
+ width: "100%",
4725
+ flexShrink: 0
4726
+ });
4727
+ super.add(this.errorTextRenderable);
4728
+ } else {
4729
+ this.errorTextRenderable.content = errorMessage;
4730
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4731
+ if (errorTextIndex === -1) {
4732
+ super.add(this.errorTextRenderable);
4733
+ }
4734
+ }
4735
+ if (!this.errorCodeRenderable) {
4736
+ this.errorCodeRenderable = new CodeRenderable(this.ctx, {
4737
+ id: this.id ? `${this.id}-error-code` : undefined,
4738
+ content: this._diff,
4739
+ filetype: "diff",
4740
+ syntaxStyle: this._syntaxStyle ?? SyntaxStyle.create(),
4741
+ wrapMode: this._wrapMode,
4742
+ conceal: this._conceal,
4743
+ width: "100%",
4744
+ flexGrow: 1,
4745
+ flexShrink: 1,
4746
+ ...this._treeSitterClient !== undefined && { treeSitterClient: this._treeSitterClient }
4747
+ });
4748
+ super.add(this.errorCodeRenderable);
4749
+ } else {
4750
+ this.errorCodeRenderable.content = this._diff;
4751
+ this.errorCodeRenderable.wrapMode = this._wrapMode ?? "none";
4752
+ if (this._syntaxStyle) {
4753
+ this.errorCodeRenderable.syntaxStyle = this._syntaxStyle;
4754
+ }
4755
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4756
+ if (errorCodeIndex === -1) {
4757
+ super.add(this.errorCodeRenderable);
4758
+ }
4759
+ }
4760
+ }
4761
+ createOrUpdateCodeRenderable(side, content, wrapMode, drawUnstyledText) {
4762
+ const existingRenderable = side === "left" ? this.leftCodeRenderable : this.rightCodeRenderable;
4763
+ if (!existingRenderable) {
4764
+ const codeOptions = {
4765
+ id: this.id ? `${this.id}-${side}-code` : undefined,
4766
+ content,
4767
+ filetype: this._filetype,
4768
+ wrapMode,
4769
+ conceal: this._conceal,
4770
+ syntaxStyle: this._syntaxStyle ?? SyntaxStyle.create(),
4771
+ width: "100%",
4772
+ height: "100%",
4773
+ ...drawUnstyledText !== undefined && { drawUnstyledText },
4774
+ ...this._selectionBg !== undefined && { selectionBg: this._selectionBg },
4775
+ ...this._selectionFg !== undefined && { selectionFg: this._selectionFg },
4776
+ ...this._treeSitterClient !== undefined && { treeSitterClient: this._treeSitterClient }
4777
+ };
4778
+ const newRenderable = new CodeRenderable(this.ctx, codeOptions);
4779
+ if (side === "left") {
4780
+ this.leftCodeRenderable = newRenderable;
4781
+ } else {
4782
+ this.rightCodeRenderable = newRenderable;
4783
+ }
4784
+ return newRenderable;
4785
+ } else {
4786
+ existingRenderable.content = content;
4787
+ existingRenderable.wrapMode = wrapMode ?? "none";
4788
+ existingRenderable.conceal = this._conceal;
4789
+ if (drawUnstyledText !== undefined) {
4790
+ existingRenderable.drawUnstyledText = drawUnstyledText;
4791
+ }
4792
+ if (this._filetype !== undefined) {
4793
+ existingRenderable.filetype = this._filetype;
4794
+ }
4795
+ if (this._syntaxStyle !== undefined) {
4796
+ existingRenderable.syntaxStyle = this._syntaxStyle;
4797
+ }
4798
+ if (this._selectionBg !== undefined) {
4799
+ existingRenderable.selectionBg = this._selectionBg;
4800
+ }
4801
+ if (this._selectionFg !== undefined) {
4802
+ existingRenderable.selectionFg = this._selectionFg;
4803
+ }
4804
+ return existingRenderable;
4805
+ }
4806
+ }
4807
+ createOrUpdateSide(side, target, lineColors, lineSigns, lineNumbers, hideLineNumbers, width) {
4808
+ const sideRef = side === "left" ? this.leftSide : this.rightSide;
4809
+ const addedFlag = side === "left" ? this.leftSideAdded : this.rightSideAdded;
4810
+ if (!sideRef) {
4811
+ const newSide = new LineNumberRenderable(this.ctx, {
4812
+ id: this.id ? `${this.id}-${side}` : undefined,
4813
+ target,
4814
+ fg: this._lineNumberFg,
4815
+ bg: this._lineNumberBg,
4816
+ lineColors,
4817
+ lineSigns,
4818
+ lineNumbers,
4819
+ lineNumberOffset: 0,
4820
+ hideLineNumbers,
4821
+ width,
4822
+ height: "100%"
4823
+ });
4824
+ newSide.showLineNumbers = this._showLineNumbers;
4825
+ super.add(newSide);
4826
+ if (side === "left") {
4827
+ this.leftSide = newSide;
4828
+ this.leftSideAdded = true;
4829
+ } else {
4830
+ this.rightSide = newSide;
4831
+ this.rightSideAdded = true;
4832
+ }
4833
+ } else {
4834
+ sideRef.width = width;
4835
+ sideRef.setLineColors(lineColors);
4836
+ sideRef.setLineSigns(lineSigns);
4837
+ sideRef.setLineNumbers(lineNumbers);
4838
+ sideRef.setHideLineNumbers(hideLineNumbers);
4839
+ if (!addedFlag) {
4840
+ super.add(sideRef);
4841
+ if (side === "left") {
4842
+ this.leftSideAdded = true;
4843
+ } else {
4844
+ this.rightSideAdded = true;
4845
+ }
4846
+ }
4847
+ }
4848
+ }
4849
+ buildUnifiedView() {
4850
+ if (!this._parsedDiff)
4851
+ return;
4852
+ this.flexDirection = "column";
4853
+ if (this.errorTextRenderable) {
4854
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4855
+ if (errorTextIndex !== -1) {
4856
+ super.remove(this.errorTextRenderable.id);
4857
+ }
4858
+ }
4859
+ if (this.errorCodeRenderable) {
4860
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4861
+ if (errorCodeIndex !== -1) {
4862
+ super.remove(this.errorCodeRenderable.id);
4863
+ }
4864
+ }
4865
+ const contentLines = [];
4866
+ const lineColors = new Map;
4867
+ const lineSigns = new Map;
4868
+ const lineNumbers = new Map;
4869
+ let lineIndex = 0;
4870
+ for (const hunk of this._parsedDiff.hunks) {
4871
+ let oldLineNum = hunk.oldStart;
4872
+ let newLineNum = hunk.newStart;
4873
+ for (const line of hunk.lines) {
4874
+ const firstChar = line[0];
4875
+ const content2 = line.slice(1);
4876
+ if (firstChar === "+") {
4877
+ contentLines.push(content2);
4878
+ const config = {
4879
+ gutter: this._addedLineNumberBg
4880
+ };
4881
+ if (this._addedContentBg) {
4882
+ config.content = this._addedContentBg;
4883
+ } else {
4884
+ config.content = this._addedBg;
4885
+ }
4886
+ lineColors.set(lineIndex, config);
4887
+ lineSigns.set(lineIndex, {
4888
+ after: " +",
4889
+ afterColor: this._addedSignColor
4890
+ });
4891
+ lineNumbers.set(lineIndex, newLineNum);
4892
+ newLineNum++;
4893
+ lineIndex++;
4894
+ } else if (firstChar === "-") {
4895
+ contentLines.push(content2);
4896
+ const config = {
4897
+ gutter: this._removedLineNumberBg
4898
+ };
4899
+ if (this._removedContentBg) {
4900
+ config.content = this._removedContentBg;
4901
+ } else {
4902
+ config.content = this._removedBg;
4903
+ }
4904
+ lineColors.set(lineIndex, config);
4905
+ lineSigns.set(lineIndex, {
4906
+ after: " -",
4907
+ afterColor: this._removedSignColor
4908
+ });
4909
+ lineNumbers.set(lineIndex, oldLineNum);
4910
+ oldLineNum++;
4911
+ lineIndex++;
4912
+ } else if (firstChar === " ") {
4913
+ contentLines.push(content2);
4914
+ const config = {
4915
+ gutter: this._lineNumberBg
4916
+ };
4917
+ if (this._contextContentBg) {
4918
+ config.content = this._contextContentBg;
4919
+ } else {
4920
+ config.content = this._contextBg;
4921
+ }
4922
+ lineColors.set(lineIndex, config);
4923
+ lineNumbers.set(lineIndex, newLineNum);
4924
+ oldLineNum++;
4925
+ newLineNum++;
4926
+ lineIndex++;
4927
+ }
4928
+ }
4929
+ }
4930
+ const content = contentLines.join(`
4931
+ `);
4932
+ const codeRenderable = this.createOrUpdateCodeRenderable("left", content, this._wrapMode);
4933
+ this.createOrUpdateSide("left", codeRenderable, lineColors, lineSigns, lineNumbers, new Set, "100%");
4934
+ if (this.rightSide && this.rightSideAdded) {
4935
+ super.remove(this.rightSide.id);
4936
+ this.rightSideAdded = false;
4937
+ }
4938
+ }
4939
+ buildSplitView() {
4940
+ if (!this._parsedDiff)
4941
+ return;
4942
+ this.flexDirection = "row";
4943
+ if (this.errorTextRenderable) {
4944
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4945
+ if (errorTextIndex !== -1) {
4946
+ super.remove(this.errorTextRenderable.id);
4947
+ }
4948
+ }
4949
+ if (this.errorCodeRenderable) {
4950
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4951
+ if (errorCodeIndex !== -1) {
4952
+ super.remove(this.errorCodeRenderable.id);
4953
+ }
4954
+ }
4955
+ const leftLogicalLines = [];
4956
+ const rightLogicalLines = [];
4957
+ for (const hunk of this._parsedDiff.hunks) {
4958
+ let oldLineNum = hunk.oldStart;
4959
+ let newLineNum = hunk.newStart;
4960
+ let i = 0;
4961
+ while (i < hunk.lines.length) {
4962
+ const line = hunk.lines[i];
4963
+ const firstChar = line[0];
4964
+ if (firstChar === " ") {
4965
+ const content = line.slice(1);
4966
+ leftLogicalLines.push({
4967
+ content,
4968
+ lineNum: oldLineNum,
4969
+ color: this._contextBg,
4970
+ type: "context"
4971
+ });
4972
+ rightLogicalLines.push({
4973
+ content,
4974
+ lineNum: newLineNum,
4975
+ color: this._contextBg,
4976
+ type: "context"
4977
+ });
4978
+ oldLineNum++;
4979
+ newLineNum++;
4980
+ i++;
4981
+ } else if (firstChar === "\\") {
4982
+ i++;
4983
+ } else {
4984
+ const removes = [];
4985
+ const adds = [];
4986
+ while (i < hunk.lines.length) {
4987
+ const currentLine = hunk.lines[i];
4988
+ const currentChar = currentLine[0];
4989
+ if (currentChar === " " || currentChar === "\\") {
4990
+ break;
4991
+ }
4992
+ const content = currentLine.slice(1);
4993
+ if (currentChar === "-") {
4994
+ removes.push({ content, lineNum: oldLineNum });
4995
+ oldLineNum++;
4996
+ } else if (currentChar === "+") {
4997
+ adds.push({ content, lineNum: newLineNum });
4998
+ newLineNum++;
4999
+ }
5000
+ i++;
5001
+ }
5002
+ const maxLength = Math.max(removes.length, adds.length);
5003
+ for (let j = 0;j < maxLength; j++) {
5004
+ if (j < removes.length) {
5005
+ leftLogicalLines.push({
5006
+ content: removes[j].content,
5007
+ lineNum: removes[j].lineNum,
5008
+ color: this._removedBg,
5009
+ sign: {
5010
+ after: " -",
5011
+ afterColor: this._removedSignColor
5012
+ },
5013
+ type: "remove"
5014
+ });
5015
+ } else {
5016
+ leftLogicalLines.push({
5017
+ content: "",
5018
+ hideLineNumber: true,
5019
+ type: "empty"
5020
+ });
5021
+ }
5022
+ if (j < adds.length) {
5023
+ rightLogicalLines.push({
5024
+ content: adds[j].content,
5025
+ lineNum: adds[j].lineNum,
5026
+ color: this._addedBg,
5027
+ sign: {
5028
+ after: " +",
5029
+ afterColor: this._addedSignColor
5030
+ },
5031
+ type: "add"
5032
+ });
5033
+ } else {
5034
+ rightLogicalLines.push({
5035
+ content: "",
5036
+ hideLineNumber: true,
5037
+ type: "empty"
5038
+ });
5039
+ }
5040
+ }
5041
+ }
5042
+ }
5043
+ }
5044
+ const canDoWrapAlignment = this.width > 0 && (this._wrapMode === "word" || this._wrapMode === "char");
5045
+ const preLeftContent = leftLogicalLines.map((l) => l.content).join(`
5046
+ `);
5047
+ const preRightContent = rightLogicalLines.map((l) => l.content).join(`
5048
+ `);
5049
+ const needsConsistentConcealing = (this._wrapMode === "word" || this._wrapMode === "char") && this._conceal && this._filetype;
5050
+ const drawUnstyledText = !needsConsistentConcealing;
5051
+ const leftCodeRenderable = this.createOrUpdateCodeRenderable("left", preLeftContent, this._wrapMode, drawUnstyledText);
5052
+ const rightCodeRenderable = this.createOrUpdateCodeRenderable("right", preRightContent, this._wrapMode, drawUnstyledText);
5053
+ let finalLeftLines;
5054
+ let finalRightLines;
5055
+ if (canDoWrapAlignment) {
5056
+ const leftLineInfo = leftCodeRenderable.lineInfo;
5057
+ const rightLineInfo = rightCodeRenderable.lineInfo;
5058
+ const leftSources = leftLineInfo.lineSources || [];
5059
+ const rightSources = rightLineInfo.lineSources || [];
5060
+ const leftVisualCounts = new Map;
5061
+ const rightVisualCounts = new Map;
5062
+ for (const logicalLine of leftSources) {
5063
+ leftVisualCounts.set(logicalLine, (leftVisualCounts.get(logicalLine) || 0) + 1);
5064
+ }
5065
+ for (const logicalLine of rightSources) {
5066
+ rightVisualCounts.set(logicalLine, (rightVisualCounts.get(logicalLine) || 0) + 1);
5067
+ }
5068
+ finalLeftLines = [];
5069
+ finalRightLines = [];
5070
+ let leftVisualPos = 0;
5071
+ let rightVisualPos = 0;
5072
+ for (let i = 0;i < leftLogicalLines.length; i++) {
5073
+ const leftLine = leftLogicalLines[i];
5074
+ const rightLine = rightLogicalLines[i];
5075
+ const leftVisualCount = leftVisualCounts.get(i) || 1;
5076
+ const rightVisualCount = rightVisualCounts.get(i) || 1;
5077
+ if (leftVisualPos < rightVisualPos) {
5078
+ const pad = rightVisualPos - leftVisualPos;
5079
+ for (let p = 0;p < pad; p++) {
5080
+ finalLeftLines.push({ content: "", hideLineNumber: true, type: "empty" });
5081
+ }
5082
+ leftVisualPos += pad;
5083
+ } else if (rightVisualPos < leftVisualPos) {
5084
+ const pad = leftVisualPos - rightVisualPos;
5085
+ for (let p = 0;p < pad; p++) {
5086
+ finalRightLines.push({ content: "", hideLineNumber: true, type: "empty" });
5087
+ }
5088
+ rightVisualPos += pad;
5089
+ }
5090
+ finalLeftLines.push(leftLine);
5091
+ finalRightLines.push(rightLine);
5092
+ leftVisualPos += leftVisualCount;
5093
+ rightVisualPos += rightVisualCount;
5094
+ }
5095
+ if (leftVisualPos < rightVisualPos) {
5096
+ const pad = rightVisualPos - leftVisualPos;
5097
+ for (let p = 0;p < pad; p++) {
5098
+ finalLeftLines.push({ content: "", hideLineNumber: true, type: "empty" });
5099
+ }
5100
+ } else if (rightVisualPos < leftVisualPos) {
5101
+ const pad = leftVisualPos - rightVisualPos;
5102
+ for (let p = 0;p < pad; p++) {
5103
+ finalRightLines.push({ content: "", hideLineNumber: true, type: "empty" });
5104
+ }
5105
+ }
5106
+ } else {
5107
+ finalLeftLines = leftLogicalLines;
5108
+ finalRightLines = rightLogicalLines;
5109
+ }
5110
+ const leftLineColors = new Map;
5111
+ const rightLineColors = new Map;
5112
+ const leftLineSigns = new Map;
5113
+ const rightLineSigns = new Map;
5114
+ const leftHideLineNumbers = new Set;
5115
+ const rightHideLineNumbers = new Set;
5116
+ const leftLineNumbers = new Map;
5117
+ const rightLineNumbers = new Map;
5118
+ finalLeftLines.forEach((line, index) => {
5119
+ if (line.lineNum !== undefined) {
5120
+ leftLineNumbers.set(index, line.lineNum);
5121
+ }
5122
+ if (line.hideLineNumber) {
5123
+ leftHideLineNumbers.add(index);
5124
+ }
5125
+ if (line.type === "remove") {
5126
+ const config = {
5127
+ gutter: this._removedLineNumberBg
5128
+ };
5129
+ if (this._removedContentBg) {
5130
+ config.content = this._removedContentBg;
5131
+ } else {
5132
+ config.content = this._removedBg;
5133
+ }
5134
+ leftLineColors.set(index, config);
5135
+ } else if (line.type === "context") {
5136
+ const config = {
5137
+ gutter: this._lineNumberBg
5138
+ };
5139
+ if (this._contextContentBg) {
5140
+ config.content = this._contextContentBg;
5141
+ } else {
5142
+ config.content = this._contextBg;
5143
+ }
5144
+ leftLineColors.set(index, config);
5145
+ }
5146
+ if (line.sign) {
5147
+ leftLineSigns.set(index, line.sign);
5148
+ }
5149
+ });
5150
+ finalRightLines.forEach((line, index) => {
5151
+ if (line.lineNum !== undefined) {
5152
+ rightLineNumbers.set(index, line.lineNum);
5153
+ }
5154
+ if (line.hideLineNumber) {
5155
+ rightHideLineNumbers.add(index);
5156
+ }
5157
+ if (line.type === "add") {
5158
+ const config = {
5159
+ gutter: this._addedLineNumberBg
5160
+ };
5161
+ if (this._addedContentBg) {
5162
+ config.content = this._addedContentBg;
5163
+ } else {
5164
+ config.content = this._addedBg;
5165
+ }
5166
+ rightLineColors.set(index, config);
5167
+ } else if (line.type === "context") {
5168
+ const config = {
5169
+ gutter: this._lineNumberBg
5170
+ };
5171
+ if (this._contextContentBg) {
5172
+ config.content = this._contextContentBg;
5173
+ } else {
5174
+ config.content = this._contextBg;
5175
+ }
5176
+ rightLineColors.set(index, config);
5177
+ }
5178
+ if (line.sign) {
5179
+ rightLineSigns.set(index, line.sign);
5180
+ }
5181
+ });
5182
+ const leftContentFinal = finalLeftLines.map((l) => l.content).join(`
5183
+ `);
5184
+ const rightContentFinal = finalRightLines.map((l) => l.content).join(`
5185
+ `);
5186
+ leftCodeRenderable.content = leftContentFinal;
5187
+ rightCodeRenderable.content = rightContentFinal;
5188
+ this.createOrUpdateSide("left", leftCodeRenderable, leftLineColors, leftLineSigns, leftLineNumbers, leftHideLineNumbers, "50%");
5189
+ this.createOrUpdateSide("right", rightCodeRenderable, rightLineColors, rightLineSigns, rightLineNumbers, rightHideLineNumbers, "50%");
5190
+ }
5191
+ get diff() {
5192
+ return this._diff;
5193
+ }
5194
+ set diff(value) {
5195
+ if (this._diff !== value) {
5196
+ this._diff = value;
5197
+ this.parseDiff();
5198
+ this.rebuildView();
5199
+ }
5200
+ }
5201
+ get view() {
5202
+ return this._view;
5203
+ }
5204
+ set view(value) {
5205
+ if (this._view !== value) {
5206
+ this._view = value;
5207
+ this.flexDirection = value === "split" ? "row" : "column";
5208
+ this.buildView();
5209
+ }
5210
+ }
5211
+ get filetype() {
5212
+ return this._filetype;
5213
+ }
5214
+ set filetype(value) {
5215
+ if (this._filetype !== value) {
5216
+ this._filetype = value;
5217
+ this.rebuildView();
5218
+ }
5219
+ }
5220
+ get syntaxStyle() {
5221
+ return this._syntaxStyle;
5222
+ }
5223
+ set syntaxStyle(value) {
5224
+ if (this._syntaxStyle !== value) {
5225
+ this._syntaxStyle = value;
5226
+ this.rebuildView();
5227
+ }
5228
+ }
5229
+ get wrapMode() {
5230
+ return this._wrapMode;
5231
+ }
5232
+ set wrapMode(value) {
5233
+ if (this._wrapMode !== value) {
5234
+ this._wrapMode = value;
5235
+ if (this._view === "unified" && this.leftCodeRenderable) {
5236
+ this.leftCodeRenderable.wrapMode = value ?? "none";
5237
+ } else if (this._view === "split") {
5238
+ this.requestRebuild();
5239
+ }
5240
+ }
5241
+ }
5242
+ get showLineNumbers() {
5243
+ return this._showLineNumbers;
5244
+ }
5245
+ set showLineNumbers(value) {
5246
+ if (this._showLineNumbers !== value) {
5247
+ this._showLineNumbers = value;
5248
+ if (this.leftSide) {
5249
+ this.leftSide.showLineNumbers = value;
5250
+ }
5251
+ if (this.rightSide) {
5252
+ this.rightSide.showLineNumbers = value;
5253
+ }
5254
+ }
5255
+ }
5256
+ get addedBg() {
5257
+ return this._addedBg;
5258
+ }
5259
+ set addedBg(value) {
5260
+ const parsed = parseColor(value);
5261
+ if (this._addedBg !== parsed) {
5262
+ this._addedBg = parsed;
5263
+ this.rebuildView();
5264
+ }
5265
+ }
5266
+ get removedBg() {
5267
+ return this._removedBg;
5268
+ }
5269
+ set removedBg(value) {
5270
+ const parsed = parseColor(value);
5271
+ if (this._removedBg !== parsed) {
5272
+ this._removedBg = parsed;
5273
+ this.rebuildView();
5274
+ }
5275
+ }
5276
+ get contextBg() {
5277
+ return this._contextBg;
5278
+ }
5279
+ set contextBg(value) {
5280
+ const parsed = parseColor(value);
5281
+ if (this._contextBg !== parsed) {
5282
+ this._contextBg = parsed;
5283
+ this.rebuildView();
5284
+ }
5285
+ }
5286
+ get addedSignColor() {
5287
+ return this._addedSignColor;
5288
+ }
5289
+ set addedSignColor(value) {
5290
+ const parsed = parseColor(value);
5291
+ if (this._addedSignColor !== parsed) {
5292
+ this._addedSignColor = parsed;
5293
+ this.rebuildView();
5294
+ }
5295
+ }
5296
+ get removedSignColor() {
5297
+ return this._removedSignColor;
5298
+ }
5299
+ set removedSignColor(value) {
5300
+ const parsed = parseColor(value);
5301
+ if (this._removedSignColor !== parsed) {
5302
+ this._removedSignColor = parsed;
5303
+ this.rebuildView();
5304
+ }
5305
+ }
5306
+ get addedLineNumberBg() {
5307
+ return this._addedLineNumberBg;
5308
+ }
5309
+ set addedLineNumberBg(value) {
5310
+ const parsed = parseColor(value);
5311
+ if (this._addedLineNumberBg !== parsed) {
5312
+ this._addedLineNumberBg = parsed;
5313
+ this.rebuildView();
5314
+ }
5315
+ }
5316
+ get removedLineNumberBg() {
5317
+ return this._removedLineNumberBg;
5318
+ }
5319
+ set removedLineNumberBg(value) {
5320
+ const parsed = parseColor(value);
5321
+ if (this._removedLineNumberBg !== parsed) {
5322
+ this._removedLineNumberBg = parsed;
5323
+ this.rebuildView();
5324
+ }
5325
+ }
5326
+ get lineNumberFg() {
5327
+ return this._lineNumberFg;
5328
+ }
5329
+ set lineNumberFg(value) {
5330
+ const parsed = parseColor(value);
5331
+ if (this._lineNumberFg !== parsed) {
5332
+ this._lineNumberFg = parsed;
5333
+ this.rebuildView();
5334
+ }
5335
+ }
5336
+ get lineNumberBg() {
5337
+ return this._lineNumberBg;
5338
+ }
5339
+ set lineNumberBg(value) {
5340
+ const parsed = parseColor(value);
5341
+ if (this._lineNumberBg !== parsed) {
5342
+ this._lineNumberBg = parsed;
5343
+ this.rebuildView();
5344
+ }
5345
+ }
5346
+ get addedContentBg() {
5347
+ return this._addedContentBg;
5348
+ }
5349
+ set addedContentBg(value) {
5350
+ const parsed = value ? parseColor(value) : null;
5351
+ if (this._addedContentBg !== parsed) {
5352
+ this._addedContentBg = parsed;
5353
+ this.rebuildView();
5354
+ }
5355
+ }
5356
+ get removedContentBg() {
5357
+ return this._removedContentBg;
5358
+ }
5359
+ set removedContentBg(value) {
5360
+ const parsed = value ? parseColor(value) : null;
5361
+ if (this._removedContentBg !== parsed) {
5362
+ this._removedContentBg = parsed;
5363
+ this.rebuildView();
5364
+ }
5365
+ }
5366
+ get contextContentBg() {
5367
+ return this._contextContentBg;
5368
+ }
5369
+ set contextContentBg(value) {
5370
+ const parsed = value ? parseColor(value) : null;
5371
+ if (this._contextContentBg !== parsed) {
5372
+ this._contextContentBg = parsed;
5373
+ this.rebuildView();
5374
+ }
5375
+ }
5376
+ get selectionBg() {
5377
+ return this._selectionBg;
5378
+ }
5379
+ set selectionBg(value) {
5380
+ const parsed = value ? parseColor(value) : undefined;
5381
+ if (this._selectionBg !== parsed) {
5382
+ this._selectionBg = parsed;
5383
+ if (this.leftCodeRenderable) {
5384
+ this.leftCodeRenderable.selectionBg = parsed;
5385
+ }
5386
+ if (this.rightCodeRenderable) {
5387
+ this.rightCodeRenderable.selectionBg = parsed;
5388
+ }
5389
+ }
5390
+ }
5391
+ get selectionFg() {
5392
+ return this._selectionFg;
5393
+ }
5394
+ set selectionFg(value) {
5395
+ const parsed = value ? parseColor(value) : undefined;
5396
+ if (this._selectionFg !== parsed) {
5397
+ this._selectionFg = parsed;
5398
+ if (this.leftCodeRenderable) {
5399
+ this.leftCodeRenderable.selectionFg = parsed;
5400
+ }
5401
+ if (this.rightCodeRenderable) {
5402
+ this.rightCodeRenderable.selectionFg = parsed;
5403
+ }
5404
+ }
5405
+ }
5406
+ get conceal() {
5407
+ return this._conceal;
5408
+ }
5409
+ set conceal(value) {
5410
+ if (this._conceal !== value) {
5411
+ this._conceal = value;
5412
+ this.rebuildView();
5413
+ }
5414
+ }
5415
+ }
5416
+ // src/renderables/Input.ts
5417
+ var InputRenderableEvents;
5418
+ ((InputRenderableEvents2) => {
5419
+ InputRenderableEvents2["INPUT"] = "input";
5420
+ InputRenderableEvents2["CHANGE"] = "change";
5421
+ InputRenderableEvents2["ENTER"] = "enter";
5422
+ })(InputRenderableEvents ||= {});
5423
+
5424
+ class InputRenderable extends Renderable {
5425
+ _focusable = true;
5426
+ _value = "";
5427
+ _cursorPosition = 0;
5428
+ _placeholder;
5429
+ _backgroundColor;
5430
+ _textColor;
5431
+ _focusedBackgroundColor;
5432
+ _focusedTextColor;
5433
+ _placeholderColor;
5434
+ _cursorColor;
5435
+ _cursorStyle;
5436
+ _maxLength;
5437
+ _lastCommittedValue = "";
5438
+ _defaultOptions = {
5439
+ backgroundColor: "transparent",
5440
+ textColor: "#FFFFFF",
5441
+ focusedBackgroundColor: "#1a1a1a",
5442
+ focusedTextColor: "#FFFFFF",
5443
+ placeholder: "",
5444
+ placeholderColor: "#666666",
5445
+ cursorColor: "#FFFFFF",
5446
+ cursorStyle: {
5447
+ style: "block",
5448
+ blinking: true
5449
+ },
5450
+ maxLength: 1000,
5451
+ value: ""
5452
+ };
5453
+ constructor(ctx, options) {
5454
+ super(ctx, { ...options, buffered: true });
5455
+ this._backgroundColor = parseColor(options.backgroundColor || this._defaultOptions.backgroundColor);
5456
+ this._textColor = parseColor(options.textColor || this._defaultOptions.textColor);
5457
+ this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || this._defaultOptions.focusedBackgroundColor);
5458
+ this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || this._defaultOptions.focusedTextColor);
5459
+ this._placeholder = options.placeholder || this._defaultOptions.placeholder;
5460
+ this._value = options.value || this._defaultOptions.value;
5461
+ this._lastCommittedValue = this._value;
5462
+ this._cursorPosition = this._value.length;
5463
+ this._maxLength = options.maxLength || this._defaultOptions.maxLength;
5464
+ this._placeholderColor = parseColor(options.placeholderColor || this._defaultOptions.placeholderColor);
5465
+ this._cursorColor = parseColor(options.cursorColor || this._defaultOptions.cursorColor);
5466
+ this._cursorStyle = options.cursorStyle || this._defaultOptions.cursorStyle;
5467
+ }
5468
+ updateCursorPosition() {
5469
+ if (!this._focused)
5470
+ return;
5471
+ const contentX = 0;
5472
+ const contentY = 0;
5473
+ const contentWidth = this.width;
5474
+ const maxVisibleChars = contentWidth - 1;
5475
+ let displayStartIndex = 0;
5476
+ if (this._cursorPosition >= maxVisibleChars) {
5477
+ displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
5478
+ }
5479
+ const cursorDisplayX = this._cursorPosition - displayStartIndex;
5480
+ if (cursorDisplayX >= 0 && cursorDisplayX < contentWidth) {
5481
+ const absoluteCursorX = this.x + contentX + cursorDisplayX + 1;
5482
+ const absoluteCursorY = this.y + contentY + 1;
5483
+ this._ctx.setCursorPosition(absoluteCursorX, absoluteCursorY, true);
5484
+ this._ctx.setCursorColor(this._cursorColor);
5485
+ }
5486
+ }
5487
+ focus() {
5488
+ super.focus();
5489
+ this._ctx.setCursorStyle(this._cursorStyle.style, this._cursorStyle.blinking);
5490
+ this._ctx.setCursorColor(this._cursorColor);
5491
+ this.updateCursorPosition();
5492
+ }
5493
+ blur() {
5494
+ super.blur();
5495
+ this._ctx.setCursorPosition(0, 0, false);
5496
+ if (this._value !== this._lastCommittedValue) {
5497
+ this._lastCommittedValue = this._value;
5498
+ this.emit("change" /* CHANGE */, this._value);
5499
+ }
5500
+ }
5501
+ renderSelf(buffer, deltaTime) {
5502
+ if (!this.visible || !this.frameBuffer)
5503
+ return;
5504
+ if (this.isDirty) {
5505
+ this.refreshFrameBuffer();
5506
+ }
5507
+ }
5508
+ refreshFrameBuffer() {
5509
+ if (!this.frameBuffer)
5510
+ return;
5511
+ const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
5512
+ this.frameBuffer.clear(bgColor);
5513
+ const contentX = 0;
5514
+ const contentY = 0;
5515
+ const contentWidth = this.width;
5516
+ const contentHeight = this.height;
5517
+ const displayText = this._value || this._placeholder;
5518
+ const isPlaceholder = !this._value && this._placeholder;
5519
+ const baseTextColor = this._focused ? this._focusedTextColor : this._textColor;
5520
+ const textColor = isPlaceholder ? this._placeholderColor : baseTextColor;
5521
+ const maxVisibleChars = contentWidth - 1;
5522
+ let displayStartIndex = 0;
5523
+ if (this._cursorPosition >= maxVisibleChars) {
5524
+ displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
5525
+ }
5526
+ const visibleText = displayText.substring(displayStartIndex, displayStartIndex + maxVisibleChars);
5527
+ if (visibleText) {
5528
+ this.frameBuffer.drawText(visibleText, contentX, contentY, textColor);
5529
+ }
5530
+ if (this._focused) {
5531
+ this.updateCursorPosition();
5532
+ }
5533
+ }
5534
+ get value() {
5535
+ return this._value;
5536
+ }
5537
+ set value(value) {
5538
+ const newValue = value.substring(0, this._maxLength);
5539
+ if (this._value !== newValue) {
5540
+ this._value = newValue;
5541
+ this._cursorPosition = Math.min(this._cursorPosition, this._value.length);
5542
+ this.requestRender();
5543
+ this.updateCursorPosition();
5544
+ this.emit("input" /* INPUT */, this._value);
5545
+ }
5546
+ }
5547
+ set placeholder(placeholder) {
5548
+ if (this._placeholder !== placeholder) {
5549
+ this._placeholder = placeholder;
5550
+ this.requestRender();
5551
+ }
5552
+ }
5553
+ get cursorPosition() {
5554
+ return this._cursorPosition;
5555
+ }
5556
+ set cursorPosition(position) {
5557
+ const newPosition = Math.max(0, Math.min(position, this._value.length));
5558
+ if (this._cursorPosition !== newPosition) {
5559
+ this._cursorPosition = newPosition;
5560
+ this.requestRender();
5561
+ this.updateCursorPosition();
5562
+ }
5563
+ }
5564
+ insertText(text) {
5565
+ if (this._value.length + text.length > this._maxLength) {
3333
5566
  return;
3334
5567
  }
3335
5568
  const beforeCursor = this._value.substring(0, this._cursorPosition);
@@ -4100,6 +6333,8 @@ class ScrollBoxRenderable extends BoxRenderable {
4100
6333
  cachedAutoScrollSpeed = 3;
4101
6334
  autoScrollAccumulatorX = 0;
4102
6335
  autoScrollAccumulatorY = 0;
6336
+ scrollAccumulatorX = 0;
6337
+ scrollAccumulatorY = 0;
4103
6338
  _stickyScroll;
4104
6339
  _stickyScrollTop = false;
4105
6340
  _stickyScrollBottom = false;
@@ -4375,14 +6610,35 @@ class ScrollBoxRenderable extends BoxRenderable {
4375
6610
  const baseDelta = event.scroll?.delta ?? 0;
4376
6611
  const now = Date.now();
4377
6612
  const multiplier = this.scrollAccel.tick(now);
6613
+ const scrollAmount = baseDelta * multiplier;
4378
6614
  if (dir === "up") {
4379
- this.scrollTop -= baseDelta * multiplier;
6615
+ this.scrollAccumulatorY -= scrollAmount;
6616
+ const integerScroll = Math.trunc(this.scrollAccumulatorY);
6617
+ if (integerScroll !== 0) {
6618
+ this.scrollTop += integerScroll;
6619
+ this.scrollAccumulatorY -= integerScroll;
6620
+ }
4380
6621
  } else if (dir === "down") {
4381
- this.scrollTop += baseDelta * multiplier;
6622
+ this.scrollAccumulatorY += scrollAmount;
6623
+ const integerScroll = Math.trunc(this.scrollAccumulatorY);
6624
+ if (integerScroll !== 0) {
6625
+ this.scrollTop += integerScroll;
6626
+ this.scrollAccumulatorY -= integerScroll;
6627
+ }
4382
6628
  } else if (dir === "left") {
4383
- this.scrollLeft -= baseDelta * multiplier;
6629
+ this.scrollAccumulatorX -= scrollAmount;
6630
+ const integerScroll = Math.trunc(this.scrollAccumulatorX);
6631
+ if (integerScroll !== 0) {
6632
+ this.scrollLeft += integerScroll;
6633
+ this.scrollAccumulatorX -= integerScroll;
6634
+ }
4384
6635
  } else if (dir === "right") {
4385
- this.scrollLeft += baseDelta * multiplier;
6636
+ this.scrollAccumulatorX += scrollAmount;
6637
+ const integerScroll = Math.trunc(this.scrollAccumulatorX);
6638
+ if (integerScroll !== 0) {
6639
+ this.scrollLeft += integerScroll;
6640
+ this.scrollAccumulatorX -= integerScroll;
6641
+ }
4386
6642
  }
4387
6643
  const maxScrollTop = Math.max(0, this.scrollHeight - this.viewport.height);
4388
6644
  const maxScrollLeft = Math.max(0, this.scrollWidth - this.viewport.width);
@@ -4400,15 +6656,21 @@ class ScrollBoxRenderable extends BoxRenderable {
4400
6656
  if (this.verticalScrollBar.handleKeyPress(key)) {
4401
6657
  this._hasManualScroll = true;
4402
6658
  this.scrollAccel.reset();
6659
+ this.resetScrollAccumulators();
4403
6660
  return true;
4404
6661
  }
4405
6662
  if (this.horizontalScrollBar.handleKeyPress(key)) {
4406
6663
  this._hasManualScroll = true;
4407
6664
  this.scrollAccel.reset();
6665
+ this.resetScrollAccumulators();
4408
6666
  return true;
4409
6667
  }
4410
6668
  return false;
4411
6669
  }
6670
+ resetScrollAccumulators() {
6671
+ this.scrollAccumulatorX = 0;
6672
+ this.scrollAccumulatorY = 0;
6673
+ }
4412
6674
  startAutoScroll(mouseX, mouseY) {
4413
6675
  this.stopAutoScroll();
4414
6676
  this.autoScrollMouseX = mouseX;
@@ -4715,7 +6977,6 @@ class SelectRenderable extends Renderable {
4715
6977
  }
4716
6978
  if (this._showDescription && itemY + this.fontHeight < contentY + contentHeight) {
4717
6979
  const descColor = isSelected ? this._selectedDescriptionColor : this._descriptionColor;
4718
- const descBg = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
4719
6980
  this.frameBuffer.drawText(option.description, descX, itemY + this.fontHeight, descColor);
4720
6981
  }
4721
6982
  }
@@ -4997,10 +7258,12 @@ class TabSelectRenderable extends Renderable {
4997
7258
  }
4998
7259
  }
4999
7260
  refreshFrameBuffer() {
5000
- if (!this.frameBuffer || this._options.length === 0)
7261
+ if (!this.frameBuffer)
5001
7262
  return;
5002
7263
  const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
5003
7264
  this.frameBuffer.clear(bgColor);
7265
+ if (this._options.length === 0)
7266
+ return;
5004
7267
  const contentX = 0;
5005
7268
  const contentY = 0;
5006
7269
  const contentWidth = this.width;
@@ -5235,101 +7498,6 @@ class TabSelectRenderable extends Renderable {
5235
7498
  this.requestRender();
5236
7499
  }
5237
7500
  }
5238
- // src/renderables/Text.ts
5239
- class TextRenderable extends TextBufferRenderable {
5240
- _text;
5241
- _hasManualStyledText = false;
5242
- rootTextNode;
5243
- _contentDefaultOptions = {
5244
- content: ""
5245
- };
5246
- constructor(ctx, options) {
5247
- super(ctx, options);
5248
- const content = options.content ?? this._contentDefaultOptions.content;
5249
- const styledText = typeof content === "string" ? stringToStyledText(content) : content;
5250
- this._text = styledText;
5251
- this._hasManualStyledText = options.content !== undefined && content !== "";
5252
- this.rootTextNode = new RootTextNodeRenderable(ctx, {
5253
- id: `${this.id}-root`,
5254
- fg: this._defaultFg,
5255
- bg: this._defaultBg,
5256
- attributes: this._defaultAttributes
5257
- }, this);
5258
- this.updateTextBuffer(styledText);
5259
- }
5260
- updateTextBuffer(styledText) {
5261
- this.textBuffer.setStyledText(styledText);
5262
- this.clearChunks(styledText);
5263
- }
5264
- clearChunks(styledText) {}
5265
- get content() {
5266
- return this._text;
5267
- }
5268
- get chunks() {
5269
- return this._text.chunks;
5270
- }
5271
- get textNode() {
5272
- return this.rootTextNode;
5273
- }
5274
- set content(value) {
5275
- this._hasManualStyledText = true;
5276
- const styledText = typeof value === "string" ? stringToStyledText(value) : value;
5277
- if (this._text !== styledText) {
5278
- this._text = styledText;
5279
- this.updateTextBuffer(styledText);
5280
- this.updateTextInfo();
5281
- }
5282
- }
5283
- updateTextFromNodes() {
5284
- if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
5285
- const chunks = this.rootTextNode.gatherWithInheritedStyle({
5286
- fg: this._defaultFg,
5287
- bg: this._defaultBg,
5288
- attributes: this._defaultAttributes
5289
- });
5290
- this.textBuffer.setStyledText(new StyledText(chunks));
5291
- this.refreshLocalSelection();
5292
- this.yogaNode.markDirty();
5293
- }
5294
- }
5295
- add(obj, index) {
5296
- return this.rootTextNode.add(obj, index);
5297
- }
5298
- remove(id) {
5299
- this.rootTextNode.remove(id);
5300
- }
5301
- insertBefore(obj, anchor) {
5302
- this.rootTextNode.insertBefore(obj, anchor);
5303
- return this.rootTextNode.children.indexOf(obj);
5304
- }
5305
- getTextChildren() {
5306
- return this.rootTextNode.getChildren();
5307
- }
5308
- clear() {
5309
- this.rootTextNode.clear();
5310
- const emptyStyledText = stringToStyledText("");
5311
- this._text = emptyStyledText;
5312
- this.updateTextBuffer(emptyStyledText);
5313
- this.updateTextInfo();
5314
- this.requestRender();
5315
- }
5316
- onLifecyclePass = () => {
5317
- this.updateTextFromNodes();
5318
- };
5319
- onFgChanged(newColor) {
5320
- this.rootTextNode.fg = newColor;
5321
- }
5322
- onBgChanged(newColor) {
5323
- this.rootTextNode.bg = newColor;
5324
- }
5325
- onAttributesChanged(newAttributes) {
5326
- this.rootTextNode.attributes = newAttributes;
5327
- }
5328
- destroy() {
5329
- this.rootTextNode.children.length = 0;
5330
- super.destroy();
5331
- }
5332
- }
5333
7501
  // src/renderables/EditBufferRenderable.ts
5334
7502
  class EditBufferRenderable extends Renderable {
5335
7503
  _focusable = true;
@@ -5347,6 +7515,7 @@ class EditBufferRenderable extends Renderable {
5347
7515
  lastLocalSelection = null;
5348
7516
  _tabIndicator;
5349
7517
  _tabIndicatorColor;
7518
+ _selectionAnchorState = null;
5350
7519
  _cursorChangeListener = undefined;
5351
7520
  _contentChangeListener = undefined;
5352
7521
  editBuffer;
@@ -5403,6 +7572,9 @@ class EditBufferRenderable extends Renderable {
5403
7572
  this.setupMeasureFunc();
5404
7573
  this.setupEventListeners(options);
5405
7574
  }
7575
+ get lineInfo() {
7576
+ return this.editorView.getLogicalLineInfo();
7577
+ }
5406
7578
  setupEventListeners(options) {
5407
7579
  this._cursorChangeListener = options.onCursorChange;
5408
7580
  this._contentChangeListener = options.onContentChange;
@@ -5418,11 +7590,21 @@ class EditBufferRenderable extends Renderable {
5418
7590
  this.editBuffer.on("content-changed", () => {
5419
7591
  this.yogaNode.markDirty();
5420
7592
  this.requestRender();
7593
+ this.emit("line-info-change");
5421
7594
  if (this._contentChangeListener) {
5422
7595
  this._contentChangeListener({});
5423
7596
  }
5424
7597
  });
5425
7598
  }
7599
+ get lineCount() {
7600
+ return this.editBuffer.getLineCount();
7601
+ }
7602
+ get virtualLineCount() {
7603
+ return this.editorView.getVirtualLineCount();
7604
+ }
7605
+ get scrollY() {
7606
+ return this.editorView.getViewport().offsetY;
7607
+ }
5426
7608
  get plainText() {
5427
7609
  return this.editBuffer.getText();
5428
7610
  }
@@ -5615,19 +7797,25 @@ class EditBufferRenderable extends Renderable {
5615
7797
  }
5616
7798
  setupMeasureFunc() {
5617
7799
  const measureFunc = (width, widthMode, height, heightMode) => {
5618
- const effectiveHeight = isNaN(height) ? 1 : height;
5619
- const effectiveWidth = isNaN(width) ? 1 : width;
5620
- if (this._wrapMode !== "none" && this.width !== effectiveWidth) {
5621
- this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
7800
+ let effectiveWidth;
7801
+ if (widthMode === MeasureMode.Undefined || isNaN(width)) {
7802
+ effectiveWidth = 0;
5622
7803
  } else {
5623
- this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
7804
+ effectiveWidth = width;
7805
+ }
7806
+ const effectiveHeight = isNaN(height) ? 1 : height;
7807
+ const measureResult = this.editorView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
7808
+ const measuredWidth = measureResult ? Math.max(1, measureResult.maxWidth) : 1;
7809
+ const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
7810
+ if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
7811
+ return {
7812
+ width: Math.min(effectiveWidth, measuredWidth),
7813
+ height: Math.min(effectiveHeight, measuredHeight)
7814
+ };
5624
7815
  }
5625
- const lineInfo = this.editorView.getLogicalLineInfo();
5626
- const measuredWidth = lineInfo.maxLineWidth;
5627
- const measuredHeight = lineInfo.lineStarts.length;
5628
7816
  return {
5629
- width: Math.max(1, measuredWidth),
5630
- height: Math.max(1, measuredHeight)
7817
+ width: measuredWidth,
7818
+ height: measuredHeight
5631
7819
  };
5632
7820
  };
5633
7821
  this.yogaNode.setMeasureFunc(measureFunc);
@@ -5672,12 +7860,15 @@ class EditBufferRenderable extends Renderable {
5672
7860
  }
5673
7861
  }
5674
7862
  destroy() {
7863
+ if (this.isDestroyed)
7864
+ return;
5675
7865
  if (this._focused) {
5676
7866
  this._ctx.setCursorPosition(0, 0, false);
7867
+ this.blur();
5677
7868
  }
5678
- super.destroy();
5679
7869
  this.editorView.destroy();
5680
7870
  this.editBuffer.destroy();
7871
+ super.destroy();
5681
7872
  }
5682
7873
  set onCursorChange(handler) {
5683
7874
  this._cursorChangeListener = handler;
@@ -5748,6 +7939,55 @@ class EditBufferRenderable extends Renderable {
5748
7939
  getTextRangeByCoords(startRow, startCol, endRow, endCol) {
5749
7940
  return this.editBuffer.getTextRangeByCoords(startRow, startCol, endRow, endCol);
5750
7941
  }
7942
+ updateSelectionForMovement(shiftPressed, isBeforeMovement) {
7943
+ if (!this.selectable)
7944
+ return;
7945
+ if (!shiftPressed) {
7946
+ this._ctx.clearSelection();
7947
+ this._selectionAnchorState = null;
7948
+ return;
7949
+ }
7950
+ const visualCursor = this.editorView.getVisualCursor();
7951
+ const viewport = this.editorView.getViewport();
7952
+ const cursorX = this.x + visualCursor.visualCol;
7953
+ const cursorY = this.y + visualCursor.visualRow;
7954
+ if (isBeforeMovement) {
7955
+ if (!this._ctx.hasSelection) {
7956
+ this._ctx.startSelection(this, cursorX, cursorY);
7957
+ this._selectionAnchorState = {
7958
+ screenX: cursorX,
7959
+ screenY: cursorY,
7960
+ viewportX: viewport.offsetX,
7961
+ viewportY: viewport.offsetY
7962
+ };
7963
+ } else if (!this._selectionAnchorState) {
7964
+ const selection = this._ctx.getSelection();
7965
+ if (selection && selection.isActive) {
7966
+ this._selectionAnchorState = {
7967
+ screenX: selection.anchor.x,
7968
+ screenY: selection.anchor.y,
7969
+ viewportX: viewport.offsetX,
7970
+ viewportY: viewport.offsetY
7971
+ };
7972
+ }
7973
+ }
7974
+ } else {
7975
+ if (this._selectionAnchorState) {
7976
+ const deltaY = viewport.offsetY - this._selectionAnchorState.viewportY;
7977
+ const deltaX = viewport.offsetX - this._selectionAnchorState.viewportX;
7978
+ if (deltaY !== 0 || deltaX !== 0) {
7979
+ const newAnchorX = this._selectionAnchorState.screenX - deltaX;
7980
+ const newAnchorY = this._selectionAnchorState.screenY - deltaY;
7981
+ this._ctx.startSelection(this, newAnchorX, newAnchorY);
7982
+ this._ctx.updateSelection(this, cursorX, cursorY);
7983
+ } else {
7984
+ this._ctx.updateSelection(this, cursorX, cursorY);
7985
+ }
7986
+ } else {
7987
+ this._ctx.updateSelection(this, cursorX, cursorY);
7988
+ }
7989
+ }
7990
+ }
5751
7991
  }
5752
7992
 
5753
7993
  // src/lib/keymapping.ts
@@ -5785,12 +8025,12 @@ var defaultTextareaKeybindings = [
5785
8025
  { name: "right", shift: true, action: "select-right" },
5786
8026
  { name: "up", shift: true, action: "select-up" },
5787
8027
  { name: "down", shift: true, action: "select-down" },
5788
- { name: "home", action: "line-home" },
5789
- { name: "end", action: "line-end" },
5790
- { name: "home", shift: true, action: "select-line-home" },
5791
- { name: "end", shift: true, action: "select-line-end" },
5792
- { name: "a", ctrl: true, action: "buffer-home" },
5793
- { name: "e", ctrl: true, action: "buffer-end" },
8028
+ { name: "home", action: "buffer-home" },
8029
+ { name: "end", action: "buffer-end" },
8030
+ { name: "home", shift: true, action: "select-buffer-home" },
8031
+ { name: "end", shift: true, action: "select-buffer-end" },
8032
+ { name: "a", ctrl: true, action: "line-home" },
8033
+ { name: "e", ctrl: true, action: "line-end" },
5794
8034
  { name: "f", ctrl: true, action: "move-right" },
5795
8035
  { name: "b", ctrl: true, action: "move-left" },
5796
8036
  { name: "d", ctrl: true, action: "delete-word-forward" },
@@ -5888,6 +8128,8 @@ class TextareaRenderable extends EditBufferRenderable {
5888
8128
  ["line-end", () => this.gotoLineEnd()],
5889
8129
  ["select-line-home", () => this.gotoLineHome({ select: true })],
5890
8130
  ["select-line-end", () => this.gotoLineEnd({ select: true })],
8131
+ ["select-buffer-home", () => this.gotoBufferHome({ select: true })],
8132
+ ["select-buffer-end", () => this.gotoBufferEnd({ select: true })],
5891
8133
  ["buffer-home", () => this.gotoBufferHome()],
5892
8134
  ["buffer-end", () => this.gotoBufferEnd()],
5893
8135
  ["delete-line", () => this.deleteLine()],
@@ -6004,33 +8246,33 @@ class TextareaRenderable extends EditBufferRenderable {
6004
8246
  }
6005
8247
  moveCursorLeft(options) {
6006
8248
  const select = options?.select ?? false;
6007
- this.handleShiftSelection(select, true);
8249
+ this.updateSelectionForMovement(select, true);
6008
8250
  this.editBuffer.moveCursorLeft();
6009
- this.handleShiftSelection(select, false);
8251
+ this.updateSelectionForMovement(select, false);
6010
8252
  this.requestRender();
6011
8253
  return true;
6012
8254
  }
6013
8255
  moveCursorRight(options) {
6014
8256
  const select = options?.select ?? false;
6015
- this.handleShiftSelection(select, true);
8257
+ this.updateSelectionForMovement(select, true);
6016
8258
  this.editBuffer.moveCursorRight();
6017
- this.handleShiftSelection(select, false);
8259
+ this.updateSelectionForMovement(select, false);
6018
8260
  this.requestRender();
6019
8261
  return true;
6020
8262
  }
6021
8263
  moveCursorUp(options) {
6022
8264
  const select = options?.select ?? false;
6023
- this.handleShiftSelection(select, true);
8265
+ this.updateSelectionForMovement(select, true);
6024
8266
  this.editorView.moveUpVisual();
6025
- this.handleShiftSelection(select, false);
8267
+ this.updateSelectionForMovement(select, false);
6026
8268
  this.requestRender();
6027
8269
  return true;
6028
8270
  }
6029
8271
  moveCursorDown(options) {
6030
8272
  const select = options?.select ?? false;
6031
- this.handleShiftSelection(select, true);
8273
+ this.updateSelectionForMovement(select, true);
6032
8274
  this.editorView.moveDownVisual();
6033
- this.handleShiftSelection(select, false);
8275
+ this.updateSelectionForMovement(select, false);
6034
8276
  this.requestRender();
6035
8277
  return true;
6036
8278
  }
@@ -6040,29 +8282,35 @@ class TextareaRenderable extends EditBufferRenderable {
6040
8282
  }
6041
8283
  gotoLineHome(options) {
6042
8284
  const select = options?.select ?? false;
6043
- this.handleShiftSelection(select, true);
8285
+ this.updateSelectionForMovement(select, true);
6044
8286
  const cursor = this.editorView.getCursor();
6045
8287
  this.editBuffer.setCursor(cursor.row, 0);
6046
- this.handleShiftSelection(select, false);
8288
+ this.updateSelectionForMovement(select, false);
6047
8289
  this.requestRender();
6048
8290
  return true;
6049
8291
  }
6050
8292
  gotoLineEnd(options) {
6051
8293
  const select = options?.select ?? false;
6052
- this.handleShiftSelection(select, true);
8294
+ this.updateSelectionForMovement(select, true);
6053
8295
  const eol = this.editBuffer.getEOL();
6054
8296
  this.editBuffer.setCursor(eol.row, eol.col);
6055
- this.handleShiftSelection(select, false);
8297
+ this.updateSelectionForMovement(select, false);
6056
8298
  this.requestRender();
6057
8299
  return true;
6058
8300
  }
6059
- gotoBufferHome() {
8301
+ gotoBufferHome(options) {
8302
+ const select = options?.select ?? false;
8303
+ this.updateSelectionForMovement(select, true);
6060
8304
  this.editBuffer.setCursor(0, 0);
8305
+ this.updateSelectionForMovement(select, false);
6061
8306
  this.requestRender();
6062
8307
  return true;
6063
8308
  }
6064
- gotoBufferEnd() {
8309
+ gotoBufferEnd(options) {
8310
+ const select = options?.select ?? false;
8311
+ this.updateSelectionForMovement(select, true);
6065
8312
  this.editBuffer.gotoLine(999999);
8313
+ this.updateSelectionForMovement(select, false);
6066
8314
  this.requestRender();
6067
8315
  return true;
6068
8316
  }
@@ -6097,19 +8345,19 @@ class TextareaRenderable extends EditBufferRenderable {
6097
8345
  }
6098
8346
  moveWordForward(options) {
6099
8347
  const select = options?.select ?? false;
6100
- this.handleShiftSelection(select, true);
8348
+ this.updateSelectionForMovement(select, true);
6101
8349
  const nextWord = this.editBuffer.getNextWordBoundary();
6102
8350
  this.editBuffer.setCursorByOffset(nextWord.offset);
6103
- this.handleShiftSelection(select, false);
8351
+ this.updateSelectionForMovement(select, false);
6104
8352
  this.requestRender();
6105
8353
  return true;
6106
8354
  }
6107
8355
  moveWordBackward(options) {
6108
8356
  const select = options?.select ?? false;
6109
- this.handleShiftSelection(select, true);
8357
+ this.updateSelectionForMovement(select, true);
6110
8358
  const prevWord = this.editBuffer.getPrevWordBoundary();
6111
8359
  this.editBuffer.setCursorByOffset(prevWord.offset);
6112
- this.handleShiftSelection(select, false);
8360
+ this.updateSelectionForMovement(select, false);
6113
8361
  this.requestRender();
6114
8362
  return true;
6115
8363
  }
@@ -6141,32 +8389,15 @@ class TextareaRenderable extends EditBufferRenderable {
6141
8389
  this.requestRender();
6142
8390
  return true;
6143
8391
  }
6144
- handleShiftSelection(shiftPressed, isBeforeMovement) {
6145
- if (!this.selectable)
6146
- return;
6147
- if (!shiftPressed) {
6148
- this._ctx.clearSelection();
6149
- return;
6150
- }
6151
- const visualCursor = this.editorView.getVisualCursor();
6152
- const viewport = this.editorView.getViewport();
6153
- const cursorX = this.x + visualCursor.visualCol;
6154
- const cursorY = this.y + (visualCursor.visualRow - viewport.offsetY);
6155
- if (isBeforeMovement) {
6156
- if (!this._ctx.hasSelection) {
6157
- this._ctx.startSelection(this, cursorX, cursorY);
6158
- }
6159
- } else {
6160
- this._ctx.updateSelection(this, cursorX, cursorY);
6161
- }
6162
- }
6163
8392
  focus() {
6164
8393
  super.focus();
6165
8394
  this.updateColors();
6166
8395
  }
6167
8396
  blur() {
6168
8397
  super.blur();
6169
- this.updateColors();
8398
+ if (!this.isDestroyed) {
8399
+ this.updateColors();
8400
+ }
6170
8401
  }
6171
8402
  get placeholder() {
6172
8403
  return this._placeholder;
@@ -6347,7 +8578,7 @@ export {
6347
8578
  applyChromaticAberration,
6348
8579
  applyAsciiArt,
6349
8580
  addDefaultParsers,
6350
- exports_src as Yoga,
8581
+ exports_dist as Yoga,
6351
8582
  VignetteEffect,
6352
8583
  VRenderable,
6353
8584
  TreeSitterClient,
@@ -6389,6 +8620,7 @@ export {
6389
8620
  MacOSScrollAccel,
6390
8621
  LogLevel,
6391
8622
  LinearScrollAccel,
8623
+ LineNumberRenderable,
6392
8624
  LayoutEvents,
6393
8625
  KeyHandler,
6394
8626
  KeyEvent,
@@ -6403,6 +8635,7 @@ export {
6403
8635
  EditorView,
6404
8636
  EditBuffer,
6405
8637
  DistortionEffect,
8638
+ DiffRenderable,
6406
8639
  DebugOverlayCorner,
6407
8640
  DataPathsManager,
6408
8641
  ConsolePosition,
@@ -6423,5 +8656,5 @@ export {
6423
8656
  ASCIIFont
6424
8657
  };
6425
8658
 
6426
- //# debugId=B9B7175D268B0B9C64756E2164756E21
8659
+ //# debugId=77A659B0F45EAC2C64756E2164756E21
6427
8660
  //# sourceMappingURL=index.js.map