diff --git a/package.json b/package.json index 63f95049..753f79a1 100644 --- a/package.json +++ b/package.json @@ -221,6 +221,10 @@ { "command": "leetcode.submitSolution", "group": "leetcode@2" + }, + { + "command": "leetcode.showSolution", + "group": "leetcode@3" } ] }, diff --git a/src/codelens/CustomCodeLensProvider.ts b/src/codelens/CustomCodeLensProvider.ts index 001ccc0b..3ee7270d 100644 --- a/src/codelens/CustomCodeLensProvider.ts +++ b/src/codelens/CustomCodeLensProvider.ts @@ -20,10 +20,17 @@ export class CustomCodeLensProvider implements vscode.CodeLensProvider { new vscode.CodeLens(range, { title: "Submit", command: "leetcode.submitSolution", + arguments: [document.uri], }), new vscode.CodeLens(range, { title: "Test", command: "leetcode.testSolution", + arguments: [document.uri], + }), + new vscode.CodeLens(range, { + title: "Solution", + command: "leetcode.showSolution", + arguments: [document.uri], }), ]; } diff --git a/src/commands/show.ts b/src/commands/show.ts index 24d3b50f..77256dbf 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -47,17 +47,24 @@ export async function searchProblem(): Promise { await showProblemInternal(choice.value); } -export async function showSolution(node?: LeetCodeNode): Promise { - if (!node) { +export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { + let problemInput: string | undefined; + if (input instanceof LeetCodeNode) { + problemInput = input.id; + } else if (input instanceof vscode.Uri) { + problemInput = `"${input.fsPath}"`; + } else { + vscode.window.showErrorMessage("Invalid input to fetch the solution data"); return; } + const language: string | undefined = await fetchProblemLanguage(); if (!language) { return; } try { - const solution: string = await leetCodeExecutor.showSolution(node, language); - leetCodeSolutionProvider.show(unescapeJS(solution), node); + const solution: string = await leetCodeExecutor.showSolution(problemInput, language); + 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); @@ -133,8 +140,6 @@ async function showProblemInternal(node: IProblem): Promise { async function movePreviewAsideIfNeeded(node: IProblem): Promise { if (vscode.workspace.getConfiguration("leetcode").get("enableSideMode", true)) { return previewProblem(node, true); - } else { - return Promise.resolve(); } } diff --git a/src/extension.ts b/src/extension.ts index 2ebefd9b..978d90ae 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -56,7 +56,7 @@ export async function activate(context: vscode.ExtensionContext): Promise vscode.commands.registerCommand("leetcode.previewProblem", (node: LeetCodeNode) => show.previewProblem(node)), vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(node)), vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()), - vscode.commands.registerCommand("leetcode.showSolution", (node: LeetCodeNode) => show.showSolution(node)), + vscode.commands.registerCommand("leetcode.showSolution", (input: LeetCodeNode | vscode.Uri) => show.showSolution(input)), vscode.commands.registerCommand("leetcode.refreshExplorer", () => leetCodeTreeDataProvider.refresh()), vscode.commands.registerCommand("leetcode.testSolution", (uri?: vscode.Uri) => test.testSolution(uri)), vscode.commands.registerCommand("leetcode.submitSolution", (uri?: vscode.Uri) => submit.submitSolution(uri)), diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 27b896c1..ac110190 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -107,8 +107,8 @@ class LeetCodeExecutor implements Disposable { return filePath; } - public async showSolution(problemNode: IProblem, language: string): Promise { - const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", problemNode.id, "--solution", "-l", language]); + public async showSolution(input: string, language: string): Promise { + const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "show", input, "--solution", "-l", language]); return solution; } diff --git a/src/webview/leetCodeSolutionProvider.ts b/src/webview/leetCodeSolutionProvider.ts index 952af2cd..59c548d6 100644 --- a/src/webview/leetCodeSolutionProvider.ts +++ b/src/webview/leetCodeSolutionProvider.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import { ViewColumn } from "vscode"; -import { IProblem } from "../shared"; import { leetCodePreviewProvider } from "./leetCodePreviewProvider"; import { ILeetCodeWebviewOption, LeetCodeWebview } from "./LeetCodeWebview"; import { markdownEngine } from "./markdownEngine"; @@ -10,25 +9,26 @@ import { markdownEngine } from "./markdownEngine"; class LeetCodeSolutionProvider extends LeetCodeWebview { protected readonly viewType: string = "leetcode.solution"; + private problemName: string; private solution: Solution; - public show(solutionString: string, problem: IProblem): void { - this.solution = this.parseSolution(solutionString, problem); + public show(solutionString: string): void { + this.solution = this.parseSolution(solutionString); this.showWebviewInternal(); } protected getWebviewOption(): ILeetCodeWebviewOption { - if (!leetCodePreviewProvider.isSideMode()) { - return { - title: `${this.solution.problem}: Solution`, - viewColumn: ViewColumn.One, - }; - } else { + if (leetCodePreviewProvider.isSideMode()) { return { title: "Solution", viewColumn: ViewColumn.Two, preserveFocus: true, }; + } else { + return { + title: `Solution: ${this.problemName}`, + viewColumn: ViewColumn.One, + }; } } @@ -66,17 +66,17 @@ class LeetCodeSolutionProvider extends LeetCodeWebview { delete this.solution; } - private parseSolution(raw: string, problem: IProblem): Solution { + private parseSolution(raw: string): Solution { + raw = raw.slice(1); // skip first empty line + [this.problemName, raw] = raw.split(/\n\n([^]+)/); // parse problem name and skip one line const solution: Solution = new Solution(); // [^] matches everything including \n, yet can be replaced by . in ES2018's `m` flag - raw = raw.slice(1); // skip first empty line - [solution.title, raw] = raw.split(/\n\n([^]+)/); // parse title and skip one line - [solution.url, raw] = raw.split(/\n\n([^]+)/); // parse url and skip one line + [solution.title, raw] = raw.split(/\n\n([^]+)/); + [solution.url, raw] = raw.split(/\n\n([^]+)/); [solution.lang, raw] = raw.match(/\* Lang:\s+(.+)\n([^]+)/)!.slice(1); [solution.author, raw] = raw.match(/\* Author:\s+(.+)\n([^]+)/)!.slice(1); [solution.votes, raw] = raw.match(/\* Votes:\s+(\d+)\n\n([^]+)/)!.slice(1); solution.body = raw; - solution.problem = problem.name; return solution; } } @@ -89,7 +89,6 @@ class Solution { public author: string = ""; public votes: string = ""; public body: string = ""; // Markdown supported - public problem: string = ""; } export const leetCodeSolutionProvider: LeetCodeSolutionProvider = new LeetCodeSolutionProvider();