@@ -4,11 +4,15 @@ import * as ra from "./lsp_ext";
4
4
5
5
import { Config , substituteVariablesInEnv , substituteVSCodeVariables } from "./config" ;
6
6
import { createClient } from "./client" ;
7
- import { isRustEditor , log , RustEditor } from "./util" ;
7
+ import { isRustDocument , isRustEditor , log , RustEditor } from "./util" ;
8
8
import { ServerStatusParams } from "./lsp_ext" ;
9
9
import { PersistentState } from "./persistent_state" ;
10
10
import { bootstrap } from "./bootstrap" ;
11
11
12
+ // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
13
+ // only those are in use. We use "Empty" to represent these scenarios
14
+ // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
15
+
12
16
export type Workspace =
13
17
| { kind : "Empty" }
14
18
| {
@@ -19,6 +23,24 @@ export type Workspace =
19
23
files : vscode . TextDocument [ ] ;
20
24
} ;
21
25
26
+ export function fetchWorkspace ( ) : Workspace {
27
+ const folders = ( vscode . workspace . workspaceFolders || [ ] ) . filter (
28
+ ( folder ) => folder . uri . scheme === "file"
29
+ ) ;
30
+ const rustDocuments = vscode . workspace . textDocuments . filter ( ( document ) =>
31
+ isRustDocument ( document )
32
+ ) ;
33
+
34
+ return folders . length === 0
35
+ ? rustDocuments . length === 0
36
+ ? { kind : "Empty" }
37
+ : {
38
+ kind : "Detached Files" ,
39
+ files : rustDocuments ,
40
+ }
41
+ : { kind : "Workspace Folder" } ;
42
+ }
43
+
22
44
export type CommandFactory = {
23
45
enabled : ( ctx : CtxInit ) => Cmd ;
24
46
disabled ?: ( ctx : Ctx ) => Cmd ;
@@ -75,6 +97,31 @@ export class Ctx {
75
97
this . commandDisposables . forEach ( ( disposable ) => disposable . dispose ( ) ) ;
76
98
}
77
99
100
+ async onWorkspaceFolderChanges ( ) {
101
+ const workspace = fetchWorkspace ( ) ;
102
+ if ( workspace . kind === "Detached Files" && this . workspace . kind === "Detached Files" ) {
103
+ if ( workspace . files !== this . workspace . files ) {
104
+ if ( this . client ?. isRunning ( ) ) {
105
+ // Ideally we wouldn't need to tear down the server here, but currently detached files
106
+ // are only specified at server start
107
+ await this . stopAndDispose ( ) ;
108
+ await this . start ( ) ;
109
+ }
110
+ return ;
111
+ }
112
+ }
113
+ if ( workspace . kind === "Workspace Folder" && this . workspace . kind === "Workspace Folder" ) {
114
+ return ;
115
+ }
116
+ if ( workspace . kind === "Empty" ) {
117
+ await this . stopAndDispose ( ) ;
118
+ return ;
119
+ }
120
+ if ( this . client ?. isRunning ( ) ) {
121
+ await this . restart ( ) ;
122
+ }
123
+ }
124
+
78
125
private async getOrCreateClient ( ) {
79
126
if ( this . workspace . kind === "Empty" ) {
80
127
return ;
@@ -143,8 +190,8 @@ export class Ctx {
143
190
return this . _client ;
144
191
}
145
192
146
- async activate ( ) {
147
- log . info ( "Activating language client" ) ;
193
+ async start ( ) {
194
+ log . info ( "Starting language client" ) ;
148
195
const client = await this . getOrCreateClient ( ) ;
149
196
if ( ! client ) {
150
197
return ;
@@ -153,20 +200,26 @@ export class Ctx {
153
200
this . updateCommands ( ) ;
154
201
}
155
202
156
- async deactivate ( ) {
203
+ async restart ( ) {
204
+ // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
205
+ await this . stopAndDispose ( ) ;
206
+ await this . start ( ) ;
207
+ }
208
+
209
+ async stop ( ) {
157
210
if ( ! this . _client ) {
158
211
return ;
159
212
}
160
- log . info ( "Deactivating language client" ) ;
213
+ log . info ( "Stopping language client" ) ;
161
214
this . updateCommands ( "disable" ) ;
162
215
await this . _client . stop ( ) ;
163
216
}
164
217
165
- async stop ( ) {
218
+ async stopAndDispose ( ) {
166
219
if ( ! this . _client ) {
167
220
return ;
168
221
}
169
- log . info ( "Stopping language client" ) ;
222
+ log . info ( "Disposing language client" ) ;
170
223
this . updateCommands ( "disable" ) ;
171
224
await this . disposeClient ( ) ;
172
225
}
0 commit comments