diff --git a/src/vs/editor/browser/controller/textAreaHandler.ts b/src/vs/editor/browser/controller/textAreaHandler.ts index 495308c83f9..43c10128454 100644 --- a/src/vs/editor/browser/controller/textAreaHandler.ts +++ b/src/vs/editor/browser/controller/textAreaHandler.ts @@ -201,6 +201,9 @@ export class TextAreaHandler extends ViewPart { }, getValueLengthInRange: (range: Range, eol: EndOfLinePreference): number => { return this._context.viewModel.getValueLengthInRange(range, eol); + }, + modifyPosition: (position: Position, offset: number): Position => { + return this._context.viewModel.modifyPosition(position, offset); } }; @@ -230,7 +233,7 @@ export class TextAreaHandler extends ViewPart { mode }; }, - getScreenReaderContent: (currentState: TextAreaState): TextAreaState => { + getScreenReaderContent: (): TextAreaState => { if (this._accessibilitySupport === AccessibilitySupport.Disabled) { // We know for a fact that a screen reader is not attached // On OSX, we write the character before the cursor to allow for "long-press" composition @@ -245,7 +248,7 @@ export class TextAreaHandler extends ViewPart { } if (textBefore.length > 0) { - return new TextAreaState(textBefore, textBefore.length, textBefore.length, position, position); + return new TextAreaState(textBefore, textBefore.length, textBefore.length, Range.fromPositions(position), 0); } } // on macOS, write current selection into textarea will allow system text services pick selected text, @@ -255,7 +258,7 @@ export class TextAreaHandler extends ViewPart { const LIMIT_CHARS = 500; if (platform.isMacintosh && !selection.isEmpty() && simpleModel.getValueLengthInRange(selection, EndOfLinePreference.TextDefined) < LIMIT_CHARS) { const text = simpleModel.getValueInRange(selection, EndOfLinePreference.TextDefined); - return new TextAreaState(text, 0, text.length, selection.getStartPosition(), selection.getEndPosition()); + return new TextAreaState(text, 0, text.length, selection, 0); } // on Safari, document.execCommand('cut') and document.execCommand('copy') will just not work @@ -263,7 +266,7 @@ export class TextAreaHandler extends ViewPart { // is selected in the textarea. if (browser.isSafari && !selection.isEmpty()) { const placeholderText = 'vscode-placeholder'; - return new TextAreaState(placeholderText, 0, placeholderText.length, null, null); + return new TextAreaState(placeholderText, 0, placeholderText.length, null, undefined); } return TextAreaState.EMPTY; @@ -279,13 +282,13 @@ export class TextAreaHandler extends ViewPart { const position = selection.getStartPosition(); const [wordAtPosition, positionOffsetInWord] = this._getAndroidWordAtPosition(position); if (wordAtPosition.length > 0) { - return new TextAreaState(wordAtPosition, positionOffsetInWord, positionOffsetInWord, position, position); + return new TextAreaState(wordAtPosition, positionOffsetInWord, positionOffsetInWord, Range.fromPositions(position), 0); } } return TextAreaState.EMPTY; } - return PagedScreenReaderStrategy.fromEditorSelection(currentState, simpleModel, this._selections[0], this._accessibilityPageSize, this._accessibilitySupport === AccessibilitySupport.Unknown); + return PagedScreenReaderStrategy.fromEditorSelection(simpleModel, this._selections[0], this._accessibilityPageSize, this._accessibilitySupport === AccessibilitySupport.Unknown); }, deduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => { diff --git a/src/vs/editor/browser/controller/textAreaInput.ts b/src/vs/editor/browser/controller/textAreaInput.ts index 1e785855191..224e996b170 100644 --- a/src/vs/editor/browser/controller/textAreaInput.ts +++ b/src/vs/editor/browser/controller/textAreaInput.ts @@ -52,7 +52,7 @@ export interface ClipboardStoredMetadata { export interface ITextAreaInputHost { getDataToCopy(): ClipboardDataToCopy; - getScreenReaderContent(currentState: TextAreaState): TextAreaState; + getScreenReaderContent(): TextAreaState; deduceModelPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position; } @@ -296,7 +296,7 @@ export class TextAreaInput extends Disposable { // For example, if the cursor is in the middle of a word like Mic|osoft // and Microsoft is chosen from the keyboard's suggestions, the e.data will contain "Microsoft". // This is not really usable because it doesn't tell us where the edit began and where it ended. - const newState = TextAreaState.readFromTextArea(this._textArea); + const newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState); const typeInput = TextAreaState.deduceAndroidCompositionInput(this._textAreaState, newState); this._textAreaState = newState; this._onType.fire(typeInput); @@ -304,7 +304,7 @@ export class TextAreaInput extends Disposable { return; } const typeInput = currentComposition.handleCompositionUpdate(e.data); - this._textAreaState = TextAreaState.readFromTextArea(this._textArea); + this._textAreaState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState); this._onType.fire(typeInput); this._onCompositionUpdate.fire(e); })); @@ -326,7 +326,7 @@ export class TextAreaInput extends Disposable { // For example, if the cursor is in the middle of a word like Mic|osoft // and Microsoft is chosen from the keyboard's suggestions, the e.data will contain "Microsoft". // This is not really usable because it doesn't tell us where the edit began and where it ended. - const newState = TextAreaState.readFromTextArea(this._textArea); + const newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState); const typeInput = TextAreaState.deduceAndroidCompositionInput(this._textAreaState, newState); this._textAreaState = newState; this._onType.fire(typeInput); @@ -335,7 +335,7 @@ export class TextAreaInput extends Disposable { } const typeInput = currentComposition.handleCompositionUpdate(e.data); - this._textAreaState = TextAreaState.readFromTextArea(this._textArea); + this._textAreaState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState); this._onType.fire(typeInput); this._onCompositionEnd.fire(); })); @@ -353,7 +353,7 @@ export class TextAreaInput extends Disposable { return; } - const newState = TextAreaState.readFromTextArea(this._textArea); + const newState = TextAreaState.readFromTextArea(this._textArea, this._textAreaState); const typeInput = TextAreaState.deduceInput(this._textAreaState, newState, /*couldBeEmojiInput*/this._OS === OperatingSystem.Macintosh); if (typeInput.replacePrevCharCnt === 0 && typeInput.text.length === 1 && strings.isHighSurrogate(typeInput.text.charCodeAt(0))) { @@ -459,7 +459,7 @@ export class TextAreaInput extends Disposable { _initializeFromTest(): void { this._hasFocus = true; - this._textAreaState = TextAreaState.readFromTextArea(this._textArea); + this._textAreaState = TextAreaState.readFromTextArea(this._textArea, null); } private _installSelectionChangeListener(): IDisposable { @@ -512,7 +512,7 @@ export class TextAreaInput extends Disposable { return; } - if (!this._textAreaState.selectionStartPosition || !this._textAreaState.selectionEndPosition) { + if (!this._textAreaState.selection) { // Cannot correlate a position in the textarea with a position in the editor... return; } @@ -611,7 +611,7 @@ export class TextAreaInput extends Disposable { return; } - this._setAndWriteTextAreaState(reason, this._host.getScreenReaderContent(this._textAreaState)); + this._setAndWriteTextAreaState(reason, this._host.getScreenReaderContent()); } private _ensureClipboardGetsEditorSelection(e: ClipboardEvent): void { diff --git a/src/vs/editor/browser/controller/textAreaState.ts b/src/vs/editor/browser/controller/textAreaState.ts index d80806f7f0b..adbf0ef7b3e 100644 --- a/src/vs/editor/browser/controller/textAreaState.ts +++ b/src/vs/editor/browser/controller/textAreaState.ts @@ -24,6 +24,7 @@ export interface ISimpleModel { getLineMaxColumn(lineNumber: number): number; getValueInRange(range: Range, eol: EndOfLinePreference): string; getValueLengthInRange(range: Range, eol: EndOfLinePreference): number; + modifyPosition(position: Position, offset: number): Position; } export interface ITypeData { @@ -35,32 +36,44 @@ export interface ITypeData { export class TextAreaState { - public static readonly EMPTY = new TextAreaState('', 0, 0, null, null); + public static readonly EMPTY = new TextAreaState('', 0, 0, null, undefined); - public readonly value: string; - public readonly selectionStart: number; - public readonly selectionEnd: number; - public readonly selectionStartPosition: Position | null; - public readonly selectionEndPosition: Position | null; - - constructor(value: string, selectionStart: number, selectionEnd: number, selectionStartPosition: Position | null, selectionEndPosition: Position | null) { - this.value = value; - this.selectionStart = selectionStart; - this.selectionEnd = selectionEnd; - this.selectionStartPosition = selectionStartPosition; - this.selectionEndPosition = selectionEndPosition; - } + constructor( + public readonly value: string, + /** the offset where selection starts inside `value` */ + public readonly selectionStart: number, + /** the offset where selection ends inside `value` */ + public readonly selectionEnd: number, + /** the editor range in the view coordinate system that matches the selection inside `value` */ + public readonly selection: Range | null, + /** the visible line count (wrapped, not necessarily matching \n characters) for the text in `value` before `selectionStart` */ + public readonly newlineCountBeforeSelection: number | undefined, + ) { } public toString(): string { return `[ <${this.value}>, selectionStart: ${this.selectionStart}, selectionEnd: ${this.selectionEnd}]`; } - public static readFromTextArea(textArea: ITextAreaWrapper): TextAreaState { - return new TextAreaState(textArea.getValue(), textArea.getSelectionStart(), textArea.getSelectionEnd(), null, null); + public static readFromTextArea(textArea: ITextAreaWrapper, previousState: TextAreaState | null): TextAreaState { + const value = textArea.getValue(); + const selectionStart = textArea.getSelectionStart(); + const selectionEnd = textArea.getSelectionEnd(); + let newlineCountBeforeSelection: number | undefined = undefined; + if (previousState) { + const valueBeforeSelectionStart = value.substring(0, selectionStart); + const previousValueBeforeSelectionStart = previousState.value.substring(0, previousState.selectionStart); + if (valueBeforeSelectionStart === previousValueBeforeSelectionStart) { + newlineCountBeforeSelection = previousState.newlineCountBeforeSelection; + } + } + return new TextAreaState(value, selectionStart, selectionEnd, null, newlineCountBeforeSelection); } public collapseSelection(): TextAreaState { - return new TextAreaState(this.value, this.value.length, this.value.length, null, null); + if (this.selectionStart === this.value.length) { + return this; + } + return new TextAreaState(this.value, this.value.length, this.value.length, null, undefined); } public writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void { @@ -76,18 +89,18 @@ export class TextAreaState { public deduceEditorPosition(offset: number): [Position | null, number, number] { if (offset <= this.selectionStart) { const str = this.value.substring(offset, this.selectionStart); - return this._finishDeduceEditorPosition(this.selectionStartPosition, str, -1); + return this._finishDeduceEditorPosition(this.selection?.getStartPosition() ?? null, str, -1); } if (offset >= this.selectionEnd) { const str = this.value.substring(this.selectionEnd, offset); - return this._finishDeduceEditorPosition(this.selectionEndPosition, str, 1); + return this._finishDeduceEditorPosition(this.selection?.getEndPosition() ?? null, str, 1); } const str1 = this.value.substring(this.selectionStart, offset); if (str1.indexOf(String.fromCharCode(8230)) === -1) { - return this._finishDeduceEditorPosition(this.selectionStartPosition, str1, 1); + return this._finishDeduceEditorPosition(this.selection?.getStartPosition() ?? null, str1, 1); } const str2 = this.value.substring(offset, this.selectionEnd); - return this._finishDeduceEditorPosition(this.selectionEndPosition, str2, -1); + return this._finishDeduceEditorPosition(this.selection?.getEndPosition() ?? null, str2, -1); } private _finishDeduceEditorPosition(anchor: Position | null, deltaText: string, signum: number): [Position | null, number, number] { @@ -224,7 +237,10 @@ export class PagedScreenReaderStrategy { return new Range(startLineNumber, 1, endLineNumber + 1, 1); } - public static fromEditorSelection(previousState: TextAreaState, model: ISimpleModel, selection: Range, linesPerPage: number, trimLongText: boolean): TextAreaState { + public static fromEditorSelection(model: ISimpleModel, selection: Range, linesPerPage: number, trimLongText: boolean): TextAreaState { + // Chromium handles very poorly text even of a few thousand chars + // Cut text to avoid stalling the entire UI + const LIMIT_CHARS = 500; const selectionStartPage = PagedScreenReaderStrategy._getPageOfLine(selection.startLineNumber, linesPerPage); const selectionStartPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionStartPage, linesPerPage); @@ -232,13 +248,21 @@ export class PagedScreenReaderStrategy { const selectionEndPage = PagedScreenReaderStrategy._getPageOfLine(selection.endLineNumber, linesPerPage); const selectionEndPageRange = PagedScreenReaderStrategy._getRangeForPage(selectionEndPage, linesPerPage); - const pretextRange = selectionStartPageRange.intersectRanges(new Range(1, 1, selection.startLineNumber, selection.startColumn))!; - let pretext = model.getValueInRange(pretextRange, EndOfLinePreference.LF); + let pretextRange = selectionStartPageRange.intersectRanges(new Range(1, 1, selection.startLineNumber, selection.startColumn))!; + if (trimLongText && model.getValueLengthInRange(pretextRange, EndOfLinePreference.LF) > LIMIT_CHARS) { + const pretextStart = model.modifyPosition(pretextRange.getEndPosition(), -LIMIT_CHARS); + pretextRange = Range.fromPositions(pretextStart, pretextRange.getEndPosition()); + } + const pretext = model.getValueInRange(pretextRange, EndOfLinePreference.LF); const lastLine = model.getLineCount(); const lastLineMaxColumn = model.getLineMaxColumn(lastLine); - const posttextRange = selectionEndPageRange.intersectRanges(new Range(selection.endLineNumber, selection.endColumn, lastLine, lastLineMaxColumn))!; - let posttext = model.getValueInRange(posttextRange, EndOfLinePreference.LF); + let posttextRange = selectionEndPageRange.intersectRanges(new Range(selection.endLineNumber, selection.endColumn, lastLine, lastLineMaxColumn))!; + if (trimLongText && model.getValueLengthInRange(posttextRange, EndOfLinePreference.LF) > LIMIT_CHARS) { + const posttextEnd = model.modifyPosition(posttextRange.getStartPosition(), LIMIT_CHARS); + posttextRange = Range.fromPositions(posttextRange.getStartPosition(), posttextEnd); + } + const posttext = model.getValueInRange(posttextRange, EndOfLinePreference.LF); let text: string; @@ -254,22 +278,10 @@ export class PagedScreenReaderStrategy { + model.getValueInRange(selectionRange2, EndOfLinePreference.LF) ); } - - // Chromium handles very poorly text even of a few thousand chars - // Cut text to avoid stalling the entire UI - if (trimLongText) { - const LIMIT_CHARS = 500; - if (pretext.length > LIMIT_CHARS) { - pretext = pretext.substring(pretext.length - LIMIT_CHARS, pretext.length); - } - if (posttext.length > LIMIT_CHARS) { - posttext = posttext.substring(0, LIMIT_CHARS); - } - if (text.length > 2 * LIMIT_CHARS) { - text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length); - } + if (trimLongText && text.length > 2 * LIMIT_CHARS) { + text = text.substring(0, LIMIT_CHARS) + String.fromCharCode(8230) + text.substring(text.length - LIMIT_CHARS, text.length); } - return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, new Position(selection.startLineNumber, selection.startColumn), new Position(selection.endLineNumber, selection.endColumn)); + return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, selection, pretextRange.endLineNumber - pretextRange.startLineNumber); } } diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index 991d3297daf..bd6d1791926 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -267,6 +267,9 @@ export class Range { * Test if range `a` equals `b`. */ public static equalsRange(a: IRange | null, b: IRange | null): boolean { + if (!a && !b) { + return true; + } return ( !!a && !!b && diff --git a/src/vs/editor/common/viewModel.ts b/src/vs/editor/common/viewModel.ts index 59c87065fc5..54a72e81f5e 100644 --- a/src/vs/editor/common/viewModel.ts +++ b/src/vs/editor/common/viewModel.ts @@ -63,6 +63,7 @@ export interface IViewModel extends ICursorSimpleModel { getAllOverviewRulerDecorations(theme: EditorTheme): OverviewRulerDecorationsGroup[]; getValueInRange(range: Range, eol: EndOfLinePreference): string; getValueLengthInRange(range: Range, eol: EndOfLinePreference): number; + modifyPosition(position: Position, offset: number): Position; getInjectedTextAt(viewPosition: Position): InjectedText | null; diff --git a/src/vs/editor/common/viewModel/viewModelImpl.ts b/src/vs/editor/common/viewModel/viewModelImpl.ts index 139df2374ad..0ced6aff547 100644 --- a/src/vs/editor/common/viewModel/viewModelImpl.ts +++ b/src/vs/editor/common/viewModel/viewModelImpl.ts @@ -788,6 +788,11 @@ export class ViewModel extends Disposable implements IViewModel { return this.model.getValueLengthInRange(modelRange, eol); } + public modifyPosition(position: Position, offset: number): Position { + const modelPosition = this.coordinatesConverter.convertViewPositionToModelPosition(position); + return this.model.modifyPosition(modelPosition, offset); + } + public deduceModelPositionRelativeToViewPosition(viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position { const modelAnchor = this.coordinatesConverter.convertViewPositionToModelPosition(viewAnchorPosition); if (this.model.getEOL().length === 2) { diff --git a/src/vs/editor/test/browser/controller/imeTester.ts b/src/vs/editor/test/browser/controller/imeTester.ts index c0269a7aeb5..bf85dd9c5bf 100644 --- a/src/vs/editor/test/browser/controller/imeTester.ts +++ b/src/vs/editor/test/browser/controller/imeTester.ts @@ -38,6 +38,11 @@ class SingleLineTestModel implements ISimpleModel { return this.getValueInRange(range, eol).length; } + modifyPosition(position: Position, offset: number): Position { + const column = Math.min(this.getLineMaxColumn(position.lineNumber), Math.max(1, position.column + offset)); + return new Position(position.lineNumber, column); + } + getModelLineContent(lineNumber: number): string { return this._line; } @@ -106,10 +111,10 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string mode: null }; }, - getScreenReaderContent: (currentState: TextAreaState): TextAreaState => { + getScreenReaderContent: (): TextAreaState => { const selection = new Range(1, 1 + cursorOffset, 1, 1 + cursorOffset + cursorLength); - return PagedScreenReaderStrategy.fromEditorSelection(currentState, model, selection, 10, true); + return PagedScreenReaderStrategy.fromEditorSelection(model, selection, 10, true); }, deduceModelPosition: (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position => { return null!; diff --git a/src/vs/editor/test/browser/controller/textAreaInput.test.ts b/src/vs/editor/test/browser/controller/textAreaInput.test.ts index c342e397662..36b10ab4e7a 100644 --- a/src/vs/editor/test/browser/controller/textAreaInput.test.ts +++ b/src/vs/editor/test/browser/controller/textAreaInput.test.ts @@ -46,8 +46,8 @@ suite('TextAreaInput', () => { getDataToCopy: function (): ClipboardDataToCopy { throw new Error('Function not implemented.'); }, - getScreenReaderContent: function (currentState: TextAreaState): TextAreaState { - return new TextAreaState('', 0, 0, null, null); + getScreenReaderContent: function (): TextAreaState { + return new TextAreaState('', 0, 0, null, undefined); }, deduceModelPosition: function (viewAnchorPosition: Position, deltaOffset: number, lineFeedCnt: number): Position { throw new Error('Function not implemented.'); diff --git a/src/vs/editor/test/browser/controller/textAreaState.test.ts b/src/vs/editor/test/browser/controller/textAreaState.test.ts index 36f5eaf45c8..56d3a35f53e 100644 --- a/src/vs/editor/test/browser/controller/textAreaState.test.ts +++ b/src/vs/editor/test/browser/controller/textAreaState.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { Disposable } from 'vs/base/common/lifecycle'; import { ITextAreaWrapper, PagedScreenReaderStrategy, TextAreaState } from 'vs/editor/browser/controller/textAreaState'; -import { Position } from 'vs/editor/common/core/position'; +import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { createTextModel } from 'vs/editor/test/common/testTextModel'; @@ -64,15 +64,15 @@ function equalsTextAreaState(a: TextAreaState, b: TextAreaState): boolean { a.value === b.value && a.selectionStart === b.selectionStart && a.selectionEnd === b.selectionEnd - && Position.equals(a.selectionStartPosition, b.selectionStartPosition) - && Position.equals(a.selectionEndPosition, b.selectionEndPosition) + && Range.equalsRange(a.selection, b.selection) + && a.newlineCountBeforeSelection === b.newlineCountBeforeSelection ); } suite('TextAreaState', () => { function assertTextAreaState(actual: TextAreaState, value: string, selectionStart: number, selectionEnd: number): void { - const desired = new TextAreaState(value, selectionStart, selectionEnd, null, null); + const desired = new TextAreaState(value, selectionStart, selectionEnd, null, undefined); assert.ok(equalsTextAreaState(desired, actual), desired.toString() + ' == ' + actual.toString()); } @@ -81,7 +81,7 @@ suite('TextAreaState', () => { textArea._value = 'Hello world!'; textArea._selectionStart = 1; textArea._selectionEnd = 12; - let actual = TextAreaState.readFromTextArea(textArea); + let actual = TextAreaState.readFromTextArea(textArea, null); assertTextAreaState(actual, 'Hello world!', 1, 12); assert.strictEqual(actual.value, 'Hello world!'); @@ -99,21 +99,21 @@ suite('TextAreaState', () => { textArea._selectionStart = 1; textArea._selectionEnd = 12; - let state = new TextAreaState('Hi world!', 2, 2, null, null); + let state = new TextAreaState('Hi world!', 2, 2, null, undefined); state.writeToTextArea('test', textArea, false); assert.strictEqual(textArea._value, 'Hi world!'); assert.strictEqual(textArea._selectionStart, 9); assert.strictEqual(textArea._selectionEnd, 9); - state = new TextAreaState('Hi world!', 3, 3, null, null); + state = new TextAreaState('Hi world!', 3, 3, null, undefined); state.writeToTextArea('test', textArea, false); assert.strictEqual(textArea._value, 'Hi world!'); assert.strictEqual(textArea._selectionStart, 9); assert.strictEqual(textArea._selectionEnd, 9); - state = new TextAreaState('Hi world!', 0, 2, null, null); + state = new TextAreaState('Hi world!', 0, 2, null, undefined); state.writeToTextArea('test', textArea, true); assert.strictEqual(textArea._value, 'Hi world!'); @@ -131,7 +131,7 @@ suite('TextAreaState', () => { textArea._selectionStart = selectionStart; textArea._selectionEnd = selectionEnd; - const newState = TextAreaState.readFromTextArea(textArea); + const newState = TextAreaState.readFromTextArea(textArea, null); const actual = TextAreaState.deduceInput(prevState, newState, couldBeEmojiInput); assert.deepStrictEqual(actual, { @@ -155,7 +155,7 @@ suite('TextAreaState', () => { test('issue #2586: Replacing selected end-of-line with newline locks up the document', () => { testDeduceInput( - new TextAreaState(']\n', 1, 2, null, null), + new TextAreaState(']\n', 1, 2, null, undefined), ']\n', 2, 2, true, '\n', 0 @@ -191,7 +191,7 @@ suite('TextAreaState', () => { test('extractNewText - had the entire line selected', () => { testDeduceInput( - new TextAreaState('Hello world!', 0, 12, null, null), + new TextAreaState('Hello world!', 0, 12, null, undefined), 'H', 1, 1, true, 'H', 0 @@ -200,7 +200,7 @@ suite('TextAreaState', () => { test('extractNewText - had previous text 1', () => { testDeduceInput( - new TextAreaState('Hello world!', 12, 12, null, null), + new TextAreaState('Hello world!', 12, 12, null, undefined), 'Hello world!a', 13, 13, true, 'a', 0 @@ -209,7 +209,7 @@ suite('TextAreaState', () => { test('extractNewText - had previous text 2', () => { testDeduceInput( - new TextAreaState('Hello world!', 0, 0, null, null), + new TextAreaState('Hello world!', 0, 0, null, undefined), 'aHello world!', 1, 1, true, 'a', 0 @@ -218,7 +218,7 @@ suite('TextAreaState', () => { test('extractNewText - had previous text 3', () => { testDeduceInput( - new TextAreaState('Hello world!', 6, 11, null, null), + new TextAreaState('Hello world!', 6, 11, null, undefined), 'Hello other!', 11, 11, true, 'other', 0 @@ -236,7 +236,7 @@ suite('TextAreaState', () => { test('extractNewText - isInOverwriteMode', () => { testDeduceInput( - new TextAreaState('Hello world!', 0, 0, null, null), + new TextAreaState('Hello world!', 0, 0, null, undefined), 'Aello world!', 1, 1, true, 'A', 0 @@ -245,7 +245,7 @@ suite('TextAreaState', () => { test('extractMacReplacedText - does nothing if there is selection', () => { testDeduceInput( - new TextAreaState('Hello world!', 5, 5, null, null), + new TextAreaState('Hello world!', 5, 5, null, undefined), 'Hellö world!', 4, 5, true, 'ö', 0 @@ -254,7 +254,7 @@ suite('TextAreaState', () => { test('extractMacReplacedText - does nothing if there is more than one extra char', () => { testDeduceInput( - new TextAreaState('Hello world!', 5, 5, null, null), + new TextAreaState('Hello world!', 5, 5, null, undefined), 'Hellöö world!', 5, 5, true, 'öö', 1 @@ -263,7 +263,7 @@ suite('TextAreaState', () => { test('extractMacReplacedText - does nothing if there is more than one changed char', () => { testDeduceInput( - new TextAreaState('Hello world!', 5, 5, null, null), + new TextAreaState('Hello world!', 5, 5, null, undefined), 'Helöö world!', 5, 5, true, 'öö', 2 @@ -272,7 +272,7 @@ suite('TextAreaState', () => { test('extractMacReplacedText', () => { testDeduceInput( - new TextAreaState('Hello world!', 5, 5, null, null), + new TextAreaState('Hello world!', 5, 5, null, undefined), 'Hellö world!', 5, 5, true, 'ö', 1 @@ -281,7 +281,7 @@ suite('TextAreaState', () => { test('issue #25101 - First key press ignored', () => { testDeduceInput( - new TextAreaState('a', 0, 1, null, null), + new TextAreaState('a', 0, 1, null, undefined), 'a', 1, 1, true, 'a', 0 @@ -290,7 +290,7 @@ suite('TextAreaState', () => { test('issue #16520 - Cmd-d of single character followed by typing same character as has no effect', () => { testDeduceInput( - new TextAreaState('x x', 0, 1, null, null), + new TextAreaState('x x', 0, 1, null, undefined), 'x x', 1, 1, true, 'x', 0 @@ -308,7 +308,7 @@ suite('TextAreaState', () => { textArea._selectionStart = selectionStart; textArea._selectionEnd = selectionEnd; - const newState = TextAreaState.readFromTextArea(textArea); + const newState = TextAreaState.readFromTextArea(textArea, null); const actual = TextAreaState.deduceAndroidCompositionInput(prevState, newState); assert.deepStrictEqual(actual, { @@ -323,11 +323,7 @@ suite('TextAreaState', () => { test('Android composition input 1', () => { testDeduceAndroidCompositionInput( - new TextAreaState( - 'Microsoft', - 4, 4, - null, null - ), + new TextAreaState('Microsoft', 4, 4, null, undefined), 'Microsoft', 4, 4, '', 0, 0, 0, @@ -336,11 +332,7 @@ suite('TextAreaState', () => { test('Android composition input 2', () => { testDeduceAndroidCompositionInput( - new TextAreaState( - 'Microsoft', - 4, 4, - null, null - ), + new TextAreaState('Microsoft', 4, 4, null, undefined), 'Microsoft', 0, 9, '', 0, 0, 5, @@ -349,11 +341,7 @@ suite('TextAreaState', () => { test('Android composition input 3', () => { testDeduceAndroidCompositionInput( - new TextAreaState( - 'Microsoft', - 0, 9, - null, null - ), + new TextAreaState('Microsoft', 0, 9, null, undefined), 'Microsoft\'s', 11, 11, '\'s', 0, 0, 0, @@ -362,11 +350,7 @@ suite('TextAreaState', () => { test('Android backspace', () => { testDeduceAndroidCompositionInput( - new TextAreaState( - 'undefinedVariable', - 2, 2, - null, null - ), + new TextAreaState('undefinedVariable', 2, 2, null, undefined), 'udefinedVariable', 1, 1, '', 1, 0, 0, @@ -377,7 +361,7 @@ suite('TextAreaState', () => { function testPagedScreenReaderStrategy(lines: string[], selection: Selection, expected: TextAreaState): void { const model = createTextModel(lines.join('\n')); - const actual = PagedScreenReaderStrategy.fromEditorSelection(TextAreaState.EMPTY, model, selection, 10, true); + const actual = PagedScreenReaderStrategy.fromEditorSelection(model, selection, 10, true); assert.ok(equalsTextAreaState(actual, expected)); model.dispose(); } @@ -388,7 +372,7 @@ suite('TextAreaState', () => { 'Hello world!' ], new Selection(1, 13, 1, 13), - new TextAreaState('Hello world!', 12, 12, new Position(1, 13), new Position(1, 13)) + new TextAreaState('Hello world!', 12, 12, new Range(1, 13, 1, 13), 0) ); testPagedScreenReaderStrategy( @@ -396,7 +380,7 @@ suite('TextAreaState', () => { 'Hello world!' ], new Selection(1, 1, 1, 1), - new TextAreaState('Hello world!', 0, 0, new Position(1, 1), new Position(1, 1)) + new TextAreaState('Hello world!', 0, 0, new Range(1, 1, 1, 1), 0) ); testPagedScreenReaderStrategy( @@ -404,7 +388,7 @@ suite('TextAreaState', () => { 'Hello world!' ], new Selection(1, 1, 1, 6), - new TextAreaState('Hello world!', 0, 5, new Position(1, 1), new Position(1, 6)) + new TextAreaState('Hello world!', 0, 5, new Range(1, 1, 1, 6), 0) ); }); @@ -415,7 +399,7 @@ suite('TextAreaState', () => { 'How are you?' ], new Selection(1, 1, 1, 1), - new TextAreaState('Hello world!\nHow are you?', 0, 0, new Position(1, 1), new Position(1, 1)) + new TextAreaState('Hello world!\nHow are you?', 0, 0, new Range(1, 1, 1, 1), 0) ); testPagedScreenReaderStrategy( @@ -424,7 +408,7 @@ suite('TextAreaState', () => { 'How are you?' ], new Selection(2, 1, 2, 1), - new TextAreaState('Hello world!\nHow are you?', 13, 13, new Position(2, 1), new Position(2, 1)) + new TextAreaState('Hello world!\nHow are you?', 13, 13, new Range(2, 1, 2, 1), 1) ); }); @@ -434,7 +418,7 @@ suite('TextAreaState', () => { 'L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\nL11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\nL21' ], new Selection(1, 1, 1, 1), - new TextAreaState('L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\n', 0, 0, new Position(1, 1), new Position(1, 1)) + new TextAreaState('L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\n', 0, 0, new Range(1, 1, 1, 1), 0) ); testPagedScreenReaderStrategy( @@ -442,7 +426,7 @@ suite('TextAreaState', () => { 'L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\nL11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\nL21' ], new Selection(11, 1, 11, 1), - new TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 0, 0, new Position(11, 1), new Position(11, 1)) + new TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 0, 0, new Range(11, 1, 11, 1), 0) ); testPagedScreenReaderStrategy( @@ -450,7 +434,7 @@ suite('TextAreaState', () => { 'L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\nL11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\nL21' ], new Selection(12, 1, 12, 1), - new TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 4, 4, new Position(12, 1), new Position(12, 1)) + new TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 4, 4, new Range(12, 1, 12, 1), 1) ); testPagedScreenReaderStrategy( @@ -458,7 +442,7 @@ suite('TextAreaState', () => { 'L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\nL11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\nL21' ], new Selection(21, 1, 21, 1), - new TextAreaState('L21', 0, 0, new Position(21, 1), new Position(21, 1)) + new TextAreaState('L21', 0, 0, new Range(21, 1, 21, 1), 0) ); });