Support double click select word over wrapped lines

Part of #1571
This commit is contained in:
Daniel Imms
2018-07-26 11:09:29 -07:00
parent 8f22d8dda4
commit 7b68cb9fe7
2 changed files with 43 additions and 6 deletions
+37 -4
View File
@@ -9,7 +9,7 @@ import * as Browser from './shared/utils/Browser';
import { CharMeasure } from './ui/CharMeasure';
import { EventEmitter } from './EventEmitter';
import { SelectionModel } from './SelectionModel';
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX } from './Buffer';
import { CHAR_DATA_WIDTH_INDEX, CHAR_DATA_CHAR_INDEX, CHAR_DATA_CODE_INDEX } from './Buffer';
import { AltClickHandler } from './handlers/AltClickHandler';
/**
@@ -677,7 +677,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
* Gets positional information for the word at the coordinated specified.
* @param coords The coordinates to get the word at.
*/
private _getWordAt(coords: [number, number], allowWhitespaceOnlySelection: boolean): IWordPosition {
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) {
return null;
@@ -772,7 +772,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
// Calculate the start _column_, converting the the string indexes back to
// column coordinates.
const start =
let start =
startIndex // The index of the selection's start char in the line string
+ charOffset // The difference between the initial char's column and index
- leftWideCharCount // The number of wide chars left of the initial char
@@ -780,7 +780,7 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
// Calculate the length in _columns_, converting the the string indexes back
// to column coordinates.
const length = Math.min(this._terminal.cols, // Disallow lengths larger than the terminal cols
let length = Math.min(this._terminal.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
@@ -792,6 +792,34 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
return null;
}
// Recurse upwards if the line is wrapped and the word wraps to the above line
if (followWrappedLinesAbove) {
if (start === 0 && bufferLine[0][CHAR_DATA_CODE_INDEX] !== 32 /*' '*/) {
const previousBufferLine = this._buffer.lines.get(coords[1] - 1);
if (previousBufferLine && (<any>bufferLine).isWrapped && previousBufferLine[this._terminal.cols - 1][CHAR_DATA_CODE_INDEX] !== 32 /*' '*/) {
const previousLineWordPosition = this._getWordAt([this._terminal.cols - 1, coords[1] - 1], false, true, false);
if (previousLineWordPosition) {
const offset = this._terminal.cols - previousLineWordPosition.start;
start -= offset;
length += offset;
}
}
}
}
// Recurse downwards if the line is wrapped and the word wraps to the next line
if (followWrappedLinesBelow) {
if (start + length === this._terminal.cols && bufferLine[this._terminal.cols - 1][CHAR_DATA_CODE_INDEX] !== 32 /*' '*/) {
const nextBufferLine = this._buffer.lines.get(coords[1] + 1);
if (nextBufferLine && (<any>nextBufferLine).isWrapped && nextBufferLine[0][CHAR_DATA_CODE_INDEX] !== 32 /*' '*/) {
const nextLineWordPosition = this._getWordAt([0, coords[1] + 1], false, false, true);
if (nextLineWordPosition) {
length += nextLineWordPosition.length;
}
}
}
}
return { start, length };
}
@@ -803,6 +831,11 @@ export class SelectionManager extends EventEmitter implements ISelectionManager
protected _selectWordAt(coords: [number, number], allowWhitespaceOnlySelection: boolean): void {
const wordPosition = this._getWordAt(coords, allowWhitespaceOnlySelection);
if (wordPosition) {
// Adjust negative start values
while (wordPosition.start < 0) {
wordPosition.start += this._terminal.cols;
coords[1]--;
}
this._model.selectionStart = [wordPosition.start, coords[1]];
this._model.selectionStartLength = wordPosition.length;
}
+6 -2
View File
@@ -77,8 +77,12 @@ export class SelectionModel {
}
// Use the selection start if the end doesn't exist or they're reversed
if (!this.selectionEnd || this.areSelectionValuesReversed()) {
return [this.selectionStart[0] + this.selectionStartLength, this.selectionStart[1]];
if (!this.selectionEnd) {
const startPlusLength = this.selectionStart[0] + this.selectionStartLength;
if (startPlusLength > this._terminal.cols) {
return [startPlusLength % this._terminal.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._terminal.cols)];
}
return [startPlusLength, this.selectionStart[1]];
}
// Ensure the the word/line is selected after a double/triple click