@@ -19,10 +19,13 @@ import { SwiftOutputChannel } from "./SwiftOutputChannel";
19
19
import { execSwift , getSwiftExecutable , getXCTestPath } from "./utilities" ;
20
20
import { getLLDBLibPath } from "./lldb" ;
21
21
22
- // Context for whole workspace. Holds array of contexts for each workspace folder
23
- // and the ExtensionContext
22
+ /**
23
+ * Context for whole workspace. Holds array of contexts for each workspace folder
24
+ * and the ExtensionContext
25
+ */
24
26
export class WorkspaceContext implements vscode . Disposable {
25
27
public folders : FolderContext [ ] = [ ] ;
28
+ public currentFolder ?: FolderContext ;
26
29
public outputChannel : SwiftOutputChannel ;
27
30
public statusItem : StatusItem ;
28
31
public xcTestPath ?: string ;
@@ -38,8 +41,70 @@ export class WorkspaceContext implements vscode.Disposable {
38
41
this . statusItem . dispose ( ) ;
39
42
}
40
43
41
- // catch workspace folder changes and add/remove folders based on those changes
42
- public async onDidChangeWorkspaceFolders ( event : vscode . WorkspaceFoldersChangeEvent ) {
44
+ /** Setup the vscode event listeners to catch folder changes and active window changes */
45
+ setupEventListeners ( ) {
46
+ // add event listener for when a workspace folder is added/removed
47
+ const onWorkspaceChange = vscode . workspace . onDidChangeWorkspaceFolders ( event => {
48
+ if ( this === undefined ) {
49
+ console . log ( "Trying to run onDidChangeWorkspaceFolders on deleted context" ) ;
50
+ return ;
51
+ }
52
+ this . onDidChangeWorkspaceFolders ( event ) ;
53
+ } ) ;
54
+ // add event listener for when the active edited text document changes
55
+ const onDidChangeActiveWindow = vscode . window . onDidChangeActiveTextEditor ( editor => {
56
+ if ( this === undefined ) {
57
+ console . log ( "Trying to run onDidChangeWorkspaceFolders on deleted context" ) ;
58
+ return ;
59
+ }
60
+
61
+ const workspaceFolder = this . getWorkspaceFolder ( editor ) ;
62
+ if ( workspaceFolder ) {
63
+ this . focusFolder ( workspaceFolder ) ;
64
+ }
65
+ } ) ;
66
+ this . extensionContext . subscriptions . push ( onWorkspaceChange , onDidChangeActiveWindow ) ;
67
+ }
68
+
69
+ /**
70
+ * Fire an event to all folder observers
71
+ * @param folder folder to fire event for
72
+ * @param event event type
73
+ */
74
+ async fireEvent ( folder : FolderContext , event : FolderEvent ) {
75
+ for ( const observer of this . observers ) {
76
+ await observer ( folder , event , this ) ;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * set the focus folder
82
+ * @param folder folder that has gained focus
83
+ */
84
+ async focusFolder ( folder ?: vscode . WorkspaceFolder ) {
85
+ const folderContext = this . folders . find ( context => context . folder === folder ) ;
86
+ if ( folderContext === this . currentFolder ) {
87
+ return ;
88
+ }
89
+
90
+ // send unfocus event for previous folder observers
91
+ if ( this . currentFolder ) {
92
+ await this . fireEvent ( this . currentFolder , FolderEvent . unfocus ) ;
93
+ }
94
+ this . currentFolder = folderContext ;
95
+ if ( ! folderContext ) {
96
+ return ;
97
+ }
98
+
99
+ // send focus event to all observers
100
+ await this . fireEvent ( folderContext , FolderEvent . focus ) ;
101
+ }
102
+
103
+ /**
104
+ * catch workspace folder changes and add or remove folders based on those changes
105
+ * @param event workspace folder event
106
+ */
107
+ async onDidChangeWorkspaceFolders ( event : vscode . WorkspaceFoldersChangeEvent ) {
43
108
for ( const folder of event . added ) {
44
109
await this . addFolder ( folder ) ;
45
110
}
@@ -49,8 +114,11 @@ export class WorkspaceContext implements vscode.Disposable {
49
114
}
50
115
}
51
116
52
- // add folder to workspace
53
- public async addFolder ( folder : vscode . WorkspaceFolder ) {
117
+ /**
118
+ * Called whenever a folder is added to the workspace
119
+ * @param folder folder being added
120
+ */
121
+ async addFolder ( folder : vscode . WorkspaceFolder ) {
54
122
const isRootFolder = this . folders . length === 0 ;
55
123
const folderContext = await FolderContext . create ( folder , isRootFolder , this ) ;
56
124
this . folders . push ( folderContext ) ;
@@ -65,12 +133,21 @@ export class WorkspaceContext implements vscode.Disposable {
65
133
) ;
66
134
}
67
135
}
68
- for ( const observer of this . observers ) {
69
- await observer ( folderContext , "add" ) ;
136
+ await this . fireEvent ( folderContext , FolderEvent . add ) ;
137
+
138
+ // if this is the first folder then set a focus event
139
+ if (
140
+ this . folders . length === 1 ||
141
+ this . getWorkspaceFolder ( vscode . window . activeTextEditor ) === folder
142
+ ) {
143
+ this . focusFolder ( folder ) ;
70
144
}
71
145
}
72
146
73
- // remove folder from workspace
147
+ /**
148
+ * called when a folder is removed from workspace
149
+ * @param folder folder being removed
150
+ */
74
151
async removeFolder ( folder : vscode . WorkspaceFolder ) {
75
152
// find context with root folder
76
153
const index = this . folders . findIndex ( context => context . folder === folder ) ;
@@ -79,23 +156,33 @@ export class WorkspaceContext implements vscode.Disposable {
79
156
return ;
80
157
}
81
158
const context = this . folders [ index ] ;
159
+ // if current folder is this folder send unfocus event by setting
160
+ // current folder to undefined
161
+ if ( this . currentFolder === context ) {
162
+ this . focusFolder ( undefined ) ;
163
+ }
82
164
// run observer functions in reverse order when removing
83
165
const observersReversed = [ ...this . observers ] ;
84
166
observersReversed . reverse ( ) ;
85
167
for ( const observer of observersReversed ) {
86
- await observer ( context , " remove" ) ;
168
+ await observer ( context , FolderEvent . remove , this ) ;
87
169
}
88
170
context . dispose ( ) ;
89
171
// remove context
90
172
this . folders . splice ( index , 1 ) ;
91
173
}
92
174
93
- observerFolders ( fn : WorkspaceFoldersObserver ) : vscode . Disposable {
175
+ /**
176
+ * Add workspace folder event observer
177
+ * @param fn observer function to be called when event occurs
178
+ * @returns disposable object
179
+ */
180
+ observeFolders ( fn : WorkspaceFoldersObserver ) : vscode . Disposable {
94
181
this . observers . add ( fn ) ;
95
182
return { dispose : ( ) => this . observers . delete ( fn ) } ;
96
183
}
97
184
98
- // report swift version and throw error if it failed to find swift
185
+ /** report swift version and throw error if it failed to find swift */
99
186
async reportSwiftVersion ( ) {
100
187
try {
101
188
const { stdout } = await execSwift ( [ "--version" ] ) ;
@@ -106,7 +193,7 @@ export class WorkspaceContext implements vscode.Disposable {
106
193
}
107
194
}
108
195
109
- // find LLDB version and setup path in CodeLLDB
196
+ /** find LLDB version and setup path in CodeLLDB */
110
197
async setLLDBVersion ( ) {
111
198
// don't set LLDB on windows as swift version is not working at the moment
112
199
if ( process . platform === "win32" ) {
@@ -149,10 +236,40 @@ export class WorkspaceContext implements vscode.Disposable {
149
236
} ) ;
150
237
}
151
238
239
+ // return workspace folder from text editor
240
+ private getWorkspaceFolder ( editor ?: vscode . TextEditor ) : vscode . WorkspaceFolder | undefined {
241
+ if ( ! editor || ! editor . document ) {
242
+ return ;
243
+ }
244
+ return vscode . workspace . getWorkspaceFolder ( editor . document . uri ) ;
245
+ }
246
+
152
247
private observers : Set < WorkspaceFoldersObserver > = new Set ( ) ;
153
248
}
154
249
250
+ /** Workspace Folder events */
251
+ export class FolderEvent {
252
+ /** Workspace folder has been added */
253
+ static add = new FolderEvent ( "add" ) ;
254
+ /** Workspace folder has been removed */
255
+ static remove = new FolderEvent ( "remove" ) ;
256
+ /** Workspace folder has gained focus via a file inside the folder becoming the actively edited file */
257
+ static focus = new FolderEvent ( "focus" ) ;
258
+ /** Workspace folder loses focus because another workspace folder gained it */
259
+ static unfocus = new FolderEvent ( "unfocus" ) ;
260
+
261
+ constructor ( private readonly name : string ) {
262
+ this . name = name ;
263
+ }
264
+
265
+ toString ( ) {
266
+ return this . name ;
267
+ }
268
+ }
269
+
270
+ /** Workspace Folder observer function */
155
271
export type WorkspaceFoldersObserver = (
156
272
folder : FolderContext ,
157
- operation : "add" | "remove"
273
+ operation : FolderEvent ,
274
+ workspace : WorkspaceContext
158
275
) => unknown ;
0 commit comments