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 { Event } from 'vs/base/common/event' ;
7+ import { Disposable } from 'vs/base/common/lifecycle' ;
8+ import { IContextKeyService , IContextKey } from 'vs/platform/contextkey/common/contextkey' ;
9+ import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys' ;
10+ import { IWindowConfiguration , IWindowService } from 'vs/platform/windows/common/windows' ;
11+ import { ActiveEditorContext , EditorsVisibleContext , TextCompareEditorVisibleContext , TextCompareEditorActiveContext , ActiveEditorGroupEmptyContext , MultipleEditorGroupsContext , TEXT_DIFF_EDITOR_ID , SplitEditorsVertically } from 'vs/workbench/common/editor' ;
12+ import { IsMacContext , IsLinuxContext , IsWindowsContext , HasMacNativeTabsContext , IsDevelopmentContext , SupportsWorkspacesContext , SupportsOpenFileFolderContext , WorkbenchStateContext , WorkspaceFolderCountContext } from 'vs/workbench/common/contextkeys' ;
13+ import { trackFocus , addDisposableListener , EventType } from 'vs/base/browser/dom' ;
14+ import { preferredSideBySideGroupDirection , GroupDirection , IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService' ;
15+ import { IConfigurationService } from 'vs/platform/configuration/common/configuration' ;
16+ import { IEnvironmentService } from 'vs/platform/environment/common/environment' ;
17+ import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
18+ import { WorkbenchState , IWorkspaceContextService } from 'vs/platform/workspace/common/workspace' ;
19+ import { EditorGroupsServiceImpl } from 'vs/workbench/browser/parts/editor/editor' ;
20+
21+ export class WorkbenchContextKeysHandler extends Disposable {
22+ private inputFocusedContext : IContextKey < boolean > ;
23+ private activeEditorContext : IContextKey < string > ;
24+ private editorsVisibleContext : IContextKey < boolean > ;
25+ private textCompareEditorVisibleContext : IContextKey < boolean > ;
26+ private textCompareEditorActiveContext : IContextKey < boolean > ;
27+ private activeEditorGroupEmpty : IContextKey < boolean > ;
28+ private multipleEditorGroupsContext : IContextKey < boolean > ;
29+ private workbenchStateContext : IContextKey < string > ;
30+ private workspaceFolderCountContext : IContextKey < number > ;
31+ private splitEditorsVerticallyContext : IContextKey < boolean > ;
32+
33+ constructor (
34+ @IContextKeyService private contextKeyService : IContextKeyService ,
35+ @IWorkspaceContextService private contextService : IWorkspaceContextService ,
36+ @IConfigurationService private configurationService : IConfigurationService ,
37+ @IEnvironmentService private environmentService : IEnvironmentService ,
38+ @IWindowService private windowService : IWindowService ,
39+ @IEditorService private editorService : IEditorService ,
40+ @IEditorGroupsService private editorGroupService : EditorGroupsServiceImpl
41+ ) {
42+ super ( ) ;
43+
44+ this . initContextKeys ( ) ;
45+ this . registerListeners ( ) ;
46+ }
47+
48+ private registerListeners ( ) : void {
49+ this . editorGroupService . whenRestored . then ( ( ) => this . updateEditorContextKeys ( ) ) ;
50+
51+ this . _register ( this . editorService . onDidActiveEditorChange ( ( ) => this . updateEditorContextKeys ( ) ) ) ;
52+ this . _register ( this . editorService . onDidVisibleEditorsChange ( ( ) => this . updateEditorContextKeys ( ) ) ) ;
53+ this . _register ( this . editorGroupService . onDidAddGroup ( ( ) => this . updateEditorContextKeys ( ) ) ) ;
54+ this . _register ( this . editorGroupService . onDidRemoveGroup ( ( ) => this . updateEditorContextKeys ( ) ) ) ;
55+
56+ this . _register ( addDisposableListener ( window , EventType . FOCUS_IN , ( ) => this . updateInputContextKeys ( ) , true ) ) ;
57+
58+ this . _register ( this . contextService . onDidChangeWorkbenchState ( ( ) => this . updateWorkbenchStateContextKey ( ) ) ) ;
59+ this . _register ( this . contextService . onDidChangeWorkspaceFolders ( ( ) => this . updateWorkspaceFolderCountContextKey ( ) ) ) ;
60+
61+ this . _register ( this . configurationService . onDidChangeConfiguration ( e => {
62+ if ( e . affectsConfiguration ( 'workbench.editor.openSideBySideDirection' ) ) {
63+ this . updateSplitEditorsVerticallyContext ( ) ;
64+ }
65+ } ) ) ;
66+ }
67+
68+ private initContextKeys ( ) : void {
69+
70+ // Platform
71+ IsMacContext . bindTo ( this . contextKeyService ) ;
72+ IsLinuxContext . bindTo ( this . contextKeyService ) ;
73+ IsWindowsContext . bindTo ( this . contextKeyService ) ;
74+
75+ // macOS Native Tabs
76+ const windowConfig = this . configurationService . getValue < IWindowConfiguration > ( ) ;
77+ HasMacNativeTabsContext . bindTo ( this . contextKeyService ) . set ( windowConfig && windowConfig . window && windowConfig . window . nativeTabs ) ;
78+
79+ // Development
80+ IsDevelopmentContext . bindTo ( this . contextKeyService ) . set ( ! this . environmentService . isBuilt || this . environmentService . isExtensionDevelopment ) ;
81+
82+ // File Pickers
83+ SupportsWorkspacesContext . bindTo ( this . contextKeyService ) ;
84+ SupportsOpenFileFolderContext . bindTo ( this . contextKeyService ) . set ( ! ! this . windowService . getConfiguration ( ) . remoteAuthority ) ;
85+
86+ // Editors
87+ this . activeEditorContext = ActiveEditorContext . bindTo ( this . contextKeyService ) ;
88+ this . editorsVisibleContext = EditorsVisibleContext . bindTo ( this . contextKeyService ) ;
89+ this . textCompareEditorVisibleContext = TextCompareEditorVisibleContext . bindTo ( this . contextKeyService ) ;
90+ this . textCompareEditorActiveContext = TextCompareEditorActiveContext . bindTo ( this . contextKeyService ) ;
91+ this . activeEditorGroupEmpty = ActiveEditorGroupEmptyContext . bindTo ( this . contextKeyService ) ;
92+ this . multipleEditorGroupsContext = MultipleEditorGroupsContext . bindTo ( this . contextKeyService ) ;
93+
94+ // Inputs
95+ this . inputFocusedContext = InputFocusedContext . bindTo ( this . contextKeyService ) ;
96+
97+ // Workbench State
98+ this . workbenchStateContext = WorkbenchStateContext . bindTo ( this . contextKeyService ) ;
99+ this . updateWorkbenchStateContextKey ( ) ;
100+
101+ // Workspace Folder Count
102+ this . workspaceFolderCountContext = WorkspaceFolderCountContext . bindTo ( this . contextKeyService ) ;
103+ this . updateWorkspaceFolderCountContextKey ( ) ;
104+
105+ // Editor Layout
106+ this . splitEditorsVerticallyContext = SplitEditorsVertically . bindTo ( this . contextKeyService ) ;
107+ this . updateSplitEditorsVerticallyContext ( ) ;
108+ }
109+
110+ private updateEditorContextKeys ( ) : void {
111+ const activeControl = this . editorService . activeControl ;
112+ const visibleEditors = this . editorService . visibleControls ;
113+
114+ this . textCompareEditorActiveContext . set ( ! ! activeControl && activeControl . getId ( ) === TEXT_DIFF_EDITOR_ID ) ;
115+ this . textCompareEditorVisibleContext . set ( visibleEditors . some ( control => control . getId ( ) === TEXT_DIFF_EDITOR_ID ) ) ;
116+
117+ if ( visibleEditors . length > 0 ) {
118+ this . editorsVisibleContext . set ( true ) ;
119+ } else {
120+ this . editorsVisibleContext . reset ( ) ;
121+ }
122+
123+ if ( ! this . editorService . activeEditor ) {
124+ this . activeEditorGroupEmpty . set ( true ) ;
125+ } else {
126+ this . activeEditorGroupEmpty . reset ( ) ;
127+ }
128+
129+ if ( this . editorGroupService . count > 1 ) {
130+ this . multipleEditorGroupsContext . set ( true ) ;
131+ } else {
132+ this . multipleEditorGroupsContext . reset ( ) ;
133+ }
134+
135+ if ( activeControl ) {
136+ this . activeEditorContext . set ( activeControl . getId ( ) ) ;
137+ } else {
138+ this . activeEditorContext . reset ( ) ;
139+ }
140+ }
141+
142+ private updateInputContextKeys ( ) : void {
143+
144+ function activeElementIsInput ( ) : boolean {
145+ return ! ! document . activeElement && ( document . activeElement . tagName === 'INPUT' || document . activeElement . tagName === 'TEXTAREA' ) ;
146+ }
147+
148+ const isInputFocused = activeElementIsInput ( ) ;
149+ this . inputFocusedContext . set ( isInputFocused ) ;
150+
151+ if ( isInputFocused ) {
152+ const tracker = trackFocus ( document . activeElement as HTMLElement ) ;
153+ Event . once ( tracker . onDidBlur ) ( ( ) => {
154+ this . inputFocusedContext . set ( activeElementIsInput ( ) ) ;
155+
156+ tracker . dispose ( ) ;
157+ } ) ;
158+ }
159+ }
160+
161+ private updateWorkbenchStateContextKey ( ) : void {
162+ this . workbenchStateContext . set ( this . getWorkbenchStateString ( ) ) ;
163+ }
164+
165+ private updateWorkspaceFolderCountContextKey ( ) : void {
166+ this . workspaceFolderCountContext . set ( this . contextService . getWorkspace ( ) . folders . length ) ;
167+ }
168+
169+ private updateSplitEditorsVerticallyContext ( ) : void {
170+ const direction = preferredSideBySideGroupDirection ( this . configurationService ) ;
171+ this . splitEditorsVerticallyContext . set ( direction === GroupDirection . DOWN ) ;
172+ }
173+
174+ private getWorkbenchStateString ( ) : string {
175+ switch ( this . contextService . getWorkbenchState ( ) ) {
176+ case WorkbenchState . EMPTY : return 'empty' ;
177+ case WorkbenchState . FOLDER : return 'folder' ;
178+ case WorkbenchState . WORKSPACE : return 'workspace' ;
179+ }
180+ }
181+ }
0 commit comments