Add keybinding for navigating separators (#207028)

Fixes https://github.com/microsoft/vscode/issues/70861
This commit is contained in:
Tyler James Leonhardt 2024-03-06 19:02:16 -08:00 committed by GitHub
parent c8024cf91f
commit d990bac0cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 19 deletions

View file

@ -21,7 +21,7 @@ import { Codicon } from 'vs/base/common/codicons';
import { Emitter, Event } from 'vs/base/common/event';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isIOS } from 'vs/base/common/platform';
import { isIOS, isMacintosh } from 'vs/base/common/platform';
import Severity from 'vs/base/common/severity';
import { ThemeIcon } from 'vs/base/common/themables';
import 'vs/css!./media/quickInput';
@ -826,20 +826,25 @@ export class QuickPick<T extends IQuickPickItem> extends QuickInput implements I
this.ui.inputBox.onDidChange(value => {
this.doSetValue(value, true /* skip update since this originates from the UI */);
}));
// Keybindings for the input box or list if there is no input box
this.visibleDisposables.add((this._hideInput ? this.ui.list : this.ui.inputBox).onKeyDown((event: KeyboardEvent | StandardKeyboardEvent) => {
switch (event.keyCode) {
case KeyCode.DownArrow:
this.ui.list.focus(QuickInputListFocus.Next);
if (isMacintosh ? event.metaKey : event.ctrlKey) {
this.ui.list.focus(QuickInputListFocus.NextSeparator);
} else {
this.ui.list.focus(QuickInputListFocus.Next);
}
if (this.canSelectMany) {
this.ui.list.domFocus();
}
dom.EventHelper.stop(event, true);
break;
case KeyCode.UpArrow:
if (this.ui.list.getFocusedElements().length) {
this.ui.list.focus(QuickInputListFocus.Previous);
if (isMacintosh ? event.metaKey : event.ctrlKey) {
this.ui.list.focus(QuickInputListFocus.PreviousSeparator);
} else {
this.ui.list.focus(QuickInputListFocus.Last);
this.ui.list.focus(QuickInputListFocus.Previous);
}
if (this.canSelectMany) {
this.ui.list.domFocus();

View file

@ -219,6 +219,7 @@ export class QuickInputController extends Disposable {
inputBox.setFocus();
}));
// TODO: Turn into commands instead of handling KEY_DOWN
// Keybindings for the quickinput widget as a whole
this._register(dom.addStandardDisposableListener(container, dom.EventType.KEY_DOWN, (event) => {
if (dom.isAncestor(event.target, widget)) {
return; // Ignore event if target is inside widget to allow the widget to handle the event.

View file

@ -430,7 +430,9 @@ export enum QuickInputListFocus {
Next,
Previous,
NextPage,
PreviousPage
PreviousPage,
NextSeparator,
PreviousSeparator
}
export class QuickInputList {
@ -499,6 +501,7 @@ export class QuickInputList {
} as IListOptions<IListElement>);
this.list.getHTMLElement().id = id;
this.disposables.push(this.list);
// Keybindings for the list itself
this.disposables.push(this.list.onKeyDown(e => {
const event = new StandardKeyboardEvent(e);
switch (event.keyCode) {
@ -510,6 +513,7 @@ export class QuickInputList {
this.list.setFocus(range(this.list.length));
}
break;
// When we hit the top of the list, we fire the onLeave event.
case KeyCode.UpArrow: {
const focus1 = this.list.getFocus();
if (focus1.length === 1 && focus1[0] === 0) {
@ -517,6 +521,7 @@ export class QuickInputList {
}
break;
}
// When we hit the bottom of the list, we fire the onLeave event.
case KeyCode.DownArrow: {
const focus2 = this.list.getFocus();
if (focus2.length === 1 && focus2[0] === this.list.length - 1) {
@ -810,33 +815,67 @@ export class QuickInputList {
this.list.scrollTop = this.list.scrollHeight;
this.list.focusLast(undefined, (e) => !!e.item);
break;
case QuickInputListFocus.Next: {
case QuickInputListFocus.Next:
this.list.focusNext(undefined, true, undefined, (e) => !!e.item);
const index = this.list.getFocus()[0];
if (index !== 0 && !this.elements[index - 1].item && this.list.firstVisibleIndex > index - 1) {
this.list.reveal(index - 1);
}
break;
}
case QuickInputListFocus.Previous: {
case QuickInputListFocus.Previous:
this.list.focusPrevious(undefined, true, undefined, (e) => !!e.item);
const index = this.list.getFocus()[0];
if (index !== 0 && !this.elements[index - 1].item && this.list.firstVisibleIndex > index - 1) {
this.list.reveal(index - 1);
}
break;
}
case QuickInputListFocus.NextPage:
this.list.focusNextPage(undefined, (e) => !!e.item);
break;
case QuickInputListFocus.PreviousPage:
this.list.focusPreviousPage(undefined, (e) => !!e.item);
break;
case QuickInputListFocus.NextSeparator: {
let foundSeparatorAsItem = false;
this.list.focusNext(undefined, true, undefined, (e) => {
if (foundSeparatorAsItem) {
// This should be the index right after the separator so it
// is the item we want to focus.
return true;
}
if (e.separator) {
if (e.item) {
return true;
} else {
foundSeparatorAsItem = true;
}
}
return false;
});
break;
}
case QuickInputListFocus.PreviousSeparator: {
let foundSeparatorAsItem = false;
this.list.focusPrevious(undefined, true, undefined, (e) => {
if (foundSeparatorAsItem) {
// This should be the index right before the separator so it
// is the item we want to focus.
return true;
}
if (e.separator) {
if (e.item) {
// This would be an inline-separator so we should
// focus this item.
return true;
} else {
foundSeparatorAsItem = true;
}
}
return false;
});
break;
}
}
const focused = this.list.getFocus()[0];
if (typeof focused === 'number') {
this.list.reveal(focused);
if (focused !== 0 && !this.elements[focused - 1].item && this.list.firstVisibleIndex > focused - 1) {
this.list.reveal(focused - 1);
} else {
this.list.reveal(focused);
}
}
}