Skip to content

Commit 52a84d3

Browse files
Vigilansjdneo
authored andcommitted
Add side mode to webview (#271)
1 parent 8d3e09f commit 52a84d3

12 files changed

+97
-34
lines changed

Diff for: README.md

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
| `leetcode.outputFolder`| Specify the relative path to save the problem files. Besides using customized path, there are also several reserved words which can be used here: <ul><li>`${tag}`: Categorize the problem according to their tags.<li>`${language}`: Categorize the problem according to their language.</li><li>`${difficulty}`: Categorize the problem according to their difficulty.</li></ul> | N/A |
142142
| `leetcode.enableStatusBar` | Specify whether the LeetCode status bar will be shown or not. | `true` |
143143
| `leetcode.enableShortcuts` | Specify whether the submit and test shortcuts in editor or not. | `true` |
144+
| `leetcode.enableSideMode` | Specify whether `preview`, `solution` and `submission` tab should be grouped into the second editor column when solving a problem. | `true` |
144145
| `leetcode.nodePath` | Specify the `Node.js` executable path. | `node` |
145146

146147
## Want Help?

Diff for: docs/README_zh-CN.md

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
| `leetcode.outputFolder` | 指定保存文件时所用的相对文件夹路径。除了用户自定义路径外,也可以使用保留项,包括:<ul><li>`${tag}`: 根据题目的类别进行分类。<li>`${language}`: 根据题目的语言进行分类。</li><li>`${difficulty}`: 根据题目的难度进行分类。</li></ul> | N/A |
142142
| `leetcode.enableStatusBar` | 指定是否在 VS Code 下方显示插件状态栏。 | `true` |
143143
| `leetcode.enableShortcuts` | 指定是否在 VS Code 编辑文件下方显示提交和测试的快捷按钮。 | `true` |
144+
| `leetcode.enableSideMode` | 指定在解决一道题时,是否将`问题预览``高票答案``提交结果`窗口集中在编辑器的第二栏。 | `true` |
144145
| `leetcode.nodePath` | 指定 `Node.js` 可执行文件的路径。 | `node` |
145146

146147
## 需要帮助?

Diff for: package-lock.json

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+7-1
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,12 @@
301301
"scope": "application",
302302
"description": "Show the submit and test shortcuts in editor or not."
303303
},
304+
"leetcode.enableSideMode": {
305+
"type": "boolean",
306+
"default": true,
307+
"scope": "application",
308+
"description": "Determine whether to group all webview pages into the second editor column when solving problems."
309+
},
304310
"leetcode.nodePath": {
305311
"type": "string",
306312
"default": "node",
@@ -338,6 +344,6 @@
338344
"markdown-it": "^8.4.2",
339345
"require-from-string": "^2.0.2",
340346
"unescape-js": "^1.1.1",
341-
"vsc-leetcode-cli": "2.6.3"
347+
"vsc-leetcode-cli": "2.6.4"
342348
}
343349
}

Diff for: src/commands/show.ts

+20-3
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,15 @@ import { IProblem, IQuickItemEx, languages, ProblemState } from "../shared";
1313
import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
1414
import { selectWorkspaceFolder } from "../utils/workspaceUtils";
1515
import * as wsl from "../utils/wslUtils";
16+
import { leetCodePreviewProvider } from "../webview/leetCodePreviewProvider";
1617
import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider";
1718
import * as list from "./list";
1819

20+
export async function previewProblem(node: IProblem, isSideMode: boolean = false): Promise<void> {
21+
const descString: string = await leetCodeExecutor.getDescription(node);
22+
leetCodePreviewProvider.show(descString, node, isSideMode);
23+
}
24+
1925
export async function showProblem(node?: LeetCodeNode): Promise<void> {
2026
if (!node) {
2127
return;
@@ -51,7 +57,7 @@ export async function showSolution(node?: LeetCodeNode): Promise<void> {
5157
}
5258
try {
5359
const solution: string = await leetCodeExecutor.showSolution(node, language);
54-
await leetCodeSolutionProvider.show(unescapeJS(solution), node);
60+
leetCodeSolutionProvider.show(unescapeJS(solution), node);
5561
} catch (error) {
5662
leetCodeChannel.appendLine(error.toString());
5763
await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error);
@@ -95,7 +101,7 @@ async function showProblemInternal(node: IProblem): Promise<void> {
95101
// SUGGESTION: group config retriving into one file
96102
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
97103
let outDir: string = await selectWorkspaceFolder();
98-
let relativePath: string = (leetCodeConfig.get<string>("outputFolder") || "").trim();
104+
let relativePath: string = (leetCodeConfig.get<string>("outputFolder", "")).trim();
99105
const matchResult: RegExpMatchArray | null = relativePath.match(/\$\{(.*?)\}/);
100106
if (matchResult) {
101107
const resolvedPath: string | undefined = await resolveRelativePath(matchResult[1].toLocaleLowerCase(), node, language);
@@ -111,12 +117,23 @@ async function showProblemInternal(node: IProblem): Promise<void> {
111117

112118
const originFilePath: string = await leetCodeExecutor.showProblem(node, language, outDir);
113119
const filePath: string = wsl.useWsl() ? await wsl.toWinPath(originFilePath) : originFilePath;
114-
await vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false, viewColumn: vscode.ViewColumn.One });
120+
await Promise.all([
121+
vscode.window.showTextDocument(vscode.Uri.file(filePath), { preview: false, viewColumn: vscode.ViewColumn.One }),
122+
movePreviewAsideIfNeeded(node),
123+
]);
115124
} catch (error) {
116125
await promptForOpenOutputChannel("Failed to show the problem. Please open the output channel for details.", DialogType.error);
117126
}
118127
}
119128

129+
async function movePreviewAsideIfNeeded(node: IProblem): Promise<void> {
130+
if (vscode.workspace.getConfiguration("leetcode").get<boolean>("enableSideMode", true)) {
131+
return previewProblem(node, true);
132+
} else {
133+
return Promise.resolve();
134+
}
135+
}
136+
120137
async function parseProblemsToPicks(p: Promise<IProblem[]>): Promise<Array<IQuickItemEx<IProblem>>> {
121138
return new Promise(async (resolve: (res: Array<IQuickItemEx<IProblem>>) => void): Promise<void> => {
122139
const picks: Array<IQuickItemEx<IProblem>> = (await p).map((problem: IProblem) => Object.assign({}, {

Diff for: src/commands/submit.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export async function submitSolution(uri?: vscode.Uri): Promise<void> {
2121

2222
try {
2323
const result: string = await leetCodeExecutor.submitSolution(filePath);
24-
await leetCodeSubmissionProvider.show(result);
24+
leetCodeSubmissionProvider.show(result);
2525
} catch (error) {
2626
await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error);
2727
}

Diff for: src/commands/test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export async function testSolution(uri?: vscode.Uri): Promise<void> {
8181
if (!result) {
8282
return;
8383
}
84-
await leetCodeSubmissionProvider.show(result);
84+
leetCodeSubmissionProvider.show(result);
8585
} catch (error) {
8686
await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error);
8787
}

Diff for: src/extension.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
5151
vscode.commands.registerCommand("leetcode.signout", () => leetCodeManager.signOut()),
5252
vscode.commands.registerCommand("leetcode.selectSessions", () => session.selectSession()),
5353
vscode.commands.registerCommand("leetcode.createSession", () => session.createSession()),
54-
vscode.commands.registerCommand("leetcode.previewProblem", (node: LeetCodeNode) => leetCodePreviewProvider.show(node)),
54+
vscode.commands.registerCommand("leetcode.previewProblem", (node: LeetCodeNode) => show.previewProblem(node)),
5555
vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(node)),
5656
vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()),
5757
vscode.commands.registerCommand("leetcode.showSolution", (node: LeetCodeNode) => show.showSolution(node)),

Diff for: src/webview/LeetCodeWebview.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Copyright (c) jdneo. All rights reserved.
22
// Licensed under the MIT license.
33

4-
import { ConfigurationChangeEvent, Disposable, ViewColumn, WebviewPanel, window, workspace } from "vscode";
4+
import { commands, ConfigurationChangeEvent, Disposable, ViewColumn, WebviewPanel, window, workspace } from "vscode";
55
import { markdownEngine } from "./markdownEngine";
66

77
export abstract class LeetCodeWebview implements Disposable {
88

9+
protected readonly viewType: string = "leetcode.webview";
910
protected panel: WebviewPanel | undefined;
1011
private listeners: Disposable[] = [];
1112

@@ -16,9 +17,9 @@ export abstract class LeetCodeWebview implements Disposable {
1617
}
1718

1819
protected showWebviewInternal(): void {
19-
const { viewType, title, viewColumn, preserveFocus } = this.getWebviewOption();
20+
const { title, viewColumn, preserveFocus } = this.getWebviewOption();
2021
if (!this.panel) {
21-
this.panel = window.createWebviewPanel(viewType, title, { viewColumn, preserveFocus }, {
22+
this.panel = window.createWebviewPanel(this.viewType, title, { viewColumn, preserveFocus }, {
2223
enableScripts: true,
2324
enableCommandUris: true,
2425
enableFindWidget: true,
@@ -30,7 +31,14 @@ export abstract class LeetCodeWebview implements Disposable {
3031
workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.listeners);
3132
} else {
3233
this.panel.title = title;
33-
this.panel.reveal(viewColumn, preserveFocus);
34+
if (viewColumn === ViewColumn.Two) {
35+
// Make sure second group exists. See vscode#71608 issue
36+
commands.executeCommand("workbench.action.focusSecondEditorGroup").then(() => {
37+
this.panel!.reveal(viewColumn, preserveFocus);
38+
});
39+
} else {
40+
this.panel.reveal(viewColumn, preserveFocus);
41+
}
3442
}
3543
this.panel.webview.html = this.getWebviewContent();
3644
}
@@ -57,7 +65,6 @@ export abstract class LeetCodeWebview implements Disposable {
5765
}
5866

5967
export interface ILeetCodeWebviewOption {
60-
viewType: string;
6168
title: string;
6269
viewColumn: ViewColumn;
6370
preserveFocus?: boolean;

Diff for: src/webview/leetCodePreviewProvider.ts

+33-11
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,44 @@
22
// Licensed under the MIT license.
33

44
import { commands, ViewColumn } from "vscode";
5-
import { leetCodeExecutor } from "../leetCodeExecutor";
65
import { IProblem } from "../shared";
76
import { ILeetCodeWebviewOption, LeetCodeWebview } from "./LeetCodeWebview";
87
import { markdownEngine } from "./markdownEngine";
98

109
class LeetCodePreviewProvider extends LeetCodeWebview {
1110

11+
protected readonly viewType: string = "leetcode.preview";
1212
private node: IProblem;
1313
private description: IDescription;
14+
private sideMode: boolean = false;
1415

15-
public async show(node: IProblem): Promise<void> {
16-
this.description = this.parseDescription(await leetCodeExecutor.getDescription(node), node);
16+
public isSideMode(): boolean {
17+
return this.sideMode;
18+
}
19+
20+
public show(descString: string, node: IProblem, isSideMode: boolean = false): void {
21+
this.description = this.parseDescription(descString, node);
1722
this.node = node;
23+
this.sideMode = isSideMode;
1824
this.showWebviewInternal();
25+
if (this.sideMode) {
26+
this.hideSideBar(); // For better view area
27+
}
1928
}
2029

2130
protected getWebviewOption(): ILeetCodeWebviewOption {
22-
return {
23-
viewType: "leetcode.preview",
24-
title: `${this.node.name}: Preview`,
25-
viewColumn: ViewColumn.One,
26-
};
31+
if (!this.sideMode) {
32+
return {
33+
title: `${this.node.name}: Preview`,
34+
viewColumn: ViewColumn.One,
35+
};
36+
} else {
37+
return {
38+
title: "Description",
39+
viewColumn: ViewColumn.Two,
40+
preserveFocus: true,
41+
};
42+
}
2743
}
2844

2945
protected getWebviewContent(): string {
@@ -84,18 +100,18 @@ class LeetCodePreviewProvider extends LeetCodeWebview {
84100
<html>
85101
<head>
86102
${markdownEngine.getStyles()}
87-
${button.style}
103+
${!this.sideMode ? button.style : ""}
88104
</head>
89105
<body>
90106
${head}
91107
${info}
92108
${tags}
93109
${companies}
94110
${body}
95-
${button.element}
111+
${!this.sideMode ? button.element : ""}
96112
<script>
97113
const vscode = acquireVsCodeApi();
98-
${button.script}
114+
${!this.sideMode ? button.script : ""}
99115
</script>
100116
</body>
101117
</html>
@@ -106,6 +122,7 @@ class LeetCodePreviewProvider extends LeetCodeWebview {
106122
super.onDidDisposeWebview();
107123
delete this.node;
108124
delete this.description;
125+
this.sideMode = false;
109126
}
110127

111128
protected async onDidReceiveMessage(message: IWebViewMessage): Promise<void> {
@@ -117,6 +134,11 @@ class LeetCodePreviewProvider extends LeetCodeWebview {
117134
}
118135
}
119136

137+
private async hideSideBar(): Promise<void> {
138+
await commands.executeCommand("workbench.action.focusSideBar");
139+
await commands.executeCommand("workbench.action.toggleSidebarVisibility");
140+
}
141+
120142
private parseDescription(descString: string, problem: IProblem): IDescription {
121143
const [
122144
/* title */, ,

Diff for: src/webview/leetCodeSolutionProvider.ts

+15-6
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@
33

44
import { ViewColumn } from "vscode";
55
import { IProblem } from "../shared";
6+
import { leetCodePreviewProvider } from "./leetCodePreviewProvider";
67
import { ILeetCodeWebviewOption, LeetCodeWebview } from "./LeetCodeWebview";
78
import { markdownEngine } from "./markdownEngine";
89

910
class LeetCodeSolutionProvider extends LeetCodeWebview {
1011

12+
protected readonly viewType: string = "leetcode.solution";
1113
private solution: Solution;
1214

13-
public async show(solutionString: string, problem: IProblem): Promise<void> {
15+
public show(solutionString: string, problem: IProblem): void {
1416
this.solution = this.parseSolution(solutionString, problem);
1517
this.showWebviewInternal();
1618
}
1719

1820
protected getWebviewOption(): ILeetCodeWebviewOption {
19-
return {
20-
viewType: "leetcode.solution",
21-
title: `${this.solution.problem}: Solution`,
22-
viewColumn: ViewColumn.One,
23-
};
21+
if (!leetCodePreviewProvider.isSideMode()) {
22+
return {
23+
title: `${this.solution.problem}: Solution`,
24+
viewColumn: ViewColumn.One,
25+
};
26+
} else {
27+
return {
28+
title: "Solution",
29+
viewColumn: ViewColumn.Two,
30+
preserveFocus: true,
31+
};
32+
}
2433
}
2534

2635
protected getWebviewContent(): string {

Diff for: src/webview/leetCodeSubmissionProvider.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ import { markdownEngine } from "./markdownEngine";
77

88
class LeetCodeSubmissionProvider extends LeetCodeWebview {
99

10+
protected readonly viewType: string = "leetcode.submission";
1011
private result: string;
1112

12-
public async show(result: string): Promise<void> {
13+
public show(result: string): void {
1314
this.result = result;
1415
this.showWebviewInternal();
1516
}
1617

1718
protected getWebviewOption(): ILeetCodeWebviewOption {
1819
return {
19-
viewType: "leetcode.submission",
2020
title: "Submission",
2121
viewColumn: ViewColumn.Two,
2222
};

0 commit comments

Comments
 (0)