Change:
Hello, as of now it is possible to conveniently collapse all tree nodes using the "collapse all" button in the action toolbar of the tree view. However, there is no button for the opposite action ("expand all"). One solution would be to make this button into a toggle. And I suppose that I am not the only one who tried to click the collapse all button again to expand the whole tree again, so it would be quite a natural user experience I suppose. Is there already an Issue regarding this? I couldn't find one for the life of me. Basically we need for the explorer.
(Experimental duplicate detection) Thanks for submitting this issue. Please also check if it is already covered by an existing one, like: <!-- score: 0.506 --- <!-- score: 0.479 --- <!-- score: 0.475 --<!-- potentialduplicatescomment --
Discussed in
This is a fair feature request which I like, however we do not have it on our immediate plan. Thus assigning to backlog candidates and we might add this in the future. Thanks
<!-- -96bd-47a8-a0e8- --This feature request is now a candidate for our backlog. The community has 60 days to upvote the issue. If it receives 20 upvotes we will move it to our backlog. If not, we will close it. To learn more about how we handle feature requests, please see our . Happy Coding!
Not so sure, but this may be useful, even for only see that there is a useful feature waiting to be implemented. I see another possibility which may be very useful (at least to me) while avoiding unintended performance problems, when there are so many files: When i type in the Explorer then I can quickly jump to matching files. When I then click on this unfortunately shows only files in already opened folders. To me this is unexpected, as I want to filter from all my files. Maybe when using this toggle the explorer can be populated fully for this search, while keeping the toggle state in the explorer. Thanks
I think this is also applicable to the Variable section when debugging. If the variable I'm analyzing is an array or object, I have to manually open every single entry. It would be much more convenient if there was an 'Expand All' button that opens each entry of the object/array. The image below describes what I mean: ! It would be very nice if there was an 'Expand All' button on every expandable (root) variable. In fact, this feature is present in other IDEs.
for what it's worth, i'd love to see this as well - the lack of an "expand all" control is real pain when flitting between large projects that all have their odd deeply-nested structures
Without this enhancement, the feature does not scale well. Would also be nice if we could Copy the list, then Paste it into Excel (tab-delimited, not comma-delimited). Presently we cannot Copy the list at all. :-( GeneMi (= MightyPen)
+1 to this in general and if possible add option called or something like that: 2-click on a file it opens it editor panel and collapse any other folder open in the folder explorer ! 2-click on any file in the editor does the same (only the folder to which the files belongs is expanded all the rest are collapsed)
Alt-Click on the Collapse-All button could toggle it to expand either one or all layers.
Any news?
Hello I've given this a go by mimicking the search behaviour of swapping between an "Expand All" and "Collapse All" depending on the explorer state. Feel free to leave any feedback on the behaviour/code
Reopening this as there are some UX questions for expand all left. The toggle button seems great but file systems are async. Whether it be going to a remote resource, or cyclical symlinks expansion of all nodes can be very expensive. From my understand the largest use case here is filtering?
Tree views currently support the showCollapseAll option (Whether to show collapse all action or not). It would be nice if there was an analogous showExpandAll option like in ?
Mind sharing the use case you have in mind for expand all? I'm trying to better understand so I can implement the feature well. Wouldn't a fully expanded tree be super noisy?
We'd like to expand all top-level elements one level deep. Allowing extensions to specify might avoid having noisy trees. Our use case is to display the details of user's latest pipelines in their CI. Tree is paginated anyway to it limits noisiness. Today, extensions that are willing to have expandAll must also implement collapseAll, because the  setting cannot be changed after the tree view creation: extensions cannot use only when at least one item is collapsible. Because the opposite of reveal() does not exist (no API yet), and because vscode only takes into account for new items only, implementing collapseAll and expandAll is a tough task. Note that extensions might need to know whether everything is collapsed or expanded in order to consistently populate the TreeItemCollapsibleState of new items.
Maybe I misinterpreted this original issue. It sounds like the request is for a generalized expansion functionality that can be optionally to any tree
Not only super noisy, but costly for some and event impossible for some others. Expanding everything in the Explorer from a large workspace will be very expensive. And async data trees can be infinitely recursive, like a variable inspector showing an object with a circular dependency.
Is there an extension available for this feature now?
I understand we can't have ExpandAll on the explorer, but the request is slightly different: We're requesting a button to expand 1, 2 or 3 levels deep, just like the reveal method Infinite expansion is not requested ExpandAll on the explorer is not requested, the request is only for extension-contributed tree views
Closing this as out of scope as it seems like the root solution to this is actually since the expansion is only necessary to get search to work. If there is an ask for extension contributed views to support expand all please file that separately as this issue seems to be a mix of explorer and all trees making it hard to tackle as they're different items.
We closed this issue because we in the foreseeable future. If you disagree and feel that this issue is crucial: we are happy to listen and to reconsider. If you wonder what we are up to, please see our and . Thanks for your understanding, and happy coding!
I think this should be reconsidered. I disagree with the premise for closing it. For instance, in the test runner I have, there's a tag called "open", which allows me to filter tests that are currently open in the editor. I can combine that with the "failed" tag also to narrow it even further down. Let's say that brings me to 5 different test files that I am currently working on. Because these are nested a lot, I need to manually expand all the tests to see their status at a glance while I am in "Continuous Run Mode", instead of just being able to expand their status directly. With this in mind, I hope you can see that most people here (including those voting on the triage bot comment) have other use-cases in mind.

Discussion:
import * as perf from 'vs/base/common/performance'; import { IAction, WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; <del> import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID, ExplorerResourceNotReadonlyContext } from 'vs/workbench/contrib/files/common/files'; </del> <ins> import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, ExplorerResourceCut, ExplorerResourceMoveableToTrash, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext, ExplorerCompressedLastFocusContext, ExplorerResourceAvailableEditorIdsContext, VIEW_ID, VIEWLET_ID, ExplorerResourceNotReadonlyContext, ViewHasSomeCollapsibleRootItemContext } from 'vs/workbench/contrib/files/common/files'; </ins> import { FileCopiedContext, NEW_FILE_COMMAND_ID, NEW_FOLDER_COMMAND_ID } from 'vs/workbench/contrib/files/browser/fileActions'; import * as DOM from 'vs/base/browser/dom'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';

listDropBackground?: Color; } <del> function hasExpandedRootChild(tree: WorkbenchCompressibleAsyncDataTree<ExplorerItem | ExplorerItem[], ExplorerItem, FuzzyScore>, treeInput: ExplorerItem[]): boolean { for (const folder of treeInput) { if (tree.hasNode(folder) && !tree.isCollapsed(folder)) { for (const [, child] of folder.children.entries()) { if (tree.hasNode(child) && tree.isCollapsible(child) && !tree.isCollapsed(child)) { return true; } </del> <ins> // Accepts a single or multiple workspace folders function hasExpandedRootChild(tree: WorkbenchCompressibleAsyncDataTree<ExplorerItem | ExplorerItem[], ExplorerItem, FuzzyScore>, treeInput: ExplorerItem | ExplorerItem[]): boolean { const inputsToCheck = []; if (Array.isArray(treeInput)) { inputsToCheck.push(...treeInput.filter(folder => tree.hasNode(folder) && !tree.isCollapsed(folder))); } else { inputsToCheck.push(treeInput); } for (const folder of inputsToCheck) { for (const [, child] of folder.children.entries()) { if (tree.hasNode(child) && tree.isCollapsible(child) && !tree.isCollapsed(child)) { return true; </ins> } } }

private compressedFocusFirstContext: IContextKey<boolean>; private compressedFocusLastContext: IContextKey<boolean>; <ins> private viewHasSomeCollapsibleRootItem: IContextKey<boolean>; </ins> private horizontalScrolling: boolean | undefined; private dragHandler!: DelayedDragHandler;

this.compressedFocusContext = ExplorerCompressedFocusContext.bindTo(contextKeyService); this.compressedFocusFirstContext = ExplorerCompressedFirstFocusContext.bindTo(contextKeyService); this.compressedFocusLastContext = ExplorerCompressedLastFocusContext.bindTo(contextKeyService); <ins> this.viewHasSomeCollapsibleRootItem = ViewHasSomeCollapsibleRootItemContext.bindTo(contextKeyService); </ins> this.explorerService.registerView(this); }

} })); <ins> this._register(this.tree.onDidChangeCollapseState(() => this.updateAnyCollapsedContext())); this.updateAnyCollapsedContext(); </ins> this._register(this.tree.onMouseDblClick(e => { if (e.element === null) { // click in empty area -> create a new file #116676

} } <ins> expandAll(): void { if (this.explorerService.isEditable(undefined)) { this.tree.domFocus(); } const treeInput = this.tree.getInput(); if (Array.isArray(treeInput)) { treeInput.forEach(folder => { folder.children.forEach(child => this.tree.hasNode(child) && this.tree.expand(child, true)); }); return; } this.tree.expandAll(); } </ins> collapseAll(): void { if (this.explorerService.isEditable(undefined)) { this.tree.domFocus();

this.compressedFocusLastContext.set(controller.index === controller.count - 1); } <ins> private updateAnyCollapsedContext(): void { const treeInput = this.tree.getInput(); if (treeInput === undefined) { return; } this.viewHasSomeCollapsibleRootItem.set(hasExpandedRootChild(this.tree, treeInput)); } </ins> styleListDropBackground(styles: IExplorerViewStyles): void { const content: string[] = [];

menu: { id: MenuId.ViewTitle, group: 'navigation', <del> when: ContextKeyExpr.equals('view', VIEW_ID), </del> <ins> when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), ViewHasSomeCollapsibleRootItemContext), </ins> order: 40 } });

explorerView.collapseAll(); } }); <ins> registerAction2(class extends Action2 { constructor() { super({ id: 'workbench.files.action.expandExplorerFolders', title: { value: nls.localize('expandExplorerFolders', "Expand Folders in Explorer"), original: 'Expand Folders in Explorer' }, f1: true, icon: Codicon.expandAll, menu: { id: MenuId.ViewTitle, group: 'navigation', when: ContextKeyExpr.and(ContextKeyExpr.equals('view', VIEW_ID), ViewHasSomeCollapsibleRootItemContext.toNegated()), order: 40 } }); } run(accessor: ServicesAccessor) { const viewsService = accessor.get(IViewsService); const explorerView = viewsService.getViewWithId(VIEW_ID) as ExplorerView; explorerView.expandAll(); } }); </ins>

export const ExplorerCompressedFirstFocusContext = new RawContextKey<boolean>('explorerViewletCompressedFirstFocus', true, { type: 'boolean', description: localize('explorerViewletCompressedFirstFocus', "True when the focus is inside a compact item's first part in the EXPLORER view.") }); export const ExplorerCompressedLastFocusContext = new RawContextKey<boolean>('explorerViewletCompressedLastFocus', true, { type: 'boolean', description: localize('explorerViewletCompressedLastFocus', "True when the focus is inside a compact item's last part in the EXPLORER view.") }); <ins> export const ViewHasSomeCollapsibleRootItemContext = new RawContextKey<boolean>('viewHasSomeCollapsibleItem', false, { type: 'boolean', description: localize('viewHasSomeCollapsibleItem', "True when a workspace in the EXPLORER view has some collapsible root child.") }); </ins> export const FilesExplorerFocusCondition = ContextKeyExpr.and(ExplorerViewletVisibleContext, FilesExplorerFocusedContext, ContextKeyExpr.not(InputFocusedContextKey)); export const ExplorerFocusCondition = ContextKeyExpr.and(ExplorerViewletVisibleContext, ExplorerFocusedContext, ContextKeyExpr.not(InputFocusedContextKey));