1+ /*---------------------------------------------------------------------------------------------
2+ * Copyright (c) Microsoft Corporation. All rights reserved.
3+ * Licensed under the MIT License. See License.txt in the project root for license information.
4+ *--------------------------------------------------------------------------------------------*/
5+
6+ import { IDisposable } from 'vs/base/common/lifecycle' ;
7+ import { ViewsRegistry , IViewDescriptor , ViewLocation } from 'vs/workbench/common/views' ;
8+ import { IContextKeyService , IContextKeyChangeEvent , IReadableSet } from 'vs/platform/contextkey/common/contextkey' ;
9+ import { Event , chain , filterEvent , Emitter } from 'vs/base/common/event' ;
10+ import { binarySearch , findFirst } from 'vs/base/common/arrays' ;
11+ import { ISplice } from 'vs/base/common/sequence' ;
12+
13+ function filterViewEvent ( location : ViewLocation , event : Event < IViewDescriptor [ ] > ) : Event < IViewDescriptor [ ] > {
14+ return chain ( event )
15+ . map ( views => views . filter ( view => view . location === location ) )
16+ . filter ( views => views . length > 0 )
17+ . event ;
18+ }
19+
20+ class CounterSet < T > implements IReadableSet < T > {
21+
22+ private map = new Map < T , number > ( ) ;
23+
24+ add ( value : T ) : CounterSet < T > {
25+ this . map . set ( value , ( this . map . get ( value ) || 0 ) + 1 ) ;
26+ return this ;
27+ }
28+
29+ delete ( value : T ) : boolean {
30+ let counter = this . map . get ( value ) || 0 ;
31+
32+ if ( counter === 0 ) {
33+ return false ;
34+ }
35+
36+ counter -- ;
37+
38+ if ( counter === 0 ) {
39+ this . map . delete ( value ) ;
40+ } else {
41+ this . map . set ( value , counter ) ;
42+ }
43+
44+ return true ;
45+ }
46+
47+ has ( value : T ) : boolean {
48+ return this . map . has ( value ) ;
49+ }
50+ }
51+
52+ export interface IView {
53+ collapsed : boolean ;
54+ }
55+
56+ export interface IViewItem {
57+ viewDescriptor : IViewDescriptor ;
58+ visible : boolean ;
59+ }
60+
61+ function compareViewDescriptors ( a : IViewDescriptor , b : IViewDescriptor ) : number {
62+ if ( typeof a . order !== 'number' ) {
63+ return 1 ;
64+ } else if ( typeof b . order !== 'number' ) {
65+ return - 1 ;
66+ }
67+
68+ return a . order - b . order ;
69+ }
70+
71+ function compareViewItems ( a : IViewItem , b : IViewItem ) : number {
72+ return compareViewDescriptors ( a . viewDescriptor , b . viewDescriptor ) ;
73+ }
74+
75+ export class ContributableViews {
76+
77+ private contextKeys = new CounterSet < string > ( ) ;
78+ private items : IViewItem [ ] = [ ] ;
79+ private disposables : IDisposable [ ] = [ ] ;
80+
81+ private _onDidSplice = new Emitter < ISplice < IViewDescriptor > > ( ) ;
82+ readonly onDidSplice : Event < ISplice < IViewDescriptor > > = this . _onDidSplice . event ;
83+
84+ get viewDescriptors ( ) : IViewDescriptor [ ] {
85+ return this . items
86+ . filter ( i => i . visible )
87+ . map ( i => i . viewDescriptor ) ;
88+ }
89+
90+ constructor (
91+ location : ViewLocation ,
92+ @IContextKeyService private contextKeyService : IContextKeyService
93+ ) {
94+ const onRelevantViewsRegistered = filterViewEvent ( location , ViewsRegistry . onViewsRegistered ) ;
95+ onRelevantViewsRegistered ( this . onViewsRegistered , this , this . disposables ) ;
96+
97+ const onRelevantViewsDeregistered = filterViewEvent ( location , ViewsRegistry . onViewsDeregistered ) ;
98+ onRelevantViewsDeregistered ( this . onViewsDeregistered , this , this . disposables ) ;
99+
100+ const onRelevantContextChange = filterEvent ( contextKeyService . onDidChangeContext , e => e . affectsSome ( this . contextKeys ) ) ;
101+ onRelevantContextChange ( this . onContextChanged , this ) ;
102+
103+ this . onViewsRegistered ( ViewsRegistry . getViews ( location ) ) ;
104+ }
105+
106+ private onViewsRegistered ( viewDescriptors : IViewDescriptor [ ] ) : any {
107+ for ( const viewDescriptor of viewDescriptors ) {
108+ const item = {
109+ viewDescriptor,
110+ visible : this . canViewDescriptorBeVisible ( viewDescriptor ) // TODO: should read from some state?
111+ } ;
112+
113+ let index = binarySearch ( this . items , item , compareViewItems ) ;
114+ console . log ( 'GOT INDEX' , index , ~ index ) ;
115+
116+ // insert this new view descriptor at the end of same order view descriptors
117+ if ( index < 0 ) {
118+ index = ~ index ;
119+
120+ while ( index < this . items . length && compareViewItems ( this . items [ index ] , item ) === 0 ) {
121+ index ++ ;
122+ }
123+ }
124+
125+ this . items . splice ( index , 0 , item ) ;
126+
127+ if ( viewDescriptor . when ) {
128+ for ( const key of viewDescriptor . when . keys ( ) ) {
129+ this . contextKeys . add ( key ) ;
130+ }
131+ }
132+
133+ if ( item . visible ) {
134+ this . _onDidSplice . fire ( { start : index , deleteCount : 0 , toInsert : [ viewDescriptor ] } ) ;
135+ }
136+ }
137+ }
138+
139+ private onViewsDeregistered ( viewDescriptors : IViewDescriptor [ ] ) : any {
140+ for ( const viewDescriptor of viewDescriptors ) {
141+ const index = findFirst ( this . items , i => i . viewDescriptor . id === viewDescriptor . id ) ;
142+
143+ if ( index === - 1 ) {
144+ continue ;
145+ }
146+
147+ const item = this . items [ index ] ;
148+ this . items . splice ( index , 1 ) ;
149+
150+ if ( viewDescriptor . when ) {
151+ for ( const key of viewDescriptor . when . keys ( ) ) {
152+ this . contextKeys . delete ( key ) ;
153+ }
154+ }
155+
156+ if ( item . visible ) {
157+ this . _onDidSplice . fire ( { start : index , deleteCount : 1 , toInsert : [ ] } ) ;
158+ }
159+ }
160+ }
161+
162+ private onContextChanged ( event : IContextKeyChangeEvent ) : any {
163+ let index = 0 ;
164+
165+ for ( const item of this . items ) {
166+ const visible = this . canViewDescriptorBeVisible ( item . viewDescriptor ) ;
167+
168+ if ( item . visible === visible ) {
169+ if ( visible ) {
170+ index ++ ;
171+ }
172+
173+ continue ;
174+ }
175+
176+ if ( visible ) { // show
177+ this . _onDidSplice . fire ( { start : index , deleteCount : 0 , toInsert : [ item . viewDescriptor ] } ) ;
178+ index ++ ;
179+ } else { // hide
180+ this . _onDidSplice . fire ( { start : index , deleteCount : 1 , toInsert : [ ] } ) ;
181+ }
182+
183+ item . visible = visible ;
184+ }
185+ }
186+
187+ private canViewDescriptorBeVisible ( viewDescriptor : IViewDescriptor ) : boolean {
188+ return this . contextKeyService . contextMatchesRules ( viewDescriptor . when ) ;
189+ }
190+ }
0 commit comments