Merge pull request #816 from joaomoreno/alt-selection

Alt key should force selection
This commit is contained in:
Daniel Imms 2017-07-28 14:24:45 -07:00 committed by GitHub
commit bcff69b79c
3 changed files with 46 additions and 23 deletions

View File

@ -45,6 +45,7 @@ describe('SelectionManager', () => {
dom = new jsdom.JSDOM(''); dom = new jsdom.JSDOM('');
window = dom.window; window = dom.window;
document = window.document; document = window.document;
rowContainer = document.createElement('div');
terminal = <any>{ cols: 80, rows: 2 }; terminal = <any>{ cols: 80, rows: 2 };
terminal.scrollback = 100; terminal.scrollback = 100;
terminal.buffers = new BufferSet(terminal); terminal.buffers = new BufferSet(terminal);

View File

@ -91,9 +91,12 @@ export class SelectionManager extends EventEmitter {
*/ */
private _refreshAnimationFrame: number; private _refreshAnimationFrame: number;
private _bufferTrimListener: any; /**
* Whether selection is enabled.
*/
private _enabled = true;
private _mouseMoveListener: EventListener; private _mouseMoveListener: EventListener;
private _mouseDownListener: EventListener;
private _mouseUpListener: EventListener; private _mouseUpListener: EventListener;
constructor( constructor(
@ -114,10 +117,16 @@ export class SelectionManager extends EventEmitter {
* Initializes listener variables. * Initializes listener variables.
*/ */
private _initListeners() { private _initListeners() {
this._bufferTrimListener = (amount: number) => this._onTrim(amount);
this._mouseMoveListener = event => this._onMouseMove(<MouseEvent>event); this._mouseMoveListener = event => this._onMouseMove(<MouseEvent>event);
this._mouseDownListener = event => this._onMouseDown(<MouseEvent>event);
this._mouseUpListener = event => this._onMouseUp(<MouseEvent>event); this._mouseUpListener = event => this._onMouseUp(<MouseEvent>event);
this._rowContainer.addEventListener('mousedown', event => this._onMouseDown(<MouseEvent>event));
// Only adjust the selection on trim, shiftElements is rarely used (only in
// reverseIndex) and delete in a splice is only ever used when the same
// number of elements was just added. Given this is could actually be
// beneficial to leave the selection as is for these cases.
this._buffer.on('trim', (amount: number) => this._onTrim(amount));
} }
/** /**
@ -126,20 +135,14 @@ export class SelectionManager extends EventEmitter {
*/ */
public disable() { public disable() {
this.clearSelection(); this.clearSelection();
this._buffer.off('trim', this._bufferTrimListener); this._enabled = false;
this._rowContainer.removeEventListener('mousedown', this._mouseDownListener);
} }
/** /**
* Enable the selection manager. * Enable the selection manager.
*/ */
public enable() { public enable() {
// Only adjust the selection on trim, shiftElements is rarely used (only in this._enabled = true;
// reverseIndex) and delete in a splice is only ever used when the same
// number of elements was just added. Given this is could actually be
// beneficial to leave the selection as is for these cases.
this._buffer.on('trim', this._bufferTrimListener);
this._rowContainer.addEventListener('mousedown', this._mouseDownListener);
} }
/** /**
@ -314,26 +317,45 @@ export class SelectionManager extends EventEmitter {
* @param event The mousedown event. * @param event The mousedown event.
*/ */
private _onMouseDown(event: MouseEvent) { private _onMouseDown(event: MouseEvent) {
// If we have selection, we want the context menu on right click even if the
// terminal is in mouse mode.
if (event.button === 2 && this.hasSelection) {
event.stopPropagation();
return;
}
// Only action the primary button // Only action the primary button
if (event.button !== 0) { if (event.button !== 0) {
return; return;
} }
// Allow selection when using a specific modifier key, even when disabled
if (!this._enabled) {
const shouldForceSelection = Browser.isMac && event.altKey;
if (!shouldForceSelection) {
return;
}
// Don't send the mouse down event to the current process, we want to select
event.stopPropagation();
}
// Tell the browser not to start a regular selection // Tell the browser not to start a regular selection
event.preventDefault(); event.preventDefault();
// Reset drag scroll state // Reset drag scroll state
this._dragScrollAmount = 0; this._dragScrollAmount = 0;
if (event.shiftKey) { if (this._enabled && event.shiftKey) {
this._onShiftClick(event); this._onIncrementalClick(event);
} else { } else {
if (event.detail === 1) { if (event.detail === 1) {
this._onSingleClick(event); this._onSingleClick(event);
} else if (event.detail === 2) { } else if (event.detail === 2) {
this._onDoubleClick(event); this._onDoubleClick(event);
} else if (event.detail === 3) { } else if (event.detail === 3) {
this._onTripleClick(event); this._onTripleClick(event);
} }
} }
@ -362,11 +384,11 @@ export class SelectionManager extends EventEmitter {
} }
/** /**
* Performs a shift click, setting the selection end position to the mouse * Performs an incremental click, setting the selection end position to the mouse
* position. * position.
* @param event The mouse event. * @param event The mouse event.
*/ */
private _onShiftClick(event: MouseEvent): void { private _onIncrementalClick(event: MouseEvent): void {
if (this._model.selectionStart) { if (this._model.selectionStart) {
this._model.selectionEnd = this._getMouseBufferCoords(event); this._model.selectionEnd = this._getMouseBufferCoords(event);
} }
@ -479,8 +501,8 @@ export class SelectionManager extends EventEmitter {
// Only draw here if the selection changes. // Only draw here if the selection changes.
if (!previousSelectionEnd || if (!previousSelectionEnd ||
previousSelectionEnd[0] !== this._model.selectionEnd[0] || previousSelectionEnd[0] !== this._model.selectionEnd[0] ||
previousSelectionEnd[1] !== this._model.selectionEnd[1]) { previousSelectionEnd[1] !== this._model.selectionEnd[1]) {
this.refresh(true); this.refresh(true);
} }
} }
@ -603,7 +625,7 @@ export class SelectionManager extends EventEmitter {
const start = startIndex + charOffset - leftWideCharCount; const start = startIndex + charOffset - leftWideCharCount;
const length = Math.min(endIndex - startIndex + leftWideCharCount + rightWideCharCount + 1/*include endIndex char*/, this._terminal.cols); const length = Math.min(endIndex - startIndex + leftWideCharCount + rightWideCharCount + 1/*include endIndex char*/, this._terminal.cols);
return {start, length}; return { start, length };
} }
/** /**

View File

@ -517,7 +517,7 @@ Terminal.prototype.initGlobal = function() {
on(this.element, 'copy', event => { on(this.element, 'copy', event => {
// If mouse events are active it means the selection manager is disabled and // If mouse events are active it means the selection manager is disabled and
// copy should be handled by the host program. // copy should be handled by the host program.
if (this.mouseEvents) { if (!term.hasSelection()) {
return; return;
} }
copyHandler(event, term, this.selectionManager); copyHandler(event, term, this.selectionManager);