Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit f23bfa2

Browse files
committed
Add soluton command and solution webview provider
1 parent 8d5d6d6 commit f23bfa2

File tree

5 files changed

+130
-24
lines changed

5 files changed

+130
-24
lines changed

package.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@
103103
"dark": "resources/dark/search.svg"
104104
}
105105
},
106+
{
107+
"command": "leetcode.showSolution",
108+
"title": "Show Top Voted Solution",
109+
"category": "LeetCode"
110+
},
106111
{
107112
"command": "leetcode.testSolution",
108113
"title": "Test in LeetCode",
@@ -164,12 +169,21 @@
164169
"command": "leetcode.showProblem",
165170
"when": "view == leetCodeExplorer && viewItem == problem",
166171
"group": "leetcode@1"
172+
},
173+
{
174+
"command": "leetcode.showSolution",
175+
"when": "view == leetCodeExplorer && viewItem == problem",
176+
"group": "leetcode@2"
167177
}
168178
],
169179
"commandPalette": [
170180
{
171181
"command": "leetcode.showProblem",
172182
"when": "never"
183+
},
184+
{
185+
"command": "leetcode.showSolution",
186+
"when": "never"
173187
}
174188
],
175189
"explorer/context": [

src/commands/show.ts

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { LeetCodeNode } from "../explorer/LeetCodeNode";
88
import { leetCodeChannel } from "../leetCodeChannel";
99
import { leetCodeExecutor } from "../leetCodeExecutor";
1010
import { leetCodeManager } from "../leetCodeManager";
11+
import { leetCodeSolutionProvider } from "../leetCodeSolutionProvider";
1112
import { IProblem, IQuickItemEx, languages, ProblemState } from "../shared";
1213
import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
1314
import { selectWorkspaceFolder } from "../utils/workspaceUtils";
@@ -39,18 +40,58 @@ export async function searchProblem(): Promise<void> {
3940
await showProblemInternal(choice.value);
4041
}
4142

42-
async function showProblemInternal(node: IProblem): Promise<void> {
43+
export async function showSolution(node?: LeetCodeNode): Promise<void> {
44+
if (!node) {
45+
return;
46+
}
47+
const language: string | undefined = await fetchProblemLanguage();
48+
if (!language) {
49+
return;
50+
}
4351
try {
44-
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
45-
let defaultLanguage: string | undefined = leetCodeConfig.get<string>("defaultLanguage");
46-
if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) {
47-
defaultLanguage = undefined;
52+
const solution: string = await leetCodeExecutor.showSolution(node, language);
53+
await leetCodeSolutionProvider.show(solution);
54+
} catch (error) {
55+
await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error);
56+
}
57+
}
58+
59+
// SUGGESTION: group config retriving into one file
60+
async function fetchProblemLanguage(): Promise<string | undefined> {
61+
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
62+
let defaultLanguage: string | undefined = leetCodeConfig.get<string>("defaultLanguage");
63+
if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) {
64+
defaultLanguage = undefined;
65+
}
66+
const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" });
67+
// fire-and-forget default language query
68+
(async (): Promise<void> => {
69+
if (!defaultLanguage && leetCodeConfig.get<boolean>("showSetDefaultLanguageHint")) {
70+
const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
71+
`Would you like to set '${language}' as your default language?`,
72+
DialogOptions.yes,
73+
DialogOptions.no,
74+
DialogOptions.never,
75+
);
76+
if (choice === DialogOptions.yes) {
77+
leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */);
78+
} else if (choice === DialogOptions.never) {
79+
leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */);
80+
}
4881
}
49-
const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use" });
82+
})();
83+
return language;
84+
}
85+
86+
async function showProblemInternal(node: IProblem): Promise<void> {
87+
try {
88+
const language: string | undefined = await fetchProblemLanguage();
5089
if (!language) {
5190
return;
5291
}
5392

93+
// SUGGESTION: group config retriving into one file
94+
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
5495
let outDir: string = await selectWorkspaceFolder();
5596
let relativePath: string = (leetCodeConfig.get<string>("outputFolder") || "").trim();
5697
const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/);
@@ -69,20 +110,6 @@ async function showProblemInternal(node: IProblem): Promise<void> {
69110
const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir);
70111
const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath;
71112
await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false });
72-
73-
if (!defaultLanguage && leetCodeConfig.get<boolean>("showSetDefaultLanguageHint")) {
74-
const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
75-
`Would you like to set '${language}' as your default language?`,
76-
DialogOptions.yes,
77-
DialogOptions.no,
78-
DialogOptions.never,
79-
);
80-
if (choice === DialogOptions.yes) {
81-
leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */);
82-
} else if (choice === DialogOptions.never) {
83-
leetCodeConfig.update("showSetDefaultLanguageHint", false, true /* UserSetting */);
84-
}
85-
}
86113
} catch (error) {
87114
await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error);
88115
}

src/extension.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { leetCodeChannel } from "./leetCodeChannel";
1616
import { leetCodeExecutor } from "./leetCodeExecutor";
1717
import { leetCodeManager } from "./leetCodeManager";
1818
import { leetCodeResultProvider } from "./leetCodeResultProvider";
19+
import { leetCodeSolutionProvider } from "./leetCodeSolutionProvider";
1920
import { leetCodeStatusBarItem } from "./leetCodeStatusBarItem";
2021

2122
export async function activate(context: vscode.ExtensionContext): Promise<void> {
@@ -30,11 +31,13 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
3031

3132
const leetCodeTreeDataProvider: LeetCodeTreeDataProvider = new LeetCodeTreeDataProvider(context);
3233
leetCodeResultProvider.initialize(context);
34+
leetCodeSolutionProvider.initialize(context);
3335

3436
context.subscriptions.push(
3537
leetCodeStatusBarItem,
3638
leetCodeChannel,
3739
leetCodeResultProvider,
40+
leetCodeSolutionProvider,
3841
vscode.window.registerTreeDataProvider("leetCodeExplorer", leetCodeTreeDataProvider),
3942
vscode.languages.registerCodeLensProvider({ scheme: "file" }, codeLensProvider),
4043
vscode.commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()),
@@ -45,6 +48,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
4548
vscode.commands.registerCommand("leetcode.createSession", () => session.createSession()),
4649
vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(node)),
4750
vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()),
51+
vscode.commands.registerCommand("leetcode.showSolution", (node: LeetCodeNode) => show.showSolution(node)),
4852
vscode.commands.registerCommand("leetcode.refreshExplorer", () => leetCodeTreeDataProvider.refresh()),
4953
vscode.commands.registerCommand("leetcode.testSolution", (uri?: vscode.Uri) => test.testSolution(uri)),
5054
vscode.commands.registerCommand("leetcode.submitSolution", (uri?: vscode.Uri) => submit.submitSolution(uri)),

src/leetCodeExecutor.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,12 @@ class LeetCodeExecutor {
4848
}
4949
return false;
5050
}
51-
try { // Check company plugin
52-
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "company"]);
53-
} catch (error) { // Download company plugin and activate
54-
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", "company"]);
51+
for (const plugin of ["company", "solution.discuss"]) {
52+
try { // Check plugin
53+
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", plugin]);
54+
} catch (error) { // Download plugin and activate
55+
await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-i", plugin]);
56+
}
5557
}
5658
return true;
5759
}
@@ -87,6 +89,11 @@ class LeetCodeExecutor {
8789
return filePath;
8890
}
8991

92+
public async showSolution(node: IProblem, language: string): Promise<string> {
93+
const solution: string = await this.executeCommandWithProgressEx("Fetching top voted solution from discussions...", "node", [await this.getLeetCodeBinaryPath(), "show", node.id, "--solution", "-l", language]);
94+
return solution;
95+
}
96+
9097
public async listSessions(): Promise<string> {
9198
return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "session"]);
9299
}

src/leetCodeSolutionProvider.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) jdneo. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
import { Disposable, ExtensionContext, ViewColumn, WebviewPanel, window } from "vscode";
5+
6+
class LeetCodeSolutionProvider implements Disposable {
7+
8+
private context: ExtensionContext;
9+
private panel: WebviewPanel | undefined;
10+
11+
public initialize(context: ExtensionContext): void {
12+
this.context = context;
13+
}
14+
15+
public async show(result: string): Promise<void> {
16+
if (!this.panel) {
17+
this.panel = window.createWebviewPanel("leetCode", "LeetCode Top Voted Solution", ViewColumn.Active, {
18+
retainContextWhenHidden: true,
19+
enableFindWidget: true,
20+
});
21+
22+
this.panel.onDidDispose(() => {
23+
this.panel = undefined;
24+
}, null, this.context.subscriptions);
25+
}
26+
27+
this.panel.webview.html = this.getWebViewContent(result);
28+
this.panel.reveal(ViewColumn.Active);
29+
}
30+
31+
public dispose(): void {
32+
if (this.panel) {
33+
this.panel.dispose();
34+
}
35+
}
36+
37+
private getWebViewContent(result: string): string {
38+
return `
39+
<!DOCTYPE html>
40+
<html lang="en">
41+
<head>
42+
<meta charset="UTF-8">
43+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
44+
<title>LeetCode Top Voted Solution</title>
45+
</head>
46+
<body>
47+
<pre>${result.trim()}</pre>
48+
</body>
49+
</html>
50+
`;
51+
}
52+
}
53+
54+
export const leetCodeSolutionProvider: LeetCodeSolutionProvider = new LeetCodeSolutionProvider();

0 commit comments

Comments
 (0)