@opentui/core 0.0.0-20251106-788e97e4 → 0.0.0-20251108-0c7899b1

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
@@ -136,7 +136,7 @@ import {
136
136
  white,
137
137
  wrapWithDelegates,
138
138
  yellow
139
- } from "./index-pb1pm3hk.js";
139
+ } from "./index-z5bb2h2z.js";
140
140
  // src/text-buffer-view.ts
141
141
  class TextBufferView {
142
142
  lib;
@@ -2661,9 +2661,8 @@ class CodeRenderable extends TextBufferRenderable {
2661
2661
  _syntaxStyle;
2662
2662
  _isHighlighting = false;
2663
2663
  _treeSitterClient;
2664
- _pendingRehighlight = false;
2665
- _pendingUpdate = false;
2666
- _currentHighlightId = 0;
2664
+ _highlightsDirty = false;
2665
+ _highlightSnapshotId = 0;
2667
2666
  _conceal;
2668
2667
  _drawUnstyledText;
2669
2668
  _shouldRenderTextBuffer = true;
@@ -2685,7 +2684,7 @@ class CodeRenderable extends TextBufferRenderable {
2685
2684
  this._conceal = options.conceal ?? this._contentDefaultOptions.conceal;
2686
2685
  this._drawUnstyledText = options.drawUnstyledText ?? this._contentDefaultOptions.drawUnstyledText;
2687
2686
  this._streaming = options.streaming ?? this._contentDefaultOptions.streaming;
2688
- this.updateContent(this._content);
2687
+ this._highlightsDirty = this._content.length > 0;
2689
2688
  }
2690
2689
  get content() {
2691
2690
  return this._content;
@@ -2693,7 +2692,7 @@ class CodeRenderable extends TextBufferRenderable {
2693
2692
  set content(value) {
2694
2693
  if (this._content !== value) {
2695
2694
  this._content = value;
2696
- this.scheduleUpdate();
2695
+ this._highlightsDirty = true;
2697
2696
  }
2698
2697
  }
2699
2698
  get filetype() {
@@ -2702,7 +2701,7 @@ class CodeRenderable extends TextBufferRenderable {
2702
2701
  set filetype(value) {
2703
2702
  if (this._filetype !== value) {
2704
2703
  this._filetype = value;
2705
- this.scheduleUpdate();
2704
+ this._highlightsDirty = true;
2706
2705
  }
2707
2706
  }
2708
2707
  get syntaxStyle() {
@@ -2711,7 +2710,7 @@ class CodeRenderable extends TextBufferRenderable {
2711
2710
  set syntaxStyle(value) {
2712
2711
  if (this._syntaxStyle !== value) {
2713
2712
  this._syntaxStyle = value;
2714
- this.scheduleUpdate();
2713
+ this._highlightsDirty = true;
2715
2714
  }
2716
2715
  }
2717
2716
  get conceal() {
@@ -2720,7 +2719,7 @@ class CodeRenderable extends TextBufferRenderable {
2720
2719
  set conceal(value) {
2721
2720
  if (this._conceal !== value) {
2722
2721
  this._conceal = value;
2723
- this.scheduleUpdate();
2722
+ this._highlightsDirty = true;
2724
2723
  }
2725
2724
  }
2726
2725
  get drawUnstyledText() {
@@ -2729,7 +2728,7 @@ class CodeRenderable extends TextBufferRenderable {
2729
2728
  set drawUnstyledText(value) {
2730
2729
  if (this._drawUnstyledText !== value) {
2731
2730
  this._drawUnstyledText = value;
2732
- this.scheduleUpdate();
2731
+ this._highlightsDirty = true;
2733
2732
  }
2734
2733
  }
2735
2734
  get streaming() {
@@ -2740,7 +2739,7 @@ class CodeRenderable extends TextBufferRenderable {
2740
2739
  this._streaming = value;
2741
2740
  this._hadInitialContent = false;
2742
2741
  this._lastHighlights = [];
2743
- this.scheduleUpdate();
2742
+ this._highlightsDirty = true;
2744
2743
  }
2745
2744
  }
2746
2745
  get treeSitterClient() {
@@ -2749,53 +2748,66 @@ class CodeRenderable extends TextBufferRenderable {
2749
2748
  set treeSitterClient(value) {
2750
2749
  if (this._treeSitterClient !== value) {
2751
2750
  this._treeSitterClient = value;
2752
- this.scheduleUpdate();
2751
+ this._highlightsDirty = true;
2753
2752
  }
2754
2753
  }
2755
- scheduleUpdate() {
2756
- if (this._pendingUpdate)
2757
- return;
2758
- this._pendingUpdate = true;
2759
- queueMicrotask(() => {
2760
- this._pendingUpdate = false;
2761
- this.updateContent(this._content);
2762
- });
2763
- }
2764
- async updateContent(content) {
2765
- if (content.length === 0)
2766
- return;
2754
+ ensureVisibleTextBeforeHighlight() {
2755
+ const content = this._content;
2767
2756
  if (!this._filetype) {
2768
- this.fallback(content);
2757
+ if (this.isDestroyed)
2758
+ return;
2759
+ this.textBuffer.setText(content);
2769
2760
  this._shouldRenderTextBuffer = true;
2761
+ this.updateTextInfo();
2770
2762
  return;
2771
2763
  }
2772
- this._currentHighlightId++;
2773
- const highlightId = this._currentHighlightId;
2774
2764
  const isInitialContent = this._streaming && !this._hadInitialContent;
2775
- if (isInitialContent) {
2776
- this._hadInitialContent = true;
2777
- }
2778
2765
  const shouldDrawUnstyledNow = this._streaming ? isInitialContent && this._drawUnstyledText : this._drawUnstyledText;
2779
- this.fallback(content);
2780
- if (!shouldDrawUnstyledNow) {
2781
- this._shouldRenderTextBuffer = false;
2782
- }
2783
- if (this._streaming && !isInitialContent && this._lastHighlights.length > 0) {
2784
- const chunks = treeSitterToTextChunks(content, this._lastHighlights, this._syntaxStyle, {
2785
- enabled: this._conceal
2786
- });
2787
- const partialStyledText = new StyledText(chunks);
2766
+ if (this._streaming && !isInitialContent) {
2767
+ if (this._lastHighlights.length > 0) {
2768
+ const chunks = treeSitterToTextChunks(content, this._lastHighlights, this._syntaxStyle, {
2769
+ enabled: this._conceal
2770
+ });
2771
+ const partialStyledText = new StyledText(chunks);
2772
+ if (this.isDestroyed)
2773
+ return;
2774
+ this.textBuffer.setStyledText(partialStyledText);
2775
+ this._shouldRenderTextBuffer = true;
2776
+ this.updateTextInfo();
2777
+ } else {
2778
+ if (this.isDestroyed)
2779
+ return;
2780
+ this.textBuffer.setText(content);
2781
+ this._shouldRenderTextBuffer = true;
2782
+ this.updateTextInfo();
2783
+ }
2784
+ } else if (shouldDrawUnstyledNow) {
2788
2785
  if (this.isDestroyed)
2789
2786
  return;
2790
- this.textBuffer.setStyledText(partialStyledText);
2787
+ this.textBuffer.setText(content);
2791
2788
  this._shouldRenderTextBuffer = true;
2792
2789
  this.updateTextInfo();
2790
+ } else {
2791
+ if (this.isDestroyed)
2792
+ return;
2793
+ this._shouldRenderTextBuffer = false;
2794
+ this.updateTextInfo();
2795
+ }
2796
+ }
2797
+ async startHighlight() {
2798
+ const content = this._content;
2799
+ const filetype = this._filetype;
2800
+ const snapshotId = ++this._highlightSnapshotId;
2801
+ if (!filetype)
2802
+ return;
2803
+ const isInitialContent = this._streaming && !this._hadInitialContent;
2804
+ if (isInitialContent) {
2805
+ this._hadInitialContent = true;
2793
2806
  }
2794
2807
  this._isHighlighting = true;
2795
- this._pendingRehighlight = false;
2796
2808
  try {
2797
- const result = await this._treeSitterClient.highlightOnce(content, this._filetype);
2798
- if (highlightId !== this._currentHighlightId) {
2809
+ const result = await this._treeSitterClient.highlightOnce(content, filetype);
2810
+ if (snapshotId !== this._highlightSnapshotId) {
2799
2811
  return;
2800
2812
  }
2801
2813
  if (this.isDestroyed)
@@ -2810,46 +2822,53 @@ class CodeRenderable extends TextBufferRenderable {
2810
2822
  const styledText = new StyledText(chunks);
2811
2823
  this.textBuffer.setStyledText(styledText);
2812
2824
  } else {
2813
- this.fallback(content);
2825
+ this.textBuffer.setText(content);
2814
2826
  }
2815
2827
  this._shouldRenderTextBuffer = true;
2816
2828
  this.updateTextInfo();
2829
+ this._isHighlighting = false;
2830
+ this._highlightsDirty = false;
2831
+ this.requestRender();
2817
2832
  } catch (error) {
2818
- if (highlightId !== this._currentHighlightId) {
2833
+ if (snapshotId !== this._highlightSnapshotId) {
2819
2834
  return;
2820
2835
  }
2821
2836
  console.warn("Code highlighting failed, falling back to plain text:", error);
2822
- this.fallback(content);
2837
+ if (this.isDestroyed)
2838
+ return;
2839
+ this.textBuffer.setText(content);
2823
2840
  this._shouldRenderTextBuffer = true;
2824
- } finally {
2825
- if (highlightId === this._currentHighlightId) {
2826
- this._isHighlighting = false;
2827
- }
2841
+ this.updateTextInfo();
2842
+ this._isHighlighting = false;
2843
+ this._highlightsDirty = false;
2844
+ this.requestRender();
2828
2845
  }
2829
2846
  }
2830
- fallback(content) {
2831
- const fallbackStyledText = this.createFallbackStyledText(content);
2832
- if (this.isDestroyed)
2833
- return;
2834
- this.textBuffer.setStyledText(fallbackStyledText);
2835
- this.updateTextInfo();
2836
- }
2837
- createFallbackStyledText(content) {
2838
- const chunks = [
2839
- {
2840
- __isChunk: true,
2841
- text: content,
2842
- fg: this._defaultFg,
2843
- bg: this._defaultBg,
2844
- attributes: this._defaultAttributes
2845
- }
2846
- ];
2847
- return new StyledText(chunks);
2848
- }
2849
2847
  getLineHighlights(lineIdx) {
2850
2848
  return this.textBuffer.getLineHighlights(lineIdx);
2851
2849
  }
2852
2850
  renderSelf(buffer) {
2851
+ if (this._highlightsDirty) {
2852
+ if (this._content.length === 0) {
2853
+ if (this.isDestroyed)
2854
+ return;
2855
+ this.textBuffer.setText("");
2856
+ this._shouldRenderTextBuffer = false;
2857
+ this._highlightsDirty = false;
2858
+ this.updateTextInfo();
2859
+ } else if (!this._filetype) {
2860
+ if (this.isDestroyed)
2861
+ return;
2862
+ this.textBuffer.setText(this._content);
2863
+ this._shouldRenderTextBuffer = true;
2864
+ this._highlightsDirty = false;
2865
+ this.updateTextInfo();
2866
+ } else {
2867
+ this.ensureVisibleTextBeforeHighlight();
2868
+ this._highlightsDirty = false;
2869
+ this.startHighlight();
2870
+ }
2871
+ }
2853
2872
  if (!this._shouldRenderTextBuffer)
2854
2873
  return;
2855
2874
  super.renderSelf(buffer);
@@ -4046,11 +4065,11 @@ class ContentRenderable extends BoxRenderable {
4046
4065
  set viewportCulling(value) {
4047
4066
  this._viewportCulling = value;
4048
4067
  }
4049
- _getChildren() {
4068
+ _getVisibleChildren() {
4050
4069
  if (this._viewportCulling) {
4051
- return getObjectsInViewport(this.viewport, this.getChildrenSortedByPrimaryAxis(), this.primaryAxis);
4070
+ return getObjectsInViewport(this.viewport, this.getChildrenSortedByPrimaryAxis(), this.primaryAxis).map((child) => child.num);
4052
4071
  }
4053
- return this.getChildrenSortedByPrimaryAxis();
4072
+ return this.getChildrenSortedByPrimaryAxis().map((child) => child.num);
4054
4073
  }
4055
4074
  }
4056
4075
 
@@ -4082,6 +4101,7 @@ class ScrollBoxRenderable extends BoxRenderable {
4082
4101
  _stickyScrollRight = false;
4083
4102
  _stickyStart;
4084
4103
  _hasManualScroll = false;
4104
+ _isApplyingStickyScroll = false;
4085
4105
  scrollAccel;
4086
4106
  get stickyScroll() {
4087
4107
  return this._stickyScroll;
@@ -4102,7 +4122,12 @@ class ScrollBoxRenderable extends BoxRenderable {
4102
4122
  }
4103
4123
  set scrollTop(value) {
4104
4124
  this.verticalScrollBar.scrollPosition = value;
4105
- this._hasManualScroll = true;
4125
+ if (!this._isApplyingStickyScroll) {
4126
+ const maxScrollTop = Math.max(0, this.scrollHeight - this.viewport.height);
4127
+ if (!this.isAtStickyPosition() && maxScrollTop > 1) {
4128
+ this._hasManualScroll = true;
4129
+ }
4130
+ }
4106
4131
  this.updateStickyState();
4107
4132
  }
4108
4133
  get scrollLeft() {
@@ -4110,7 +4135,12 @@ class ScrollBoxRenderable extends BoxRenderable {
4110
4135
  }
4111
4136
  set scrollLeft(value) {
4112
4137
  this.horizontalScrollBar.scrollPosition = value;
4113
- this._hasManualScroll = true;
4138
+ if (!this._isApplyingStickyScroll) {
4139
+ const maxScrollLeft = Math.max(0, this.scrollWidth - this.viewport.width);
4140
+ if (!this.isAtStickyPosition() && maxScrollLeft > 1) {
4141
+ this._hasManualScroll = true;
4142
+ }
4143
+ }
4114
4144
  this.updateStickyState();
4115
4145
  }
4116
4146
  get scrollWidth() {
@@ -4146,6 +4176,7 @@ class ScrollBoxRenderable extends BoxRenderable {
4146
4176
  }
4147
4177
  }
4148
4178
  applyStickyStart(stickyStart) {
4179
+ this._isApplyingStickyScroll = true;
4149
4180
  switch (stickyStart) {
4150
4181
  case "top":
4151
4182
  this._stickyScrollTop = true;
@@ -4168,6 +4199,7 @@ class ScrollBoxRenderable extends BoxRenderable {
4168
4199
  this.horizontalScrollBar.scrollPosition = Math.max(0, this.scrollWidth - this.viewport.width);
4169
4200
  break;
4170
4201
  }
4202
+ this._isApplyingStickyScroll = false;
4171
4203
  }
4172
4204
  constructor(ctx, {
4173
4205
  wrapperOptions,
@@ -4241,7 +4273,12 @@ class ScrollBoxRenderable extends BoxRenderable {
4241
4273
  orientation: "vertical",
4242
4274
  onChange: (position) => {
4243
4275
  this.content.translateY = -position;
4244
- this._hasManualScroll = true;
4276
+ if (!this._isApplyingStickyScroll) {
4277
+ const maxScrollTop = Math.max(0, this.scrollHeight - this.viewport.height);
4278
+ if (!this.isAtStickyPosition() && maxScrollTop > 1) {
4279
+ this._hasManualScroll = true;
4280
+ }
4281
+ }
4245
4282
  this.updateStickyState();
4246
4283
  }
4247
4284
  });
@@ -4257,7 +4294,12 @@ class ScrollBoxRenderable extends BoxRenderable {
4257
4294
  orientation: "horizontal",
4258
4295
  onChange: (position) => {
4259
4296
  this.content.translateX = -position;
4260
- this._hasManualScroll = true;
4297
+ if (!this._isApplyingStickyScroll) {
4298
+ const maxScrollLeft = Math.max(0, this.scrollWidth - this.viewport.width);
4299
+ if (!this.isAtStickyPosition() && maxScrollLeft > 1) {
4300
+ this._hasManualScroll = true;
4301
+ }
4302
+ }
4261
4303
  this.updateStickyState();
4262
4304
  }
4263
4305
  });
@@ -4284,7 +4326,6 @@ class ScrollBoxRenderable extends BoxRenderable {
4284
4326
  this.verticalScrollBar.scrollBy(delta.y, unit);
4285
4327
  this.horizontalScrollBar.scrollBy(delta.x, unit);
4286
4328
  }
4287
- this._hasManualScroll = true;
4288
4329
  }
4289
4330
  scrollTo(position) {
4290
4331
  if (typeof position === "number") {
@@ -4294,6 +4335,25 @@ class ScrollBoxRenderable extends BoxRenderable {
4294
4335
  this.scrollLeft = position.x;
4295
4336
  }
4296
4337
  }
4338
+ isAtStickyPosition() {
4339
+ if (!this._stickyScroll || !this._stickyStart) {
4340
+ return false;
4341
+ }
4342
+ const maxScrollTop = Math.max(0, this.scrollHeight - this.viewport.height);
4343
+ const maxScrollLeft = Math.max(0, this.scrollWidth - this.viewport.width);
4344
+ switch (this._stickyStart) {
4345
+ case "top":
4346
+ return this.scrollTop === 0;
4347
+ case "bottom":
4348
+ return this.scrollTop >= maxScrollTop;
4349
+ case "left":
4350
+ return this.scrollLeft === 0;
4351
+ case "right":
4352
+ return this.scrollLeft >= maxScrollLeft;
4353
+ default:
4354
+ return false;
4355
+ }
4356
+ }
4297
4357
  add(obj, index) {
4298
4358
  return this.content.add(obj, index);
4299
4359
  }
@@ -4323,7 +4383,11 @@ class ScrollBoxRenderable extends BoxRenderable {
4323
4383
  } else if (dir === "right") {
4324
4384
  this.scrollLeft += baseDelta * multiplier;
4325
4385
  }
4326
- this._hasManualScroll = true;
4386
+ const maxScrollTop = Math.max(0, this.scrollHeight - this.viewport.height);
4387
+ const maxScrollLeft = Math.max(0, this.scrollWidth - this.viewport.width);
4388
+ if (maxScrollTop > 1 || maxScrollLeft > 1) {
4389
+ this._hasManualScroll = true;
4390
+ }
4327
4391
  }
4328
4392
  if (event.type === "drag" && event.isSelecting) {
4329
4393
  this.updateAutoScroll(event.x, event.y);
@@ -4451,6 +4515,8 @@ class ScrollBoxRenderable extends BoxRenderable {
4451
4515
  }
4452
4516
  }
4453
4517
  recalculateBarProps() {
4518
+ const wasApplyingStickyScroll = this._isApplyingStickyScroll;
4519
+ this._isApplyingStickyScroll = true;
4454
4520
  this.verticalScrollBar.scrollSize = this.content.height;
4455
4521
  this.verticalScrollBar.viewportSize = this.viewport.height;
4456
4522
  this.horizontalScrollBar.scrollSize = this.content.width;
@@ -4473,6 +4539,7 @@ class ScrollBoxRenderable extends BoxRenderable {
4473
4539
  }
4474
4540
  }
4475
4541
  }
4542
+ this._isApplyingStickyScroll = wasApplyingStickyScroll;
4476
4543
  process.nextTick(() => {
4477
4544
  this.requestRender();
4478
4545
  });
@@ -6338,5 +6405,5 @@ export {
6338
6405
  ASCIIFont
6339
6406
  };
6340
6407
 
6341
- //# debugId=027AE54A57A8DE7D64756E2164756E21
6408
+ //# debugId=33D29679C10495BA64756E2164756E21
6342
6409
  //# sourceMappingURL=index.js.map