From d3865ad23f6d42b53efd7fdd66a340b0dbac0210 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Thu, 1 Jun 2017 17:36:47 -0700 Subject: [PATCH] Add some SelectionManager selectWorkAt tests, fix lint --- src/SelectionManager.test.ts | 140 +++++++++++++++++++++++++++++++++++ src/SelectionManager.ts | 12 +-- src/xterm.js | 2 +- 3 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 src/SelectionManager.test.ts diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts new file mode 100644 index 0000000..e35a057 --- /dev/null +++ b/src/SelectionManager.test.ts @@ -0,0 +1,140 @@ +/** + * @license MIT + */ +import jsdom = require('jsdom'); +import { assert } from 'chai'; +import { ITerminal } from './Interfaces'; +import { CharMeasure } from './utils/CharMeasure'; +import { CircularList } from './utils/CircularList'; +import { SelectionManager } from './SelectionManager'; + +class TestSelectionManager extends SelectionManager { + constructor( + terminal: ITerminal, + buffer: CircularList, + rowContainer: HTMLElement, + charMeasure: CharMeasure + ) { + super(terminal, buffer, rowContainer, charMeasure); + } + + public selectWordAt(coords: [number, number]): void { this._selectWordAt(coords); } + + // Disable DOM interaction + public enable(): void {} + public disable(): void {} + public refresh(): void {} +} + +describe('SelectionManager', () => { + let window: Window; + let document: Document; + + let buffer: CircularList; + let rowContainer: HTMLElement; + let selectionManager: TestSelectionManager; + + beforeEach(done => { + jsdom.env('', (err, w) => { + window = w; + document = window.document; + buffer = new CircularList(100); + selectionManager = new TestSelectionManager(null, buffer, rowContainer, null); + done(); + }); + }); + + function stringToRow(text: string): [number, string, number][] { + let result: [number, string, number][] = []; + for (let i = 0; i < text.length; i++) { + result.push([0, text.charAt(i), 1]); + } + return result; + } + + describe('_selectWordAt', () => { + it('should expand selection for normal width chars', () => { + buffer.push(stringToRow('foo bar')); + selectionManager.selectWordAt([0, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + selectionManager.selectWordAt([1, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + selectionManager.selectWordAt([2, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + selectionManager.selectWordAt([3, 0]); + assert.equal(selectionManager.selectionText, ' '); + selectionManager.selectWordAt([4, 0]); + assert.equal(selectionManager.selectionText, 'bar'); + selectionManager.selectWordAt([5, 0]); + assert.equal(selectionManager.selectionText, 'bar'); + selectionManager.selectWordAt([6, 0]); + assert.equal(selectionManager.selectionText, 'bar'); + }); + it('should expand selection for whitespace', () => { + buffer.push(stringToRow('a b')); + selectionManager.selectWordAt([0, 0]); + assert.equal(selectionManager.selectionText, 'a'); + selectionManager.selectWordAt([1, 0]); + assert.equal(selectionManager.selectionText, ' '); + selectionManager.selectWordAt([2, 0]); + assert.equal(selectionManager.selectionText, ' '); + selectionManager.selectWordAt([3, 0]); + assert.equal(selectionManager.selectionText, ' '); + selectionManager.selectWordAt([4, 0]); + assert.equal(selectionManager.selectionText, 'b'); + }); + it('should expand selection for wide characters', () => { + // Wide characters use a special format + buffer.push([ + [null, '中', 2], + [null, '', 0], + [null, '文', 2], + [null, '', 0], + [null, ' ', 1], + [null, 'a', 1], + [null, '中', 2], + [null, '', 0], + [null, '文', 2], + [null, '', 0], + [null, 'b', 1], + [null, ' ', 1], + [null, 'f', 1], + [null, 'o', 1], + [null, 'o', 1] + ]); + // Ensure wide characters take up 2 columns + selectionManager.selectWordAt([0, 0]); + assert.equal(selectionManager.selectionText, '中文'); + selectionManager.selectWordAt([1, 0]); + assert.equal(selectionManager.selectionText, '中文'); + selectionManager.selectWordAt([2, 0]); + assert.equal(selectionManager.selectionText, '中文'); + selectionManager.selectWordAt([3, 0]); + assert.equal(selectionManager.selectionText, '中文'); + selectionManager.selectWordAt([4, 0]); + assert.equal(selectionManager.selectionText, ' '); + // Ensure wide characters work when wrapped in normal width characters + selectionManager.selectWordAt([5, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([6, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([7, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([8, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([9, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([10, 0]); + assert.equal(selectionManager.selectionText, 'a中文b'); + selectionManager.selectWordAt([11, 0]); + assert.equal(selectionManager.selectionText, ' '); + // Ensure normal width characters work fine in a line containing wide characters + selectionManager.selectWordAt([12, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + selectionManager.selectWordAt([13, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + selectionManager.selectWordAt([14, 0]); + assert.equal(selectionManager.selectionText, 'foo'); + }); + }); +}); diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index 4f8c873..991fa6b 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -155,7 +155,7 @@ export class SelectionManager extends EventEmitter { // Calculate the final end col by trimming whitespace on the right of the // line if needed. - let finalEndCol = widthAdjustedEndCol || line.length + let finalEndCol = widthAdjustedEndCol || line.length; if (trimRight) { const rightWhitespaceIndex = lineString.search(/\s+$/); if (rightWhitespaceIndex !== -1) { @@ -284,10 +284,10 @@ export class SelectionManager extends EventEmitter { private _setMouseClickCount(): void { let currentTime = (new Date()).getTime(); - if (currentTime - this._lastMouseDownTime > CLEAR_MOUSE_DOWN_TIME) { + if (currentTime - this._lastMouseDownTime > CLEAR_MOUSE_DOWN_TIME) { this._clickCount = 0; - } - this._lastMouseDownTime = currentTime; + } + this._lastMouseDownTime = currentTime; this._clickCount++; // TODO: Invalidate click count if the position is different @@ -351,7 +351,7 @@ export class SelectionManager extends EventEmitter { /** * Converts a viewport column to the character index on the buffer line, the * latter takes into account wide characters. - * @param coords The coordinates to find the character index for. + * @param coords The coordinates to find the 2 index for. */ private _convertViewportColToCharacterIndex(bufferLine: any, coords: [number, number]): number { let charIndex = coords[0]; @@ -418,7 +418,7 @@ export class SelectionManager extends EventEmitter { startIndex--; startCol--; } - while (endIndex < line.length && line.charAt(endIndex + 1) !== ' ') { + while (endIndex + 1 < line.length && line.charAt(endIndex + 1) !== ' ') { if (bufferLine[endCol + 1][LINE_DATA_WIDTH_INDEX] === 2) { // If the next character is a wide char, record it and skip the column rightWideCharCount++; diff --git a/src/xterm.js b/src/xterm.js index c923955..acf1eac 100644 --- a/src/xterm.js +++ b/src/xterm.js @@ -693,7 +693,7 @@ Terminal.prototype.open = function(parent, focus) { this.viewport = new Viewport(this, this.viewportElement, this.viewportScrollArea, this.charMeasure); this.renderer = new Renderer(this); - this.selectionManager = new SelectionManager(this, this.lines, this.rowContainer, this.selectionContainer, this.charMeasure); + this.selectionManager = new SelectionManager(this, this.lines, this.rowContainer, this.charMeasure); this.selectionManager.on('refresh', data => this.renderer.refreshSelection(data.start, data.end)); this.on('scroll', () => this.selectionManager.refresh()); this.viewportElement.addEventListener('scroll', () => this.selectionManager.refresh()); -- 2.39.5