diff --git a/src/browser/selection/SelectionModel.test.ts b/src/browser/selection/SelectionModel.test.ts index 410902d75..5ce3e316c 100644 --- a/src/browser/selection/SelectionModel.test.ts +++ b/src/browser/selection/SelectionModel.test.ts @@ -116,6 +116,12 @@ describe('SelectionModel', () => { model.selectionStartLength = 4; assert.deepEqual(model.finalSelectionEnd, [2, 3]); }); + it('should return the end on a different row when start + length overflows onto a following row with selectionEnd inbetween', () => { + model.selectionStart = [78, 2]; + model.selectionEnd = [79, 2]; + model.selectionStartLength = 4; + assert.deepEqual(model.finalSelectionEnd, [2, 3]); + }); it('should return selection end if selection end is after selection start + length', () => { model.selectionStart = [2, 2]; model.selectionStartLength = 2; diff --git a/src/browser/selection/SelectionModel.ts b/src/browser/selection/SelectionModel.ts index 1d84446a0..6c8abbfd2 100644 --- a/src/browser/selection/SelectionModel.ts +++ b/src/browser/selection/SelectionModel.ts @@ -92,7 +92,12 @@ export class SelectionModel { if (this.selectionStartLength) { // Select the larger of the two when start and end are on the same line if (this.selectionEnd[1] === this.selectionStart[1]) { - return [Math.max(this.selectionStart[0] + this.selectionStartLength, this.selectionEnd[0]), this.selectionEnd[1]]; + // Keep the whole wrapped word/line selected if the content wraps multiple lines + const startPlusLength = this.selectionStart[0] + this.selectionStartLength; + if (startPlusLength > this._bufferService.cols) { + return [startPlusLength % this._bufferService.cols, this.selectionStart[1] + Math.floor(startPlusLength / this._bufferService.cols)]; + } + return [Math.max(startPlusLength, this.selectionEnd[0]), this.selectionEnd[1]]; } } return this.selectionEnd; diff --git a/src/browser/services/SelectionService.test.ts b/src/browser/services/SelectionService.test.ts index 514d5803c..d829e3945 100644 --- a/src/browser/services/SelectionService.test.ts +++ b/src/browser/services/SelectionService.test.ts @@ -340,6 +340,9 @@ describe('SelectionService', () => { buffer.lines.set(0, stringToRow('foo bar')); selectionService.selectLineAt(0); assert.equal(selectionService.selectionText, 'foo bar', 'The selected text is correct'); + assert.deepEqual(selectionService.model.selectionStart, [0, 0]); + assert.deepEqual(selectionService.model.selectionEnd, undefined); + assert.deepEqual(selectionService.model.selectionStartLength, 20); assert.deepEqual(selectionService.model.finalSelectionStart, [0, 0]); assert.deepEqual(selectionService.model.finalSelectionEnd, [bufferService.cols, 0], 'The actual selection spans the entire column'); }); @@ -350,6 +353,9 @@ describe('SelectionService', () => { buffer.lines.set(1, line2); selectionService.selectLineAt(0); assert.equal(selectionService.selectionText, 'foobar', 'The selected text is correct'); + assert.deepEqual(selectionService.model.selectionStart, [0, 0]); + assert.deepEqual(selectionService.model.selectionEnd, undefined); + assert.deepEqual(selectionService.model.selectionStartLength, 40); assert.deepEqual(selectionService.model.finalSelectionStart, [0, 0]); assert.deepEqual(selectionService.model.finalSelectionEnd, [bufferService.cols, 1], 'The actual selection spans the entire column'); }); diff --git a/src/browser/services/SelectionService.ts b/src/browser/services/SelectionService.ts index 1ea2395d8..53020b534 100644 --- a/src/browser/services/SelectionService.ts +++ b/src/browser/services/SelectionService.ts @@ -11,7 +11,7 @@ import { SelectionModel } from 'browser/selection/SelectionModel'; import { CellData } from 'common/buffer/CellData'; import { EventEmitter, IEvent } from 'common/EventEmitter'; import { IMouseService, ISelectionService, IRenderService } from 'browser/services/Services'; -import { ILinkifier2 } from 'browser/Types'; +import { IBufferRange, ILinkifier2 } from 'browser/Types'; import { IBufferService, IOptionsService, ICoreService } from 'common/services/Services'; import { getCoordsRelativeToElement } from 'browser/input/Mouse'; import { moveToCellSequence } from 'browser/input/MoveToCell'; @@ -1002,8 +1002,12 @@ export class SelectionService extends Disposable implements ISelectionService { */ protected _selectLineAt(line: number): void { const wrappedRange = this._bufferService.buffer.getWrappedRangeForLine(line); + const range: IBufferRange = { + start: { x: 0, y: wrappedRange.first }, + end: { x: this._bufferService.cols - 1, y: wrappedRange.last } + }; this._model.selectionStart = [0, wrappedRange.first]; - this._model.selectionEnd = [this._bufferService.cols, wrappedRange.last]; - this._model.selectionStartLength = 0; + this._model.selectionEnd = undefined; + this._model.selectionStartLength = getRangeLength(range, this._bufferService.cols); } }