@xterm/xterm 6.1.0-beta.25 → 6.1.0-beta.251

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/README.md +62 -38
  2. package/css/xterm.css +29 -22
  3. package/lib/xterm.js +1 -1
  4. package/lib/xterm.js.map +1 -1
  5. package/lib/xterm.mjs +8 -34
  6. package/lib/xterm.mjs.map +4 -4
  7. package/package.json +25 -22
  8. package/src/browser/AccessibilityManager.ts +11 -6
  9. package/src/browser/Clipboard.ts +6 -3
  10. package/src/browser/CoreBrowserTerminal.ts +149 -319
  11. package/src/browser/Dom.ts +178 -0
  12. package/src/browser/Linkifier.ts +11 -11
  13. package/src/browser/OscLinkProvider.ts +82 -14
  14. package/src/browser/RenderDebouncer.ts +2 -2
  15. package/src/browser/TimeBasedDebouncer.ts +2 -2
  16. package/src/browser/Types.ts +12 -11
  17. package/src/browser/Viewport.ts +55 -20
  18. package/src/browser/decorations/BufferDecorationRenderer.ts +1 -1
  19. package/src/browser/decorations/OverviewRulerRenderer.ts +33 -17
  20. package/src/browser/input/CompositionHelper.ts +44 -8
  21. package/src/browser/public/Terminal.ts +25 -28
  22. package/src/browser/renderer/dom/DomRenderer.ts +242 -76
  23. package/src/browser/renderer/dom/DomRendererRowFactory.ts +19 -13
  24. package/src/browser/renderer/dom/WidthCache.ts +54 -52
  25. package/src/browser/renderer/shared/Constants.ts +7 -0
  26. package/src/browser/renderer/shared/TextBlinkStateManager.ts +97 -0
  27. package/src/browser/renderer/shared/Types.ts +8 -2
  28. package/src/browser/scrollable/abstractScrollbar.ts +300 -0
  29. package/src/browser/scrollable/fastDomNode.ts +126 -0
  30. package/src/browser/scrollable/globalPointerMoveMonitor.ts +90 -0
  31. package/src/browser/scrollable/horizontalScrollbar.ts +85 -0
  32. package/src/browser/scrollable/mouseEvent.ts +292 -0
  33. package/src/browser/scrollable/scrollable.ts +486 -0
  34. package/src/browser/scrollable/scrollableElement.ts +581 -0
  35. package/src/browser/scrollable/scrollableElementOptions.ts +161 -0
  36. package/src/browser/scrollable/scrollbarArrow.ts +110 -0
  37. package/src/browser/scrollable/scrollbarState.ts +246 -0
  38. package/src/browser/scrollable/scrollbarVisibilityController.ts +113 -0
  39. package/src/browser/scrollable/touch.ts +485 -0
  40. package/src/browser/scrollable/verticalScrollbar.ts +143 -0
  41. package/src/browser/scrollable/widget.ts +23 -0
  42. package/src/browser/services/CharSizeService.ts +2 -2
  43. package/src/browser/services/CoreBrowserService.ts +7 -5
  44. package/src/browser/services/KeyboardService.ts +67 -0
  45. package/src/browser/services/LinkProviderService.ts +1 -1
  46. package/src/browser/services/MouseCoordsService.ts +47 -0
  47. package/src/browser/services/MouseService.ts +518 -25
  48. package/src/browser/services/RenderService.ts +28 -16
  49. package/src/browser/services/SelectionService.ts +45 -39
  50. package/src/browser/services/Services.ts +40 -17
  51. package/src/browser/services/ThemeService.ts +2 -2
  52. package/src/common/Async.ts +141 -0
  53. package/src/common/CircularList.ts +2 -2
  54. package/src/common/Color.ts +8 -0
  55. package/src/common/CoreTerminal.ts +32 -22
  56. package/src/common/Event.ts +118 -0
  57. package/src/common/InputHandler.ts +286 -87
  58. package/src/common/Lifecycle.ts +113 -0
  59. package/src/common/Platform.ts +13 -3
  60. package/src/common/SortedList.ts +7 -3
  61. package/src/common/StringBuilder.ts +67 -0
  62. package/src/common/TaskQueue.ts +14 -5
  63. package/src/common/Types.ts +51 -31
  64. package/src/common/Version.ts +9 -0
  65. package/src/common/buffer/Buffer.ts +34 -19
  66. package/src/common/buffer/BufferLine.ts +140 -68
  67. package/src/common/buffer/BufferLineStringCache.ts +69 -0
  68. package/src/common/buffer/BufferReflow.ts +4 -1
  69. package/src/common/buffer/BufferSet.ts +11 -6
  70. package/src/common/buffer/CellData.ts +57 -0
  71. package/src/common/buffer/Marker.ts +2 -2
  72. package/src/common/buffer/Types.ts +6 -2
  73. package/src/common/data/EscapeSequences.ts +71 -70
  74. package/src/common/input/Keyboard.ts +14 -7
  75. package/src/common/input/KittyKeyboard.ts +526 -0
  76. package/src/common/input/Win32InputMode.ts +297 -0
  77. package/src/common/input/WriteBuffer.ts +107 -38
  78. package/src/common/input/XParseColor.ts +2 -2
  79. package/src/common/parser/ApcParser.ts +196 -0
  80. package/src/common/parser/Constants.ts +14 -4
  81. package/src/common/parser/DcsParser.ts +11 -12
  82. package/src/common/parser/EscapeSequenceParser.ts +205 -63
  83. package/src/common/parser/OscParser.ts +11 -12
  84. package/src/common/parser/Params.ts +27 -8
  85. package/src/common/parser/Types.ts +36 -2
  86. package/src/common/public/BufferLineApiView.ts +2 -2
  87. package/src/common/public/BufferNamespaceApi.ts +3 -3
  88. package/src/common/public/ParserApi.ts +3 -0
  89. package/src/common/services/BufferService.ts +14 -9
  90. package/src/common/services/CharsetService.ts +4 -0
  91. package/src/common/services/CoreService.ts +22 -9
  92. package/src/common/services/DecorationService.ts +255 -8
  93. package/src/common/services/LogService.ts +1 -31
  94. package/src/common/services/{CoreMouseService.ts → MouseStateService.ts} +21 -132
  95. package/src/common/services/OptionsService.ts +13 -4
  96. package/src/common/services/ServiceRegistry.ts +9 -7
  97. package/src/common/services/Services.ts +49 -40
  98. package/src/common/services/UnicodeService.ts +1 -1
  99. package/typings/xterm.d.ts +318 -34
  100. package/src/common/Clone.ts +0 -23
  101. package/src/common/TypedArrayUtils.ts +0 -17
  102. package/src/vs/base/browser/browser.ts +0 -141
  103. package/src/vs/base/browser/canIUse.ts +0 -49
  104. package/src/vs/base/browser/dom.ts +0 -2369
  105. package/src/vs/base/browser/fastDomNode.ts +0 -316
  106. package/src/vs/base/browser/globalPointerMoveMonitor.ts +0 -112
  107. package/src/vs/base/browser/iframe.ts +0 -135
  108. package/src/vs/base/browser/keyboardEvent.ts +0 -213
  109. package/src/vs/base/browser/mouseEvent.ts +0 -229
  110. package/src/vs/base/browser/touch.ts +0 -372
  111. package/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +0 -303
  112. package/src/vs/base/browser/ui/scrollbar/horizontalScrollbar.ts +0 -114
  113. package/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +0 -720
  114. package/src/vs/base/browser/ui/scrollbar/scrollableElementOptions.ts +0 -165
  115. package/src/vs/base/browser/ui/scrollbar/scrollbarArrow.ts +0 -114
  116. package/src/vs/base/browser/ui/scrollbar/scrollbarState.ts +0 -243
  117. package/src/vs/base/browser/ui/scrollbar/scrollbarVisibilityController.ts +0 -118
  118. package/src/vs/base/browser/ui/scrollbar/verticalScrollbar.ts +0 -116
  119. package/src/vs/base/browser/ui/widget.ts +0 -57
  120. package/src/vs/base/browser/window.ts +0 -14
  121. package/src/vs/base/common/arrays.ts +0 -887
  122. package/src/vs/base/common/arraysFind.ts +0 -202
  123. package/src/vs/base/common/assert.ts +0 -71
  124. package/src/vs/base/common/async.ts +0 -1992
  125. package/src/vs/base/common/cancellation.ts +0 -148
  126. package/src/vs/base/common/charCode.ts +0 -450
  127. package/src/vs/base/common/collections.ts +0 -140
  128. package/src/vs/base/common/decorators.ts +0 -130
  129. package/src/vs/base/common/equals.ts +0 -146
  130. package/src/vs/base/common/errors.ts +0 -303
  131. package/src/vs/base/common/event.ts +0 -1778
  132. package/src/vs/base/common/functional.ts +0 -32
  133. package/src/vs/base/common/hash.ts +0 -316
  134. package/src/vs/base/common/iterator.ts +0 -159
  135. package/src/vs/base/common/keyCodes.ts +0 -526
  136. package/src/vs/base/common/keybindings.ts +0 -284
  137. package/src/vs/base/common/lazy.ts +0 -47
  138. package/src/vs/base/common/lifecycle.ts +0 -801
  139. package/src/vs/base/common/linkedList.ts +0 -142
  140. package/src/vs/base/common/map.ts +0 -202
  141. package/src/vs/base/common/numbers.ts +0 -98
  142. package/src/vs/base/common/observable.ts +0 -76
  143. package/src/vs/base/common/observableInternal/api.ts +0 -31
  144. package/src/vs/base/common/observableInternal/autorun.ts +0 -281
  145. package/src/vs/base/common/observableInternal/base.ts +0 -489
  146. package/src/vs/base/common/observableInternal/debugName.ts +0 -145
  147. package/src/vs/base/common/observableInternal/derived.ts +0 -428
  148. package/src/vs/base/common/observableInternal/lazyObservableValue.ts +0 -146
  149. package/src/vs/base/common/observableInternal/logging.ts +0 -328
  150. package/src/vs/base/common/observableInternal/promise.ts +0 -209
  151. package/src/vs/base/common/observableInternal/utils.ts +0 -610
  152. package/src/vs/base/common/platform.ts +0 -281
  153. package/src/vs/base/common/scrollable.ts +0 -522
  154. package/src/vs/base/common/sequence.ts +0 -34
  155. package/src/vs/base/common/stopwatch.ts +0 -43
  156. package/src/vs/base/common/strings.ts +0 -557
  157. package/src/vs/base/common/symbols.ts +0 -9
  158. package/src/vs/base/common/uint.ts +0 -59
  159. package/src/vs/patches/nls.ts +0 -90
  160. package/src/vs/typings/base-common.d.ts +0 -20
  161. package/src/vs/typings/require.d.ts +0 -42
  162. package/src/vs/typings/vscode-globals-nls.d.ts +0 -36
  163. package/src/vs/typings/vscode-globals-product.d.ts +0 -33
@@ -5,24 +5,29 @@
5
5
 
6
6
  import { DomRendererRowFactory, RowCss } from 'browser/renderer/dom/DomRendererRowFactory';
7
7
  import { WidthCache } from 'browser/renderer/dom/WidthCache';
8
- import { INVERTED_DEFAULT_COLOR } from 'browser/renderer/shared/Constants';
8
+ import { INVERTED_DEFAULT_COLOR, RendererConstants } from 'browser/renderer/shared/Constants';
9
9
  import { createRenderDimensions } from 'browser/renderer/shared/RendererUtils';
10
10
  import { createSelectionRenderModel } from 'browser/renderer/shared/SelectionRenderModel';
11
+ import { TextBlinkStateManager } from 'browser/renderer/shared/TextBlinkStateManager';
11
12
  import { IRenderDimensions, IRenderer, IRequestRedrawEvent, ISelectionRenderModel } from 'browser/renderer/shared/Types';
12
13
  import { ICharSizeService, ICoreBrowserService, IThemeService } from 'browser/services/Services';
13
14
  import { ILinkifier2, ILinkifierEvent, ITerminal, ReadonlyColorSet } from 'browser/Types';
14
15
  import { color } from 'common/Color';
15
- import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
16
+ import { Disposable, toDisposable } from 'common/Lifecycle';
16
17
  import { IBufferService, ICoreService, IInstantiationService, IOptionsService } from 'common/services/Services';
17
- import { Emitter } from 'vs/base/common/event';
18
-
19
-
20
- const TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-';
21
- const ROW_CONTAINER_CLASS = 'xterm-rows';
22
- const FG_CLASS_PREFIX = 'xterm-fg-';
23
- const BG_CLASS_PREFIX = 'xterm-bg-';
24
- const FOCUS_CLASS = 'xterm-focus';
25
- const SELECTION_CLASS = 'xterm-selection';
18
+ import { Emitter } from 'common/Event';
19
+ import { addDisposableListener } from 'browser/Dom';
20
+
21
+
22
+ const enum Constants {
23
+ TERMINAL_CLASS_PREFIX = 'xterm-dom-renderer-owner-',
24
+ ROW_CONTAINER_CLASS = 'xterm-rows',
25
+ FG_CLASS_PREFIX = 'xterm-fg-',
26
+ BG_CLASS_PREFIX = 'xterm-bg-',
27
+ FOCUS_CLASS = 'xterm-focus',
28
+ SELECTION_CLASS = 'xterm-selection',
29
+ CURSOR_BLINK_IDLE_CLASS = 'xterm-cursor-blink-idle'
30
+ }
26
31
 
27
32
  let nextTerminalId = 1;
28
33
 
@@ -42,10 +47,18 @@ export class DomRenderer extends Disposable implements IRenderer {
42
47
  private _selectionContainer: HTMLElement;
43
48
  private _widthCache: WidthCache;
44
49
  private _selectionRenderModel: ISelectionRenderModel = createSelectionRenderModel();
50
+ private _lastSelectionStart: [number, number] | undefined;
51
+ private _lastSelectionEnd: [number, number] | undefined;
52
+ private _lastSelectionColumnMode: boolean = false;
53
+ private _cursorBlinkStateManager: CursorBlinkStateManager;
54
+ private _textBlinkStateManager: TextBlinkStateManager;
55
+ private _rowHasBlinkingCells: boolean[] = [];
56
+ private _rowHasBlinkingCellsCount: number = 0;
45
57
 
46
58
  public dimensions: IRenderDimensions;
47
59
 
48
- public readonly onRequestRedraw = this._register(new Emitter<IRequestRedrawEvent>()).event;
60
+ private readonly _onRequestRedraw = this._register(new Emitter<IRequestRedrawEvent>());
61
+ public readonly onRequestRedraw = this._onRequestRedraw.event;
49
62
 
50
63
  constructor(
51
64
  private readonly _terminal: ITerminal,
@@ -65,12 +78,12 @@ export class DomRenderer extends Disposable implements IRenderer {
65
78
  ) {
66
79
  super();
67
80
  this._rowContainer = this._document.createElement('div');
68
- this._rowContainer.classList.add(ROW_CONTAINER_CLASS);
81
+ this._rowContainer.classList.add(Constants.ROW_CONTAINER_CLASS);
69
82
  this._rowContainer.style.lineHeight = 'normal';
70
83
  this._rowContainer.setAttribute('aria-hidden', 'true');
71
84
  this._refreshRowElements(this._bufferService.cols, this._bufferService.rows);
72
85
  this._selectionContainer = this._document.createElement('div');
73
- this._selectionContainer.classList.add(SELECTION_CLASS);
86
+ this._selectionContainer.classList.add(Constants.SELECTION_CLASS);
74
87
  this._selectionContainer.setAttribute('aria-hidden', 'true');
75
88
 
76
89
  this.dimensions = createRenderDimensions();
@@ -82,15 +95,24 @@ export class DomRenderer extends Disposable implements IRenderer {
82
95
 
83
96
  this._rowFactory = instantiationService.createInstance(DomRendererRowFactory, document);
84
97
 
85
- this._element.classList.add(TERMINAL_CLASS_PREFIX + this._terminalClass);
98
+ this._element.classList.add(Constants.TERMINAL_CLASS_PREFIX + this._terminalClass);
86
99
  this._screenElement.appendChild(this._rowContainer);
87
100
  this._screenElement.appendChild(this._selectionContainer);
88
101
 
89
102
  this._register(this._linkifier2.onShowLinkUnderline(e => this._handleLinkHover(e)));
90
103
  this._register(this._linkifier2.onHideLinkUnderline(e => this._handleLinkLeave(e)));
91
104
 
105
+ this._cursorBlinkStateManager = new CursorBlinkStateManager(this._rowContainer, this._coreBrowserService);
106
+ this._register(addDisposableListener(this._document, 'mousedown', () => this._cursorBlinkStateManager.restartBlinkAnimation()));
107
+ this._register(toDisposable(() => this._cursorBlinkStateManager.dispose()));
108
+ this._textBlinkStateManager = this._register(new TextBlinkStateManager(
109
+ () => this._onRequestRedraw.fire({ start: 0, end: this._bufferService.rows - 1 }),
110
+ this._coreBrowserService,
111
+ this._optionsService
112
+ ));
113
+
92
114
  this._register(toDisposable(() => {
93
- this._element.classList.remove(TERMINAL_CLASS_PREFIX + this._terminalClass);
115
+ this._element.classList.remove(Constants.TERMINAL_CLASS_PREFIX + this._terminalClass);
94
116
 
95
117
  // Outside influences such as React unmounts may manipulate the DOM before our disposal.
96
118
  // https://github.com/xtermjs/xterm.js/issues/2960
@@ -101,7 +123,7 @@ export class DomRenderer extends Disposable implements IRenderer {
101
123
  this._dimensionsStyleElement.remove();
102
124
  }));
103
125
 
104
- this._widthCache = new WidthCache(this._document, this._helperContainer);
126
+ this._widthCache = new WidthCache();
105
127
  this._widthCache.setFont(
106
128
  this._optionsService.rawOptions.fontFamily,
107
129
  this._optionsService.rawOptions.fontSize,
@@ -140,7 +162,7 @@ export class DomRenderer extends Disposable implements IRenderer {
140
162
  }
141
163
 
142
164
  const styles =
143
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} span {` +
165
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} span {` +
144
166
  ` display: inline-block;` + // TODO: find workaround for inline-block (creates ~20% render penalty)
145
167
  ` height: 100%;` +
146
168
  ` vertical-align: top;` +
@@ -161,19 +183,22 @@ export class DomRenderer extends Disposable implements IRenderer {
161
183
 
162
184
  // Base CSS
163
185
  let styles =
164
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} {` +
186
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} {` +
165
187
  // Disabling pointer events circumvents a browser behavior that prevents `click` events from
166
188
  // being delivered if the target element is replaced during the click. This happened due to
167
189
  // refresh() being called during the mousedown handler to start a selection.
168
190
  ` pointer-events: none;` +
169
191
  ` color: ${colors.foreground.css};` +
192
+ `}`;
193
+ styles +=
194
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}, ${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} span {` +
170
195
  ` font-family: ${this._optionsService.rawOptions.fontFamily};` +
171
196
  ` font-size: ${this._optionsService.rawOptions.fontSize}px;` +
172
197
  ` font-kerning: none;` +
173
198
  ` white-space: pre` +
174
199
  `}`;
175
200
  styles +=
176
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .xterm-dim {` +
201
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .xterm-dim {` +
177
202
  ` color: ${color.multiplyOpacity(colors.foreground, 0.5).css};` +
178
203
  `}`;
179
204
  // Text styles
@@ -186,6 +211,9 @@ export class DomRenderer extends Disposable implements IRenderer {
186
211
  `}` +
187
212
  `${this._terminalSelector} span.${RowCss.ITALIC_CLASS} {` +
188
213
  ` font-style: italic;` +
214
+ `}` +
215
+ `${this._terminalSelector} span.${RowCss.BLINK_HIDDEN_CLASS} {` +
216
+ ` visibility: hidden;` +
189
217
  `}`;
190
218
  // Blink animation
191
219
  const blinkAnimationUnderlineId = `blink_underline_${this._terminalClass}`;
@@ -216,66 +244,70 @@ export class DomRenderer extends Disposable implements IRenderer {
216
244
  `}`;
217
245
  // Cursor
218
246
  styles +=
219
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` +
247
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}.${Constants.FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` +
220
248
  ` animation: ${blinkAnimationUnderlineId} 1s step-end infinite;` +
221
249
  `}` +
222
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` +
250
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}.${Constants.FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` +
223
251
  ` animation: ${blinkAnimationBarId} 1s step-end infinite;` +
224
252
  `}` +
225
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS}.${FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
253
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}.${Constants.FOCUS_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
226
254
  ` animation: ${blinkAnimationBlockId} 1s step-end infinite;` +
227
255
  `}` +
256
+ // Disable cursor blinking when idle
257
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS}.${Constants.CURSOR_BLINK_IDLE_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_BLINK_CLASS} {` +
258
+ ` animation: none !important;` +
259
+ `}` +
228
260
  // !important helps fix an issue where the cursor will not render on top of the selection,
229
261
  // however it's very hard to fix this issue and retain the blink animation without the use of
230
262
  // !important. So this edge case fails when cursor blink is on.
231
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
263
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS} {` +
232
264
  ` background-color: ${colors.cursor.css};` +
233
265
  ` color: ${colors.cursorAccent.css};` +
234
266
  `}` +
235
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS}:not(.${RowCss.CURSOR_BLINK_CLASS}) {` +
267
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BLOCK_CLASS}:not(.${RowCss.CURSOR_BLINK_CLASS}) {` +
236
268
  ` background-color: ${colors.cursor.css} !important;` +
237
269
  ` color: ${colors.cursorAccent.css} !important;` +
238
270
  `}` +
239
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_OUTLINE_CLASS} {` +
271
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_OUTLINE_CLASS} {` +
240
272
  ` outline: 1px solid ${colors.cursor.css};` +
241
273
  ` outline-offset: -1px;` +
242
274
  `}` +
243
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` +
275
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_BAR_CLASS} {` +
244
276
  ` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${colors.cursor.css} inset;` +
245
277
  `}` +
246
- `${this._terminalSelector} .${ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` +
278
+ `${this._terminalSelector} .${Constants.ROW_CONTAINER_CLASS} .${RowCss.CURSOR_CLASS}.${RowCss.CURSOR_STYLE_UNDERLINE_CLASS} {` +
247
279
  ` border-bottom: 1px ${colors.cursor.css};` +
248
280
  ` border-bottom-style: solid;` +
249
281
  ` height: calc(100% - 1px);` +
250
282
  `}`;
251
283
  // Selection
252
284
  styles +=
253
- `${this._terminalSelector} .${SELECTION_CLASS} {` +
285
+ `${this._terminalSelector} .${Constants.SELECTION_CLASS} {` +
254
286
  ` position: absolute;` +
255
287
  ` top: 0;` +
256
288
  ` left: 0;` +
257
289
  ` z-index: 1;` +
258
290
  ` pointer-events: none;` +
259
291
  `}` +
260
- `${this._terminalSelector}.focus .${SELECTION_CLASS} div {` +
292
+ `${this._terminalSelector}.focus .${Constants.SELECTION_CLASS} div {` +
261
293
  ` position: absolute;` +
262
294
  ` background-color: ${colors.selectionBackgroundOpaque.css};` +
263
295
  `}` +
264
- `${this._terminalSelector} .${SELECTION_CLASS} div {` +
296
+ `${this._terminalSelector} .${Constants.SELECTION_CLASS} div {` +
265
297
  ` position: absolute;` +
266
298
  ` background-color: ${colors.selectionInactiveBackgroundOpaque.css};` +
267
299
  `}`;
268
300
  // Colors
269
301
  for (const [i, c] of colors.ansi.entries()) {
270
302
  styles +=
271
- `${this._terminalSelector} .${FG_CLASS_PREFIX}${i} { color: ${c.css}; }` +
272
- `${this._terminalSelector} .${FG_CLASS_PREFIX}${i}.${RowCss.DIM_CLASS} { color: ${color.multiplyOpacity(c, 0.5).css}; }` +
273
- `${this._terminalSelector} .${BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`;
303
+ `${this._terminalSelector} .${Constants.FG_CLASS_PREFIX}${i} { color: ${c.css}; }` +
304
+ `${this._terminalSelector} .${Constants.FG_CLASS_PREFIX}${i}.${RowCss.DIM_CLASS} { color: ${color.multiplyOpacity(c, 0.5).css}; }` +
305
+ `${this._terminalSelector} .${Constants.BG_CLASS_PREFIX}${i} { background-color: ${c.css}; }`;
274
306
  }
275
307
  styles +=
276
- `${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${color.opaque(colors.background).css}; }` +
277
- `${this._terminalSelector} .${FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR}.${RowCss.DIM_CLASS} { color: ${color.multiplyOpacity(color.opaque(colors.background), 0.5).css}; }` +
278
- `${this._terminalSelector} .${BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${colors.foreground.css}; }`;
308
+ `${this._terminalSelector} .${Constants.FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { color: ${color.opaque(colors.background).css}; }` +
309
+ `${this._terminalSelector} .${Constants.FG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR}.${RowCss.DIM_CLASS} { color: ${color.multiplyOpacity(color.opaque(colors.background), 0.5).css}; }` +
310
+ `${this._terminalSelector} .${Constants.BG_CLASS_PREFIX}${INVERTED_DEFAULT_COLOR} { background-color: ${colors.foreground.css}; }`;
279
311
 
280
312
  this._themeStyleElement.textContent = styles;
281
313
  }
@@ -307,10 +339,14 @@ export class DomRenderer extends Disposable implements IRenderer {
307
339
  const row = this._document.createElement('div');
308
340
  this._rowContainer.appendChild(row);
309
341
  this._rowElements.push(row);
342
+ this._rowHasBlinkingCells.push(false);
310
343
  }
311
344
  // Remove excess elements
312
345
  while (this._rowElements.length > rows) {
313
346
  this._rowContainer.removeChild(this._rowElements.pop()!);
347
+ if (this._rowHasBlinkingCells.pop()) {
348
+ this._rowHasBlinkingCellsCount--;
349
+ }
314
350
  }
315
351
  }
316
352
 
@@ -327,61 +363,105 @@ export class DomRenderer extends Disposable implements IRenderer {
327
363
  }
328
364
 
329
365
  public handleBlur(): void {
330
- this._rowContainer.classList.remove(FOCUS_CLASS);
366
+ this._rowContainer.classList.remove(Constants.FOCUS_CLASS);
367
+ this._cursorBlinkStateManager.pause();
331
368
  this.renderRows(0, this._bufferService.rows - 1);
332
369
  }
333
370
 
334
371
  public handleFocus(): void {
335
- this._rowContainer.classList.add(FOCUS_CLASS);
372
+ this._rowContainer.classList.add(Constants.FOCUS_CLASS);
373
+ this._cursorBlinkStateManager.resume();
336
374
  this.renderRows(this._bufferService.buffer.y, this._bufferService.buffer.y);
337
375
  }
338
376
 
377
+ public handleViewportVisibilityChange(isVisible: boolean): void {
378
+ this._textBlinkStateManager.setViewportVisible(isVisible);
379
+ }
380
+
339
381
  public handleSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
382
+ const rows = this._bufferService.rows;
383
+
340
384
  // Remove all selections
341
385
  this._selectionContainer.replaceChildren();
342
386
  this._rowFactory.handleSelectionChanged(start, end, columnSelectMode);
343
- this.renderRows(0, this._bufferService.rows - 1);
344
387
 
345
- // Selection does not exist
388
+ // Determine old selection viewport band
389
+ let oldViewportStart = 0;
390
+ let oldViewportEnd = -1;
391
+ if (this._lastSelectionStart && this._lastSelectionEnd) {
392
+ this._selectionRenderModel.update(this._terminal, this._lastSelectionStart, this._lastSelectionEnd, this._lastSelectionColumnMode);
393
+ if (this._selectionRenderModel.hasSelection) {
394
+ oldViewportStart = this._selectionRenderModel.viewportCappedStartRow;
395
+ oldViewportEnd = this._selectionRenderModel.viewportCappedEndRow;
396
+ }
397
+ }
398
+
399
+ // Determine new selection viewport band and create overlays
400
+ let newViewportStart = 0;
401
+ let newViewportEnd = -1;
346
402
  if (!start || !end) {
347
403
  return;
348
404
  }
349
-
350
405
  this._selectionRenderModel.update(this._terminal, start, end, columnSelectMode);
351
- if (!this._selectionRenderModel.hasSelection) {
352
- return;
406
+ if (this._selectionRenderModel.hasSelection) {
407
+ const viewportStartRow = this._selectionRenderModel.viewportStartRow;
408
+ const viewportEndRow = this._selectionRenderModel.viewportEndRow;
409
+ const viewportCappedStartRow = this._selectionRenderModel.viewportCappedStartRow;
410
+ const viewportCappedEndRow = this._selectionRenderModel.viewportCappedEndRow;
411
+
412
+ newViewportStart = viewportCappedStartRow;
413
+ newViewportEnd = viewportCappedEndRow;
414
+
415
+ // Create the selections
416
+ const documentFragment = this._document.createDocumentFragment();
417
+
418
+ if (columnSelectMode) {
419
+ const isXFlipped = start[0] > end[0];
420
+ documentFragment.appendChild(
421
+ this._createSelectionElement(viewportCappedStartRow, isXFlipped ? end[0] : start[0], isXFlipped ? start[0] : end[0], viewportCappedEndRow - viewportCappedStartRow + 1)
422
+ );
423
+ } else {
424
+ // Draw first row
425
+ const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
426
+ const endCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols;
427
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
428
+ // Draw middle rows
429
+ const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
430
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._bufferService.cols, middleRowsCount));
431
+ // Draw final row
432
+ if (viewportCappedStartRow !== viewportCappedEndRow) {
433
+ // Only draw viewportEndRow if it's not the same as viewporttartRow
434
+ const finalEndCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._bufferService.cols;
435
+ documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, finalEndCol));
436
+ }
437
+ }
438
+ this._selectionContainer.appendChild(documentFragment);
353
439
  }
354
440
 
355
- // Translate from buffer position to viewport position
356
- const viewportStartRow = this._selectionRenderModel.viewportStartRow;
357
- const viewportEndRow = this._selectionRenderModel.viewportEndRow;
358
- const viewportCappedStartRow = this._selectionRenderModel.viewportCappedStartRow;
359
- const viewportCappedEndRow = this._selectionRenderModel.viewportCappedEndRow;
360
-
361
- // Create the selections
362
- const documentFragment = this._document.createDocumentFragment();
363
-
364
- if (columnSelectMode) {
365
- const isXFlipped = start[0] > end[0];
366
- documentFragment.appendChild(
367
- this._createSelectionElement(viewportCappedStartRow, isXFlipped ? end[0] : start[0], isXFlipped ? start[0] : end[0], viewportCappedEndRow - viewportCappedStartRow + 1)
368
- );
369
- } else {
370
- // Draw first row
371
- const startCol = viewportStartRow === viewportCappedStartRow ? start[0] : 0;
372
- const endCol = viewportCappedStartRow === viewportEndRow ? end[0] : this._bufferService.cols;
373
- documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow, startCol, endCol));
374
- // Draw middle rows
375
- const middleRowsCount = viewportCappedEndRow - viewportCappedStartRow - 1;
376
- documentFragment.appendChild(this._createSelectionElement(viewportCappedStartRow + 1, 0, this._bufferService.cols, middleRowsCount));
377
- // Draw final row
378
- if (viewportCappedStartRow !== viewportCappedEndRow) {
379
- // Only draw viewportEndRow if it's not the same as viewporttartRow
380
- const endCol = viewportEndRow === viewportCappedEndRow ? end[0] : this._bufferService.cols;
381
- documentFragment.appendChild(this._createSelectionElement(viewportCappedEndRow, 0, endCol));
441
+ // Compute minimal row range to redraw
442
+ let renderStartRow = Math.min(oldViewportStart, newViewportStart);
443
+ let renderEndRow = Math.max(oldViewportEnd, newViewportEnd);
444
+
445
+ if (renderEndRow >= 0) {
446
+ // Clamp to viewport
447
+ renderStartRow = Math.max(renderStartRow, 0);
448
+ renderEndRow = Math.min(renderEndRow, rows - 1);
449
+
450
+ // Ensure cursor row is included when a selection is present
451
+ const buffer = this._bufferService.buffer;
452
+ const cursorViewportRow = buffer.y;
453
+ if (this._selectionRenderModel.hasSelection && cursorViewportRow >= 0 && cursorViewportRow < rows) {
454
+ renderStartRow = Math.min(renderStartRow, cursorViewportRow);
455
+ renderEndRow = Math.max(renderEndRow, cursorViewportRow);
382
456
  }
457
+
458
+ this.renderRows(renderStartRow, renderEndRow);
383
459
  }
384
- this._selectionContainer.appendChild(documentFragment);
460
+
461
+ // Update last selection state
462
+ this._lastSelectionStart = start;
463
+ this._lastSelectionEnd = end;
464
+ this._lastSelectionColumnMode = columnSelectMode;
385
465
  }
386
466
 
387
467
  /**
@@ -406,7 +486,8 @@ export class DomRenderer extends Disposable implements IRenderer {
406
486
  }
407
487
 
408
488
  public handleCursorMove(): void {
409
- // No-op, the cursor is drawn when rows are drawn
489
+ // Reset idle timer on cursor movement (which happens on input)
490
+ this._cursorBlinkStateManager.restartBlinkAnimation();
410
491
  }
411
492
 
412
493
  private _handleOptionsChanged(): void {
@@ -436,6 +517,11 @@ export class DomRenderer extends Disposable implements IRenderer {
436
517
  */
437
518
  e.replaceChildren();
438
519
  }
520
+ if (this._rowHasBlinkingCellsCount > 0) {
521
+ this._rowHasBlinkingCells.fill(false);
522
+ this._rowHasBlinkingCellsCount = 0;
523
+ this._textBlinkStateManager.setNeedsBlinkInViewport(false);
524
+ }
439
525
  }
440
526
 
441
527
  public renderRows(start: number, end: number): void {
@@ -445,6 +531,7 @@ export class DomRenderer extends Disposable implements IRenderer {
445
531
  const cursorBlink = this._coreService.decPrivateModes.cursorBlink ?? this._optionsService.rawOptions.cursorBlink;
446
532
  const cursorStyle = this._coreService.decPrivateModes.cursorStyle ?? this._optionsService.rawOptions.cursorStyle;
447
533
  const cursorInactiveStyle = this._optionsService.rawOptions.cursorInactiveStyle;
534
+ const rowInfo = { hasBlinkingCells: false };
448
535
 
449
536
  for (let y = start; y <= end; y++) {
450
537
  const row = y + buffer.ydisp;
@@ -462,17 +549,21 @@ export class DomRenderer extends Disposable implements IRenderer {
462
549
  cursorInactiveStyle,
463
550
  cursorX,
464
551
  cursorBlink,
552
+ this._textBlinkStateManager.isBlinkOn,
465
553
  this.dimensions.css.cell.width,
466
554
  this._widthCache,
467
555
  -1,
468
- -1
556
+ -1,
557
+ rowInfo
469
558
  )
470
559
  );
560
+ this._setRowBlinkState(y, rowInfo.hasBlinkingCells);
471
561
  }
562
+ this._updateTextBlinkState();
472
563
  }
473
564
 
474
565
  private get _terminalSelector(): string {
475
- return `.${TERMINAL_CLASS_PREFIX}${this._terminalClass}`;
566
+ return `.${Constants.TERMINAL_CLASS_PREFIX}${this._terminalClass}`;
476
567
  }
477
568
 
478
569
  private _handleLinkHover(e: ILinkifierEvent): void {
@@ -513,6 +604,7 @@ export class DomRenderer extends Disposable implements IRenderer {
513
604
  const cursorBlink = this._optionsService.rawOptions.cursorBlink;
514
605
  const cursorStyle = this._optionsService.rawOptions.cursorStyle;
515
606
  const cursorInactiveStyle = this._optionsService.rawOptions.cursorInactiveStyle;
607
+ const rowInfo = { hasBlinkingCells: false };
516
608
 
517
609
  // refresh rows within link range
518
610
  for (let i = y; i <= y2; ++i) {
@@ -531,12 +623,86 @@ export class DomRenderer extends Disposable implements IRenderer {
531
623
  cursorInactiveStyle,
532
624
  cursorX,
533
625
  cursorBlink,
626
+ this._textBlinkStateManager.isBlinkOn,
534
627
  this.dimensions.css.cell.width,
535
628
  this._widthCache,
536
629
  enabled ? (i === y ? x : 0) : -1,
537
- enabled ? ((i === y2 ? x2 : cols) - 1) : -1
630
+ enabled ? ((i === y2 ? x2 : cols) - 1) : -1,
631
+ rowInfo
538
632
  )
539
633
  );
634
+ this._setRowBlinkState(i, rowInfo.hasBlinkingCells);
540
635
  }
636
+ this._updateTextBlinkState();
637
+ }
638
+
639
+ private _setRowBlinkState(row: number, hasBlinkingCells: boolean): void {
640
+ const previous = this._rowHasBlinkingCells[row];
641
+ if (previous === hasBlinkingCells) {
642
+ return;
643
+ }
644
+ this._rowHasBlinkingCells[row] = hasBlinkingCells;
645
+ this._rowHasBlinkingCellsCount += hasBlinkingCells ? 1 : -1;
646
+ }
647
+
648
+ private _updateTextBlinkState(): void {
649
+ this._textBlinkStateManager.setNeedsBlinkInViewport(this._rowHasBlinkingCellsCount > 0);
650
+ }
651
+ }
652
+
653
+ class CursorBlinkStateManager {
654
+ private _idleTimeout: number | undefined;
655
+ private _isIdlePaused: boolean = false;
656
+
657
+ constructor(
658
+ private readonly _rowContainer: HTMLElement,
659
+ private readonly _coreBrowserService: ICoreBrowserService
660
+ ) {
661
+ if (this._coreBrowserService.isFocused) {
662
+ this._resetIdleTimer();
663
+ }
664
+ }
665
+
666
+ public dispose(): void {
667
+ this._clearIdleTimer();
668
+ }
669
+
670
+ public restartBlinkAnimation(): void {
671
+ if (this._isIdlePaused) {
672
+ this._rowContainer.classList.remove(Constants.CURSOR_BLINK_IDLE_CLASS);
673
+ }
674
+ this._resetIdleTimer();
675
+ }
676
+
677
+ public pause(): void {
678
+ this._isIdlePaused = false;
679
+ this._clearIdleTimer();
680
+ }
681
+
682
+ public resume(): void {
683
+ this._isIdlePaused = false;
684
+ this._rowContainer.classList.remove(Constants.CURSOR_BLINK_IDLE_CLASS);
685
+ this._resetIdleTimer();
686
+ }
687
+
688
+ private _resetIdleTimer(): void {
689
+ this._isIdlePaused = false;
690
+ this._clearIdleTimer();
691
+ this._idleTimeout = this._coreBrowserService.window.setTimeout(() => {
692
+ this._stopBlinkingDueToIdle();
693
+ }, RendererConstants.CURSOR_BLINK_IDLE_TIMEOUT);
694
+ }
695
+
696
+ private _clearIdleTimer(): void {
697
+ if (this._idleTimeout) {
698
+ this._coreBrowserService.window.clearTimeout(this._idleTimeout);
699
+ this._idleTimeout = undefined;
700
+ }
701
+ }
702
+
703
+ private _stopBlinkingDueToIdle(): void {
704
+ this._rowContainer.classList.add(Constants.CURSOR_BLINK_IDLE_CLASS);
705
+ this._isIdlePaused = true;
706
+ this._idleTimeout = undefined;
541
707
  }
542
708
  }
@@ -24,6 +24,7 @@ export const enum RowCss {
24
24
  UNDERLINE_CLASS = 'xterm-underline',
25
25
  OVERLINE_CLASS = 'xterm-overline',
26
26
  STRIKETHROUGH_CLASS = 'xterm-strikethrough',
27
+ BLINK_HIDDEN_CLASS = 'xterm-blink-hidden',
27
28
  CURSOR_CLASS = 'xterm-cursor',
28
29
  CURSOR_BLINK_CLASS = 'xterm-cursor-blink',
29
30
  CURSOR_STYLE_BLOCK_CLASS = 'xterm-cursor-block',
@@ -66,13 +67,18 @@ export class DomRendererRowFactory {
66
67
  cursorInactiveStyle: string | undefined,
67
68
  cursorX: number,
68
69
  cursorBlink: boolean,
70
+ blinkOn: boolean,
69
71
  cellWidth: number,
70
72
  widthCache: WidthCache,
71
73
  linkStart: number,
72
- linkEnd: number
74
+ linkEnd: number,
75
+ rowInfo?: { hasBlinkingCells: boolean }
73
76
  ): HTMLSpanElement[] {
74
77
 
75
78
  const elements: HTMLSpanElement[] = [];
79
+ if (rowInfo) {
80
+ rowInfo.hasBlinkingCells = false;
81
+ }
76
82
  const joinedRanges = this._characterJoinerService.getJoinedCharacters(row);
77
83
  const colors = this._themeService.colors;
78
84
 
@@ -118,7 +124,7 @@ export class DomRendererRowFactory {
118
124
  // Process any joined character ranges as needed. Because of how the
119
125
  // ranges are produced, we know that they are valid for the characters
120
126
  // and attributes of our input.
121
- let cell = this._workCell;
127
+ let cell: ICellData = this._workCell;
122
128
  if (joinedRanges.length > 0 && x === joinedRanges[0][0] && isValidJoinRange) {
123
129
  const range = joinedRanges.shift()!;
124
130
  // If the ligature's selection state is not consistent, don't join it. This helps the
@@ -153,6 +159,13 @@ export class DomRendererRowFactory {
153
159
  const isInSelection = this._isCellInSelection(x, row);
154
160
  const isCursorCell = isCursorRow && x === cursorX;
155
161
  const isLinkHover = hasHover && x >= linkStart && x <= linkEnd;
162
+ if (rowInfo && cell.isBlink()) {
163
+ rowInfo.hasBlinkingCells = true;
164
+ }
165
+ const isBlinkHidden = !blinkOn && cell.isBlink();
166
+ if (isBlinkHidden) {
167
+ classes.push(RowCss.BLINK_HIDDEN_CLASS);
168
+ }
156
169
 
157
170
  let isDecorated = false;
158
171
  this._decorationService.forEachDecorationAtCell(x, row, undefined, d => {
@@ -397,7 +410,7 @@ export class DomRendererRowFactory {
397
410
  break;
398
411
  case Attributes.CM_RGB:
399
412
  resolvedBg = channels.toColor(bg >> 16, bg >> 8 & 0xFF, bg & 0xFF);
400
- this._addStyle(charElement, `background-color:#${padStart((bg >>> 0).toString(16), '0', 6)}`);
413
+ this._addStyle(charElement, `background-color:#${(bg >>> 0).toString(16).padStart(6, '0')}`);
401
414
  break;
402
415
  case Attributes.CM_DEFAULT:
403
416
  default:
@@ -434,7 +447,7 @@ export class DomRendererRowFactory {
434
447
  (fg ) & 0xFF
435
448
  );
436
449
  if (!this._applyMinimumContrast(charElement, resolvedBg, color, cell, bgOverride, fgOverride)) {
437
- this._addStyle(charElement, `color:#${padStart(fg.toString(16), '0', 6)}`);
450
+ this._addStyle(charElement, `color:#${fg.toString(16).padStart(6, '0')}`);
438
451
  }
439
452
  break;
440
453
  case Attributes.CM_DEFAULT:
@@ -494,8 +507,8 @@ export class DomRendererRowFactory {
494
507
  // Dim cells only require half the contrast, otherwise they wouldn't be distinguishable from
495
508
  // non-dim cells
496
509
  const ratio = this._optionsService.rawOptions.minimumContrastRatio / (cell.isDim() ? 2 : 1);
497
- adjustedColor = color.ensureContrastRatio(bgOverride || bg, fgOverride || fg, ratio);
498
- cache.setColor((bgOverride || bg).rgba, (fgOverride || fg).rgba, adjustedColor ?? null);
510
+ adjustedColor = color.ensureContrastRatio(bgOverride ?? bg, fgOverride ?? fg, ratio);
511
+ cache.setColor((bgOverride ?? bg).rgba, (fgOverride ?? fg).rgba, adjustedColor ?? null);
499
512
  }
500
513
 
501
514
  if (adjustedColor) {
@@ -537,10 +550,3 @@ export class DomRendererRowFactory {
537
550
  (start[1] < end[1] && y === start[1] && x >= start[0]);
538
551
  }
539
552
  }
540
-
541
- function padStart(text: string, padChar: string, length: number): string {
542
- while (text.length < length) {
543
- text = padChar + text;
544
- }
545
- return text;
546
- }