@@ -22,7 +22,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'
22
22
23
23
type TreeItemHandle = string ;
24
24
25
- function toTreeItemLabel ( label : any , extension : IExtensionDescription ) : ITreeItemLabel {
25
+ function toTreeItemLabel ( label : any , extension : IExtensionDescription ) : ITreeItemLabel | undefined {
26
26
if ( isString ( label ) ) {
27
27
return { label } ;
28
28
}
@@ -31,7 +31,7 @@ function toTreeItemLabel(label: any, extension: IExtensionDescription): ITreeIte
31
31
&& typeof label === 'object'
32
32
&& typeof label . label === 'string' ) {
33
33
checkProposedApiEnabled ( extension ) ;
34
- let highlights : [ number , number ] [ ] = undefined ;
34
+ let highlights : [ number , number ] [ ] | undefined = undefined ;
35
35
if ( Array . isArray ( label . highlights ) ) {
36
36
highlights = ( < [ number , number ] [ ] > label . highlights ) . filter ( ( highlight => highlight . length === 2 && typeof highlight [ 0 ] === 'number' && typeof highlight [ 1 ] === 'number' ) ) ;
37
37
highlights = highlights . length ? highlights : undefined ;
@@ -136,14 +136,15 @@ export class ExtHostTreeViews implements ExtHostTreeViewsShape {
136
136
}
137
137
}
138
138
139
+ type Root = null | undefined ;
140
+ type TreeData < T > = { message : boolean , element : T | Root | false } ;
141
+
139
142
interface TreeNode {
140
143
item : ITreeItem ;
141
- parent : TreeNode ;
142
- children : TreeNode [ ] ;
144
+ parent : TreeNode | Root ;
145
+ children ? : TreeNode [ ] ;
143
146
}
144
147
145
- type TreeData < T > = { message : boolean , element : T | null | undefined | false } ;
146
-
147
148
class ExtHostTreeView < T > extends Disposable {
148
149
149
150
private static LABEL_HANDLE_PREFIX = '0' ;
@@ -159,7 +160,7 @@ class ExtHostTreeView<T> extends Disposable {
159
160
get visible ( ) : boolean { return this . _visible ; }
160
161
161
162
private _selectedHandles : TreeItemHandle [ ] = [ ] ;
162
- get selectedElements ( ) : T [ ] { return this . _selectedHandles . map ( handle => this . getExtensionElement ( handle ) ) . filter ( element => ! isUndefinedOrNull ( element ) ) ; }
163
+ get selectedElements ( ) : T [ ] { return < T [ ] > this . _selectedHandles . map ( handle => this . getExtensionElement ( handle ) ) . filter ( element => ! isUndefinedOrNull ( element ) ) ; }
163
164
164
165
private _onDidExpandElement : Emitter < vscode . TreeViewExpansionEvent < T > > = this . _register ( new Emitter < vscode . TreeViewExpansionEvent < T > > ( ) ) ;
165
166
readonly onDidExpandElement : Event < vscode . TreeViewExpansionEvent < T > > = this . _onDidExpandElement . event ;
@@ -186,7 +187,7 @@ class ExtHostTreeView<T> extends Disposable {
186
187
}
187
188
188
189
let refreshingPromise , promiseCallback ;
189
- this . _register ( Event . debounce < TreeData < T > , { message : boolean , elements : T [ ] } > ( this . _onDidChangeData . event , ( result , current ) => {
190
+ this . _register ( Event . debounce < TreeData < T > , { message : boolean , elements : ( T | Root ) [ ] } > ( this . _onDidChangeData . event , ( result , current ) => {
190
191
if ( ! result ) {
191
192
result = { message : false , elements : [ ] } ;
192
193
}
@@ -214,7 +215,7 @@ class ExtHostTreeView<T> extends Disposable {
214
215
} ) ) ;
215
216
}
216
217
217
- getChildren ( parentHandle ? : TreeItemHandle ) : Promise < ITreeItem [ ] > {
218
+ getChildren ( parentHandle : TreeItemHandle | Root ) : Promise < ITreeItem [ ] > {
218
219
const parentElement = parentHandle ? this . getExtensionElement ( parentHandle ) : undefined ;
219
220
if ( parentHandle && ! parentElement ) {
220
221
console . error ( `No tree item with id \'${ parentHandle } \' found.` ) ;
@@ -226,7 +227,7 @@ class ExtHostTreeView<T> extends Disposable {
226
227
. then ( nodes => nodes . map ( n => n . item ) ) ;
227
228
}
228
229
229
- getExtensionElement ( treeItemHandle : TreeItemHandle ) : T {
230
+ getExtensionElement ( treeItemHandle : TreeItemHandle ) : T | undefined {
230
231
return this . elements . get ( treeItemHandle ) ;
231
232
}
232
233
@@ -295,12 +296,12 @@ class ExtHostTreeView<T> extends Disposable {
295
296
} ) ;
296
297
}
297
298
298
- private resolveParent ( element : T ) : Promise < T > {
299
+ private resolveParent ( element : T ) : Promise < T | Root > {
299
300
const node = this . nodes . get ( element ) ;
300
301
if ( node ) {
301
- return Promise . resolve ( node . parent ? this . elements . get ( node . parent . item . handle ) : null ) ;
302
+ return Promise . resolve ( node . parent ? this . elements . get ( node . parent . item . handle ) : undefined ) ;
302
303
}
303
- return asPromise ( ( ) => this . dataProvider . getParent ( element ) ) ;
304
+ return asPromise ( ( ) => this . dataProvider . getParent ! ( element ) ) ;
304
305
}
305
306
306
307
private resolveTreeNode ( element : T , parent ?: TreeNode ) : Promise < TreeNode > {
@@ -310,7 +311,7 @@ class ExtHostTreeView<T> extends Disposable {
310
311
}
311
312
return asPromise ( ( ) => this . dataProvider . getTreeItem ( element ) )
312
313
. then ( extTreeItem => this . createHandle ( element , extTreeItem , parent , true ) )
313
- . then ( handle => this . getChildren ( parent ? parent . item . handle : null )
314
+ . then ( handle => this . getChildren ( parent ? parent . item . handle : undefined )
314
315
. then ( ( ) => {
315
316
const cachedElement = this . getExtensionElement ( handle ) ;
316
317
if ( cachedElement ) {
@@ -323,16 +324,16 @@ class ExtHostTreeView<T> extends Disposable {
323
324
} ) ) ;
324
325
}
325
326
326
- private getChildrenNodes ( parentNodeOrHandle ? : TreeNode | TreeItemHandle ) : TreeNode [ ] {
327
+ private getChildrenNodes ( parentNodeOrHandle : TreeNode | TreeItemHandle | Root ) : TreeNode [ ] | null {
327
328
if ( parentNodeOrHandle ) {
328
- let parentNode : TreeNode ;
329
+ let parentNode : TreeNode | undefined ;
329
330
if ( typeof parentNodeOrHandle === 'string' ) {
330
331
const parentElement = this . getExtensionElement ( parentNodeOrHandle ) ;
331
- parentNode = parentElement ? this . nodes . get ( parentElement ) : null ;
332
+ parentNode = parentElement ? this . nodes . get ( parentElement ) : undefined ;
332
333
} else {
333
334
parentNode = parentNodeOrHandle ;
334
335
}
335
- return parentNode ? parentNode . children : null ;
336
+ return parentNode ? parentNode . children || null : null ;
336
337
}
337
338
return this . roots ;
338
339
}
@@ -350,13 +351,13 @@ class ExtHostTreeView<T> extends Disposable {
350
351
. then ( coalesce ) ;
351
352
}
352
353
353
- private refresh ( elements : T [ ] ) : Promise < void > {
354
+ private refresh ( elements : ( T | Root ) [ ] ) : Promise < void > {
354
355
const hasRoot = elements . some ( element => ! element ) ;
355
356
if ( hasRoot ) {
356
357
this . clearAll ( ) ; // clear cache
357
358
return this . proxy . $refresh ( this . viewId ) ;
358
359
} else {
359
- const handlesToRefresh = this . getHandlesToRefresh ( elements ) ;
360
+ const handlesToRefresh = this . getHandlesToRefresh ( < T [ ] > elements ) ;
360
361
if ( handlesToRefresh . length ) {
361
362
return this . refreshHandles ( handlesToRefresh ) ;
362
363
}
@@ -370,12 +371,12 @@ class ExtHostTreeView<T> extends Disposable {
370
371
const elementNode = this . nodes . get ( element ) ;
371
372
if ( elementNode && ! elementsToUpdate . has ( elementNode . item . handle ) ) {
372
373
// check if an ancestor of extElement is already in the elements to update list
373
- let currentNode = elementNode ;
374
+ let currentNode : TreeNode | undefined = elementNode ;
374
375
while ( currentNode && currentNode . parent && ! elementsToUpdate . has ( currentNode . parent . item . handle ) ) {
375
376
const parentElement = this . elements . get ( currentNode . parent . item . handle ) ;
376
- currentNode = this . nodes . get ( parentElement ) ;
377
+ currentNode = parentElement ? this . nodes . get ( parentElement ) : undefined ;
377
378
}
378
- if ( ! currentNode . parent ) {
379
+ if ( currentNode && ! currentNode . parent ) {
379
380
elementsToUpdate . add ( elementNode . item . handle ) ;
380
381
}
381
382
}
@@ -385,9 +386,11 @@ class ExtHostTreeView<T> extends Disposable {
385
386
// Take only top level elements
386
387
elementsToUpdate . forEach ( ( handle ) => {
387
388
const element = this . elements . get ( handle ) ;
388
- const node = this . nodes . get ( element ) ;
389
- if ( node && ( ! node . parent || ! elementsToUpdate . has ( node . parent . item . handle ) ) ) {
390
- handlesToUpdate . push ( handle ) ;
389
+ if ( element ) {
390
+ const node = this . nodes . get ( element ) ;
391
+ if ( node && ( ! node . parent || ! elementsToUpdate . has ( node . parent . item . handle ) ) ) {
392
+ handlesToUpdate . push ( handle ) ;
393
+ }
391
394
}
392
395
} ) ;
393
396
@@ -403,25 +406,30 @@ class ExtHostTreeView<T> extends Disposable {
403
406
itemsToRefresh [ treeItemHandle ] = node . item ;
404
407
}
405
408
} ) ) )
406
- . then ( ( ) => Object . keys ( itemsToRefresh ) . length ? this . proxy . $refresh ( this . viewId , itemsToRefresh ) : null ) ;
409
+ . then ( ( ) => Object . keys ( itemsToRefresh ) . length ? this . proxy . $refresh ( this . viewId , itemsToRefresh ) : undefined ) ;
407
410
}
408
411
409
- private refreshNode ( treeItemHandle : TreeItemHandle ) : Promise < TreeNode > {
412
+ private refreshNode ( treeItemHandle : TreeItemHandle ) : Promise < TreeNode | null > {
410
413
const extElement = this . getExtensionElement ( treeItemHandle ) ;
411
- const existing = this . nodes . get ( extElement ) ;
412
- this . clearChildren ( extElement ) ; // clear children cache
413
- return asPromise ( ( ) => this . dataProvider . getTreeItem ( extElement ) )
414
- . then ( extTreeItem => {
415
- if ( extTreeItem ) {
416
- const newNode = this . createTreeNode ( extElement , extTreeItem , existing . parent ) ;
417
- this . updateNodeCache ( extElement , newNode , existing , existing . parent ) ;
418
- return newNode ;
419
- }
420
- return null ;
421
- } ) ;
414
+ if ( extElement ) {
415
+ const existing = this . nodes . get ( extElement ) ;
416
+ if ( existing ) {
417
+ this . clearChildren ( extElement ) ; // clear children cache
418
+ return asPromise ( ( ) => this . dataProvider . getTreeItem ( extElement ) )
419
+ . then ( extTreeItem => {
420
+ if ( extTreeItem ) {
421
+ const newNode = this . createTreeNode ( extElement , extTreeItem , existing . parent ) ;
422
+ this . updateNodeCache ( extElement , newNode , existing , existing . parent ) ;
423
+ return newNode ;
424
+ }
425
+ return null ;
426
+ } ) ;
427
+ }
428
+ }
429
+ return Promise . resolve ( null ) ;
422
430
}
423
431
424
- private createAndRegisterTreeNode ( element : T , extTreeItem : vscode . TreeItem , parentNode : TreeNode ) : TreeNode {
432
+ private createAndRegisterTreeNode ( element : T , extTreeItem : vscode . TreeItem , parentNode : TreeNode | Root ) : TreeNode {
425
433
const node = this . createTreeNode ( element , extTreeItem , parentNode ) ;
426
434
if ( extTreeItem . id && this . elements . has ( node . item . handle ) ) {
427
435
throw new Error ( localize ( 'treeView.duplicateElement' , 'Element with id {0} is already registered' , extTreeItem . id ) ) ;
@@ -431,15 +439,15 @@ class ExtHostTreeView<T> extends Disposable {
431
439
return node ;
432
440
}
433
441
434
- private createTreeNode ( element : T , extensionTreeItem : vscode . TreeItem , parent : TreeNode ) : TreeNode {
442
+ private createTreeNode ( element : T , extensionTreeItem : vscode . TreeItem , parent : TreeNode | Root ) : TreeNode {
435
443
return {
436
444
item : this . createTreeItem ( element , extensionTreeItem , parent ) ,
437
445
parent,
438
446
children : undefined
439
447
} ;
440
448
}
441
449
442
- private createTreeItem ( element : T , extensionTreeItem : vscode . TreeItem , parent ? : TreeNode ) : ITreeItem {
450
+ private createTreeItem ( element : T , extensionTreeItem : vscode . TreeItem , parent : TreeNode | Root ) : ITreeItem {
443
451
444
452
const handle = this . createHandle ( element , extensionTreeItem , parent ) ;
445
453
const icon = this . getLightIconPath ( extensionTreeItem ) ;
@@ -461,7 +469,7 @@ class ExtHostTreeView<T> extends Disposable {
461
469
return item ;
462
470
}
463
471
464
- private createHandle ( element : T , { id, label, resourceUri } : vscode . TreeItem , parent : TreeNode , returnFirst ?: boolean ) : TreeItemHandle {
472
+ private createHandle ( element : T , { id, label, resourceUri } : vscode . TreeItem , parent : TreeNode | Root , returnFirst ?: boolean ) : TreeItemHandle {
465
473
if ( id ) {
466
474
return `${ ExtHostTreeView . ID_HANDLE_PREFIX } /${ id } ` ;
467
475
}
@@ -470,7 +478,7 @@ class ExtHostTreeView<T> extends Disposable {
470
478
const prefix : string = parent ? parent . item . handle : ExtHostTreeView . LABEL_HANDLE_PREFIX ;
471
479
let elementId = treeItemLabel ? treeItemLabel . label : resourceUri ? basename ( resourceUri ) : '' ;
472
480
elementId = elementId . indexOf ( '/' ) !== - 1 ? elementId . replace ( '/' , '//' ) : elementId ;
473
- const existingHandle = this . nodes . has ( element ) ? this . nodes . get ( element ) . item . handle : undefined ;
481
+ const existingHandle = this . nodes . has ( element ) ? this . nodes . get ( element ) ! . item . handle : undefined ;
474
482
const childrenNodes = ( this . getChildrenNodes ( parent ) || [ ] ) ;
475
483
476
484
let handle : TreeItemHandle ;
@@ -489,7 +497,7 @@ class ExtHostTreeView<T> extends Disposable {
489
497
return handle ;
490
498
}
491
499
492
- private getLightIconPath ( extensionTreeItem : vscode . TreeItem ) : URI {
500
+ private getLightIconPath ( extensionTreeItem : vscode . TreeItem ) : URI | undefined {
493
501
if ( extensionTreeItem . iconPath && ! ( extensionTreeItem . iconPath instanceof ThemeIcon ) ) {
494
502
if ( typeof extensionTreeItem . iconPath === 'string'
495
503
|| extensionTreeItem . iconPath instanceof URI ) {
@@ -500,7 +508,7 @@ class ExtHostTreeView<T> extends Disposable {
500
508
return undefined ;
501
509
}
502
510
503
- private getDarkIconPath ( extensionTreeItem : vscode . TreeItem ) : URI {
511
+ private getDarkIconPath ( extensionTreeItem : vscode . TreeItem ) : URI | undefined {
504
512
if ( extensionTreeItem . iconPath && ! ( extensionTreeItem . iconPath instanceof ThemeIcon ) && extensionTreeItem . iconPath [ 'dark' ] ) {
505
513
return this . getIconPath ( extensionTreeItem . iconPath [ 'dark' ] ) ;
506
514
}
@@ -519,7 +527,7 @@ class ExtHostTreeView<T> extends Disposable {
519
527
this . nodes . set ( element , node ) ;
520
528
}
521
529
522
- private updateNodeCache ( element : T , newNode : TreeNode , existing : TreeNode , parentNode : TreeNode ) : void {
530
+ private updateNodeCache ( element : T , newNode : TreeNode , existing : TreeNode , parentNode : TreeNode | Root ) : void {
523
531
// Remove from the cache
524
532
this . elements . delete ( newNode . item . handle ) ;
525
533
this . nodes . delete ( element ) ;
@@ -538,7 +546,7 @@ class ExtHostTreeView<T> extends Disposable {
538
546
}
539
547
}
540
548
541
- private addNodeToParentCache ( node : TreeNode , parentNode : TreeNode ) : void {
549
+ private addNodeToParentCache ( node : TreeNode , parentNode : TreeNode | Root ) : void {
542
550
if ( parentNode ) {
543
551
if ( ! parentNode . children ) {
544
552
parentNode . children = [ ] ;
@@ -555,32 +563,36 @@ class ExtHostTreeView<T> extends Disposable {
555
563
private clearChildren ( parentElement ?: T ) : void {
556
564
if ( parentElement ) {
557
565
const node = this . nodes . get ( parentElement ) ;
558
- if ( node . children ) {
559
- for ( const child of node . children ) {
560
- const childEleement = this . elements . get ( child . item . handle ) ;
561
- if ( childEleement ) {
562
- this . clear ( childEleement ) ;
566
+ if ( node ) {
567
+ if ( node . children ) {
568
+ for ( const child of node . children ) {
569
+ const childEleement = this . elements . get ( child . item . handle ) ;
570
+ if ( childEleement ) {
571
+ this . clear ( childEleement ) ;
572
+ }
563
573
}
564
574
}
575
+ node . children = undefined ;
565
576
}
566
- node . children = undefined ;
567
577
} else {
568
578
this . clearAll ( ) ;
569
579
}
570
580
}
571
581
572
582
private clear ( element : T ) : void {
573
583
const node = this . nodes . get ( element ) ;
574
- if ( node . children ) {
575
- for ( const child of node . children ) {
576
- const childEleement = this . elements . get ( child . item . handle ) ;
577
- if ( childEleement ) {
578
- this . clear ( childEleement ) ;
584
+ if ( node ) {
585
+ if ( node . children ) {
586
+ for ( const child of node . children ) {
587
+ const childEleement = this . elements . get ( child . item . handle ) ;
588
+ if ( childEleement ) {
589
+ this . clear ( childEleement ) ;
590
+ }
579
591
}
580
592
}
593
+ this . nodes . delete ( element ) ;
594
+ this . elements . delete ( node . item . handle ) ;
581
595
}
582
- this . nodes . delete ( element ) ;
583
- this . elements . delete ( node . item . handle ) ;
584
596
}
585
597
586
598
private clearAll ( ) : void {
0 commit comments