diff --git a/.vscode/settings.json b/.vscode/settings.json index a3415d7559a..b4df37acfaa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -42,9 +42,7 @@ } ], "eslint.options": { - "rulePaths": [ - "./build/lib/eslint" - ] + "rulePaths": ["./build/lib/eslint"] }, "typescript.tsdk": "node_modules/typescript/lib", "npm.exclude": "**/extensions/**", @@ -54,15 +52,11 @@ "typescript.preferences.quoteStyle": "single", "json.schemas": [ { - "fileMatch": [ - "cgmanifest.json" - ], + "fileMatch": ["cgmanifest.json"], "url": "./.vscode/cgmanifest.schema.json" }, { - "fileMatch": [ - "cglicenses.json" - ], + "fileMatch": ["cglicenses.json"], "url": "./.vscode/cglicenses.schema.json" } ], @@ -73,16 +67,17 @@ "gulp.autoDetect": "off", "files.insertFinalNewline": true, "[plaintext]": { - "files.insertFinalNewline": false, + "files.insertFinalNewline": false }, "[typescript]": { "editor.defaultFormatter": "vscode.typescript-language-features", - "editor.formatOnSave": true, + "editor.formatOnSave": true }, "[javascript]": { "editor.defaultFormatter": "vscode.typescript-language-features", - "editor.formatOnSave": true, + "editor.formatOnSave": true }, "typescript.tsc.autoDetect": "off", "testing.autoRun.mode": "rerun", + "conventionalCommits.scopes": ["tree"] } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index de01350f9bf..422647e931c 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1293,6 +1293,7 @@ export abstract class AbstractTree implements IDisposable get onDidFocus(): Event { return this.view.onDidFocus; } get onDidBlur(): Event { return this.view.onDidBlur; } + get onDidChangeModel(): Event { return Event.signal(this.model.onDidSplice); } get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } get onDidChangeRenderNodeCount(): Event> { return this.model.onDidChangeRenderNodeCount; } diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 588ed907bd1..fcc3d24bc35 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -341,6 +341,7 @@ export class AsyncDataTree implements IDisposable get onDidFocus(): Event { return this.tree.onDidFocus; } get onDidBlur(): Event { return this.tree.onDidBlur; } + get onDidChangeModel(): Event { return this.tree.onDidChangeModel; } get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.tree.onDidChangeCollapseState; } get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 817b783c02a..332b3dd2ce8 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -110,6 +110,10 @@ export const WorkbenchListHasSelectionOrFocus = new RawContextKey('list export const WorkbenchListDoubleSelection = new RawContextKey('listDoubleSelection', false); export const WorkbenchListMultiSelection = new RawContextKey('listMultiSelection', false); export const WorkbenchListSelectionNavigation = new RawContextKey('listSelectionNavigation', false); +export const WorkbenchTreeElementCanCollapse = new RawContextKey('treeElementCanCollapse', false); +export const WorkbenchTreeElementHasParent = new RawContextKey('treeElementHasParent', false); +export const WorkbenchTreeElementCanExpand = new RawContextKey('treeElementCanExpand', false); +export const WorkbenchTreeElementHasChild = new RawContextKey('treeElementHasChild', false); export const WorkbenchListAutomaticKeyboardNavigationKey = 'listAutomaticKeyboardNavigation'; function createScopedContextKeyService(contextKeyService: IContextKeyService, widget: ListWidget): IContextKeyService { @@ -1087,6 +1091,10 @@ class WorkbenchTreeInternals { private hasSelectionOrFocus: IContextKey; private hasDoubleSelection: IContextKey; private hasMultiSelection: IContextKey; + private treeElementCanCollapse: IContextKey; + private treeElementHasParent: IContextKey; + private treeElementCanExpand: IContextKey; + private treeElementHasChild: IContextKey; private _useAltAsMultipleSelectionModifier: boolean; private disposables: IDisposable[] = []; private styler: IDisposable | undefined; @@ -1117,6 +1125,11 @@ class WorkbenchTreeInternals { this.hasDoubleSelection = WorkbenchListDoubleSelection.bindTo(this.contextKeyService); this.hasMultiSelection = WorkbenchListMultiSelection.bindTo(this.contextKeyService); + this.treeElementCanCollapse = WorkbenchTreeElementCanCollapse.bindTo(this.contextKeyService); + this.treeElementHasParent = WorkbenchTreeElementHasParent.bindTo(this.contextKeyService); + this.treeElementCanExpand = WorkbenchTreeElementCanExpand.bindTo(this.contextKeyService); + this.treeElementHasChild = WorkbenchTreeElementHasChild.bindTo(this.contextKeyService); + this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService); const interestingContextKeys = new Set(); @@ -1132,6 +1145,20 @@ class WorkbenchTreeInternals { this.updateStyleOverrides(overrideStyles); + const updateCollapseContextKeys = () => { + const focus = tree.getFocus()[0]; + + if (!focus) { + return; + } + + const node = tree.getNode(focus); + this.treeElementCanCollapse.set(node.collapsible && !node.collapsed); + this.treeElementHasParent.set(!!tree.getParentElement(focus)); + this.treeElementCanExpand.set(node.collapsible && node.collapsed); + this.treeElementHasChild.set(!!tree.getFirstElementChild(focus)); + }; + this.disposables.push( this.contextKeyService, (listService as ListService).register(tree), @@ -1150,7 +1177,10 @@ class WorkbenchTreeInternals { const focus = tree.getFocus(); this.hasSelectionOrFocus.set(selection.length > 0 || focus.length > 0); + updateCollapseContextKeys(); }), + tree.onDidChangeCollapseState(updateCollapseContextKeys), + tree.onDidChangeModel(updateCollapseContextKeys), configurationService.onDidChangeConfiguration(e => { let newOptions: IAbstractTreeOptionsUpdate = {}; if (e.affectsConfiguration(multiSelectModifierSettingKey)) { diff --git a/src/vs/workbench/browser/actions/listCommands.ts b/src/vs/workbench/browser/actions/listCommands.ts index 9d0eae69b5e..c63f37a25ac 100644 --- a/src/vs/workbench/browser/actions/listCommands.ts +++ b/src/vs/workbench/browser/actions/listCommands.ts @@ -7,7 +7,7 @@ import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { List } from 'vs/base/browser/ui/list/listWidget'; -import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation } from 'vs/platform/list/browser/listService'; +import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent, WorkbenchListWidget, WorkbenchListSelectionNavigation, WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent, WorkbenchTreeElementHasChild, WorkbenchTreeElementCanExpand } from 'vs/platform/list/browser/listService'; import { PagedList } from 'vs/base/browser/ui/list/listPaging'; import { equals, range } from 'vs/base/common/arrays'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -252,7 +252,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'list.collapse', weight: KeybindingWeight.WorkbenchContrib, - when: WorkbenchListFocusContextKey, + when: ContextKeyExpr.and(WorkbenchListFocusContextKey, ContextKeyExpr.or(WorkbenchTreeElementCanCollapse, WorkbenchTreeElementHasParent)), primary: KeyCode.LeftArrow, mac: { primary: KeyCode.LeftArrow, @@ -336,7 +336,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'list.expand', weight: KeybindingWeight.WorkbenchContrib, - when: WorkbenchListFocusContextKey, + when: ContextKeyExpr.and(WorkbenchListFocusContextKey, ContextKeyExpr.or(WorkbenchTreeElementCanExpand, WorkbenchTreeElementHasChild)), primary: KeyCode.RightArrow, handler: (accessor) => { const widget = accessor.get(IListService).lastFocusedList;