Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce cursor word accessibilty commands #79712

Merged
merged 5 commits into from Aug 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 30 additions & 2 deletions src/vs/editor/common/controller/cursorWordOperations.ts
Expand Up @@ -39,7 +39,8 @@ const enum WordType {
export const enum WordNavigationType {
WordStart = 0,
WordStartFast = 1,
WordEnd = 2
WordEnd = 2,
WordAccessibility = 3 // Respect chrome defintion of a word
}

export class WordOperations {
Expand Down Expand Up @@ -202,6 +203,18 @@ export class WordOperations {
return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
}

if (wordNavigationType === WordNavigationType.WordAccessibility) {
while (
prevWordOnLine
&& prevWordOnLine.wordType === WordType.Separator
) {
// Skip over words made up of only separators
prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));
}

return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
}

// We are stopping at the ending of words

if (prevWordOnLine && column <= prevWordOnLine.end + 1) {
Expand Down Expand Up @@ -270,6 +283,21 @@ export class WordOperations {
nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));
}
}
if (nextWordOnLine) {
column = nextWordOnLine.end + 1;
} else {
column = model.getLineMaxColumn(lineNumber);
}
} else if (wordNavigationType === WordNavigationType.WordAccessibility) {

while (
nextWordOnLine
&& nextWordOnLine.wordType === WordType.Separator
) {
// Skip over a word made up of one single separator
nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));
}

if (nextWordOnLine) {
column = nextWordOnLine.end + 1;
} else {
Expand Down Expand Up @@ -617,4 +645,4 @@ export class WordPartOperations extends WordOperations {

function enforceDefined<T>(arr: Array<T | undefined | null>): T[] {
return <T[]>arr.filter(el => Boolean(el));
}
}
40 changes: 39 additions & 1 deletion src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts
Expand Up @@ -9,7 +9,7 @@ import { EditorCommand } from 'vs/editor/browser/editorExtensions';
import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { deserializePipePositions, serializePipePositions, testRepeatedActionAndExtractPositions } from 'vs/editor/contrib/wordOperations/test/wordTestUtils';
import { CursorWordEndLeft, CursorWordEndLeftSelect, CursorWordEndRight, CursorWordEndRightSelect, CursorWordLeft, CursorWordLeftSelect, CursorWordRight, CursorWordRightSelect, CursorWordStartLeft, CursorWordStartLeftSelect, CursorWordStartRight, CursorWordStartRightSelect, DeleteWordEndLeft, DeleteWordEndRight, DeleteWordLeft, DeleteWordRight, DeleteWordStartLeft, DeleteWordStartRight } from 'vs/editor/contrib/wordOperations/wordOperations';
import { CursorWordEndLeft, CursorWordEndLeftSelect, CursorWordEndRight, CursorWordEndRightSelect, CursorWordLeft, CursorWordLeftSelect, CursorWordRight, CursorWordRightSelect, CursorWordStartLeft, CursorWordStartLeftSelect, CursorWordStartRight, CursorWordStartRightSelect, DeleteWordEndLeft, DeleteWordEndRight, DeleteWordLeft, DeleteWordRight, DeleteWordStartLeft, DeleteWordStartRight, CursorWordAccessibilityLeft, CursorWordAccessibilityLeftSelect, CursorWordAccessibilityRight, CursorWordAccessibilityRightSelect } from 'vs/editor/contrib/wordOperations/wordOperations';
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';

suite('WordOperations', () => {
Expand All @@ -26,6 +26,10 @@ suite('WordOperations', () => {
const _cursorWordStartRightSelect = new CursorWordStartRightSelect();
const _cursorWordEndRightSelect = new CursorWordEndRightSelect();
const _cursorWordRightSelect = new CursorWordRightSelect();
const _cursorWordAccessibilityLeft = new CursorWordAccessibilityLeft();
const _cursorWordAccessibilityLeftSelect = new CursorWordAccessibilityLeftSelect();
const _cursorWordAccessibilityRight = new CursorWordAccessibilityRight();
const _cursorWordAccessibilityRightSelect = new CursorWordAccessibilityRightSelect();
const _deleteWordLeft = new DeleteWordLeft();
const _deleteWordStartLeft = new DeleteWordStartLeft();
const _deleteWordEndLeft = new DeleteWordEndLeft();
Expand All @@ -39,6 +43,12 @@ suite('WordOperations', () => {
function cursorWordLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
runEditorCommand(editor, inSelectionMode ? _cursorWordLeftSelect : _cursorWordLeft);
}
function cursorWordAccessibilityLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
runEditorCommand(editor, inSelectionMode ? _cursorWordAccessibilityLeft : _cursorWordAccessibilityLeftSelect);
}
function cursorWordAccessibilityRight(editor: ICodeEditor, inSelectionMode: boolean = false): void {
runEditorCommand(editor, inSelectionMode ? _cursorWordAccessibilityRightSelect : _cursorWordAccessibilityRight);
}
function cursorWordStartLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
runEditorCommand(editor, inSelectionMode ? _cursorWordStartLeftSelect : _cursorWordStartLeft);
}
Expand Down Expand Up @@ -326,6 +336,34 @@ suite('WordOperations', () => {
assert.deepEqual(actual, EXPECTED);
});

test('cursorWordAccessibilityLeft', () => {
const EXPECTED = ['| /* |Just |some |more |text |a+= |3 +|5-|3 + |7 */ '].join('\n');
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1000, 1000),
ed => cursorWordAccessibilityLeft(ed),
ed => ed.getPosition()!,
ed => ed.getPosition()!.equals(new Position(1, 1))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});

test('cursorWordAccessibilityRight', () => {
const EXPECTED = [' /* Just| some| more| text| a|+= 3| +5|-3| + 7| */ |'].join('\n');
const [text,] = deserializePipePositions(EXPECTED);
const actualStops = testRepeatedActionAndExtractPositions(
text,
new Position(1, 1),
ed => cursorWordAccessibilityRight(ed),
ed => ed.getPosition()!,
ed => ed.getPosition()!.equals(new Position(1, 50))
);
const actual = serializePipePositions(text, actualStops);
assert.deepEqual(actual, EXPECTED);
});

test('deleteWordLeft for non-empty selection', () => {
withTestCodeEditor([
' \tMy First Line\t ',
Expand Down
91 changes: 91 additions & 0 deletions src/vs/editor/contrib/wordOperations/wordOperations.ts
Expand Up @@ -18,6 +18,9 @@ import { ScrollType } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { ITextModel } from 'vs/editor/common/model';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { EDITOR_DEFAULTS } from 'vs/editor/common/config/editorOptions';

export interface MoveWordOptions extends ICommandOptions {
inSelectionMode: boolean;
Expand Down Expand Up @@ -170,6 +173,48 @@ export class CursorWordLeftSelect extends WordLeftCommand {
}
}

export class CursorWordAccessibilityLeft extends WordLeftCommand {
constructor() {
super({
inSelectionMode: false,
wordNavigationType: WordNavigationType.WordAccessibility,
id: 'cursorWordAccessibilityLeft',
precondition: undefined,
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
primary: KeyMod.CtrlCmd | KeyCode.LeftArrow,
mac: { primary: KeyMod.Alt | KeyCode.LeftArrow },
weight: KeybindingWeight.EditorContrib + 1
}
});
}

protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType);
}
}

export class CursorWordAccessibilityLeftSelect extends WordLeftCommand {
constructor() {
super({
inSelectionMode: true,
wordNavigationType: WordNavigationType.WordAccessibility,
id: 'cursorWordAccessibilitLeftSelecty',
precondition: undefined,
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },
weight: KeybindingWeight.EditorContrib + 1
}
});
}

protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType);
}
}

export class CursorWordStartRight extends WordRightCommand {
constructor() {
super({
Expand Down Expand Up @@ -248,6 +293,48 @@ export class CursorWordRightSelect extends WordRightCommand {
}
}

export class CursorWordAccessibilityRight extends WordRightCommand {
constructor() {
super({
inSelectionMode: false,
wordNavigationType: WordNavigationType.WordAccessibility,
id: 'cursorWordAccessibilityRight',
precondition: undefined,
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
primary: KeyMod.CtrlCmd | KeyCode.RightArrow,
mac: { primary: KeyMod.Alt | KeyCode.RightArrow },
weight: KeybindingWeight.EditorContrib + 1
}
});
}

protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType);
}
}

export class CursorWordAccessibilityRightSelect extends WordRightCommand {
constructor() {
super({
inSelectionMode: true,
wordNavigationType: WordNavigationType.WordAccessibility,
id: 'cursorWordAccessibilityRightSelect',
precondition: undefined,
kbOpts: {
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow,
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },
weight: KeybindingWeight.EditorContrib + 1
}
});
}

protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
return super._move(getMapForWordSeparators(EDITOR_DEFAULTS.wordSeparators), model, position, wordNavigationType);
}
}

export interface DeleteWordOptions extends ICommandOptions {
whitespaceHeuristics: boolean;
wordNavigationType: WordNavigationType;
Expand Down Expand Up @@ -397,6 +484,10 @@ registerEditorCommand(new CursorWordRight());
registerEditorCommand(new CursorWordStartRightSelect());
registerEditorCommand(new CursorWordEndRightSelect());
registerEditorCommand(new CursorWordRightSelect());
registerEditorCommand(new CursorWordAccessibilityLeft());
registerEditorCommand(new CursorWordAccessibilityLeftSelect());
registerEditorCommand(new CursorWordAccessibilityRight());
registerEditorCommand(new CursorWordAccessibilityRightSelect());
registerEditorCommand(new DeleteWordStartLeft());
registerEditorCommand(new DeleteWordEndLeft());
registerEditorCommand(new DeleteWordLeft());
Expand Down