Skip to content

Commit 7981bd5

Browse files
committed
Improves quickpick keyboard navigation
- Avoids breaking ctrl+[left|right] in input - Introduces structured `keyboard` object to handle keypress event bindings and actions
1 parent 6935b4c commit 7981bd5

File tree

6 files changed

+115
-83
lines changed

6 files changed

+115
-83
lines changed

src/commands/diffWithRevision.ts

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,23 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand {
5656
'Choose a commit to compare with',
5757
{
5858
picked: gitUri.sha,
59-
keys: ['right', 'alt+right', 'ctrl+right'],
60-
onDidPressKey: async (key, item) => {
61-
void (await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
62-
repoPath: gitUri.repoPath,
63-
lhs: {
64-
sha: item.item.ref,
65-
uri: gitUri,
66-
},
67-
rhs: {
68-
sha: '',
69-
uri: gitUri,
70-
},
71-
line: args!.line,
72-
showOptions: args!.showOptions,
73-
}));
59+
keyboard: {
60+
keys: ['right', 'alt+right', 'ctrl+right'],
61+
onDidPressKey: async (key, item) => {
62+
await executeCommand<DiffWithCommandArgs>(Commands.DiffWith, {
63+
repoPath: gitUri.repoPath,
64+
lhs: {
65+
sha: item.item.ref,
66+
uri: gitUri,
67+
},
68+
rhs: {
69+
sha: '',
70+
uri: gitUri,
71+
},
72+
line: args!.line,
73+
showOptions: args!.showOptions,
74+
});
75+
},
7476
},
7577
showOtherReferences: [
7678
CommandQuickPickItem.fromCommand('Choose a Branch or Tag...', Commands.DiffWithRevisionFrom),

src/commands/gitCommands.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ export class GitCommandsCommand extends Command {
363363

364364
const scope = this.container.keyboard.createScope(mapping);
365365
void scope.start();
366+
if (step.value != null) {
367+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
368+
}
366369

367370
disposables.push(
368371
scope,
@@ -404,9 +407,9 @@ export class GitCommandsCommand extends Command {
404407
if (scope != null) {
405408
// Pause the left/right keyboard commands if there is a value, otherwise the left/right arrows won't work in the input properly
406409
if (e.length !== 0) {
407-
await scope.pause(['left', 'right']);
410+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
408411
} else {
409-
await scope.resume();
412+
void scope.resume();
410413
}
411414
}
412415

@@ -521,6 +524,9 @@ export class GitCommandsCommand extends Command {
521524

522525
const scope = this.container.keyboard.createScope(mapping);
523526
void scope.start();
527+
if (step.value != null) {
528+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
529+
}
524530

525531
let overrideItems = false;
526532

@@ -592,9 +598,9 @@ export class GitCommandsCommand extends Command {
592598
if (scope != null) {
593599
// Pause the left/right keyboard commands if there is a value, otherwise the left/right arrows won't work in the input properly
594600
if (e.length !== 0) {
595-
await scope.pause(['left', 'right']);
601+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
596602
} else {
597-
await scope.resume();
603+
void scope.resume();
598604
}
599605
}
600606

src/commands/openFileAtRevision.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,16 @@ export class OpenFileAtRevisionCommand extends ActiveEditorCommand {
133133
`Choose a commit to ${args.annotationType === 'blame' ? 'blame' : 'open'} the file revision from`,
134134
{
135135
picked: gitUri.sha,
136-
keys: ['right', 'alt+right', 'ctrl+right'],
137-
onDidPressKey: async (key, item) => {
138-
await openFileAtRevision(item.item.file!, item.item, {
139-
annotationType: args!.annotationType,
140-
line: args!.line,
141-
preserveFocus: true,
142-
preview: false,
143-
});
136+
keyboard: {
137+
keys: ['right', 'alt+right', 'ctrl+right'],
138+
onDidPressKey: async (key, item) => {
139+
await openFileAtRevision(item.item.file!, item.item, {
140+
annotationType: args!.annotationType,
141+
line: args!.line,
142+
preserveFocus: true,
143+
preview: true,
144+
});
145+
},
144146
},
145147
showOtherReferences: [
146148
CommandQuickPickItem.fromCommand(

src/commands/openFileAtRevisionFrom.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,19 @@ export class OpenFileAtRevisionFromCommand extends ActiveEditorCommand {
6565
'Choose a branch or tag to open the file revision from',
6666
{
6767
allowEnteringRefs: true,
68-
keys: ['right', 'alt+right', 'ctrl+right'],
69-
onDidPressKey: async (key, quickpick) => {
70-
const [item] = quickpick.activeItems;
71-
if (item != null) {
68+
keyboard: {
69+
keys: ['right', 'alt+right', 'ctrl+right'],
70+
onDidPressKey: async (key, item) => {
7271
await openFileAtRevision(
7372
this.container.git.getRevisionUri(item.ref, gitUri.fsPath, gitUri.repoPath!),
7473
{
7574
annotationType: args!.annotationType,
7675
line: args!.line,
7776
preserveFocus: true,
78-
preview: false,
77+
preview: true,
7978
},
8079
);
81-
}
80+
},
8281
},
8382
},
8483
);

src/quickpicks/commitPicker.ts

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ export async function showCommitPicker(
2222
placeholder: string,
2323
options?: {
2424
picked?: string;
25-
keys?: Keys[];
26-
onDidPressKey?(key: Keys, item: CommitQuickPickItem): void | Promise<void>;
25+
keyboard?: {
26+
keys: Keys[];
27+
onDidPressKey(key: Keys, item: CommitQuickPickItem): void | Promise<void>;
28+
};
2729
showOtherReferences?: CommandQuickPickItem[];
2830
},
2931
): Promise<GitCommit | undefined> {
@@ -98,17 +100,23 @@ export async function showCommitPicker(
98100
const disposables: Disposable[] = [];
99101

100102
let scope: KeyboardScope | undefined;
101-
if (options?.keys != null && options.keys.length !== 0 && options?.onDidPressKey !== null) {
103+
if (options?.keyboard != null) {
104+
const { keyboard } = options;
102105
scope = Container.instance.keyboard.createScope(
103106
Object.fromEntries(
104-
options.keys.map(key => [
107+
keyboard.keys.map(key => [
105108
key,
106109
{
107-
onDidPressKey: key => {
110+
onDidPressKey: async key => {
108111
if (quickpick.activeItems.length !== 0) {
109112
const [item] = quickpick.activeItems;
110113
if (item != null && !isDirectiveQuickPickItem(item) && !CommandQuickPickItem.is(item)) {
111-
void options.onDidPressKey!(key, item);
114+
const ignoreFocusOut = quickpick.ignoreFocusOut;
115+
quickpick.ignoreFocusOut = true;
116+
117+
await keyboard.onDidPressKey(key, item);
118+
119+
quickpick.ignoreFocusOut = ignoreFocusOut;
112120
}
113121
}
114122
},
@@ -143,14 +151,14 @@ export async function showCommitPicker(
143151
resolve(item);
144152
}
145153
}),
146-
quickpick.onDidChangeValue(async e => {
154+
quickpick.onDidChangeValue(value => {
147155
if (scope == null) return;
148156

149157
// Pause the left/right keyboard commands if there is a value, otherwise the left/right arrows won't work in the input properly
150-
if (e.length !== 0) {
151-
await scope.pause(['left', 'right']);
158+
if (value.length !== 0) {
159+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
152160
} else {
153-
await scope.resume();
161+
void scope.resume();
154162
}
155163
}),
156164
);
@@ -182,8 +190,10 @@ export async function showStashPicker(
182190
options?: {
183191
empty?: string;
184192
filter?: (c: GitStashCommit) => boolean;
185-
keys?: Keys[];
186-
onDidPressKey?(key: Keys, item: CommitQuickPickItem<GitStashCommit>): void | Promise<void>;
193+
keyboard?: {
194+
keys: Keys[];
195+
onDidPressKey(key: Keys, item: CommitQuickPickItem<GitStashCommit>): void | Promise<void>;
196+
};
187197
picked?: string;
188198
showOtherReferences?: CommandQuickPickItem[];
189199
},
@@ -231,17 +241,23 @@ export async function showStashPicker(
231241
const disposables: Disposable[] = [];
232242

233243
let scope: KeyboardScope | undefined;
234-
if (options?.keys != null && options.keys.length !== 0 && options?.onDidPressKey !== null) {
244+
if (options?.keyboard != null) {
245+
const { keyboard } = options;
235246
scope = Container.instance.keyboard.createScope(
236247
Object.fromEntries(
237-
options.keys.map(key => [
248+
keyboard.keys.map(key => [
238249
key,
239250
{
240-
onDidPressKey: key => {
251+
onDidPressKey: async key => {
241252
if (quickpick.activeItems.length !== 0) {
242253
const [item] = quickpick.activeItems;
243254
if (item != null && !isDirectiveQuickPickItem(item) && !CommandQuickPickItem.is(item)) {
244-
void options.onDidPressKey!(key, item);
255+
const ignoreFocusOut = quickpick.ignoreFocusOut;
256+
quickpick.ignoreFocusOut = true;
257+
258+
await keyboard.onDidPressKey(key, item);
259+
260+
quickpick.ignoreFocusOut = ignoreFocusOut;
245261
}
246262
}
247263
},
@@ -270,14 +286,14 @@ export async function showStashPicker(
270286
resolve(item);
271287
}
272288
}),
273-
quickpick.onDidChangeValue(async e => {
289+
quickpick.onDidChangeValue(value => {
274290
if (scope == null) return;
275291

276292
// Pause the left/right keyboard commands if there is a value, otherwise the left/right arrows won't work in the input properly
277-
if (e.length !== 0) {
278-
await scope.pause(['left', 'right']);
293+
if (value.length !== 0) {
294+
void scope.pause(['left', 'ctrl+left', 'right', 'ctrl+right']);
279295
} else {
280-
await scope.resume();
296+
void scope.resume();
281297
}
282298
}),
283299
);

0 commit comments

Comments
 (0)