diff --git a/.vscode/launch.json b/.vscode/launch.json index 6f7862ec..f34081df 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,28 +1,28 @@ // A launch configuration that compiles the extension and then opens it inside a new window { - "version": "0.1.0", - "configurations": [ - { - "name": "Launch Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], - "stopOnEntry": false, - "sourceMaps": true, - "outFiles": [ "${workspaceRoot}/out/src/**/*.js" ], - "preLaunchTask": "npm" - }, - { - "name": "Launch Tests", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test" ], - "stopOnEntry": false, - "sourceMaps": true, - "outFiles": [ "${workspaceRoot}/out/test/**/*.js" ], - "preLaunchTask": "npm" - } - ] -} \ No newline at end of file + "version": "0.1.0", + "configurations": [ + { + "name": "Launch Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--disable-extensions"], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": ["${workspaceRoot}/out/src/**/*.js"], + "preLaunchTask": "npm" + }, + { + "name": "Launch Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}", "--extensionTestsPath=${workspaceRoot}/out/test"], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": ["${workspaceRoot}/out/test/**/*.js"], + "preLaunchTask": "npm" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1ca8c371..ab446104 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,33 +1,28 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "npm", - "type": "shell", - "command": "npm", - "group": { - "kind": "build", - "isDefault": true - }, - "args": [ - "run", - "compile", - "--loglevel", - "silent" - ], - "isBackground": true, - "presentation": { - "reveal": "silent" - }, - "problemMatcher": "$tsc-watch" - }, - { - "type": "npm", - "script": "lint", - "problemMatcher": { - "base": "$tslint5", - "fileLocation": "absolute" - } - } - ] -} \ No newline at end of file + "version": "2.0.0", + "tasks": [ + { + "label": "npm", + "type": "shell", + "command": "npm", + "group": { + "kind": "build", + "isDefault": true + }, + "args": ["run", "compile", "--loglevel", "silent"], + "isBackground": true, + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$tsc-watch" + }, + { + "type": "npm", + "script": "lint", + "problemMatcher": { + "base": "$tslint5", + "fileLocation": "absolute" + } + } + ] +} diff --git a/package-lock.json b/package-lock.json index 76397db2..f51c00b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "fs-extra": "^10.0.0", "highlight.js": "^10.7.2", + "html-to-md": "^0.6.0", "lodash": "^4.17.21", "markdown-it": "^8.4.2", "require-from-string": "^2.0.2", @@ -784,6 +785,11 @@ "node": "*" } }, + "node_modules/html-to-md": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/html-to-md/-/html-to-md-0.6.0.tgz", + "integrity": "sha512-wcTvKm/hOcNUPqrlwIdjFLk16pRKZ27r+lTSw2NpZxcwQj9tDrcGJtJPerTQIUhICfhdpWtK48dqP9+dY/b4mA==" + }, "node_modules/htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", @@ -2740,6 +2746,11 @@ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.2.tgz", "integrity": "sha512-oFLl873u4usRM9K63j4ME9u3etNF0PLiJhSQ8rdfuL51Wn3zkD6drf9ZW0dOzjnZI22YYG24z30JcmfCZjMgYg==" }, + "html-to-md": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/html-to-md/-/html-to-md-0.6.0.tgz", + "integrity": "sha512-wcTvKm/hOcNUPqrlwIdjFLk16pRKZ27r+lTSw2NpZxcwQj9tDrcGJtJPerTQIUhICfhdpWtK48dqP9+dY/b4mA==" + }, "htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", diff --git a/package.json b/package.json index db0d475a..384421ec 100644 --- a/package.json +++ b/package.json @@ -300,6 +300,16 @@ "scope": "application", "description": "Show locked problems." }, + "leetcode.languageList": { + "type": "array", + "default": [], + "description": "同时生成多语言版本代码" + }, + "leetcode.showMD": { + "type": "boolean", + "default": true, + "description": "同时生成markdown介绍" + }, "leetcode.defaultLanguage": { "type": "string", "enum": [ @@ -725,6 +735,7 @@ "dependencies": { "fs-extra": "^10.0.0", "highlight.js": "^10.7.2", + "html-to-md": "^0.6.0", "lodash": "^4.17.21", "markdown-it": "^8.4.2", "require-from-string": "^2.0.2", diff --git a/src/commands/show.ts b/src/commands/show.ts index 3aebce8f..ea9b2076 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -11,7 +11,7 @@ import { leetCodeChannel } from "../leetCodeChannel"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IProblem, IQuickItemEx, languages, ProblemState } from "../shared"; -import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils"; +import { genFileExt, genFileName } from "../utils/problemUtils"; import * as settingUtils from "../utils/settingUtils"; import { IDescriptionConfiguration } from "../utils/settingUtils"; import { DialogOptions, DialogType, openSettingsEditor, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/uiUtils"; @@ -20,269 +20,337 @@ import * as wsl from "../utils/wslUtils"; import { leetCodePreviewProvider } from "../webview/leetCodePreviewProvider"; import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider"; import * as list from "./list"; +import * as fs from "fs"; +const html2md = require("html-to-md"); -export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise { - let node: IProblem; - if (input instanceof vscode.Uri) { - const activeFilePath: string = input.fsPath; - const id: string = await getNodeIdFromFile(activeFilePath); - if (!id) { - vscode.window.showErrorMessage(`Failed to resolve the problem id from file: ${activeFilePath}.`); - return; - } - const cachedNode: IProblem | undefined = explorerNodeManager.getNodeById(id); - if (!cachedNode) { - vscode.window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`); - return; - } - node = cachedNode; - // Move the preview page aside if it's triggered from Code Lens - isSideMode = true; - } else { - node = input; +function getId() { + let id = ""; + const editor = vscode.window.activeTextEditor; + + if (editor) { + const fsPath = editor.document.fileName; + let fileContent = editor.document.getText(); + + const matchResults = fileContent.match(/@lc.+id=(.+?) /); + if (matchResults && matchResults.length === 2) { + id = matchResults[1]; } - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); - const descString: string = await leetCodeExecutor.getDescription(node.id, needTranslation); - leetCodePreviewProvider.show(descString, node, isSideMode); + + if (!id) { + id = path.basename(fsPath).split(".")[0]; + } + + if (!id) { + vscode.window.showErrorMessage(`Failed to resolve the problem id from file: ${fsPath}.`); + return ""; + } + } + return id; +} + +export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise { + let node: IProblem; + console.log(input); + const id: string = await getId(); + + const cachedNode: IProblem | undefined = explorerNodeManager.getNodeById(id); + if (!cachedNode) { + vscode.window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`); + return; + } + node = cachedNode; + // Move the preview page aside if it's triggered from Code Lens + isSideMode = true; + + const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const descString: string = await leetCodeExecutor.getDescription(node.id, needTranslation); + leetCodePreviewProvider.show(descString, node, isSideMode); } export async function pickOne(): Promise { - const problems: IProblem[] = await list.listProblems(); - const randomProblem: IProblem = problems[Math.floor(Math.random() * problems.length)]; - await showProblemInternal(randomProblem); + const problems: IProblem[] = await list.listProblems(); + const randomProblem: IProblem = problems[Math.floor(Math.random() * problems.length)]; + await showProblemInternal(randomProblem); } 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); } export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { - let problemInput: string | undefined; - if (input instanceof LeetCodeNode) { // Triggerred from explorer - problemInput = input.id; - } else if (input instanceof vscode.Uri) { // Triggerred from Code Lens/context menu - problemInput = `"${input.fsPath}"`; - } else if (!input) { // Triggerred from command - problemInput = await getActiveFilePath(); - } + let problemInput: string | undefined; + if (input instanceof LeetCodeNode) { + // Triggerred from explorer + problemInput = input.id; + } else if (input instanceof vscode.Uri) { + // Triggerred from Code Lens/context menu + problemInput = `"${input.fsPath}"`; + } else if (!input) { + // Triggerred from command + problemInput = await getActiveFilePath(); + } - if (!problemInput) { - vscode.window.showErrorMessage("Invalid input to fetch the solution data."); - return; - } + if (!problemInput) { + vscode.window.showErrorMessage("Invalid input to fetch the solution data."); + return; + } - const language: string | undefined = await fetchProblemLanguage(); - if (!language) { - return; - } - try { - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); - const solution: string = await leetCodeExecutor.showSolution(problemInput, language, needTranslation); - leetCodeSolutionProvider.show(unescapeJS(solution)); - } catch (error) { - leetCodeChannel.appendLine(error.toString()); - await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error); - } + const language: string | undefined = await fetchProblemLanguage(); + if (!language) { + return; + } + try { + const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const solution: string = await leetCodeExecutor.showSolution(problemInput, language, needTranslation); + leetCodeSolutionProvider.show(unescapeJS(solution)); + } catch (error) { + leetCodeChannel.appendLine(error.toString()); + await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error); + } } async function fetchProblemLanguage(): Promise { - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage"); - if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) { - defaultLanguage = undefined; + 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", ignoreFocusOut: true })); + // fire-and-forget default language query + (async (): Promise => { + if (language && !defaultLanguage && leetCodeConfig.get("hint.setDefaultLanguage")) { + 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("hint.setDefaultLanguage", false, true /* UserSetting */); + } } - const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use", ignoreFocusOut: true }); - // fire-and-forget default language query - (async (): Promise => { - if (language && !defaultLanguage && leetCodeConfig.get("hint.setDefaultLanguage")) { - 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("hint.setDefaultLanguage", false, true /* UserSetting */); - } - } - })(); - return language; + })(); + return language; } -async function showProblemInternal(node: IProblem): Promise { - try { - const language: string | undefined = await fetchProblemLanguage(); - if (!language) { - return; - } +async function getFinalPath(node: IProblem, leetCodeConfig: vscode.WorkspaceConfiguration, language: string) { + const workspaceFolder: string = await selectWorkspaceFolder(); + if (!workspaceFolder) { + return ""; + } + const fileFolder: string = leetCodeConfig + .get(`filePath.${language}.folder`, leetCodeConfig.get(`filePath.default.folder`, "")) + .trim(); - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - const workspaceFolder: string = await selectWorkspaceFolder(); - if (!workspaceFolder) { - return; - } + const fileName: string = leetCodeConfig + .get(`filePath.${language}.filename`, leetCodeConfig.get(`filePath.default.filename`) || genFileName(node, language)) + .trim(); - const fileFolder: string = leetCodeConfig - .get(`filePath.${language}.folder`, leetCodeConfig.get(`filePath.default.folder`, "")) - .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; - } - } + let finalPath: string = path.join(workspaceFolder, fileFolder, fileName); - finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath; - - const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration(); - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); - - await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); - const promises: any[] = [ - vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }), - promptHintMessage( - "hint.commentDescription", - 'You can config how to show the problem description through "leetcode.showDescription".', - "Open settings", - (): Promise => openSettingsEditor("leetcode.showDescription"), - ), - ]; - if (descriptionConfig.showInWebview) { - promises.push(showDescriptionView(node)); - } + if (finalPath) { + finalPath = await resolveRelativePath(finalPath, node, language); + if (!finalPath) { + leetCodeChannel.appendLine("Showing problem canceled by user."); + return ""; + } + } + + finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath; + return finalPath; +} - await Promise.all(promises); - } catch (error) { - await promptForOpenOutputChannel(`${error} Please open the output channel for details.`, DialogType.error); +async function showProblemWithOneLanguage(node: IProblem, leetCodeConfig: vscode.WorkspaceConfiguration, language: string) { + let finalPath = await getFinalPath(node, leetCodeConfig, language); + + if (!fs.existsSync(finalPath)) { + const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration(); + const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + + await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); + const promises: any[] = [ + vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }), + promptHintMessage( + "hint.commentDescription", + 'You can config how to show the problem description through "leetcode.showDescription".', + "Open settings", + (): Promise => openSettingsEditor("leetcode.showDescription") + ), + ]; + if (descriptionConfig.showInWebview) { + promises.push(showDescriptionView(node)); } + + await Promise.all(promises); + const descString = await leetCodeExecutor.getDescription(node.id, needTranslation); + + return [finalPath, descString]; + } else { + return ["", ""]; + } +} +function showMarkdownDescription(finalPath, descString) { + finalPath = path.join(path.dirname(finalPath), path.parse(finalPath).name + ".md"); + if (!fs.existsSync(finalPath)) { + fs.open(finalPath, "w+", function () { + fs.writeFile(finalPath, html2md(descString), err => { + if (err) { + console.error(err); + } + console.log("Data written"); + }); + }); + } + vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }); +} +async function showProblemInternal(node: IProblem): Promise { + try { + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + const languageList: string[] | undefined = await leetCodeConfig.get("languageList"); + const showMD: boolean | undefined = await leetCodeConfig.get("showMD"); + let isShowMD = false; + if (languageList && languageList.length > 0) { + languageList.forEach(language => { + showProblemWithOneLanguage(node, leetCodeConfig, language).then(res => { + let [finalPath, descString] = res; + if (showMD && !isShowMD) { + isShowMD = true; + showMarkdownDescription(finalPath, descString); + } + }); + }); + } else { + const language: string | undefined = await fetchProblemLanguage(); + if (!language) { + return; + } + showProblemWithOneLanguage(node, leetCodeConfig, language).then(res => { + if (showMD) { + showMarkdownDescription(res[0], res[1]); + } + }); + } + } catch (error) { + await promptForOpenOutputChannel(`${error} Please open the output channel for details.`, DialogType.error); + } } async function showDescriptionView(node: IProblem): Promise { - return previewProblem(node, vscode.workspace.getConfiguration("leetcode").get("enableSideMode", true)); + return previewProblem(node, vscode.workspace.getConfiguration("leetcode").get("enableSideMode", true)); } 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(relativePath: string, node: IProblem, selectedLanguage: string): Promise { - let tag: string = ""; - if (/\$\{tag\}/i.test(relativePath)) { - tag = (await resolveTagForProblem(node)) || ""; - } + let tag: string = ""; + if (/\$\{tag\}/i.test(relativePath)) { + tag = (await resolveTagForProblem(node)) || ""; + } - let company: string = ""; - if (/\$\{company\}/i.test(relativePath)) { - company = (await resolveCompanyForProblem(node)) || ""; - } + let company: string = ""; + if (/\$\{company\}/i.test(relativePath)) { + company = (await resolveCompanyForProblem(node)) || ""; + } - 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); - } - }); + 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 { - if (problem.tags.length === 1) { - return problem.tags[0]; - } - return await vscode.window.showQuickPick( - problem.tags, - { - matchOnDetail: true, - placeHolder: "Multiple tags available, please select one", - ignoreFocusOut: true, - }, - ); + if (problem.tags.length === 1) { + return problem.tags[0]; + } + return await vscode.window.showQuickPick(problem.tags, { + matchOnDetail: true, + placeHolder: "Multiple tags available, please select one", + ignoreFocusOut: true, + }); } async function resolveCompanyForProblem(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, - }); + 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, + }); }