Skip to content

Commit df4efc5

Browse files
Expand all button in tree views (#1276)
* Added expand all util function * Added expand-all command for notes explorer * Added expand-all command for placeholder tree view * Added expand-all in tags explorer * Added id field to tree items to make `reveal` work for all items
1 parent 1e2b3b1 commit df4efc5

File tree

5 files changed

+142
-8
lines changed

5 files changed

+142
-8
lines changed

packages/foam-vscode/package.json

+42
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@
152152
"when": "view == foam-vscode.tags-explorer && foam-vscode.views.tags-explorer.group-by == 'folder'",
153153
"group": "navigation"
154154
},
155+
{
156+
"command": "foam-vscode.views.tags-explorer.expand-all",
157+
"when": "view == foam-vscode.tags-explorer",
158+
"group": "navigation"
159+
},
155160
{
156161
"command": "foam-vscode.views.placeholders.show:for-current-file",
157162
"when": "view == foam-vscode.placeholders && foam-vscode.views.placeholders.show == 'all'",
@@ -172,6 +177,11 @@
172177
"when": "view == foam-vscode.placeholders && foam-vscode.views.placeholders.group-by == 'folder'",
173178
"group": "navigation"
174179
},
180+
{
181+
"command": "foam-vscode.views.placeholders.expand-all",
182+
"when": "view == foam-vscode.placeholders",
183+
"group": "navigation"
184+
},
175185
{
176186
"command": "foam-vscode.views.notes-explorer.show:notes",
177187
"when": "view == foam-vscode.notes-explorer && foam-vscode.views.notes-explorer.show == 'all'",
@@ -181,6 +191,11 @@
181191
"command": "foam-vscode.views.notes-explorer.show:all",
182192
"when": "view == foam-vscode.notes-explorer && foam-vscode.views.notes-explorer.show == 'notes-only'",
183193
"group": "navigation"
194+
},
195+
{
196+
"command": "foam-vscode.views.notes-explorer.expand-all",
197+
"when": "view == foam-vscode.notes-explorer",
198+
"group": "navigation"
184199
}
185200
],
186201
"commandPalette": [
@@ -228,6 +243,10 @@
228243
"command": "foam-vscode.views.tags-explorer.group-by:off",
229244
"when": "false"
230245
},
246+
{
247+
"command": "foam-vscode.views.tags-explorer.expand-all",
248+
"when": "false"
249+
},
231250
{
232251
"command": "foam-vscode.views.placeholders.show:for-current-file",
233252
"when": "false"
@@ -244,6 +263,10 @@
244263
"command": "foam-vscode.views.placeholders.group-by:off",
245264
"when": "false"
246265
},
266+
{
267+
"command": "foam-vscode.views.placeholders.expand-all",
268+
"when": "false"
269+
},
247270
{
248271
"command": "foam-vscode.views.notes-explorer.show:all",
249272
"when": "false"
@@ -252,6 +275,10 @@
252275
"command": "foam-vscode.views.notes-explorer.show:notes",
253276
"when": "false"
254277
},
278+
{
279+
"command": "foam-vscode.views.notes-explorer.expand-all",
280+
"when": "false"
281+
},
255282
{
256283
"command": "foam-vscode.open-resource",
257284
"when": "false"
@@ -364,6 +391,11 @@
364391
"title": "Flat list",
365392
"icon": "$(list-flat)"
366393
},
394+
{
395+
"command": "foam-vscode.views.tags-explorer.expand-all",
396+
"title": "Expand all",
397+
"icon": "$(expand-all)"
398+
},
367399
{
368400
"command": "foam-vscode.views.placeholders.show:for-current-file",
369401
"title": "Show placeholders in current file",
@@ -384,11 +416,21 @@
384416
"title": "Flat list",
385417
"icon": "$(list-flat)"
386418
},
419+
{
420+
"command": "foam-vscode.views.placeholders.expand-all",
421+
"title": "Expand all",
422+
"icon": "$(expand-all)"
423+
},
387424
{
388425
"command": "foam-vscode.views.notes-explorer.show:all",
389426
"title": "Show all resources",
390427
"icon": "$(files)"
391428
},
429+
{
430+
"command": "foam-vscode.views.notes-explorer.expand-all",
431+
"title": "Expand all",
432+
"icon": "$(expand-all)"
433+
},
392434
{
393435
"command": "foam-vscode.views.notes-explorer.show:notes",
394436
"title": "Show only notes",

packages/foam-vscode/src/features/panels/notes-explorer.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ResourceRangeTreeItem,
66
ResourceTreeItem,
77
createBacklinkItemsForResource as createBacklinkTreeItemsForResource,
8+
expandAll,
89
} from './utils/tree-view-utils';
910
import { Resource } from '../../core/model/note';
1011
import { FoamGraph } from '../../core/model/graph';
@@ -60,6 +61,11 @@ export default async function activate(
6061
foam.graph.onDidUpdate(() => {
6162
provider.refresh();
6263
}),
64+
vscode.commands.registerCommand(
65+
`foam-vscode.views.notes-explorer.expand-all`,
66+
(...args) =>
67+
expandAll(treeView, provider, node => node.contextValue === 'folder')
68+
),
6369
vscode.window.onDidChangeActiveTextEditor(revealTextEditorItem),
6470
treeView.onDidChangeVisibility(revealTextEditorItem)
6571
);
@@ -138,30 +144,31 @@ export class NotesProvider extends FolderTreeProvider<
138144
value: Resource,
139145
parent: FolderTreeItem<Resource>
140146
): NotesTreeItems {
141-
const res = new ResourceTreeItem(value, this.workspace, {
147+
const item = new ResourceTreeItem(value, this.workspace, {
142148
parent,
143149
collapsibleState:
144150
this.graph.getBacklinks(value.uri).length > 0
145151
? vscode.TreeItemCollapsibleState.Collapsed
146152
: vscode.TreeItemCollapsibleState.None,
147153
});
148-
res.getChildren = async () => {
154+
item.id = value.uri.toString();
155+
item.getChildren = async () => {
149156
const backlinks = await createBacklinkTreeItemsForResource(
150157
this.workspace,
151158
this.graph,
152-
res.uri
159+
item.uri
153160
);
154161
backlinks.forEach(item => {
155162
item.description = item.label;
156163
item.label = item.resource.title;
157164
});
158165
return backlinks;
159166
};
160-
res.description =
167+
item.description =
161168
value.uri.getName().toLocaleLowerCase() ===
162169
value.title.toLocaleLowerCase()
163170
? undefined
164171
: value.uri.getBasename();
165-
return res;
172+
return item;
166173
}
167174
}

packages/foam-vscode/src/features/panels/placeholders.ts

+14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { GroupedResourcesTreeDataProvider } from './utils/grouped-resources-tree
66
import {
77
UriTreeItem,
88
createBacklinkItemsForResource,
9+
expandAll,
910
groupRangesByResource,
1011
} from './utils/tree-view-utils';
1112
import { IMatcher } from '../../core/services/datastore';
@@ -47,6 +48,17 @@ export default async function activate(
4748
provider.onDidChangeTreeData(() => {
4849
treeView.title = baseTitle + ` (${provider.nValues})`;
4950
}),
51+
vscode.commands.registerCommand(
52+
`foam-vscode.views.placeholders.expand-all`,
53+
() =>
54+
expandAll(
55+
treeView,
56+
provider,
57+
node =>
58+
node.contextValue === 'placeholder' ||
59+
node.contextValue === 'folder'
60+
)
61+
),
5062
vscode.window.onDidChangeActiveTextEditor(() => {
5163
if (provider.show.get() === 'for-current-file') {
5264
provider.refresh();
@@ -92,6 +104,8 @@ export class PlaceholderTreeView extends GroupedResourcesTreeDataProvider {
92104
parent,
93105
collapsibleState: vscode.TreeItemCollapsibleState.Collapsed,
94106
});
107+
item.contextValue = 'placeholder';
108+
item.id = uri.toString();
95109
item.getChildren = async () => {
96110
return groupRangesByResource(
97111
this.workspace,

packages/foam-vscode/src/features/panels/tags-explorer.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { FoamTags } from '../../core/model/tags';
66
import {
77
ResourceRangeTreeItem,
88
ResourceTreeItem,
9+
expandAll,
910
groupRangesByResource,
1011
} from './utils/tree-view-utils';
1112
import {
@@ -44,12 +45,21 @@ export default async function activate(
4445
if (provider.show.get() === 'for-current-file') {
4546
provider.refresh();
4647
}
47-
})
48+
}),
49+
vscode.commands.registerCommand(
50+
`foam-vscode.views.${provider.providerId}.expand-all`,
51+
() =>
52+
expandAll(
53+
treeView,
54+
provider,
55+
node => node.contextValue === 'tag' || node.contextValue === 'folder'
56+
)
57+
)
4858
);
4959
}
5060

5161
export class TagsProvider extends FolderTreeProvider<TagTreeItem, string> {
52-
private providerId = 'tags-explorer';
62+
public providerId = 'tags-explorer';
5363
public show = new ContextMemento<'all' | 'for-current-file'>(
5464
new MapBasedMemento(),
5565
`foam-vscode.views.${this.providerId}.show`,
@@ -178,7 +188,12 @@ export class TagsProvider extends FolderTreeProvider<TagTreeItem, string> {
178188
);
179189
return [...acc, ...items];
180190
}, []);
181-
const resources = await groupRangesByResource(this.workspace, resourceTags);
191+
const resources = (
192+
await groupRangesByResource(this.workspace, resourceTags)
193+
).map(item => {
194+
item.id = element.tag + ' / ' + item.uri.toString();
195+
return item;
196+
});
182197

183198
return [...subtags, ...resources];
184199
}
@@ -197,6 +212,7 @@ export class TagItem extends FolderTreeItem<string> {
197212
) {
198213
super(node, node.path.slice(-1)[0], parentElement);
199214
this.tag = node.path.join(TAG_SEPARATOR);
215+
this.id = this.tag;
200216
this.description = `${nResourcesInSubtree} reference${
201217
nResourcesInSubtree !== 1 ? 's' : ''
202218
}`;

packages/foam-vscode/src/features/panels/utils/tree-view-utils.ts

+55
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { getNoteTooltip } from '../../../utils';
99
import { isSome } from '../../../core/utils';
1010
import { getBlockFor } from '../../../core/services/markdown-parser';
1111
import { Connection, FoamGraph } from '../../../core/model/graph';
12+
import { Logger } from '../../../core/utils/log';
1213

1314
export class BaseTreeItem extends vscode.TreeItem {
1415
resolveTreeItem(): Promise<vscode.TreeItem> {
@@ -227,3 +228,57 @@ export function createConnectionItemsForResource(
227228
});
228229
return Promise.all(backlinkItems);
229230
}
231+
232+
/**
233+
* Expands a node and its children in a tree view that match a given predicate
234+
*
235+
* @param treeView - The tree view to expand nodes in
236+
* @param provider - The tree data provider for the view
237+
* @param element - The element to expand
238+
* @param when - A function that returns true if the node should be expanded
239+
*/
240+
export async function expandNode<T>(
241+
treeView: vscode.TreeView<any>,
242+
provider: vscode.TreeDataProvider<T>,
243+
element: T,
244+
when: (element: T) => boolean
245+
) {
246+
try {
247+
if (when(element)) {
248+
await treeView.reveal(element, {
249+
select: false,
250+
focus: false,
251+
expand: true,
252+
});
253+
}
254+
} catch (e) {
255+
const obj = element as any;
256+
const label = obj.label ?? obj.toString();
257+
Logger.warn(
258+
`Could not expand element: ${label}. Try setting the ID property of the TreeItem`
259+
);
260+
}
261+
262+
const children = await provider.getChildren(element);
263+
for (const child of children) {
264+
await expandNode(treeView, provider, child, when);
265+
}
266+
}
267+
268+
/**
269+
* Expands all items in a tree view that match a given predicate
270+
*
271+
* @param treeView - The tree view to expand items in
272+
* @param provider - The tree data provider for the view
273+
* @param when - A function that returns true if the node should be expanded
274+
*/
275+
export async function expandAll<T>(
276+
treeView: vscode.TreeView<T>,
277+
provider: vscode.TreeDataProvider<T>,
278+
when: (element: T) => boolean = () => true
279+
) {
280+
const elements = await provider.getChildren(undefined);
281+
for (const element of elements) {
282+
await expandNode(treeView, provider, element, when);
283+
}
284+
}

0 commit comments

Comments
 (0)