From 6b881fca0382492a4dd6b7ad47ad9751d2e93d74 Mon Sep 17 00:00:00 2001 From: Dec-F Date: Fri, 1 Mar 2019 18:40:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20add=20a=20new=20config:'fileNam?= =?UTF-8?q?e'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/commands/show.ts | 192 +++++++-------- src/explorer/LeetCodeTreeDataProvider.ts | 39 ++- src/leetCodeExecutor.ts | 292 +++++++++++++---------- src/utils/problemUtils.ts | 28 ++- src/utils/templateUtils.ts | 49 ++++ tslint.json | 49 ++-- 6 files changed, 365 insertions(+), 284 deletions(-) create mode 100644 src/utils/templateUtils.ts diff --git a/src/commands/show.ts b/src/commands/show.ts index d1ce1cf4..a1bbfa18 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -15,123 +15,125 @@ import * as wsl from "../utils/wslUtils"; import * as list from "./list"; export async function showProblem(node?: LeetCodeNode): Promise { - if (!node) { - return; - } - await showProblemInternal(node); + if (!node) { + return; + } + await showProblemInternal(node); } export async function searchProblem(): Promise { - if (!leetCodeManager.getUser()) { - promptForSignIn(); - return; - } - const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick( - parseProblemsToPicks(list.listProblems()), - { - matchOnDetail: true, - placeHolder: "Select one problem", - }, - ); - if (!choice) { - return; - } - await showProblemInternal(choice.value); + if (!leetCodeManager.getUser()) { + promptForSignIn(); + return; + } + const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseProblemsToPicks(list.listProblems()), { + matchOnDetail: true, + placeHolder: "Select one problem", + }); + if (!choice) { + return; + } + await showProblemInternal(choice.value); } async function showProblemInternal(node: IProblem): Promise { - try { - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage"); - if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) { - defaultLanguage = undefined; - } - const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" }); - if (!language) { - return; - } + try { + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage"); + if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) { + defaultLanguage = undefined; + } + const language: string | undefined = + defaultLanguage || (await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" })); + if (!language) { + return; + } - let outDir: string = await selectWorkspaceFolder(); - let relativePath: string = (leetCodeConfig.get("outputFolder") || "").trim(); - const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/); - if (matchResult) { - const resolvedPath: string | undefined = await resolveRelativePath(matchResult[1].toLocaleLowerCase(), node, language); - if (!resolvedPath) { - leetCodeChannel.appendLine("Showing problem canceled by user."); - return; - } - relativePath = resolvedPath; - } + let outDir: string = await selectWorkspaceFolder(); + let relativePath: string = (leetCodeConfig.get("outputFolder") || "").trim(); + const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/); + if (matchResult) { + const resolvedPath: string | undefined = await resolveRelativePath(matchResult[1].toLocaleLowerCase(), node, language); + if (!resolvedPath) { + leetCodeChannel.appendLine("Showing problem canceled by user."); + return; + } + relativePath = resolvedPath; + } - outDir = path.join(outDir, relativePath); - await fse.ensureDir(outDir); + outDir = path.join(outDir, relativePath); + await fse.ensureDir(outDir); - const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir); - const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath; - await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false }); + const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir); + const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath; + await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false }); - if (!defaultLanguage && leetCodeConfig.get("showSetDefaultLanguageHint")) { - const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage( - `Would you like to set '${language}' as your default language?`, - DialogOptions.yes, - DialogOptions.no, - DialogOptions.never, - ); - if (choice === DialogOptions.yes) { - leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */); - } else if (choice === DialogOptions.never) { - leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */); - } - } - } catch (error) { - await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error); + if (!defaultLanguage && leetCodeConfig.get("showSetDefaultLanguageHint")) { + const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage( + `Would you like to set '${language}' as your default language?`, + DialogOptions.yes, + DialogOptions.no, + DialogOptions.never, + ); + if (choice === DialogOptions.yes) { + leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */); + } else if (choice === DialogOptions.never) { + leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */); + } } + } catch (error) { + await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error); + } } async function parseProblemsToPicks(p: Promise): Promise>> { - return new Promise(async (resolve: (res: Array>) => void): Promise => { - const picks: Array> = (await p).map((problem: IProblem) => Object.assign({}, { + return new Promise( + async (resolve: (res: Array>) => void): Promise => { + const picks: Array> = (await p).map((problem: IProblem) => + Object.assign( + {}, + { label: `${parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`, description: "", detail: `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`, value: problem, - })); - resolve(picks); - }); + }, + ), + ); + resolve(picks); + }, + ); } function parseProblemDecorator(state: ProblemState, locked: boolean): string { - switch (state) { - case ProblemState.AC: - return "$(check) "; - case ProblemState.NotAC: - return "$(x) "; - default: - return locked ? "$(lock) " : ""; - } + switch (state) { + case ProblemState.AC: + return "$(check) "; + case ProblemState.NotAC: + return "$(x) "; + default: + return locked ? "$(lock) " : ""; + } } async function resolveRelativePath(value: string, node: IProblem, selectedLanguage: string): Promise { - switch (value) { - case "tag": - if (node.tags.length === 1) { - return node.tags[0]; - } - return await vscode.window.showQuickPick( - node.tags, - { - matchOnDetail: true, - placeHolder: "Multiple tags available, please select one", - ignoreFocusOut: true, - }, - ); - case "language": - return selectedLanguage; - case "difficulty": - return node.difficulty; - default: - const errorMsg: string = `The config '${value}' is not supported.`; - leetCodeChannel.appendLine(errorMsg); - throw new Error(errorMsg); - } + switch (value) { + case "tag": + if (node.tags.length === 1) { + return node.tags[0]; + } + return await vscode.window.showQuickPick(node.tags, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); + case "language": + return selectedLanguage; + case "difficulty": + return node.difficulty; + default: + const errorMsg: string = `The config '${value}' is not supported.`; + leetCodeChannel.appendLine(errorMsg); + throw new Error(errorMsg); + } } diff --git a/src/explorer/LeetCodeTreeDataProvider.ts b/src/explorer/LeetCodeTreeDataProvider.ts index 25ebbb8b..593dd103 100644 --- a/src/explorer/LeetCodeTreeDataProvider.ts +++ b/src/explorer/LeetCodeTreeDataProvider.ts @@ -65,27 +65,24 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider void): Promise => { - await this.getProblemData(); - resolve([ - new LeetCodeNode(Object.assign({}, defaultProblem, { - id: Category.Difficulty, - name: Category.Difficulty, - }), "ROOT", false), - new LeetCodeNode(Object.assign({}, defaultProblem, { - id: Category.Tag, - name: Category.Tag, - }), "ROOT", false), - new LeetCodeNode(Object.assign({}, defaultProblem, { - id: Category.Company, - name: Category.Company, - }), "ROOT", false), - new LeetCodeNode(Object.assign({}, defaultProblem, { - id: Category.Favorite, - name: Category.Favorite, - }), "ROOT", false), - ]); - }); + return [ + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Difficulty, + name: Category.Difficulty, + }), "ROOT", false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Tag, + name: Category.Tag, + }), "ROOT", false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Company, + name: Category.Company, + }), "ROOT", false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Favorite, + name: Category.Favorite, + }), "ROOT", false), + ]; } else { switch (element.name) { // First-level case Category.Favorite: diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 995c5ca3..ca8d4176 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -13,137 +13,167 @@ import { DialogOptions, openUrl } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; class LeetCodeExecutor { - private leetCodeRootPath: string; - private leetCodeRootPathInWsl: string; - - constructor() { - this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli"); - this.leetCodeRootPathInWsl = ""; - } - - public async getLeetCodeRootPath(): Promise { // not wrapped by "" - if (wsl.useWsl()) { - if (!this.leetCodeRootPathInWsl) { - this.leetCodeRootPathInWsl = `${await wsl.toWslPath(this.leetCodeRootPath)}`; - } - return `${this.leetCodeRootPathInWsl}`; - } - return `${this.leetCodeRootPath}`; - } - - public async getLeetCodeBinaryPath(): Promise { // wrapped by "" - return `"${path.join(await this.getLeetCodeRootPath(), "bin", "leetcode")}"`; - } - - public async meetRequirements(): Promise { - try { - await this.executeCommandEx("node", ["-v"]); - } 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) { - openUrl("https://nodejs.org"); - } - return false; - } - try { // Check company plugin - await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]); - } catch (error) { // Download company plugin and activate - await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]); - } - return true; - } - - public async deleteCache(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "cache", "-d"]); - } - - public async getUserInfo(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); - } - - public async signOut(): Promise { - return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); - } - - public async listProblems(showLocked: boolean): Promise { - return await this.executeCommandEx("node", showLocked ? - [await this.getLeetCodeBinaryPath(), "list"] : - [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], - ); - } - - public async showProblem(node: IProblem, language: string, outDir: string): Promise { - const fileName: string = genFileName(node, language); - 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", node.id, "-cx", "-l", language]); - await fse.writeFile(filePath, codeTemplate); - } - - return filePath; - } - - public async listSessions(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); - } - - public async enableSession(name: string): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); - } - - public async createSession(name: string): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); - } - - public async submitSolution(filePath: string): Promise { - 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 this.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}"`]); - } - - public async switchEndpoint(endpoint: string): Promise { - switch (endpoint) { - case Endpoint.LeetCodeCN: - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]); - case Endpoint.LeetCode: - default: - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]); - } - } - - public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }, tags: { [key: string]: string[] } }> { - // preprocess the plugin source - const companiesTagsPath: string = path.join(await leetCodeExecutor.getLeetCodeRootPath(), "lib", "plugins", "company.js"); - const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace( - "module.exports = plugin", - "module.exports = { COMPONIES, TAGS }", - ); - const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath); - return { companies: COMPONIES, tags: TAGS }; - } - - 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); - } + private leetCodeRootPath: string; + private leetCodeRootPathInWsl: string; + + constructor() { + this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli"); + this.leetCodeRootPathInWsl = ""; + } + + public async getLeetCodeRootPath(): Promise { + // not wrapped by "" + if (wsl.useWsl()) { + if (!this.leetCodeRootPathInWsl) { + this.leetCodeRootPathInWsl = `${await wsl.toWslPath(this.leetCodeRootPath)}`; + } + return `${this.leetCodeRootPathInWsl}`; + } + return `${this.leetCodeRootPath}`; + } + + public async getLeetCodeBinaryPath(): Promise { + // wrapped by "" + return `"${path.join(await this.getLeetCodeRootPath(), "bin", "leetcode")}"`; + } + + public async meetRequirements(): Promise { + try { + await this.executeCommandEx("node", ["-v"]); + } 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) { + openUrl("https://nodejs.org"); + } + return false; + } + try { + // Check company plugin + await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]); + } catch (error) { + // Download company plugin and activate + await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]); + } + return true; + } + + public async deleteCache(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "cache", "-d"]); + } + + public async getUserInfo(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); + } + + public async signOut(): Promise { + return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); + } + + public async listProblems(showLocked: boolean): Promise { + return await this.executeCommandEx( + "node", + showLocked ? [await this.getLeetCodeBinaryPath(), "list"] : [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], + ); + } + + public async showProblem(node: IProblem, language: string, outDir: string): Promise { + const fileName: string = await genFileName(node, language); + 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", + node.id, + "-cx", + "-l", + language, + ]); + await fse.writeFile(filePath, codeTemplate); + } + + return filePath; + } + + public async listSessions(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); + } + + public async enableSession(name: string): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); + } + + public async createSession(name: string): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); + } + + public async submitSolution(filePath: string): Promise { + 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 this.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}"`, + ]); + } + + public async switchEndpoint(endpoint: string): Promise { + switch (endpoint) { + case Endpoint.LeetCodeCN: + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]); + case Endpoint.LeetCode: + default: + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]); + } + } + + public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }; tags: { [key: string]: string[] } }> { + // preprocess the plugin source + const companiesTagsPath: string = path.join(await leetCodeExecutor.getLeetCodeRootPath(), "lib", "plugins", "company.js"); + const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace( + "module.exports = plugin", + "module.exports = { COMPONIES, TAGS }", + ); + const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath); + return { companies: COMPONIES, tags: TAGS }; + } + + 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); + } } export const leetCodeExecutor: LeetCodeExecutor = new LeetCodeExecutor(); diff --git a/src/utils/problemUtils.ts b/src/utils/problemUtils.ts index c7946bbc..bdc7b743 100644 --- a/src/utils/problemUtils.ts +++ b/src/utils/problemUtils.ts @@ -1,16 +1,26 @@ import kebabCase = require("lodash.kebabcase"); import { IProblem, langExt } from "../shared"; +import { supplantTpl } from "./templateUtils"; +import * as vscode from "vscode"; + +const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); +const fileNameTpl: string = leetCodeConfig.get("fileName") || ""; export function genFileExt(language: string): string { - const ext: string | undefined = langExt.get(language); - if (!ext) { - throw new Error(`The language "${language}" is not supported.`); - } - return ext; + const ext: string | undefined = langExt.get(language); + if (!ext) { + throw new Error(`The language "${language}" is not supported.`); + } + return ext; } -export function genFileName(node: IProblem, language: string): string { - const slug: string = kebabCase(node.name); - const ext: string = genFileExt(language); - return `${node.id}.${slug}.${ext}`; +export async function genFileName(node: IProblem, language: string): Promise { + const slug: string = kebabCase(node.name); + const ext: string = genFileExt(language); + const name: string = `${node.id}.${slug}.${ext}`; + if (!fileNameTpl) { + return name; + } else { + return `${await supplantTpl(fileNameTpl, node, language)}.${ext}` || name; + } } diff --git a/src/utils/templateUtils.ts b/src/utils/templateUtils.ts new file mode 100644 index 00000000..8807375c --- /dev/null +++ b/src/utils/templateUtils.ts @@ -0,0 +1,49 @@ +import { IProblem } from "../shared"; +import * as vscode from "vscode"; +import { leetCodeChannel } from "../leetCodeChannel"; + +export async function supplantTpl(tpl: string, node: IProblem, selectedLanguage: string): Promise { + const reg: RegExp = /[^{][a-zA-Z0-9]+(?=\})/g; + const matchResults: RegExpMatchArray = tpl.match(reg) || []; + let str: string = ""; + for (const token of matchResults) { + str += await getFiledValue(token, node, selectedLanguage); + } + + return str; +} + +async function getFiledValue(value: string, node: IProblem, selectedLanguage: string): Promise { + switch (value) { + case "id": + return node.id; + case "name": + return node.name; + case "language": + return selectedLanguage; + case "difficulty": + return node.difficulty; + case "tag": + if (node.tags.length === 1) { + return node.tags[0]; + } + return await vscode.window.showQuickPick(node.tags, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); + case "company": + if (node.companies.length === 1) { + return node.companies[0]; + } + return await vscode.window.showQuickPick(node.companies, { + matchOnDetail: true, + placeHolder: "Multiple companies available, please select one", + ignoreFocusOut: true, + }); + default: + const errorMsg: string = `The config '${value}' is not supported.`; + leetCodeChannel.appendLine(errorMsg); + throw new Error(errorMsg); + } +} diff --git a/tslint.json b/tslint.json index ae04746e..33eb4b72 100644 --- a/tslint.json +++ b/tslint.json @@ -1,31 +1,24 @@ { - "defaultSeverity": "error", - "extends": [ - "tslint:recommended" + "defaultSeverity": "error", + "extends": ["tslint:recommended"], + "jsRules": {}, + "rules": { + "object-literal-sort-keys": false, + "indent": [true, "spaces"], + "no-string-literal": false, + "no-namespace": false, + "max-line-length": [false, 120], + "typedef": [ + true, + "call-signature", + "arrow-call-signature", + "parameter", + "arrow-parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" ], - "jsRules": {}, - "rules": { - "object-literal-sort-keys": false, - "indent": [ - true, - "spaces" - ], - "no-string-literal": false, - "no-namespace": false, - "max-line-length": [ - false, - 120 - ], - "typedef": [ - true, - "call-signature", - "arrow-call-signature", - "parameter", - "arrow-parameter", - "property-declaration", - "variable-declaration", - "member-variable-declaration" - ] - }, - "rulesDirectory": [] + "ordered-imports": [false] + }, + "rulesDirectory": [] } From d7525ea3b8528d87c0d9f3e7ec5adfbb98fd02a2 Mon Sep 17 00:00:00 2001 From: Dec-F Date: Fri, 8 Mar 2019 17:02:17 +0800 Subject: [PATCH 2/2] format --- src/commands/show.ts | 202 ++++++++++++------------ src/leetCodeExecutor.ts | 322 +++++++++++++++++++------------------- src/utils/problemUtils.ts | 26 +-- 3 files changed, 275 insertions(+), 275 deletions(-) diff --git a/src/commands/show.ts b/src/commands/show.ts index a1bbfa18..e3c3cf62 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -15,125 +15,125 @@ import * as wsl from "../utils/wslUtils"; import * as list from "./list"; export async function showProblem(node?: LeetCodeNode): Promise { - if (!node) { - return; - } - await showProblemInternal(node); + if (!node) { + return; + } + await showProblemInternal(node); } export async function searchProblem(): Promise { - if (!leetCodeManager.getUser()) { - promptForSignIn(); - return; - } - const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseProblemsToPicks(list.listProblems()), { - matchOnDetail: true, - placeHolder: "Select one problem", - }); - if (!choice) { - return; - } - await showProblemInternal(choice.value); + if (!leetCodeManager.getUser()) { + promptForSignIn(); + return; + } + const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseProblemsToPicks(list.listProblems()), { + matchOnDetail: true, + placeHolder: "Select one problem", + }); + if (!choice) { + return; + } + await showProblemInternal(choice.value); } async function showProblemInternal(node: IProblem): Promise { - try { - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage"); - if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) { - defaultLanguage = undefined; - } - const language: string | undefined = - defaultLanguage || (await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" })); - if (!language) { - return; - } + try { + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage"); + if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) { + defaultLanguage = undefined; + } + const language: string | undefined = + defaultLanguage || (await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" })); + if (!language) { + return; + } - let outDir: string = await selectWorkspaceFolder(); - let relativePath: string = (leetCodeConfig.get("outputFolder") || "").trim(); - const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/); - if (matchResult) { - const resolvedPath: string | undefined = await resolveRelativePath(matchResult[1].toLocaleLowerCase(), node, language); - if (!resolvedPath) { - leetCodeChannel.appendLine("Showing problem canceled by user."); - return; - } - relativePath = resolvedPath; - } + let outDir: string = await selectWorkspaceFolder(); + let relativePath: string = (leetCodeConfig.get("outputFolder") || "").trim(); + const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/); + if (matchResult) { + const resolvedPath: string | undefined = await resolveRelativePath(matchResult[1].toLocaleLowerCase(), node, language); + if (!resolvedPath) { + leetCodeChannel.appendLine("Showing problem canceled by user."); + return; + } + relativePath = resolvedPath; + } - outDir = path.join(outDir, relativePath); - await fse.ensureDir(outDir); + outDir = path.join(outDir, relativePath); + await fse.ensureDir(outDir); - const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir); - const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath; - await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false }); + const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir); + const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath; + await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false }); - if (!defaultLanguage && leetCodeConfig.get("showSetDefaultLanguageHint")) { - const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage( - `Would you like to set '${language}' as your default language?`, - DialogOptions.yes, - DialogOptions.no, - DialogOptions.never, - ); - if (choice === DialogOptions.yes) { - leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */); - } else if (choice === DialogOptions.never) { - leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */); - } + if (!defaultLanguage && leetCodeConfig.get("showSetDefaultLanguageHint")) { + const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage( + `Would you like to set '${language}' as your default language?`, + DialogOptions.yes, + DialogOptions.no, + DialogOptions.never, + ); + if (choice === DialogOptions.yes) { + leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */); + } else if (choice === DialogOptions.never) { + leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */); + } + } + } catch (error) { + await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error); } - } catch (error) { - await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error); - } } async function parseProblemsToPicks(p: Promise): Promise>> { - return new Promise( - async (resolve: (res: Array>) => void): Promise => { - const picks: Array> = (await p).map((problem: IProblem) => - Object.assign( - {}, - { - label: `${parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`, - description: "", - detail: `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`, - value: problem, - }, - ), - ); - resolve(picks); - }, - ); + return new Promise( + async (resolve: (res: Array>) => void): Promise => { + const picks: Array> = (await p).map((problem: IProblem) => + Object.assign( + {}, + { + label: `${parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`, + description: "", + detail: `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`, + value: problem, + }, + ), + ); + resolve(picks); + }, + ); } function parseProblemDecorator(state: ProblemState, locked: boolean): string { - switch (state) { - case ProblemState.AC: - return "$(check) "; - case ProblemState.NotAC: - return "$(x) "; - default: - return locked ? "$(lock) " : ""; - } + switch (state) { + case ProblemState.AC: + return "$(check) "; + case ProblemState.NotAC: + return "$(x) "; + default: + return locked ? "$(lock) " : ""; + } } async function resolveRelativePath(value: string, node: IProblem, selectedLanguage: string): Promise { - switch (value) { - case "tag": - if (node.tags.length === 1) { - return node.tags[0]; - } - return await vscode.window.showQuickPick(node.tags, { - matchOnDetail: true, - placeHolder: "Multiple tags available, please select one", - ignoreFocusOut: true, - }); - case "language": - return selectedLanguage; - case "difficulty": - return node.difficulty; - default: - const errorMsg: string = `The config '${value}' is not supported.`; - leetCodeChannel.appendLine(errorMsg); - throw new Error(errorMsg); - } + switch (value) { + case "tag": + if (node.tags.length === 1) { + return node.tags[0]; + } + return await vscode.window.showQuickPick(node.tags, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); + case "language": + return selectedLanguage; + case "difficulty": + return node.difficulty; + default: + const errorMsg: string = `The config '${value}' is not supported.`; + leetCodeChannel.appendLine(errorMsg); + throw new Error(errorMsg); + } } diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index ca8d4176..339684f9 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -13,167 +13,167 @@ import { DialogOptions, openUrl } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; class LeetCodeExecutor { - private leetCodeRootPath: string; - private leetCodeRootPathInWsl: string; - - constructor() { - this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli"); - this.leetCodeRootPathInWsl = ""; - } - - public async getLeetCodeRootPath(): Promise { - // not wrapped by "" - if (wsl.useWsl()) { - if (!this.leetCodeRootPathInWsl) { - this.leetCodeRootPathInWsl = `${await wsl.toWslPath(this.leetCodeRootPath)}`; - } - return `${this.leetCodeRootPathInWsl}`; - } - return `${this.leetCodeRootPath}`; - } - - public async getLeetCodeBinaryPath(): Promise { - // wrapped by "" - return `"${path.join(await this.getLeetCodeRootPath(), "bin", "leetcode")}"`; - } - - public async meetRequirements(): Promise { - try { - await this.executeCommandEx("node", ["-v"]); - } 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) { - openUrl("https://nodejs.org"); - } - return false; - } - try { - // Check company plugin - await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]); - } catch (error) { - // Download company plugin and activate - await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]); - } - return true; - } - - public async deleteCache(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "cache", "-d"]); - } - - public async getUserInfo(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); - } - - public async signOut(): Promise { - return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); - } - - public async listProblems(showLocked: boolean): Promise { - return await this.executeCommandEx( - "node", - showLocked ? [await this.getLeetCodeBinaryPath(), "list"] : [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], - ); - } - - public async showProblem(node: IProblem, language: string, outDir: string): Promise { - const fileName: string = await genFileName(node, language); - 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", - node.id, - "-cx", - "-l", - language, - ]); - await fse.writeFile(filePath, codeTemplate); - } - - return filePath; - } - - public async listSessions(): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); - } - - public async enableSession(name: string): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); - } - - public async createSession(name: string): Promise { - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); - } - - public async submitSolution(filePath: string): Promise { - 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 this.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}"`, - ]); - } - - public async switchEndpoint(endpoint: string): Promise { - switch (endpoint) { - case Endpoint.LeetCodeCN: - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]); - case Endpoint.LeetCode: - default: - return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]); - } - } - - public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }; tags: { [key: string]: string[] } }> { - // preprocess the plugin source - const companiesTagsPath: string = path.join(await leetCodeExecutor.getLeetCodeRootPath(), "lib", "plugins", "company.js"); - const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace( - "module.exports = plugin", - "module.exports = { COMPONIES, TAGS }", - ); - const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath); - return { companies: COMPONIES, tags: TAGS }; - } - - 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); - } + private leetCodeRootPath: string; + private leetCodeRootPathInWsl: string; + + constructor() { + this.leetCodeRootPath = path.join(__dirname, "..", "..", "node_modules", "leetcode-cli"); + this.leetCodeRootPathInWsl = ""; + } + + public async getLeetCodeRootPath(): Promise { + // not wrapped by "" + if (wsl.useWsl()) { + if (!this.leetCodeRootPathInWsl) { + this.leetCodeRootPathInWsl = `${await wsl.toWslPath(this.leetCodeRootPath)}`; + } + return `${this.leetCodeRootPathInWsl}`; + } + return `${this.leetCodeRootPath}`; + } + + public async getLeetCodeBinaryPath(): Promise { + // wrapped by "" + return `"${path.join(await this.getLeetCodeRootPath(), "bin", "leetcode")}"`; + } + + public async meetRequirements(): Promise { + try { + await this.executeCommandEx("node", ["-v"]); + } 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) { + openUrl("https://nodejs.org"); + } + return false; + } + try { + // Check company plugin + await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]); + } catch (error) { + // Download company plugin and activate + await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]); + } + return true; + } + + public async deleteCache(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "cache", "-d"]); + } + + public async getUserInfo(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user"]); + } + + public async signOut(): Promise { + return await await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "user", "-L"]); + } + + public async listProblems(showLocked: boolean): Promise { + return await this.executeCommandEx( + "node", + showLocked ? [await this.getLeetCodeBinaryPath(), "list"] : [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], + ); + } + + public async showProblem(node: IProblem, language: string, outDir: string): Promise { + const fileName: string = await genFileName(node, language); + 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", + node.id, + "-cx", + "-l", + language, + ]); + await fse.writeFile(filePath, codeTemplate); + } + + return filePath; + } + + public async listSessions(): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]); + } + + public async enableSession(name: string): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-e", name]); + } + + public async createSession(name: string): Promise { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session", "-c", name]); + } + + public async submitSolution(filePath: string): Promise { + 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 this.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}"`, + ]); + } + + public async switchEndpoint(endpoint: string): Promise { + switch (endpoint) { + case Endpoint.LeetCodeCN: + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]); + case Endpoint.LeetCode: + default: + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]); + } + } + + public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }; tags: { [key: string]: string[] } }> { + // preprocess the plugin source + const companiesTagsPath: string = path.join(await leetCodeExecutor.getLeetCodeRootPath(), "lib", "plugins", "company.js"); + const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace( + "module.exports = plugin", + "module.exports = { COMPONIES, TAGS }", + ); + const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath); + return { companies: COMPONIES, tags: TAGS }; + } + + 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); + } } export const leetCodeExecutor: LeetCodeExecutor = new LeetCodeExecutor(); diff --git a/src/utils/problemUtils.ts b/src/utils/problemUtils.ts index bdc7b743..5ad17436 100644 --- a/src/utils/problemUtils.ts +++ b/src/utils/problemUtils.ts @@ -7,20 +7,20 @@ const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfig const fileNameTpl: string = leetCodeConfig.get("fileName") || ""; export function genFileExt(language: string): string { - const ext: string | undefined = langExt.get(language); - if (!ext) { - throw new Error(`The language "${language}" is not supported.`); - } - return ext; + const ext: string | undefined = langExt.get(language); + if (!ext) { + throw new Error(`The language "${language}" is not supported.`); + } + return ext; } export async function genFileName(node: IProblem, language: string): Promise { - const slug: string = kebabCase(node.name); - const ext: string = genFileExt(language); - const name: string = `${node.id}.${slug}.${ext}`; - if (!fileNameTpl) { - return name; - } else { - return `${await supplantTpl(fileNameTpl, node, language)}.${ext}` || name; - } + const slug: string = kebabCase(node.name); + const ext: string = genFileExt(language); + const name: string = `${node.id}.${slug}.${ext}`; + if (!fileNameTpl) { + return name; + } else { + return `${await supplantTpl(fileNameTpl, node, language)}.${ext}` || name; + } }