mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
Fix cursor movement when swapping buffers
This commit is contained in:
@@ -48,4 +48,30 @@ describe('BufferSet', () => {
|
||||
assert.equal(bufferSet.active, bufferSet.alt);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cursor handling when swapping buffers', () => {
|
||||
beforeEach(() => {
|
||||
bufferSet.normal.x = 0;
|
||||
bufferSet.normal.y = 0;
|
||||
bufferSet.alt.x = 0;
|
||||
bufferSet.alt.y = 0;
|
||||
});
|
||||
|
||||
it('should keep the cursor stationary when activating alt buffer', () => {
|
||||
bufferSet.activateNormalBuffer();
|
||||
bufferSet.active.x = 30;
|
||||
bufferSet.active.y = 10;
|
||||
bufferSet.activateAltBuffer();
|
||||
assert.equal(bufferSet.active.x, 30);
|
||||
assert.equal(bufferSet.active.y, 10);
|
||||
});
|
||||
it('should keep the cursor stationary when activating normal buffer', () => {
|
||||
bufferSet.activateAltBuffer();
|
||||
bufferSet.active.x = 30;
|
||||
bufferSet.active.y = 10;
|
||||
bufferSet.activateNormalBuffer();
|
||||
assert.equal(bufferSet.active.x, 30);
|
||||
assert.equal(bufferSet.active.y, 10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -61,6 +61,8 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
||||
if (this._activeBuffer === this._normal) {
|
||||
return;
|
||||
}
|
||||
this._normal.x = this._alt.x;
|
||||
this._normal.y = this._alt.y;
|
||||
// The alt buffer should always be cleared when we switch to the normal
|
||||
// buffer. This frees up memory since the alt buffer should always be new
|
||||
// when activated.
|
||||
@@ -82,6 +84,8 @@ export class BufferSet extends EventEmitter implements IBufferSet {
|
||||
// Since the alt buffer is always cleared when the normal buffer is
|
||||
// activated, we want to fill it when switching to it.
|
||||
this._alt.fillViewportRows();
|
||||
this._alt.x = this._normal.x;
|
||||
this._alt.y = this._normal.y;
|
||||
this._activeBuffer = this._alt;
|
||||
this.emit('activate', {
|
||||
activeBuffer: this._alt,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { assert, expect } from 'chai';
|
||||
import { InputHandler } from './InputHandler';
|
||||
import { MockInputHandlingTerminal } from './utils/TestUtils.test';
|
||||
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX } from './Buffer';
|
||||
import { NULL_CELL_CHAR, NULL_CELL_CODE, NULL_CELL_WIDTH, CHAR_DATA_CHAR_INDEX, CHAR_DATA_ATTR_INDEX, DEFAULT_ATTR } from './Buffer';
|
||||
import { Terminal } from './Terminal';
|
||||
import { IBufferLine } from './Types';
|
||||
|
||||
@@ -506,4 +506,50 @@ describe('InputHandler', () => {
|
||||
inputHandler.print(String.fromCharCode(0x200B), 0, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('alt screen', () => {
|
||||
let term: Terminal;
|
||||
let handler: InputHandler;
|
||||
|
||||
function lineContent(line: IBufferLine): string {
|
||||
let content = '';
|
||||
for (let i = 0; i < line.length; ++i) content += line.get(i)[CHAR_DATA_CHAR_INDEX];
|
||||
return content;
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
term = new Terminal();
|
||||
handler = new InputHandler(term);
|
||||
});
|
||||
it('should handle DECSET/DECRST 47 (alt screen buffer)', () => {
|
||||
handler.parse('\x1b[?47h\r\n\x1b[31mJUNK\x1b[?47lTEST');
|
||||
expect(lineContent(term.buffer.lines.get(0))).to.equal(Array(term.cols + 1).join(' '));
|
||||
expect(lineContent(term.buffer.lines.get(1))).to.equal(' TEST' + Array(term.cols - 7).join(' '));
|
||||
// Text color of 'TEST' should be red
|
||||
expect((term.buffer.lines.get(1).get(4)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||
});
|
||||
it('should handle DECSET/DECRST 1047 (alt screen buffer)', () => {
|
||||
handler.parse('\x1b[?1047h\r\n\x1b[31mJUNK\x1b[?1047lTEST');
|
||||
expect(lineContent(term.buffer.lines.get(0))).to.equal(Array(term.cols + 1).join(' '));
|
||||
expect(lineContent(term.buffer.lines.get(1))).to.equal(' TEST' + Array(term.cols - 7).join(' '));
|
||||
// Text color of 'TEST' should be red
|
||||
expect((term.buffer.lines.get(1).get(4)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||
});
|
||||
it('should handle DECSET/DECRST 1048 (alt screen cursor)', () => {
|
||||
handler.parse('\x1b[?1048h\r\n\x1b[31mJUNK\x1b[?1048lTEST');
|
||||
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||
expect(lineContent(term.buffer.lines.get(1))).to.equal('JUNK' + Array(term.cols - 3).join(' '));
|
||||
// Text color of 'TEST' should be default
|
||||
expect(term.buffer.lines.get(0).get(0)[CHAR_DATA_ATTR_INDEX]).to.equal(DEFAULT_ATTR);
|
||||
// Text color of 'JUNK' should be red
|
||||
expect((term.buffer.lines.get(1).get(0)[CHAR_DATA_ATTR_INDEX] >> 9) & 0x1ff).to.equal(1);
|
||||
});
|
||||
it('should handle DECSET/DECRST 1049 (alt screen buffer+cursor)', () => {
|
||||
handler.parse('\x1b[?1049h\r\n\x1b[31mJUNK\x1b[?1049lTEST');
|
||||
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + Array(term.cols - 3).join(' '));
|
||||
expect(lineContent(term.buffer.lines.get(1))).to.equal(Array(term.cols + 1).join(' '));
|
||||
// Text color of 'TEST' should be default
|
||||
expect(term.buffer.lines.get(0).get(0)[CHAR_DATA_ATTR_INDEX]).to.equal(DEFAULT_ATTR);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+26
-11
@@ -1280,7 +1280,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
case 66:
|
||||
this._terminal.log('Serial port requested application keypad.');
|
||||
this._terminal.applicationKeypad = true;
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
if (this._terminal.viewport) {
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
}
|
||||
break;
|
||||
case 9: // X10 Mouse
|
||||
// no release, no motion, no wheel, no modifiers.
|
||||
@@ -1329,14 +1331,19 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
case 25: // show cursor
|
||||
this._terminal.cursorHidden = false;
|
||||
break;
|
||||
case 1048: // alt screen cursor
|
||||
this.saveCursor(params);
|
||||
break;
|
||||
case 1049: // alt screen buffer cursor
|
||||
// TODO: Not sure if we need to save/restore after switching the buffer
|
||||
// this.saveCursor(params);
|
||||
this.saveCursor(params);
|
||||
// FALL-THROUGH
|
||||
case 47: // alt screen buffer
|
||||
case 1047: // alt screen buffer
|
||||
this._terminal.buffers.activateAltBuffer();
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
if (this._terminal.viewport) {
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
}
|
||||
this._terminal.showCursor();
|
||||
break;
|
||||
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
||||
@@ -1469,7 +1476,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
case 66:
|
||||
this._terminal.log('Switching back to normal keypad.');
|
||||
this._terminal.applicationKeypad = false;
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
if (this._terminal.viewport) {
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
}
|
||||
break;
|
||||
case 9: // X10 Mouse
|
||||
case 1000: // vt200 mouse
|
||||
@@ -1497,18 +1506,22 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
case 25: // hide cursor
|
||||
this._terminal.cursorHidden = true;
|
||||
break;
|
||||
case 1048: // alt screen cursor
|
||||
this.restoreCursor(params);
|
||||
break;
|
||||
case 1049: // alt screen buffer cursor
|
||||
// FALL-THROUGH
|
||||
case 47: // normal screen buffer
|
||||
case 1047: // normal screen buffer - clearing it first
|
||||
// Ensure the selection manager has the correct buffer
|
||||
this._terminal.buffers.activateNormalBuffer();
|
||||
// TODO: Not sure if we need to save/restore after switching the buffer
|
||||
// if (params[0] === 1049) {
|
||||
// this.restoreCursor(params);
|
||||
// }
|
||||
if (params[0] === 1049) {
|
||||
this.restoreCursor(params);
|
||||
}
|
||||
this._terminal.refresh(0, this._terminal.rows - 1);
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
if (this._terminal.viewport) {
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
}
|
||||
this._terminal.showCursor();
|
||||
break;
|
||||
case 2004: // bracketed paste mode (https://cirw.in/blog/bracketed-paste)
|
||||
@@ -1787,7 +1800,9 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
this._terminal.originMode = false;
|
||||
this._terminal.wraparoundMode = true; // defaults: xterm - true, vt100 - false
|
||||
this._terminal.applicationKeypad = false; // ?
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
if (this._terminal.viewport) {
|
||||
this._terminal.viewport.syncScrollArea();
|
||||
}
|
||||
this._terminal.applicationCursor = false;
|
||||
this._terminal.buffer.scrollTop = 0;
|
||||
this._terminal.buffer.scrollBottom = this._terminal.rows - 1;
|
||||
|
||||
Reference in New Issue
Block a user