Merge branch 'master' into 1737_inverse_dynamic_cache

This commit is contained in:
Daniel Imms
2018-11-23 14:31:16 -08:00
committed by GitHub
17 changed files with 245 additions and 205 deletions
+6 -2
View File
@@ -39,6 +39,7 @@ export class Buffer implements IBuffer {
public tabs: any;
public savedY: number;
public savedX: number;
public savedCurAttr: number;
public markers: Marker[] = [];
private _bufferLineConstructor: IBufferLineConstructor;
@@ -114,11 +115,14 @@ export class Buffer implements IBuffer {
/**
* Fills the buffer's viewport with blank lines.
*/
public fillViewportRows(): void {
public fillViewportRows(fillAttr?: number): void {
if (this.lines.length === 0) {
if (fillAttr === undefined) {
fillAttr = DEFAULT_ATTR;
}
let i = this._terminal.rows;
while (i--) {
this.lines.push(this.getBlankLine(DEFAULT_ATTR));
this.lines.push(this.getBlankLine(fillAttr));
}
}
}
+26
View File
@@ -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);
});
});
});
+6 -2
View File
@@ -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.
@@ -75,13 +77,15 @@ export class BufferSet extends EventEmitter implements IBufferSet {
/**
* Sets the alt Buffer of the BufferSet as its currently active Buffer
*/
public activateAltBuffer(): void {
public activateAltBuffer(fillAttr?: number): void {
if (this._activeBuffer === this._alt) {
return;
}
// 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.fillViewportRows(fillAttr);
this._alt.x = this._normal.x;
this._alt.y = this._normal.y;
this._activeBuffer = this._alt;
this.emit('activate', {
activeBuffer: this._alt,
+1 -1
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { fill } from './core/TypedArrayUtils';
import { fill } from './common/TypedArrayUtils';
export const wcwidth = (function(opts: {nul: number, control: number}): (ucs: number) => number {
// extracted from https://www.cl.cam.ac.uk/%7Emgk25/ucs/wcwidth.c
+62 -1
View File
@@ -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,65 @@ 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);
});
it('should handle DECSET/DECRST 1049 - maintains saved cursor for alt buffer', () => {
handler.parse('\x1b[?1049h\r\n\x1b[31m\x1b[s\x1b[?1049lTEST');
expect(lineContent(term.buffer.lines.get(0))).to.equal('TEST' + 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);
handler.parse('\x1b[?1049h\x1b[uTEST');
expect(lineContent(term.buffer.lines.get(1))).to.equal('TEST' + Array(term.cols - 3).join(' '));
// Text color of 'TEST' 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 - clears alt buffer with erase attributes', () => {
handler.parse('\x1b[42m\x1b[?1049h');
// Buffer should be filled with green background
expect(term.buffer.lines.get(20).get(10)[CHAR_DATA_ATTR_INDEX] & 0x1ff).to.equal(2);
});
});
});
+29 -14
View File
@@ -1284,7 +1284,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.
@@ -1333,14 +1335,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.buffers.activateAltBuffer(this._terminal.eraseAttr());
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)
@@ -1473,7 +1480,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
@@ -1501,18 +1510,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)
@@ -1791,7 +1804,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;
@@ -1858,7 +1873,7 @@ export class InputHandler extends Disposable implements IInputHandler {
public saveCursor(params: number[]): void {
this._terminal.buffer.savedX = this._terminal.buffer.x;
this._terminal.buffer.savedY = this._terminal.buffer.y;
this._terminal.savedCurAttr = this._terminal.curAttr;
this._terminal.buffer.savedCurAttr = this._terminal.curAttr;
}
@@ -1870,7 +1885,7 @@ export class InputHandler extends Disposable implements IInputHandler {
public restoreCursor(params: number[]): void {
this._terminal.buffer.x = this._terminal.buffer.savedX || 0;
this._terminal.buffer.y = this._terminal.buffer.savedY || 0;
this._terminal.curAttr = this._terminal.savedCurAttr || DEFAULT_ATTR;
this._terminal.curAttr = this._terminal.buffer.savedCurAttr || DEFAULT_ATTR;
}
+1 -1
View File
@@ -347,7 +347,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
* @param event The mouse event.
*/
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows, true);
const coords = this._terminal.mouseHelper.getCoords(event, this._terminal.screenElement, this._charMeasure, this._terminal.cols, this._terminal.rows, true);
if (!coords) {
return null;
}
+2 -3
View File
@@ -170,7 +170,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
public savedCols: number;
public curAttr: number;
public savedCurAttr: number;
public params: (string | number)[];
public currentParam: string | number;
@@ -808,7 +807,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
button = getButton(ev);
// get mouse coordinates
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.cols, self.rows);
if (!pos) return;
sendEvent(button, pos);
@@ -834,7 +833,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
// ^[[M 3<^[[M@4<^[[M@5<^[[M@6<^[[M@7<^[[M#7<
function sendMove(ev: MouseEvent): void {
let button = pressed;
const pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.options.lineHeight, self.cols, self.rows);
const pos = self.mouseHelper.getRawByteCoords(ev, self.screenElement, self.charMeasure, self.cols, self.rows);
if (!pos) return;
// buttons marked as motions
+4 -4
View File
@@ -49,7 +49,6 @@ export interface IInputHandlingTerminal extends IEventEmitter {
wraparoundMode: boolean;
bracketedPasteMode: boolean;
curAttr: number;
savedCurAttr: number;
savedCols: number;
x10Mouse: boolean;
vt200Mouse: boolean;
@@ -246,8 +245,8 @@ export interface ILinkifierAccessor {
}
export interface IMouseHelper {
getCoords(event: { pageX: number, pageY: number }, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number): { x: number, y: number };
getCoords(event: { pageX: number, pageY: number }, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number];
getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number): { x: number, y: number };
}
export interface ICharMeasure {
@@ -290,6 +289,7 @@ export interface IBuffer {
hasScrollback: boolean;
savedY: number;
savedX: number;
savedCurAttr: number;
isCursorInViewport: boolean;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string;
getWrappedRangeForLine(y: number): { first: number, last: number };
@@ -306,7 +306,7 @@ export interface IBufferSet extends IEventEmitter {
active: IBuffer;
activateNormalBuffer(): void;
activateAltBuffer(): void;
activateAltBuffer(fillAttr?: number): void;
}
export interface ISelectionManager {
+89
View File
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { fillFallback } from './TypedArrayUtils';
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
| Int8Array | Int16Array | Int32Array
| Float32Array | Float64Array;
describe('polyfill conformance tests', function(): void {
function deepEquals(a: TypedArray, b: TypedArray): void {
assert.equal(a.length, b.length);
for (let i = 0; i < a.length; ++i) {
assert.equal(a[i], b[i]);
}
}
describe('TypedArray.fill', function(): void {
it('should work with all typed array types', function(): void {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
deepEquals(fillFallback(u81, 2), u82.fill(2));
deepEquals(fillFallback(u81, -1), u82.fill(-1));
const u161 = new Uint16Array(5);
const u162 = new Uint16Array(5);
deepEquals(fillFallback(u161, 2), u162.fill(2));
deepEquals(fillFallback(u161, 65535), u162.fill(65535));
deepEquals(fillFallback(u161, -1), u162.fill(-1));
const u321 = new Uint32Array(5);
const u322 = new Uint32Array(5);
deepEquals(fillFallback(u321, 2), u322.fill(2));
deepEquals(fillFallback(u321, 65537), u322.fill(65537));
deepEquals(fillFallback(u321, -1), u322.fill(-1));
const i81 = new Int8Array(5);
const i82 = new Int8Array(5);
deepEquals(fillFallback(i81, 2), i82.fill(2));
deepEquals(fillFallback(i81, -1), i82.fill(-1));
const i161 = new Int16Array(5);
const i162 = new Int16Array(5);
deepEquals(fillFallback(i161, 2), i162.fill(2));
deepEquals(fillFallback(i161, 65535), i162.fill(65535));
deepEquals(fillFallback(i161, -1), i162.fill(-1));
const i321 = new Int32Array(5);
const i322 = new Int32Array(5);
deepEquals(fillFallback(i321, 2), i322.fill(2));
deepEquals(fillFallback(i321, 65537), i322.fill(65537));
deepEquals(fillFallback(i321, -1), i322.fill(-1));
const f321 = new Float32Array(5);
const f322 = new Float32Array(5);
deepEquals(fillFallback(f321, 1.2345), f322.fill(1.2345));
const f641 = new Float64Array(5);
const f642 = new Float64Array(5);
deepEquals(fillFallback(f641, 1.2345), f642.fill(1.2345));
const u8Clamped1 = new Uint8ClampedArray(5);
const u8Clamped2 = new Uint8ClampedArray(5);
deepEquals(fillFallback(u8Clamped1, 2), u8Clamped2.fill(2));
deepEquals(fillFallback(u8Clamped1, 257), u8Clamped2.fill(257));
});
it('start offset', function(): void {
for (let i = -2; i < 10; ++i) {
const u81 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fillFallback(u81, 2, i), u83.fill(2, i));
deepEquals(fillFallback(u81, -1, i), u83.fill(-1, i));
}
});
it('end offset', function(): void {
for (let i = -2; i < 10; ++i) {
const u81 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fillFallback(u81, 2, 0, i), u83.fill(2, 0, i));
deepEquals(fillFallback(u81, -1, 0, i), u83.fill(-1, 0, i));
}
});
it('start/end offset', function(): void {
for (let i = -2; i < 10; ++i) {
for (let j = -2; j < 10; ++j) {
const u81 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fillFallback(u81, 2, i, j), u83.fill(2, i, j));
deepEquals(fillFallback(u81, -1, i, j), u83.fill(-1, i, j));
}
}
});
});
});
@@ -12,11 +12,15 @@ type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
| Int8Array | Int16Array | Int32Array
| Float32Array | Float64Array;
export function fill(array: TypedArray, value: number, start: number = 0, end?: number | undefined): TypedArray {
export function fill<T extends TypedArray>(array: T, value: number, start?: number, end?: number): T {
// all modern engines that support .fill
if (array.fill) {
return array.fill(value, start, end);
return array.fill(value, start, end) as T;
}
return fillFallback(array, value, start, end);
}
export function fillFallback<T extends TypedArray>(array: T, value: number, start: number = 0, end: number = array.length): T {
// safari and IE 11
// since IE 11 does not support Array.prototype.fill either
// we cannot use the suggested polyfill from MDN
@@ -25,9 +29,6 @@ export function fill(array: TypedArray, value: number, start: number = 0, end?:
return array;
}
start = (array.length + start) % array.length;
if (end === undefined) {
end = array.length;
}
if (end >= array.length) {
end = array.length;
} else {
-158
View File
@@ -1,158 +0,0 @@
/**
* Copyright (c) 2018 The xterm.js authors. All rights reserved.
* @license MIT
*/
import { assert } from 'chai';
import { fill } from './TypedArrayUtils';
type TypedArray = Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray
| Int8Array | Int16Array | Int32Array
| Float32Array | Float64Array;
// we explicitly test against the looping version in the test cases
function loopFill(array: TypedArray, value: number, start: number = 0, end?: number | undefined): TypedArray {
if (start >= array.length) {
return array;
}
start = (array.length + start) % array.length;
if (end === undefined) {
end = array.length;
}
if (end >= array.length) {
end = array.length;
} else {
end = (array.length + end) % array.length;
}
for (let i = start; i < end; ++i) {
array[i] = value;
}
return array;
}
describe('polyfill conformance tests', function(): void {
function deepEquals(a: TypedArray, b: TypedArray): void {
assert.equal(a.length, b.length);
for (let i = 0; i < a.length; ++i) {
assert.equal(a[i], b[i]);
}
}
describe('TypedArray.fill', function(): void {
it('should work with all typed array types', function(): void {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
deepEquals(fill(u81, 2), u82.fill(2));
deepEquals(fill(u81, -1), u82.fill(-1));
const u161 = new Uint16Array(5);
const u162 = new Uint16Array(5);
deepEquals(fill(u161, 2), u162.fill(2));
deepEquals(fill(u161, 65535), u162.fill(65535));
deepEquals(fill(u161, -1), u162.fill(-1));
const u321 = new Uint32Array(5);
const u322 = new Uint32Array(5);
deepEquals(fill(u321, 2), u322.fill(2));
deepEquals(fill(u321, 65537), u322.fill(65537));
deepEquals(fill(u321, -1), u322.fill(-1));
const i81 = new Int8Array(5);
const i82 = new Int8Array(5);
deepEquals(fill(i81, 2), i82.fill(2));
deepEquals(fill(i81, -1), i82.fill(-1));
const i161 = new Int16Array(5);
const i162 = new Int16Array(5);
deepEquals(fill(i161, 2), i162.fill(2));
deepEquals(fill(i161, 65535), i162.fill(65535));
deepEquals(fill(i161, -1), i162.fill(-1));
const i321 = new Int32Array(5);
const i322 = new Int32Array(5);
deepEquals(fill(i321, 2), i322.fill(2));
deepEquals(fill(i321, 65537), i322.fill(65537));
deepEquals(fill(i321, -1), i322.fill(-1));
const f321 = new Float32Array(5);
const f322 = new Float32Array(5);
deepEquals(fill(f321, 1.2345), f322.fill(1.2345));
const f641 = new Float64Array(5);
const f642 = new Float64Array(5);
deepEquals(fill(f641, 1.2345), f642.fill(1.2345));
const u8Clamped1 = new Uint8ClampedArray(5);
const u8Clamped2 = new Uint8ClampedArray(5);
deepEquals(fill(u8Clamped1, 2), u8Clamped2.fill(2));
deepEquals(fill(u8Clamped1, 257), u8Clamped2.fill(257));
});
it('should work with all typed array types - explicit looping', function(): void {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
deepEquals(loopFill(u81, 2), u82.fill(2));
deepEquals(loopFill(u81, -1), u82.fill(-1));
const u161 = new Uint16Array(5);
const u162 = new Uint16Array(5);
deepEquals(loopFill(u161, 2), u162.fill(2));
deepEquals(loopFill(u161, 65535), u162.fill(65535));
deepEquals(loopFill(u161, -1), u162.fill(-1));
const u321 = new Uint32Array(5);
const u322 = new Uint32Array(5);
deepEquals(loopFill(u321, 2), u322.fill(2));
deepEquals(loopFill(u321, 65537), u322.fill(65537));
deepEquals(loopFill(u321, -1), u322.fill(-1));
const i81 = new Int8Array(5);
const i82 = new Int8Array(5);
deepEquals(loopFill(i81, 2), i82.fill(2));
deepEquals(loopFill(i81, -1), i82.fill(-1));
const i161 = new Int16Array(5);
const i162 = new Int16Array(5);
deepEquals(loopFill(i161, 2), i162.fill(2));
deepEquals(loopFill(i161, 65535), i162.fill(65535));
deepEquals(loopFill(i161, -1), i162.fill(-1));
const i321 = new Int32Array(5);
const i322 = new Int32Array(5);
deepEquals(loopFill(i321, 2), i322.fill(2));
deepEquals(loopFill(i321, 65537), i322.fill(65537));
deepEquals(loopFill(i321, -1), i322.fill(-1));
const f321 = new Float32Array(5);
const f322 = new Float32Array(5);
deepEquals(loopFill(f321, 1.2345), f322.fill(1.2345));
const f641 = new Float64Array(5);
const f642 = new Float64Array(5);
deepEquals(loopFill(f641, 1.2345), f642.fill(1.2345));
const u8Clamped1 = new Uint8ClampedArray(5);
const u8Clamped2 = new Uint8ClampedArray(5);
deepEquals(loopFill(u8Clamped1, 2), u8Clamped2.fill(2));
deepEquals(loopFill(u8Clamped1, 257), u8Clamped2.fill(257));
});
it('start offset', function(): void {
for (let i = -2; i < 10; ++i) {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fill(u81, 2, i), u83.fill(2, i));
deepEquals(fill(u81, -1, i), u83.fill(-1, i));
deepEquals(loopFill(u82, 2, i), u83.fill(2, i));
deepEquals(loopFill(u82, -1, i), u83.fill(-1, i));
}
});
it('end offset', function(): void {
for (let i = -2; i < 10; ++i) {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fill(u81, 2, 0, i), u83.fill(2, 0, i));
deepEquals(fill(u81, -1, 0, i), u83.fill(-1, 0, i));
deepEquals(loopFill(u82, 2, 0, i), u83.fill(2, 0, i));
deepEquals(loopFill(u82, -1, 0, i), u83.fill(-1, 0, i));
}
});
it('start/end offset', function(): void {
for (let i = -2; i < 10; ++i) {
for (let j = -2; j < 10; ++j) {
const u81 = new Uint8Array(5);
const u82 = new Uint8Array(5);
const u83 = new Uint8Array(5);
deepEquals(fill(u81, 2, i, j), u83.fill(2, i, j));
deepEquals(fill(u81, -1, i, j), u83.fill(-1, i, j));
deepEquals(loopFill(u82, 2, i, j), u83.fill(2, i, j));
deepEquals(loopFill(u82, -1, i, j), u83.fill(-1, i, j));
}
}
});
});
});
-1
View File
@@ -33,7 +33,6 @@ export class AltClickHandler {
this._mouseEvent,
this._terminal.element,
this._terminal.charMeasure,
this._terminal.options.lineHeight,
this._terminal.cols,
this._terminal.rows,
false
+1 -1
View File
@@ -180,7 +180,7 @@ export class MouseZoneManager extends Disposable implements IMouseZoneManager {
}
private _findZoneEventAt(e: MouseEvent): IMouseZone {
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.options.lineHeight, this._terminal.cols, this._terminal.rows);
const coords = this._terminal.mouseHelper.getCoords(e, this._terminal.screenElement, this._terminal.charMeasure, this._terminal.cols, this._terminal.rows);
if (!coords) {
return null;
}
+8 -8
View File
@@ -37,34 +37,34 @@ describe('MouseHelper.getCoords', () => {
describe('when charMeasure is not initialized', () => {
it('should return null', () => {
charMeasure = new MockCharMeasure();
assert.equal(mouseHelper.getCoords({ pageX: 0, pageY: 0 }, document.createElement('div'), charMeasure, 1, 10, 10), null);
assert.equal(mouseHelper.getCoords({ pageX: 0, pageY: 0 }, document.createElement('div'), charMeasure, 10, 10), null);
});
});
describe('when pageX/pageY are not supported', () => {
it('should return null', () => {
assert.equal(mouseHelper.getCoords({ pageX: undefined, pageY: undefined }, document.createElement('div'), charMeasure, 1, 10, 10), null);
assert.equal(mouseHelper.getCoords({ pageX: undefined, pageY: undefined }, document.createElement('div'), charMeasure, 10, 10), null);
});
});
it('should return the cell that was clicked', () => {
let coords: [number, number];
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH / 2, pageY: CHAR_HEIGHT / 2 }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH / 2, pageY: CHAR_HEIGHT / 2 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT + 1 }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH, pageY: CHAR_HEIGHT + 1 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 2]);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH + 1, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH + 1, pageY: CHAR_HEIGHT }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [2, 1]);
});
it('should ensure the coordinates are returned within the terminal bounds', () => {
let coords: [number, number];
coords = mouseHelper.getCoords({ pageX: -1, pageY: -1 }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: -1, pageY: -1 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [1, 1]);
// Event are double the cols/rows
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH * 20, pageY: CHAR_HEIGHT * 20 }, document.createElement('div'), charMeasure, 1, 10, 10);
coords = mouseHelper.getCoords({ pageX: CHAR_WIDTH * 20, pageY: CHAR_HEIGHT * 20 }, document.createElement('div'), charMeasure, 10, 10);
assert.deepEqual(coords, [10, 10], 'coordinates should never come back as larger than the terminal');
});
});
+3 -3
View File
@@ -52,7 +52,7 @@ export class MouseHelper {
* apply an offset to the x value such that the left half of the cell will
* select that cell and the right half will select the next cell.
*/
public getCoords(event: {pageX: number, pageY: number}, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
public getCoords(event: {pageX: number, pageY: number}, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number, isSelection?: boolean): [number, number] {
// Coordinates cannot be measured if charMeasure has not been initialized
if (!charMeasure.width || !charMeasure.height) {
return null;
@@ -85,8 +85,8 @@ export class MouseHelper {
* @param colCount The number of columns in the terminal.
* @param rowCount The number of rows in the terminal.
*/
public getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, lineHeight: number, colCount: number, rowCount: number): { x: number, y: number } {
const coords = this.getCoords(event, element, charMeasure, lineHeight, colCount, rowCount);
public getRawByteCoords(event: MouseEvent, element: HTMLElement, charMeasure: ICharMeasure, colCount: number, rowCount: number): { x: number, y: number } {
const coords = this.getCoords(event, element, charMeasure, colCount, rowCount);
let x = coords[0];
let y = coords[1];
+1 -1
View File
@@ -182,7 +182,6 @@ export class MockInputHandlingTerminal implements IInputHandlingTerminal {
wraparoundMode: boolean;
bracketedPasteMode: boolean;
curAttr: number;
savedCurAttr: number;
savedCols: number;
x10Mouse: boolean;
vt200Mouse: boolean;
@@ -304,6 +303,7 @@ export class MockBuffer implements IBuffer {
scrollTop: number;
savedY: number;
savedX: number;
savedCurAttr: number;
translateBufferLineToString(lineIndex: number, trimRight: boolean, startCol?: number, endCol?: number): string {
return Buffer.prototype.translateBufferLineToString.apply(this, arguments);
}