Skip to content

Commit cf7fb77

Browse files
committed
introduce cursor word accessibilty commands
1 parent edee5c0 commit cf7fb77

3 files changed

Lines changed: 164 additions & 3 deletions

File tree

src/vs/editor/common/controller/cursorWordOperations.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ const enum WordType {
3939
export const enum WordNavigationType {
4040
WordStart = 0,
4141
WordStartFast = 1,
42-
WordEnd = 2
42+
WordEnd = 2,
43+
WordAcessibility = 3 // Respect chrome defintion of a word
4344
}
4445

4546
export class WordOperations {
@@ -202,6 +203,19 @@ export class WordOperations {
202203
return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
203204
}
204205

206+
if (wordNavigationType === WordNavigationType.WordAcessibility) {
207+
while (
208+
prevWordOnLine
209+
&& prevWordOnLine.wordType === WordType.Separator
210+
&& prevWordOnLine.end - prevWordOnLine.start === 1
211+
) {
212+
// Skip over a word made up of one single separator
213+
prevWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, prevWordOnLine.start + 1));
214+
}
215+
216+
return new Position(lineNumber, prevWordOnLine ? prevWordOnLine.start + 1 : 1);
217+
}
218+
205219
// We are stopping at the ending of words
206220

207221
if (prevWordOnLine && column <= prevWordOnLine.end + 1) {
@@ -275,6 +289,22 @@ export class WordOperations {
275289
} else {
276290
column = model.getLineMaxColumn(lineNumber);
277291
}
292+
} else if (wordNavigationType === WordNavigationType.WordAcessibility) {
293+
294+
while (
295+
nextWordOnLine
296+
&& nextWordOnLine.wordType === WordType.Separator
297+
&& nextWordOnLine.end - nextWordOnLine.start === 1
298+
) {
299+
// Skip over a word made up of one single separator
300+
nextWordOnLine = WordOperations._findPreviousWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));
301+
}
302+
303+
if (nextWordOnLine) {
304+
column = nextWordOnLine.start + 1;
305+
} else {
306+
column = model.getLineMaxColumn(lineNumber);
307+
}
278308
} else {
279309
if (nextWordOnLine && !movedDown && column >= nextWordOnLine.start + 1) {
280310
nextWordOnLine = WordOperations._findNextWordOnLine(wordSeparators, model, new Position(lineNumber, nextWordOnLine.end + 1));
@@ -617,4 +647,4 @@ export class WordPartOperations extends WordOperations {
617647

618648
function enforceDefined<T>(arr: Array<T | undefined | null>): T[] {
619649
return <T[]>arr.filter(el => Boolean(el));
620-
}
650+
}

src/vs/editor/contrib/wordOperations/test/wordOperations.test.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { EditorCommand } from 'vs/editor/browser/editorExtensions';
99
import { Position } from 'vs/editor/common/core/position';
1010
import { Selection } from 'vs/editor/common/core/selection';
1111
import { deserializePipePositions, serializePipePositions, testRepeatedActionAndExtractPositions } from 'vs/editor/contrib/wordOperations/test/wordTestUtils';
12-
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';
12+
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';
1313
import { withTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
1414

1515
suite('WordOperations', () => {
@@ -26,6 +26,10 @@ suite('WordOperations', () => {
2626
const _cursorWordStartRightSelect = new CursorWordStartRightSelect();
2727
const _cursorWordEndRightSelect = new CursorWordEndRightSelect();
2828
const _cursorWordRightSelect = new CursorWordRightSelect();
29+
const _cursorWordAccessibilityLeft = new CursorWordAccessibilityLeft();
30+
const _cursorWordAccessibilityLeftSelect = new CursorWordAccessibilityLeftSelect();
31+
const _cursorWordAccessibilityRight = new CursorWordAccessibilityRight();
32+
const _cursorWordAccessibilityRightSelect = new CursorWordAccessibilityRightSelect();
2933
const _deleteWordLeft = new DeleteWordLeft();
3034
const _deleteWordStartLeft = new DeleteWordStartLeft();
3135
const _deleteWordEndLeft = new DeleteWordEndLeft();
@@ -39,6 +43,12 @@ suite('WordOperations', () => {
3943
function cursorWordLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
4044
runEditorCommand(editor, inSelectionMode ? _cursorWordLeftSelect : _cursorWordLeft);
4145
}
46+
function cursorWordAccessibilityLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
47+
runEditorCommand(editor, inSelectionMode ? _cursorWordAccessibilityLeft : _cursorWordAccessibilityLeftSelect);
48+
}
49+
function cursorWordAccessibilityRight(editor: ICodeEditor, inSelectionMode: boolean = false): void {
50+
runEditorCommand(editor, inSelectionMode ? _cursorWordAccessibilityRightSelect : _cursorWordAccessibilityRight);
51+
}
4252
function cursorWordStartLeft(editor: ICodeEditor, inSelectionMode: boolean = false): void {
4353
runEditorCommand(editor, inSelectionMode ? _cursorWordStartLeftSelect : _cursorWordStartLeft);
4454
}
@@ -326,6 +336,36 @@ suite('WordOperations', () => {
326336
assert.deepEqual(actual, EXPECTED);
327337
});
328338

339+
test('cursorWordAccessibilityLeft', () => {
340+
const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n');
341+
const [text,] = deserializePipePositions(EXPECTED);
342+
const actualStops = testRepeatedActionAndExtractPositions(
343+
text,
344+
new Position(1000, 1000),
345+
ed => cursorWordAccessibilityLeft(ed),
346+
ed => ed.getPosition()!,
347+
ed => ed.getPosition()!.equals(new Position(1, 1))
348+
);
349+
const actual = serializePipePositions(text, actualStops);
350+
assert.deepEqual(actual, EXPECTED);
351+
});
352+
353+
test('cursorWordAccessibilityRight', () => {
354+
const EXPECTED = [
355+
'console|.log|(err|)|',
356+
].join('\n');
357+
const [text,] = deserializePipePositions(EXPECTED);
358+
const actualStops = testRepeatedActionAndExtractPositions(
359+
text,
360+
new Position(1, 1),
361+
ed => cursorWordAccessibilityRight(ed),
362+
ed => ed.getPosition()!,
363+
ed => ed.getPosition()!.equals(new Position(1, 17))
364+
);
365+
const actual = serializePipePositions(text, actualStops);
366+
assert.deepEqual(actual, EXPECTED);
367+
});
368+
329369
test('deleteWordLeft for non-empty selection', () => {
330370
withTestCodeEditor([
331371
' \tMy First Line\t ',

src/vs/editor/contrib/wordOperations/wordOperations.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import { ScrollType } from 'vs/editor/common/editorCommon';
1818
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
1919
import { ITextModel } from 'vs/editor/common/model';
2020
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
21+
import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility';
22+
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
2123

2224
export interface MoveWordOptions extends ICommandOptions {
2325
inSelectionMode: boolean;
@@ -170,6 +172,49 @@ export class CursorWordLeftSelect extends WordLeftCommand {
170172
}
171173
}
172174

175+
const CHROME_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;",.<>/?';
176+
export class CursorWordAccessibilityLeft extends WordLeftCommand {
177+
constructor() {
178+
super({
179+
inSelectionMode: false,
180+
wordNavigationType: WordNavigationType.WordAcessibility,
181+
id: 'cursorWordAccessibilityLeft',
182+
precondition: undefined,
183+
kbOpts: {
184+
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
185+
primary: KeyMod.CtrlCmd | KeyCode.LeftArrow,
186+
mac: { primary: KeyMod.Alt | KeyCode.LeftArrow },
187+
weight: KeybindingWeight.EditorContrib + 1
188+
}
189+
});
190+
}
191+
192+
protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
193+
return super._move(getMapForWordSeparators(CHROME_SEPARATORS), model, position, wordNavigationType);
194+
}
195+
}
196+
197+
export class CursorWordAccessibilityLeftSelect extends WordLeftCommand {
198+
constructor() {
199+
super({
200+
inSelectionMode: true,
201+
wordNavigationType: WordNavigationType.WordAcessibility,
202+
id: 'cursorWordAccessibilitLeftSelecty',
203+
precondition: undefined,
204+
kbOpts: {
205+
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
206+
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow,
207+
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.LeftArrow },
208+
weight: KeybindingWeight.EditorContrib + 1
209+
}
210+
});
211+
}
212+
213+
protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
214+
return super._move(getMapForWordSeparators(CHROME_SEPARATORS), model, position, wordNavigationType);
215+
}
216+
}
217+
173218
export class CursorWordStartRight extends WordRightCommand {
174219
constructor() {
175220
super({
@@ -248,6 +293,48 @@ export class CursorWordRightSelect extends WordRightCommand {
248293
}
249294
}
250295

296+
export class CursorWordAccessibilityRight extends WordRightCommand {
297+
constructor() {
298+
super({
299+
inSelectionMode: false,
300+
wordNavigationType: WordNavigationType.WordAcessibility,
301+
id: 'cursorWordAccessibilityRight',
302+
precondition: undefined,
303+
kbOpts: {
304+
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
305+
primary: KeyMod.CtrlCmd | KeyCode.RightArrow,
306+
mac: { primary: KeyMod.Alt | KeyCode.RightArrow },
307+
weight: KeybindingWeight.EditorContrib + 1
308+
}
309+
});
310+
}
311+
312+
protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
313+
return super._move(getMapForWordSeparators(CHROME_SEPARATORS), model, position, wordNavigationType);
314+
}
315+
}
316+
317+
export class CursorWordAccessibilityRightSelect extends WordRightCommand {
318+
constructor() {
319+
super({
320+
inSelectionMode: true,
321+
wordNavigationType: WordNavigationType.WordAcessibility,
322+
id: 'cursorWordAccessibilityRightSelect',
323+
precondition: undefined,
324+
kbOpts: {
325+
kbExpr: ContextKeyExpr.and(EditorContextKeys.textInputFocus, CONTEXT_ACCESSIBILITY_MODE_ENABLED),
326+
primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.RightArrow,
327+
mac: { primary: KeyMod.Alt | KeyMod.Shift | KeyCode.RightArrow },
328+
weight: KeybindingWeight.EditorContrib + 1
329+
}
330+
});
331+
}
332+
333+
protected _move(_: WordCharacterClassifier, model: ITextModel, position: Position, wordNavigationType: WordNavigationType): Position {
334+
return super._move(getMapForWordSeparators(CHROME_SEPARATORS), model, position, wordNavigationType);
335+
}
336+
}
337+
251338
export interface DeleteWordOptions extends ICommandOptions {
252339
whitespaceHeuristics: boolean;
253340
wordNavigationType: WordNavigationType;
@@ -397,6 +484,10 @@ registerEditorCommand(new CursorWordRight());
397484
registerEditorCommand(new CursorWordStartRightSelect());
398485
registerEditorCommand(new CursorWordEndRightSelect());
399486
registerEditorCommand(new CursorWordRightSelect());
487+
registerEditorCommand(new CursorWordAccessibilityLeft());
488+
registerEditorCommand(new CursorWordAccessibilityLeftSelect());
489+
registerEditorCommand(new CursorWordAccessibilityRight());
490+
registerEditorCommand(new CursorWordAccessibilityRightSelect());
400491
registerEditorCommand(new DeleteWordStartLeft());
401492
registerEditorCommand(new DeleteWordEndLeft());
402493
registerEditorCommand(new DeleteWordLeft());

0 commit comments

Comments
 (0)