@kingkoo1985/ink 6.6.6
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/build/colorize.d.ts +4 -0
- package/build/colorize.js +59 -0
- package/build/colorize.js.map +1 -0
- package/build/components/AccessibilityContext.d.ts +3 -0
- package/build/components/AccessibilityContext.js +5 -0
- package/build/components/AccessibilityContext.js.map +1 -0
- package/build/components/App.d.ts +68 -0
- package/build/components/App.js +290 -0
- package/build/components/App.js.map +1 -0
- package/build/components/AppContext.d.ts +52 -0
- package/build/components/AppContext.js +16 -0
- package/build/components/AppContext.js.map +1 -0
- package/build/components/BackgroundContext.d.ts +4 -0
- package/build/components/BackgroundContext.js +3 -0
- package/build/components/BackgroundContext.js.map +1 -0
- package/build/components/Box.d.ts +171 -0
- package/build/components/Box.js +40 -0
- package/build/components/Box.js.map +1 -0
- package/build/components/ErrorOverview.d.ts +6 -0
- package/build/components/ErrorOverview.js +84 -0
- package/build/components/ErrorOverview.js.map +1 -0
- package/build/components/FocusContext.d.ts +16 -0
- package/build/components/FocusContext.js +16 -0
- package/build/components/FocusContext.js.map +1 -0
- package/build/components/Newline.d.ts +13 -0
- package/build/components/Newline.js +8 -0
- package/build/components/Newline.js.map +1 -0
- package/build/components/Spacer.d.ts +7 -0
- package/build/components/Spacer.js +11 -0
- package/build/components/Spacer.js.map +1 -0
- package/build/components/Static.d.ts +24 -0
- package/build/components/Static.js +29 -0
- package/build/components/Static.js.map +1 -0
- package/build/components/StaticRender.d.ts +8 -0
- package/build/components/StaticRender.js +19 -0
- package/build/components/StaticRender.js.map +1 -0
- package/build/components/StderrContext.d.ts +15 -0
- package/build/components/StderrContext.js +12 -0
- package/build/components/StderrContext.js.map +1 -0
- package/build/components/StdinContext.d.ts +22 -0
- package/build/components/StdinContext.js +16 -0
- package/build/components/StdinContext.js.map +1 -0
- package/build/components/StdoutContext.d.ts +15 -0
- package/build/components/StdoutContext.js +12 -0
- package/build/components/StdoutContext.js.map +1 -0
- package/build/components/Text.d.ts +63 -0
- package/build/components/Text.js +50 -0
- package/build/components/Text.js.map +1 -0
- package/build/components/Transform.d.ts +16 -0
- package/build/components/Transform.js +15 -0
- package/build/components/Transform.js.map +1 -0
- package/build/data-limited-lru-map.d.ts +20 -0
- package/build/data-limited-lru-map.js +65 -0
- package/build/data-limited-lru-map.js.map +1 -0
- package/build/debug-log.d.ts +2 -0
- package/build/debug-log.js +44 -0
- package/build/debug-log.js.map +1 -0
- package/build/devtools-window-polyfill.d.ts +1 -0
- package/build/devtools-window-polyfill.js +65 -0
- package/build/devtools-window-polyfill.js.map +1 -0
- package/build/devtools.d.ts +1 -0
- package/build/devtools.js +8 -0
- package/build/devtools.js.map +1 -0
- package/build/dom.d.ts +114 -0
- package/build/dom.js +169 -0
- package/build/dom.js.map +1 -0
- package/build/get-max-width.d.ts +3 -0
- package/build/get-max-width.js +10 -0
- package/build/get-max-width.js.map +1 -0
- package/build/hooks/use-app.d.ts +5 -0
- package/build/hooks/use-app.js +8 -0
- package/build/hooks/use-app.js.map +1 -0
- package/build/hooks/use-focus-manager.d.ts +28 -0
- package/build/hooks/use-focus-manager.js +17 -0
- package/build/hooks/use-focus-manager.js.map +1 -0
- package/build/hooks/use-focus.d.ts +29 -0
- package/build/hooks/use-focus.js +42 -0
- package/build/hooks/use-focus.js.map +1 -0
- package/build/hooks/use-input.d.ts +93 -0
- package/build/hooks/use-input.js +92 -0
- package/build/hooks/use-input.js.map +1 -0
- package/build/hooks/use-is-screen-reader-enabled.d.ts +5 -0
- package/build/hooks/use-is-screen-reader-enabled.js +11 -0
- package/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
- package/build/hooks/use-stderr.d.ts +5 -0
- package/build/hooks/use-stderr.js +8 -0
- package/build/hooks/use-stderr.js.map +1 -0
- package/build/hooks/use-stdin.d.ts +5 -0
- package/build/hooks/use-stdin.js +8 -0
- package/build/hooks/use-stdin.js.map +1 -0
- package/build/hooks/use-stdout.d.ts +5 -0
- package/build/hooks/use-stdout.js +8 -0
- package/build/hooks/use-stdout.js.map +1 -0
- package/build/index.d.ts +38 -0
- package/build/index.js +27 -0
- package/build/index.js.map +1 -0
- package/build/ink.d.ts +110 -0
- package/build/ink.js +576 -0
- package/build/ink.js.map +1 -0
- package/build/instances.d.ts +3 -0
- package/build/instances.js +8 -0
- package/build/instances.js.map +1 -0
- package/build/layout.d.ts +18 -0
- package/build/layout.js +54 -0
- package/build/layout.js.map +1 -0
- package/build/log-update.d.ts +28 -0
- package/build/log-update.js +529 -0
- package/build/log-update.js.map +1 -0
- package/build/measure-element.d.ts +119 -0
- package/build/measure-element.js +825 -0
- package/build/measure-element.js.map +1 -0
- package/build/measure-text.d.ts +50 -0
- package/build/measure-text.js +237 -0
- package/build/measure-text.js.map +1 -0
- package/build/output.d.ts +242 -0
- package/build/output.js +607 -0
- package/build/output.js.map +1 -0
- package/build/parse-keypress.d.ts +14 -0
- package/build/parse-keypress.js +225 -0
- package/build/parse-keypress.js.map +1 -0
- package/build/reconciler.d.ts +4 -0
- package/build/reconciler.js +326 -0
- package/build/reconciler.js.map +1 -0
- package/build/render-background.d.ts +4 -0
- package/build/render-background.js +37 -0
- package/build/render-background.js.map +1 -0
- package/build/render-border.d.ts +4 -0
- package/build/render-border.js +81 -0
- package/build/render-border.js.map +1 -0
- package/build/render-cached.d.ts +18 -0
- package/build/render-cached.js +66 -0
- package/build/render-cached.js.map +1 -0
- package/build/render-container.d.ts +27 -0
- package/build/render-container.js +169 -0
- package/build/render-container.js.map +1 -0
- package/build/render-node-to-output.d.ts +32 -0
- package/build/render-node-to-output.js +177 -0
- package/build/render-node-to-output.js.map +1 -0
- package/build/render-screen-reader.d.ts +5 -0
- package/build/render-screen-reader.js +54 -0
- package/build/render-screen-reader.js.map +1 -0
- package/build/render-scrollbar.d.ts +23 -0
- package/build/render-scrollbar.js +70 -0
- package/build/render-scrollbar.js.map +1 -0
- package/build/render-sticky.d.ts +53 -0
- package/build/render-sticky.js +317 -0
- package/build/render-sticky.js.map +1 -0
- package/build/render-text-node.d.ts +20 -0
- package/build/render-text-node.js +155 -0
- package/build/render-text-node.js.map +1 -0
- package/build/render.d.ts +165 -0
- package/build/render.js +60 -0
- package/build/render.js.map +1 -0
- package/build/renderer.d.ts +24 -0
- package/build/renderer.js +292 -0
- package/build/renderer.js.map +1 -0
- package/build/replay.d.ts +59 -0
- package/build/replay.js +128 -0
- package/build/replay.js.map +1 -0
- package/build/resize-observer.d.ts +24 -0
- package/build/resize-observer.js +102 -0
- package/build/resize-observer.js.map +1 -0
- package/build/scroll.d.ts +11 -0
- package/build/scroll.js +123 -0
- package/build/scroll.js.map +1 -0
- package/build/selection.d.ts +52 -0
- package/build/selection.js +359 -0
- package/build/selection.js.map +1 -0
- package/build/serialization.d.ts +25 -0
- package/build/serialization.js +224 -0
- package/build/serialization.js.map +1 -0
- package/build/squash-text-nodes.d.ts +16 -0
- package/build/squash-text-nodes.js +58 -0
- package/build/squash-text-nodes.js.map +1 -0
- package/build/styled-line.d.ts +58 -0
- package/build/styled-line.js +629 -0
- package/build/styled-line.js.map +1 -0
- package/build/styles.d.ts +286 -0
- package/build/styles.js +257 -0
- package/build/styles.js.map +1 -0
- package/build/terminal-buffer.d.ts +57 -0
- package/build/terminal-buffer.js +507 -0
- package/build/terminal-buffer.js.map +1 -0
- package/build/text-wrap.d.ts +12 -0
- package/build/text-wrap.js +154 -0
- package/build/text-wrap.js.map +1 -0
- package/build/tokenize.d.ts +47 -0
- package/build/tokenize.js +419 -0
- package/build/tokenize.js.map +1 -0
- package/build/vertical-gap.d.ts +17 -0
- package/build/vertical-gap.js +20 -0
- package/build/vertical-gap.js.map +1 -0
- package/build/worker/animation-controller.d.ts +72 -0
- package/build/worker/animation-controller.js +128 -0
- package/build/worker/animation-controller.js.map +1 -0
- package/build/worker/ansi-utils.d.ts +16 -0
- package/build/worker/ansi-utils.js +40 -0
- package/build/worker/ansi-utils.js.map +1 -0
- package/build/worker/canvas.d.ts +49 -0
- package/build/worker/canvas.js +90 -0
- package/build/worker/canvas.js.map +1 -0
- package/build/worker/compositor.d.ts +33 -0
- package/build/worker/compositor.js +308 -0
- package/build/worker/compositor.js.map +1 -0
- package/build/worker/platform.d.ts +15 -0
- package/build/worker/platform.js +19 -0
- package/build/worker/platform.js.map +1 -0
- package/build/worker/render-worker.d.ts +112 -0
- package/build/worker/render-worker.js +944 -0
- package/build/worker/render-worker.js.map +1 -0
- package/build/worker/scene-manager.d.ts +26 -0
- package/build/worker/scene-manager.js +109 -0
- package/build/worker/scene-manager.js.map +1 -0
- package/build/worker/scroll-optimizer.d.ts +32 -0
- package/build/worker/scroll-optimizer.js +110 -0
- package/build/worker/scroll-optimizer.js.map +1 -0
- package/build/worker/terminal-writer.d.ts +116 -0
- package/build/worker/terminal-writer.js +708 -0
- package/build/worker/terminal-writer.js.map +1 -0
- package/build/worker/worker-entry.d.ts +6 -0
- package/build/worker/worker-entry.js +130 -0
- package/build/worker/worker-entry.js.map +1 -0
- package/license +9 -0
- package/package.json +208 -0
- package/readme.md +2353 -0
|
@@ -0,0 +1,708 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import process from 'node:process';
|
|
7
|
+
import ansiEscapes from 'ansi-escapes';
|
|
8
|
+
import { styledLineToString } from '../tokenize.js';
|
|
9
|
+
import { StyledLine } from '../styled-line.js';
|
|
10
|
+
import { debugLog } from '../debug-log.js';
|
|
11
|
+
import colorize from '../colorize.js';
|
|
12
|
+
import { debugWorker } from './render-worker.js';
|
|
13
|
+
import { enterSynchronizedOutput, exitSynchronizedOutput, resetScrollRegion, ris, clearScrollbackStandard, homeEraseDown, getMoveCursorDownCode, getMoveCursorUpCode, getDeleteLinesCode, getInsertLinesCode, getSetScrollRegionCode, } from './ansi-utils.js';
|
|
14
|
+
import { platform } from './platform.js';
|
|
15
|
+
const synchronizeOutput = true;
|
|
16
|
+
export const rainbowColors = [
|
|
17
|
+
'ansi256(17)',
|
|
18
|
+
'ansi256(18)',
|
|
19
|
+
'ansi256(19)',
|
|
20
|
+
'ansi256(20)',
|
|
21
|
+
'ansi256(21)',
|
|
22
|
+
'ansi256(25)',
|
|
23
|
+
'ansi256(26)',
|
|
24
|
+
'ansi256(27)',
|
|
25
|
+
'ansi256(31)',
|
|
26
|
+
'ansi256(32)',
|
|
27
|
+
'ansi256(33)',
|
|
28
|
+
'ansi256(39)',
|
|
29
|
+
'ansi256(63)',
|
|
30
|
+
'ansi256(69)',
|
|
31
|
+
'ansi256(75)',
|
|
32
|
+
];
|
|
33
|
+
export function linesEqual(lineA, lineB) {
|
|
34
|
+
if (lineA === lineB)
|
|
35
|
+
return true;
|
|
36
|
+
if (!lineA || !lineB)
|
|
37
|
+
return false;
|
|
38
|
+
return lineA.equals(lineB);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Low level terminal renderer.
|
|
42
|
+
*
|
|
43
|
+
* This class makes it robust and simple to perform efficient incremental updates to the
|
|
44
|
+
* terminal, scroll regions, and inject content into the backbuffer.
|
|
45
|
+
* It handles caching what content was previously rendered and operations
|
|
46
|
+
* such as syncing individual lines without generating flicker, adding
|
|
47
|
+
* lines to the backbuffer, and scrolling content onto the backbuffer.
|
|
48
|
+
*/
|
|
49
|
+
export class TerminalWriter {
|
|
50
|
+
columns;
|
|
51
|
+
rows;
|
|
52
|
+
stdout;
|
|
53
|
+
isTainted = false;
|
|
54
|
+
debugRainbowColor;
|
|
55
|
+
backbufferDirty = false;
|
|
56
|
+
backbufferScrolledIncorrectly = false;
|
|
57
|
+
backbufferDirtyCurrentFrame = false;
|
|
58
|
+
fullRenderTimeout;
|
|
59
|
+
maxScrollbackLength = 1000;
|
|
60
|
+
forceScrollToBottomOnBackbufferRefresh = false;
|
|
61
|
+
linesUpdated = 0;
|
|
62
|
+
screen = [];
|
|
63
|
+
backbuffer = [];
|
|
64
|
+
cursorX = -1;
|
|
65
|
+
cursorY = -1;
|
|
66
|
+
targetCursorX = -1;
|
|
67
|
+
targetCursorY = -1;
|
|
68
|
+
scrollRegionTop = -1;
|
|
69
|
+
scrollRegionBottom = -1;
|
|
70
|
+
firstRender = true;
|
|
71
|
+
enableSynchronizedOutput = synchronizeOutput;
|
|
72
|
+
cancelSlowFlush;
|
|
73
|
+
isDone = false;
|
|
74
|
+
outputBuffer = [];
|
|
75
|
+
currentChunkBuffer = [];
|
|
76
|
+
constructor(columns, rows, stdout) {
|
|
77
|
+
this.columns = columns;
|
|
78
|
+
this.rows = rows;
|
|
79
|
+
this.stdout = stdout;
|
|
80
|
+
}
|
|
81
|
+
getLinesUpdated() {
|
|
82
|
+
return this.linesUpdated;
|
|
83
|
+
}
|
|
84
|
+
resetLinesUpdated() {
|
|
85
|
+
this.linesUpdated = 0;
|
|
86
|
+
}
|
|
87
|
+
unkownCursorLocation() {
|
|
88
|
+
this.cursorX = -1;
|
|
89
|
+
this.cursorY = -1;
|
|
90
|
+
}
|
|
91
|
+
writeRaw(text) {
|
|
92
|
+
this.writeHelper(text);
|
|
93
|
+
}
|
|
94
|
+
taintScreen() {
|
|
95
|
+
for (const line of this.screen) {
|
|
96
|
+
if (line) {
|
|
97
|
+
line.tainted = true;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
getBackbufferLength() {
|
|
102
|
+
return this.backbuffer.length;
|
|
103
|
+
}
|
|
104
|
+
getBackbufferEntry(index) {
|
|
105
|
+
return this.backbuffer[index];
|
|
106
|
+
}
|
|
107
|
+
getScreenLine(y) {
|
|
108
|
+
return this.screen[y];
|
|
109
|
+
}
|
|
110
|
+
setBackbuffer(lines) {
|
|
111
|
+
this.backbuffer = lines;
|
|
112
|
+
}
|
|
113
|
+
get isFirstRender() {
|
|
114
|
+
return this.firstRender;
|
|
115
|
+
}
|
|
116
|
+
appendLinesBackbuffer(lines) {
|
|
117
|
+
this.startSynchronizedOutput();
|
|
118
|
+
try {
|
|
119
|
+
for (const line of lines) {
|
|
120
|
+
// 1. Replace the top line with the clean version
|
|
121
|
+
this.syncLine(line, 0);
|
|
122
|
+
// 2. Scroll the terminal up, which pushes row 0 (the clean line) to history
|
|
123
|
+
this.applyScrollUpBackbuffer(0, this.rows);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
this.endSynchronizedOutput();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
updateBackbuffer(start, deleteCount, newLines) {
|
|
131
|
+
const backbufferLength = this.backbuffer.length;
|
|
132
|
+
const screenStart = Math.max(0, backbufferLength - this.rows);
|
|
133
|
+
// Case 1: Append at the very end
|
|
134
|
+
if (start === backbufferLength && deleteCount === 0) {
|
|
135
|
+
this.appendLinesBackbuffer(newLines);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Case 2: Within the screen
|
|
139
|
+
if (start >= screenStart) {
|
|
140
|
+
this.backbuffer.splice(start, deleteCount, ...newLines);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// Case 3: Other cases (outside screen, not append)
|
|
144
|
+
this.isTainted = true;
|
|
145
|
+
}
|
|
146
|
+
syncLines(lines) {
|
|
147
|
+
const backBufferLength = Math.max(0, lines.length - this.rows);
|
|
148
|
+
for (const [i, line] of lines.entries()) {
|
|
149
|
+
if (i < backBufferLength) {
|
|
150
|
+
const clampedLine = this.clampLine(line.styledChars, this.columns);
|
|
151
|
+
this.backbuffer.push(clampedLine);
|
|
152
|
+
if (this.backbuffer.length > this.maxScrollbackLength) {
|
|
153
|
+
this.backbuffer.shift();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const screenRow = i - backBufferLength;
|
|
158
|
+
this.syncLine(line, screenRow);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
this.firstRender = false;
|
|
162
|
+
}
|
|
163
|
+
writeLines(lines) {
|
|
164
|
+
if (this.backbuffer.length > 0 || this.screen.length > 0) {
|
|
165
|
+
throw new Error(`writeLines can only be called on an empty terminal. Sizes = ${this.backbuffer.length}, ${this.screen.length}`);
|
|
166
|
+
}
|
|
167
|
+
const backBufferLength = Math.max(0, lines.length - this.rows);
|
|
168
|
+
for (const [i, line] of lines.entries()) {
|
|
169
|
+
const clampedLine = this.clampLine(line.styledChars, this.columns);
|
|
170
|
+
let textToWrite = clampedLine.text;
|
|
171
|
+
if (this.debugRainbowColor) {
|
|
172
|
+
textToWrite = colorize(textToWrite, this.debugRainbowColor, 'background');
|
|
173
|
+
}
|
|
174
|
+
this.writeHelper(textToWrite);
|
|
175
|
+
this.linesUpdated++;
|
|
176
|
+
if (i >= backBufferLength &&
|
|
177
|
+
i < backBufferLength + this.rows &&
|
|
178
|
+
this.isFirstRender &&
|
|
179
|
+
clampedLine.length < this.columns) {
|
|
180
|
+
// Need to clear any text we might be rendering on top of.
|
|
181
|
+
this.writeHelper(ansiEscapes.eraseEndLine);
|
|
182
|
+
}
|
|
183
|
+
if (i + 1 < lines.length) {
|
|
184
|
+
this.writeHelper('\n');
|
|
185
|
+
}
|
|
186
|
+
if (i < backBufferLength) {
|
|
187
|
+
this.backbuffer.push(clampedLine);
|
|
188
|
+
if (this.backbuffer.length > this.maxScrollbackLength) {
|
|
189
|
+
this.backbuffer.shift();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.screen.push(clampedLine);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (this.isFirstRender) {
|
|
197
|
+
/// Clean up lines at the bottom of the screen if we
|
|
198
|
+
// rendered at less than the terminal height.
|
|
199
|
+
for (let row = lines.length; row < this.rows; row++) {
|
|
200
|
+
this.writeHelper('\n' + ansiEscapes.eraseEndLine);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
this.cursorX = -1;
|
|
204
|
+
this.cursorY = -1;
|
|
205
|
+
this.firstRender = false;
|
|
206
|
+
this.finishChunkAndUpdateCursor();
|
|
207
|
+
}
|
|
208
|
+
setTargetCursorPosition(row, col) {
|
|
209
|
+
if (this.targetCursorY === row && this.targetCursorX === col) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
this.targetCursorY = row;
|
|
213
|
+
this.targetCursorX = col;
|
|
214
|
+
}
|
|
215
|
+
getExpectedState() {
|
|
216
|
+
return {
|
|
217
|
+
backbuffer: [...this.backbuffer],
|
|
218
|
+
screen: [...this.screen],
|
|
219
|
+
cursorX: this.cursorX,
|
|
220
|
+
cursorY: this.cursorY,
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
finish() {
|
|
224
|
+
this.finishChunkAndUpdateCursor();
|
|
225
|
+
this.targetCursorY = -1;
|
|
226
|
+
this.targetCursorX = -1;
|
|
227
|
+
}
|
|
228
|
+
done() {
|
|
229
|
+
this.finishChunkAndUpdateCursor();
|
|
230
|
+
this.unkownCursorLocation();
|
|
231
|
+
this.resetScrollRegion();
|
|
232
|
+
if (this.screen.length > 0) {
|
|
233
|
+
this.moveCursor(this.rows - 1, 0);
|
|
234
|
+
this.writeHelper('\n');
|
|
235
|
+
this.cursorX = 0;
|
|
236
|
+
this.cursorY = this.rows;
|
|
237
|
+
}
|
|
238
|
+
this.finishChunkAndUpdateCursor();
|
|
239
|
+
this.flush();
|
|
240
|
+
this.isDone = true;
|
|
241
|
+
}
|
|
242
|
+
moveCursor(x, y) {
|
|
243
|
+
if (x === this.cursorY && y === this.cursorX) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const diff = x - this.cursorY;
|
|
247
|
+
if (this.cursorY < 0 ||
|
|
248
|
+
this.cursorX < 0 ||
|
|
249
|
+
x !== this.cursorY ||
|
|
250
|
+
y !== this.cursorX) {
|
|
251
|
+
this.writeHelper(ansiEscapes.cursorTo(y, x));
|
|
252
|
+
this.cursorY = x;
|
|
253
|
+
this.cursorX = y;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (diff > 0) {
|
|
257
|
+
this.writeHelper(getMoveCursorDownCode(diff));
|
|
258
|
+
}
|
|
259
|
+
else if (diff < 0) {
|
|
260
|
+
this.writeHelper(getMoveCursorUpCode(-diff));
|
|
261
|
+
}
|
|
262
|
+
this.cursorY = x;
|
|
263
|
+
if (y !== this.cursorX) {
|
|
264
|
+
if (y === 0) {
|
|
265
|
+
this.writeHelper(ansiEscapes.cursorLeft);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
this.writeHelper(ansiEscapes.cursorTo(y));
|
|
269
|
+
}
|
|
270
|
+
this.cursorX = y;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
clampLine(line, width) {
|
|
274
|
+
if (width <= 0 || !line) {
|
|
275
|
+
return {
|
|
276
|
+
styledChars: new StyledLine(),
|
|
277
|
+
text: '',
|
|
278
|
+
length: 0,
|
|
279
|
+
tainted: false,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
let i = line.length - 1;
|
|
283
|
+
while (i >= 0 && line.getValue(i) === ' ' && !line.hasStyles(i)) {
|
|
284
|
+
i--;
|
|
285
|
+
}
|
|
286
|
+
const trimmedLength = i + 1;
|
|
287
|
+
let visualWidth = 0;
|
|
288
|
+
for (let k = 0; k < trimmedLength; k++) {
|
|
289
|
+
const val = line.getValue(k);
|
|
290
|
+
if (val === '')
|
|
291
|
+
continue;
|
|
292
|
+
visualWidth += line.getFullWidth(k) ? 2 : 1;
|
|
293
|
+
}
|
|
294
|
+
if (visualWidth <= width) {
|
|
295
|
+
const styledChars = trimmedLength === line.length ? line : line.slice(0, trimmedLength);
|
|
296
|
+
return {
|
|
297
|
+
styledChars,
|
|
298
|
+
text: styledLineToString(styledChars),
|
|
299
|
+
length: visualWidth,
|
|
300
|
+
tainted: false,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
// Truncate logic
|
|
304
|
+
const lastVal = line.getValue(i);
|
|
305
|
+
const lastFullWidth = line.getFullWidth(i);
|
|
306
|
+
const hasBoxChar = lastVal === '╮' || lastVal === '│' || lastVal === '╯';
|
|
307
|
+
let targetVisualWidth = width;
|
|
308
|
+
if (hasBoxChar) {
|
|
309
|
+
targetVisualWidth -= lastFullWidth ? 2 : 1;
|
|
310
|
+
}
|
|
311
|
+
let currentWidth = 0;
|
|
312
|
+
let sliceIndex = 0;
|
|
313
|
+
for (let k = 0; k < trimmedLength; k++) {
|
|
314
|
+
const charWidth = line.getFullWidth(k) ? 2 : 1;
|
|
315
|
+
if (currentWidth + charWidth > targetVisualWidth) {
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
currentWidth += charWidth;
|
|
319
|
+
sliceIndex++;
|
|
320
|
+
}
|
|
321
|
+
if (hasBoxChar) {
|
|
322
|
+
const boxWidth = lastFullWidth ? 2 : 1;
|
|
323
|
+
const lastCharLine = new StyledLine();
|
|
324
|
+
lastCharLine.pushChar(lastVal, line.getFormatFlags(i), line.getFgColor(i), line.getBgColor(i), line.getLink(i));
|
|
325
|
+
const styledChars = line.slice(0, sliceIndex).combine(lastCharLine);
|
|
326
|
+
return {
|
|
327
|
+
styledChars,
|
|
328
|
+
text: styledLineToString(styledChars),
|
|
329
|
+
length: currentWidth + boxWidth,
|
|
330
|
+
tainted: false,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
const styledChars = line.slice(0, sliceIndex);
|
|
334
|
+
return {
|
|
335
|
+
styledChars,
|
|
336
|
+
text: styledLineToString(styledChars),
|
|
337
|
+
length: currentWidth,
|
|
338
|
+
tainted: false,
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
syncLine(line, y) {
|
|
342
|
+
if (y < 0 || y >= this.rows) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
const clampedLine = this.clampLine(line.styledChars, this.columns);
|
|
346
|
+
const currentLine = this.screen[y];
|
|
347
|
+
if (currentLine &&
|
|
348
|
+
!currentLine.tainted &&
|
|
349
|
+
currentLine.text === clampedLine.text) {
|
|
350
|
+
// Content matches, no update needed
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
this.moveCursor(y, 0);
|
|
354
|
+
this.linesUpdated++;
|
|
355
|
+
let textToWrite = clampedLine.text;
|
|
356
|
+
if (this.debugRainbowColor) {
|
|
357
|
+
textToWrite = colorize(textToWrite, this.debugRainbowColor, 'background');
|
|
358
|
+
}
|
|
359
|
+
this.writeHelper(textToWrite);
|
|
360
|
+
if (clampedLine.length < this.columns) {
|
|
361
|
+
this.writeHelper(ansiEscapes.eraseEndLine);
|
|
362
|
+
}
|
|
363
|
+
if (y !== this.rows - 1 && y !== this.scrollRegionBottom - 1) {
|
|
364
|
+
this.writeHelper('\n');
|
|
365
|
+
this.cursorY = y + 1;
|
|
366
|
+
this.cursorX = -1;
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.cursorY = y;
|
|
370
|
+
this.cursorX = clampedLine.length;
|
|
371
|
+
}
|
|
372
|
+
clampedLine.tainted = false;
|
|
373
|
+
this.screen[y] = clampedLine;
|
|
374
|
+
}
|
|
375
|
+
scrollLines(options) {
|
|
376
|
+
try {
|
|
377
|
+
this.performScroll(options);
|
|
378
|
+
}
|
|
379
|
+
finally {
|
|
380
|
+
this.resetScrollRegion();
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
resize(columns, rows) {
|
|
384
|
+
if (this.columns === columns && this.rows === rows) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
this.columns = columns;
|
|
388
|
+
this.rows = rows;
|
|
389
|
+
const startIndex = Math.max(0, this.backbuffer.length - this.rows);
|
|
390
|
+
for (let i = startIndex; i < this.backbuffer.length; i++) {
|
|
391
|
+
const line = this.backbuffer[i];
|
|
392
|
+
if (line && line.length >= this.columns) {
|
|
393
|
+
line.tainted = true;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
for (const line of this.screen) {
|
|
397
|
+
if (line) {
|
|
398
|
+
line.tainted = true;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
clear(_options) {
|
|
403
|
+
if (process.env['TERM_PROGRAM'] === 'vscode' &&
|
|
404
|
+
this.forceScrollToBottomOnBackbufferRefresh) {
|
|
405
|
+
this.writeHelper(ris);
|
|
406
|
+
}
|
|
407
|
+
else if (process.env['TERM_PROGRAM'] === 'iTerm.app') {
|
|
408
|
+
this.writeHelper(ansiEscapes.clearTerminal);
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
this.writeHelper(clearScrollbackStandard);
|
|
412
|
+
this.writeHelper(homeEraseDown);
|
|
413
|
+
}
|
|
414
|
+
// Tmux does not reset the scroll region reliably on clear so we
|
|
415
|
+
// reset it manually.
|
|
416
|
+
this.writeHelper(resetScrollRegion);
|
|
417
|
+
this.scrollRegionTop = -1;
|
|
418
|
+
this.scrollRegionBottom = -1;
|
|
419
|
+
this.screen = [];
|
|
420
|
+
this.backbuffer = [];
|
|
421
|
+
this.firstRender = true;
|
|
422
|
+
this.backbufferDirty = false;
|
|
423
|
+
this.backbufferDirtyCurrentFrame = false;
|
|
424
|
+
if (this.fullRenderTimeout) {
|
|
425
|
+
clearTimeout(this.fullRenderTimeout);
|
|
426
|
+
this.fullRenderTimeout = undefined;
|
|
427
|
+
}
|
|
428
|
+
// Set the cursor to an unknown location as tmux
|
|
429
|
+
// Does not appear to always reset it to 0,0 on clear
|
|
430
|
+
// While in mouse mode.
|
|
431
|
+
this.cursorX = -1;
|
|
432
|
+
this.cursorY = -1;
|
|
433
|
+
}
|
|
434
|
+
startSynchronizedOutput() {
|
|
435
|
+
this.writeHelper(enterSynchronizedOutput);
|
|
436
|
+
}
|
|
437
|
+
endSynchronizedOutput() {
|
|
438
|
+
this.writeHelper(exitSynchronizedOutput);
|
|
439
|
+
this.finishChunkAndUpdateCursor();
|
|
440
|
+
}
|
|
441
|
+
flush() {
|
|
442
|
+
if (this.isDone)
|
|
443
|
+
return;
|
|
444
|
+
if (this.cancelSlowFlush) {
|
|
445
|
+
this.cancelSlowFlush();
|
|
446
|
+
}
|
|
447
|
+
this.finishChunkAndUpdateCursor();
|
|
448
|
+
if (this.outputBuffer.length > 0) {
|
|
449
|
+
this.synchronizedWrite(this.outputBuffer.join(''));
|
|
450
|
+
}
|
|
451
|
+
this.firstRender = false;
|
|
452
|
+
this.outputBuffer = [];
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Testing only method that flushes content slowly to simplify debugging
|
|
456
|
+
* hard to diagnose issues.
|
|
457
|
+
*
|
|
458
|
+
* If there are bugs in terminal-writer a good way to debug is to call
|
|
459
|
+
* slowFlush instead of flush() so you can see the incremental states the
|
|
460
|
+
* terminal goes through applying the changes.
|
|
461
|
+
*/
|
|
462
|
+
async slowFlush() {
|
|
463
|
+
if (this.isDone)
|
|
464
|
+
return;
|
|
465
|
+
if (this.cancelSlowFlush) {
|
|
466
|
+
this.cancelSlowFlush();
|
|
467
|
+
}
|
|
468
|
+
this.finishChunkAndUpdateCursor();
|
|
469
|
+
if (this.outputBuffer.length === 0) {
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
this.firstRender = false;
|
|
473
|
+
while (this.outputBuffer.length > 0) {
|
|
474
|
+
const chunk = this.outputBuffer.shift();
|
|
475
|
+
if (chunk) {
|
|
476
|
+
this.synchronizedWrite(chunk);
|
|
477
|
+
}
|
|
478
|
+
// eslint-disable-next-line no-await-in-loop
|
|
479
|
+
await new Promise(resolve => {
|
|
480
|
+
let finished = false;
|
|
481
|
+
const timer = setTimeout(() => {
|
|
482
|
+
finished = true;
|
|
483
|
+
this.cancelSlowFlush = undefined;
|
|
484
|
+
resolve();
|
|
485
|
+
}, 50);
|
|
486
|
+
this.cancelSlowFlush = () => {
|
|
487
|
+
if (!finished) {
|
|
488
|
+
clearTimeout(timer);
|
|
489
|
+
finished = true;
|
|
490
|
+
if (this.outputBuffer.length > 0) {
|
|
491
|
+
this.synchronizedWrite(this.outputBuffer.join(''));
|
|
492
|
+
this.outputBuffer = [];
|
|
493
|
+
}
|
|
494
|
+
this.cancelSlowFlush = undefined;
|
|
495
|
+
resolve();
|
|
496
|
+
}
|
|
497
|
+
};
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
validateLinesConsistent(lines) {
|
|
502
|
+
if (this.isTainted) {
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
for (let r = 0; r < this.rows; r++) {
|
|
506
|
+
const index = lines.length + r - this.rows;
|
|
507
|
+
if (index < 0) {
|
|
508
|
+
continue;
|
|
509
|
+
}
|
|
510
|
+
if (!linesEqual(this.screen[r]?.styledChars, lines[index]?.styledChars) &&
|
|
511
|
+
debugWorker) {
|
|
512
|
+
debugLog(`Line ${r} on screen inconsistent between terminalWriter and ground truth. Expected "${styledLineToString(lines[index]?.styledChars ?? new StyledLine())}", got "${styledLineToString(this.screen[r]?.styledChars ?? new StyledLine())}"`);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
// Validated the backbuffer matches for lines 0 -> this.lines.length - this.rows
|
|
516
|
+
const backbufferLimit = lines.length - this.rows;
|
|
517
|
+
for (let i = 0; i < backbufferLimit; i++) {
|
|
518
|
+
if (!linesEqual(this.backbuffer[i]?.styledChars, lines[i]?.styledChars) &&
|
|
519
|
+
debugWorker) {
|
|
520
|
+
debugLog(`Line ${i} in backbuffer inconsistent. Expected "${styledLineToString(lines[i]?.styledChars ?? new StyledLine())}", got "${styledLineToString(this.backbuffer[i]?.styledChars ?? new StyledLine())}"`);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
shiftScreenUp(start, bottom) {
|
|
525
|
+
for (let i = start; i < bottom - 1; i++) {
|
|
526
|
+
this.screen[i] = this.screen[i + 1];
|
|
527
|
+
}
|
|
528
|
+
this.screen[bottom - 1] = {
|
|
529
|
+
styledChars: new StyledLine(),
|
|
530
|
+
text: '',
|
|
531
|
+
length: 0,
|
|
532
|
+
tainted: false,
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Trigger a scroll up of content into the backbuffer.
|
|
537
|
+
*/
|
|
538
|
+
applyScrollUpBackbuffer(start, bottom) {
|
|
539
|
+
// Simulate the effect of adding a linebreak at the bottom of the scroll region.
|
|
540
|
+
this.moveCursor(bottom - 1, 0);
|
|
541
|
+
this.writeHelper('\n');
|
|
542
|
+
this.cursorX = -1;
|
|
543
|
+
this.cursorY = bottom - 1;
|
|
544
|
+
if (start === 0) {
|
|
545
|
+
this.backbuffer.push(this.screen[0]);
|
|
546
|
+
if (this.backbuffer.length > this.maxScrollbackLength) {
|
|
547
|
+
this.backbuffer.shift();
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
this.shiftScreenUp(start, bottom);
|
|
551
|
+
}
|
|
552
|
+
applyScrollUp(start, bottom) {
|
|
553
|
+
if (start === 0 && platform.isAppleTerminal() && bottom > 1) {
|
|
554
|
+
// Terminal.app doesn't respect scroll regions starting at line 0.
|
|
555
|
+
// Workaround: set scroll region to exclude line 0, do hardware scroll
|
|
556
|
+
// on lines 1+, then manually rewrite line 0.
|
|
557
|
+
const line0Content = this.screen[1];
|
|
558
|
+
// Set scroll region to lines 1 through bottom (excluding line 0)
|
|
559
|
+
this.writeHelper(getSetScrollRegionCode(1, bottom)); // 1-indexed: line 2 = index 1
|
|
560
|
+
this.scrollRegionTop = 1;
|
|
561
|
+
this.scrollRegionBottom = bottom;
|
|
562
|
+
// Now delete a line at line 1 (this will scroll within the region)
|
|
563
|
+
this.moveCursor(1, 0);
|
|
564
|
+
this.writeHelper(getDeleteLinesCode(1));
|
|
565
|
+
// Update screen state for lines 1 through bottom-1
|
|
566
|
+
this.shiftScreenUp(1, bottom);
|
|
567
|
+
// Mark line 0 as tainted so it gets redrawn with what was line 1
|
|
568
|
+
if (line0Content) {
|
|
569
|
+
this.screen[0] = { ...line0Content, tainted: true };
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
this.screen[0] = {
|
|
573
|
+
styledChars: new StyledLine(),
|
|
574
|
+
text: '',
|
|
575
|
+
length: 0,
|
|
576
|
+
tainted: true,
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
this.moveCursor(start, 0);
|
|
582
|
+
this.writeHelper(getDeleteLinesCode(1));
|
|
583
|
+
// Simulate the effect of the ansi escape for scroll up
|
|
584
|
+
this.shiftScreenUp(start, bottom);
|
|
585
|
+
}
|
|
586
|
+
applyScrollDown(start, bottom) {
|
|
587
|
+
this.moveCursor(start, 0);
|
|
588
|
+
this.writeHelper(getInsertLinesCode(1));
|
|
589
|
+
// Simulate the effect of the ansi escape for scroll up
|
|
590
|
+
for (let i = bottom - 1; i > start; i--) {
|
|
591
|
+
this.screen[i] = this.screen[i - 1];
|
|
592
|
+
}
|
|
593
|
+
this.screen[start] = {
|
|
594
|
+
styledChars: new StyledLine(),
|
|
595
|
+
text: '',
|
|
596
|
+
length: 0,
|
|
597
|
+
tainted: false,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
performScroll(options) {
|
|
601
|
+
const { start, end, linesToScroll, lines, direction, scrollToBackbuffer } = options;
|
|
602
|
+
if (debugWorker) {
|
|
603
|
+
debugLog(`[terminal-writer] SCROLLING LINES ${start}-${end} by ${linesToScroll} ${direction}`);
|
|
604
|
+
}
|
|
605
|
+
this.setScrollRegion(start, end);
|
|
606
|
+
const scrollAreaHeight = end - start;
|
|
607
|
+
if (lines.length !== end - start + linesToScroll) {
|
|
608
|
+
throw new Error(`Mismatch in scrollLines: expected ${end - start + linesToScroll} lines, got ${lines.length}`);
|
|
609
|
+
}
|
|
610
|
+
if (scrollToBackbuffer && direction !== 'up') {
|
|
611
|
+
throw new Error(`scrollToBackbuffer is only supported for direction "up"`);
|
|
612
|
+
}
|
|
613
|
+
// Make sure the content on screen before scrolling really matches what is in lines.
|
|
614
|
+
// For 'up', existing content is at the start of 'lines'.
|
|
615
|
+
// For 'down', existing content is at the end of 'lines'.
|
|
616
|
+
const existingContentOffset = direction === 'up' ? 0 : linesToScroll;
|
|
617
|
+
for (let i = start; i < end; i++) {
|
|
618
|
+
this.syncLine(lines[existingContentOffset + i - start], i);
|
|
619
|
+
}
|
|
620
|
+
if (direction === 'up') {
|
|
621
|
+
for (let i = 0; i < linesToScroll; i++) {
|
|
622
|
+
if (scrollToBackbuffer) {
|
|
623
|
+
if (start > 0) {
|
|
624
|
+
// Case: Scrolling a region that doesn't start at row 0.
|
|
625
|
+
// To push row 0 to history, we MUST scroll the whole screen.
|
|
626
|
+
this.setScrollRegion(0, this.rows);
|
|
627
|
+
const savedHeader = this.screen.slice(0, start);
|
|
628
|
+
const savedFooter = this.screen.slice(end, this.rows);
|
|
629
|
+
this.syncLine(lines[i], 0);
|
|
630
|
+
this.applyScrollUpBackbuffer(0, this.rows);
|
|
631
|
+
for (const [k, element] of savedHeader.entries()) {
|
|
632
|
+
this.syncLine(element, k);
|
|
633
|
+
}
|
|
634
|
+
for (const [k, element] of savedFooter.entries()) {
|
|
635
|
+
this.syncLine(element, end + k);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
// Case: start === 0.
|
|
640
|
+
// We can push to history by scrolling the region from 0 to 'end'.
|
|
641
|
+
// This preserves everything below 'end' (e.g. the footer).
|
|
642
|
+
this.setScrollRegion(0, end);
|
|
643
|
+
// 1. Use the provided 'clean' line to replace the top row
|
|
644
|
+
this.syncLine(lines[i], 0);
|
|
645
|
+
this.applyScrollUpBackbuffer(0, end);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
this.applyScrollUp(start, end);
|
|
650
|
+
}
|
|
651
|
+
// Add the new line at the end after scrolling up the other lines
|
|
652
|
+
this.unkownCursorLocation();
|
|
653
|
+
this.syncLine(lines[i + scrollAreaHeight], end - 1);
|
|
654
|
+
}
|
|
655
|
+
this.finishChunkAndUpdateCursor();
|
|
656
|
+
}
|
|
657
|
+
else if (direction === 'down') {
|
|
658
|
+
for (let i = 0; i < linesToScroll; i++) {
|
|
659
|
+
const line = lines[linesToScroll - 1 - i];
|
|
660
|
+
this.applyScrollDown(start, end);
|
|
661
|
+
// Add the new line at the end after scrolling up the other lines
|
|
662
|
+
this.unkownCursorLocation();
|
|
663
|
+
this.syncLine(line, start);
|
|
664
|
+
}
|
|
665
|
+
this.finishChunkAndUpdateCursor();
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
synchronizedWrite(text) {
|
|
669
|
+
if (this.enableSynchronizedOutput) {
|
|
670
|
+
this.stdout.write(enterSynchronizedOutput + text + exitSynchronizedOutput);
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
this.stdout.write(text);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
resetScrollRegion() {
|
|
677
|
+
if (this.scrollRegionTop !== -1 || this.scrollRegionBottom !== -1) {
|
|
678
|
+
this.writeHelper(resetScrollRegion);
|
|
679
|
+
this.unkownCursorLocation();
|
|
680
|
+
this.scrollRegionTop = -1;
|
|
681
|
+
this.scrollRegionBottom = -1;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
setScrollRegion(top, bottom) {
|
|
685
|
+
if (this.scrollRegionTop !== top || this.scrollRegionBottom !== bottom) {
|
|
686
|
+
this.writeHelper(getSetScrollRegionCode(top, bottom));
|
|
687
|
+
this.unkownCursorLocation();
|
|
688
|
+
this.scrollRegionTop = top;
|
|
689
|
+
this.scrollRegionBottom = bottom;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
writeHelper(text) {
|
|
693
|
+
if (this.isDone) {
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
this.currentChunkBuffer.push(text);
|
|
697
|
+
}
|
|
698
|
+
finishChunkAndUpdateCursor() {
|
|
699
|
+
if (this.targetCursorY >= 0 && this.targetCursorX >= 0) {
|
|
700
|
+
this.moveCursor(this.targetCursorY, this.targetCursorX);
|
|
701
|
+
}
|
|
702
|
+
if (this.currentChunkBuffer.length > 0) {
|
|
703
|
+
this.outputBuffer.push(this.currentChunkBuffer.join(''));
|
|
704
|
+
this.currentChunkBuffer = [];
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
//# sourceMappingURL=terminal-writer.js.map
|