2
2
// Licensed under the MIT License.
3
3
import { inject , injectable } from 'inversify' ;
4
4
import * as path from 'path' ;
5
- import { ConfigurationChangeEvent , Disposable , Event , EventEmitter , WorkspaceFolder } from 'vscode' ;
6
- import { DocumentFilter , DocumentSelector , LanguageClientOptions , RevealOutputChannelOn } from 'vscode-languageclient' ;
5
+ import { ConfigurationChangeEvent , WorkspaceFolder } from 'vscode' ;
6
+ import { DocumentFilter } from 'vscode-languageclient' ;
7
7
8
8
import { IWorkspaceService } from '../../common/application/types' ;
9
- import { isTestExecution , PYTHON_LANGUAGE } from '../../common/constants' ;
10
9
import { traceDecorators , traceError } from '../../common/logger' ;
11
- import { IConfigurationService , IExtensionContext , IOutputChannel , IPathUtils , Resource } from '../../common/types' ;
10
+ import { IConfigurationService , IExtensionContext , IPathUtils , Resource } from '../../common/types' ;
12
11
import { debounceSync } from '../../common/utils/decorators' ;
13
12
import { IEnvironmentVariablesProvider } from '../../common/variables/types' ;
14
13
import { PythonInterpreter } from '../../interpreter/contracts' ;
15
- import { ILanguageServerAnalysisOptions , ILanguageServerFolderService , ILanguageServerOutputChannel } from '../types' ;
14
+ import { LanguageServerAnalysisOptionsBase } from '../common/analysisOptions' ;
15
+ import { ILanguageServerFolderService , ILanguageServerOutputChannel } from '../types' ;
16
16
17
17
@injectable ( )
18
- export class LanguageServerAnalysisOptions implements ILanguageServerAnalysisOptions {
19
- private envPythonPath : string = '' ;
20
- private excludedFiles : string [ ] = [ ] ;
21
- private typeshedPaths : string [ ] = [ ] ;
22
- private disposables : Disposable [ ] = [ ] ;
23
- private languageServerFolder : string = '' ;
18
+ export class DotNetLanguageServerAnalysisOptions extends LanguageServerAnalysisOptionsBase {
24
19
private resource : Resource ;
25
20
private interpreter : PythonInterpreter | undefined ;
26
- private output : IOutputChannel ;
27
- private readonly didChange = new EventEmitter < void > ( ) ;
21
+ private languageServerFolder : string = '' ;
22
+ private excludedFiles : string [ ] = [ ] ;
23
+ private typeshedPaths : string [ ] = [ ] ;
24
+
28
25
constructor (
29
26
@inject ( IExtensionContext ) private readonly context : IExtensionContext ,
30
- @inject ( IEnvironmentVariablesProvider ) private readonly envVarsProvider : IEnvironmentVariablesProvider ,
27
+ @inject ( IEnvironmentVariablesProvider ) envVarsProvider : IEnvironmentVariablesProvider ,
31
28
@inject ( IConfigurationService ) private readonly configuration : IConfigurationService ,
32
29
@inject ( IWorkspaceService ) private readonly workspace : IWorkspaceService ,
33
- @inject ( ILanguageServerOutputChannel ) private readonly lsOutputChannel : ILanguageServerOutputChannel ,
30
+ @inject ( ILanguageServerOutputChannel ) lsOutputChannel : ILanguageServerOutputChannel ,
34
31
@inject ( IPathUtils ) private readonly pathUtils : IPathUtils ,
35
32
@inject ( ILanguageServerFolderService ) private readonly languageServerFolderService : ILanguageServerFolderService
36
33
) {
37
- this . output = this . lsOutputChannel . channel ;
34
+ super ( envVarsProvider , lsOutputChannel ) ;
38
35
}
36
+
39
37
public async initialize ( resource : Resource , interpreter : PythonInterpreter | undefined ) {
38
+ await super . initialize ( resource , interpreter ) ;
39
+
40
40
this . resource = resource ;
41
41
this . interpreter = interpreter ;
42
42
this . languageServerFolder = await this . languageServerFolderService . getLanguageServerFolderName ( resource ) ;
43
43
44
- let disposable = this . workspace . onDidChangeConfiguration ( this . onSettingsChangedHandler , this ) ;
45
- this . disposables . push ( disposable ) ;
46
-
47
- disposable = this . envVarsProvider . onDidEnvironmentVariablesChange ( this . onEnvVarChange , this ) ;
44
+ const disposable = this . workspace . onDidChangeConfiguration ( this . onSettingsChangedHandler , this ) ;
48
45
this . disposables . push ( disposable ) ;
49
46
}
50
- public get onDidChange ( ) : Event < void > {
51
- return this . didChange . event ;
47
+
48
+ protected getWorkspaceFolder ( ) : WorkspaceFolder | undefined {
49
+ return this . workspace . getWorkspaceFolder ( this . resource ) ;
52
50
}
53
- public dispose ( ) : void {
54
- this . disposables . forEach ( ( d ) => d . dispose ( ) ) ;
55
- this . didChange . dispose ( ) ;
51
+
52
+ protected getDocumentFilters ( workspaceFolder ?: WorkspaceFolder ) : DocumentFilter [ ] {
53
+ const filters = super . getDocumentFilters ( workspaceFolder ) ;
54
+
55
+ // Set the document selector only when in a multi-root workspace scenario.
56
+ if (
57
+ workspaceFolder &&
58
+ Array . isArray ( this . workspace . workspaceFolders ) &&
59
+ this . workspace . workspaceFolders ! . length > 1
60
+ ) {
61
+ filters [ 0 ] . pattern = `${ workspaceFolder . uri . fsPath } /**/*` ;
62
+ }
63
+
64
+ return filters ;
56
65
}
57
- // tslint:disable-next-line: max-func-body-length
58
- @traceDecorators . error ( 'Failed to get analysis options' )
59
- public async getAnalysisOptions ( ) : Promise < LanguageClientOptions > {
66
+
67
+ protected async getInitializationOptions ( ) {
60
68
const properties : Record < string , { } > = { } ;
61
69
62
70
const interpreterInfo = this . interpreter ;
63
71
if ( ! interpreterInfo ) {
64
- // tslint:disable-next-line:no-suspicious-comment
65
- // TODO: How do we handle this? It is pretty unlikely...
66
72
throw Error ( 'did not find an active interpreter' ) ;
67
73
}
68
74
69
- // tslint:disable-next-line:no-string-literal
70
- properties [ 'InterpreterPath' ] = interpreterInfo . path ;
75
+ properties . InterpreterPath = interpreterInfo . path ;
71
76
72
77
const version = interpreterInfo . version ;
73
78
if ( version ) {
74
- // tslint:disable-next-line:no-string-literal
75
- properties [ 'Version' ] = `${ version . major } .${ version . minor } .${ version . patch } ` ;
79
+ properties . Version = `${ version . major } .${ version . minor } .${ version . patch } ` ;
76
80
} else {
77
81
traceError ( 'Unable to determine Python version. Analysis may be limited.' ) ;
78
82
}
@@ -87,72 +91,25 @@ export class LanguageServerAnalysisOptions implements ILanguageServerAnalysisOpt
87
91
}
88
92
}
89
93
90
- // tslint:disable-next-line: no-suspicious-comment
91
- // TODO: remove this setting since LS 0.2.92+ is not using it.
92
- // tslint:disable-next-line:no-string-literal
93
- properties [ 'DatabasePath' ] = path . join ( this . context . extensionPath , this . languageServerFolder ) ;
94
-
95
- const vars = await this . envVarsProvider . getEnvironmentVariables ( ) ;
96
- this . envPythonPath = vars . PYTHONPATH || '' ;
97
- if ( this . envPythonPath !== '' ) {
98
- const paths = this . envPythonPath . split ( this . pathUtils . delimiter ) . filter ( ( item ) => item . trim ( ) . length > 0 ) ;
94
+ const envPythonPath = await this . getEnvPythonPath ( ) ;
95
+ if ( envPythonPath !== '' ) {
96
+ const paths = envPythonPath . split ( this . pathUtils . delimiter ) . filter ( ( item ) => item . trim ( ) . length > 0 ) ;
99
97
searchPaths . push ( ...paths ) ;
100
98
}
101
99
102
100
searchPaths = searchPaths . map ( ( p ) => path . normalize ( p ) ) ;
103
101
104
- this . excludedFiles = this . getExcludedFiles ( ) ;
105
- this . typeshedPaths = this . getTypeshedPaths ( ) ;
106
- const workspaceFolder = this . workspace . getWorkspaceFolder ( this . resource ) ;
107
- const documentSelector = this . getDocumentSelector ( workspaceFolder ) ;
108
- // Options to control the language client.
109
102
return {
110
- // Register the server for Python documents.
111
- documentSelector,
112
- workspaceFolder,
113
- synchronize : {
114
- configurationSection : PYTHON_LANGUAGE
103
+ interpreter : {
104
+ properties
115
105
} ,
116
- outputChannel : this . output ,
117
- revealOutputChannelOn : RevealOutputChannelOn . Never ,
118
- initializationOptions : {
119
- interpreter : {
120
- properties
121
- } ,
122
- displayOptions : {
123
- preferredFormat : 'markdown' ,
124
- trimDocumentationLines : false ,
125
- maxDocumentationLineLength : 0 ,
126
- trimDocumentationText : false ,
127
- maxDocumentationTextLength : 0
128
- } ,
129
- searchPaths,
130
- typeStubSearchPaths : this . typeshedPaths ,
131
- cacheFolderPath : this . getCacheFolderPath ( ) ,
132
- excludeFiles : this . excludedFiles ,
133
- testEnvironment : isTestExecution ( ) ,
134
- analysisUpdates : true ,
135
- traceLogging : true , // Max level, let LS decide through settings actual level of logging.
136
- asyncStartup : true
137
- }
106
+ searchPaths,
107
+ typeStubSearchPaths : this . typeshedPaths ,
108
+ cacheFolderPath : this . getCacheFolderPath ( ) ,
109
+ excludeFiles : this . excludedFiles
138
110
} ;
139
111
}
140
- protected getDocumentSelector ( workspaceFolder ?: WorkspaceFolder ) : DocumentSelector {
141
- const documentSelector : DocumentFilter [ ] = [
142
- { scheme : 'file' , language : PYTHON_LANGUAGE } ,
143
- { scheme : 'untitled' , language : PYTHON_LANGUAGE }
144
- ] ;
145
- // Set the document selector only when in a multi-root workspace scenario.
146
- if (
147
- workspaceFolder &&
148
- Array . isArray ( this . workspace . workspaceFolders ) &&
149
- this . workspace . workspaceFolders ! . length > 1
150
- ) {
151
- // tslint:disable-next-line:no-any
152
- documentSelector [ 0 ] . pattern = `${ workspaceFolder . uri . fsPath } /**/*` ;
153
- }
154
- return documentSelector ;
155
- }
112
+
156
113
protected getExcludedFiles ( ) : string [ ] {
157
114
const list : string [ ] = [ '**/Lib/**' , '**/site-packages/**' ] ;
158
115
this . getVsCodeExcludeSection ( 'search.exclude' , list ) ;
@@ -170,35 +127,41 @@ export class LanguageServerAnalysisOptions implements ILanguageServerAnalysisOpt
170
127
. forEach ( ( p ) => list . push ( p ) ) ;
171
128
}
172
129
}
130
+
173
131
protected getPythonExcludeSection ( list : string [ ] ) : void {
174
132
const pythonSettings = this . configuration . getSettings ( this . resource ) ;
175
133
const paths = pythonSettings && pythonSettings . linting ? pythonSettings . linting . ignorePatterns : undefined ;
176
134
if ( paths && Array . isArray ( paths ) ) {
177
135
paths . filter ( ( p ) => p && p . length > 0 ) . forEach ( ( p ) => list . push ( p ) ) ;
178
136
}
179
137
}
138
+
180
139
protected getTypeshedPaths ( ) : string [ ] {
181
140
const settings = this . configuration . getSettings ( this . resource ) ;
182
141
return settings . analysis . typeshedPaths && settings . analysis . typeshedPaths . length > 0
183
142
? settings . analysis . typeshedPaths
184
143
: [ path . join ( this . context . extensionPath , this . languageServerFolder , 'Typeshed' ) ] ;
185
144
}
145
+
186
146
protected getCacheFolderPath ( ) : string | null {
187
147
const settings = this . configuration . getSettings ( this . resource ) ;
188
148
return settings . analysis . cacheFolderPath && settings . analysis . cacheFolderPath . length > 0
189
149
? settings . analysis . cacheFolderPath
190
150
: null ;
191
151
}
152
+
192
153
protected async onSettingsChangedHandler ( e ?: ConfigurationChangeEvent ) : Promise < void > {
193
154
if ( e && ! e . affectsConfiguration ( 'python' , this . resource ) ) {
194
155
return ;
195
156
}
196
157
this . onSettingsChanged ( ) ;
197
158
}
159
+
198
160
@debounceSync ( 1000 )
199
161
protected onSettingsChanged ( ) : void {
200
162
this . notifyIfSettingsChanged ( ) . ignoreErrors ( ) ;
201
163
}
164
+
202
165
@traceDecorators . verbose ( 'Changes in python settings detected in analysis options' )
203
166
protected async notifyIfSettingsChanged ( ) : Promise < void > {
204
167
const excludedFiles = this . getExcludedFiles ( ) ;
@@ -221,18 +184,4 @@ export class LanguageServerAnalysisOptions implements ILanguageServerAnalysisOpt
221
184
}
222
185
}
223
186
}
224
-
225
- @debounceSync ( 1000 )
226
- protected onEnvVarChange ( ) : void {
227
- this . notifyifEnvPythonPathChanged ( ) . ignoreErrors ( ) ;
228
- }
229
-
230
- protected async notifyifEnvPythonPathChanged ( ) : Promise < void > {
231
- const vars = await this . envVarsProvider . getEnvironmentVariables ( ) ;
232
- const envPythonPath = vars . PYTHONPATH || '' ;
233
-
234
- if ( this . envPythonPath !== envPythonPath ) {
235
- this . didChange . fire ( ) ;
236
- }
237
- }
238
187
}
0 commit comments