@@ -5,20 +5,29 @@ import * as cp from "child_process";
5
5
import * as fse from "fs-extra" ;
6
6
import * as path from "path" ;
7
7
import * as requireFromString from "require-from-string" ;
8
- import * as vscode from "vscode" ;
8
+ import { ConfigurationChangeEvent , Disposable , MessageItem , window , workspace , WorkspaceConfiguration } from "vscode" ;
9
9
import { Endpoint , IProblem , supportedPlugins } from "./shared" ;
10
10
import { executeCommand , executeCommandWithProgress } from "./utils/cpUtils" ;
11
11
import { genFileName } from "./utils/problemUtils" ;
12
12
import { DialogOptions , openUrl } from "./utils/uiUtils" ;
13
13
import * as wsl from "./utils/wslUtils" ;
14
+ import { toWslPath , useWsl } from "./utils/wslUtils" ;
14
15
15
- class LeetCodeExecutor {
16
+ class LeetCodeExecutor implements Disposable {
16
17
private leetCodeRootPath : string ;
17
18
private leetCodeRootPathInWsl : string ;
19
+ private nodeExecutable : string ;
20
+ private configurationChangeListener : Disposable ;
18
21
19
22
constructor ( ) {
20
23
this . leetCodeRootPath = path . join ( __dirname , ".." , ".." , "node_modules" , "vsc-leetcode-cli" ) ;
21
24
this . leetCodeRootPathInWsl = "" ;
25
+ this . nodeExecutable = this . getNodePath ( ) ;
26
+ this . configurationChangeListener = workspace . onDidChangeConfiguration ( ( event : ConfigurationChangeEvent ) => {
27
+ if ( event . affectsConfiguration ( "leetcode.nodePath" ) ) {
28
+ this . nodeExecutable = this . getNodePath ( ) ;
29
+ }
30
+ } , this ) ;
22
31
}
23
32
24
33
public async getLeetCodeRootPath ( ) : Promise < string > { // not wrapped by ""
@@ -36,10 +45,18 @@ class LeetCodeExecutor {
36
45
}
37
46
38
47
public async meetRequirements ( ) : Promise < boolean > {
48
+ if ( this . nodeExecutable !== "node" ) {
49
+ if ( ! await fse . pathExists ( this . nodeExecutable ) ) {
50
+ throw new Error ( `The Node.js executable does not exist on path ${ this . nodeExecutable } ` ) ;
51
+ }
52
+ if ( useWsl ( ) ) {
53
+ this . nodeExecutable = await toWslPath ( this . nodeExecutable ) ;
54
+ }
55
+ }
39
56
try {
40
- await this . executeCommandEx ( "node" , [ "-v" ] ) ;
57
+ await this . executeCommandEx ( this . nodeExecutable , [ "-v" ] ) ;
41
58
} catch ( error ) {
42
- const choice : vscode . MessageItem | undefined = await vscode . window . showErrorMessage (
59
+ const choice : MessageItem | undefined = await window . showErrorMessage (
43
60
"LeetCode extension needs Node.js installed in environment path" ,
44
61
DialogOptions . open ,
45
62
) ;
@@ -50,28 +67,28 @@ class LeetCodeExecutor {
50
67
}
51
68
for ( const plugin of supportedPlugins ) {
52
69
try { // Check plugin
53
- await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-e" , plugin ] ) ;
70
+ await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-e" , plugin ] ) ;
54
71
} catch ( error ) { // Download plugin and activate
55
- await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-i" , plugin ] ) ;
72
+ await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-i" , plugin ] ) ;
56
73
}
57
74
}
58
75
return true ;
59
76
}
60
77
61
78
public async deleteCache ( ) : Promise < string > {
62
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "cache" , "-d" ] ) ;
79
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "cache" , "-d" ] ) ;
63
80
}
64
81
65
82
public async getUserInfo ( ) : Promise < string > {
66
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "user" ] ) ;
83
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "user" ] ) ;
67
84
}
68
85
69
86
public async signOut ( ) : Promise < string > {
70
- return await await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "user" , "-L" ] ) ;
87
+ return await await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "user" , "-L" ] ) ;
71
88
}
72
89
73
90
public async listProblems ( showLocked : boolean ) : Promise < string > {
74
- return await this . executeCommandEx ( "node" , showLocked ?
91
+ return await this . executeCommandEx ( this . nodeExecutable , showLocked ?
75
92
[ await this . getLeetCodeBinaryPath ( ) , "list" ] :
76
93
[ await this . getLeetCodeBinaryPath ( ) , "list" , "-q" , "L" ] ,
77
94
) ;
@@ -82,37 +99,37 @@ class LeetCodeExecutor {
82
99
const filePath : string = path . join ( outDir , fileName ) ;
83
100
84
101
if ( ! await fse . pathExists ( filePath ) ) {
85
- const codeTemplate : string = await this . executeCommandWithProgressEx ( "Fetching problem data..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "-cx" , "-l" , language ] ) ;
102
+ const codeTemplate : string = await this . executeCommandWithProgressEx ( "Fetching problem data..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "-cx" , "-l" , language ] ) ;
86
103
await fse . writeFile ( filePath , codeTemplate ) ;
87
104
}
88
105
89
106
return filePath ;
90
107
}
91
108
92
109
public async showSolution ( problemNode : IProblem , language : string ) : Promise < string > {
93
- const solution : string = await this . executeCommandWithProgressEx ( "Fetching top voted solution from discussions..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "--solution" , "-l" , language ] ) ;
110
+ const solution : string = await this . executeCommandWithProgressEx ( "Fetching top voted solution from discussions..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "--solution" , "-l" , language ] ) ;
94
111
return solution ;
95
112
}
96
113
97
114
public async getDescription ( problemNode : IProblem ) : Promise < string > {
98
- return await this . executeCommandWithProgressEx ( "Fetching problem description..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "-x" ] ) ;
115
+ return await this . executeCommandWithProgressEx ( "Fetching problem description..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "show" , problemNode . id , "-x" ] ) ;
99
116
}
100
117
101
118
public async listSessions ( ) : Promise < string > {
102
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "session" ] ) ;
119
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "session" ] ) ;
103
120
}
104
121
105
122
public async enableSession ( name : string ) : Promise < string > {
106
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "session" , "-e" , name ] ) ;
123
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "session" , "-e" , name ] ) ;
107
124
}
108
125
109
126
public async createSession ( name : string ) : Promise < string > {
110
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "session" , "-c" , name ] ) ;
127
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "session" , "-c" , name ] ) ;
111
128
}
112
129
113
130
public async submitSolution ( filePath : string ) : Promise < string > {
114
131
try {
115
- return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "submit" , `"${ filePath } "` ] ) ;
132
+ return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "submit" , `"${ filePath } "` ] ) ;
116
133
} catch ( error ) {
117
134
if ( error . result ) {
118
135
return error . result ;
@@ -123,18 +140,18 @@ class LeetCodeExecutor {
123
140
124
141
public async testSolution ( filePath : string , testString ?: string ) : Promise < string > {
125
142
if ( testString ) {
126
- return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "test" , `"${ filePath } "` , "-t" , `${ testString } ` ] ) ;
143
+ return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "test" , `"${ filePath } "` , "-t" , `${ testString } ` ] ) ;
127
144
}
128
- return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , "node" , [ await this . getLeetCodeBinaryPath ( ) , "test" , `"${ filePath } "` ] ) ;
145
+ return await this . executeCommandWithProgressEx ( "Submitting to LeetCode..." , this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "test" , `"${ filePath } "` ] ) ;
129
146
}
130
147
131
148
public async switchEndpoint ( endpoint : string ) : Promise < string > {
132
149
switch ( endpoint ) {
133
150
case Endpoint . LeetCodeCN :
134
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-e" , "leetcode.cn" ] ) ;
151
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-e" , "leetcode.cn" ] ) ;
135
152
case Endpoint . LeetCode :
136
153
default :
137
- return await this . executeCommandEx ( "node" , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-d" , "leetcode.cn" ] ) ;
154
+ return await this . executeCommandEx ( this . nodeExecutable , [ await this . getLeetCodeBinaryPath ( ) , "plugin" , "-d" , "leetcode.cn" ] ) ;
138
155
}
139
156
}
140
157
@@ -149,6 +166,19 @@ class LeetCodeExecutor {
149
166
return { companies : COMPONIES , tags : TAGS } ;
150
167
}
151
168
169
+ public get node ( ) : string {
170
+ return this . nodeExecutable ;
171
+ }
172
+
173
+ public dispose ( ) : void {
174
+ this . configurationChangeListener . dispose ( ) ;
175
+ }
176
+
177
+ private getNodePath ( ) : string {
178
+ const extensionConfig : WorkspaceConfiguration = workspace . getConfiguration ( "leetcode" , null ) ;
179
+ return extensionConfig . get < string > ( "nodePath" , "node" /* default value */ ) ;
180
+ }
181
+
152
182
private async executeCommandEx ( command : string , args : string [ ] , options : cp . SpawnOptions = { shell : true } ) : Promise < string > {
153
183
if ( wsl . useWsl ( ) ) {
154
184
return await executeCommand ( "wsl" , [ command ] . concat ( args ) , options ) ;
0 commit comments