Skip to content

Commit e5bcb02

Browse files
committed
fix(tree): 🐛 allow navigating between breadcrumbs using arrow keys
1 parent b5ac86a commit e5bcb02

File tree

5 files changed

+42
-15
lines changed

5 files changed

+42
-15
lines changed

.vscode/settings.json

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@
4242
}
4343
],
4444
"eslint.options": {
45-
"rulePaths": [
46-
"./build/lib/eslint"
47-
]
45+
"rulePaths": ["./build/lib/eslint"]
4846
},
4947
"typescript.tsdk": "node_modules/typescript/lib",
5048
"npm.exclude": "**/extensions/**",
@@ -54,15 +52,11 @@
5452
"typescript.preferences.quoteStyle": "single",
5553
"json.schemas": [
5654
{
57-
"fileMatch": [
58-
"cgmanifest.json"
59-
],
55+
"fileMatch": ["cgmanifest.json"],
6056
"url": "./.vscode/cgmanifest.schema.json"
6157
},
6258
{
63-
"fileMatch": [
64-
"cglicenses.json"
65-
],
59+
"fileMatch": ["cglicenses.json"],
6660
"url": "./.vscode/cglicenses.schema.json"
6761
}
6862
],
@@ -73,16 +67,17 @@
7367
"gulp.autoDetect": "off",
7468
"files.insertFinalNewline": true,
7569
"[plaintext]": {
76-
"files.insertFinalNewline": false,
70+
"files.insertFinalNewline": false
7771
},
7872
"[typescript]": {
7973
"editor.defaultFormatter": "vscode.typescript-language-features",
80-
"editor.formatOnSave": true,
74+
"editor.formatOnSave": true
8175
},
8276
"[javascript]": {
8377
"editor.defaultFormatter": "vscode.typescript-language-features",
84-
"editor.formatOnSave": true,
78+
"editor.formatOnSave": true
8579
},
8680
"typescript.tsc.autoDetect": "off",
8781
"testing.autoRun.mode": "rerun",
82+
"conventionalCommits.scopes": ["tree"]
8883
}

src/vs/base/browser/ui/tree/abstractTree.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,7 @@ export abstract class AbstractTree<T, TFilterData, TRef> implements IDisposable
12931293
get onDidFocus(): Event<void> { return this.view.onDidFocus; }
12941294
get onDidBlur(): Event<void> { return this.view.onDidBlur; }
12951295

1296+
get onDidChangeModel(): Event<void> { return Event.signal(this.model.onDidSplice); }
12961297
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<T, TFilterData>> { return this.model.onDidChangeCollapseState; }
12971298
get onDidChangeRenderNodeCount(): Event<ITreeNode<T, TFilterData>> { return this.model.onDidChangeRenderNodeCount; }
12981299

src/vs/base/browser/ui/tree/asyncDataTree.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
341341
get onDidFocus(): Event<void> { return this.tree.onDidFocus; }
342342
get onDidBlur(): Event<void> { return this.tree.onDidBlur; }
343343

344+
get onDidChangeModel(): Event<void> { return this.tree.onDidChangeModel; }
344345
get onDidChangeCollapseState(): Event<ICollapseStateChangeEvent<IAsyncDataTreeNode<TInput, T> | null, TFilterData>> { return this.tree.onDidChangeCollapseState; }
345346

346347
get onDidUpdateOptions(): Event<IAsyncDataTreeOptionsUpdate> { return this.tree.onDidUpdateOptions; }

src/vs/platform/list/browser/listService.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ export const WorkbenchListHasSelectionOrFocus = new RawContextKey<boolean>('list
110110
export const WorkbenchListDoubleSelection = new RawContextKey<boolean>('listDoubleSelection', false);
111111
export const WorkbenchListMultiSelection = new RawContextKey<boolean>('listMultiSelection', false);
112112
export const WorkbenchListSelectionNavigation = new RawContextKey<boolean>('listSelectionNavigation', false);
113+
export const WorkbenchTreeElementCanCollapse = new RawContextKey<boolean>('treeElementCanCollapse', false);
114+
export const WorkbenchTreeElementHasParent = new RawContextKey<boolean>('treeElementHasParent', false);
115+
export const WorkbenchTreeElementCanExpand = new RawContextKey<boolean>('treeElementCanExpand', false);
116+
export const WorkbenchTreeElementHasChild = new RawContextKey<boolean>('treeElementHasChild', false);
113117
export const WorkbenchListAutomaticKeyboardNavigationKey = 'listAutomaticKeyboardNavigation';
114118

115119
function createScopedContextKeyService(contextKeyService: IContextKeyService, widget: ListWidget): IContextKeyService {
@@ -1087,6 +1091,10 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
10871091
private hasSelectionOrFocus: IContextKey<boolean>;
10881092
private hasDoubleSelection: IContextKey<boolean>;
10891093
private hasMultiSelection: IContextKey<boolean>;
1094+
private treeElementCanCollapse: IContextKey<boolean>;
1095+
private treeElementHasParent: IContextKey<boolean>;
1096+
private treeElementCanExpand: IContextKey<boolean>;
1097+
private treeElementHasChild: IContextKey<boolean>;
10901098
private _useAltAsMultipleSelectionModifier: boolean;
10911099
private disposables: IDisposable[] = [];
10921100
private styler: IDisposable | undefined;
@@ -1117,6 +1125,11 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
11171125
this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService);
11181126
this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService);
11191127

1128+
this.treeElementCanCollapse = WorkbenchTreeElementCanCollapse.bindTo(this.contextKeyService);
1129+
this.treeElementHasParent = WorkbenchTreeElementHasParent.bindTo(this.contextKeyService);
1130+
this.treeElementCanExpand = WorkbenchTreeElementCanExpand.bindTo(this.contextKeyService);
1131+
this.treeElementHasChild = WorkbenchTreeElementHasChild.bindTo(this.contextKeyService);
1132+
11201133
this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService);
11211134

11221135
const interestingContextKeys = new Set();
@@ -1132,6 +1145,20 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
11321145

11331146
this.updateStyleOverrides(overrideStyles);
11341147

1148+
const updateCollapseContextKeys = () => {
1149+
const focus = tree.getFocus()[0];
1150+
1151+
if (!focus) {
1152+
return;
1153+
}
1154+
1155+
const node = tree.getNode(focus);
1156+
this.treeElementCanCollapse.set(node.collapsible && !node.collapsed);
1157+
this.treeElementHasParent.set(!!tree.getParentElement(focus));
1158+
this.treeElementCanExpand.set(node.collapsible && node.collapsed);
1159+
this.treeElementHasChild.set(!!tree.getFirstElementChild(focus));
1160+
};
1161+
11351162
this.disposables.push(
11361163
this.contextKeyService,
11371164
(listService as ListService).register(tree),
@@ -1150,7 +1177,10 @@ class WorkbenchTreeInternals<TInput, T, TFilterData> {
11501177
const focus = tree.getFocus();
11511178

11521179
this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0);
1180+
updateCollapseContextKeys();
11531181
}),
1182+
tree.onDidChangeCollapseState(updateCollapseContextKeys),
1183+
tree.onDidChangeModel(updateCollapseContextKeys),
11541184
configurationService.onDidChangeConfiguration(e => {
11551185
let newOptions: IAbstractTreeOptionsUpdate = {};
11561186
if (e.affectsConfiguration(multiSelectModifierSettingKey)) {

src/vs/workbench/browser/actions/listCommands.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
77
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
88
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
99
import { List } from 'vs/base/browser/ui/list/listWidget';
10-
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation } from 'vs/platform/list/browser/listService';
10+
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation, WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent, WorkbenchTreeElementHasChild, WorkbenchTreeElementCanExpand } from 'vs/platform/list/browser/listService';
1111
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
1212
import { equals, range } from 'vs/base/common/arrays';
1313
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
@@ -252,7 +252,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
252252
KeybindingsRegistry.registerCommandAndKeybindingRule({
253253
id: 'list.collapse',
254254
weight: KeybindingWeight.WorkbenchContrib,
255-
when: WorkbenchListFocusContextKey,
255+
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, ContextKeyExpr.or(WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent)),
256256
primary: KeyCode.LeftArrow,
257257
mac: {
258258
primary: KeyCode.LeftArrow,
@@ -336,7 +336,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
336336
KeybindingsRegistry.registerCommandAndKeybindingRule({
337337
id: 'list.expand',
338338
weight: KeybindingWeight.WorkbenchContrib,
339-
when: WorkbenchListFocusContextKey,
339+
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, ContextKeyExpr.or(WorkbenchTreeElementCanExpand, WorkbenchTreeElementHasChild)),
340340
primary: KeyCode.RightArrow,
341341
handler: (accessor) => {
342342
const widget = accessor.get(IListService).lastFocusedList;

0 commit comments

Comments
 (0)