Skip to content

Commit 9aba07f

Browse files
committed
putty-style ED2 sequence handling as terminal option
1 parent 41e8ae3 commit 9aba07f

5 files changed

Lines changed: 68 additions & 6 deletions

File tree

src/common/InputHandler.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,37 @@ describe('InputHandler', () => {
438438
inputHandler.eraseInLine(Params.fromArray([2]));
439439
assert.equal(bufferService.buffer.lines.get(2)!.isWrapped, false);
440440
});
441+
it('ED2 with scrollOnDisplayErase turned on', async () => {
442+
const inputHandler = new TestInputHandler(
443+
bufferService,
444+
new MockCharsetService(),
445+
new MockCoreService(),
446+
new MockLogService(),
447+
new MockOptionsService({ scrollOnDisplayErase: true }),
448+
new MockOscLinkService(),
449+
new MockCoreMouseService(),
450+
new MockUnicodeService()
451+
);
452+
const aLine = Array(bufferService.cols + 1).join('a');
453+
// add 2 full lines of text.
454+
await inputHandler.parseP(aLine);
455+
await inputHandler.parseP(aLine);
456+
457+
inputHandler.eraseInDisplay(Params.fromArray([2]));
458+
// those 2 lines should have been pushed to scrollback.
459+
assert.equal(bufferService.rows + 2, bufferService.buffer.lines.length);
460+
assert.equal(bufferService.buffer.ybase, 2);
461+
assert.equal(bufferService.buffer.lines.get(0)?.translateToString(), aLine);
462+
assert.equal(bufferService.buffer.lines.get(1)?.translateToString(), aLine);
463+
464+
// Move to last line and add more text.
465+
bufferService.buffer.y = bufferService.rows - 1;
466+
bufferService.buffer.x = 0;
467+
await inputHandler.parseP(aLine);
468+
inputHandler.eraseInDisplay(Params.fromArray([2]));
469+
// Screen should have been scrolled by a full screen size.
470+
assert.equal(bufferService.rows * 2 + 2, bufferService.buffer.lines.length);
471+
});
441472
it('eraseInDisplay', async () => {
442473
const bufferService = new MockBufferService(80, 7);
443474
const inputHandler = new TestInputHandler(

src/common/InputHandler.ts

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,12 +1220,30 @@ export class InputHandler extends Disposable implements IInputHandler {
12201220
this._dirtyRowTracker.markDirty(0);
12211221
break;
12221222
case 2:
1223-
j = this._bufferService.rows;
1224-
this._dirtyRowTracker.markDirty(j - 1);
1225-
while (j--) {
1226-
this._resetBufferLine(j, respectProtect);
1223+
if (this._optionsService.rawOptions.scrollOnDisplayErase) {
1224+
let fouldLastLineToKeep = false;
1225+
j = this._bufferService.rows;
1226+
const x = this._activeBuffer.getBlankLine(this._eraseAttrData());
1227+
while (j > 0 && !fouldLastLineToKeep) {
1228+
j--;
1229+
const currentLine = this._activeBuffer.lines.get(this._activeBuffer.ybase + j);
1230+
if (currentLine?.translateToString() !== x.translateToString()) {
1231+
fouldLastLineToKeep = true;
1232+
this._dirtyRowTracker.markRangeDirty(0, j);
1233+
}
1234+
}
1235+
for (; j >= 0; j--) {
1236+
this._bufferService.scroll(this._eraseAttrData());
1237+
}
1238+
}
1239+
else {
1240+
j = this._bufferService.rows;
1241+
this._dirtyRowTracker.markDirty(j - 1);
1242+
while (j--) {
1243+
this._resetBufferLine(j, respectProtect);
1244+
}
1245+
this._dirtyRowTracker.markDirty(0);
12271246
}
1228-
this._dirtyRowTracker.markDirty(0);
12291247
break;
12301248
case 3:
12311249
// Clear scrollback (everything not in viewport)

src/common/services/OptionsService.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ export const DEFAULT_OPTIONS: Readonly<Required<ITerminalOptions>> = {
5454
convertEol: false,
5555
termName: 'xterm',
5656
cancelEvents: false,
57-
overviewRuler: {}
57+
overviewRuler: {},
58+
scrollOnDisplayErase: false
5859
};
5960

6061
const FONT_WEIGHT_OPTIONS: Extract<FontWeight, string>[] = ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'];

typings/xterm-headless.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ declare module '@xterm/headless' {
248248
* All features are disabled by default for security reasons.
249249
*/
250250
windowOptions?: IWindowOptions;
251+
252+
/**
253+
* If enabled ED2 (clear screen) escape sequence will push erased text to scrollback.
254+
* This emulates PuTTY default clear screen behaviour.
255+
*/
256+
scrollOnDisplayErase?: boolean
251257
}
252258

253259
/**

typings/xterm.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,12 @@ declare module '@xterm/xterm' {
331331
* decorations underneath the scroll bar.
332332
*/
333333
overviewRuler?: IOverviewRulerOptions;
334+
335+
/**
336+
* If enabled ED2 (clear screen) escape sequence will push erased text to scrollback.
337+
* This emulates PuTTY default clear screen behaviour.
338+
*/
339+
scrollOnDisplayErase?: boolean
334340
}
335341

336342
/**

0 commit comments

Comments
 (0)