@@ -5,20 +5,29 @@ import * as cp from "child_process";
55import * as fse from "fs-extra" ;
66import * as path from "path" ;
77import * as requireFromString from "require-from-string" ;
8- import * as vscode from "vscode" ;
8+ import { ConfigurationChangeEvent , Disposable , MessageItem , window , workspace , WorkspaceConfiguration } from "vscode" ;
99import { Endpoint , IProblem , supportedPlugins } from "./shared" ;
1010import { executeCommand , executeCommandWithProgress } from "./utils/cpUtils" ;
1111import { genFileName } from "./utils/problemUtils" ;
1212import { DialogOptions , openUrl } from "./utils/uiUtils" ;
1313import * as wsl from "./utils/wslUtils" ;
14+ import { toWslPath , useWsl } from "./utils/wslUtils" ;
1415
15- class LeetCodeExecutor {
16+ class LeetCodeExecutor implements Disposable {
1617 private leetCodeRootPath : string ;
1718 private leetCodeRootPathInWsl : string ;
19+ private nodeExecutable : string ;
20+ private configurationChangeListener : Disposable ;
1821
1922 constructor ( ) {
2023 this . leetCodeRootPath = path . join ( __dirname , ".." , ".." , "node_modules" , "vsc-leetcode-cli" ) ;
2124 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 ) ;
2231 }
2332
2433 public async getLeetCodeRootPath ( ) : Promise < string > { // not wrapped by ""
@@ -36,10 +45,18 @@ class LeetCodeExecutor {
3645 }
3746
3847 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+ }
3956 try {
40- await this . executeCommandEx ( "node" , [ "-v" ] ) ;
57+ await this . executeCommandEx ( this . nodeExecutable , [ "-v" ] ) ;
4158 } catch ( error ) {
42- const choice : vscode . MessageItem | undefined = await vscode . window . showErrorMessage (
59+ const choice : MessageItem | undefined = await window . showErrorMessage (
4360 "LeetCode extension needs Node.js installed in environment path" ,
4461 DialogOptions . open ,
4562 ) ;
@@ -50,28 +67,28 @@ class LeetCodeExecutor {
5067 }
5168 for ( const plugin of supportedPlugins ) {
5269 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 ] ) ;
5471 } 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 ] ) ;
5673 }
5774 }
5875 return true ;
5976 }
6077
6178 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" ] ) ;
6380 }
6481
6582 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" ] ) ;
6784 }
6885
6986 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" ] ) ;
7188 }
7289
7390 public async listProblems ( showLocked : boolean ) : Promise < string > {
74- return await this . executeCommandEx ( "node" , showLocked ?
91+ return await this . executeCommandEx ( this . nodeExecutable , showLocked ?
7592 [ await this . getLeetCodeBinaryPath ( ) , "list" ] :
7693 [ await this . getLeetCodeBinaryPath ( ) , "list" , "-q" , "L" ] ,
7794 ) ;
@@ -82,37 +99,37 @@ class LeetCodeExecutor {
8299 const filePath : string = path . join ( outDir , fileName ) ;
83100
84101 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 ] ) ;
86103 await fse . writeFile ( filePath , codeTemplate ) ;
87104 }
88105
89106 return filePath ;
90107 }
91108
92109 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 ] ) ;
94111 return solution ;
95112 }
96113
97114 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" ] ) ;
99116 }
100117
101118 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" ] ) ;
103120 }
104121
105122 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 ] ) ;
107124 }
108125
109126 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 ] ) ;
111128 }
112129
113130 public async submitSolution ( filePath : string ) : Promise < string > {
114131 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 } "` ] ) ;
116133 } catch ( error ) {
117134 if ( error . result ) {
118135 return error . result ;
@@ -123,18 +140,18 @@ class LeetCodeExecutor {
123140
124141 public async testSolution ( filePath : string , testString ?: string ) : Promise < string > {
125142 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 } ` ] ) ;
127144 }
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 } "` ] ) ;
129146 }
130147
131148 public async switchEndpoint ( endpoint : string ) : Promise < string > {
132149 switch ( endpoint ) {
133150 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" ] ) ;
135152 case Endpoint . LeetCode :
136153 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" ] ) ;
138155 }
139156 }
140157
@@ -149,6 +166,19 @@ class LeetCodeExecutor {
149166 return { companies : COMPONIES , tags : TAGS } ;
150167 }
151168
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+
152182 private async executeCommandEx ( command : string , args : string [ ] , options : cp . SpawnOptions = { shell : true } ) : Promise < string > {
153183 if ( wsl . useWsl ( ) ) {
154184 return await executeCommand ( "wsl" , [ command ] . concat ( args ) , options ) ;
0 commit comments