diff --git a/src/commands/show.ts b/src/commands/show.ts index d1ce1cf4..e3c3cf62 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -26,13 +26,10 @@ export async function searchProblem(): Promise { promptForSignIn(); return; } - const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick( - parseProblemsToPicks(list.listProblems()), - { - matchOnDetail: true, - placeHolder: "Select one problem", - }, - ); + const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseProblemsToPicks(list.listProblems()), { + matchOnDetail: true, + placeHolder: "Select one problem", + }); if (!choice) { return; } @@ -46,7 +43,8 @@ async function showProblemInternal(node: IProblem): Promise { 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" }); + const language: string | undefined = + defaultLanguage || (await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" })); if (!language) { return; } @@ -89,15 +87,22 @@ async function showProblemInternal(node: IProblem): Promise { } 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 { @@ -117,14 +122,11 @@ async function resolveRelativePath(value: string, node: IProblem, selectedLangua 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, - }, - ); + return await vscode.window.showQuickPick(node.tags, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); case "language": return selectedLanguage; case "difficulty": diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 373bda11..77898443 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -21,7 +21,8 @@ class LeetCodeExecutor { this.leetCodeRootPathInWsl = ""; } - public async getLeetCodeRootPath(): Promise { // not wrapped by "" + public async getLeetCodeRootPath(): Promise { + // not wrapped by "" if (wsl.useWsl()) { if (!this.leetCodeRootPathInWsl) { this.leetCodeRootPathInWsl = `${await wsl.toWslPath(this.leetCodeRootPath)}`; @@ -31,7 +32,8 @@ class LeetCodeExecutor { return `${this.leetCodeRootPath}`; } - public async getLeetCodeBinaryPath(): Promise { // wrapped by "" + public async getLeetCodeBinaryPath(): Promise { + // wrapped by "" return `"${path.join(await this.getLeetCodeRootPath(), "bin", "leetcode")}"`; } @@ -48,9 +50,11 @@ class LeetCodeExecutor { } return false; } - try { // Check company plugin + try { + // Check company plugin await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]); - } catch (error) { // Download company plugin and activate + } catch (error) { + // Download company plugin and activate await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]); } return true; @@ -69,18 +73,25 @@ class LeetCodeExecutor { } public async listProblems(showLocked: boolean): Promise { - return await this.executeCommandEx("node", showLocked ? - [await this.getLeetCodeBinaryPath(), "list"] : - [await this.getLeetCodeBinaryPath(), "list", "-q", "L"], + 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 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]); + 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); } @@ -100,14 +111,28 @@ class LeetCodeExecutor { } public async submitSolution(filePath: string): Promise { - return await this.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 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}"`, + "-t", + `${testString}`, + ]); } - return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]); + return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [ + await this.getLeetCodeBinaryPath(), + "test", + `"${filePath}"`, + ]); } public async switchEndpoint(endpoint: string): Promise { @@ -120,7 +145,7 @@ class LeetCodeExecutor { } } - public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }, tags: { [key: string]: string[] } }> { + 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( @@ -138,7 +163,12 @@ class LeetCodeExecutor { return await executeCommand(command, args, options); } - private async executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { + 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); } diff --git a/src/utils/problemUtils.ts b/src/utils/problemUtils.ts index c7946bbc..5ad17436 100644 --- a/src/utils/problemUtils.ts +++ b/src/utils/problemUtils.ts @@ -1,5 +1,10 @@ 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); @@ -9,8 +14,13 @@ export function genFileExt(language: string): string { return ext; } -export function genFileName(node: IProblem, language: string): string { +export async function genFileName(node: IProblem, language: string): Promise { const slug: string = kebabCase(node.name); const ext: string = genFileExt(language); - return `${node.id}.${slug}.${ext}`; + 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": [] }