@@ -25,14 +25,19 @@ export interface TreeNode<T = unknown> {
25
25
readonly resource : T
26
26
27
27
/**
28
- * A tree item used to display the node in a tree view .
28
+ * An optional event to signal that this node's children has changed .
29
29
*/
30
- readonly treeItem : vscode . TreeItem
30
+ readonly onDidChangeChildren ? : vscode . Event < void >
31
31
32
32
/**
33
- * Optional event to signal that this node's children has changed.
33
+ * An optional event to signal that this node's tree item has changed.
34
34
*/
35
- readonly onDidChangeChildren ?: vscode . Event < void >
35
+ readonly onDidChangeTreeItem ?: vscode . Event < void >
36
+
37
+ /**
38
+ * Returns a tree item used to display the node in a tree view.
39
+ */
40
+ getTreeItem ( ) : Promise < vscode . TreeItem > | vscode . TreeItem
36
41
37
42
/**
38
43
* Optional method to provide child nodes.
@@ -46,38 +51,52 @@ export function isTreeNode(obj: unknown): obj is TreeNode {
46
51
typeof obj === 'object' &&
47
52
'resource' in obj &&
48
53
typeof ( obj as TreeNode ) . id === 'string' &&
49
- ( obj as TreeNode ) . treeItem instanceof vscode . TreeItem
54
+ typeof ( obj as TreeNode ) . getTreeItem === 'function'
50
55
)
51
56
}
52
57
53
58
function copyNode < T > ( id : string , node : Omit < TreeNode < T > , 'id' > ) : TreeNode < T > {
54
59
return {
55
60
id,
56
61
resource : node . resource ,
57
- treeItem : node . treeItem ,
58
62
onDidChangeChildren : node . onDidChangeChildren ,
63
+ onDidChangeTreeItem : node . onDidChangeTreeItem ,
64
+ getTreeItem : node . getTreeItem ?. bind ( node ) ,
59
65
getChildren : node . getChildren ?. bind ( node ) ,
60
66
}
61
67
}
62
68
63
69
export class ResourceTreeDataProvider implements vscode . TreeDataProvider < TreeNode > {
64
- private readonly children : Map < string , TreeNode [ ] > = new Map ( )
65
- private readonly listeners : Map < string , vscode . Disposable > = new Map ( )
70
+ private readonly items = new Map < string , vscode . TreeItem > ( )
71
+ private readonly children = new Map < string , TreeNode [ ] > ( )
72
+ private readonly listeners = new Map < string , vscode . Disposable > ( )
66
73
private readonly onDidChangeTreeDataEmitter = new vscode . EventEmitter < TreeNode | void > ( )
67
74
public readonly onDidChangeTreeData = this . onDidChangeTreeDataEmitter . event
68
75
69
76
public constructor ( private readonly root : Required < Pick < TreeNode , 'getChildren' > > ) { }
70
77
71
- public getTreeItem ( element : TreeNode ) : vscode . TreeItem {
72
- const item = element . treeItem
78
+ public async getTreeItem ( element : TreeNode ) : Promise < vscode . TreeItem > {
79
+ const previousItem = this . items . get ( element . id )
80
+ if ( previousItem ) {
81
+ return previousItem
82
+ }
83
+
84
+ const item = await element . getTreeItem ( )
73
85
item . id = element . id
86
+ this . items . set ( element . id , item )
74
87
75
88
return item
76
89
}
77
90
78
91
public async getChildren ( element ?: TreeNode ) : Promise < TreeNode [ ] > {
79
92
if ( element ) {
80
- this . children . get ( element . id ) ?. forEach ( n => this . clear ( n ) )
93
+ const previousChildren = this . children . get ( element . id )
94
+
95
+ if ( previousChildren !== undefined ) {
96
+ return previousChildren
97
+ } else {
98
+ this . children . get ( element . id ) ?. forEach ( n => this . clear ( n ) )
99
+ }
81
100
}
82
101
83
102
const getId = ( id : string ) => ( element ? `${ element . id } /${ id } ` : id )
@@ -91,6 +110,7 @@ export class ResourceTreeDataProvider implements vscode.TreeDataProvider<TreeNod
91
110
public refresh ( ) : void {
92
111
vscode . Disposable . from ( ...this . listeners . values ( ) ) . dispose ( )
93
112
113
+ this . items . clear ( )
94
114
this . children . clear ( )
95
115
this . listeners . clear ( )
96
116
this . onDidChangeTreeDataEmitter . fire ( )
@@ -99,6 +119,7 @@ export class ResourceTreeDataProvider implements vscode.TreeDataProvider<TreeNod
99
119
private clear ( node : TreeNode ) : void {
100
120
const children = this . children . get ( node . id )
101
121
122
+ this . items . delete ( node . id )
102
123
this . children . delete ( node . id )
103
124
this . listeners . get ( node . id ) ?. dispose ( )
104
125
this . listeners . delete ( node . id )
@@ -108,14 +129,29 @@ export class ResourceTreeDataProvider implements vscode.TreeDataProvider<TreeNod
108
129
109
130
private insert ( id : string , resource : TreeNode ) : TreeNode {
110
131
const node = copyNode ( id , resource )
132
+ const listeners : vscode . Disposable [ ] = [ ]
111
133
112
134
if ( node . onDidChangeChildren ) {
113
- const listener = node . onDidChangeChildren ?.( ( ) => {
114
- this . children . get ( node . id ) ?. forEach ( n => this . clear ( n ) )
115
- this . onDidChangeTreeDataEmitter . fire ( node )
116
- } )
135
+ listeners . push (
136
+ node . onDidChangeChildren ?.( ( ) => {
137
+ this . children . get ( node . id ) ?. forEach ( n => this . clear ( n ) )
138
+ this . children . delete ( node . id )
139
+ this . onDidChangeTreeDataEmitter . fire ( node )
140
+ } )
141
+ )
142
+ }
143
+
144
+ if ( node . onDidChangeTreeItem ) {
145
+ listeners . push (
146
+ node . onDidChangeTreeItem ?.( ( ) => {
147
+ this . items . delete ( node . id )
148
+ this . onDidChangeTreeDataEmitter . fire ( node )
149
+ } )
150
+ )
151
+ }
117
152
118
- this . listeners . set ( id , listener )
153
+ if ( listeners . length !== 0 ) {
154
+ this . listeners . set ( id , vscode . Disposable . from ( ...listeners ) )
119
155
}
120
156
121
157
return node
0 commit comments