@@ -6,12 +6,12 @@ import * as path from 'path';
6
6
import { OutputChannel , Uri } from 'vscode' ;
7
7
import { Disposable , LanguageClient , LanguageClientOptions , ServerOptions } from 'vscode-languageclient' ;
8
8
import { IApplicationShell , ICommandManager , IWorkspaceService } from '../common/application/types' ;
9
+ import { PythonSettings } from '../common/configSettings' ;
9
10
import { isTestExecution , STANDARD_OUTPUT_CHANNEL } from '../common/constants' ;
10
11
import { createDeferred , Deferred } from '../common/helpers' ;
11
12
import { IFileSystem , IPlatformService } from '../common/platform/types' ;
12
13
import { StopWatch } from '../common/stopWatch' ;
13
- import { IConfigurationService , IExtensionContext , IOutputChannel } from '../common/types' ;
14
- import { IInterpreterService } from '../interpreter/contracts' ;
14
+ import { IConfigurationService , IExtensionContext , IOutputChannel , IPythonSettings } from '../common/types' ;
15
15
import { IServiceContainer } from '../ioc/types' ;
16
16
import {
17
17
PYTHON_ANALYSIS_ENGINE_DOWNLOADED ,
@@ -38,7 +38,6 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
38
38
private readonly fs : IFileSystem ;
39
39
private readonly sw = new StopWatch ( ) ;
40
40
private readonly platformData : PlatformData ;
41
- private readonly interpreterService : IInterpreterService ;
42
41
private readonly startupCompleted : Deferred < void > ;
43
42
private readonly disposables : Disposable [ ] = [ ] ;
44
43
private readonly context : IExtensionContext ;
@@ -47,6 +46,8 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
47
46
48
47
private languageClient : LanguageClient | undefined ;
49
48
private interpreterHash : string = '' ;
49
+ private excludedFiles : string [ ] = [ ] ;
50
+ private typeshedPaths : string [ ] = [ ] ;
50
51
private loadExtensionArgs : { } | undefined ;
51
52
52
53
constructor ( @inject ( IServiceContainer ) private readonly services : IServiceContainer ) {
@@ -56,7 +57,6 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
56
57
this . output = this . services . get < OutputChannel > ( IOutputChannel , STANDARD_OUTPUT_CHANNEL ) ;
57
58
this . fs = this . services . get < IFileSystem > ( IFileSystem ) ;
58
59
this . platformData = new PlatformData ( services . get < IPlatformService > ( IPlatformService ) , this . fs ) ;
59
- this . interpreterService = this . services . get < IInterpreterService > ( IInterpreterService ) ;
60
60
this . workspace = this . services . get < IWorkspaceService > ( IWorkspaceService ) ;
61
61
62
62
// Currently only a single root. Multi-root support is future.
@@ -76,6 +76,8 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
76
76
}
77
77
}
78
78
) ) ;
79
+
80
+ ( this . configuration . getSettings ( ) as PythonSettings ) . addListener ( 'change' , this . onSettingsChanged ) ;
79
81
}
80
82
81
83
public async activate ( ) : Promise < boolean > {
@@ -84,7 +86,6 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
84
86
if ( ! clientOptions ) {
85
87
return false ;
86
88
}
87
- this . disposables . push ( this . interpreterService . onDidChangeInterpreter ( ( ) => this . restartLanguageServer ( ) ) ) ;
88
89
return this . startLanguageServer ( clientOptions ) ;
89
90
}
90
91
@@ -96,19 +97,7 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
96
97
for ( const d of this . disposables ) {
97
98
d . dispose ( ) ;
98
99
}
99
- }
100
-
101
- private async restartLanguageServer ( ) : Promise < void > {
102
- if ( ! this . context ) {
103
- return ;
104
- }
105
- const ids = new InterpreterDataService ( this . context , this . services ) ;
106
- const idata = await ids . getInterpreterData ( ) ;
107
- if ( ! idata || idata . hash !== this . interpreterHash ) {
108
- this . interpreterHash = idata ? idata . hash : '' ;
109
- await this . deactivate ( ) ;
110
- await this . activate ( ) ;
111
- }
100
+ ( this . configuration . getSettings ( ) as PythonSettings ) . removeListener ( 'change' , this . onSettingsChanged ) ;
112
101
}
113
102
114
103
private async startLanguageServer ( clientOptions : LanguageClientOptions ) : Promise < boolean > {
@@ -204,34 +193,27 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
204
193
properties [ 'PrefixPath' ] = interpreterData . prefix ;
205
194
}
206
195
207
- let searchPathsString = interpreterData ? interpreterData . searchPaths : '' ;
208
- let typeshedPaths : string [ ] = [ ] ;
196
+ // tslint:disable-next-line:no-string-literal
197
+ properties [ 'DatabasePath' ] = path . join ( this . context . extensionPath , analysisEngineFolder ) ;
209
198
199
+ let searchPaths = interpreterData ? interpreterData . searchPaths . split ( path . delimiter ) : [ ] ;
210
200
const settings = this . configuration . getSettings ( ) ;
211
201
if ( settings . autoComplete ) {
212
202
const extraPaths = settings . autoComplete . extraPaths ;
213
203
if ( extraPaths && extraPaths . length > 0 ) {
214
- searchPathsString = ` ${ searchPathsString } ; ${ extraPaths . join ( ';' ) } ` ;
204
+ searchPaths . push ( ... extraPaths ) ;
215
205
}
216
- typeshedPaths = settings . autoComplete . typeshedPaths ;
217
206
}
218
207
219
- // tslint:disable-next-line:no-string-literal
220
- properties [ 'DatabasePath' ] = path . join ( this . context . extensionPath , analysisEngineFolder ) ;
221
-
222
208
// Make sure paths do not contain multiple slashes so file URIs
223
209
// in VS Code (Node.js) and in the language server (.NET) match.
224
210
// Note: for the language server paths separator is always ;
225
- const searchPaths = searchPathsString . split ( path . delimiter ) . map ( p => path . normalize ( p ) ) ;
226
- // tslint:disable-next-line:no-string-literal
227
- properties [ 'SearchPaths' ] = `${ searchPaths . join ( ';' ) } ;${ pythonPath } ` ;
228
-
229
- if ( ! typeshedPaths || typeshedPaths . length === 0 ) {
230
- typeshedPaths = [ path . join ( this . context . extensionPath , 'typeshed' ) ] ;
231
- }
211
+ searchPaths . push ( pythonPath ) ;
212
+ searchPaths = searchPaths . map ( p => path . normalize ( p ) ) ;
232
213
233
214
const selector = [ { language : PYTHON , scheme : 'file' } ] ;
234
- const excludeFiles = this . getExcludedFiles ( ) ;
215
+ this . excludedFiles = this . getExcludedFiles ( ) ;
216
+ this . typeshedPaths = this . getTypeshedPaths ( settings ) ;
235
217
236
218
// Options to control the language client
237
219
return {
@@ -253,9 +235,8 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
253
235
maxDocumentationTextLength : 0
254
236
} ,
255
237
searchPaths,
256
- typeStubSearchPaths : typeshedPaths ,
257
- asyncStartup : true ,
258
- excludeFiles : excludeFiles ,
238
+ typeStubSearchPaths : this . typeshedPaths ,
239
+ excludeFiles : this . excludedFiles ,
259
240
testEnvironment : isTestExecution ( )
260
241
}
261
242
} ;
@@ -289,4 +270,49 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
289
270
. forEach ( p => list . push ( p ) ) ;
290
271
}
291
272
}
273
+
274
+ private getTypeshedPaths ( settings : IPythonSettings ) : string [ ] {
275
+ return settings . analysis . typeshedPaths && settings . analysis . typeshedPaths . length > 0
276
+ ? settings . analysis . typeshedPaths
277
+ : [ path . join ( this . context . extensionPath , 'typeshed' ) ] ;
278
+ }
279
+
280
+ private async onSettingsChanged ( ) : Promise < void > {
281
+ const ids = new InterpreterDataService ( this . context , this . services ) ;
282
+ const idata = await ids . getInterpreterData ( ) ;
283
+ if ( ! idata || idata . hash !== this . interpreterHash ) {
284
+ this . interpreterHash = idata ? idata . hash : '' ;
285
+ await this . restartLanguageServer ( ) ;
286
+ return ;
287
+ }
288
+
289
+ const excludedFiles = this . getExcludedFiles ( ) ;
290
+ await this . restartLanguageServerIfArrayChanged ( this . excludedFiles , excludedFiles ) ;
291
+
292
+ const settings = this . configuration . getSettings ( ) ;
293
+ const typeshedPaths = this . getTypeshedPaths ( settings ) ;
294
+ await this . restartLanguageServerIfArrayChanged ( this . typeshedPaths , typeshedPaths ) ;
295
+ }
296
+
297
+ private async restartLanguageServerIfArrayChanged ( oldArray : string [ ] , newArray : string [ ] ) : Promise < void > {
298
+ if ( newArray . length !== oldArray . length ) {
299
+ await this . restartLanguageServer ( ) ;
300
+ return ;
301
+ }
302
+
303
+ for ( let i = 0 ; i < oldArray . length ; i += 1 ) {
304
+ if ( oldArray [ i ] !== newArray [ i ] ) {
305
+ await this . restartLanguageServer ( ) ;
306
+ return ;
307
+ }
308
+ }
309
+ }
310
+
311
+ private async restartLanguageServer ( ) : Promise < void > {
312
+ if ( ! this . context ) {
313
+ return ;
314
+ }
315
+ await this . deactivate ( ) ;
316
+ await this . activate ( ) ;
317
+ }
292
318
}
0 commit comments