@@ -13,6 +13,7 @@ import { IProcessServiceFactory } from '../common/process/types';
13
13
import { StopWatch } from '../common/stopWatch' ;
14
14
import { IConfigurationService , IOutputChannel , IPythonSettings } from '../common/types' ;
15
15
import { IEnvironmentVariablesProvider } from '../common/variables/types' ;
16
+ import { IInterpreterService } from '../interpreter/contracts' ;
16
17
import { IServiceContainer } from '../ioc/types' ;
17
18
import {
18
19
PYTHON_ANALYSIS_ENGINE_DOWNLOADED ,
@@ -35,11 +36,11 @@ class LanguageServerStartupErrorHandler implements ErrorHandler {
35
36
constructor ( private readonly deferred : Deferred < void > ) { }
36
37
public error ( error : Error , message : Message , count : number ) : ErrorAction {
37
38
this . deferred . reject ( error ) ;
38
- return ErrorAction . Shutdown ;
39
+ return ErrorAction . Continue ;
39
40
}
40
41
public closed ( ) : CloseAction {
41
42
this . deferred . reject ( ) ;
42
- return CloseAction . DoNotRestart ;
43
+ return CloseAction . Restart ;
43
44
}
44
45
}
45
46
@@ -50,39 +51,66 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
50
51
private readonly fs : IFileSystem ;
51
52
private readonly sw = new StopWatch ( ) ;
52
53
private readonly platformData : PlatformData ;
54
+ private readonly interpreterService : IInterpreterService ;
55
+ private readonly disposables : Disposable [ ] = [ ] ;
53
56
private languageClient : LanguageClient | undefined ;
57
+ private context : ExtensionContext | undefined ;
58
+ private interpreterHash : string = '' ;
54
59
55
60
constructor ( private readonly services : IServiceContainer , pythonSettings : IPythonSettings ) {
56
61
this . configuration = this . services . get < IConfigurationService > ( IConfigurationService ) ;
57
62
this . appShell = this . services . get < IApplicationShell > ( IApplicationShell ) ;
58
63
this . output = this . services . get < OutputChannel > ( IOutputChannel , STANDARD_OUTPUT_CHANNEL ) ;
59
64
this . fs = this . services . get < IFileSystem > ( IFileSystem ) ;
60
65
this . platformData = new PlatformData ( services . get < IPlatformService > ( IPlatformService ) , this . fs ) ;
66
+ this . interpreterService = this . services . get < IInterpreterService > ( IInterpreterService ) ;
61
67
}
62
68
63
69
public async activate ( context : ExtensionContext ) : Promise < boolean > {
70
+ this . sw . reset ( ) ;
71
+ this . context = context ;
64
72
const clientOptions = await this . getAnalysisOptions ( context ) ;
65
73
if ( ! clientOptions ) {
66
74
return false ;
67
75
}
76
+ this . disposables . push ( this . interpreterService . onDidChangeInterpreter ( ( ) => this . restartLanguageServer ( ) ) ) ;
68
77
return this . startLanguageServer ( context , clientOptions ) ;
69
78
}
70
79
71
80
public async deactivate ( ) : Promise < void > {
72
81
if ( this . languageClient ) {
73
82
await this . languageClient . stop ( ) ;
74
83
}
84
+ for ( const d of this . disposables ) {
85
+ d . dispose ( ) ;
86
+ }
87
+ }
88
+
89
+ private async restartLanguageServer ( ) : Promise < void > {
90
+ if ( ! this . context ) {
91
+ return ;
92
+ }
93
+ const ids = new InterpreterDataService ( this . context , this . services ) ;
94
+ const idata = await ids . getInterpreterData ( ) ;
95
+ if ( ! idata || idata . hash !== this . interpreterHash ) {
96
+ this . interpreterHash = idata ? idata . hash : '' ;
97
+ await this . deactivate ( ) ;
98
+ await this . activate ( this . context ) ;
99
+ }
75
100
}
76
101
77
102
private async startLanguageServer ( context : ExtensionContext , clientOptions : LanguageClientOptions ) : Promise < boolean > {
78
103
// Determine if we are running MSIL/Universal via dotnet or self-contained app.
79
104
const mscorlib = path . join ( context . extensionPath , analysisEngineFolder , 'mscorlib.dll' ) ;
105
+ const downloader = new AnalysisEngineDownloader ( this . services , analysisEngineFolder ) ;
80
106
let downloadPackage = false ;
81
107
82
108
const reporter = getTelemetryReporter ( ) ;
83
109
reporter . sendTelemetryEvent ( PYTHON_ANALYSIS_ENGINE_ENABLED ) ;
84
110
85
- if ( ! await this . fs . fileExistsAsync ( mscorlib ) ) {
111
+ await this . checkPythiaModel ( context , downloader ) ;
112
+
113
+ if ( ! await this . fs . fileExists ( mscorlib ) ) {
86
114
// Depends on .NET Runtime or SDK
87
115
this . languageClient = this . createSimpleLanguageClient ( context , clientOptions ) ;
88
116
try {
@@ -100,7 +128,7 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
100
128
}
101
129
102
130
if ( downloadPackage ) {
103
- const downloader = new AnalysisEngineDownloader ( this . services , analysisEngineFolder ) ;
131
+ this . appShell . showWarningMessage ( '.NET Runtime is not found, platform-specific Python Analysis Engine will be downloaded.' ) ;
104
132
await downloader . downloadAnalysisEngine ( context ) ;
105
133
reporter . sendTelemetryEvent ( PYTHON_ANALYSIS_ENGINE_DOWNLOADED ) ;
106
134
}
@@ -128,7 +156,9 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
128
156
disposable = lc . start ( ) ;
129
157
lc . onReady ( )
130
158
. then ( ( ) => deferred . resolve ( ) )
131
- . catch ( deferred . reject ) ;
159
+ . catch ( ( reason ) => {
160
+ deferred . reject ( reason ) ;
161
+ } ) ;
132
162
await deferred . promise ;
133
163
134
164
this . output . appendLine ( `Language server ready: ${ this . sw . elapsedTime } ms` ) ;
@@ -172,20 +202,19 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
172
202
const interpreterData = await interpreterDataService . getInterpreterData ( ) ;
173
203
if ( ! interpreterData ) {
174
204
const appShell = this . services . get < IApplicationShell > ( IApplicationShell ) ;
175
- appShell . showErrorMessage ( 'Unable to determine path to Python interpreter.' ) ;
176
- return ;
205
+ appShell . showWarningMessage ( 'Unable to determine path to Python interpreter. IntelliSense will be limited.' ) ;
177
206
}
178
207
179
- // tslint:disable-next-line:no-string-literal
180
- properties [ 'InterpreterPath' ] = interpreterData . path ;
181
- // tslint:disable-next-line:no-string-literal
182
- properties [ 'Version' ] = interpreterData . version ;
183
- // tslint:disable-next-line:no-string-literal
184
- properties [ 'PrefixPath' ] = interpreterData . prefix ;
185
- // tslint:disable-next-line:no-string-literal
186
- properties [ 'DatabasePath' ] = path . join ( context . extensionPath , analysisEngineFolder ) ;
208
+ if ( interpreterData ) {
209
+ // tslint:disable-next-line:no-string-literal
210
+ properties [ 'InterpreterPath' ] = interpreterData . path ;
211
+ // tslint:disable-next-line:no-string-literal
212
+ properties [ 'Version' ] = interpreterData . version ;
213
+ // tslint:disable-next-line:no-string-literal
214
+ properties [ 'PrefixPath' ] = interpreterData . prefix ;
215
+ }
187
216
188
- let searchPaths = interpreterData . searchPaths ;
217
+ let searchPaths = interpreterData ? interpreterData . searchPaths : '' ;
189
218
const settings = this . configuration . getSettings ( ) ;
190
219
if ( settings . autoComplete ) {
191
220
const extraPaths = settings . autoComplete . extraPaths ;
@@ -194,12 +223,15 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
194
223
}
195
224
}
196
225
226
+ // tslint:disable-next-line:no-string-literal
227
+ properties [ 'DatabasePath' ] = path . join ( context . extensionPath , analysisEngineFolder ) ;
228
+
197
229
const envProvider = this . services . get < IEnvironmentVariablesProvider > ( IEnvironmentVariablesProvider ) ;
198
230
const pythonPath = ( await envProvider . getEnvironmentVariables ( ) ) . PYTHONPATH ;
231
+ this . interpreterHash = interpreterData ? interpreterData . hash : '' ;
199
232
200
233
// tslint:disable-next-line:no-string-literal
201
234
properties [ 'SearchPaths' ] = `${ searchPaths } ;${ pythonPath ? pythonPath : '' } ` ;
202
-
203
235
const selector : string [ ] = [ PYTHON ] ;
204
236
205
237
// Options to control the language client
@@ -215,12 +247,14 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
215
247
properties
216
248
} ,
217
249
displayOptions : {
250
+ preferredFormat : 1 , // Markdown
218
251
trimDocumentationLines : false ,
219
252
maxDocumentationLineLength : 0 ,
220
253
trimDocumentationText : false ,
221
254
maxDocumentationTextLength : 0
222
255
} ,
223
256
asyncStartup : true ,
257
+ pythiaEnabled : settings . pythiaEnabled ,
224
258
testEnvironment : isTestExecution ( )
225
259
}
226
260
} ;
@@ -231,4 +265,11 @@ export class AnalysisExtensionActivator implements IExtensionActivator {
231
265
const result = await ps . exec ( 'dotnet' , [ '--version' ] ) . catch ( ( ) => { return { stdout : '' } ; } ) ;
232
266
return result . stdout . trim ( ) . startsWith ( '2.' ) ;
233
267
}
268
+
269
+ private async checkPythiaModel ( context : ExtensionContext , downloader : AnalysisEngineDownloader ) : Promise < void > {
270
+ const settings = this . configuration . getSettings ( ) ;
271
+ if ( settings . pythiaEnabled ) {
272
+ await downloader . downloadPythiaModel ( context ) ;
273
+ }
274
+ }
234
275
}
0 commit comments