提交 1e8673b0 编写于 作者: A Alex Dima

Towards deducing desired editor selection from a selectionchange event (#27216)

上级 c87d853a
......@@ -37,6 +37,7 @@ export interface ITextAreaInputHost {
getPlainTextToCopy(): string;
getHTMLToCopy(): string;
getScreenReaderContent(currentState: TextAreaState): TextAreaState;
// deduceEditorPosition(anchor: Position, delta: number, lineFeedCnt: number): Position;
}
/**
......@@ -344,10 +345,34 @@ export class TextAreaInput extends Disposable {
return;
}
// TODO: React here to the new text area selection
if (!this._textAreaState.selectionStartPosition || !this._textAreaState.selectionEndPosition) {
// Cannot correlate a position in the textarea with a position in the editor...
return;
}
const newValue = this._textArea.getValue();
if (this._textAreaState.value !== newValue) {
// Cannot correlate a position in the textarea with a position in the editor...
return;
}
const newSelectionStart = this._textArea.getSelectionStart();
const newSelectionEnd = this._textArea.getSelectionEnd();
if (this._textAreaState.selectionStart === newSelectionStart && this._textAreaState.selectionEnd === newSelectionEnd) {
// Nothing to do...
return;
}
// const newSelectionStartPosition = this._textAreaState.deduceEditorPosition(newSelectionStart);
// const newSelectionEndPosition = this._textAreaState.deduceEditorPosition(newSelectionEnd);
// // TODO: React here to the new text area selection
// console.warn('!!!!!!!' + Date.now() + ':: RECEIVED selectionchange');
// console.log(this._textArea.getSelectionStart(), this._textArea.getSelectionEnd());
// console.log(this._textAreaState.selectionStart, this._textAreaState.selectionEnd);
// console.log(this._textAreaState.selectionStartPosition, this._textAreaState.selectionEndPosition);
// console.log(newSelectionStartPosition);
// console.log(newSelectionEndPosition);
}));
}
......
......@@ -5,6 +5,7 @@
'use strict';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
import * as strings from 'vs/base/common/strings';
......@@ -30,16 +31,20 @@ export interface ITypeData {
export class TextAreaState {
public static EMPTY = new TextAreaState('', 0, 0);
public static EMPTY = new TextAreaState('', 0, 0, null, null);
public readonly value: string;
public readonly selectionStart: number;
public readonly selectionEnd: number;
public readonly selectionStartPosition: Position;
public readonly selectionEndPosition: Position;
constructor(value: string, selectionStart: number, selectionEnd: number) {
constructor(value: string, selectionStart: number, selectionEnd: number, selectionStartPosition: Position, selectionEndPosition: Position) {
this.value = value;
this.selectionStart = selectionStart;
this.selectionEnd = selectionEnd;
this.selectionStartPosition = selectionStartPosition;
this.selectionEndPosition = selectionEndPosition;
}
public equals(other: TextAreaState): boolean {
......@@ -48,6 +53,8 @@ export class TextAreaState {
this.value === other.value
&& this.selectionStart === other.selectionStart
&& this.selectionEnd === other.selectionEnd
&& Position.equals(this.selectionStartPosition, other.selectionStartPosition)
&& Position.equals(this.selectionEndPosition, other.selectionEndPosition)
);
}
return false;
......@@ -58,11 +65,11 @@ export class TextAreaState {
}
public readFromTextArea(textArea: ITextAreaWrapper): TextAreaState {
return new TextAreaState(textArea.getValue(), textArea.getSelectionStart(), textArea.getSelectionEnd());
return new TextAreaState(textArea.getValue(), textArea.getSelectionStart(), textArea.getSelectionEnd(), null, null);
}
public collapseSelection(): TextAreaState {
return new TextAreaState(this.value, this.value.length, this.value.length);
return new TextAreaState(this.value, this.value.length, this.value.length, null, null);
}
public writeToTextArea(reason: string, textArea: ITextAreaWrapper, select: boolean): void {
......@@ -73,8 +80,34 @@ export class TextAreaState {
}
}
public deduceEditorPosition(offset: number): [Position, number, number] {
if (offset <= this.selectionStart) {
const str = this.value.substring(offset, this.selectionStart);
return this._finishDeduceEditorPosition(this.selectionStartPosition, str, -1);
}
if (offset >= this.selectionEnd) {
const str = this.value.substring(this.selectionEnd, offset);
return this._finishDeduceEditorPosition(this.selectionEndPosition, str, 1);
}
const str1 = this.value.substring(this.selectionStart, offset);
if (str1.indexOf(String.fromCharCode(8230)) === -1) {
return this._finishDeduceEditorPosition(this.selectionStartPosition, str1, 1);
}
const str2 = this.value.substring(offset, this.selectionEnd);
return this._finishDeduceEditorPosition(this.selectionEndPosition, str2, -1);
}
private _finishDeduceEditorPosition(anchor: Position, deltaText: string, signum: number): [Position, number, number] {
let lineFeedCnt = 0;
let lastLineFeedIndex = -1;
while ((lastLineFeedIndex = deltaText.indexOf('\n', lastLineFeedIndex + 1)) !== -1) {
lineFeedCnt++;
}
return [anchor, signum * deltaText.length, lineFeedCnt];
}
public static selectedText(text: string): TextAreaState {
return new TextAreaState(text, 0, text.length);
return new TextAreaState(text, 0, text.length, null, null);
}
public static deduceInput(previousState: TextAreaState, currentState: TextAreaState, couldBeEmojiInput: boolean): ITypeData {
......@@ -251,6 +284,6 @@ export class PagedScreenReaderStrategy {
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);
return new TextAreaState(pretext + text + posttext, pretext.length, pretext.length + text.length, new Position(selection.startLineNumber, selection.startColumn), new Position(selection.endLineNumber, selection.endColumn));
}
}
......@@ -7,6 +7,7 @@
import * as assert from 'assert';
import { ISimpleModel, TextAreaState, ITextAreaWrapper, PagedScreenReaderStrategy } from 'vs/editor/browser/controller/textAreaState';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { EndOfLinePreference } from 'vs/editor/common/editorCommon';
import { Disposable } from 'vs/base/common/lifecycle';
import { Model } from 'vs/editor/common/model/model';
......@@ -64,7 +65,7 @@ export class MockTextAreaWrapper extends Disposable implements ITextAreaWrapper
suite('TextAreaState', () => {
function assertTextAreaState(actual: TextAreaState, value: string, selectionStart: number, selectionEnd: number): void {
let desired = new TextAreaState(value, selectionStart, selectionEnd);
let desired = new TextAreaState(value, selectionStart, selectionEnd, null, null);
assert.ok(desired.equals(actual), desired.toString() + ' == ' + actual.toString());
}
......@@ -91,21 +92,21 @@ suite('TextAreaState', () => {
textArea._selectionStart = 1;
textArea._selectionEnd = 12;
let state = new TextAreaState('Hi world!', 2, 2);
let state = new TextAreaState('Hi world!', 2, 2, null, null);
state.writeToTextArea('test', textArea, false);
assert.equal(textArea._value, 'Hi world!');
assert.equal(textArea._selectionStart, 9);
assert.equal(textArea._selectionEnd, 9);
state = new TextAreaState('Hi world!', 3, 3);
state = new TextAreaState('Hi world!', 3, 3, null, null);
state.writeToTextArea('test', textArea, false);
assert.equal(textArea._value, 'Hi world!');
assert.equal(textArea._selectionStart, 9);
assert.equal(textArea._selectionEnd, 9);
state = new TextAreaState('Hi world!', 0, 2);
state = new TextAreaState('Hi world!', 0, 2, null, null);
state.writeToTextArea('test', textArea, true);
assert.equal(textArea._value, 'Hi world!');
......@@ -153,7 +154,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <s>, selectionStart: 0, selectionEnd: 1, selectionToken: 0]
// CURRENT STATE: [ <せ>, selectionStart: 0, selectionEnd: 1, selectionToken: 0]
testDeduceInput(
new TextAreaState('', 0, 1),
new TextAreaState('', 0, 1, null, null),
'',
0, 1,
'', 1
......@@ -163,7 +164,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せ>, selectionStart: 0, selectionEnd: 1, selectionToken: 0]
// CURRENT STATE: [ <せn>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
testDeduceInput(
new TextAreaState('', 0, 1),
new TextAreaState('', 0, 1, null, null),
'せn',
0, 2,
'せn', 1
......@@ -173,7 +174,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せn>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
// CURRENT STATE: [ <せん>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
testDeduceInput(
new TextAreaState('せn', 0, 2),
new TextAreaState('せn', 0, 2, null, null),
'せん',
0, 2,
'せん', 2
......@@ -183,7 +184,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せん>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
// CURRENT STATE: [ <せんs>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
testDeduceInput(
new TextAreaState('せん', 0, 2),
new TextAreaState('せん', 0, 2, null, null),
'せんs',
0, 3,
'せんs', 2
......@@ -193,7 +194,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せんs>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
// CURRENT STATE: [ <せんせ>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんs', 0, 3),
new TextAreaState('せんs', 0, 3, null, null),
'せんせ',
0, 3,
'せんせ', 3
......@@ -203,7 +204,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せんせ>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
// CURRENT STATE: [ <せんせ>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんせ', 0, 3),
new TextAreaState('せんせ', 0, 3, null, null),
'せんせ',
0, 3,
'せんせ', 3
......@@ -213,7 +214,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せんせ>, selectionStart: 0, selectionEnd: 3, selectionToken: 0]
// CURRENT STATE: [ <せんせい>, selectionStart: 0, selectionEnd: 4, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんせ', 0, 3),
new TextAreaState('せんせ', 0, 3, null, null),
'せんせい',
0, 4,
'せんせい', 3
......@@ -223,7 +224,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せんせい>, selectionStart: 0, selectionEnd: 4, selectionToken: 0]
// CURRENT STATE: [ <せんせい>, selectionStart: 4, selectionEnd: 4, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんせい', 0, 4),
new TextAreaState('せんせい', 0, 4, null, null),
'せんせい',
4, 4,
'', 0
......@@ -242,7 +243,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <せんせい>, selectionStart: 0, selectionEnd: 4, selectionToken: 0]
// CURRENT STATE: [ <せんせい>, selectionStart: 0, selectionEnd: 4, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんせい', 0, 4),
new TextAreaState('せんせい', 0, 4, null, null),
'せんせい',
0, 4,
'せんせい', 4
......@@ -252,7 +253,7 @@ suite('TextAreaState', () => {
// CURRENT STATE: [ <先生>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
// PREVIOUS STATE: [ <せんせい>, selectionStart: 0, selectionEnd: 4, selectionToken: 0]
testDeduceInput(
new TextAreaState('せんせい', 0, 4),
new TextAreaState('せんせい', 0, 4, null, null),
'先生',
0, 2,
'先生', 4
......@@ -262,7 +263,7 @@ suite('TextAreaState', () => {
// PREVIOUS STATE: [ <先生>, selectionStart: 0, selectionEnd: 2, selectionToken: 0]
// CURRENT STATE: [ <先生>, selectionStart: 2, selectionEnd: 2, selectionToken: 0]
testDeduceInput(
new TextAreaState('先生', 0, 2),
new TextAreaState('先生', 0, 2, null, null),
'先生',
2, 2,
'', 0
......@@ -280,7 +281,7 @@ suite('TextAreaState', () => {
test('issue #2586: Replacing selected end-of-line with newline locks up the document', () => {
testDeduceInput(
new TextAreaState(']\n', 1, 2),
new TextAreaState(']\n', 1, 2, null, null),
']\n',
2, 2,
'\n', 0
......@@ -316,7 +317,7 @@ suite('TextAreaState', () => {
test('extractNewText - had the entire line selected', () => {
testDeduceInput(
new TextAreaState('Hello world!', 0, 12),
new TextAreaState('Hello world!', 0, 12, null, null),
'H',
1, 1,
'H', 0
......@@ -325,7 +326,7 @@ suite('TextAreaState', () => {
test('extractNewText - had previous text 1', () => {
testDeduceInput(
new TextAreaState('Hello world!', 12, 12),
new TextAreaState('Hello world!', 12, 12, null, null),
'Hello world!a',
13, 13,
'a', 0
......@@ -334,7 +335,7 @@ suite('TextAreaState', () => {
test('extractNewText - had previous text 2', () => {
testDeduceInput(
new TextAreaState('Hello world!', 0, 0),
new TextAreaState('Hello world!', 0, 0, null, null),
'aHello world!',
1, 1,
'a', 0
......@@ -343,7 +344,7 @@ suite('TextAreaState', () => {
test('extractNewText - had previous text 3', () => {
testDeduceInput(
new TextAreaState('Hello world!', 6, 11),
new TextAreaState('Hello world!', 6, 11, null, null),
'Hello other!',
11, 11,
'other', 0
......@@ -361,7 +362,7 @@ suite('TextAreaState', () => {
test('extractNewText - isInOverwriteMode', () => {
testDeduceInput(
new TextAreaState('Hello world!', 0, 0),
new TextAreaState('Hello world!', 0, 0, null, null),
'Aello world!',
1, 1,
'A', 0
......@@ -370,7 +371,7 @@ suite('TextAreaState', () => {
test('extractMacReplacedText - does nothing if there is selection', () => {
testDeduceInput(
new TextAreaState('Hello world!', 5, 5),
new TextAreaState('Hello world!', 5, 5, null, null),
'Hellö world!',
4, 5,
'ö', 0
......@@ -379,7 +380,7 @@ suite('TextAreaState', () => {
test('extractMacReplacedText - does nothing if there is more than one extra char', () => {
testDeduceInput(
new TextAreaState('Hello world!', 5, 5),
new TextAreaState('Hello world!', 5, 5, null, null),
'Hellöö world!',
5, 5,
'öö', 1
......@@ -388,7 +389,7 @@ suite('TextAreaState', () => {
test('extractMacReplacedText - does nothing if there is more than one changed char', () => {
testDeduceInput(
new TextAreaState('Hello world!', 5, 5),
new TextAreaState('Hello world!', 5, 5, null, null),
'Helöö world!',
5, 5,
'öö', 2
......@@ -397,7 +398,7 @@ suite('TextAreaState', () => {
test('extractMacReplacedText', () => {
testDeduceInput(
new TextAreaState('Hello world!', 5, 5),
new TextAreaState('Hello world!', 5, 5, null, null),
'Hellö world!',
5, 5,
'ö', 1
......@@ -406,7 +407,7 @@ suite('TextAreaState', () => {
test('issue #25101 - First key press ignored', () => {
testDeduceInput(
new TextAreaState('a', 0, 1),
new TextAreaState('a', 0, 1, null, null),
'a',
1, 1,
'a', 0
......@@ -415,7 +416,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),
new TextAreaState('x x', 0, 1, null, null),
'x x',
1, 1,
'x', 0
......@@ -435,7 +436,8 @@ suite('TextAreaState', () => {
'some6 text',
'some7 text'
].join('\n'),
42, 42
42, 42,
null, null
),
[
'so📅me1 text',
......@@ -456,7 +458,8 @@ suite('TextAreaState', () => {
testDeduceInput(
new TextAreaState(
'some1 text',
6, 6
6, 6,
null, null
),
'some💊1 text',
6, 6,
......@@ -469,7 +472,8 @@ suite('TextAreaState', () => {
testDeduceInput(
new TextAreaState(
'qwertyu\nasdfghj\nzxcvbnm',
12, 12
12, 12,
null, null
),
'qwertyu\nasdfghj\nzxcvbnm🎈',
25, 25,
......@@ -483,7 +487,8 @@ suite('TextAreaState', () => {
testDeduceInput(
new TextAreaState(
'some1 text',
6, 6
6, 6,
null, null
),
'some⌨️1 text',
6, 6,
......@@ -506,7 +511,7 @@ suite('TextAreaState', () => {
'Hello world!'
],
new Selection(1, 13, 1, 13),
new TextAreaState('Hello world!', 12, 12)
new TextAreaState('Hello world!', 12, 12, new Position(1, 13), new Position(1, 13))
);
testPagedScreenReaderStrategy(
......@@ -514,7 +519,7 @@ suite('TextAreaState', () => {
'Hello world!'
],
new Selection(1, 1, 1, 1),
new TextAreaState('Hello world!', 0, 0)
new TextAreaState('Hello world!', 0, 0, new Position(1, 1), new Position(1, 1))
);
testPagedScreenReaderStrategy(
......@@ -522,7 +527,7 @@ suite('TextAreaState', () => {
'Hello world!'
],
new Selection(1, 1, 1, 6),
new TextAreaState('Hello world!', 0, 5)
new TextAreaState('Hello world!', 0, 5, new Position(1, 1), new Position(1, 6))
);
});
......@@ -533,7 +538,7 @@ suite('TextAreaState', () => {
'How are you?'
],
new Selection(1, 1, 1, 1),
new TextAreaState('Hello world!\nHow are you?', 0, 0)
new TextAreaState('Hello world!\nHow are you?', 0, 0, new Position(1, 1), new Position(1, 1))
);
testPagedScreenReaderStrategy(
......@@ -542,7 +547,7 @@ suite('TextAreaState', () => {
'How are you?'
],
new Selection(2, 1, 2, 1),
new TextAreaState('Hello world!\nHow are you?', 13, 13)
new TextAreaState('Hello world!\nHow are you?', 13, 13, new Position(2, 1), new Position(2, 1))
);
});
......@@ -552,7 +557,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 TextAreaState('L1\nL2\nL3\nL4\nL5\nL6\nL7\nL8\nL9\nL10\n', 0, 0, new Position(1, 1), new Position(1, 1))
);
testPagedScreenReaderStrategy(
......@@ -560,7 +565,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 TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 0, 0, new Position(11, 1), new Position(11, 1))
);
testPagedScreenReaderStrategy(
......@@ -568,7 +573,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 TextAreaState('L11\nL12\nL13\nL14\nL15\nL16\nL17\nL18\nL19\nL20\n', 4, 4, new Position(12, 1), new Position(12, 1))
);
testPagedScreenReaderStrategy(
......@@ -576,7 +581,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 TextAreaState('L21', 0, 0, new Position(21, 1), new Position(21, 1))
);
});
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册