diff --git a/package.json b/package.json index 7e759e68..0ffde67d 100644 --- a/package.json +++ b/package.json @@ -367,7 +367,248 @@ "leetcode.outputFolder": { "type": "string", "scope": "application", - "description": "The relative path to save the problem files." + "description": "[Deprecated] The output folder to save the problem files." + }, + "leetcode.filePath": { + "type": "object", + "scope": "application", + "description": "The output folder and filename to save the problem files.", + "properties": { + "default": { + "type": "object", + "properties": { + "folder": { + "type": "string", + "examples": [ + "src" + ] + }, + "filename": { + "type": "string", + "examples": [ + "${camelCaseName}.${ext}", + "${PascalCaseName}.${ext}", + "${id}-${kebab-case-name}.${ext}", + "${id}_${snake_case_name}.${ext}" + ] + } + }, + "required": [ + "folder", + "filename" + ] + }, + "bash": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "c": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "cpp": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "csharp": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "golang": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "java": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "javascript": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "kotlin": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "mysql": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "php": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "python": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "python3": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "ruby": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "rust": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "scala": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "swift": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + } + }, + "additionalProperties": { + "type": "object", + "properties": { + "folder": { + "type": "string" + }, + "filename": { + "type": "string" + } + }, + "minProperties": 1 + }, + "default": { + "default": { + "folder": "", + "filename": "${id}.${kebab-case-name}.${ext}" + } + } }, "leetcode.enableStatusBar": { "type": "boolean", diff --git a/src/commands/show.ts b/src/commands/show.ts index b946c298..1906bd8e 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -1,7 +1,7 @@ // Copyright (c) jdneo. All rights reserved. // Licensed under the MIT license. -import * as fse from "fs-extra"; +import * as _ from "lodash"; import * as path from "path"; import * as unescapeJS from "unescape-js"; import * as vscode from "vscode"; @@ -11,7 +11,7 @@ import { leetCodeChannel } from "../leetCodeChannel"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IProblem, IQuickItemEx, languages, ProblemState } from "../shared"; -import { getNodeIdFromFile } from "../utils/problemUtils"; +import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils"; import { DialogOptions, DialogType, openSettingsEditor, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/uiUtils"; import { getActiveFilePath, selectWorkspaceFolder } from "../utils/workspaceUtils"; import * as wsl from "../utils/wslUtils"; @@ -137,27 +137,38 @@ async function showProblemInternal(node: IProblem): Promise { } const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - let outDir: string = await selectWorkspaceFolder(); - if (!outDir) { + const workspaceFolder: string = await selectWorkspaceFolder(); + if (!workspaceFolder) { return; } - let relativePath: string = (leetCodeConfig.get("outputFolder", "")).trim(); - if (relativePath) { - relativePath = await resolveRelativePath(relativePath, node, language); - if (!relativePath) { + const outputFolder: string = leetCodeConfig.get("outputFolder", "").trim(); + + const fileFolder: string = leetCodeConfig + .get(`filePath.${language}.folder`, leetCodeConfig.get(`filePath.default.folder`, outputFolder)) + .trim(); + const fileName: string = leetCodeConfig + .get( + `filePath.${language}.filename`, + leetCodeConfig.get(`filePath.default.filename`, genFileName(node, language)), + ) + .trim(); + + let finalPath: string = path.join(workspaceFolder, fileFolder, fileName); + + if (finalPath) { + finalPath = await resolveRelativePath(finalPath, node, language); + if (!finalPath) { leetCodeChannel.appendLine("Showing problem canceled by user."); return; } } - outDir = path.join(outDir, relativePath); - await fse.ensureDir(outDir); + finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath; - const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir, leetCodeConfig.get("showCommentDescription")); - const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath; + await leetCodeExecutor.showProblem(node, language, finalPath, leetCodeConfig.get("showCommentDescription")); await Promise.all([ - vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false, viewColumn: vscode.ViewColumn.One }), + vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }), movePreviewAsideIfNeeded(node), promptHintMessage( "hint.commentDescription", @@ -201,26 +212,49 @@ function parseProblemDecorator(state: ProblemState, locked: boolean): string { } async function resolveRelativePath(relativePath: string, node: IProblem, selectedLanguage: string): Promise { + let tag: string = ""; if (/\$\{tag\}/i.test(relativePath)) { - const tag: string | undefined = await resolveTagForProblem(node); - if (!tag) { - return ""; - } - relativePath = relativePath.replace(/\$\{tag\}/ig, tag); + tag = (await resolveTagForProblem(node)) || ""; } - relativePath = relativePath.replace(/\$\{language\}/ig, selectedLanguage); - relativePath = relativePath.replace(/\$\{difficulty\}/ig, node.difficulty.toLocaleLowerCase()); - - // Check if there is any unsupported configuration - const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/); - if (matchResult && matchResult.length >= 1) { - const errorMsg: string = `The config '${matchResult[1]}' is not supported.`; - leetCodeChannel.appendLine(errorMsg); - throw new Error(errorMsg); + let company: string = ""; + if (/\$\{company\}/i.test(relativePath)) { + company = (await resolveCompanyForProblem(node)) || ""; } - return relativePath; + return relativePath.replace(/\$\{(.*?)\}/g, (_substring: string, ...args: string[]) => { + const placeholder: string = args[0].toLowerCase().trim(); + switch (placeholder) { + case "id": + return node.id; + case "name": + return node.name; + case "camelcasename": + return _.camelCase(node.name); + case "pascalcasename": + return _.upperFirst(_.camelCase(node.name)); + case "kebabcasename": + case "kebab-case-name": + return _.kebabCase(node.name); + case "snakecasename": + case "snake_case_name": + return _.snakeCase(node.name); + case "ext": + return genFileExt(selectedLanguage); + case "language": + return selectedLanguage; + case "difficulty": + return node.difficulty.toLocaleLowerCase(); + case "tag": + return tag; + case "company": + return company; + default: + const errorMsg: string = `The config '${placeholder}' is not supported.`; + leetCodeChannel.appendLine(errorMsg); + throw new Error(errorMsg); + } + }); } async function resolveTagForProblem(problem: IProblem): Promise { @@ -236,3 +270,14 @@ async function resolveTagForProblem(problem: IProblem): Promise { + if (problem.companies.length === 1) { + return problem.companies[0]; + } + return await vscode.window.showQuickPick(problem.companies, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); +} diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 04b89013..ce4a84e8 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -8,7 +8,6 @@ import * as requireFromString from "require-from-string"; 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"; @@ -96,17 +95,14 @@ class LeetCodeExecutor implements Disposable { ); } - public async showProblem(problemNode: IProblem, language: string, outDir: string, detailed: boolean = false): Promise { - const fileName: string = genFileName(problemNode, language); - const filePath: string = path.join(outDir, fileName); + public async showProblem(problemNode: IProblem, language: string, filePath: string, detailed: boolean = false): Promise { const templateType: string = detailed ? "-cx" : "-c"; if (!await fse.pathExists(filePath)) { + await fse.createFile(filePath); const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", problemNode.id, templateType, "-l", language]); await fse.writeFile(filePath, codeTemplate); } - - return filePath; } public async showSolution(input: string, language: string): Promise { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy