Skip to content

Commit a260f7d

Browse files
authored
Merge pull request #5321 from Tyriar/5319
Reflow on resize using similar logic to conpty
2 parents 2042bb8 + 16772e8 commit a260f7d

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
"jsdom": "^18.0.1",
9696
"mocha": "^10.1.0",
9797
"mustache": "^4.2.0",
98-
"node-pty": "1.1.0-beta19",
98+
"node-pty": "^1.1.0-beta31",
9999
"nyc": "^15.1.0",
100100
"source-map-loader": "^3.0.0",
101101
"source-map-support": "^0.5.20",

src/common/buffer/Buffer.ts

+74-1
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,37 @@ export class Buffer implements IBuffer {
320320
if (toRemove.length > 0) {
321321
const newLayoutResult = reflowLargerCreateNewLayout(this.lines, toRemove);
322322
reflowLargerApplyNewLayout(this.lines, newLayoutResult.layout);
323+
324+
// For conpty, it has its own copy of the buffer _without scrollback_ internally. Its behavior
325+
// when reflowing larger is to insert empty lines at the bottom of the buffer as when lines
326+
// unwrap conpty's view cannot pull scrollback down, so it adds empty lines at the end.
327+
let removedInViewport = 0;
328+
const isWindowsMode = this._optionsService.rawOptions.windowsMode || this._optionsService.rawOptions.windowsPty.backend !== undefined || this._optionsService.rawOptions.windowsPty.buildNumber !== undefined;
329+
if (isWindowsMode) {
330+
for (let i = (toRemove.length / 2) - 1; i >= 0; i--) {
331+
if (toRemove[i * 2 + 0] > this.ybase + removedInViewport) {
332+
removedInViewport += toRemove[i * 2 + 1];
333+
}
334+
}
335+
}
336+
323337
this._reflowLargerAdjustViewport(newCols, newRows, newLayoutResult.countRemoved);
338+
339+
// Apply empty lines for any removed in viewport for conpty.
340+
if (isWindowsMode) {
341+
if (removedInViewport > 0) {
342+
for (let i = 0; i < removedInViewport; i++) {
343+
// Just add the new missing rows on Windows as conpty reprints the screen with it's
344+
// view of the world. Once a line enters scrollback for conpty it remains there
345+
this.lines.push(new BufferLine(newCols, this.getNullCell(DEFAULT_ATTR_DATA)));
346+
}
347+
if (this.ybase === this.ydisp) {
348+
this.ydisp += removedInViewport;
349+
}
350+
this.ybase += removedInViewport;
351+
this.y -= removedInViewport;
352+
}
353+
}
324354
}
325355
}
326356

@@ -352,7 +382,7 @@ export class Buffer implements IBuffer {
352382
const nullCell = this.getNullCell(DEFAULT_ATTR_DATA);
353383
// Gather all BufferLines that need to be inserted into the Buffer here so that they can be
354384
// batched up and only committed once
355-
const toInsert = [];
385+
const toInsert: { start: number, newLines: IBufferLine[] }[] = [];
356386
let countToInsert = 0;
357387
// Go backwards as many lines may be trimmed and this will avoid considering them
358388
for (let y = this.lines.length - 1; y >= 0; y--) {
@@ -467,6 +497,20 @@ export class Buffer implements IBuffer {
467497
this.savedY = Math.min(this.savedY + linesToAdd, this.ybase + newRows - 1);
468498
}
469499

500+
// For conpty, it has its own copy of the buffer _without scrollback_ internally. Its behavior
501+
// when reflowing smaller is to reflow all lines inside the viewport, and removing empty or
502+
// whitespace only lines from the bottom, until non-whitespace is hit in order to prevent
503+
// content from being pushed into the scrollback.
504+
let addedInViewport = 0;
505+
const isWindowsMode = this._optionsService.rawOptions.windowsMode || this._optionsService.rawOptions.windowsPty.backend !== undefined || this._optionsService.rawOptions.windowsPty.buildNumber !== undefined;
506+
if (isWindowsMode) {
507+
for (let i = toInsert.length - 1; i >= 0; i--) {
508+
if (toInsert[i].start > this.ybase + addedInViewport) {
509+
addedInViewport += toInsert[i].newLines.length;
510+
}
511+
}
512+
}
513+
470514
// Rearrange lines in the buffer if there are any insertions, this is done at the end rather
471515
// than earlier so that it's a single O(n) pass through the buffer, instead of O(n^2) from many
472516
// costly calls to CircularList.splice.
@@ -520,6 +564,35 @@ export class Buffer implements IBuffer {
520564
this.lines.onTrimEmitter.fire(amountToTrim);
521565
}
522566
}
567+
568+
// Apply empty lines to remove calculated earlier for conpty.
569+
if (isWindowsMode) {
570+
if (addedInViewport > 0) {
571+
let emptyLinesAtBottom = 0;
572+
for (let i = this.lines.length - 1; i >= this.ybase + this.y; i--) {
573+
const line = this.lines.get(i) as BufferLine;
574+
if (line.isWrapped || line.getTrimmedLength() > 0) {
575+
break;
576+
}
577+
emptyLinesAtBottom++;
578+
}
579+
const emptyLinesToRemove = Math.min(addedInViewport, emptyLinesAtBottom);
580+
if (emptyLinesToRemove > 0) {
581+
for (let i = 0; i < emptyLinesToRemove; i++) {
582+
this.lines.pop();
583+
}
584+
if (this.ybase === this.ydisp) {
585+
this.ydisp -= emptyLinesToRemove;
586+
}
587+
this.ybase -= emptyLinesToRemove;
588+
this.y += emptyLinesToRemove;
589+
this.lines.onDeleteEmitter.fire({
590+
index: this.lines.length - emptyLinesToRemove,
591+
amount: emptyLinesToRemove
592+
});
593+
}
594+
}
595+
}
523596
}
524597

525598
/**

yarn.lock

+4-4
Original file line numberDiff line numberDiff line change
@@ -3296,10 +3296,10 @@ node-preload@^0.2.1:
32963296
dependencies:
32973297
process-on-spawn "^1.0.0"
32983298

3299-
3300-
version "1.1.0-beta19"
3301-
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta19.tgz#a74dc04429903c5ac49ee81a15a24590da67d4f3"
3302-
integrity sha512-/p4Zu56EYDdXjjaLWzrIlFyrBnND11LQGP0/L6GEVGURfCNkAlHc3Twg/2I4NPxghimHXgvDlwp7Z2GtvDIh8A==
3299+
node-pty@^1.1.0-beta31:
3300+
version "1.1.0-beta9"
3301+
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.1.0-beta9.tgz#ed643cb3b398d031b4e31c216e8f3b0042435f1d"
3302+
integrity sha512-/Ue38pvXJdgRZ3+me1FgfglLd301GhJN0NStiotdt61tm43N5htUyR/IXOUzOKuNaFmCwIhy6nwb77Ky41LMbw==
33033303
dependencies:
33043304
node-addon-api "^7.1.0"
33053305

0 commit comments

Comments
 (0)