From a154c782854a77d2130cfd78e2565c4a54461f45 Mon Sep 17 00:00:00 2001 From: "sheche@microsoft.com" Date: Wed, 1 Aug 2018 21:10:05 +0800 Subject: [PATCH 1/5] extract leetcode command - part 1 --- src/commands/list.ts | 5 ++-- src/commands/session.ts | 7 +++--- src/leetCodeExecutor.ts | 53 +++++++++++++++++++++++++++++++++++++++++ src/leetCodeManager.ts | 2 +- src/shared.ts | 9 +------ src/utils/cpUtils.ts | 5 +--- src/utils/wslUtils.ts | 19 +++++++++++---- 7 files changed, 77 insertions(+), 23 deletions(-) create mode 100644 src/leetCodeExecutor.ts diff --git a/src/commands/list.ts b/src/commands/list.ts index fd425796..83f836a4 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -1,6 +1,7 @@ "use strict"; import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { leetCodeBinaryPath, ProblemState, UserStatus } from "../shared"; import { executeCommand } from "../utils/cpUtils"; @@ -22,8 +23,8 @@ export async function listProblems(): Promise { return []; } const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - const showLocked: boolean | undefined = leetCodeConfig.get("showLocked"); - const result: string = await executeCommand("node", showLocked ? [leetCodeBinaryPath, "list"] : [leetCodeBinaryPath, "list", "-q", "L"]); + const showLocked: boolean = !!leetCodeConfig.get("showLocked"); + const result: string = await leetCodeExecutor.listProblems(showLocked); const problems: IProblem[] = []; const lines: string[] = result.split("\n"); const reg: RegExp = /^(.)\s(.{1,2})\s(.)\s\[\s*(\d*)\]\s*(.*)\s*(Easy|Medium|Hard)\s*\((\s*\d+\.\d+ %)\)/; diff --git a/src/commands/session.ts b/src/commands/session.ts index b3f3e431..4a7fa232 100644 --- a/src/commands/session.ts +++ b/src/commands/session.ts @@ -1,6 +1,7 @@ "use strict"; import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IQuickItemEx, leetCodeBinaryPath } from "../shared"; import { executeCommand } from "../utils/cpUtils"; @@ -12,7 +13,7 @@ export async function getSessionList(): Promise { promptForSignIn(); return []; } - const result: string = await executeCommand("node", [leetCodeBinaryPath, "session"]); + const result: string = await leetCodeExecutor.listSessions(); const lines: string[] = result.split("\n"); const sessions: ISession[] = []; const reg: RegExp = /(.?)\s*(\d+)\s+(.*)\s+(\d+ \(\s*\d+\.\d+ %\))\s+(\d+ \(\s*\d+\.\d+ %\))/; @@ -41,7 +42,7 @@ export async function selectSession(): Promise { return; } try { - await executeCommand("node", [leetCodeBinaryPath, "session", "-e", choice.value]); + await leetCodeExecutor.enableSession(choice.value); vscode.window.showInformationMessage(`Successfully switched to session '${choice.label}'.`); await vscode.commands.executeCommand("leetcode.refreshExplorer"); } catch (error) { @@ -81,7 +82,7 @@ export async function createSession(): Promise { return; } try { - await executeCommand("node", [leetCodeBinaryPath, "session", "-c", session]); + await leetCodeExecutor.createSession(session); vscode.window.showInformationMessage("New session created, you can switch to it by clicking the status bar."); } catch (error) { await promptForOpenOutputChannel("Failed to create session. Please open the output channel for details.", DialogType.error); diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts new file mode 100644 index 00000000..b43318f0 --- /dev/null +++ b/src/leetCodeExecutor.ts @@ -0,0 +1,53 @@ +"use strict"; + +import * as path from "path"; +import * as wsl from "./utils/wslUtils"; + +export interface ILeetCodeExecutor { + listProblems(showLocked: boolean): Promise; + + listSessions(): Promise; + enableSession(name: string): Promise; + createSession(name: string): Promise; +} + +class LeetCodeExecutor implements ILeetCodeExecutor { + private leetCodeBinaryPath: string; + private leetCodeBinaryPathInWsl: string; + + constructor() { + this.leetCodeBinaryPath = `"${path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode")}"`; + this.leetCodeBinaryPathInWsl = ""; + } + + public async getLeetCodeBinaryPath(): Promise { + if (wsl.useWsl()) { + if (!this.leetCodeBinaryPathInWsl) { + this.leetCodeBinaryPathInWsl = await wsl.toWslPath(this.leetCodeBinaryPath); + } + return this.leetCodeBinaryPathInWsl; + } + return this.leetCodeBinaryPath; + } + + public async listProblems(showLocked: boolean): Promise { + return await wsl.executeCommandEx("node", showLocked ? + [await this.getLeetCodeBinaryPath(), "list"] : + [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], + ); + } + + public async listSessions(): Promise { + return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); + } + + public async enableSession(name: string): Promise { + return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); + } + + public async createSession(name: string): Promise { + return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); + } +} + +export const leetCodeExecutor: ILeetCodeExecutor = new LeetCodeExecutor(); diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 542b365d..6e0de436 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -47,7 +47,7 @@ class LeetCodeManager extends EventEmitter implements ILeetCodeManager { let result: string = ""; const childProc: cp.ChildProcess = wsl.useWsl() - ? cp.spawn("wsl", ["node", leetCodeBinaryPath, "user", "-l"], { shell: true }) + ? cp.spawn("wsl", ["node", await wsl.toWslPath(leetCodeBinaryPath), "user", "-l"], { shell: true }) : cp.spawn("node", [leetCodeBinaryPath, "user", "-l"], { shell: true }); childProc.stdout.on("data", (data: string | Buffer) => { diff --git a/src/shared.ts b/src/shared.ts index 0c85a68b..6a2317f6 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -2,15 +2,8 @@ import * as path from "path"; import * as vscode from "vscode"; -import * as wsl from "./utils/wslUtils"; -let binPath: string = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode"); - -if (wsl.useWsl()) { - binPath = wsl.toWslPath(binPath); -} - -export const leetCodeBinaryPath: string = `"${binPath}"`; +export const leetCodeBinaryPath: string = `"${path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode")}"`; export interface IQuickItemEx extends vscode.QuickPickItem { value: T; diff --git a/src/utils/cpUtils.ts b/src/utils/cpUtils.ts index c8393ebb..75e7f6ce 100644 --- a/src/utils/cpUtils.ts +++ b/src/utils/cpUtils.ts @@ -3,15 +3,12 @@ import * as cp from "child_process"; import * as vscode from "vscode"; import { leetCodeChannel } from "../leetCodeChannel"; -import * as wsl from "./wslUtils"; export async function executeCommand(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { return new Promise((resolve: (res: string) => void, reject: (e: Error) => void): void => { let result: string = ""; - const childProc: cp.ChildProcess = wsl.useWsl() - ? cp.spawn("wsl", [command].concat(args), options) - : cp.spawn(command, args, options); + const childProc: cp.ChildProcess = cp.spawn(command, args, options); childProc.stdout.on("data", (data: string | Buffer) => { data = data.toString(); diff --git a/src/utils/wslUtils.ts b/src/utils/wslUtils.ts index d2b0d566..b09c9c4f 100644 --- a/src/utils/wslUtils.ts +++ b/src/utils/wslUtils.ts @@ -2,17 +2,26 @@ import * as cp from "child_process"; import * as vscode from "vscode"; +import { executeCommand } from "./cpUtils"; + +const wslCommand: string = "wsl"; export function useWsl(): boolean { const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - return process.platform === "win32" && leetCodeConfig.get("useWsl") === true; } -export function toWslPath(path: string): string { - return cp.execFileSync("wsl", ["wslpath", "-u", `${path.replace(/\\/g, "/")}`]).toString().trim(); +export async function toWslPath(path: string): Promise { + return await executeCommand(wslCommand, ["wslpath", "-u", `"${path}"`]).toString().trim(); +} + +export async function toWinPath(path: string): Promise { + return await executeCommand(wslCommand, ["wslpath", "-w", `"${path}"`]).toString().trim(); } -export function toWinPath(path: string): string { - return cp.execFileSync("wsl", ["wslpath", "-w", path]).toString().trim(); +export async function executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { + if (useWsl()) { + return await executeCommand(wslCommand, [command].concat(args), options); + } + return await executeCommand(command, args, options); } From 262e8ba533e0b78853e1e8a1c49c337004d9c925 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Mon, 6 Aug 2018 19:38:31 +0800 Subject: [PATCH 2/5] improve - part 2 --- src/commands/list.ts | 3 +-- src/commands/session.ts | 3 +-- src/commands/show.ts | 8 +++---- src/commands/submit.ts | 5 ++--- src/commands/test.ts | 10 ++++----- src/leetCodeExecutor.ts | 46 +++++++++++++++++++++++++++++++++++++---- src/leetCodeManager.ts | 11 +++++----- src/shared.ts | 2 -- src/utils/wslUtils.ts | 13 +++++++++--- 9 files changed, 71 insertions(+), 30 deletions(-) diff --git a/src/commands/list.ts b/src/commands/list.ts index 83f836a4..4656a230 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -3,8 +3,7 @@ import * as vscode from "vscode"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; -import { leetCodeBinaryPath, ProblemState, UserStatus } from "../shared"; -import { executeCommand } from "../utils/cpUtils"; +import { ProblemState, UserStatus } from "../shared"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; export interface IProblem { diff --git a/src/commands/session.ts b/src/commands/session.ts index 4a7fa232..04da3239 100644 --- a/src/commands/session.ts +++ b/src/commands/session.ts @@ -3,8 +3,7 @@ import * as vscode from "vscode"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; -import { IQuickItemEx, leetCodeBinaryPath } from "../shared"; -import { executeCommand } from "../utils/cpUtils"; +import { IQuickItemEx } from "../shared"; import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; export async function getSessionList(): Promise { diff --git a/src/commands/show.ts b/src/commands/show.ts index 808f00be..e50fa821 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -2,10 +2,10 @@ import * as fse from "fs-extra"; import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; import { LeetCodeNode } from "../leetCodeExplorer"; import { leetCodeManager } from "../leetCodeManager"; -import { IQuickItemEx, languages, leetCodeBinaryPath, ProblemState } from "../shared"; -import { executeCommandWithProgress } from "../utils/cpUtils"; +import { IQuickItemEx, languages, ProblemState } from "../shared"; import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; import { selectWorkspaceFolder } from "../utils/workspaceUtils"; import * as wsl from "../utils/wslUtils"; @@ -50,11 +50,11 @@ async function showProblemInternal(id: string): Promise { const outdir: string = await selectWorkspaceFolder(); await fse.ensureDir(outdir); - const result: string = await executeCommandWithProgress("Fetching problem data...", "node", [leetCodeBinaryPath, "show", id, "-gx", "-l", language, "-o", `"${outdir}"`]); + const result: string = await leetCodeExecutor.showProblem(id, language, outdir); const reg: RegExp = /\* Source Code:\s*(.*)/; const match: RegExpMatchArray | null = result.match(reg); if (match && match.length >= 2) { - const filePath: string = wsl.useWsl() ? wsl.toWinPath(match[1].trim()) : match[1].trim(); + const filePath: string = wsl.useWsl() ? await wsl.toWinPath(match[1].trim()) : match[1].trim(); await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false }); } else { diff --git a/src/commands/submit.ts b/src/commands/submit.ts index ee67720a..1eaeb2b3 100644 --- a/src/commands/submit.ts +++ b/src/commands/submit.ts @@ -1,9 +1,8 @@ "use strict"; import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; -import { leetCodeBinaryPath } from "../shared"; -import { executeCommandWithProgress } from "../utils/cpUtils"; import { DialogType, promptForOpenOutputChannel, promptForSignIn, showResultFile } from "../utils/uiUtils"; import { getActivefilePath } from "../utils/workspaceUtils"; @@ -19,7 +18,7 @@ export async function submitSolution(uri?: vscode.Uri): Promise { } try { - const result: string = await executeCommandWithProgress("Submitting to LeetCode...", "node", [leetCodeBinaryPath, "submit", `"${filePath}"`]); + const result: string = await leetCodeExecutor.submitSolution(filePath); await showResultFile(result); } catch (error) { await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error); diff --git a/src/commands/test.ts b/src/commands/test.ts index 2df1878e..4d22b5e9 100644 --- a/src/commands/test.ts +++ b/src/commands/test.ts @@ -2,9 +2,9 @@ import * as fse from "fs-extra"; import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; -import { IQuickItemEx, leetCodeBinaryPath, UserStatus } from "../shared"; -import { executeCommandWithProgress } from "../utils/cpUtils"; +import { IQuickItemEx, UserStatus } from "../shared"; import { DialogType, promptForOpenOutputChannel, showFileSelectDialog, showResultFile } from "../utils/uiUtils"; import { getActivefilePath } from "../utils/workspaceUtils"; @@ -47,7 +47,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { let result: string | undefined; switch (choice.value) { case ":default": - result = await executeCommandWithProgress("Submitting to LeetCode...", "node", [leetCodeBinaryPath, "test", `"${filePath}"`]); + result = await leetCodeExecutor.testSolution(filePath); break; case ":direct": const testString: string | undefined = await vscode.window.showInputBox({ @@ -57,7 +57,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { ignoreFocusOut: true, }); if (testString) { - result = await executeCommandWithProgress("Submitting to LeetCode...", "node", [leetCodeBinaryPath, "test", `"${filePath}"`, "-t", `"${testString.replace(/"/g, "")}"`]); + result = await leetCodeExecutor.testSolution(filePath, testString.replace(/"/g, "")); } break; case ":file": @@ -65,7 +65,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { if (testFile && testFile.length) { const input: string = await fse.readFile(testFile[0].fsPath, "utf-8"); if (input.trim()) { - result = await executeCommandWithProgress("Submitting to LeetCode...", "node", [leetCodeBinaryPath, "test", `"${filePath}"`, "-t", `"${input.replace(/"/g, "").replace(/\r?\n/g, "\\n")}"`]); + result = await leetCodeExecutor.testSolution(filePath, input.replace(/"/g, "").replace(/\r?\n/g, "\\n")); } else { vscode.window.showErrorMessage("The selected test file must not be empty."); } diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index b43318f0..0749dea4 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -4,11 +4,26 @@ import * as path from "path"; import * as wsl from "./utils/wslUtils"; export interface ILeetCodeExecutor { + getLeetCodeBinaryPath(): Promise; + + /* section for user command */ + getUserInfo(): Promise; + signOut(): Promise; + // TODO: implement login when leetcode-cli support login in batch mode. + // signIn(): Promise; + + /* section for problem command */ listProblems(showLocked: boolean): Promise; + showProblem(id: string, language: string, outdir: string): Promise; + /* section for session command */ listSessions(): Promise; enableSession(name: string): Promise; createSession(name: string): Promise; + + /* section for solution command */ + submitSolution(filePath: string): Promise; + testSolution(filePath: string, testString?: string): Promise; } class LeetCodeExecutor implements ILeetCodeExecutor { @@ -16,18 +31,26 @@ class LeetCodeExecutor implements ILeetCodeExecutor { private leetCodeBinaryPathInWsl: string; constructor() { - this.leetCodeBinaryPath = `"${path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode")}"`; + this.leetCodeBinaryPath = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode"); this.leetCodeBinaryPathInWsl = ""; } public async getLeetCodeBinaryPath(): Promise { if (wsl.useWsl()) { if (!this.leetCodeBinaryPathInWsl) { - this.leetCodeBinaryPathInWsl = await wsl.toWslPath(this.leetCodeBinaryPath); + this.leetCodeBinaryPathInWsl = `${await wsl.toWslPath(this.leetCodeBinaryPath)}`; } - return this.leetCodeBinaryPathInWsl; + return `"${this.leetCodeBinaryPathInWsl}"`; } - return this.leetCodeBinaryPath; + return `"${this.leetCodeBinaryPath}"`; + } + + public async getUserInfo(): Promise { + return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); + } + + public async signOut(): Promise { + return await await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); } public async listProblems(showLocked: boolean): Promise { @@ -37,6 +60,10 @@ class LeetCodeExecutor implements ILeetCodeExecutor { ); } + public async showProblem(id: string, language: string, outdir: string): Promise { + return await wsl.executeCommandWithProgressEx("Fetching problem data...", "node", [await this.getLeetCodeBinaryPath(), "show", id, "-gx", "-l", language, "-o", `"${outdir}"`]); + } + public async listSessions(): Promise { return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); } @@ -48,6 +75,17 @@ class LeetCodeExecutor implements ILeetCodeExecutor { public async createSession(name: string): Promise { return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); } + + public async submitSolution(filePath: string): Promise { + return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]); + } + + public async testSolution(filePath: string, testString?: string): Promise { + if (testString) { + return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `"${testString}"`]); + } + return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]); + } } export const leetCodeExecutor: ILeetCodeExecutor = new LeetCodeExecutor(); diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 6e0de436..24ad4ebc 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -4,9 +4,8 @@ import * as cp from "child_process"; import { EventEmitter } from "events"; import * as vscode from "vscode"; import { leetCodeChannel } from "./leetCodeChannel"; +import { leetCodeExecutor } from "./leetCodeExecutor"; import { UserStatus } from "./shared"; -import { leetCodeBinaryPath } from "./shared"; -import { executeCommand } from "./utils/cpUtils"; import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; @@ -30,7 +29,7 @@ class LeetCodeManager extends EventEmitter implements ILeetCodeManager { public async getLoginStatus(): Promise { try { - const result: string = await executeCommand("node", [leetCodeBinaryPath, "user"]); + const result: string = await leetCodeExecutor.getUserInfo(); this.currentUser = result.slice("You are now login as".length).trim(); this.userStatus = UserStatus.SignedIn; } catch (error) { @@ -46,8 +45,10 @@ class LeetCodeManager extends EventEmitter implements ILeetCodeManager { const userName: string | undefined = await new Promise(async (resolve: (res: string | undefined) => void, reject: (e: Error) => void): Promise => { let result: string = ""; + const leetCodeBinaryPath: string = await leetCodeExecutor.getLeetCodeBinaryPath(); + const childProc: cp.ChildProcess = wsl.useWsl() - ? cp.spawn("wsl", ["node", await wsl.toWslPath(leetCodeBinaryPath), "user", "-l"], { shell: true }) + ? cp.spawn("wsl", ["node", leetCodeBinaryPath, "user", "-l"], { shell: true }) : cp.spawn("node", [leetCodeBinaryPath, "user", "-l"], { shell: true }); childProc.stdout.on("data", (data: string | Buffer) => { @@ -102,7 +103,7 @@ class LeetCodeManager extends EventEmitter implements ILeetCodeManager { public async signOut(): Promise { try { - await executeCommand("node", [leetCodeBinaryPath, "user", "-L"]); + await leetCodeExecutor.signOut(); vscode.window.showInformationMessage("Successfully signed out."); this.currentUser = undefined; this.userStatus = UserStatus.SignedOut; diff --git a/src/shared.ts b/src/shared.ts index 6a2317f6..37ae1b04 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -3,8 +3,6 @@ import * as path from "path"; import * as vscode from "vscode"; -export const leetCodeBinaryPath: string = `"${path.join(__dirname, "..", "..", "node_modules", "leetcode-cli", "bin", "leetcode")}"`; - export interface IQuickItemEx extends vscode.QuickPickItem { value: T; } diff --git a/src/utils/wslUtils.ts b/src/utils/wslUtils.ts index b09c9c4f..0e3a65aa 100644 --- a/src/utils/wslUtils.ts +++ b/src/utils/wslUtils.ts @@ -2,7 +2,7 @@ import * as cp from "child_process"; import * as vscode from "vscode"; -import { executeCommand } from "./cpUtils"; +import { executeCommand, executeCommandWithProgress } from "./cpUtils"; const wslCommand: string = "wsl"; @@ -12,11 +12,11 @@ export function useWsl(): boolean { } export async function toWslPath(path: string): Promise { - return await executeCommand(wslCommand, ["wslpath", "-u", `"${path}"`]).toString().trim(); + return (await executeCommand(wslCommand, ["wslpath", "-u", `"${path.replace(/\\/g, "/")}"`])).trim(); } export async function toWinPath(path: string): Promise { - return await executeCommand(wslCommand, ["wslpath", "-w", `"${path}"`]).toString().trim(); + return (await executeCommand(wslCommand, ["wslpath", "-w", `"${path}"`])).trim(); } export async function executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { @@ -25,3 +25,10 @@ export async function executeCommandEx(command: string, args: string[], options: } return await executeCommand(command, args, options); } + +export async function executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { + if (useWsl()) { + return await executeCommandWithProgress(message, wslCommand, [command].concat(args), options); + } + return await executeCommandWithProgress(message, command, args, options); +} From 60299f3d6329e2e4d00d00ab6bb8fa410bf05965 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 7 Aug 2018 19:02:19 +0800 Subject: [PATCH 3/5] move wsl logic into leetCodeExecutor --- src/leetCodeExecutor.ts | 36 ++++++++++++++++++++++++++---------- src/utils/wslUtils.ts | 23 +++-------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 0749dea4..a9c044b8 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -1,6 +1,8 @@ "use strict"; +import * as cp from "child_process"; import * as path from "path"; +import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils"; import * as wsl from "./utils/wslUtils"; export interface ILeetCodeExecutor { @@ -46,45 +48,59 @@ class LeetCodeExecutor implements ILeetCodeExecutor { } public async getUserInfo(): Promise { - return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); } public async signOut(): Promise { - return await await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); + return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); } public async listProblems(showLocked: boolean): Promise { - return await wsl.executeCommandEx("node", showLocked ? + return await this.executeCommandEx("node", showLocked ? [await this.getLeetCodeBinaryPath(), "list"] : [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], ); } public async showProblem(id: string, language: string, outdir: string): Promise { - return await wsl.executeCommandWithProgressEx("Fetching problem data...", "node", [await this.getLeetCodeBinaryPath(), "show", id, "-gx", "-l", language, "-o", `"${outdir}"`]); + return await this.executeCommandWithProgressEx("Fetching problem data...", "node", [await this.getLeetCodeBinaryPath(), "show", id, "-gx", "-l", language, "-o", `"${outdir}"`]); } public async listSessions(): Promise { - return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); } public async enableSession(name: string): Promise { - return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); } public async createSession(name: string): Promise { - return await wsl.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); } public async submitSolution(filePath: string): Promise { - return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]); + return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]); } public async testSolution(filePath: string, testString?: string): Promise { if (testString) { - return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `"${testString}"`]); + return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `"${testString}"`]); } - return await wsl.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]); + return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]); + } + + private async executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { + if (wsl.useWsl()) { + return await executeCommand("wsl", [command].concat(args), options); + } + return await executeCommand(command, args, options); + } + + private async executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { + if (wsl.useWsl()) { + return await executeCommandWithProgress(message, "wsl", [command].concat(args), options); + } + return await executeCommandWithProgress(message, command, args, options); } } diff --git a/src/utils/wslUtils.ts b/src/utils/wslUtils.ts index 0e3a65aa..6b1efcc3 100644 --- a/src/utils/wslUtils.ts +++ b/src/utils/wslUtils.ts @@ -1,10 +1,7 @@ "use strict"; -import * as cp from "child_process"; import * as vscode from "vscode"; -import { executeCommand, executeCommandWithProgress } from "./cpUtils"; - -const wslCommand: string = "wsl"; +import { executeCommand } from "./cpUtils"; export function useWsl(): boolean { const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); @@ -12,23 +9,9 @@ export function useWsl(): boolean { } export async function toWslPath(path: string): Promise { - return (await executeCommand(wslCommand, ["wslpath", "-u", `"${path.replace(/\\/g, "/")}"`])).trim(); + return (await executeCommand("wsl", ["wslpath", "-u", `"${path.replace(/\\/g, "/")}"`])).trim(); } export async function toWinPath(path: string): Promise { - return (await executeCommand(wslCommand, ["wslpath", "-w", `"${path}"`])).trim(); -} - -export async function executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { - if (useWsl()) { - return await executeCommand(wslCommand, [command].concat(args), options); - } - return await executeCommand(command, args, options); -} - -export async function executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { - if (useWsl()) { - return await executeCommandWithProgress(message, wslCommand, [command].concat(args), options); - } - return await executeCommandWithProgress(message, command, args, options); + return (await executeCommand("wsl", ["wslpath", "-w", `"${path}"`])).trim(); } From 8c52f42f37bcc48b0f79210545169e629ec456d3 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Tue, 7 Aug 2018 19:04:47 +0800 Subject: [PATCH 4/5] remove unused imports --- src/shared.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared.ts b/src/shared.ts index 37ae1b04..9a5184ee 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -1,6 +1,5 @@ "use strict"; -import * as path from "path"; import * as vscode from "vscode"; export interface IQuickItemEx extends vscode.QuickPickItem { From 526cedd1eb52c6383fe1342c9d3b744bde784b39 Mon Sep 17 00:00:00 2001 From: Sheng Chen Date: Wed, 8 Aug 2018 21:04:41 +0800 Subject: [PATCH 5/5] fix bug --- src/extension.ts | 4 ++-- src/leetCodeExecutor.ts | 20 ++++++++++++++++++++ src/utils/nodeUtils.ts | 22 ---------------------- 3 files changed, 22 insertions(+), 24 deletions(-) delete mode 100644 src/utils/nodeUtils.ts diff --git a/src/extension.ts b/src/extension.ts index b8b298b9..78182b67 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,13 +6,13 @@ import * as show from "./commands/show"; import * as submit from "./commands/submit"; import * as test from "./commands/test"; import { leetCodeChannel } from "./leetCodeChannel"; +import { leetCodeExecutor } from "./leetCodeExecutor"; import { LeetCodeNode, LeetCodeTreeDataProvider } from "./leetCodeExplorer"; import { leetCodeManager } from "./leetCodeManager"; import { leetCodeStatusBarItem } from "./leetCodeStatusBarItem"; -import { isNodeInstalled } from "./utils/nodeUtils"; export async function activate(context: vscode.ExtensionContext): Promise { - if (!await isNodeInstalled()) { + if (!await leetCodeExecutor.meetRequirements()) { return; } leetCodeManager.getLoginStatus(); diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index a9c044b8..20353c03 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -1,11 +1,15 @@ "use strict"; import * as cp from "child_process"; +import * as opn from "opn"; import * as path from "path"; +import * as vscode from "vscode"; import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils"; +import { DialogOptions } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; export interface ILeetCodeExecutor { + meetRequirements(): Promise; getLeetCodeBinaryPath(): Promise; /* section for user command */ @@ -47,6 +51,22 @@ class LeetCodeExecutor implements ILeetCodeExecutor { return `"${this.leetCodeBinaryPath}"`; } + public async meetRequirements(): Promise { + try { + await this.executeCommandEx("node", ["-v"]); + return true; + } catch (error) { + const choice: vscode.MessageItem | undefined = await vscode.window.showErrorMessage( + "LeetCode extension needs Node.js installed in environment path", + DialogOptions.open, + ); + if (choice === DialogOptions.open) { + opn("https://nodejs.org"); + } + return false; + } + } + public async getUserInfo(): Promise { return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); } diff --git a/src/utils/nodeUtils.ts b/src/utils/nodeUtils.ts deleted file mode 100644 index 98df8705..00000000 --- a/src/utils/nodeUtils.ts +++ /dev/null @@ -1,22 +0,0 @@ -"use strict"; - -import * as opn from "opn"; -import * as vscode from "vscode"; -import { executeCommand } from "./cpUtils"; -import { DialogOptions } from "./uiUtils"; - -export async function isNodeInstalled(): Promise { - try { - await executeCommand("node", ["-v"]); - return true; - } catch (error) { - const choice: vscode.MessageItem | undefined = await vscode.window.showErrorMessage( - "LeetCode extension need Node.js installed in environment path", - DialogOptions.open, - ); - if (choice === DialogOptions.open) { - opn("https://nodejs.org"); - } - return false; - } -}