1
- 'use strict' ;
1
+ // tslint:disable:no-any no-empty member-ordering prefer-const prefer-template no-var-self
2
2
3
3
import * as child_process from 'child_process' ;
4
4
import * as path from 'path' ;
5
5
import * as vscode from 'vscode' ;
6
+ import { Uri } from 'vscode' ;
6
7
import { IPythonSettings } from '../common/configSettings' ;
7
- import { mergeEnvVariables } from '../common/envFileParser' ;
8
- import { getCustomEnvVarsSync , getWindowsLineEndingCount , IS_WINDOWS } from '../common/utils' ;
8
+ import '../common/extensions' ;
9
+ import { createDeferred , Deferred } from '../common/helpers' ;
10
+ import { IPythonExecutionFactory } from '../common/process/types' ;
11
+ import { getWindowsLineEndingCount , IS_WINDOWS } from '../common/utils' ;
12
+ import { IServiceContainer } from '../ioc/types' ;
9
13
10
14
export class RefactorProxy extends vscode . Disposable {
11
- private _process : child_process . ChildProcess ;
15
+ private _process ? : child_process . ChildProcess ;
12
16
private _extensionDir : string ;
13
17
private _previousOutData : string = '' ;
14
18
private _previousStdErrData : string = '' ;
15
19
private _startedSuccessfully : boolean = false ;
16
- private _commandResolve : ( value ?: any | PromiseLike < any > ) => void ;
20
+ private _commandResolve ? : ( value ?: any | PromiseLike < any > ) => void ;
17
21
private _commandReject : ( reason ?: any ) => void ;
18
- private _initializeReject : ( reason ?: any ) => void ;
19
- constructor ( extensionDir : string , private pythonSettings : IPythonSettings , private workspaceRoot : string ) {
22
+ private initialized : Deferred < void > ;
23
+ constructor ( extensionDir : string , private pythonSettings : IPythonSettings , private workspaceRoot : string ,
24
+ private serviceContainer : IServiceContainer ) {
20
25
super ( ( ) => { } ) ;
21
26
this . _extensionDir = extensionDir ;
22
27
}
23
28
24
- dispose ( ) {
29
+ public dispose ( ) {
25
30
try {
26
- this . _process . kill ( ) ;
31
+ this . _process ! . kill ( ) ;
32
+ } catch ( ex ) {
27
33
}
28
- catch ( ex ) {
29
- }
30
- this . _process = null ;
34
+ this . _process = undefined ;
31
35
}
32
36
private getOffsetAt ( document : vscode . TextDocument , position : vscode . Position ) : number {
33
37
if ( ! IS_WINDOWS ) {
@@ -43,52 +47,52 @@ export class RefactorProxy extends vscode.Disposable {
43
47
44
48
return offset - winEols ;
45
49
}
46
- rename < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
50
+ public rename < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
47
51
if ( ! options ) {
48
- options = vscode . window . activeTextEditor . options ;
52
+ options = vscode . window . activeTextEditor ! . options ;
49
53
}
50
- let command = {
51
- " lookup" : " rename" ,
52
- " file" : filePath ,
53
- " start" : this . getOffsetAt ( document , range . start ) . toString ( ) ,
54
- "id" : "1" ,
55
- " name" : name ,
56
- " indent_size" : options . tabSize
54
+ const command = {
55
+ lookup : ' rename' ,
56
+ file : filePath ,
57
+ start : this . getOffsetAt ( document , range . start ) . toString ( ) ,
58
+ id : '1' ,
59
+ name : name ,
60
+ indent_size : options . tabSize
57
61
} ;
58
62
59
63
return this . sendCommand < T > ( JSON . stringify ( command ) ) ;
60
64
}
61
- extractVariable < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
65
+ public extractVariable < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
62
66
if ( ! options ) {
63
- options = vscode . window . activeTextEditor . options ;
67
+ options = vscode . window . activeTextEditor ! . options ;
64
68
}
65
- let command = {
66
- " lookup" : " extract_variable" ,
67
- " file" : filePath ,
68
- " start" : this . getOffsetAt ( document , range . start ) . toString ( ) ,
69
- " end" : this . getOffsetAt ( document , range . end ) . toString ( ) ,
70
- "id" : "1" ,
71
- " name" : name ,
72
- " indent_size" : options . tabSize
69
+ const command = {
70
+ lookup : ' extract_variable' ,
71
+ file : filePath ,
72
+ start : this . getOffsetAt ( document , range . start ) . toString ( ) ,
73
+ end : this . getOffsetAt ( document , range . end ) . toString ( ) ,
74
+ id : '1' ,
75
+ name : name ,
76
+ indent_size : options . tabSize
73
77
} ;
74
78
return this . sendCommand < T > ( JSON . stringify ( command ) ) ;
75
79
}
76
- extractMethod < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
80
+ public extractMethod < T > ( document : vscode . TextDocument , name : string , filePath : string , range : vscode . Range , options ?: vscode . TextEditorOptions ) : Promise < T > {
77
81
if ( ! options ) {
78
- options = vscode . window . activeTextEditor . options ;
82
+ options = vscode . window . activeTextEditor ! . options ;
79
83
}
80
84
// Ensure last line is an empty line
81
85
if ( ! document . lineAt ( document . lineCount - 1 ) . isEmptyOrWhitespace && range . start . line === document . lineCount - 1 ) {
82
86
return Promise . reject < T > ( 'Missing blank line at the end of document (PEP8).' ) ;
83
87
}
84
- let command = {
85
- " lookup" : " extract_method" ,
86
- " file" : filePath ,
87
- " start" : this . getOffsetAt ( document , range . start ) . toString ( ) ,
88
- " end" : this . getOffsetAt ( document , range . end ) . toString ( ) ,
89
- "id" : "1" ,
90
- " name" : name ,
91
- " indent_size" : options . tabSize
88
+ const command = {
89
+ lookup : ' extract_method' ,
90
+ file : filePath ,
91
+ start : this . getOffsetAt ( document , range . start ) . toString ( ) ,
92
+ end : this . getOffsetAt ( document , range . end ) . toString ( ) ,
93
+ id : '1' ,
94
+ name : name ,
95
+ indent_size : options . tabSize
92
96
} ;
93
97
return this . sendCommand < T > ( JSON . stringify ( command ) ) ;
94
98
}
@@ -98,39 +102,30 @@ export class RefactorProxy extends vscode.Disposable {
98
102
return new Promise < T > ( ( resolve , reject ) => {
99
103
this . _commandResolve = resolve ;
100
104
this . _commandReject = reject ;
101
- this . _process . stdin . write ( command + '\n' ) ;
105
+ this . _process ! . stdin . write ( command + '\n' ) ;
102
106
} ) ;
103
107
} ) ;
104
108
}
105
- private initialize ( pythonPath : string ) : Promise < string > {
106
- return new Promise < any > ( ( resolve , reject ) => {
107
- this . _initializeReject = reject ;
108
- let environmentVariables : Object & { [ key : string ] : string } = { 'PYTHONUNBUFFERED' : '1' } ;
109
- let customEnvironmentVars = getCustomEnvVarsSync ( vscode . Uri . file ( this . workspaceRoot ) ) ;
110
- if ( customEnvironmentVars ) {
111
- environmentVariables = mergeEnvVariables ( environmentVariables , customEnvironmentVars ) ;
109
+ private async initialize ( pythonPath : string ) : Promise < void > {
110
+ const pythonProc = await this . serviceContainer . get < IPythonExecutionFactory > ( IPythonExecutionFactory ) . create ( Uri . file ( this . workspaceRoot ) ) ;
111
+ this . initialized = createDeferred < void > ( ) ;
112
+ const args = [ 'refactor.py' , this . workspaceRoot ] ;
113
+ const cwd = path . join ( this . _extensionDir , 'pythonFiles' ) ;
114
+ const result = pythonProc . execObservable ( args , { cwd } ) ;
115
+ this . _process = result . proc ;
116
+ result . out . subscribe ( output => {
117
+ if ( output . source === 'stdout' ) {
118
+ if ( ! this . _startedSuccessfully && output . out . startsWith ( 'STARTED' ) ) {
119
+ this . _startedSuccessfully = true ;
120
+ return this . initialized . resolve ( ) ;
121
+ }
122
+ this . onData ( output . out ) ;
123
+ } else {
124
+ this . handleStdError ( output . out ) ;
112
125
}
113
- environmentVariables = mergeEnvVariables ( environmentVariables ) ;
114
- this . _process = child_process . spawn ( pythonPath , [ 'refactor.py' , this . workspaceRoot ] ,
115
- {
116
- cwd : path . join ( this . _extensionDir , 'pythonFiles' ) ,
117
- env : environmentVariables
118
- } ) ;
119
- this . _process . stderr . setEncoding ( 'utf8' ) ;
120
- this . _process . stderr . on ( 'data' , this . handleStdError . bind ( this ) ) ;
121
- this . _process . on ( 'error' , this . handleError . bind ( this ) ) ;
126
+ } , error => this . handleError ( error ) ) ;
122
127
123
- let that = this ;
124
- this . _process . stdout . setEncoding ( 'utf8' ) ;
125
- this . _process . stdout . on ( 'data' , ( data : string ) => {
126
- let dataStr : string = data + '' ;
127
- if ( ! that . _startedSuccessfully && dataStr . startsWith ( 'STARTED' ) ) {
128
- that . _startedSuccessfully = true ;
129
- return resolve ( ) ;
130
- }
131
- that . onData ( data ) ;
132
- } ) ;
133
- } ) ;
128
+ return this . initialized . promise ;
134
129
}
135
130
private handleStdError ( data : string ) {
136
131
// Possible there was an exception in parsing the data returned
@@ -140,34 +135,32 @@ export class RefactorProxy extends vscode.Disposable {
140
135
try {
141
136
errorResponse = dataStr . split ( / \r ? \n / g) . filter ( line => line . length > 0 ) . map ( resp => JSON . parse ( resp ) ) ;
142
137
this . _previousStdErrData = '' ;
143
- }
144
- catch ( ex ) {
138
+ } catch ( ex ) {
145
139
console . error ( ex ) ;
146
140
// Possible we've only received part of the data, hence don't clear previousData
147
141
return ;
148
142
}
149
143
if ( typeof errorResponse [ 0 ] . message !== 'string' || errorResponse [ 0 ] . message . length === 0 ) {
150
- errorResponse [ 0 ] . message = errorResponse [ 0 ] . traceback . split ( / \r ? \n / g ) . pop ( ) ;
144
+ errorResponse [ 0 ] . message = errorResponse [ 0 ] . traceback . splitLines ( ) . pop ( ) ! ;
151
145
}
152
146
let errorMessage = errorResponse [ 0 ] . message + '\n' + errorResponse [ 0 ] . traceback ;
153
147
154
148
if ( this . _startedSuccessfully ) {
155
149
this . _commandReject ( `Refactor failed. ${ errorMessage } ` ) ;
156
- }
157
- else {
150
+ } else {
158
151
if ( typeof errorResponse [ 0 ] . type === 'string' && errorResponse [ 0 ] . type === 'ModuleNotFoundError' ) {
159
- this . _initializeReject ( 'Not installed' ) ;
152
+ this . initialized . reject ( 'Not installed' ) ;
160
153
return ;
161
154
}
162
155
163
- this . _initializeReject ( `Refactor failed. ${ errorMessage } ` ) ;
156
+ this . initialized . reject ( `Refactor failed. ${ errorMessage } ` ) ;
164
157
}
165
158
}
166
159
private handleError ( error : Error ) {
167
160
if ( this . _startedSuccessfully ) {
168
161
return this . _commandReject ( error ) ;
169
162
}
170
- this . _initializeReject ( error ) ;
163
+ this . initialized . reject ( error ) ;
171
164
}
172
165
private onData ( data : string ) {
173
166
if ( ! this . _commandResolve ) { return ; }
@@ -179,13 +172,12 @@ export class RefactorProxy extends vscode.Disposable {
179
172
try {
180
173
response = dataStr . split ( / \r ? \n / g) . filter ( line => line . length > 0 ) . map ( resp => JSON . parse ( resp ) ) ;
181
174
this . _previousOutData = '' ;
182
- }
183
- catch ( ex ) {
175
+ } catch ( ex ) {
184
176
// Possible we've only received part of the data, hence don't clear previousData
185
177
return ;
186
178
}
187
179
this . dispose ( ) ;
188
- this . _commandResolve ( response [ 0 ] ) ;
189
- this . _commandResolve = null ;
180
+ this . _commandResolve ! ( response [ 0 ] ) ;
181
+ this . _commandResolve = undefined ;
190
182
}
191
183
}
0 commit comments