Skip to content

Commit

Permalink
Can specify the node path (#233)
Browse files Browse the repository at this point in the history
  • Loading branch information
jdneo authored Apr 1, 2019
1 parent a6367f5 commit c6c4e9c
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 27 deletions.
12 changes: 9 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
"type": "boolean",
"default": false,
"scope": "application",
"description": "Use Node.js inside the Windows Subsystem for Linux."
"description": "Use the Windows Subsystem for Linux."
},
"leetcode.endpoint": {
"type": "string",
Expand All @@ -286,13 +286,19 @@
"leetcode.outputFolder": {
"type": "string",
"scope": "application",
"description": "Specify the relative path to save the problem files."
"description": "The relative path to save the problem files."
},
"leetcode.enableStatusBar": {
"type": "boolean",
"default": true,
"scope": "application",
"description": "Specify whether the LeetCode status bar will be shown or not."
"description": "Show the LeetCode status bar or not."
},
"leetcode.nodePath": {
"type": "string",
"default": "node",
"scope": "application",
"description": "The Node.js executable path."
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
leetCodePreviewProvider,
leetCodeResultProvider,
leetCodeSolutionProvider,
leetCodeExecutor,
vscode.window.createTreeView("leetCodeExplorer", { treeDataProvider: leetCodeTreeDataProvider, showCollapseAll: true }),
vscode.languages.registerCodeLensProvider({ scheme: "file" }, codeLensProvider),
vscode.commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()),
Expand Down
72 changes: 51 additions & 21 deletions src/leetCodeExecutor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,29 @@ import * as cp from "child_process";
import * as fse from "fs-extra";
import * as path from "path";
import * as requireFromString from "require-from-string";
import * as vscode from "vscode";
import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace, WorkspaceConfiguration } from "vscode";
import { Endpoint, IProblem, supportedPlugins } from "./shared";
import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils";
import { genFileName } from "./utils/problemUtils";
import { DialogOptions, openUrl } from "./utils/uiUtils";
import * as wsl from "./utils/wslUtils";
import { toWslPath, useWsl } from "./utils/wslUtils";

class LeetCodeExecutor {
class LeetCodeExecutor implements Disposable {
private leetCodeRootPath: string;
private leetCodeRootPathInWsl: string;
private nodeExecutable: string;
private configurationChangeListener: Disposable;

constructor() {
this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "vsc-leetcode-cli");
this.leetCodeRootPathInWsl = "";
this.nodeExecutable = this.getNodePath();
this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
if (event.affectsConfiguration("leetcode.nodePath")) {
this.nodeExecutable = this.getNodePath();
}
}, this);
}

public async getLeetCodeRootPath(): Promise<string> { // not wrapped by ""
Expand All @@ -36,10 +45,18 @@ class LeetCodeExecutor {
}

public async meetRequirements(): Promise<boolean> {
if (this.nodeExecutable !== "node") {
if (!await fse.pathExists(this.nodeExecutable)) {
throw new Error(`The Node.js executable does not exist on path ${this.nodeExecutable}`);
}
if (useWsl()) {
this.nodeExecutable = await toWslPath(this.nodeExecutable);
}
}
try {
await this.executeCommandEx("node", ["-v"]);
await this.executeCommandEx(this.nodeExecutable, ["-v"]);
} catch (error) {
const choice: vscode.MessageItem | undefined = await vscode.window.showErrorMessage(
const choice: MessageItem | undefined = await window.showErrorMessage(
"LeetCode extension needs Node.js installed in environment path",
DialogOptions.open,
);
Expand All @@ -50,28 +67,28 @@ class LeetCodeExecutor {
}
for (const plugin of supportedPlugins) {
try { // Check plugin
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", plugin]);
await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-e", plugin]);
} catch (error) { // Download plugin and activate
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", plugin]);
await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-i", plugin]);
}
}
return true;
}

public async deleteCache(): Promise<string> {
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "cache", "-d"]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "cache", "-d"]);
}

public async getUserInfo(): Promise<string> {
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "user"]);
}

public async signOut(): Promise<string> {
return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]);
return await await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "user", "-L"]);
}

public async listProblems(showLocked: boolean): Promise<string> {
return await this.executeCommandEx("node", showLocked ?
return await this.executeCommandEx(this.nodeExecutable, showLocked ?
[await this.getLeetCodeBinaryPath(), "list"] :
[await this.getLeetCodeBinaryPath(), "list", "-q", "L"],
);
Expand All @@ -82,37 +99,37 @@ class LeetCodeExecutor {
const filePath: string = path.join(outDir, fileName);

if (!await fse.pathExists(filePath)) {
const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", "node", [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "-cx", "-l", language]);
const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "-cx", "-l", language]);
await fse.writeFile(filePath, codeTemplate);
}

return filePath;
}

public async showSolution(problemNode: IProblem, language: string): Promise<string> {
const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", "node", [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "--solution", "-l", language]);
const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "--solution", "-l", language]);
return solution;
}

public async getDescription(problemNode: IProblem): Promise<string> {
return await this.executeCommandWithProgressEx("Fetching problem description...", "node", [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "-x"]);
return await this.executeCommandWithProgressEx("Fetching problem description...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "-x"]);
}

public async listSessions(): Promise<string> {
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session"]);
}

public async enableSession(name: string): Promise<string> {
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-e", name]);
}

public async createSession(name: string): Promise<string> {
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-c", name]);
}

public async submitSolution(filePath: string): Promise<string> {
try {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]);
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]);
} catch (error) {
if (error.result) {
return error.result;
Expand All @@ -123,18 +140,18 @@ class LeetCodeExecutor {

public async testSolution(filePath: string, testString?: string): Promise<string> {
if (testString) {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `${testString}`]);
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `${testString}`]);
}
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]);
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]);
}

public async switchEndpoint(endpoint: string): Promise<string> {
switch (endpoint) {
case Endpoint.LeetCodeCN:
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]);
case Endpoint.LeetCode:
default:
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]);
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]);
}
}

Expand All @@ -149,6 +166,19 @@ class LeetCodeExecutor {
return { companies: COMPONIES, tags: TAGS };
}

public get node(): string {
return this.nodeExecutable;
}

public dispose(): void {
this.configurationChangeListener.dispose();
}

private getNodePath(): string {
const extensionConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode", null);
return extensionConfig.get<string>("nodePath", "node" /* default value */);
}

private async executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise<string> {
if (wsl.useWsl()) {
return await executeCommand("wsl", [command].concat(args), options);
Expand Down
4 changes: 2 additions & 2 deletions src/leetCodeManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ class LeetCodeManager extends EventEmitter {
const leetCodeBinaryPath: string = await leetCodeExecutor.getLeetCodeBinaryPath();

const childProc: cp.ChildProcess = wsl.useWsl()
? cp.spawn("wsl", ["node", leetCodeBinaryPath, "user", "-l"], { shell: true })
: cp.spawn("node", [leetCodeBinaryPath, "user", "-l"], {
? cp.spawn("wsl", [leetCodeExecutor.node, leetCodeBinaryPath, "user", "-l"], { shell: true })
: cp.spawn(leetCodeExecutor.node, [leetCodeBinaryPath, "user", "-l"], {
shell: true,
env: createEnvOption(),
});
Expand Down
3 changes: 2 additions & 1 deletion src/utils/wslUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@

import * as vscode from "vscode";
import { executeCommand } from "./cpUtils";
import { isWindows } from "./osUtils";

export function useWsl(): boolean {
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
return process.platform === "win32" && leetCodeConfig.get<boolean>("useWsl") === true;
return isWindows() && leetCodeConfig.get<boolean>("useWsl") === true;
}

export async function toWslPath(path: string): Promise<string> {
Expand Down

0 comments on commit c6c4e9c

Please sign in to comment.