@opentui/core 0.1.50 → 0.1.52

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -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,
@@ -136,7 +137,7 @@ import {
136
137
  white,
137
138
  wrapWithDelegates,
138
139
  yellow
139
- } from "./index-ztfy2qy3.js";
140
+ } from "./index-vhxgbbed.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,10 @@ 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
+ }
237
246
  destroy() {
238
247
  if (this._destroyed)
239
248
  return;
@@ -319,6 +328,10 @@ class EditBuffer extends EventEmitter {
319
328
  const textBytes = this.lib.encoder.encode(text);
320
329
  this.lib.editBufferSetText(this.bufferPtr, textBytes, history);
321
330
  }
331
+ getLineCount() {
332
+ this.guard();
333
+ return this.lib.textBufferGetLineCount(this.textBufferPtr);
334
+ }
322
335
  getText() {
323
336
  this.guard();
324
337
  const maxSize = 1024 * 1024;
@@ -551,6 +564,7 @@ class EditorView {
551
564
  editBuffer;
552
565
  _destroyed = false;
553
566
  _extmarksController;
567
+ _textBufferViewPtr;
554
568
  constructor(lib, ptr, editBuffer) {
555
569
  this.lib = lib;
556
570
  this.viewPtr = ptr;
@@ -696,6 +710,13 @@ class EditorView {
696
710
  this.guard();
697
711
  this.lib.editorViewSetTabIndicatorColor(this.viewPtr, color);
698
712
  }
713
+ measureForDimensions(width, height) {
714
+ this.guard();
715
+ if (!this._textBufferViewPtr) {
716
+ this._textBufferViewPtr = this.lib.editorViewGetTextBufferView(this.viewPtr);
717
+ }
718
+ return this.lib.textBufferViewMeasureForDimensions(this._textBufferViewPtr, width, height);
719
+ }
699
720
  destroy() {
700
721
  if (this._destroyed)
701
722
  return;
@@ -2403,9 +2424,10 @@ class TextBufferRenderable extends Renderable {
2403
2424
  lastLocalSelection = null;
2404
2425
  _tabIndicator;
2405
2426
  _tabIndicatorColor;
2427
+ _scrollX = 0;
2428
+ _scrollY = 0;
2406
2429
  textBuffer;
2407
2430
  textBufferView;
2408
- _lineInfo = { lineStarts: [], lineWidths: [], maxLineWidth: 0 };
2409
2431
  _defaultOptions = {
2410
2432
  fg: RGBA.fromValues(1, 1, 1, 1),
2411
2433
  bg: RGBA.fromValues(0, 0, 0, 0),
@@ -2444,10 +2466,82 @@ class TextBufferRenderable extends Renderable {
2444
2466
  this.textBufferView.setTabIndicatorColor(this._tabIndicatorColor);
2445
2467
  }
2446
2468
  if (this._wrapMode !== "none" && this.width > 0) {
2447
- this.updateWrapWidth(this.width);
2469
+ this.textBufferView.setWrapWidth(this.width);
2470
+ }
2471
+ if (this.width > 0 && this.height > 0) {
2472
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
2448
2473
  }
2449
2474
  this.updateTextInfo();
2450
2475
  }
2476
+ onMouseEvent(event) {
2477
+ if (event.type === "scroll") {
2478
+ this.handleScroll(event);
2479
+ }
2480
+ }
2481
+ handleScroll(event) {
2482
+ if (!event.scroll)
2483
+ return;
2484
+ const { direction, delta } = event.scroll;
2485
+ if (direction === "up") {
2486
+ this.scrollY -= delta;
2487
+ } else if (direction === "down") {
2488
+ this.scrollY += delta;
2489
+ }
2490
+ if (this._wrapMode === "none") {
2491
+ if (direction === "left") {
2492
+ this.scrollX -= delta;
2493
+ } else if (direction === "right") {
2494
+ this.scrollX += delta;
2495
+ }
2496
+ }
2497
+ }
2498
+ get lineInfo() {
2499
+ return this.textBufferView.logicalLineInfo;
2500
+ }
2501
+ get lineCount() {
2502
+ return this.textBuffer.getLineCount();
2503
+ }
2504
+ get scrollY() {
2505
+ return this._scrollY;
2506
+ }
2507
+ set scrollY(value) {
2508
+ const maxScrollY = Math.max(0, this.scrollHeight - this.height);
2509
+ const clamped = Math.max(0, Math.min(value, maxScrollY));
2510
+ if (this._scrollY !== clamped) {
2511
+ this._scrollY = clamped;
2512
+ this.updateViewportOffset();
2513
+ this.requestRender();
2514
+ }
2515
+ }
2516
+ get scrollX() {
2517
+ return this._scrollX;
2518
+ }
2519
+ set scrollX(value) {
2520
+ const maxScrollX = Math.max(0, this.scrollWidth - this.width);
2521
+ const clamped = Math.max(0, Math.min(value, maxScrollX));
2522
+ if (this._scrollX !== clamped) {
2523
+ this._scrollX = clamped;
2524
+ this.updateViewportOffset();
2525
+ this.requestRender();
2526
+ }
2527
+ }
2528
+ get scrollWidth() {
2529
+ return this.lineInfo.maxLineWidth;
2530
+ }
2531
+ get scrollHeight() {
2532
+ return this.lineInfo.lineStarts.length;
2533
+ }
2534
+ get maxScrollY() {
2535
+ return Math.max(0, this.scrollHeight - this.height);
2536
+ }
2537
+ get maxScrollX() {
2538
+ return Math.max(0, this.scrollWidth - this.width);
2539
+ }
2540
+ updateViewportOffset() {
2541
+ if (this.width > 0 && this.height > 0) {
2542
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, this.width, this.height);
2543
+ }
2544
+ }
2451
2545
  get plainText() {
2452
2546
  return this.textBuffer.getPlainText();
2453
2547
  }
@@ -2523,7 +2617,7 @@ class TextBufferRenderable extends Renderable {
2523
2617
  this._wrapMode = value;
2524
2618
  this.textBufferView.setWrapMode(this._wrapMode);
2525
2619
  if (value !== "none" && this.width > 0) {
2526
- this.updateWrapWidth(this.width);
2620
+ this.textBufferView.setWrapWidth(this.width);
2527
2621
  }
2528
2622
  this.yogaNode.markDirty();
2529
2623
  this.requestRender();
@@ -2555,7 +2649,7 @@ class TextBufferRenderable extends Renderable {
2555
2649
  }
2556
2650
  }
2557
2651
  onResize(width, height) {
2558
- this.textBufferView.setViewportSize(width, height);
2652
+ this.textBufferView.setViewport(this._scrollX, this._scrollY, width, height);
2559
2653
  if (this.lastLocalSelection) {
2560
2654
  const changed = this.updateLocalSelection(this.lastLocalSelection);
2561
2655
  if (changed) {
@@ -2582,30 +2676,29 @@ class TextBufferRenderable extends Renderable {
2582
2676
  }
2583
2677
  this.yogaNode.markDirty();
2584
2678
  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();
2679
+ this.emit("line-info-change");
2595
2680
  }
2596
2681
  setupMeasureFunc() {
2597
2682
  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);
2683
+ let effectiveWidth;
2684
+ if (widthMode === MeasureMode.Undefined || isNaN(width)) {
2685
+ effectiveWidth = 0;
2601
2686
  } else {
2602
- this.updateLineInfo();
2687
+ effectiveWidth = width;
2688
+ }
2689
+ const effectiveHeight = isNaN(height) ? 1 : height;
2690
+ const measureResult = this.textBufferView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
2691
+ const measuredWidth = measureResult ? Math.max(1, measureResult.maxWidth) : 1;
2692
+ const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
2693
+ if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
2694
+ return {
2695
+ width: Math.min(effectiveWidth, measuredWidth),
2696
+ height: Math.min(effectiveHeight, measuredHeight)
2697
+ };
2603
2698
  }
2604
- const measuredWidth = this._lineInfo.maxLineWidth;
2605
- const measuredHeight = this._lineInfo.lineStarts.length;
2606
2699
  return {
2607
- width: Math.max(1, measuredWidth),
2608
- height: Math.max(1, measuredHeight)
2700
+ width: measuredWidth,
2701
+ height: measuredHeight
2609
2702
  };
2610
2703
  };
2611
2704
  this.yogaNode.setMeasureFunc(measureFunc);
@@ -2690,6 +2783,10 @@ class CodeRenderable extends TextBufferRenderable {
2690
2783
  this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
2691
2784
  this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
2692
2785
  this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
2786
+ if (this._content.length > 0 && (this._drawUnstyledText || !this._filetype)) {
2787
+ this.textBuffer.setText(this._content);
2788
+ this.updateTextInfo();
2789
+ }
2693
2790
  this._highlightsDirty = this._content.length > 0;
2694
2791
  }
2695
2792
  get content() {
@@ -2699,6 +2796,10 @@ class CodeRenderable extends TextBufferRenderable {
2699
2796
  if (this._content !== value) {
2700
2797
  this._content = value;
2701
2798
  this._highlightsDirty = true;
2799
+ if (this._drawUnstyledText || !this._filetype) {
2800
+ this.textBuffer.setText(value);
2801
+ this.updateTextInfo();
2802
+ }
2702
2803
  }
2703
2804
  }
2704
2805
  get filetype() {
@@ -3180,170 +3281,2273 @@ class VRenderable extends Renderable {
3180
3281
  }
3181
3282
  }
3182
3283
  }
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;
3284
+ // src/renderables/LineNumberRenderable.ts
3285
+ class GutterRenderable extends Renderable {
3286
+ target;
3287
+ _fg;
3288
+ _bg;
3289
+ _minWidth;
3290
+ _paddingRight;
3291
+ _lineColorsGutter;
3292
+ _lineColorsContent;
3293
+ _lineSigns;
3294
+ _lineNumberOffset;
3295
+ _hideLineNumbers;
3296
+ _lineNumbers;
3297
+ _maxBeforeWidth = 0;
3298
+ _maxAfterWidth = 0;
3299
+ _lastKnownLineCount = 0;
3300
+ _lastKnownScrollY = 0;
3301
+ constructor(ctx, target, options) {
3302
+ super(ctx, {
3303
+ id: options.id,
3304
+ width: "auto",
3305
+ height: "auto",
3306
+ flexGrow: 0,
3307
+ flexShrink: 0,
3308
+ buffered: options.buffered
3309
+ });
3310
+ this.target = target;
3311
+ this._fg = options.fg;
3312
+ this._bg = options.bg;
3313
+ this._minWidth = options.minWidth;
3314
+ this._paddingRight = options.paddingRight;
3315
+ this._lineColorsGutter = options.lineColorsGutter;
3316
+ this._lineColorsContent = options.lineColorsContent;
3317
+ this._lineSigns = options.lineSigns;
3318
+ this._lineNumberOffset = options.lineNumberOffset;
3319
+ this._hideLineNumbers = options.hideLineNumbers;
3320
+ this._lineNumbers = options.lineNumbers ?? new Map;
3321
+ this._lastKnownLineCount = this.target.lineCount;
3322
+ this._lastKnownScrollY = this.target.scrollY;
3323
+ this.calculateSignWidths();
3324
+ this.setupMeasureFunc();
3325
+ this.onLifecyclePass = () => {
3326
+ const currentLineCount = this.target.lineCount;
3327
+ if (currentLineCount !== this._lastKnownLineCount) {
3328
+ this._lastKnownLineCount = currentLineCount;
3329
+ this.yogaNode.markDirty();
3330
+ this.requestRender();
3331
+ }
3332
+ };
3234
3333
  }
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;
3334
+ setupMeasureFunc() {
3335
+ const measureFunc = (width, widthMode, height, heightMode) => {
3336
+ const gutterWidth = this.calculateWidth();
3337
+ const gutterHeight = this.target.lineCount;
3338
+ return {
3339
+ width: gutterWidth,
3340
+ height: gutterHeight
3341
+ };
3342
+ };
3343
+ this.yogaNode.setMeasureFunc(measureFunc);
3344
+ }
3345
+ remeasure() {
3346
+ this.yogaNode.markDirty();
3347
+ }
3348
+ calculateSignWidths() {
3349
+ this._maxBeforeWidth = 0;
3350
+ this._maxAfterWidth = 0;
3351
+ for (const sign of this._lineSigns.values()) {
3352
+ if (sign.before) {
3353
+ const width = Bun.stringWidth(sign.before);
3354
+ this._maxBeforeWidth = Math.max(this._maxBeforeWidth, width);
3355
+ }
3356
+ if (sign.after) {
3357
+ const width = Bun.stringWidth(sign.after);
3358
+ this._maxAfterWidth = Math.max(this._maxAfterWidth, width);
3359
+ }
3245
3360
  }
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);
3361
+ }
3362
+ calculateWidth() {
3363
+ const totalLines = this.target.lineCount;
3364
+ let maxLineNumber = totalLines + this._lineNumberOffset;
3365
+ if (this._lineNumbers.size > 0) {
3366
+ for (const customLineNum of this._lineNumbers.values()) {
3367
+ maxLineNumber = Math.max(maxLineNumber, customLineNum);
3368
+ }
3252
3369
  }
3370
+ const digits = maxLineNumber > 0 ? Math.floor(Math.log10(maxLineNumber)) + 1 : 1;
3371
+ const baseWidth = Math.max(this._minWidth, digits + this._paddingRight + 1);
3372
+ return baseWidth + this._maxBeforeWidth + this._maxAfterWidth;
3253
3373
  }
3254
- focus() {
3255
- super.focus();
3256
- this._ctx.setCursorStyle(this._cursorStyle.style, this._cursorStyle.blinking);
3257
- this._ctx.setCursorColor(this._cursorColor);
3258
- this.updateCursorPosition();
3374
+ setLineColors(lineColorsGutter, lineColorsContent) {
3375
+ this._lineColorsGutter = lineColorsGutter;
3376
+ this._lineColorsContent = lineColorsContent;
3377
+ this.requestRender();
3259
3378
  }
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);
3379
+ getLineColors() {
3380
+ return {
3381
+ gutter: this._lineColorsGutter,
3382
+ content: this._lineColorsContent
3383
+ };
3384
+ }
3385
+ setLineSigns(lineSigns) {
3386
+ const oldMaxBefore = this._maxBeforeWidth;
3387
+ const oldMaxAfter = this._maxAfterWidth;
3388
+ this._lineSigns = lineSigns;
3389
+ this.calculateSignWidths();
3390
+ if (this._maxBeforeWidth !== oldMaxBefore || this._maxAfterWidth !== oldMaxAfter) {
3391
+ this.yogaNode.markDirty();
3266
3392
  }
3393
+ this.requestRender();
3267
3394
  }
3268
- renderSelf(buffer, deltaTime) {
3269
- if (!this.visible || !this.frameBuffer)
3395
+ getLineSigns() {
3396
+ return this._lineSigns;
3397
+ }
3398
+ renderSelf(buffer) {
3399
+ const currentScrollY = this.target.scrollY;
3400
+ const scrollChanged = currentScrollY !== this._lastKnownScrollY;
3401
+ if (this.buffered && !this.isDirty && !scrollChanged) {
3270
3402
  return;
3271
- if (this.isDirty) {
3272
- this.refreshFrameBuffer();
3273
3403
  }
3404
+ this._lastKnownScrollY = currentScrollY;
3405
+ this.refreshFrameBuffer(buffer);
3274
3406
  }
3275
- refreshFrameBuffer() {
3276
- if (!this.frameBuffer)
3407
+ refreshFrameBuffer(buffer) {
3408
+ const startX = this.buffered ? 0 : this.x;
3409
+ const startY = this.buffered ? 0 : this.y;
3410
+ if (this.buffered) {
3411
+ buffer.clear(this._bg);
3412
+ } else if (this._bg.a > 0) {
3413
+ buffer.fillRect(startX, startY, this.width, this.height, this._bg);
3414
+ }
3415
+ const lineInfo = this.target.lineInfo;
3416
+ if (!lineInfo || !lineInfo.lineSources)
3277
3417
  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;
3418
+ const sources = lineInfo.lineSources;
3419
+ let lastSource = -1;
3420
+ const startLine = this.target.scrollY;
3421
+ if (startLine >= sources.length)
3422
+ return;
3423
+ lastSource = startLine > 0 ? sources[startLine - 1] : -1;
3424
+ for (let i = 0;i < this.height; i++) {
3425
+ const visualLineIndex = startLine + i;
3426
+ if (visualLineIndex >= sources.length)
3427
+ break;
3428
+ const logicalLine = sources[visualLineIndex];
3429
+ const lineBg = this._lineColorsGutter.get(logicalLine) ?? this._bg;
3430
+ if (lineBg !== this._bg) {
3431
+ buffer.fillRect(startX, startY + i, this.width, 1, lineBg);
3432
+ }
3433
+ if (logicalLine === lastSource) {} else {
3434
+ let currentX = startX;
3435
+ const sign = this._lineSigns.get(logicalLine);
3436
+ if (sign?.before) {
3437
+ const beforeWidth = Bun.stringWidth(sign.before);
3438
+ const padding = this._maxBeforeWidth - beforeWidth;
3439
+ currentX += padding;
3440
+ const beforeColor = sign.beforeColor ? parseColor(sign.beforeColor) : this._fg;
3441
+ buffer.drawText(sign.before, currentX, startY + i, beforeColor, lineBg);
3442
+ currentX += beforeWidth;
3443
+ } else if (this._maxBeforeWidth > 0) {
3444
+ currentX += this._maxBeforeWidth;
3445
+ }
3446
+ if (!this._hideLineNumbers.has(logicalLine)) {
3447
+ const customLineNum = this._lineNumbers.get(logicalLine);
3448
+ const lineNum = customLineNum !== undefined ? customLineNum : logicalLine + 1 + this._lineNumberOffset;
3449
+ const lineNumStr = lineNum.toString();
3450
+ const lineNumWidth = lineNumStr.length;
3451
+ const availableSpace = this.width - this._maxBeforeWidth - this._maxAfterWidth - this._paddingRight;
3452
+ const lineNumX = startX + this._maxBeforeWidth + 1 + availableSpace - lineNumWidth - 1;
3453
+ if (lineNumX >= startX + this._maxBeforeWidth + 1) {
3454
+ buffer.drawText(lineNumStr, lineNumX, startY + i, this._fg, lineBg);
3455
+ }
3456
+ }
3457
+ if (sign?.after) {
3458
+ const afterX = startX + this.width - this._paddingRight - this._maxAfterWidth;
3459
+ const afterColor = sign.afterColor ? parseColor(sign.afterColor) : this._fg;
3460
+ buffer.drawText(sign.after, afterX, startY + i, afterColor, lineBg);
3461
+ }
3462
+ }
3463
+ lastSource = logicalLine;
3292
3464
  }
3293
- const visibleText = displayText.substring(displayStartIndex, displayStartIndex + maxVisibleChars);
3294
- if (visibleText) {
3295
- this.frameBuffer.drawText(visibleText, contentX, contentY, textColor);
3465
+ }
3466
+ }
3467
+ function darkenColor(color) {
3468
+ return RGBA.fromValues(color.r * 0.8, color.g * 0.8, color.b * 0.8, color.a);
3469
+ }
3470
+
3471
+ class LineNumberRenderable extends Renderable {
3472
+ gutter = null;
3473
+ target = null;
3474
+ _lineColorsGutter;
3475
+ _lineColorsContent;
3476
+ _lineSigns;
3477
+ _fg;
3478
+ _bg;
3479
+ _minWidth;
3480
+ _paddingRight;
3481
+ _lineNumberOffset;
3482
+ _hideLineNumbers;
3483
+ _lineNumbers;
3484
+ _isDestroying = false;
3485
+ handleLineInfoChange = () => {
3486
+ this.gutter?.remeasure();
3487
+ this.requestRender();
3488
+ };
3489
+ parseLineColor(line, color) {
3490
+ if (typeof color === "object" && "gutter" in color) {
3491
+ const config = color;
3492
+ if (config.gutter) {
3493
+ this._lineColorsGutter.set(line, parseColor(config.gutter));
3494
+ }
3495
+ if (config.content) {
3496
+ this._lineColorsContent.set(line, parseColor(config.content));
3497
+ } else if (config.gutter) {
3498
+ this._lineColorsContent.set(line, darkenColor(parseColor(config.gutter)));
3499
+ }
3500
+ } else {
3501
+ const parsedColor = parseColor(color);
3502
+ this._lineColorsGutter.set(line, parsedColor);
3503
+ this._lineColorsContent.set(line, darkenColor(parsedColor));
3296
3504
  }
3297
- if (this._focused) {
3298
- this.updateCursorPosition();
3505
+ }
3506
+ constructor(ctx, options) {
3507
+ super(ctx, {
3508
+ ...options,
3509
+ flexDirection: "row",
3510
+ height: "auto"
3511
+ });
3512
+ this._fg = parseColor(options.fg ?? "#888888");
3513
+ this._bg = parseColor(options.bg ?? "transparent");
3514
+ this._minWidth = options.minWidth ?? 3;
3515
+ this._paddingRight = options.paddingRight ?? 1;
3516
+ this._lineNumberOffset = options.lineNumberOffset ?? 0;
3517
+ this._hideLineNumbers = options.hideLineNumbers ?? new Set;
3518
+ this._lineNumbers = options.lineNumbers ?? new Map;
3519
+ this._lineColorsGutter = new Map;
3520
+ this._lineColorsContent = new Map;
3521
+ if (options.lineColors) {
3522
+ for (const [line, color] of options.lineColors) {
3523
+ this.parseLineColor(line, color);
3524
+ }
3525
+ }
3526
+ this._lineSigns = new Map;
3527
+ if (options.lineSigns) {
3528
+ for (const [line, sign] of options.lineSigns) {
3529
+ this._lineSigns.set(line, sign);
3530
+ }
3531
+ }
3532
+ if (options.target) {
3533
+ this.setTarget(options.target);
3299
3534
  }
3300
3535
  }
3301
- get value() {
3302
- return this._value;
3536
+ setTarget(target) {
3537
+ if (this.target === target)
3538
+ return;
3539
+ if (this.target) {
3540
+ this.target.off("line-info-change", this.handleLineInfoChange);
3541
+ super.remove(this.target.id);
3542
+ }
3543
+ if (this.gutter) {
3544
+ super.remove(this.gutter.id);
3545
+ this.gutter = null;
3546
+ }
3547
+ this.target = target;
3548
+ this.target.on("line-info-change", this.handleLineInfoChange);
3549
+ this.gutter = new GutterRenderable(this.ctx, this.target, {
3550
+ fg: this._fg,
3551
+ bg: this._bg,
3552
+ minWidth: this._minWidth,
3553
+ paddingRight: this._paddingRight,
3554
+ lineColorsGutter: this._lineColorsGutter,
3555
+ lineColorsContent: this._lineColorsContent,
3556
+ lineSigns: this._lineSigns,
3557
+ lineNumberOffset: this._lineNumberOffset,
3558
+ hideLineNumbers: this._hideLineNumbers,
3559
+ lineNumbers: this._lineNumbers,
3560
+ id: this.id ? `${this.id}-gutter` : undefined,
3561
+ buffered: true
3562
+ });
3563
+ super.add(this.gutter);
3564
+ super.add(this.target);
3303
3565
  }
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);
3566
+ add(child) {
3567
+ if (!this.target && "lineInfo" in child && "lineCount" in child && "scrollY" in child) {
3568
+ this.setTarget(child);
3569
+ return this.getChildrenCount() - 1;
3312
3570
  }
3571
+ return -1;
3313
3572
  }
3314
- set placeholder(placeholder) {
3315
- if (this._placeholder !== placeholder) {
3316
- this._placeholder = placeholder;
3317
- this.requestRender();
3573
+ remove(id) {
3574
+ if (this._isDestroying) {
3575
+ super.remove(id);
3576
+ return;
3577
+ }
3578
+ if (this.gutter && id === this.gutter.id) {
3579
+ throw new Error("LineNumberRenderable: Cannot remove gutter directly.");
3580
+ }
3581
+ if (this.target && id === this.target.id) {
3582
+ throw new Error("LineNumberRenderable: Cannot remove target directly. Use clearTarget() instead.");
3318
3583
  }
3584
+ super.remove(id);
3319
3585
  }
3320
- get cursorPosition() {
3321
- return this._cursorPosition;
3586
+ destroyRecursively() {
3587
+ this._isDestroying = true;
3588
+ if (this.target) {
3589
+ this.target.off("line-info-change", this.handleLineInfoChange);
3590
+ }
3591
+ super.destroyRecursively();
3592
+ this.gutter = null;
3593
+ this.target = null;
3322
3594
  }
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();
3595
+ clearTarget() {
3596
+ if (this.target) {
3597
+ this.target.off("line-info-change", this.handleLineInfoChange);
3598
+ super.remove(this.target.id);
3599
+ this.target = null;
3600
+ }
3601
+ if (this.gutter) {
3602
+ super.remove(this.gutter.id);
3603
+ this.gutter = null;
3329
3604
  }
3330
3605
  }
3331
- insertText(text) {
3332
- if (this._value.length + text.length > this._maxLength) {
3606
+ renderSelf(buffer) {
3607
+ if (!this.target || !this.gutter)
3608
+ return;
3609
+ const lineInfo = this.target.lineInfo;
3610
+ if (!lineInfo || !lineInfo.lineSources)
3333
3611
  return;
3612
+ const sources = lineInfo.lineSources;
3613
+ const startLine = this.target.scrollY;
3614
+ if (startLine >= sources.length)
3615
+ return;
3616
+ const gutterWidth = this.gutter.visible ? this.gutter.width : 0;
3617
+ const contentWidth = this.width - gutterWidth;
3618
+ for (let i = 0;i < this.height; i++) {
3619
+ const visualLineIndex = startLine + i;
3620
+ if (visualLineIndex >= sources.length)
3621
+ break;
3622
+ const logicalLine = sources[visualLineIndex];
3623
+ const lineBg = this._lineColorsContent.get(logicalLine);
3624
+ if (lineBg) {
3625
+ buffer.fillRect(this.x + gutterWidth, this.y + i, contentWidth, 1, lineBg);
3626
+ }
3334
3627
  }
3335
- const beforeCursor = this._value.substring(0, this._cursorPosition);
3336
- const afterCursor = this._value.substring(this._cursorPosition);
3337
- this._value = beforeCursor + text + afterCursor;
3338
- this._cursorPosition += text.length;
3339
- this.requestRender();
3340
- this.updateCursorPosition();
3341
- this.emit("input" /* INPUT */, this._value);
3342
3628
  }
3343
- deleteCharacter(direction) {
3344
- if (direction === "backward" && this._cursorPosition > 0) {
3345
- const beforeCursor = this._value.substring(0, this._cursorPosition - 1);
3346
- const afterCursor = this._value.substring(this._cursorPosition);
3629
+ set showLineNumbers(value) {
3630
+ if (this.gutter) {
3631
+ this.gutter.visible = value;
3632
+ }
3633
+ }
3634
+ get showLineNumbers() {
3635
+ return this.gutter?.visible ?? false;
3636
+ }
3637
+ setLineColor(line, color) {
3638
+ this.parseLineColor(line, color);
3639
+ if (this.gutter) {
3640
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3641
+ }
3642
+ }
3643
+ clearLineColor(line) {
3644
+ this._lineColorsGutter.delete(line);
3645
+ this._lineColorsContent.delete(line);
3646
+ if (this.gutter) {
3647
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3648
+ }
3649
+ }
3650
+ clearAllLineColors() {
3651
+ this._lineColorsGutter.clear();
3652
+ this._lineColorsContent.clear();
3653
+ if (this.gutter) {
3654
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3655
+ }
3656
+ }
3657
+ setLineColors(lineColors) {
3658
+ this._lineColorsGutter.clear();
3659
+ this._lineColorsContent.clear();
3660
+ for (const [line, color] of lineColors) {
3661
+ this.parseLineColor(line, color);
3662
+ }
3663
+ if (this.gutter) {
3664
+ this.gutter.setLineColors(this._lineColorsGutter, this._lineColorsContent);
3665
+ }
3666
+ }
3667
+ getLineColors() {
3668
+ return {
3669
+ gutter: this._lineColorsGutter,
3670
+ content: this._lineColorsContent
3671
+ };
3672
+ }
3673
+ setLineSign(line, sign) {
3674
+ this._lineSigns.set(line, sign);
3675
+ if (this.gutter) {
3676
+ this.gutter.setLineSigns(this._lineSigns);
3677
+ }
3678
+ }
3679
+ clearLineSign(line) {
3680
+ this._lineSigns.delete(line);
3681
+ if (this.gutter) {
3682
+ this.gutter.setLineSigns(this._lineSigns);
3683
+ }
3684
+ }
3685
+ clearAllLineSigns() {
3686
+ this._lineSigns.clear();
3687
+ if (this.gutter) {
3688
+ this.gutter.setLineSigns(this._lineSigns);
3689
+ }
3690
+ }
3691
+ setLineSigns(lineSigns) {
3692
+ this._lineSigns.clear();
3693
+ for (const [line, sign] of lineSigns) {
3694
+ this._lineSigns.set(line, sign);
3695
+ }
3696
+ if (this.gutter) {
3697
+ this.gutter.setLineSigns(this._lineSigns);
3698
+ }
3699
+ }
3700
+ getLineSigns() {
3701
+ return this._lineSigns;
3702
+ }
3703
+ set lineNumberOffset(value) {
3704
+ if (this._lineNumberOffset !== value) {
3705
+ this._lineNumberOffset = value;
3706
+ if (this.gutter && this.target) {
3707
+ const target = this.target;
3708
+ super.remove(this.gutter.id);
3709
+ super.remove(this.target.id);
3710
+ this.gutter = null;
3711
+ this.target = null;
3712
+ this.setTarget(target);
3713
+ }
3714
+ }
3715
+ }
3716
+ get lineNumberOffset() {
3717
+ return this._lineNumberOffset;
3718
+ }
3719
+ setHideLineNumbers(hideLineNumbers) {
3720
+ this._hideLineNumbers = hideLineNumbers;
3721
+ if (this.gutter && this.target) {
3722
+ const target = this.target;
3723
+ super.remove(this.gutter.id);
3724
+ super.remove(this.target.id);
3725
+ this.gutter = null;
3726
+ this.target = null;
3727
+ this.setTarget(target);
3728
+ }
3729
+ }
3730
+ getHideLineNumbers() {
3731
+ return this._hideLineNumbers;
3732
+ }
3733
+ setLineNumbers(lineNumbers) {
3734
+ this._lineNumbers = lineNumbers;
3735
+ if (this.gutter && this.target) {
3736
+ const target = this.target;
3737
+ super.remove(this.gutter.id);
3738
+ super.remove(this.target.id);
3739
+ this.gutter = null;
3740
+ this.target = null;
3741
+ this.setTarget(target);
3742
+ }
3743
+ }
3744
+ getLineNumbers() {
3745
+ return this._lineNumbers;
3746
+ }
3747
+ }
3748
+
3749
+ // ../../node_modules/diff/libesm/diff/base.js
3750
+ class Diff {
3751
+ diff(oldStr, newStr, options = {}) {
3752
+ let callback;
3753
+ if (typeof options === "function") {
3754
+ callback = options;
3755
+ options = {};
3756
+ } else if ("callback" in options) {
3757
+ callback = options.callback;
3758
+ }
3759
+ const oldString = this.castInput(oldStr, options);
3760
+ const newString = this.castInput(newStr, options);
3761
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
3762
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
3763
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
3764
+ }
3765
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
3766
+ var _a;
3767
+ const done = (value) => {
3768
+ value = this.postProcess(value, options);
3769
+ if (callback) {
3770
+ setTimeout(function() {
3771
+ callback(value);
3772
+ }, 0);
3773
+ return;
3774
+ } else {
3775
+ return value;
3776
+ }
3777
+ };
3778
+ const newLen = newTokens.length, oldLen = oldTokens.length;
3779
+ let editLength = 1;
3780
+ let maxEditLength = newLen + oldLen;
3781
+ if (options.maxEditLength != null) {
3782
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
3783
+ }
3784
+ const maxExecutionTime = (_a = options.timeout) !== null && _a !== undefined ? _a : Infinity;
3785
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
3786
+ const bestPath = [{ oldPos: -1, lastComponent: undefined }];
3787
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
3788
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3789
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
3790
+ }
3791
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
3792
+ const execEditLength = () => {
3793
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength);diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
3794
+ let basePath;
3795
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
3796
+ if (removePath) {
3797
+ bestPath[diagonalPath - 1] = undefined;
3798
+ }
3799
+ let canAdd = false;
3800
+ if (addPath) {
3801
+ const addPathNewPos = addPath.oldPos - diagonalPath;
3802
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
3803
+ }
3804
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
3805
+ if (!canAdd && !canRemove) {
3806
+ bestPath[diagonalPath] = undefined;
3807
+ continue;
3808
+ }
3809
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
3810
+ basePath = this.addToPath(addPath, true, false, 0, options);
3811
+ } else {
3812
+ basePath = this.addToPath(removePath, false, true, 1, options);
3813
+ }
3814
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
3815
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
3816
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
3817
+ } else {
3818
+ bestPath[diagonalPath] = basePath;
3819
+ if (basePath.oldPos + 1 >= oldLen) {
3820
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
3821
+ }
3822
+ if (newPos + 1 >= newLen) {
3823
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
3824
+ }
3825
+ }
3826
+ }
3827
+ editLength++;
3828
+ };
3829
+ if (callback) {
3830
+ (function exec() {
3831
+ setTimeout(function() {
3832
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
3833
+ return callback(undefined);
3834
+ }
3835
+ if (!execEditLength()) {
3836
+ exec();
3837
+ }
3838
+ }, 0);
3839
+ })();
3840
+ } else {
3841
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
3842
+ const ret = execEditLength();
3843
+ if (ret) {
3844
+ return ret;
3845
+ }
3846
+ }
3847
+ }
3848
+ }
3849
+ addToPath(path, added, removed, oldPosInc, options) {
3850
+ const last = path.lastComponent;
3851
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
3852
+ return {
3853
+ oldPos: path.oldPos + oldPosInc,
3854
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
3855
+ };
3856
+ } else {
3857
+ return {
3858
+ oldPos: path.oldPos + oldPosInc,
3859
+ lastComponent: { count: 1, added, removed, previousComponent: last }
3860
+ };
3861
+ }
3862
+ }
3863
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
3864
+ const newLen = newTokens.length, oldLen = oldTokens.length;
3865
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
3866
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
3867
+ newPos++;
3868
+ oldPos++;
3869
+ commonCount++;
3870
+ if (options.oneChangePerToken) {
3871
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
3872
+ }
3873
+ }
3874
+ if (commonCount && !options.oneChangePerToken) {
3875
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
3876
+ }
3877
+ basePath.oldPos = oldPos;
3878
+ return newPos;
3879
+ }
3880
+ equals(left, right, options) {
3881
+ if (options.comparator) {
3882
+ return options.comparator(left, right);
3883
+ } else {
3884
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
3885
+ }
3886
+ }
3887
+ removeEmpty(array) {
3888
+ const ret = [];
3889
+ for (let i = 0;i < array.length; i++) {
3890
+ if (array[i]) {
3891
+ ret.push(array[i]);
3892
+ }
3893
+ }
3894
+ return ret;
3895
+ }
3896
+ castInput(value, options) {
3897
+ return value;
3898
+ }
3899
+ tokenize(value, options) {
3900
+ return Array.from(value);
3901
+ }
3902
+ join(chars) {
3903
+ return chars.join("");
3904
+ }
3905
+ postProcess(changeObjects, options) {
3906
+ return changeObjects;
3907
+ }
3908
+ get useLongestToken() {
3909
+ return false;
3910
+ }
3911
+ buildValues(lastComponent, newTokens, oldTokens) {
3912
+ const components = [];
3913
+ let nextComponent;
3914
+ while (lastComponent) {
3915
+ components.push(lastComponent);
3916
+ nextComponent = lastComponent.previousComponent;
3917
+ delete lastComponent.previousComponent;
3918
+ lastComponent = nextComponent;
3919
+ }
3920
+ components.reverse();
3921
+ const componentLen = components.length;
3922
+ let componentPos = 0, newPos = 0, oldPos = 0;
3923
+ for (;componentPos < componentLen; componentPos++) {
3924
+ const component = components[componentPos];
3925
+ if (!component.removed) {
3926
+ if (!component.added && this.useLongestToken) {
3927
+ let value = newTokens.slice(newPos, newPos + component.count);
3928
+ value = value.map(function(value2, i) {
3929
+ const oldValue = oldTokens[oldPos + i];
3930
+ return oldValue.length > value2.length ? oldValue : value2;
3931
+ });
3932
+ component.value = this.join(value);
3933
+ } else {
3934
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
3935
+ }
3936
+ newPos += component.count;
3937
+ if (!component.added) {
3938
+ oldPos += component.count;
3939
+ }
3940
+ } else {
3941
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
3942
+ oldPos += component.count;
3943
+ }
3944
+ }
3945
+ return components;
3946
+ }
3947
+ }
3948
+
3949
+ // ../../node_modules/diff/libesm/diff/character.js
3950
+ class CharacterDiff extends Diff {
3951
+ }
3952
+ var characterDiff = new CharacterDiff;
3953
+
3954
+ // ../../node_modules/diff/libesm/util/string.js
3955
+ function longestCommonPrefix(str1, str2) {
3956
+ let i;
3957
+ for (i = 0;i < str1.length && i < str2.length; i++) {
3958
+ if (str1[i] != str2[i]) {
3959
+ return str1.slice(0, i);
3960
+ }
3961
+ }
3962
+ return str1.slice(0, i);
3963
+ }
3964
+ function longestCommonSuffix(str1, str2) {
3965
+ let i;
3966
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {
3967
+ return "";
3968
+ }
3969
+ for (i = 0;i < str1.length && i < str2.length; i++) {
3970
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {
3971
+ return str1.slice(-i);
3972
+ }
3973
+ }
3974
+ return str1.slice(-i);
3975
+ }
3976
+ function replacePrefix(string, oldPrefix, newPrefix) {
3977
+ if (string.slice(0, oldPrefix.length) != oldPrefix) {
3978
+ throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
3979
+ }
3980
+ return newPrefix + string.slice(oldPrefix.length);
3981
+ }
3982
+ function replaceSuffix(string, oldSuffix, newSuffix) {
3983
+ if (!oldSuffix) {
3984
+ return string + newSuffix;
3985
+ }
3986
+ if (string.slice(-oldSuffix.length) != oldSuffix) {
3987
+ throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
3988
+ }
3989
+ return string.slice(0, -oldSuffix.length) + newSuffix;
3990
+ }
3991
+ function removePrefix(string, oldPrefix) {
3992
+ return replacePrefix(string, oldPrefix, "");
3993
+ }
3994
+ function removeSuffix(string, oldSuffix) {
3995
+ return replaceSuffix(string, oldSuffix, "");
3996
+ }
3997
+ function maximumOverlap(string1, string2) {
3998
+ return string2.slice(0, overlapCount(string1, string2));
3999
+ }
4000
+ function overlapCount(a, b) {
4001
+ let startA = 0;
4002
+ if (a.length > b.length) {
4003
+ startA = a.length - b.length;
4004
+ }
4005
+ let endB = b.length;
4006
+ if (a.length < b.length) {
4007
+ endB = a.length;
4008
+ }
4009
+ const map = Array(endB);
4010
+ let k = 0;
4011
+ map[0] = 0;
4012
+ for (let j = 1;j < endB; j++) {
4013
+ if (b[j] == b[k]) {
4014
+ map[j] = map[k];
4015
+ } else {
4016
+ map[j] = k;
4017
+ }
4018
+ while (k > 0 && b[j] != b[k]) {
4019
+ k = map[k];
4020
+ }
4021
+ if (b[j] == b[k]) {
4022
+ k++;
4023
+ }
4024
+ }
4025
+ k = 0;
4026
+ for (let i = startA;i < a.length; i++) {
4027
+ while (k > 0 && a[i] != b[k]) {
4028
+ k = map[k];
4029
+ }
4030
+ if (a[i] == b[k]) {
4031
+ k++;
4032
+ }
4033
+ }
4034
+ return k;
4035
+ }
4036
+ function trailingWs(string) {
4037
+ let i;
4038
+ for (i = string.length - 1;i >= 0; i--) {
4039
+ if (!string[i].match(/\s/)) {
4040
+ break;
4041
+ }
4042
+ }
4043
+ return string.substring(i + 1);
4044
+ }
4045
+ function leadingWs(string) {
4046
+ const match = string.match(/^\s*/);
4047
+ return match ? match[0] : "";
4048
+ }
4049
+
4050
+ // ../../node_modules/diff/libesm/diff/word.js
4051
+ 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}";
4052
+ var tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug");
4053
+
4054
+ class WordDiff extends Diff {
4055
+ equals(left, right, options) {
4056
+ if (options.ignoreCase) {
4057
+ left = left.toLowerCase();
4058
+ right = right.toLowerCase();
4059
+ }
4060
+ return left.trim() === right.trim();
4061
+ }
4062
+ tokenize(value, options = {}) {
4063
+ let parts;
4064
+ if (options.intlSegmenter) {
4065
+ const segmenter = options.intlSegmenter;
4066
+ if (segmenter.resolvedOptions().granularity != "word") {
4067
+ throw new Error('The segmenter passed must have a granularity of "word"');
4068
+ }
4069
+ parts = Array.from(segmenter.segment(value), (segment) => segment.segment);
4070
+ } else {
4071
+ parts = value.match(tokenizeIncludingWhitespace) || [];
4072
+ }
4073
+ const tokens = [];
4074
+ let prevPart = null;
4075
+ parts.forEach((part) => {
4076
+ if (/\s/.test(part)) {
4077
+ if (prevPart == null) {
4078
+ tokens.push(part);
4079
+ } else {
4080
+ tokens.push(tokens.pop() + part);
4081
+ }
4082
+ } else if (prevPart != null && /\s/.test(prevPart)) {
4083
+ if (tokens[tokens.length - 1] == prevPart) {
4084
+ tokens.push(tokens.pop() + part);
4085
+ } else {
4086
+ tokens.push(prevPart + part);
4087
+ }
4088
+ } else {
4089
+ tokens.push(part);
4090
+ }
4091
+ prevPart = part;
4092
+ });
4093
+ return tokens;
4094
+ }
4095
+ join(tokens) {
4096
+ return tokens.map((token, i) => {
4097
+ if (i == 0) {
4098
+ return token;
4099
+ } else {
4100
+ return token.replace(/^\s+/, "");
4101
+ }
4102
+ }).join("");
4103
+ }
4104
+ postProcess(changes, options) {
4105
+ if (!changes || options.oneChangePerToken) {
4106
+ return changes;
4107
+ }
4108
+ let lastKeep = null;
4109
+ let insertion = null;
4110
+ let deletion = null;
4111
+ changes.forEach((change) => {
4112
+ if (change.added) {
4113
+ insertion = change;
4114
+ } else if (change.removed) {
4115
+ deletion = change;
4116
+ } else {
4117
+ if (insertion || deletion) {
4118
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
4119
+ }
4120
+ lastKeep = change;
4121
+ insertion = null;
4122
+ deletion = null;
4123
+ }
4124
+ });
4125
+ if (insertion || deletion) {
4126
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
4127
+ }
4128
+ return changes;
4129
+ }
4130
+ }
4131
+ var wordDiff = new WordDiff;
4132
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
4133
+ if (deletion && insertion) {
4134
+ const oldWsPrefix = leadingWs(deletion.value);
4135
+ const oldWsSuffix = trailingWs(deletion.value);
4136
+ const newWsPrefix = leadingWs(insertion.value);
4137
+ const newWsSuffix = trailingWs(insertion.value);
4138
+ if (startKeep) {
4139
+ const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
4140
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
4141
+ deletion.value = removePrefix(deletion.value, commonWsPrefix);
4142
+ insertion.value = removePrefix(insertion.value, commonWsPrefix);
4143
+ }
4144
+ if (endKeep) {
4145
+ const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
4146
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
4147
+ deletion.value = removeSuffix(deletion.value, commonWsSuffix);
4148
+ insertion.value = removeSuffix(insertion.value, commonWsSuffix);
4149
+ }
4150
+ } else if (insertion) {
4151
+ if (startKeep) {
4152
+ const ws = leadingWs(insertion.value);
4153
+ insertion.value = insertion.value.substring(ws.length);
4154
+ }
4155
+ if (endKeep) {
4156
+ const ws = leadingWs(endKeep.value);
4157
+ endKeep.value = endKeep.value.substring(ws.length);
4158
+ }
4159
+ } else if (startKeep && endKeep) {
4160
+ const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);
4161
+ const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
4162
+ deletion.value = removePrefix(deletion.value, newWsStart);
4163
+ const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
4164
+ deletion.value = removeSuffix(deletion.value, newWsEnd);
4165
+ endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
4166
+ startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
4167
+ } else if (endKeep) {
4168
+ const endKeepWsPrefix = leadingWs(endKeep.value);
4169
+ const deletionWsSuffix = trailingWs(deletion.value);
4170
+ const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
4171
+ deletion.value = removeSuffix(deletion.value, overlap);
4172
+ } else if (startKeep) {
4173
+ const startKeepWsSuffix = trailingWs(startKeep.value);
4174
+ const deletionWsPrefix = leadingWs(deletion.value);
4175
+ const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
4176
+ deletion.value = removePrefix(deletion.value, overlap);
4177
+ }
4178
+ }
4179
+
4180
+ class WordsWithSpaceDiff extends Diff {
4181
+ tokenize(value) {
4182
+ const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
4183
+ return value.match(regex) || [];
4184
+ }
4185
+ }
4186
+ var wordsWithSpaceDiff = new WordsWithSpaceDiff;
4187
+
4188
+ // ../../node_modules/diff/libesm/diff/line.js
4189
+ class LineDiff extends Diff {
4190
+ constructor() {
4191
+ super(...arguments);
4192
+ this.tokenize = tokenize;
4193
+ }
4194
+ equals(left, right, options) {
4195
+ if (options.ignoreWhitespace) {
4196
+ if (!options.newlineIsToken || !left.includes(`
4197
+ `)) {
4198
+ left = left.trim();
4199
+ }
4200
+ if (!options.newlineIsToken || !right.includes(`
4201
+ `)) {
4202
+ right = right.trim();
4203
+ }
4204
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
4205
+ if (left.endsWith(`
4206
+ `)) {
4207
+ left = left.slice(0, -1);
4208
+ }
4209
+ if (right.endsWith(`
4210
+ `)) {
4211
+ right = right.slice(0, -1);
4212
+ }
4213
+ }
4214
+ return super.equals(left, right, options);
4215
+ }
4216
+ }
4217
+ var lineDiff = new LineDiff;
4218
+ function tokenize(value, options) {
4219
+ if (options.stripTrailingCr) {
4220
+ value = value.replace(/\r\n/g, `
4221
+ `);
4222
+ }
4223
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
4224
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
4225
+ linesAndNewlines.pop();
4226
+ }
4227
+ for (let i = 0;i < linesAndNewlines.length; i++) {
4228
+ const line = linesAndNewlines[i];
4229
+ if (i % 2 && !options.newlineIsToken) {
4230
+ retLines[retLines.length - 1] += line;
4231
+ } else {
4232
+ retLines.push(line);
4233
+ }
4234
+ }
4235
+ return retLines;
4236
+ }
4237
+
4238
+ // ../../node_modules/diff/libesm/diff/sentence.js
4239
+ function isSentenceEndPunct(char) {
4240
+ return char == "." || char == "!" || char == "?";
4241
+ }
4242
+
4243
+ class SentenceDiff extends Diff {
4244
+ tokenize(value) {
4245
+ var _a;
4246
+ const result = [];
4247
+ let tokenStartI = 0;
4248
+ for (let i = 0;i < value.length; i++) {
4249
+ if (i == value.length - 1) {
4250
+ result.push(value.slice(tokenStartI));
4251
+ break;
4252
+ }
4253
+ if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) {
4254
+ result.push(value.slice(tokenStartI, i + 1));
4255
+ i = tokenStartI = i + 1;
4256
+ while ((_a = value[i + 1]) === null || _a === undefined ? undefined : _a.match(/\s/)) {
4257
+ i++;
4258
+ }
4259
+ result.push(value.slice(tokenStartI, i + 1));
4260
+ tokenStartI = i + 1;
4261
+ }
4262
+ }
4263
+ return result;
4264
+ }
4265
+ }
4266
+ var sentenceDiff = new SentenceDiff;
4267
+
4268
+ // ../../node_modules/diff/libesm/diff/css.js
4269
+ class CssDiff extends Diff {
4270
+ tokenize(value) {
4271
+ return value.split(/([{}:;,]|\s+)/);
4272
+ }
4273
+ }
4274
+ var cssDiff = new CssDiff;
4275
+
4276
+ // ../../node_modules/diff/libesm/diff/json.js
4277
+ class JsonDiff extends Diff {
4278
+ constructor() {
4279
+ super(...arguments);
4280
+ this.tokenize = tokenize;
4281
+ }
4282
+ get useLongestToken() {
4283
+ return true;
4284
+ }
4285
+ castInput(value, options) {
4286
+ const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options;
4287
+ return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " ");
4288
+ }
4289
+ equals(left, right, options) {
4290
+ return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
4291
+ }
4292
+ }
4293
+ var jsonDiff = new JsonDiff;
4294
+ function canonicalize(obj, stack, replacementStack, replacer, key) {
4295
+ stack = stack || [];
4296
+ replacementStack = replacementStack || [];
4297
+ if (replacer) {
4298
+ obj = replacer(key === undefined ? "" : key, obj);
4299
+ }
4300
+ let i;
4301
+ for (i = 0;i < stack.length; i += 1) {
4302
+ if (stack[i] === obj) {
4303
+ return replacementStack[i];
4304
+ }
4305
+ }
4306
+ let canonicalizedObj;
4307
+ if (Object.prototype.toString.call(obj) === "[object Array]") {
4308
+ stack.push(obj);
4309
+ canonicalizedObj = new Array(obj.length);
4310
+ replacementStack.push(canonicalizedObj);
4311
+ for (i = 0;i < obj.length; i += 1) {
4312
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, String(i));
4313
+ }
4314
+ stack.pop();
4315
+ replacementStack.pop();
4316
+ return canonicalizedObj;
4317
+ }
4318
+ if (obj && obj.toJSON) {
4319
+ obj = obj.toJSON();
4320
+ }
4321
+ if (typeof obj === "object" && obj !== null) {
4322
+ stack.push(obj);
4323
+ canonicalizedObj = {};
4324
+ replacementStack.push(canonicalizedObj);
4325
+ const sortedKeys = [];
4326
+ let key2;
4327
+ for (key2 in obj) {
4328
+ if (Object.prototype.hasOwnProperty.call(obj, key2)) {
4329
+ sortedKeys.push(key2);
4330
+ }
4331
+ }
4332
+ sortedKeys.sort();
4333
+ for (i = 0;i < sortedKeys.length; i += 1) {
4334
+ key2 = sortedKeys[i];
4335
+ canonicalizedObj[key2] = canonicalize(obj[key2], stack, replacementStack, replacer, key2);
4336
+ }
4337
+ stack.pop();
4338
+ replacementStack.pop();
4339
+ } else {
4340
+ canonicalizedObj = obj;
4341
+ }
4342
+ return canonicalizedObj;
4343
+ }
4344
+
4345
+ // ../../node_modules/diff/libesm/diff/array.js
4346
+ class ArrayDiff extends Diff {
4347
+ tokenize(value) {
4348
+ return value.slice();
4349
+ }
4350
+ join(value) {
4351
+ return value;
4352
+ }
4353
+ removeEmpty(value) {
4354
+ return value;
4355
+ }
4356
+ }
4357
+ var arrayDiff = new ArrayDiff;
4358
+
4359
+ // ../../node_modules/diff/libesm/patch/parse.js
4360
+ function parsePatch(uniDiff) {
4361
+ const diffstr = uniDiff.split(/\n/), list = [];
4362
+ let i = 0;
4363
+ function parseIndex() {
4364
+ const index = {};
4365
+ list.push(index);
4366
+ while (i < diffstr.length) {
4367
+ const line = diffstr[i];
4368
+ if (/^(---|\+\+\+|@@)\s/.test(line)) {
4369
+ break;
4370
+ }
4371
+ const header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line);
4372
+ if (header) {
4373
+ index.index = header[1];
4374
+ }
4375
+ i++;
4376
+ }
4377
+ parseFileHeader(index);
4378
+ parseFileHeader(index);
4379
+ index.hunks = [];
4380
+ while (i < diffstr.length) {
4381
+ const line = diffstr[i];
4382
+ if (/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line)) {
4383
+ break;
4384
+ } else if (/^@@/.test(line)) {
4385
+ index.hunks.push(parseHunk());
4386
+ } else if (line) {
4387
+ throw new Error("Unknown line " + (i + 1) + " " + JSON.stringify(line));
4388
+ } else {
4389
+ i++;
4390
+ }
4391
+ }
4392
+ }
4393
+ function parseFileHeader(index) {
4394
+ const fileHeader = /^(---|\+\+\+)\s+(.*)\r?$/.exec(diffstr[i]);
4395
+ if (fileHeader) {
4396
+ const data = fileHeader[2].split("\t", 2), header = (data[1] || "").trim();
4397
+ let fileName = data[0].replace(/\\\\/g, "\\");
4398
+ if (/^".*"$/.test(fileName)) {
4399
+ fileName = fileName.substr(1, fileName.length - 2);
4400
+ }
4401
+ if (fileHeader[1] === "---") {
4402
+ index.oldFileName = fileName;
4403
+ index.oldHeader = header;
4404
+ } else {
4405
+ index.newFileName = fileName;
4406
+ index.newHeader = header;
4407
+ }
4408
+ i++;
4409
+ }
4410
+ }
4411
+ function parseHunk() {
4412
+ var _a;
4413
+ const chunkHeaderIndex = i, chunkHeaderLine = diffstr[i++], chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/);
4414
+ const hunk = {
4415
+ oldStart: +chunkHeader[1],
4416
+ oldLines: typeof chunkHeader[2] === "undefined" ? 1 : +chunkHeader[2],
4417
+ newStart: +chunkHeader[3],
4418
+ newLines: typeof chunkHeader[4] === "undefined" ? 1 : +chunkHeader[4],
4419
+ lines: []
4420
+ };
4421
+ if (hunk.oldLines === 0) {
4422
+ hunk.oldStart += 1;
4423
+ }
4424
+ if (hunk.newLines === 0) {
4425
+ hunk.newStart += 1;
4426
+ }
4427
+ let addCount = 0, removeCount = 0;
4428
+ for (;i < diffstr.length && (removeCount < hunk.oldLines || addCount < hunk.newLines || ((_a = diffstr[i]) === null || _a === undefined ? undefined : _a.startsWith("\\"))); i++) {
4429
+ const operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? " " : diffstr[i][0];
4430
+ if (operation === "+" || operation === "-" || operation === " " || operation === "\\") {
4431
+ hunk.lines.push(diffstr[i]);
4432
+ if (operation === "+") {
4433
+ addCount++;
4434
+ } else if (operation === "-") {
4435
+ removeCount++;
4436
+ } else if (operation === " ") {
4437
+ addCount++;
4438
+ removeCount++;
4439
+ }
4440
+ } else {
4441
+ throw new Error(`Hunk at line ${chunkHeaderIndex + 1} contained invalid line ${diffstr[i]}`);
4442
+ }
4443
+ }
4444
+ if (!addCount && hunk.newLines === 1) {
4445
+ hunk.newLines = 0;
4446
+ }
4447
+ if (!removeCount && hunk.oldLines === 1) {
4448
+ hunk.oldLines = 0;
4449
+ }
4450
+ if (addCount !== hunk.newLines) {
4451
+ throw new Error("Added line count did not match for hunk at line " + (chunkHeaderIndex + 1));
4452
+ }
4453
+ if (removeCount !== hunk.oldLines) {
4454
+ throw new Error("Removed line count did not match for hunk at line " + (chunkHeaderIndex + 1));
4455
+ }
4456
+ return hunk;
4457
+ }
4458
+ while (i < diffstr.length) {
4459
+ parseIndex();
4460
+ }
4461
+ return list;
4462
+ }
4463
+
4464
+ // src/renderables/Text.ts
4465
+ class TextRenderable extends TextBufferRenderable {
4466
+ _text;
4467
+ _hasManualStyledText = false;
4468
+ rootTextNode;
4469
+ _contentDefaultOptions = {
4470
+ content: ""
4471
+ };
4472
+ constructor(ctx, options) {
4473
+ super(ctx, options);
4474
+ const content = options.content ?? this._contentDefaultOptions.content;
4475
+ const styledText = typeof content === "string" ? stringToStyledText(content) : content;
4476
+ this._text = styledText;
4477
+ this._hasManualStyledText = options.content !== undefined && content !== "";
4478
+ this.rootTextNode = new RootTextNodeRenderable(ctx, {
4479
+ id: `${this.id}-root`,
4480
+ fg: this._defaultFg,
4481
+ bg: this._defaultBg,
4482
+ attributes: this._defaultAttributes
4483
+ }, this);
4484
+ this.updateTextBuffer(styledText);
4485
+ }
4486
+ updateTextBuffer(styledText) {
4487
+ this.textBuffer.setStyledText(styledText);
4488
+ this.clearChunks(styledText);
4489
+ }
4490
+ clearChunks(styledText) {}
4491
+ get content() {
4492
+ return this._text;
4493
+ }
4494
+ get chunks() {
4495
+ return this._text.chunks;
4496
+ }
4497
+ get textNode() {
4498
+ return this.rootTextNode;
4499
+ }
4500
+ set content(value) {
4501
+ this._hasManualStyledText = true;
4502
+ const styledText = typeof value === "string" ? stringToStyledText(value) : value;
4503
+ if (this._text !== styledText) {
4504
+ this._text = styledText;
4505
+ this.updateTextBuffer(styledText);
4506
+ this.updateTextInfo();
4507
+ }
4508
+ }
4509
+ updateTextFromNodes() {
4510
+ if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
4511
+ const chunks = this.rootTextNode.gatherWithInheritedStyle({
4512
+ fg: this._defaultFg,
4513
+ bg: this._defaultBg,
4514
+ attributes: this._defaultAttributes
4515
+ });
4516
+ this.textBuffer.setStyledText(new StyledText(chunks));
4517
+ this.refreshLocalSelection();
4518
+ this.yogaNode.markDirty();
4519
+ }
4520
+ }
4521
+ add(obj, index) {
4522
+ return this.rootTextNode.add(obj, index);
4523
+ }
4524
+ remove(id) {
4525
+ this.rootTextNode.remove(id);
4526
+ }
4527
+ insertBefore(obj, anchor) {
4528
+ this.rootTextNode.insertBefore(obj, anchor);
4529
+ return this.rootTextNode.children.indexOf(obj);
4530
+ }
4531
+ getTextChildren() {
4532
+ return this.rootTextNode.getChildren();
4533
+ }
4534
+ clear() {
4535
+ this.rootTextNode.clear();
4536
+ const emptyStyledText = stringToStyledText("");
4537
+ this._text = emptyStyledText;
4538
+ this.updateTextBuffer(emptyStyledText);
4539
+ this.updateTextInfo();
4540
+ this.requestRender();
4541
+ }
4542
+ onLifecyclePass = () => {
4543
+ this.updateTextFromNodes();
4544
+ };
4545
+ onFgChanged(newColor) {
4546
+ this.rootTextNode.fg = newColor;
4547
+ }
4548
+ onBgChanged(newColor) {
4549
+ this.rootTextNode.bg = newColor;
4550
+ }
4551
+ onAttributesChanged(newAttributes) {
4552
+ this.rootTextNode.attributes = newAttributes;
4553
+ }
4554
+ destroy() {
4555
+ this.rootTextNode.children.length = 0;
4556
+ super.destroy();
4557
+ }
4558
+ }
4559
+
4560
+ // src/renderables/Diff.ts
4561
+ class DiffRenderable extends Renderable {
4562
+ _diff;
4563
+ _view;
4564
+ _parsedDiff = null;
4565
+ _parseError = null;
4566
+ _filetype;
4567
+ _syntaxStyle;
4568
+ _wrapMode;
4569
+ _conceal;
4570
+ _selectionBg;
4571
+ _selectionFg;
4572
+ _showLineNumbers;
4573
+ _lineNumberFg;
4574
+ _lineNumberBg;
4575
+ _addedBg;
4576
+ _removedBg;
4577
+ _contextBg;
4578
+ _addedContentBg;
4579
+ _removedContentBg;
4580
+ _contextContentBg;
4581
+ _addedSignColor;
4582
+ _removedSignColor;
4583
+ _addedLineNumberBg;
4584
+ _removedLineNumberBg;
4585
+ leftSide = null;
4586
+ rightSide = null;
4587
+ leftSideAdded = false;
4588
+ rightSideAdded = false;
4589
+ leftCodeRenderable = null;
4590
+ rightCodeRenderable = null;
4591
+ pendingRebuild = false;
4592
+ errorTextRenderable = null;
4593
+ errorCodeRenderable = null;
4594
+ constructor(ctx, options) {
4595
+ super(ctx, {
4596
+ ...options,
4597
+ flexDirection: options.view === "split" ? "row" : "column"
4598
+ });
4599
+ this._diff = options.diff ?? "";
4600
+ this._view = options.view ?? "unified";
4601
+ this._filetype = options.filetype;
4602
+ this._syntaxStyle = options.syntaxStyle;
4603
+ this._wrapMode = options.wrapMode;
4604
+ this._conceal = options.conceal ?? true;
4605
+ this._selectionBg = options.selectionBg ? parseColor(options.selectionBg) : undefined;
4606
+ this._selectionFg = options.selectionFg ? parseColor(options.selectionFg) : undefined;
4607
+ this._showLineNumbers = options.showLineNumbers ?? true;
4608
+ this._lineNumberFg = parseColor(options.lineNumberFg ?? "#888888");
4609
+ this._lineNumberBg = parseColor(options.lineNumberBg ?? "transparent");
4610
+ this._addedBg = parseColor(options.addedBg ?? "#1a4d1a");
4611
+ this._removedBg = parseColor(options.removedBg ?? "#4d1a1a");
4612
+ this._contextBg = parseColor(options.contextBg ?? "transparent");
4613
+ this._addedContentBg = options.addedContentBg ? parseColor(options.addedContentBg) : null;
4614
+ this._removedContentBg = options.removedContentBg ? parseColor(options.removedContentBg) : null;
4615
+ this._contextContentBg = options.contextContentBg ? parseColor(options.contextContentBg) : null;
4616
+ this._addedSignColor = parseColor(options.addedSignColor ?? "#22c55e");
4617
+ this._removedSignColor = parseColor(options.removedSignColor ?? "#ef4444");
4618
+ this._addedLineNumberBg = parseColor(options.addedLineNumberBg ?? "transparent");
4619
+ this._removedLineNumberBg = parseColor(options.removedLineNumberBg ?? "transparent");
4620
+ if (this._diff) {
4621
+ this.parseDiff();
4622
+ this.buildView();
4623
+ }
4624
+ }
4625
+ parseDiff() {
4626
+ if (!this._diff) {
4627
+ this._parsedDiff = null;
4628
+ this._parseError = null;
4629
+ return;
4630
+ }
4631
+ try {
4632
+ const patches = parsePatch(this._diff);
4633
+ if (patches.length === 0) {
4634
+ this._parsedDiff = null;
4635
+ this._parseError = null;
4636
+ return;
4637
+ }
4638
+ this._parsedDiff = patches[0];
4639
+ this._parseError = null;
4640
+ } catch (error) {
4641
+ this._parsedDiff = null;
4642
+ this._parseError = error instanceof Error ? error : new Error(String(error));
4643
+ }
4644
+ }
4645
+ buildView() {
4646
+ if (this._parseError) {
4647
+ this.buildErrorView();
4648
+ return;
4649
+ }
4650
+ if (!this._parsedDiff || this._parsedDiff.hunks.length === 0) {
4651
+ return;
4652
+ }
4653
+ if (this._view === "unified") {
4654
+ this.buildUnifiedView();
4655
+ } else {
4656
+ this.buildSplitView();
4657
+ }
4658
+ }
4659
+ onResize(width, height) {
4660
+ super.onResize(width, height);
4661
+ if (this._view === "split" && this._wrapMode !== "none" && this._wrapMode !== undefined) {
4662
+ this.requestRebuild();
4663
+ }
4664
+ }
4665
+ requestRebuild() {
4666
+ if (this.pendingRebuild) {
4667
+ return;
4668
+ }
4669
+ this.pendingRebuild = true;
4670
+ queueMicrotask(() => {
4671
+ if (!this.isDestroyed && this.pendingRebuild) {
4672
+ this.pendingRebuild = false;
4673
+ this.buildView();
4674
+ this.requestRender();
4675
+ }
4676
+ });
4677
+ }
4678
+ rebuildView() {
4679
+ if (this._view === "split") {
4680
+ this.requestRebuild();
4681
+ } else {
4682
+ this.buildView();
4683
+ }
4684
+ }
4685
+ destroyRecursively() {
4686
+ this.pendingRebuild = false;
4687
+ this.leftSideAdded = false;
4688
+ this.rightSideAdded = false;
4689
+ super.destroyRecursively();
4690
+ }
4691
+ buildErrorView() {
4692
+ this.flexDirection = "column";
4693
+ if (this.leftSide && this.leftSideAdded) {
4694
+ super.remove(this.leftSide.id);
4695
+ this.leftSideAdded = false;
4696
+ }
4697
+ if (this.rightSide && this.rightSideAdded) {
4698
+ super.remove(this.rightSide.id);
4699
+ this.rightSideAdded = false;
4700
+ }
4701
+ const errorMessage = `Error parsing diff: ${this._parseError?.message || "Unknown error"}
4702
+ `;
4703
+ if (!this.errorTextRenderable) {
4704
+ this.errorTextRenderable = new TextRenderable(this.ctx, {
4705
+ id: this.id ? `${this.id}-error-text` : undefined,
4706
+ content: errorMessage,
4707
+ fg: "#ef4444",
4708
+ width: "100%",
4709
+ flexShrink: 0
4710
+ });
4711
+ super.add(this.errorTextRenderable);
4712
+ } else {
4713
+ this.errorTextRenderable.content = errorMessage;
4714
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4715
+ if (errorTextIndex === -1) {
4716
+ super.add(this.errorTextRenderable);
4717
+ }
4718
+ }
4719
+ if (!this.errorCodeRenderable) {
4720
+ this.errorCodeRenderable = new CodeRenderable(this.ctx, {
4721
+ id: this.id ? `${this.id}-error-code` : undefined,
4722
+ content: this._diff,
4723
+ filetype: "diff",
4724
+ syntaxStyle: this._syntaxStyle ?? SyntaxStyle.create(),
4725
+ wrapMode: this._wrapMode,
4726
+ conceal: this._conceal,
4727
+ width: "100%",
4728
+ flexGrow: 1,
4729
+ flexShrink: 1
4730
+ });
4731
+ super.add(this.errorCodeRenderable);
4732
+ } else {
4733
+ this.errorCodeRenderable.content = this._diff;
4734
+ this.errorCodeRenderable.wrapMode = this._wrapMode ?? "none";
4735
+ if (this._syntaxStyle) {
4736
+ this.errorCodeRenderable.syntaxStyle = this._syntaxStyle;
4737
+ }
4738
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4739
+ if (errorCodeIndex === -1) {
4740
+ super.add(this.errorCodeRenderable);
4741
+ }
4742
+ }
4743
+ }
4744
+ createOrUpdateCodeRenderable(side, content, wrapMode, drawUnstyledText) {
4745
+ const existingRenderable = side === "left" ? this.leftCodeRenderable : this.rightCodeRenderable;
4746
+ if (!existingRenderable) {
4747
+ const codeOptions = {
4748
+ id: this.id ? `${this.id}-${side}-code` : undefined,
4749
+ content,
4750
+ filetype: this._filetype,
4751
+ wrapMode,
4752
+ conceal: this._conceal,
4753
+ syntaxStyle: this._syntaxStyle ?? SyntaxStyle.create(),
4754
+ width: "100%",
4755
+ height: "100%",
4756
+ ...drawUnstyledText !== undefined && { drawUnstyledText },
4757
+ ...this._selectionBg !== undefined && { selectionBg: this._selectionBg },
4758
+ ...this._selectionFg !== undefined && { selectionFg: this._selectionFg }
4759
+ };
4760
+ const newRenderable = new CodeRenderable(this.ctx, codeOptions);
4761
+ if (side === "left") {
4762
+ this.leftCodeRenderable = newRenderable;
4763
+ } else {
4764
+ this.rightCodeRenderable = newRenderable;
4765
+ }
4766
+ return newRenderable;
4767
+ } else {
4768
+ existingRenderable.content = content;
4769
+ existingRenderable.wrapMode = wrapMode ?? "none";
4770
+ if (drawUnstyledText !== undefined) {
4771
+ existingRenderable.drawUnstyledText = drawUnstyledText;
4772
+ }
4773
+ if (this._filetype !== undefined) {
4774
+ existingRenderable.filetype = this._filetype;
4775
+ }
4776
+ if (this._syntaxStyle !== undefined) {
4777
+ existingRenderable.syntaxStyle = this._syntaxStyle;
4778
+ }
4779
+ if (this._selectionBg !== undefined) {
4780
+ existingRenderable.selectionBg = this._selectionBg;
4781
+ }
4782
+ if (this._selectionFg !== undefined) {
4783
+ existingRenderable.selectionFg = this._selectionFg;
4784
+ }
4785
+ return existingRenderable;
4786
+ }
4787
+ }
4788
+ createOrUpdateSide(side, target, lineColors, lineSigns, lineNumbers, hideLineNumbers, width) {
4789
+ const sideRef = side === "left" ? this.leftSide : this.rightSide;
4790
+ const addedFlag = side === "left" ? this.leftSideAdded : this.rightSideAdded;
4791
+ if (!sideRef) {
4792
+ const newSide = new LineNumberRenderable(this.ctx, {
4793
+ id: this.id ? `${this.id}-${side}` : undefined,
4794
+ target,
4795
+ fg: this._lineNumberFg,
4796
+ bg: this._lineNumberBg,
4797
+ lineColors,
4798
+ lineSigns,
4799
+ lineNumbers,
4800
+ lineNumberOffset: 0,
4801
+ hideLineNumbers,
4802
+ width,
4803
+ height: "100%"
4804
+ });
4805
+ newSide.showLineNumbers = this._showLineNumbers;
4806
+ super.add(newSide);
4807
+ if (side === "left") {
4808
+ this.leftSide = newSide;
4809
+ this.leftSideAdded = true;
4810
+ } else {
4811
+ this.rightSide = newSide;
4812
+ this.rightSideAdded = true;
4813
+ }
4814
+ } else {
4815
+ sideRef.width = width;
4816
+ sideRef.setLineColors(lineColors);
4817
+ sideRef.setLineSigns(lineSigns);
4818
+ sideRef.setLineNumbers(lineNumbers);
4819
+ sideRef.setHideLineNumbers(hideLineNumbers);
4820
+ if (!addedFlag) {
4821
+ super.add(sideRef);
4822
+ if (side === "left") {
4823
+ this.leftSideAdded = true;
4824
+ } else {
4825
+ this.rightSideAdded = true;
4826
+ }
4827
+ }
4828
+ }
4829
+ }
4830
+ buildUnifiedView() {
4831
+ if (!this._parsedDiff)
4832
+ return;
4833
+ this.flexDirection = "column";
4834
+ if (this.errorTextRenderable) {
4835
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4836
+ if (errorTextIndex !== -1) {
4837
+ super.remove(this.errorTextRenderable.id);
4838
+ }
4839
+ }
4840
+ if (this.errorCodeRenderable) {
4841
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4842
+ if (errorCodeIndex !== -1) {
4843
+ super.remove(this.errorCodeRenderable.id);
4844
+ }
4845
+ }
4846
+ const contentLines = [];
4847
+ const lineColors = new Map;
4848
+ const lineSigns = new Map;
4849
+ const lineNumbers = new Map;
4850
+ let lineIndex = 0;
4851
+ for (const hunk of this._parsedDiff.hunks) {
4852
+ let oldLineNum = hunk.oldStart;
4853
+ let newLineNum = hunk.newStart;
4854
+ for (const line of hunk.lines) {
4855
+ const firstChar = line[0];
4856
+ const content2 = line.slice(1);
4857
+ if (firstChar === "+") {
4858
+ contentLines.push(content2);
4859
+ const config = {
4860
+ gutter: this._addedLineNumberBg
4861
+ };
4862
+ if (this._addedContentBg) {
4863
+ config.content = this._addedContentBg;
4864
+ } else {
4865
+ config.content = this._addedBg;
4866
+ }
4867
+ lineColors.set(lineIndex, config);
4868
+ lineSigns.set(lineIndex, {
4869
+ after: " +",
4870
+ afterColor: this._addedSignColor
4871
+ });
4872
+ lineNumbers.set(lineIndex, newLineNum);
4873
+ newLineNum++;
4874
+ lineIndex++;
4875
+ } else if (firstChar === "-") {
4876
+ contentLines.push(content2);
4877
+ const config = {
4878
+ gutter: this._removedLineNumberBg
4879
+ };
4880
+ if (this._removedContentBg) {
4881
+ config.content = this._removedContentBg;
4882
+ } else {
4883
+ config.content = this._removedBg;
4884
+ }
4885
+ lineColors.set(lineIndex, config);
4886
+ lineSigns.set(lineIndex, {
4887
+ after: " -",
4888
+ afterColor: this._removedSignColor
4889
+ });
4890
+ lineNumbers.set(lineIndex, oldLineNum);
4891
+ oldLineNum++;
4892
+ lineIndex++;
4893
+ } else if (firstChar === " ") {
4894
+ contentLines.push(content2);
4895
+ const config = {
4896
+ gutter: this._lineNumberBg
4897
+ };
4898
+ if (this._contextContentBg) {
4899
+ config.content = this._contextContentBg;
4900
+ } else {
4901
+ config.content = this._contextBg;
4902
+ }
4903
+ lineColors.set(lineIndex, config);
4904
+ lineNumbers.set(lineIndex, newLineNum);
4905
+ oldLineNum++;
4906
+ newLineNum++;
4907
+ lineIndex++;
4908
+ }
4909
+ }
4910
+ }
4911
+ const content = contentLines.join(`
4912
+ `);
4913
+ const codeRenderable = this.createOrUpdateCodeRenderable("left", content, this._wrapMode);
4914
+ this.createOrUpdateSide("left", codeRenderable, lineColors, lineSigns, lineNumbers, new Set, "100%");
4915
+ if (this.rightSide && this.rightSideAdded) {
4916
+ super.remove(this.rightSide.id);
4917
+ this.rightSideAdded = false;
4918
+ }
4919
+ }
4920
+ buildSplitView() {
4921
+ if (!this._parsedDiff)
4922
+ return;
4923
+ this.flexDirection = "row";
4924
+ if (this.errorTextRenderable) {
4925
+ const errorTextIndex = this.getChildren().indexOf(this.errorTextRenderable);
4926
+ if (errorTextIndex !== -1) {
4927
+ super.remove(this.errorTextRenderable.id);
4928
+ }
4929
+ }
4930
+ if (this.errorCodeRenderable) {
4931
+ const errorCodeIndex = this.getChildren().indexOf(this.errorCodeRenderable);
4932
+ if (errorCodeIndex !== -1) {
4933
+ super.remove(this.errorCodeRenderable.id);
4934
+ }
4935
+ }
4936
+ const leftLogicalLines = [];
4937
+ const rightLogicalLines = [];
4938
+ for (const hunk of this._parsedDiff.hunks) {
4939
+ let oldLineNum = hunk.oldStart;
4940
+ let newLineNum = hunk.newStart;
4941
+ let i = 0;
4942
+ while (i < hunk.lines.length) {
4943
+ const line = hunk.lines[i];
4944
+ const firstChar = line[0];
4945
+ if (firstChar === " ") {
4946
+ const content = line.slice(1);
4947
+ leftLogicalLines.push({
4948
+ content,
4949
+ lineNum: oldLineNum,
4950
+ color: this._contextBg,
4951
+ type: "context"
4952
+ });
4953
+ rightLogicalLines.push({
4954
+ content,
4955
+ lineNum: newLineNum,
4956
+ color: this._contextBg,
4957
+ type: "context"
4958
+ });
4959
+ oldLineNum++;
4960
+ newLineNum++;
4961
+ i++;
4962
+ } else if (firstChar === "\\") {
4963
+ i++;
4964
+ } else {
4965
+ const removes = [];
4966
+ const adds = [];
4967
+ while (i < hunk.lines.length) {
4968
+ const currentLine = hunk.lines[i];
4969
+ const currentChar = currentLine[0];
4970
+ if (currentChar === " " || currentChar === "\\") {
4971
+ break;
4972
+ }
4973
+ const content = currentLine.slice(1);
4974
+ if (currentChar === "-") {
4975
+ removes.push({ content, lineNum: oldLineNum });
4976
+ oldLineNum++;
4977
+ } else if (currentChar === "+") {
4978
+ adds.push({ content, lineNum: newLineNum });
4979
+ newLineNum++;
4980
+ }
4981
+ i++;
4982
+ }
4983
+ const maxLength = Math.max(removes.length, adds.length);
4984
+ for (let j = 0;j < maxLength; j++) {
4985
+ if (j < removes.length) {
4986
+ leftLogicalLines.push({
4987
+ content: removes[j].content,
4988
+ lineNum: removes[j].lineNum,
4989
+ color: this._removedBg,
4990
+ sign: {
4991
+ after: " -",
4992
+ afterColor: this._removedSignColor
4993
+ },
4994
+ type: "remove"
4995
+ });
4996
+ } else {
4997
+ leftLogicalLines.push({
4998
+ content: "",
4999
+ hideLineNumber: true,
5000
+ type: "empty"
5001
+ });
5002
+ }
5003
+ if (j < adds.length) {
5004
+ rightLogicalLines.push({
5005
+ content: adds[j].content,
5006
+ lineNum: adds[j].lineNum,
5007
+ color: this._addedBg,
5008
+ sign: {
5009
+ after: " +",
5010
+ afterColor: this._addedSignColor
5011
+ },
5012
+ type: "add"
5013
+ });
5014
+ } else {
5015
+ rightLogicalLines.push({
5016
+ content: "",
5017
+ hideLineNumber: true,
5018
+ type: "empty"
5019
+ });
5020
+ }
5021
+ }
5022
+ }
5023
+ }
5024
+ }
5025
+ const canDoWrapAlignment = this.width > 0 && (this._wrapMode === "word" || this._wrapMode === "char");
5026
+ const preLeftContent = leftLogicalLines.map((l) => l.content).join(`
5027
+ `);
5028
+ const preRightContent = rightLogicalLines.map((l) => l.content).join(`
5029
+ `);
5030
+ const effectiveWrapMode = canDoWrapAlignment ? this._wrapMode : "none";
5031
+ const leftCodeRenderable = this.createOrUpdateCodeRenderable("left", preLeftContent, effectiveWrapMode, true);
5032
+ const rightCodeRenderable = this.createOrUpdateCodeRenderable("right", preRightContent, effectiveWrapMode, true);
5033
+ let finalLeftLines;
5034
+ let finalRightLines;
5035
+ if (canDoWrapAlignment) {
5036
+ const leftLineInfo = leftCodeRenderable.lineInfo;
5037
+ const rightLineInfo = rightCodeRenderable.lineInfo;
5038
+ const leftSources = leftLineInfo.lineSources || [];
5039
+ const rightSources = rightLineInfo.lineSources || [];
5040
+ const leftVisualCounts = new Map;
5041
+ const rightVisualCounts = new Map;
5042
+ for (const logicalLine of leftSources) {
5043
+ leftVisualCounts.set(logicalLine, (leftVisualCounts.get(logicalLine) || 0) + 1);
5044
+ }
5045
+ for (const logicalLine of rightSources) {
5046
+ rightVisualCounts.set(logicalLine, (rightVisualCounts.get(logicalLine) || 0) + 1);
5047
+ }
5048
+ finalLeftLines = [];
5049
+ finalRightLines = [];
5050
+ let leftVisualPos = 0;
5051
+ let rightVisualPos = 0;
5052
+ for (let i = 0;i < leftLogicalLines.length; i++) {
5053
+ const leftLine = leftLogicalLines[i];
5054
+ const rightLine = rightLogicalLines[i];
5055
+ const leftVisualCount = leftVisualCounts.get(i) || 1;
5056
+ const rightVisualCount = rightVisualCounts.get(i) || 1;
5057
+ if (leftVisualPos < rightVisualPos) {
5058
+ const pad = rightVisualPos - leftVisualPos;
5059
+ for (let p = 0;p < pad; p++) {
5060
+ finalLeftLines.push({ content: "", hideLineNumber: true, type: "empty" });
5061
+ }
5062
+ leftVisualPos += pad;
5063
+ } else if (rightVisualPos < leftVisualPos) {
5064
+ const pad = leftVisualPos - rightVisualPos;
5065
+ for (let p = 0;p < pad; p++) {
5066
+ finalRightLines.push({ content: "", hideLineNumber: true, type: "empty" });
5067
+ }
5068
+ rightVisualPos += pad;
5069
+ }
5070
+ finalLeftLines.push(leftLine);
5071
+ finalRightLines.push(rightLine);
5072
+ leftVisualPos += leftVisualCount;
5073
+ rightVisualPos += rightVisualCount;
5074
+ }
5075
+ if (leftVisualPos < rightVisualPos) {
5076
+ const pad = rightVisualPos - leftVisualPos;
5077
+ for (let p = 0;p < pad; p++) {
5078
+ finalLeftLines.push({ content: "", hideLineNumber: true, type: "empty" });
5079
+ }
5080
+ } else if (rightVisualPos < leftVisualPos) {
5081
+ const pad = leftVisualPos - rightVisualPos;
5082
+ for (let p = 0;p < pad; p++) {
5083
+ finalRightLines.push({ content: "", hideLineNumber: true, type: "empty" });
5084
+ }
5085
+ }
5086
+ } else {
5087
+ finalLeftLines = leftLogicalLines;
5088
+ finalRightLines = rightLogicalLines;
5089
+ }
5090
+ const leftLineColors = new Map;
5091
+ const rightLineColors = new Map;
5092
+ const leftLineSigns = new Map;
5093
+ const rightLineSigns = new Map;
5094
+ const leftHideLineNumbers = new Set;
5095
+ const rightHideLineNumbers = new Set;
5096
+ const leftLineNumbers = new Map;
5097
+ const rightLineNumbers = new Map;
5098
+ finalLeftLines.forEach((line, index) => {
5099
+ if (line.lineNum !== undefined) {
5100
+ leftLineNumbers.set(index, line.lineNum);
5101
+ }
5102
+ if (line.hideLineNumber) {
5103
+ leftHideLineNumbers.add(index);
5104
+ }
5105
+ if (line.type === "remove") {
5106
+ const config = {
5107
+ gutter: this._removedLineNumberBg
5108
+ };
5109
+ if (this._removedContentBg) {
5110
+ config.content = this._removedContentBg;
5111
+ } else {
5112
+ config.content = this._removedBg;
5113
+ }
5114
+ leftLineColors.set(index, config);
5115
+ } else if (line.type === "context") {
5116
+ const config = {
5117
+ gutter: this._lineNumberBg
5118
+ };
5119
+ if (this._contextContentBg) {
5120
+ config.content = this._contextContentBg;
5121
+ } else {
5122
+ config.content = this._contextBg;
5123
+ }
5124
+ leftLineColors.set(index, config);
5125
+ }
5126
+ if (line.sign) {
5127
+ leftLineSigns.set(index, line.sign);
5128
+ }
5129
+ });
5130
+ finalRightLines.forEach((line, index) => {
5131
+ if (line.lineNum !== undefined) {
5132
+ rightLineNumbers.set(index, line.lineNum);
5133
+ }
5134
+ if (line.hideLineNumber) {
5135
+ rightHideLineNumbers.add(index);
5136
+ }
5137
+ if (line.type === "add") {
5138
+ const config = {
5139
+ gutter: this._addedLineNumberBg
5140
+ };
5141
+ if (this._addedContentBg) {
5142
+ config.content = this._addedContentBg;
5143
+ } else {
5144
+ config.content = this._addedBg;
5145
+ }
5146
+ rightLineColors.set(index, config);
5147
+ } else if (line.type === "context") {
5148
+ const config = {
5149
+ gutter: this._lineNumberBg
5150
+ };
5151
+ if (this._contextContentBg) {
5152
+ config.content = this._contextContentBg;
5153
+ } else {
5154
+ config.content = this._contextBg;
5155
+ }
5156
+ rightLineColors.set(index, config);
5157
+ }
5158
+ if (line.sign) {
5159
+ rightLineSigns.set(index, line.sign);
5160
+ }
5161
+ });
5162
+ const leftContentFinal = finalLeftLines.map((l) => l.content).join(`
5163
+ `);
5164
+ const rightContentFinal = finalRightLines.map((l) => l.content).join(`
5165
+ `);
5166
+ leftCodeRenderable.content = leftContentFinal;
5167
+ rightCodeRenderable.content = rightContentFinal;
5168
+ this.createOrUpdateSide("left", leftCodeRenderable, leftLineColors, leftLineSigns, leftLineNumbers, leftHideLineNumbers, "50%");
5169
+ this.createOrUpdateSide("right", rightCodeRenderable, rightLineColors, rightLineSigns, rightLineNumbers, rightHideLineNumbers, "50%");
5170
+ }
5171
+ get diff() {
5172
+ return this._diff;
5173
+ }
5174
+ set diff(value) {
5175
+ if (this._diff !== value) {
5176
+ this._diff = value;
5177
+ this.parseDiff();
5178
+ this.rebuildView();
5179
+ }
5180
+ }
5181
+ get view() {
5182
+ return this._view;
5183
+ }
5184
+ set view(value) {
5185
+ if (this._view !== value) {
5186
+ this._view = value;
5187
+ this.flexDirection = value === "split" ? "row" : "column";
5188
+ this.buildView();
5189
+ }
5190
+ }
5191
+ get filetype() {
5192
+ return this._filetype;
5193
+ }
5194
+ set filetype(value) {
5195
+ if (this._filetype !== value) {
5196
+ this._filetype = value;
5197
+ this.rebuildView();
5198
+ }
5199
+ }
5200
+ get syntaxStyle() {
5201
+ return this._syntaxStyle;
5202
+ }
5203
+ set syntaxStyle(value) {
5204
+ if (this._syntaxStyle !== value) {
5205
+ this._syntaxStyle = value;
5206
+ this.rebuildView();
5207
+ }
5208
+ }
5209
+ get wrapMode() {
5210
+ return this._wrapMode;
5211
+ }
5212
+ set wrapMode(value) {
5213
+ if (this._wrapMode !== value) {
5214
+ this._wrapMode = value;
5215
+ if (this._view === "unified" && this.leftCodeRenderable) {
5216
+ this.leftCodeRenderable.wrapMode = value ?? "none";
5217
+ } else if (this._view === "split") {
5218
+ this.requestRebuild();
5219
+ }
5220
+ }
5221
+ }
5222
+ get showLineNumbers() {
5223
+ return this._showLineNumbers;
5224
+ }
5225
+ set showLineNumbers(value) {
5226
+ if (this._showLineNumbers !== value) {
5227
+ this._showLineNumbers = value;
5228
+ if (this.leftSide) {
5229
+ this.leftSide.showLineNumbers = value;
5230
+ }
5231
+ if (this.rightSide) {
5232
+ this.rightSide.showLineNumbers = value;
5233
+ }
5234
+ }
5235
+ }
5236
+ get addedBg() {
5237
+ return this._addedBg;
5238
+ }
5239
+ set addedBg(value) {
5240
+ const parsed = parseColor(value);
5241
+ if (this._addedBg !== parsed) {
5242
+ this._addedBg = parsed;
5243
+ this.rebuildView();
5244
+ }
5245
+ }
5246
+ get removedBg() {
5247
+ return this._removedBg;
5248
+ }
5249
+ set removedBg(value) {
5250
+ const parsed = parseColor(value);
5251
+ if (this._removedBg !== parsed) {
5252
+ this._removedBg = parsed;
5253
+ this.rebuildView();
5254
+ }
5255
+ }
5256
+ get contextBg() {
5257
+ return this._contextBg;
5258
+ }
5259
+ set contextBg(value) {
5260
+ const parsed = parseColor(value);
5261
+ if (this._contextBg !== parsed) {
5262
+ this._contextBg = parsed;
5263
+ this.rebuildView();
5264
+ }
5265
+ }
5266
+ get addedSignColor() {
5267
+ return this._addedSignColor;
5268
+ }
5269
+ set addedSignColor(value) {
5270
+ const parsed = parseColor(value);
5271
+ if (this._addedSignColor !== parsed) {
5272
+ this._addedSignColor = parsed;
5273
+ this.rebuildView();
5274
+ }
5275
+ }
5276
+ get removedSignColor() {
5277
+ return this._removedSignColor;
5278
+ }
5279
+ set removedSignColor(value) {
5280
+ const parsed = parseColor(value);
5281
+ if (this._removedSignColor !== parsed) {
5282
+ this._removedSignColor = parsed;
5283
+ this.rebuildView();
5284
+ }
5285
+ }
5286
+ get addedLineNumberBg() {
5287
+ return this._addedLineNumberBg;
5288
+ }
5289
+ set addedLineNumberBg(value) {
5290
+ const parsed = parseColor(value);
5291
+ if (this._addedLineNumberBg !== parsed) {
5292
+ this._addedLineNumberBg = parsed;
5293
+ this.rebuildView();
5294
+ }
5295
+ }
5296
+ get removedLineNumberBg() {
5297
+ return this._removedLineNumberBg;
5298
+ }
5299
+ set removedLineNumberBg(value) {
5300
+ const parsed = parseColor(value);
5301
+ if (this._removedLineNumberBg !== parsed) {
5302
+ this._removedLineNumberBg = parsed;
5303
+ this.rebuildView();
5304
+ }
5305
+ }
5306
+ get lineNumberFg() {
5307
+ return this._lineNumberFg;
5308
+ }
5309
+ set lineNumberFg(value) {
5310
+ const parsed = parseColor(value);
5311
+ if (this._lineNumberFg !== parsed) {
5312
+ this._lineNumberFg = parsed;
5313
+ this.rebuildView();
5314
+ }
5315
+ }
5316
+ get lineNumberBg() {
5317
+ return this._lineNumberBg;
5318
+ }
5319
+ set lineNumberBg(value) {
5320
+ const parsed = parseColor(value);
5321
+ if (this._lineNumberBg !== parsed) {
5322
+ this._lineNumberBg = parsed;
5323
+ this.rebuildView();
5324
+ }
5325
+ }
5326
+ get addedContentBg() {
5327
+ return this._addedContentBg;
5328
+ }
5329
+ set addedContentBg(value) {
5330
+ const parsed = value ? parseColor(value) : null;
5331
+ if (this._addedContentBg !== parsed) {
5332
+ this._addedContentBg = parsed;
5333
+ this.rebuildView();
5334
+ }
5335
+ }
5336
+ get removedContentBg() {
5337
+ return this._removedContentBg;
5338
+ }
5339
+ set removedContentBg(value) {
5340
+ const parsed = value ? parseColor(value) : null;
5341
+ if (this._removedContentBg !== parsed) {
5342
+ this._removedContentBg = parsed;
5343
+ this.rebuildView();
5344
+ }
5345
+ }
5346
+ get contextContentBg() {
5347
+ return this._contextContentBg;
5348
+ }
5349
+ set contextContentBg(value) {
5350
+ const parsed = value ? parseColor(value) : null;
5351
+ if (this._contextContentBg !== parsed) {
5352
+ this._contextContentBg = parsed;
5353
+ this.rebuildView();
5354
+ }
5355
+ }
5356
+ get selectionBg() {
5357
+ return this._selectionBg;
5358
+ }
5359
+ set selectionBg(value) {
5360
+ const parsed = value ? parseColor(value) : undefined;
5361
+ if (this._selectionBg !== parsed) {
5362
+ this._selectionBg = parsed;
5363
+ if (this.leftCodeRenderable) {
5364
+ this.leftCodeRenderable.selectionBg = parsed;
5365
+ }
5366
+ if (this.rightCodeRenderable) {
5367
+ this.rightCodeRenderable.selectionBg = parsed;
5368
+ }
5369
+ }
5370
+ }
5371
+ get selectionFg() {
5372
+ return this._selectionFg;
5373
+ }
5374
+ set selectionFg(value) {
5375
+ const parsed = value ? parseColor(value) : undefined;
5376
+ if (this._selectionFg !== parsed) {
5377
+ this._selectionFg = parsed;
5378
+ if (this.leftCodeRenderable) {
5379
+ this.leftCodeRenderable.selectionFg = parsed;
5380
+ }
5381
+ if (this.rightCodeRenderable) {
5382
+ this.rightCodeRenderable.selectionFg = parsed;
5383
+ }
5384
+ }
5385
+ }
5386
+ }
5387
+ // src/renderables/Input.ts
5388
+ var InputRenderableEvents;
5389
+ ((InputRenderableEvents2) => {
5390
+ InputRenderableEvents2["INPUT"] = "input";
5391
+ InputRenderableEvents2["CHANGE"] = "change";
5392
+ InputRenderableEvents2["ENTER"] = "enter";
5393
+ })(InputRenderableEvents ||= {});
5394
+
5395
+ class InputRenderable extends Renderable {
5396
+ _focusable = true;
5397
+ _value = "";
5398
+ _cursorPosition = 0;
5399
+ _placeholder;
5400
+ _backgroundColor;
5401
+ _textColor;
5402
+ _focusedBackgroundColor;
5403
+ _focusedTextColor;
5404
+ _placeholderColor;
5405
+ _cursorColor;
5406
+ _cursorStyle;
5407
+ _maxLength;
5408
+ _lastCommittedValue = "";
5409
+ _defaultOptions = {
5410
+ backgroundColor: "transparent",
5411
+ textColor: "#FFFFFF",
5412
+ focusedBackgroundColor: "#1a1a1a",
5413
+ focusedTextColor: "#FFFFFF",
5414
+ placeholder: "",
5415
+ placeholderColor: "#666666",
5416
+ cursorColor: "#FFFFFF",
5417
+ cursorStyle: {
5418
+ style: "block",
5419
+ blinking: true
5420
+ },
5421
+ maxLength: 1000,
5422
+ value: ""
5423
+ };
5424
+ constructor(ctx, options) {
5425
+ super(ctx, { ...options, buffered: true });
5426
+ this._backgroundColor = parseColor(options.backgroundColor || this._defaultOptions.backgroundColor);
5427
+ this._textColor = parseColor(options.textColor || this._defaultOptions.textColor);
5428
+ this._focusedBackgroundColor = parseColor(options.focusedBackgroundColor || options.backgroundColor || this._defaultOptions.focusedBackgroundColor);
5429
+ this._focusedTextColor = parseColor(options.focusedTextColor || options.textColor || this._defaultOptions.focusedTextColor);
5430
+ this._placeholder = options.placeholder || this._defaultOptions.placeholder;
5431
+ this._value = options.value || this._defaultOptions.value;
5432
+ this._lastCommittedValue = this._value;
5433
+ this._cursorPosition = this._value.length;
5434
+ this._maxLength = options.maxLength || this._defaultOptions.maxLength;
5435
+ this._placeholderColor = parseColor(options.placeholderColor || this._defaultOptions.placeholderColor);
5436
+ this._cursorColor = parseColor(options.cursorColor || this._defaultOptions.cursorColor);
5437
+ this._cursorStyle = options.cursorStyle || this._defaultOptions.cursorStyle;
5438
+ }
5439
+ updateCursorPosition() {
5440
+ if (!this._focused)
5441
+ return;
5442
+ const contentX = 0;
5443
+ const contentY = 0;
5444
+ const contentWidth = this.width;
5445
+ const maxVisibleChars = contentWidth - 1;
5446
+ let displayStartIndex = 0;
5447
+ if (this._cursorPosition >= maxVisibleChars) {
5448
+ displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
5449
+ }
5450
+ const cursorDisplayX = this._cursorPosition - displayStartIndex;
5451
+ if (cursorDisplayX >= 0 && cursorDisplayX < contentWidth) {
5452
+ const absoluteCursorX = this.x + contentX + cursorDisplayX + 1;
5453
+ const absoluteCursorY = this.y + contentY + 1;
5454
+ this._ctx.setCursorPosition(absoluteCursorX, absoluteCursorY, true);
5455
+ this._ctx.setCursorColor(this._cursorColor);
5456
+ }
5457
+ }
5458
+ focus() {
5459
+ super.focus();
5460
+ this._ctx.setCursorStyle(this._cursorStyle.style, this._cursorStyle.blinking);
5461
+ this._ctx.setCursorColor(this._cursorColor);
5462
+ this.updateCursorPosition();
5463
+ }
5464
+ blur() {
5465
+ super.blur();
5466
+ this._ctx.setCursorPosition(0, 0, false);
5467
+ if (this._value !== this._lastCommittedValue) {
5468
+ this._lastCommittedValue = this._value;
5469
+ this.emit("change" /* CHANGE */, this._value);
5470
+ }
5471
+ }
5472
+ renderSelf(buffer, deltaTime) {
5473
+ if (!this.visible || !this.frameBuffer)
5474
+ return;
5475
+ if (this.isDirty) {
5476
+ this.refreshFrameBuffer();
5477
+ }
5478
+ }
5479
+ refreshFrameBuffer() {
5480
+ if (!this.frameBuffer)
5481
+ return;
5482
+ const bgColor = this._focused ? this._focusedBackgroundColor : this._backgroundColor;
5483
+ this.frameBuffer.clear(bgColor);
5484
+ const contentX = 0;
5485
+ const contentY = 0;
5486
+ const contentWidth = this.width;
5487
+ const contentHeight = this.height;
5488
+ const displayText = this._value || this._placeholder;
5489
+ const isPlaceholder = !this._value && this._placeholder;
5490
+ const baseTextColor = this._focused ? this._focusedTextColor : this._textColor;
5491
+ const textColor = isPlaceholder ? this._placeholderColor : baseTextColor;
5492
+ const maxVisibleChars = contentWidth - 1;
5493
+ let displayStartIndex = 0;
5494
+ if (this._cursorPosition >= maxVisibleChars) {
5495
+ displayStartIndex = this._cursorPosition - maxVisibleChars + 1;
5496
+ }
5497
+ const visibleText = displayText.substring(displayStartIndex, displayStartIndex + maxVisibleChars);
5498
+ if (visibleText) {
5499
+ this.frameBuffer.drawText(visibleText, contentX, contentY, textColor);
5500
+ }
5501
+ if (this._focused) {
5502
+ this.updateCursorPosition();
5503
+ }
5504
+ }
5505
+ get value() {
5506
+ return this._value;
5507
+ }
5508
+ set value(value) {
5509
+ const newValue = value.substring(0, this._maxLength);
5510
+ if (this._value !== newValue) {
5511
+ this._value = newValue;
5512
+ this._cursorPosition = Math.min(this._cursorPosition, this._value.length);
5513
+ this.requestRender();
5514
+ this.updateCursorPosition();
5515
+ this.emit("input" /* INPUT */, this._value);
5516
+ }
5517
+ }
5518
+ set placeholder(placeholder) {
5519
+ if (this._placeholder !== placeholder) {
5520
+ this._placeholder = placeholder;
5521
+ this.requestRender();
5522
+ }
5523
+ }
5524
+ get cursorPosition() {
5525
+ return this._cursorPosition;
5526
+ }
5527
+ set cursorPosition(position) {
5528
+ const newPosition = Math.max(0, Math.min(position, this._value.length));
5529
+ if (this._cursorPosition !== newPosition) {
5530
+ this._cursorPosition = newPosition;
5531
+ this.requestRender();
5532
+ this.updateCursorPosition();
5533
+ }
5534
+ }
5535
+ insertText(text) {
5536
+ if (this._value.length + text.length > this._maxLength) {
5537
+ return;
5538
+ }
5539
+ const beforeCursor = this._value.substring(0, this._cursorPosition);
5540
+ const afterCursor = this._value.substring(this._cursorPosition);
5541
+ this._value = beforeCursor + text + afterCursor;
5542
+ this._cursorPosition += text.length;
5543
+ this.requestRender();
5544
+ this.updateCursorPosition();
5545
+ this.emit("input" /* INPUT */, this._value);
5546
+ }
5547
+ deleteCharacter(direction) {
5548
+ if (direction === "backward" && this._cursorPosition > 0) {
5549
+ const beforeCursor = this._value.substring(0, this._cursorPosition - 1);
5550
+ const afterCursor = this._value.substring(this._cursorPosition);
3347
5551
  this._value = beforeCursor + afterCursor;
3348
5552
  this._cursorPosition--;
3349
5553
  this.requestRender();
@@ -5263,101 +7467,6 @@ class TabSelectRenderable extends Renderable {
5263
7467
  this.requestRender();
5264
7468
  }
5265
7469
  }
5266
- // src/renderables/Text.ts
5267
- class TextRenderable extends TextBufferRenderable {
5268
- _text;
5269
- _hasManualStyledText = false;
5270
- rootTextNode;
5271
- _contentDefaultOptions = {
5272
- content: ""
5273
- };
5274
- constructor(ctx, options) {
5275
- super(ctx, options);
5276
- const content = options.content ?? this._contentDefaultOptions.content;
5277
- const styledText = typeof content === "string" ? stringToStyledText(content) : content;
5278
- this._text = styledText;
5279
- this._hasManualStyledText = options.content !== undefined && content !== "";
5280
- this.rootTextNode = new RootTextNodeRenderable(ctx, {
5281
- id: `${this.id}-root`,
5282
- fg: this._defaultFg,
5283
- bg: this._defaultBg,
5284
- attributes: this._defaultAttributes
5285
- }, this);
5286
- this.updateTextBuffer(styledText);
5287
- }
5288
- updateTextBuffer(styledText) {
5289
- this.textBuffer.setStyledText(styledText);
5290
- this.clearChunks(styledText);
5291
- }
5292
- clearChunks(styledText) {}
5293
- get content() {
5294
- return this._text;
5295
- }
5296
- get chunks() {
5297
- return this._text.chunks;
5298
- }
5299
- get textNode() {
5300
- return this.rootTextNode;
5301
- }
5302
- set content(value) {
5303
- this._hasManualStyledText = true;
5304
- const styledText = typeof value === "string" ? stringToStyledText(value) : value;
5305
- if (this._text !== styledText) {
5306
- this._text = styledText;
5307
- this.updateTextBuffer(styledText);
5308
- this.updateTextInfo();
5309
- }
5310
- }
5311
- updateTextFromNodes() {
5312
- if (this.rootTextNode.isDirty && !this._hasManualStyledText) {
5313
- const chunks = this.rootTextNode.gatherWithInheritedStyle({
5314
- fg: this._defaultFg,
5315
- bg: this._defaultBg,
5316
- attributes: this._defaultAttributes
5317
- });
5318
- this.textBuffer.setStyledText(new StyledText(chunks));
5319
- this.refreshLocalSelection();
5320
- this.yogaNode.markDirty();
5321
- }
5322
- }
5323
- add(obj, index) {
5324
- return this.rootTextNode.add(obj, index);
5325
- }
5326
- remove(id) {
5327
- this.rootTextNode.remove(id);
5328
- }
5329
- insertBefore(obj, anchor) {
5330
- this.rootTextNode.insertBefore(obj, anchor);
5331
- return this.rootTextNode.children.indexOf(obj);
5332
- }
5333
- getTextChildren() {
5334
- return this.rootTextNode.getChildren();
5335
- }
5336
- clear() {
5337
- this.rootTextNode.clear();
5338
- const emptyStyledText = stringToStyledText("");
5339
- this._text = emptyStyledText;
5340
- this.updateTextBuffer(emptyStyledText);
5341
- this.updateTextInfo();
5342
- this.requestRender();
5343
- }
5344
- onLifecyclePass = () => {
5345
- this.updateTextFromNodes();
5346
- };
5347
- onFgChanged(newColor) {
5348
- this.rootTextNode.fg = newColor;
5349
- }
5350
- onBgChanged(newColor) {
5351
- this.rootTextNode.bg = newColor;
5352
- }
5353
- onAttributesChanged(newAttributes) {
5354
- this.rootTextNode.attributes = newAttributes;
5355
- }
5356
- destroy() {
5357
- this.rootTextNode.children.length = 0;
5358
- super.destroy();
5359
- }
5360
- }
5361
7470
  // src/renderables/EditBufferRenderable.ts
5362
7471
  class EditBufferRenderable extends Renderable {
5363
7472
  _focusable = true;
@@ -5375,6 +7484,7 @@ class EditBufferRenderable extends Renderable {
5375
7484
  lastLocalSelection = null;
5376
7485
  _tabIndicator;
5377
7486
  _tabIndicatorColor;
7487
+ _selectionAnchorState = null;
5378
7488
  _cursorChangeListener = undefined;
5379
7489
  _contentChangeListener = undefined;
5380
7490
  editBuffer;
@@ -5431,6 +7541,9 @@ class EditBufferRenderable extends Renderable {
5431
7541
  this.setupMeasureFunc();
5432
7542
  this.setupEventListeners(options);
5433
7543
  }
7544
+ get lineInfo() {
7545
+ return this.editorView.getLogicalLineInfo();
7546
+ }
5434
7547
  setupEventListeners(options) {
5435
7548
  this._cursorChangeListener = options.onCursorChange;
5436
7549
  this._contentChangeListener = options.onContentChange;
@@ -5446,11 +7559,18 @@ class EditBufferRenderable extends Renderable {
5446
7559
  this.editBuffer.on("content-changed", () => {
5447
7560
  this.yogaNode.markDirty();
5448
7561
  this.requestRender();
7562
+ this.emit("line-info-change");
5449
7563
  if (this._contentChangeListener) {
5450
7564
  this._contentChangeListener({});
5451
7565
  }
5452
7566
  });
5453
7567
  }
7568
+ get lineCount() {
7569
+ return this.editBuffer.getLineCount();
7570
+ }
7571
+ get scrollY() {
7572
+ return this.editorView.getViewport().offsetY;
7573
+ }
5454
7574
  get plainText() {
5455
7575
  return this.editBuffer.getText();
5456
7576
  }
@@ -5643,19 +7763,25 @@ class EditBufferRenderable extends Renderable {
5643
7763
  }
5644
7764
  setupMeasureFunc() {
5645
7765
  const measureFunc = (width, widthMode, height, heightMode) => {
5646
- const effectiveHeight = isNaN(height) ? 1 : height;
5647
- const effectiveWidth = isNaN(width) ? 1 : width;
5648
- if (this._wrapMode !== "none" && this.width !== effectiveWidth) {
5649
- this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
7766
+ let effectiveWidth;
7767
+ if (widthMode === MeasureMode.Undefined || isNaN(width)) {
7768
+ effectiveWidth = 0;
5650
7769
  } else {
5651
- this.editorView.setViewportSize(effectiveWidth, effectiveHeight);
7770
+ effectiveWidth = width;
7771
+ }
7772
+ const effectiveHeight = isNaN(height) ? 1 : height;
7773
+ const measureResult = this.editorView.measureForDimensions(Math.floor(effectiveWidth), Math.floor(effectiveHeight));
7774
+ const measuredWidth = measureResult ? Math.max(1, measureResult.maxWidth) : 1;
7775
+ const measuredHeight = measureResult ? Math.max(1, measureResult.lineCount) : 1;
7776
+ if (widthMode === MeasureMode.AtMost && this._positionType !== "absolute") {
7777
+ return {
7778
+ width: Math.min(effectiveWidth, measuredWidth),
7779
+ height: Math.min(effectiveHeight, measuredHeight)
7780
+ };
5652
7781
  }
5653
- const lineInfo = this.editorView.getLogicalLineInfo();
5654
- const measuredWidth = lineInfo.maxLineWidth;
5655
- const measuredHeight = lineInfo.lineStarts.length;
5656
7782
  return {
5657
- width: Math.max(1, measuredWidth),
5658
- height: Math.max(1, measuredHeight)
7783
+ width: measuredWidth,
7784
+ height: measuredHeight
5659
7785
  };
5660
7786
  };
5661
7787
  this.yogaNode.setMeasureFunc(measureFunc);
@@ -5776,6 +7902,55 @@ class EditBufferRenderable extends Renderable {
5776
7902
  getTextRangeByCoords(startRow, startCol, endRow, endCol) {
5777
7903
  return this.editBuffer.getTextRangeByCoords(startRow, startCol, endRow, endCol);
5778
7904
  }
7905
+ updateSelectionForMovement(shiftPressed, isBeforeMovement) {
7906
+ if (!this.selectable)
7907
+ return;
7908
+ if (!shiftPressed) {
7909
+ this._ctx.clearSelection();
7910
+ this._selectionAnchorState = null;
7911
+ return;
7912
+ }
7913
+ const visualCursor = this.editorView.getVisualCursor();
7914
+ const viewport = this.editorView.getViewport();
7915
+ const cursorX = this.x + visualCursor.visualCol;
7916
+ const cursorY = this.y + visualCursor.visualRow;
7917
+ if (isBeforeMovement) {
7918
+ if (!this._ctx.hasSelection) {
7919
+ this._ctx.startSelection(this, cursorX, cursorY);
7920
+ this._selectionAnchorState = {
7921
+ screenX: cursorX,
7922
+ screenY: cursorY,
7923
+ viewportX: viewport.offsetX,
7924
+ viewportY: viewport.offsetY
7925
+ };
7926
+ } else if (!this._selectionAnchorState) {
7927
+ const selection = this._ctx.getSelection();
7928
+ if (selection && selection.isActive) {
7929
+ this._selectionAnchorState = {
7930
+ screenX: selection.anchor.x,
7931
+ screenY: selection.anchor.y,
7932
+ viewportX: viewport.offsetX,
7933
+ viewportY: viewport.offsetY
7934
+ };
7935
+ }
7936
+ }
7937
+ } else {
7938
+ if (this._selectionAnchorState) {
7939
+ const deltaY = viewport.offsetY - this._selectionAnchorState.viewportY;
7940
+ const deltaX = viewport.offsetX - this._selectionAnchorState.viewportX;
7941
+ if (deltaY !== 0 || deltaX !== 0) {
7942
+ const newAnchorX = this._selectionAnchorState.screenX - deltaX;
7943
+ const newAnchorY = this._selectionAnchorState.screenY - deltaY;
7944
+ this._ctx.startSelection(this, newAnchorX, newAnchorY);
7945
+ this._ctx.updateSelection(this, cursorX, cursorY);
7946
+ } else {
7947
+ this._ctx.updateSelection(this, cursorX, cursorY);
7948
+ }
7949
+ } else {
7950
+ this._ctx.updateSelection(this, cursorX, cursorY);
7951
+ }
7952
+ }
7953
+ }
5779
7954
  }
5780
7955
 
5781
7956
  // src/lib/keymapping.ts
@@ -5813,12 +7988,12 @@ var defaultTextareaKeybindings = [
5813
7988
  { name: "right", shift: true, action: "select-right" },
5814
7989
  { name: "up", shift: true, action: "select-up" },
5815
7990
  { name: "down", shift: true, action: "select-down" },
5816
- { name: "home", action: "line-home" },
5817
- { name: "end", action: "line-end" },
5818
- { name: "home", shift: true, action: "select-line-home" },
5819
- { name: "end", shift: true, action: "select-line-end" },
5820
- { name: "a", ctrl: true, action: "buffer-home" },
5821
- { name: "e", ctrl: true, action: "buffer-end" },
7991
+ { name: "home", action: "buffer-home" },
7992
+ { name: "end", action: "buffer-end" },
7993
+ { name: "home", shift: true, action: "select-buffer-home" },
7994
+ { name: "end", shift: true, action: "select-buffer-end" },
7995
+ { name: "a", ctrl: true, action: "line-home" },
7996
+ { name: "e", ctrl: true, action: "line-end" },
5822
7997
  { name: "f", ctrl: true, action: "move-right" },
5823
7998
  { name: "b", ctrl: true, action: "move-left" },
5824
7999
  { name: "d", ctrl: true, action: "delete-word-forward" },
@@ -5916,6 +8091,8 @@ class TextareaRenderable extends EditBufferRenderable {
5916
8091
  ["line-end", () => this.gotoLineEnd()],
5917
8092
  ["select-line-home", () => this.gotoLineHome({ select: true })],
5918
8093
  ["select-line-end", () => this.gotoLineEnd({ select: true })],
8094
+ ["select-buffer-home", () => this.gotoBufferHome({ select: true })],
8095
+ ["select-buffer-end", () => this.gotoBufferEnd({ select: true })],
5919
8096
  ["buffer-home", () => this.gotoBufferHome()],
5920
8097
  ["buffer-end", () => this.gotoBufferEnd()],
5921
8098
  ["delete-line", () => this.deleteLine()],
@@ -6032,33 +8209,33 @@ class TextareaRenderable extends EditBufferRenderable {
6032
8209
  }
6033
8210
  moveCursorLeft(options) {
6034
8211
  const select = options?.select ?? false;
6035
- this.handleShiftSelection(select, true);
8212
+ this.updateSelectionForMovement(select, true);
6036
8213
  this.editBuffer.moveCursorLeft();
6037
- this.handleShiftSelection(select, false);
8214
+ this.updateSelectionForMovement(select, false);
6038
8215
  this.requestRender();
6039
8216
  return true;
6040
8217
  }
6041
8218
  moveCursorRight(options) {
6042
8219
  const select = options?.select ?? false;
6043
- this.handleShiftSelection(select, true);
8220
+ this.updateSelectionForMovement(select, true);
6044
8221
  this.editBuffer.moveCursorRight();
6045
- this.handleShiftSelection(select, false);
8222
+ this.updateSelectionForMovement(select, false);
6046
8223
  this.requestRender();
6047
8224
  return true;
6048
8225
  }
6049
8226
  moveCursorUp(options) {
6050
8227
  const select = options?.select ?? false;
6051
- this.handleShiftSelection(select, true);
8228
+ this.updateSelectionForMovement(select, true);
6052
8229
  this.editorView.moveUpVisual();
6053
- this.handleShiftSelection(select, false);
8230
+ this.updateSelectionForMovement(select, false);
6054
8231
  this.requestRender();
6055
8232
  return true;
6056
8233
  }
6057
8234
  moveCursorDown(options) {
6058
8235
  const select = options?.select ?? false;
6059
- this.handleShiftSelection(select, true);
8236
+ this.updateSelectionForMovement(select, true);
6060
8237
  this.editorView.moveDownVisual();
6061
- this.handleShiftSelection(select, false);
8238
+ this.updateSelectionForMovement(select, false);
6062
8239
  this.requestRender();
6063
8240
  return true;
6064
8241
  }
@@ -6068,29 +8245,35 @@ class TextareaRenderable extends EditBufferRenderable {
6068
8245
  }
6069
8246
  gotoLineHome(options) {
6070
8247
  const select = options?.select ?? false;
6071
- this.handleShiftSelection(select, true);
8248
+ this.updateSelectionForMovement(select, true);
6072
8249
  const cursor = this.editorView.getCursor();
6073
8250
  this.editBuffer.setCursor(cursor.row, 0);
6074
- this.handleShiftSelection(select, false);
8251
+ this.updateSelectionForMovement(select, false);
6075
8252
  this.requestRender();
6076
8253
  return true;
6077
8254
  }
6078
8255
  gotoLineEnd(options) {
6079
8256
  const select = options?.select ?? false;
6080
- this.handleShiftSelection(select, true);
8257
+ this.updateSelectionForMovement(select, true);
6081
8258
  const eol = this.editBuffer.getEOL();
6082
8259
  this.editBuffer.setCursor(eol.row, eol.col);
6083
- this.handleShiftSelection(select, false);
8260
+ this.updateSelectionForMovement(select, false);
6084
8261
  this.requestRender();
6085
8262
  return true;
6086
8263
  }
6087
- gotoBufferHome() {
8264
+ gotoBufferHome(options) {
8265
+ const select = options?.select ?? false;
8266
+ this.updateSelectionForMovement(select, true);
6088
8267
  this.editBuffer.setCursor(0, 0);
8268
+ this.updateSelectionForMovement(select, false);
6089
8269
  this.requestRender();
6090
8270
  return true;
6091
8271
  }
6092
- gotoBufferEnd() {
8272
+ gotoBufferEnd(options) {
8273
+ const select = options?.select ?? false;
8274
+ this.updateSelectionForMovement(select, true);
6093
8275
  this.editBuffer.gotoLine(999999);
8276
+ this.updateSelectionForMovement(select, false);
6094
8277
  this.requestRender();
6095
8278
  return true;
6096
8279
  }
@@ -6125,19 +8308,19 @@ class TextareaRenderable extends EditBufferRenderable {
6125
8308
  }
6126
8309
  moveWordForward(options) {
6127
8310
  const select = options?.select ?? false;
6128
- this.handleShiftSelection(select, true);
8311
+ this.updateSelectionForMovement(select, true);
6129
8312
  const nextWord = this.editBuffer.getNextWordBoundary();
6130
8313
  this.editBuffer.setCursorByOffset(nextWord.offset);
6131
- this.handleShiftSelection(select, false);
8314
+ this.updateSelectionForMovement(select, false);
6132
8315
  this.requestRender();
6133
8316
  return true;
6134
8317
  }
6135
8318
  moveWordBackward(options) {
6136
8319
  const select = options?.select ?? false;
6137
- this.handleShiftSelection(select, true);
8320
+ this.updateSelectionForMovement(select, true);
6138
8321
  const prevWord = this.editBuffer.getPrevWordBoundary();
6139
8322
  this.editBuffer.setCursorByOffset(prevWord.offset);
6140
- this.handleShiftSelection(select, false);
8323
+ this.updateSelectionForMovement(select, false);
6141
8324
  this.requestRender();
6142
8325
  return true;
6143
8326
  }
@@ -6169,24 +8352,6 @@ class TextareaRenderable extends EditBufferRenderable {
6169
8352
  this.requestRender();
6170
8353
  return true;
6171
8354
  }
6172
- handleShiftSelection(shiftPressed, isBeforeMovement) {
6173
- if (!this.selectable)
6174
- return;
6175
- if (!shiftPressed) {
6176
- this._ctx.clearSelection();
6177
- return;
6178
- }
6179
- const visualCursor = this.editorView.getVisualCursor();
6180
- const cursorX = this.x + visualCursor.visualCol;
6181
- const cursorY = this.y + visualCursor.visualRow;
6182
- if (isBeforeMovement) {
6183
- if (!this._ctx.hasSelection) {
6184
- this._ctx.startSelection(this, cursorX, cursorY);
6185
- }
6186
- } else {
6187
- this._ctx.updateSelection(this, cursorX, cursorY);
6188
- }
6189
- }
6190
8355
  focus() {
6191
8356
  super.focus();
6192
8357
  this.updateColors();
@@ -6416,6 +8581,7 @@ export {
6416
8581
  MacOSScrollAccel,
6417
8582
  LogLevel,
6418
8583
  LinearScrollAccel,
8584
+ LineNumberRenderable,
6419
8585
  LayoutEvents,
6420
8586
  KeyHandler,
6421
8587
  KeyEvent,
@@ -6430,6 +8596,7 @@ export {
6430
8596
  EditorView,
6431
8597
  EditBuffer,
6432
8598
  DistortionEffect,
8599
+ DiffRenderable,
6433
8600
  DebugOverlayCorner,
6434
8601
  DataPathsManager,
6435
8602
  ConsolePosition,
@@ -6450,5 +8617,5 @@ export {
6450
8617
  ASCIIFont
6451
8618
  };
6452
8619
 
6453
- //# debugId=96ABDB71AC96072A64756E2164756E21
8620
+ //# debugId=61DC3DAACFF9549264756E2164756E21
6454
8621
  //# sourceMappingURL=index.js.map