Merge pull request #2245 from Tyriar/clipboard_term_dep

Remove some terminal dependencies in Clipboard and SelectionManager
This commit is contained in:
Daniel Imms
2019-06-21 20:39:06 -07:00
committed by GitHub
4 changed files with 96 additions and 92 deletions
+25 -26
View File
@@ -3,7 +3,7 @@
* @license MIT
*/
import { ITerminal, ISelectionManager } from './Types';
import { ISelectionManager } from './Types';
/**
* Prepares text to be pasted into the terminal by normalizing the line endings
@@ -28,7 +28,7 @@ export function bracketTextForPaste(text: string, bracketedPasteMode: boolean):
* Binds copy functionality to the given terminal.
* @param ev The original copy event to be handled
*/
export function copyHandler(ev: ClipboardEvent, term: ITerminal, selectionManager: ISelectionManager): void {
export function copyHandler(ev: ClipboardEvent, selectionManager: ISelectionManager): void {
ev.clipboardData.setData('text/plain', selectionManager.selectionText);
// Prevent or the original text will be copied.
ev.preventDefault();
@@ -39,17 +39,16 @@ export function copyHandler(ev: ClipboardEvent, term: ITerminal, selectionManage
* @param ev The original paste event to be handled
* @param term The terminal on which to apply the handled paste event
*/
export function pasteHandler(ev: ClipboardEvent, term: ITerminal): void {
export function pasteHandler(ev: ClipboardEvent, textarea: HTMLTextAreaElement, bracketedPasteMode: boolean, triggerUserInput: (data: string) => void): void {
ev.stopPropagation();
let text: string;
const dispatchPaste = function(text: string): void {
text = prepareTextForTerminal(text);
text = bracketTextForPaste(text, term.bracketedPasteMode);
term.handler(text);
term.textarea.value = '';
term.cancel(ev);
text = bracketTextForPaste(text, bracketedPasteMode);
triggerUserInput(text);
textarea.value = '';
};
if (ev.clipboardData) {
@@ -63,32 +62,32 @@ export function pasteHandler(ev: ClipboardEvent, term: ITerminal): void {
* @param ev The original right click event to be handled.
* @param textarea The terminal's textarea.
*/
export function moveTextAreaUnderMouseCursor(ev: MouseEvent, term: ITerminal): void {
export function moveTextAreaUnderMouseCursor(ev: MouseEvent, textarea: HTMLTextAreaElement, screenElement: HTMLElement): void {
// Calculate textarea position relative to the screen element
const pos = term.screenElement.getBoundingClientRect();
const pos = screenElement.getBoundingClientRect();
const left = ev.clientX - pos.left - 10;
const top = ev.clientY - pos.top - 10;
// Bring textarea at the cursor position
term.textarea.style.position = 'absolute';
term.textarea.style.width = '20px';
term.textarea.style.height = '20px';
term.textarea.style.left = `${left}px`;
term.textarea.style.top = `${top}px`;
term.textarea.style.zIndex = '1000';
textarea.style.position = 'absolute';
textarea.style.width = '20px';
textarea.style.height = '20px';
textarea.style.left = `${left}px`;
textarea.style.top = `${top}px`;
textarea.style.zIndex = '1000';
term.textarea.focus();
textarea.focus();
// Reset the terminal textarea's styling
// Timeout needs to be long enough for click event to be handled.
setTimeout(() => {
term.textarea.style.position = null;
term.textarea.style.width = null;
term.textarea.style.height = null;
term.textarea.style.left = null;
term.textarea.style.top = null;
term.textarea.style.zIndex = null;
textarea.style.position = null;
textarea.style.width = null;
textarea.style.height = null;
textarea.style.left = null;
textarea.style.top = null;
textarea.style.zIndex = null;
}, 200);
}
@@ -99,14 +98,14 @@ export function moveTextAreaUnderMouseCursor(ev: MouseEvent, term: ITerminal): v
* @param selectionManager The terminal's selection manager.
* @param shouldSelectWord If true and there is no selection the current word will be selected
*/
export function rightClickHandler(ev: MouseEvent, term: ITerminal, selectionManager: ISelectionManager, shouldSelectWord: boolean): void {
moveTextAreaUnderMouseCursor(ev, term);
export function rightClickHandler(ev: MouseEvent, textarea: HTMLTextAreaElement, screenElement: HTMLElement, selectionManager: ISelectionManager, shouldSelectWord: boolean): void {
moveTextAreaUnderMouseCursor(ev, textarea, screenElement);
if (shouldSelectWord && !selectionManager.isClickInSelection(ev)) {
selectionManager.selectWordAtCursor(ev);
}
// Get textarea ready to copy from the context menu
term.textarea.value = selectionManager.selectionText;
term.textarea.select();
textarea.value = selectionManager.selectionText;
textarea.select();
}
+9 -6
View File
@@ -10,9 +10,9 @@ import { ITerminal } from './Types';
import { IBuffer } from 'common/buffer/Types';
import { IBufferLine } from 'common/Types';
import { MockTerminal } from './TestUtils.test';
import { MockBufferService } from 'common/TestUtils.test';
import { MockBufferService, MockOptionsService } from 'common/TestUtils.test';
import { BufferLine } from 'common/buffer/BufferLine';
import { IBufferService } from 'common/services/Services';
import { IBufferService, IOptionsService } from 'common/services/Services';
import { MockCharSizeService, MockMouseService } from 'browser/TestUtils.test';
import { CellData } from 'common/buffer/CellData';
@@ -23,9 +23,10 @@ class TestMockTerminal extends MockTerminal {
class TestSelectionManager extends SelectionManager {
constructor(
terminal: ITerminal,
bufferService: IBufferService
bufferService: IBufferService,
optionsService: IOptionsService
) {
super(terminal, new MockCharSizeService(10, 10), bufferService, new MockMouseService());
super(terminal, null, new MockCharSizeService(10, 10), bufferService, new MockMouseService(), optionsService);
}
public get model(): SelectionModel { return this._model; }
@@ -46,17 +47,19 @@ describe('SelectionManager', () => {
let terminal: ITerminal;
let buffer: IBuffer;
let bufferService: IBufferService;
let optionsService: IOptionsService;
let selectionManager: TestSelectionManager;
beforeEach(() => {
terminal = new TestMockTerminal();
bufferService = new MockBufferService(20, 20);
optionsService = new MockOptionsService();
bufferService = new MockBufferService(20, 20, optionsService);
terminal.buffers = bufferService.buffers;
terminal.cols = 20;
terminal.rows = 20;
terminal.buffer = terminal.buffers.active;
buffer = terminal.buffer;
selectionManager = new TestSelectionManager(terminal, bufferService);
selectionManager = new TestSelectionManager(terminal, bufferService, optionsService);
});
function stringToRow(text: string): IBufferLine {
+56 -54
View File
@@ -13,7 +13,7 @@ import { CellData } from 'common/buffer/CellData';
import { IDisposable } from 'xterm';
import { EventEmitter, IEvent } from 'common/EventEmitter';
import { ICharSizeService, IMouseService } from 'browser/services/Services';
import { IBufferService } from 'common/services/Services';
import { IBufferService, IOptionsService } from 'common/services/Services';
import { getCoordsRelativeToElement } from 'browser/input/Mouse';
/**
@@ -113,14 +113,16 @@ export class SelectionManager implements ISelectionManager {
constructor(
private readonly _terminal: ITerminal,
private readonly _screenElement: HTMLElement,
private readonly _charSizeService: ICharSizeService,
readonly bufferService: IBufferService,
private readonly _mouseService: IMouseService
private readonly _bufferService: IBufferService,
private readonly _mouseService: IMouseService,
private readonly _optionsService: IOptionsService
) {
this._initListeners();
this.enable();
this._model = new SelectionModel(bufferService);
this._model = new SelectionModel(this._bufferService);
this._activeSelectionMode = SelectionMode.NORMAL;
}
@@ -128,10 +130,6 @@ export class SelectionManager implements ISelectionManager {
this._removeMouseDownListeners();
}
private get _buffer(): IBuffer {
return this._terminal.buffers.active;
}
/**
* Initializes listener variables.
*/
@@ -143,8 +141,8 @@ export class SelectionManager implements ISelectionManager {
}
public initBuffersListeners(): void {
this._trimListener = this._terminal.buffer.lines.onTrim(amount => this._onTrim(amount));
this._terminal.buffers.onBufferActivate(e => this._onBufferActivate(e));
this._trimListener = this._bufferService.buffer.lines.onTrim(amount => this._onTrim(amount));
this._bufferService.buffers.onBufferActivate(e => this._onBufferActivate(e));
}
/**
@@ -188,6 +186,7 @@ export class SelectionManager implements ISelectionManager {
return '';
}
const buffer = this._bufferService.buffer;
const result: string[] = [];
if (this._activeSelectionMode === SelectionMode.COLUMN) {
@@ -197,18 +196,18 @@ export class SelectionManager implements ISelectionManager {
}
for (let i = start[1]; i <= end[1]; i++) {
const lineText = this._buffer.translateBufferLineToString(i, true, start[0], end[0]);
const lineText = buffer.translateBufferLineToString(i, true, start[0], end[0]);
result.push(lineText);
}
} else {
// Get first row
const startRowEndCol = start[1] === end[1] ? end[0] : undefined;
result.push(this._buffer.translateBufferLineToString(start[1], true, start[0], startRowEndCol));
result.push(buffer.translateBufferLineToString(start[1], true, start[0], startRowEndCol));
// Get middle rows
for (let i = start[1] + 1; i <= end[1] - 1; i++) {
const bufferLine = this._buffer.lines.get(i);
const lineText = this._buffer.translateBufferLineToString(i, true);
const bufferLine = buffer.lines.get(i);
const lineText = buffer.translateBufferLineToString(i, true);
if (bufferLine.isWrapped) {
result[result.length - 1] += lineText;
} else {
@@ -218,8 +217,8 @@ export class SelectionManager implements ISelectionManager {
// Get final row
if (start[1] !== end[1]) {
const bufferLine = this._buffer.lines.get(end[1]);
const lineText = this._buffer.translateBufferLineToString(end[1], true, 0, end[0]);
const bufferLine = buffer.lines.get(end[1]);
const lineText = buffer.translateBufferLineToString(end[1], true, 0, end[0]);
if (bufferLine.isWrapped) {
result[result.length - 1] += lineText;
} else {
@@ -329,9 +328,9 @@ export class SelectionManager implements ISelectionManager {
public selectLines(start: number, end: number): void {
this._model.clearSelection();
start = Math.max(start, 0);
end = Math.min(end, this._terminal.buffer.lines.length - 1);
end = Math.min(end, this._bufferService.buffer.lines.length - 1);
this._model.selectionStart = [0, start];
this._model.selectionEnd = [this._terminal.cols, end];
this._model.selectionEnd = [this._bufferService.cols, end];
this.refresh();
this._onSelectionChange.fire();
}
@@ -352,7 +351,7 @@ export class SelectionManager implements ISelectionManager {
* @param event The mouse event.
*/
private _getMouseBufferCoords(event: MouseEvent): [number, number] {
const coords = this._mouseService.getCoords(event, this._terminal.screenElement, this._terminal.cols, this._terminal.rows, true);
const coords = this._mouseService.getCoords(event, this._screenElement, this._bufferService.cols, this._bufferService.rows, true);
if (!coords) {
return null;
}
@@ -362,7 +361,7 @@ export class SelectionManager implements ISelectionManager {
coords[1]--;
// Convert viewport coords to buffer coords
coords[1] += this._terminal.buffer.ydisp;
coords[1] += this._bufferService.buffer.ydisp;
return coords;
}
@@ -372,8 +371,8 @@ export class SelectionManager implements ISelectionManager {
* @param event The mouse event.
*/
private _getMouseEventScrollAmount(event: MouseEvent): number {
let offset = getCoordsRelativeToElement(event, this._terminal.screenElement)[1];
const terminalHeight = this._terminal.rows * Math.ceil(this._charSizeService.height * this._terminal.options.lineHeight);
let offset = getCoordsRelativeToElement(event, this._screenElement)[1];
const terminalHeight = this._bufferService.rows * Math.ceil(this._charSizeService.height * this._optionsService.options.lineHeight);
if (offset >= 0 && offset <= terminalHeight) {
return 0;
}
@@ -393,7 +392,7 @@ export class SelectionManager implements ISelectionManager {
*/
public shouldForceSelection(event: MouseEvent): boolean {
if (Browser.isMac) {
return event.altKey && this._terminal.options.macOptionClickForcesSelection;
return event.altKey && this._optionsService.options.macOptionClickForcesSelection;
}
return event.shiftKey;
@@ -453,8 +452,8 @@ export class SelectionManager implements ISelectionManager {
*/
private _addMouseDownListeners(): void {
// Listen on the document so that dragging outside of viewport works
this._terminal.element.ownerDocument.addEventListener('mousemove', this._mouseMoveListener);
this._terminal.element.ownerDocument.addEventListener('mouseup', this._mouseUpListener);
this._screenElement.ownerDocument.addEventListener('mousemove', this._mouseMoveListener);
this._screenElement.ownerDocument.addEventListener('mouseup', this._mouseUpListener);
this._dragScrollIntervalTimer = setInterval(() => this._dragScroll(), DRAG_SCROLL_INTERVAL);
}
@@ -462,9 +461,9 @@ export class SelectionManager implements ISelectionManager {
* Removes the listeners that are registered when mousedown is triggered.
*/
private _removeMouseDownListeners(): void {
if (this._terminal.element.ownerDocument) {
this._terminal.element.ownerDocument.removeEventListener('mousemove', this._mouseMoveListener);
this._terminal.element.ownerDocument.removeEventListener('mouseup', this._mouseUpListener);
if (this._screenElement.ownerDocument) {
this._screenElement.ownerDocument.removeEventListener('mousemove', this._mouseMoveListener);
this._screenElement.ownerDocument.removeEventListener('mouseup', this._mouseUpListener);
}
clearInterval(this._dragScrollIntervalTimer);
this._dragScrollIntervalTimer = null;
@@ -499,7 +498,7 @@ export class SelectionManager implements ISelectionManager {
this._model.selectionEnd = null;
// Ensure the line exists
const line = this._buffer.lines.get(this._model.selectionStart[1]);
const line = this._bufferService.buffer.lines.get(this._model.selectionStart[1]);
if (!line) {
return;
}
@@ -546,7 +545,7 @@ export class SelectionManager implements ISelectionManager {
* @param event the mouse or keyboard event
*/
public shouldColumnSelect(event: KeyboardEvent | MouseEvent): boolean {
return event.altKey && !(Browser.isMac && this._terminal.options.macOptionClickForcesSelection);
return event.altKey && !(Browser.isMac && this._optionsService.options.macOptionClickForcesSelection);
}
/**
@@ -576,7 +575,7 @@ export class SelectionManager implements ISelectionManager {
if (this._model.selectionEnd[1] < this._model.selectionStart[1]) {
this._model.selectionEnd[0] = 0;
} else {
this._model.selectionEnd[0] = this._terminal.cols;
this._model.selectionEnd[0] = this._bufferService.cols;
}
} else if (this._activeSelectionMode === SelectionMode.WORD) {
this._selectToWordAt(this._model.selectionEnd);
@@ -590,7 +589,7 @@ export class SelectionManager implements ISelectionManager {
// NOT in column select mode.
if (this._activeSelectionMode !== SelectionMode.COLUMN) {
if (this._dragScrollAmount > 0) {
this._model.selectionEnd[0] = this._terminal.cols;
this._model.selectionEnd[0] = this._bufferService.cols;
} else if (this._dragScrollAmount < 0) {
this._model.selectionEnd[0] = 0;
}
@@ -599,8 +598,9 @@ export class SelectionManager implements ISelectionManager {
// If the character is a wide character include the cell to the right in the
// selection. Note that selections at the very end of the line will never
// have a character.
if (this._model.selectionEnd[1] < this._buffer.lines.length) {
if (this._buffer.lines.get(this._model.selectionEnd[1]).hasWidth(this._model.selectionEnd[0]) === 0) {
const buffer = this._bufferService.buffer;
if (this._model.selectionEnd[1] < buffer.lines.length) {
if (buffer.lines.get(this._model.selectionEnd[1]).hasWidth(this._model.selectionEnd[0]) === 0) {
this._model.selectionEnd[0]++;
}
}
@@ -624,16 +624,17 @@ export class SelectionManager implements ISelectionManager {
// If the cursor was above or below the viewport, make sure it's at the
// start or end of the viewport respectively. This should only happen when
// NOT in column select mode.
const buffer = this._bufferService.buffer;
if (this._dragScrollAmount > 0) {
if (this._activeSelectionMode !== SelectionMode.COLUMN) {
this._model.selectionEnd[0] = this._terminal.cols;
this._model.selectionEnd[0] = this._bufferService.cols;
}
this._model.selectionEnd[1] = Math.min(this._terminal.buffer.ydisp + this._terminal.rows, this._terminal.buffer.lines.length - 1);
this._model.selectionEnd[1] = Math.min(buffer.ydisp + this._bufferService.rows, buffer.lines.length - 1);
} else {
if (this._activeSelectionMode !== SelectionMode.COLUMN) {
this._model.selectionEnd[0] = 0;
}
this._model.selectionEnd[1] = this._terminal.buffer.ydisp;
this._model.selectionEnd[1] = buffer.ydisp;
}
this.refresh();
}
@@ -704,16 +705,17 @@ export class SelectionManager implements ISelectionManager {
*/
private _getWordAt(coords: [number, number], allowWhitespaceOnlySelection: boolean, followWrappedLinesAbove: boolean = true, followWrappedLinesBelow: boolean = true): IWordPosition {
// Ensure coords are within viewport (eg. not within scroll bar)
if (coords[0] >= this._terminal.cols) {
if (coords[0] >= this._bufferService.cols) {
return null;
}
const bufferLine = this._buffer.lines.get(coords[1]);
const buffer = this._bufferService.buffer;
const bufferLine = buffer.lines.get(coords[1]);
if (!bufferLine) {
return null;
}
const line = this._buffer.translateBufferLineToString(coords[1], false);
const line = buffer.translateBufferLineToString(coords[1], false);
// Get actual index, taking into consideration wide characters
let startIndex = this._convertViewportColToCharacterIndex(bufferLine, coords);
@@ -808,7 +810,7 @@ export class SelectionManager implements ISelectionManager {
// Calculate the length in _columns_, converting the the string indexes back
// to column coordinates.
let length = Math.min(this._terminal.cols, // Disallow lengths larger than the terminal cols
let length = Math.min(this._bufferService.cols, // Disallow lengths larger than the terminal cols
endIndex // The index of the selection's end char in the line string
- startIndex // The index of the selection's start char in the line string
+ leftWideCharCount // The number of wide chars left of the initial char
@@ -823,11 +825,11 @@ export class SelectionManager implements ISelectionManager {
// Recurse upwards if the line is wrapped and the word wraps to the above line
if (followWrappedLinesAbove) {
if (start === 0 && bufferLine.getCodePoint(0) !== 32 /*' '*/) {
const previousBufferLine = this._buffer.lines.get(coords[1] - 1);
if (previousBufferLine && bufferLine.isWrapped && previousBufferLine.getCodePoint(this._terminal.cols - 1) !== 32 /*' '*/) {
const previousLineWordPosition = this._getWordAt([this._terminal.cols - 1, coords[1] - 1], false, true, false);
const previousBufferLine = buffer.lines.get(coords[1] - 1);
if (previousBufferLine && bufferLine.isWrapped && previousBufferLine.getCodePoint(this._bufferService.cols - 1) !== 32 /*' '*/) {
const previousLineWordPosition = this._getWordAt([this._bufferService.cols - 1, coords[1] - 1], false, true, false);
if (previousLineWordPosition) {
const offset = this._terminal.cols - previousLineWordPosition.start;
const offset = this._bufferService.cols - previousLineWordPosition.start;
start -= offset;
length += offset;
}
@@ -837,8 +839,8 @@ export class SelectionManager implements ISelectionManager {
// Recurse downwards if the line is wrapped and the word wraps to the next line
if (followWrappedLinesBelow) {
if (start + length === this._terminal.cols && bufferLine.getCodePoint(this._terminal.cols - 1) !== 32 /*' '*/) {
const nextBufferLine = this._buffer.lines.get(coords[1] + 1);
if (start + length === this._bufferService.cols && bufferLine.getCodePoint(this._bufferService.cols - 1) !== 32 /*' '*/) {
const nextBufferLine = buffer.lines.get(coords[1] + 1);
if (nextBufferLine && nextBufferLine.isWrapped && nextBufferLine.getCodePoint(0) !== 32 /*' '*/) {
const nextLineWordPosition = this._getWordAt([0, coords[1] + 1], false, false, true);
if (nextLineWordPosition) {
@@ -861,7 +863,7 @@ export class SelectionManager implements ISelectionManager {
if (wordPosition) {
// Adjust negative start value
while (wordPosition.start < 0) {
wordPosition.start += this._terminal.cols;
wordPosition.start += this._bufferService.cols;
coords[1]--;
}
this._model.selectionStart = [wordPosition.start, coords[1]];
@@ -880,15 +882,15 @@ export class SelectionManager implements ISelectionManager {
// Adjust negative start value
while (wordPosition.start < 0) {
wordPosition.start += this._terminal.cols;
wordPosition.start += this._bufferService.cols;
endRow--;
}
// Adjust wrapped length value, this only needs to happen when values are reversed as in that
// case we're interested in the start of the word, not the end
if (!this._model.areSelectionValuesReversed()) {
while (wordPosition.start + wordPosition.length > this._terminal.cols) {
wordPosition.length -= this._terminal.cols;
while (wordPosition.start + wordPosition.length > this._bufferService.cols) {
wordPosition.length -= this._bufferService.cols;
endRow++;
}
}
@@ -908,7 +910,7 @@ export class SelectionManager implements ISelectionManager {
if (cell.getWidth() === 0) {
return false;
}
return this._terminal.optionsService.options.wordSeparator.indexOf(cell.getChars()) >= 0;
return this._optionsService.options.wordSeparator.indexOf(cell.getChars()) >= 0;
}
/**
@@ -916,9 +918,9 @@ export class SelectionManager implements ISelectionManager {
* @param line The line index.
*/
protected _selectLineAt(line: number): void {
const wrappedRange = this._buffer.getWrappedRangeForLine(line);
const wrappedRange = this._bufferService.buffer.getWrappedRangeForLine(line);
this._model.selectionStart = [0, wrappedRange.first];
this._model.selectionEnd = [this._terminal.cols, wrappedRange.last];
this._model.selectionEnd = [this._bufferService.cols, wrappedRange.last];
this._model.selectionStartLength = 0;
}
}
+6 -6
View File
@@ -478,9 +478,9 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
if (!this.hasSelection()) {
return;
}
copyHandler(event, this, this.selectionManager);
copyHandler(event, this.selectionManager);
}));
const pasteHandlerWrapper = (event: ClipboardEvent) => pasteHandler(event, this);
const pasteHandlerWrapper = (event: ClipboardEvent) => pasteHandler(event, this.textarea, this.bracketedPasteMode, e => this.handler(e));
this.register(addDisposableDomListener(this.textarea, 'paste', pasteHandlerWrapper));
this.register(addDisposableDomListener(this.element, 'paste', pasteHandlerWrapper));
@@ -489,12 +489,12 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
// Firefox doesn't appear to fire the contextmenu event on right click
this.register(addDisposableDomListener(this.element, 'mousedown', (event: MouseEvent) => {
if (event.button === 2) {
rightClickHandler(event, this, this.selectionManager, this.options.rightClickSelectsWord);
rightClickHandler(event, this.textarea, this.screenElement, this.selectionManager, this.options.rightClickSelectsWord);
}
}));
} else {
this.register(addDisposableDomListener(this.element, 'contextmenu', (event: MouseEvent) => {
rightClickHandler(event, this, this.selectionManager, this.options.rightClickSelectsWord);
rightClickHandler(event, this.textarea, this.screenElement, this.selectionManager, this.options.rightClickSelectsWord);
}));
}
@@ -506,7 +506,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
// that the regular click event doesn't fire for the middle mouse button.
this.register(addDisposableDomListener(this.element, 'auxclick', (event: MouseEvent) => {
if (event.button === 1) {
moveTextAreaUnderMouseCursor(event, this);
moveTextAreaUnderMouseCursor(event, this.textarea, this.screenElement);
}
}));
}
@@ -640,7 +640,7 @@ export class Terminal extends Disposable implements ITerminal, IDisposable, IInp
this.register(this.onFocus(() => this._renderService.onFocus()));
this.register(this._renderService.onDimensionsChange(() => this.viewport.syncScrollArea()));
this.selectionManager = new SelectionManager(this, this._charSizeService, this._bufferService, this._mouseService);
this.selectionManager = new SelectionManager(this, this.screenElement, this._charSizeService, this._bufferService, this._mouseService, this.optionsService);
this.register(this.selectionManager.onSelectionChange(() => this._onSelectionChange.fire()));
this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this.selectionManager.onMouseDown(e)));
this.register(this.selectionManager.onRedrawRequest(e => this._renderService.onSelectionChanged(e.start, e.end, e.columnSelectMode)));