Merge pull request #2238 from Tyriar/selection_layering
Move SelectionModel to browser
This commit is contained in:
@@ -5,13 +5,12 @@
|
|||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { SelectionManager, SelectionMode } from './SelectionManager';
|
import { SelectionManager, SelectionMode } from './SelectionManager';
|
||||||
import { SelectionModel } from './SelectionModel';
|
import { SelectionModel } from 'browser/selection/SelectionModel';
|
||||||
import { BufferSet } from 'common/buffer/BufferSet';
|
|
||||||
import { ITerminal } from './Types';
|
import { ITerminal } from './Types';
|
||||||
import { IBuffer } from 'common/buffer/Types';
|
import { IBuffer } from 'common/buffer/Types';
|
||||||
import { IBufferLine } from 'common/Types';
|
import { IBufferLine } from 'common/Types';
|
||||||
import { MockTerminal } from './TestUtils.test';
|
import { MockTerminal } from './TestUtils.test';
|
||||||
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
|
import { MockBufferService } from 'common/TestUtils.test';
|
||||||
import { BufferLine } from 'common/buffer/BufferLine';
|
import { BufferLine } from 'common/buffer/BufferLine';
|
||||||
import { IBufferService } from 'common/services/Services';
|
import { IBufferService } from 'common/services/Services';
|
||||||
import { MockCharSizeService, MockMouseService } from 'browser/TestUtils.test';
|
import { MockCharSizeService, MockMouseService } from 'browser/TestUtils.test';
|
||||||
@@ -52,10 +51,7 @@ describe('SelectionManager', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
terminal = new TestMockTerminal();
|
terminal = new TestMockTerminal();
|
||||||
bufferService = new MockBufferService(20, 20);
|
bufferService = new MockBufferService(20, 20);
|
||||||
terminal.buffers = new BufferSet(
|
terminal.buffers = bufferService.buffers;
|
||||||
new MockOptionsService({ scrollback: 100 }),
|
|
||||||
bufferService
|
|
||||||
);
|
|
||||||
terminal.cols = 20;
|
terminal.cols = 20;
|
||||||
terminal.rows = 20;
|
terminal.rows = 20;
|
||||||
terminal.buffer = terminal.buffers.active;
|
terminal.buffer = terminal.buffers.active;
|
||||||
@@ -366,14 +362,13 @@ describe('SelectionManager', () => {
|
|||||||
|
|
||||||
describe('selectAll', () => {
|
describe('selectAll', () => {
|
||||||
it('should select the entire buffer, beyond the viewport', () => {
|
it('should select the entire buffer, beyond the viewport', () => {
|
||||||
buffer.lines.length = 5;
|
bufferService.resize(20, 5);
|
||||||
buffer.lines.set(0, stringToRow('1'));
|
buffer.lines.set(0, stringToRow('1'));
|
||||||
buffer.lines.set(1, stringToRow('2'));
|
buffer.lines.set(1, stringToRow('2'));
|
||||||
buffer.lines.set(2, stringToRow('3'));
|
buffer.lines.set(2, stringToRow('3'));
|
||||||
buffer.lines.set(3, stringToRow('4'));
|
buffer.lines.set(3, stringToRow('4'));
|
||||||
buffer.lines.set(4, stringToRow('5'));
|
buffer.lines.set(4, stringToRow('5'));
|
||||||
selectionManager.selectAll();
|
selectionManager.selectAll();
|
||||||
terminal.buffer.ybase = buffer.lines.length - bufferService.rows;
|
|
||||||
assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5');
|
assert.equal(selectionManager.selectionText, '1\n2\n3\n4\n5');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ITerminal, ISelectionManager, ISelectionRedrawRequestEvent } from './Ty
|
|||||||
import { IBuffer } from 'common/buffer/Types';
|
import { IBuffer } from 'common/buffer/Types';
|
||||||
import { IBufferLine } from 'common/Types';
|
import { IBufferLine } from 'common/Types';
|
||||||
import * as Browser from 'common/Platform';
|
import * as Browser from 'common/Platform';
|
||||||
import { SelectionModel } from './SelectionModel';
|
import { SelectionModel } from 'browser/selection/SelectionModel';
|
||||||
import { AltClickHandler } from './handlers/AltClickHandler';
|
import { AltClickHandler } from './handlers/AltClickHandler';
|
||||||
import { CellData } from 'common/buffer/CellData';
|
import { CellData } from 'common/buffer/CellData';
|
||||||
import { IDisposable } from 'xterm';
|
import { IDisposable } from 'xterm';
|
||||||
@@ -126,7 +126,7 @@ export class SelectionManager implements ISelectionManager {
|
|||||||
this._initListeners();
|
this._initListeners();
|
||||||
this.enable();
|
this.enable();
|
||||||
|
|
||||||
this._model = new SelectionModel(_terminal, bufferService);
|
this._model = new SelectionModel(bufferService);
|
||||||
this._activeSelectionMode = SelectionMode.NORMAL;
|
this._activeSelectionMode = SelectionMode.NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,36 +4,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { ITerminal } from './Types';
|
|
||||||
import { SelectionModel } from './SelectionModel';
|
import { SelectionModel } from './SelectionModel';
|
||||||
import { BufferSet } from 'common/buffer/BufferSet';
|
import { MockBufferService } from 'common/TestUtils.test';
|
||||||
import { MockTerminal } from './TestUtils.test';
|
|
||||||
import { MockOptionsService, MockBufferService } from 'common/TestUtils.test';
|
|
||||||
import { IBufferService } from 'common/services/Services';
|
|
||||||
|
|
||||||
class TestSelectionModel extends SelectionModel {
|
describe('SelectionModel', () => {
|
||||||
constructor(
|
let model: SelectionModel;
|
||||||
terminal: ITerminal,
|
|
||||||
bufferService: IBufferService
|
|
||||||
) {
|
|
||||||
super(terminal, bufferService);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe('SelectionManager', () => {
|
|
||||||
let terminal: ITerminal;
|
|
||||||
let model: TestSelectionModel;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
terminal = new MockTerminal();
|
|
||||||
const bufferService = new MockBufferService(80, 2);
|
const bufferService = new MockBufferService(80, 2);
|
||||||
terminal.buffers = new BufferSet(
|
model = new SelectionModel(bufferService);
|
||||||
new MockOptionsService({ scrollback: 10 }),
|
|
||||||
bufferService
|
|
||||||
);
|
|
||||||
terminal.buffer = terminal.buffers.active;
|
|
||||||
|
|
||||||
model = new TestSelectionModel(terminal, bufferService);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('clearSelection', () => {
|
describe('clearSelection', () => {
|
||||||
@@ -43,8 +22,8 @@ describe('SelectionManager', () => {
|
|||||||
assert.deepEqual(model.finalSelectionStart, [0, 0]);
|
assert.deepEqual(model.finalSelectionStart, [0, 0]);
|
||||||
assert.deepEqual(model.finalSelectionEnd, [10, 2]);
|
assert.deepEqual(model.finalSelectionEnd, [10, 2]);
|
||||||
model.clearSelection();
|
model.clearSelection();
|
||||||
assert.deepEqual(model.finalSelectionStart, null);
|
assert.deepEqual(model.finalSelectionStart, undefined);
|
||||||
assert.deepEqual(model.finalSelectionEnd, null);
|
assert.deepEqual(model.finalSelectionEnd, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,8 +61,8 @@ describe('SelectionManager', () => {
|
|||||||
model.selectionStart = [0, 0];
|
model.selectionStart = [0, 0];
|
||||||
model.selectionEnd = [10, 0];
|
model.selectionEnd = [10, 0];
|
||||||
model.onTrim(1);
|
model.onTrim(1);
|
||||||
assert.deepEqual(model.finalSelectionStart, null);
|
assert.deepEqual(model.finalSelectionStart, undefined);
|
||||||
assert.deepEqual(model.finalSelectionEnd, null);
|
assert.deepEqual(model.finalSelectionEnd, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -111,9 +90,9 @@ describe('SelectionManager', () => {
|
|||||||
assert.deepEqual(model.finalSelectionEnd, [80, 1]);
|
assert.deepEqual(model.finalSelectionEnd, [80, 1]);
|
||||||
});
|
});
|
||||||
it('should return null if there is no selection start', () => {
|
it('should return null if there is no selection start', () => {
|
||||||
assert.equal(model.finalSelectionEnd, null);
|
assert.equal(model.finalSelectionEnd, undefined);
|
||||||
model.selectionEnd = [1, 2];
|
model.selectionEnd = [1, 2];
|
||||||
assert.equal(model.finalSelectionEnd, null);
|
assert.equal(model.finalSelectionEnd, undefined);
|
||||||
});
|
});
|
||||||
it('should return selection start + length if there is no selection end', () => {
|
it('should return selection start + length if there is no selection end', () => {
|
||||||
model.selectionStart = [2, 2];
|
model.selectionStart = [2, 2];
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ITerminal } from './Types';
|
|
||||||
import { IBufferService } from 'common/services/Services';
|
import { IBufferService } from 'common/services/Services';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,38 +13,36 @@ export class SelectionModel {
|
|||||||
/**
|
/**
|
||||||
* Whether select all is currently active.
|
* Whether select all is currently active.
|
||||||
*/
|
*/
|
||||||
public isSelectAllActive: boolean;
|
public isSelectAllActive: boolean = false;
|
||||||
|
|
||||||
/**
|
|
||||||
* The [x, y] position the selection starts at.
|
|
||||||
*/
|
|
||||||
public selectionStart: [number, number];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The minimal length of the selection from the start position. When double
|
* The minimal length of the selection from the start position. When double
|
||||||
* clicking on a word, the word will be selected which makes the selection
|
* clicking on a word, the word will be selected which makes the selection
|
||||||
* start at the start of the word and makes this variable the length.
|
* start at the start of the word and makes this variable the length.
|
||||||
*/
|
*/
|
||||||
public selectionStartLength: number;
|
public selectionStartLength: number = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [x, y] position the selection starts at.
|
||||||
|
*/
|
||||||
|
public selectionStart: [number, number] | undefined;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [x, y] position the selection ends at.
|
* The [x, y] position the selection ends at.
|
||||||
*/
|
*/
|
||||||
public selectionEnd: [number, number];
|
public selectionEnd: [number, number] | undefined;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private _terminal: ITerminal,
|
|
||||||
private _bufferService: IBufferService
|
private _bufferService: IBufferService
|
||||||
) {
|
) {
|
||||||
this.clearSelection();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clears the current selection.
|
* Clears the current selection.
|
||||||
*/
|
*/
|
||||||
public clearSelection(): void {
|
public clearSelection(): void {
|
||||||
this.selectionStart = null;
|
this.selectionStart = undefined;
|
||||||
this.selectionEnd = null;
|
this.selectionEnd = undefined;
|
||||||
this.isSelectAllActive = false;
|
this.isSelectAllActive = false;
|
||||||
this.selectionStartLength = 0;
|
this.selectionStartLength = 0;
|
||||||
}
|
}
|
||||||
@@ -53,7 +50,7 @@ export class SelectionModel {
|
|||||||
/**
|
/**
|
||||||
* The final selection start, taking into consideration select all.
|
* The final selection start, taking into consideration select all.
|
||||||
*/
|
*/
|
||||||
public get finalSelectionStart(): [number, number] {
|
public get finalSelectionStart(): [number, number] | undefined {
|
||||||
if (this.isSelectAllActive) {
|
if (this.isSelectAllActive) {
|
||||||
return [0, 0];
|
return [0, 0];
|
||||||
}
|
}
|
||||||
@@ -69,13 +66,13 @@ export class SelectionModel {
|
|||||||
* The final selection end, taking into consideration select all, double click
|
* The final selection end, taking into consideration select all, double click
|
||||||
* word selection and triple click line selection.
|
* word selection and triple click line selection.
|
||||||
*/
|
*/
|
||||||
public get finalSelectionEnd(): [number, number] {
|
public get finalSelectionEnd(): [number, number] | undefined {
|
||||||
if (this.isSelectAllActive) {
|
if (this.isSelectAllActive) {
|
||||||
return [this._bufferService.cols, this._terminal.buffer.ybase + this._bufferService.rows - 1];
|
return [this._bufferService.cols, this._bufferService.buffer.ybase + this._bufferService.rows - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.selectionStart) {
|
if (!this.selectionStart) {
|
||||||
return null;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the selection start + length if the end doesn't exist or they're reversed
|
// Use the selection start + length if the end doesn't exist or they're reversed
|
||||||
@@ -8,14 +8,18 @@ import { IEvent, EventEmitter } from 'common/EventEmitter';
|
|||||||
import { clone } from 'common/Clone';
|
import { clone } from 'common/Clone';
|
||||||
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
|
import { DEFAULT_OPTIONS } from 'common/services/OptionsService';
|
||||||
import { IBufferSet, IBuffer } from 'common/buffer/Types';
|
import { IBufferSet, IBuffer } from 'common/buffer/Types';
|
||||||
|
import { BufferSet } from 'common/buffer/BufferSet';
|
||||||
|
|
||||||
export class MockBufferService implements IBufferService {
|
export class MockBufferService implements IBufferService {
|
||||||
public buffer: IBuffer = {} as any;
|
public get buffer(): IBuffer { return this.buffers.active; }
|
||||||
public buffers: IBufferSet = {} as any;
|
public buffers: IBufferSet = {} as any;
|
||||||
constructor(
|
constructor(
|
||||||
public cols: number,
|
public cols: number,
|
||||||
public rows: number
|
public rows: number,
|
||||||
) {}
|
optionsService: IOptionsService = new MockOptionsService()
|
||||||
|
) {
|
||||||
|
this.buffers = new BufferSet(optionsService, this);
|
||||||
|
}
|
||||||
resize(cols: number, rows: number): void {
|
resize(cols: number, rows: number): void {
|
||||||
this.cols = cols;
|
this.cols = cols;
|
||||||
this.rows = rows;
|
this.rows = rows;
|
||||||
@@ -26,8 +30,10 @@ export class MockBufferService implements IBufferService {
|
|||||||
export class MockOptionsService implements IOptionsService {
|
export class MockOptionsService implements IOptionsService {
|
||||||
options: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
options: ITerminalOptions = clone(DEFAULT_OPTIONS);
|
||||||
onOptionChange: IEvent<string> = new EventEmitter<string>().event;
|
onOptionChange: IEvent<string> = new EventEmitter<string>().event;
|
||||||
constructor(testOptions: IPartialTerminalOptions) {
|
constructor(testOptions?: IPartialTerminalOptions) {
|
||||||
Object.keys(testOptions).forEach(key => this.options[key] = (<any>testOptions)[key]);
|
if (testOptions) {
|
||||||
|
Object.keys(testOptions).forEach(key => this.options[key] = (<any>testOptions)[key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setOption<T>(key: string, value: T): void {
|
setOption<T>(key: string, value: T): void {
|
||||||
throw new Error('Method not implemented.');
|
throw new Error('Method not implemented.');
|
||||||
|
|||||||
Reference in New Issue
Block a user