From 19af64fec1693e88c8b94335cd968892672a12fa Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Thu, 20 Jun 2019 12:58:20 +0800
Subject: [PATCH 01/84] docs: Update documents (#351)
---
README.md | 2 +-
docs/README_zh-CN.md | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 5fcf3138..8943f671 100644
--- a/README.md
+++ b/README.md
@@ -124,7 +124,7 @@
| `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: - `${tag}`: Categorize the problem according to their tags.
- `${language}`: Categorize the problem according to their language.
- `${difficulty}`: Categorize the problem according to their difficulty.
For example: `problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | Specify whether the LeetCode status bar will be shown or not. | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | Specify whether the submit and test shortcuts in editor or not. | `true` |
-| `leetcode.editor.shortcuts` | Specify the customized shorcuts in editors | `["submit, test"]` |
+| `leetcode.editor.shortcuts` | Specify the customized shorcuts in editors. Supported values are: `submit`, `test`, `solution` and `description`. | `["submit, test"]` |
| `leetcode.enableSideMode` | Specify whether `preview`, `solution` and `submission` tab should be grouped into the second editor column when solving a problem. | `true` |
| `leetcode.nodePath` | Specify the `Node.js` executable path. | `node` |
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index 0bd9d54d..d1a06b16 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -124,7 +124,7 @@
| `leetcode.outputFolder` | 指定保存文件时所用的相对文件夹路径。除了用户自定义路径外,也可以使用保留项,包括:- `${tag}`: 根据题目的类别进行分类。
- `${language}`: 根据题目的语言进行分类。
- `${difficulty}`: 根据题目的难度进行分类。
例如:`problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | 指定是否在 VS Code 下方显示插件状态栏。 | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | 指定是否在 VS Code 编辑文件下方显示提交和测试的快捷按钮。 | `true` |
-| `leetcode.editor.shortcuts` | 指定在编辑器内所自定义的快捷方式。 | `["submit, test"]` |
+| `leetcode.editor.shortcuts` | 指定在编辑器内所自定义的快捷方式。可用的快捷方式有: `submit`, `test`, `solution`, `description`。 | `["submit, test"]` |
| `leetcode.enableSideMode` | 指定在解决一道题时,是否将`问题预览`、`高票答案`与`提交结果`窗口集中在编辑器的第二栏。 | `true` |
| `leetcode.nodePath` | 指定 `Node.js` 可执行文件的路径。 | `node` |
From 1004e1df2573a8665a6060f6bd68cae852cfa80b Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Fri, 28 Jun 2019 13:07:47 +0800
Subject: [PATCH 02/84] feat: Support delete a session (#358)
---
README.md | 2 +-
docs/README_zh-CN.md | 2 +-
package-lock.json | 6 +-
package.json | 14 ++--
src/commands/session.ts | 91 +++++++++++++++++++++-----
src/extension.ts | 3 +-
src/leetCodeExecutor.ts | 8 ++-
src/statusbar/LeetCodeStatusBarItem.ts | 2 +-
8 files changed, 91 insertions(+), 37 deletions(-)
diff --git a/README.md b/README.md
index 8943f671..cc0bffea 100644
--- a/README.md
+++ b/README.md
@@ -110,7 +110,7 @@
-- To manage your LeetCode sessions, just clicking the `LeetCode: ***` at the bottom of the status bar. You can **switch** between sessions or **create** a new session.
+- To manage your LeetCode sessions, just clicking the `LeetCode: ***` at the bottom of the status bar. You can **switch** between sessions or **create**, **delete** a session.
## Settings
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index d1a06b16..0a3e23e5 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -110,7 +110,7 @@
-- 点击位于 VS Code 底部状态栏的 `LeetCode: ***` 管理 `LeetCode 存档`。你可以**切换**存档或者**创建**新的存档。
+- 点击位于 VS Code 底部状态栏的 `LeetCode: ***` 管理 `LeetCode 存档`。你可以**切换**存档或者**创建**,**删除**存档。
## 插件配置项
diff --git a/package-lock.json b/package-lock.json
index 0dbe10b8..46afe0b2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1786,9 +1786,9 @@
}
},
"vsc-leetcode-cli": {
- "version": "2.6.7",
- "resolved": "https://registry.npmjs.org/vsc-leetcode-cli/-/vsc-leetcode-cli-2.6.7.tgz",
- "integrity": "sha512-OBTF0XV9drJEdGCOysx/nCmmzgqBOnn6baH9On6ZbTNr9chl3reuC7OfKHNts/DzEW71wStT7Xg2N2WJSMsojw==",
+ "version": "2.6.8",
+ "resolved": "https://registry.npmjs.org/vsc-leetcode-cli/-/vsc-leetcode-cli-2.6.8.tgz",
+ "integrity": "sha512-Zo1GBWgr7orJawlTUmXMUCGpPJ8RThoHMh9vABiPJO3n+uhPgLNGkuETIKk7u+I1dD7FHk+G/IxfD5siR49z2A==",
"requires": {
"ansi-styles": "3.2.1",
"cheerio": "0.20.0",
diff --git a/package.json b/package.json
index d0f5360e..0ba3e9aa 100644
--- a/package.json
+++ b/package.json
@@ -29,8 +29,7 @@
"onCommand:leetcode.toggleLeetCodeCn",
"onCommand:leetcode.signin",
"onCommand:leetcode.signout",
- "onCommand:leetcode.selectSessions",
- "onCommand:leetcode.createSession",
+ "onCommand:leetcode.manageSessions",
"onCommand:leetcode.refreshExplorer",
"onCommand:leetcode.showProblem",
"onCommand:leetcode.previewProblem",
@@ -72,13 +71,8 @@
"category": "LeetCode"
},
{
- "command": "leetcode.selectSessions",
- "title": "Select Session",
- "category": "LeetCode"
- },
- {
- "command": "leetcode.createSession",
- "title": "Create New Session",
+ "command": "leetcode.manageSessions",
+ "title": "Manage Sessions",
"category": "LeetCode"
},
{
@@ -394,6 +388,6 @@
"markdown-it": "^8.4.2",
"require-from-string": "^2.0.2",
"unescape-js": "^1.1.1",
- "vsc-leetcode-cli": "2.6.7"
+ "vsc-leetcode-cli": "2.6.8"
}
}
diff --git a/src/commands/session.ts b/src/commands/session.ts
index 5cf37724..f86d4cf3 100644
--- a/src/commands/session.ts
+++ b/src/commands/session.ts
@@ -5,7 +5,7 @@ import * as vscode from "vscode";
import { leetCodeExecutor } from "../leetCodeExecutor";
import { leetCodeManager } from "../leetCodeManager";
import { IQuickItemEx } from "../shared";
-import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
+import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
export async function getSessionList(): Promise {
const signInStatus: string | undefined = leetCodeManager.getUser();
@@ -32,17 +32,21 @@ export async function getSessionList(): Promise {
return sessions;
}
-export async function selectSession(): Promise {
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseSessionsToPicks());
+export async function manageSessions(): Promise {
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(parseSessionsToPicks(true /* includeOperation */));
if (!choice || choice.description === "Active") {
return;
}
- if (choice.value === ":createNewSession") {
- await vscode.commands.executeCommand("leetcode.createSession");
+ if (choice.value === ":createSession") {
+ await createSession();
+ return;
+ }
+ if (choice.value === ":deleteSession") {
+ await deleteSession();
return;
}
try {
- await leetCodeExecutor.enableSession(choice.value);
+ await leetCodeExecutor.enableSession((choice.value as ISession).id);
vscode.window.showInformationMessage(`Successfully switched to session '${choice.label}'.`);
await vscode.commands.executeCommand("leetcode.refreshExplorer");
} catch (error) {
@@ -50,22 +54,20 @@ export async function selectSession(): Promise {
}
}
-async function parseSessionsToPicks(): Promise>> {
- return new Promise(async (resolve: (res: Array>) => void): Promise => {
+async function parseSessionsToPicks(includeOperations: boolean = false): Promise>> {
+ return new Promise(async (resolve: (res: Array>) => void): Promise => {
try {
const sessions: ISession[] = await getSessionList();
- const picks: Array> = sessions.map((s: ISession) => Object.assign({}, {
+ const picks: Array> = sessions.map((s: ISession) => Object.assign({}, {
label: `${s.active ? "$(check) " : ""}${s.name}`,
description: s.active ? "Active" : "",
detail: `AC Questions: ${s.acQuestions}, AC Submits: ${s.acSubmits}`,
- value: s.id,
+ value: s,
}));
- picks.push({
- label: "$(plus) Create a new session",
- description: "",
- detail: "Click this item to create a new session",
- value: ":createNewSession",
- });
+
+ if (includeOperations) {
+ picks.push(...parseSessionManagementOperations());
+ }
resolve(picks);
} catch (error) {
return await promptForOpenOutputChannel("Failed to list sessions. Please open the output channel for details.", DialogType.error);
@@ -73,7 +75,21 @@ async function parseSessionsToPicks(): Promise>> {
});
}
-export async function createSession(): Promise {
+function parseSessionManagementOperations(): Array> {
+ return [{
+ label: "$(plus) Create a session",
+ description: "",
+ detail: "Click this item to create a session",
+ value: ":createSession",
+ }, {
+ label: "$(trashcan) Delete a session",
+ description: "",
+ detail: "Click this item to DELETE a session",
+ value: ":deleteSession",
+ }];
+}
+
+async function createSession(): Promise {
const session: string | undefined = await vscode.window.showInputBox({
prompt: "Enter the new session name.",
validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "Session name must not be empty",
@@ -89,6 +105,47 @@ export async function createSession(): Promise {
}
}
+async function deleteSession(): Promise {
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
+ parseSessionsToPicks(false /* includeOperation */),
+ { placeHolder: "Please select the session you want to delete" },
+ );
+ if (!choice) {
+ return;
+ }
+
+ const selectedSession: ISession = choice.value as ISession;
+ if (selectedSession.active) {
+ vscode.window.showInformationMessage("Cannot delete an active session.");
+ return;
+ }
+
+ const action: vscode.MessageItem | undefined = await vscode.window.showWarningMessage(
+ `This operation cannot be reverted. Are you sure to delete the session: ${selectedSession.name}?`,
+ DialogOptions.yes,
+ DialogOptions.no,
+ );
+ if (action !== DialogOptions.yes) {
+ return;
+ }
+
+ const confirm: string | undefined = await vscode.window.showInputBox({
+ prompt: "Enter 'yes' to confirm deleting the session",
+ validateInput: (value: string): string => {
+ if (value === "yes") {
+ return "";
+ } else {
+ return "Enter 'yes' to confirm";
+ }
+ },
+ });
+
+ if (confirm === "yes") {
+ await leetCodeExecutor.deleteSession(selectedSession.id);
+ vscode.window.showInformationMessage("The session has been successfully deleted.");
+ }
+}
+
export interface ISession {
active: boolean;
id: string;
diff --git a/src/extension.ts b/src/extension.ts
index a2467c8d..4d33d803 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -51,8 +51,7 @@ export async function activate(context: vscode.ExtensionContext): Promise
vscode.commands.registerCommand("leetcode.toggleLeetCodeCn", () => plugin.switchEndpoint()),
vscode.commands.registerCommand("leetcode.signin", () => leetCodeManager.signIn()),
vscode.commands.registerCommand("leetcode.signout", () => leetCodeManager.signOut()),
- vscode.commands.registerCommand("leetcode.selectSessions", () => session.selectSession()),
- vscode.commands.registerCommand("leetcode.createSession", () => session.createSession()),
+ vscode.commands.registerCommand("leetcode.manageSessions", () => session.manageSessions()),
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()),
diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts
index ad2d0514..c3ef495c 100644
--- a/src/leetCodeExecutor.ts
+++ b/src/leetCodeExecutor.ts
@@ -124,8 +124,12 @@ class LeetCodeExecutor implements Disposable {
return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-e", name]);
}
- public async createSession(name: string): Promise {
- return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-c", name]);
+ public async createSession(id: string): Promise {
+ return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-c", id]);
+ }
+
+ public async deleteSession(id: string): Promise {
+ return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-d", id]);
}
public async submitSolution(filePath: string): Promise {
diff --git a/src/statusbar/LeetCodeStatusBarItem.ts b/src/statusbar/LeetCodeStatusBarItem.ts
index 5ca9bde6..35ca7412 100644
--- a/src/statusbar/LeetCodeStatusBarItem.ts
+++ b/src/statusbar/LeetCodeStatusBarItem.ts
@@ -9,7 +9,7 @@ export class LeetCodeStatusBarItem implements vscode.Disposable {
constructor() {
this.statusBarItem = vscode.window.createStatusBarItem();
- this.statusBarItem.command = "leetcode.selectSessions";
+ this.statusBarItem.command = "leetcode.manageSessions";
}
public updateStatusBar(status: UserStatus, user?: string): void {
From 4abd6fcce099d1afc87638719c866ad477bce160 Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Fri, 28 Jun 2019 13:29:23 +0800
Subject: [PATCH 03/84] fix: Break new line when the description is too long
(#359)
---
src/webview/leetCodePreviewProvider.ts | 3 +++
1 file changed, 3 insertions(+)
diff --git a/src/webview/leetCodePreviewProvider.ts b/src/webview/leetCodePreviewProvider.ts
index a019db95..1bd83e69 100644
--- a/src/webview/leetCodePreviewProvider.ts
+++ b/src/webview/leetCodePreviewProvider.ts
@@ -103,6 +103,9 @@ class LeetCodePreviewProvider extends LeetCodeWebview {
${markdownEngine.getStyles()}
${!this.sideMode ? button.style : ""}
+
${head}
From 453c51a3bf62aacb2354e92fdcccd3c49aeb3550 Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Thu, 11 Jul 2019 16:23:40 +0800
Subject: [PATCH 04/84] feat: Can specify the workspace folder to save the
files (#360)
---
README.md | 3 ++-
docs/README_zh-CN.md | 3 ++-
package.json | 6 +++++
src/commands/show.ts | 4 +++
src/utils/settingUtils.ts | 6 +++++
src/utils/workspaceUtils.ts | 54 +++++++++++++++++++++++++++++--------
6 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/README.md b/README.md
index cc0bffea..a46fe59c 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@
- Directly click on the problem or right click the problem in the `LeetCode Explorer` and select `Preview Problem` to see the problem description.
- Select `Show Problem` to directly open the file with the problem description.
- > Note: If no folder is opened in VS Code, the extension will save the problem files in **$HOME/.leetcode/**.
+ > Note:You can specify the path of the workspace folder to store the problem files by updating the setting `leetcode.workspaceFolder`. The default value is:**$HOME/.leetcode/**.
> You can specify whether including the problem description in comments or not by updating the setting `leetcode.showCommentDescription`.
@@ -121,6 +121,7 @@
| `leetcode.defaultLanguage` | Specify the default language used to solve the problem. Supported languages are: `bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`,`rust`, `scala`,`swift` | `N/A` |
| `leetcode.useWsl` | Specify whether to use WSL or not | `false` |
| `leetcode.endpoint` | Specify the active endpoint. Supported endpoints are: `leetcode`, `leetcode-cn` | `leetcode` |
+| `leetcode.workspaceFolder` | Specify the path of the workspace folder to store the problem files. | `${home}/.leetcode` |
| `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: - `${tag}`: Categorize the problem according to their tags.
- `${language}`: Categorize the problem according to their language.
- `${difficulty}`: Categorize the problem according to their difficulty.
For example: `problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | Specify whether the LeetCode status bar will be shown or not. | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | Specify whether the submit and test shortcuts in editor or not. | `true` |
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index 0a3e23e5..6d90edb6 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -73,7 +73,7 @@
- 直接点击题目或者在 `LeetCode Explorer` 中**右键**题目并选择 `Preview Problem` 可查看题目描述
- 选择 `Show Problem` 可直接进行答题。
- > 注意:若当前 VS Code 没有已打开的文件夹,则生成的题目文件会存储于 **$HOME/.leetcode/** 目录下。
+ > 注意:你可以通过更新配置项 `leetcode.workspaceFolder` 来指定保存题目文件所用的工作区路径。默认工作区路径为:**$HOME/.leetcode/**。
> 注意:你可以通过更新配置项 `leetcode.showCommentDescription` 来指定是否要在注释中包含题目描述。
@@ -121,6 +121,7 @@
| `leetcode.defaultLanguage` | 指定答题时使用的默认语言,可选语言有:`bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`, `rust`, `scala`,`swift` | `N/A` |
| `leetcode.useWsl` | 指定是否启用 WSL | `false` |
| `leetcode.endpoint` | 指定使用的终端,可用终端有:`leetcode`, `leetcode-cn` | `leetcode` |
+| `leetcode.workspaceFolder` | 指定保存文件的工作区目录 | `${home}/.leetcode` |
| `leetcode.outputFolder` | 指定保存文件时所用的相对文件夹路径。除了用户自定义路径外,也可以使用保留项,包括:- `${tag}`: 根据题目的类别进行分类。
- `${language}`: 根据题目的语言进行分类。
- `${difficulty}`: 根据题目的难度进行分类。
例如:`problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | 指定是否在 VS Code 下方显示插件状态栏。 | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | 指定是否在 VS Code 编辑文件下方显示提交和测试的快捷按钮。 | `true` |
diff --git a/package.json b/package.json
index 0ba3e9aa..5f90e490 100644
--- a/package.json
+++ b/package.json
@@ -310,6 +310,12 @@
],
"description": "Endpoint of the user account."
},
+ "leetcode.workspaceFolder": {
+ "type": "string",
+ "scope": "application",
+ "description": "The path of the workspace folder to store the problem files.",
+ "default": "${home}/.leetcode"
+ },
"leetcode.outputFolder": {
"type": "string",
"scope": "application",
diff --git a/src/commands/show.ts b/src/commands/show.ts
index 7dceffed..896516a9 100644
--- a/src/commands/show.ts
+++ b/src/commands/show.ts
@@ -128,6 +128,10 @@ async function showProblemInternal(node: IProblem): Promise {
const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode");
let outDir: string = await selectWorkspaceFolder();
+ if (!outDir) {
+ return;
+ }
+
let relativePath: string = (leetCodeConfig.get("outputFolder", "")).trim();
if (relativePath) {
relativePath = await resolveRelativePath(relativePath, node, language);
diff --git a/src/utils/settingUtils.ts b/src/utils/settingUtils.ts
index 3cc48ea7..b7cb5919 100644
--- a/src/utils/settingUtils.ts
+++ b/src/utils/settingUtils.ts
@@ -1,6 +1,7 @@
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.
+import * as os from "os";
import { workspace, WorkspaceConfiguration } from "vscode";
export function getWorkspaceConfiguration(): WorkspaceConfiguration {
@@ -11,6 +12,11 @@ export function shouldHideSolvedProblem(): boolean {
return getWorkspaceConfiguration().get("hideSolved", false);
}
+export function getWorkspaceFolder(): string {
+ const rawWorkspaceFolder: string = getWorkspaceConfiguration().get("workspaceFolder", "${home}/.leetcode");
+ return rawWorkspaceFolder.replace(/\${home}/i, os.homedir());
+}
+
export function getEditorShortcuts(): string[] {
return getWorkspaceConfiguration().get("editor.shortcuts", ["submit", "test"]);
}
diff --git a/src/utils/workspaceUtils.ts b/src/utils/workspaceUtils.ts
index f2f2d16b..df7df0ad 100644
--- a/src/utils/workspaceUtils.ts
+++ b/src/utils/workspaceUtils.ts
@@ -1,26 +1,47 @@
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.
-import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
+import { getWorkspaceFolder } from "./settingUtils";
import * as wsl from "./wslUtils";
export async function selectWorkspaceFolder(): Promise {
- let folder: vscode.WorkspaceFolder | undefined;
- if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
- if (vscode.workspace.workspaceFolders.length > 1) {
- folder = await vscode.window.showWorkspaceFolderPick({
- placeHolder: "Select the working directory you wish to use",
- });
- } else {
- folder = vscode.workspace.workspaceFolders[0];
+ const workspaceFolderSetting: string = getWorkspaceFolder();
+ const workspaceFolders: vscode.WorkspaceFolder[] = vscode.workspace.workspaceFolders || [];
+ let needAsk: boolean = true;
+ for (const folder of workspaceFolders) {
+ if (isSubFolder(folder.uri.fsPath, workspaceFolderSetting)) {
+ needAsk = false;
}
}
- const workFolder: string = folder ? folder.uri.fsPath : path.join(os.homedir(), ".leetcode");
+ if (needAsk) {
+ const choice: string | undefined = await vscode.window.showQuickPick(
+ [
+ OpenOption.openInCurrentWindow,
+ OpenOption.openInNewWindow,
+ OpenOption.addToWorkspace,
+ ],
+ { placeHolder: "Select how you would like to open your workspace folder" },
+ );
- return wsl.useWsl() ? wsl.toWslPath(workFolder) : workFolder;
+ switch (choice) {
+ case OpenOption.openInCurrentWindow:
+ await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), false);
+ return "";
+ case OpenOption.openInNewWindow:
+ await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), true);
+ return "";
+ case OpenOption.addToWorkspace:
+ vscode.workspace.updateWorkspaceFolders(workspaceFolders.length, 0, { uri: vscode.Uri.file(workspaceFolderSetting) });
+ break;
+ default:
+ return "";
+ }
+ }
+
+ return wsl.useWsl() ? wsl.toWslPath(workspaceFolderSetting) : workspaceFolderSetting;
}
export async function getActiveFilePath(uri?: vscode.Uri): Promise {
@@ -40,3 +61,14 @@ export async function getActiveFilePath(uri?: vscode.Uri): Promise
Date: Thu, 11 Jul 2019 17:00:49 +0800
Subject: [PATCH 05/84] fix: Failed to resolve the Node executable path when it
contains spaces (#363)
---
README.md | 2 +-
docs/README_zh-CN.md | 2 +-
package.json | 2 +-
src/leetCodeExecutor.ts | 2 ++
src/utils/workspaceUtils.ts | 5 ++++-
5 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/README.md b/README.md
index a46fe59c..ce36142a 100644
--- a/README.md
+++ b/README.md
@@ -127,7 +127,7 @@
| **(Deprecated)** `leetcode.enableShortcuts` | Specify whether the submit and test shortcuts in editor or not. | `true` |
| `leetcode.editor.shortcuts` | Specify the customized shorcuts in editors. Supported values are: `submit`, `test`, `solution` and `description`. | `["submit, test"]` |
| `leetcode.enableSideMode` | Specify whether `preview`, `solution` and `submission` tab should be grouped into the second editor column when solving a problem. | `true` |
-| `leetcode.nodePath` | Specify the `Node.js` executable path. | `node` |
+| `leetcode.nodePath` | Specify the `Node.js` executable path. for example, C:\Program Files\nodejs\node.exe | `node` |
## Want Help?
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index 6d90edb6..be328359 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -127,7 +127,7 @@
| **(Deprecated)** `leetcode.enableShortcuts` | 指定是否在 VS Code 编辑文件下方显示提交和测试的快捷按钮。 | `true` |
| `leetcode.editor.shortcuts` | 指定在编辑器内所自定义的快捷方式。可用的快捷方式有: `submit`, `test`, `solution`, `description`。 | `["submit, test"]` |
| `leetcode.enableSideMode` | 指定在解决一道题时,是否将`问题预览`、`高票答案`与`提交结果`窗口集中在编辑器的第二栏。 | `true` |
-| `leetcode.nodePath` | 指定 `Node.js` 可执行文件的路径。 | `node` |
+| `leetcode.nodePath` | 指定 `Node.js` 可执行文件的路径。如:C:\Program Files\nodejs\node.exe | `node` |
## 需要帮助?
在遇到任何问题时,可以先查看一下[疑难解答](https://github.com/jdneo/vscode-leetcode/wiki/%E7%96%91%E9%9A%BE%E8%A7%A3%E7%AD%94)以及[常见问题](https://github.com/jdneo/vscode-leetcode/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)寻求帮助。
diff --git a/package.json b/package.json
index 5f90e490..5e0005b8 100644
--- a/package.json
+++ b/package.json
@@ -361,7 +361,7 @@
"type": "string",
"default": "node",
"scope": "application",
- "description": "The Node.js executable path."
+ "description": "The Node.js executable path. for example, C:\\Program Files\\nodejs\\node.exe"
}
}
}
diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts
index c3ef495c..8bef00fa 100644
--- a/src/leetCodeExecutor.ts
+++ b/src/leetCodeExecutor.ts
@@ -49,6 +49,8 @@ class LeetCodeExecutor implements Disposable {
if (!await fse.pathExists(this.nodeExecutable)) {
throw new Error(`The Node.js executable does not exist on path ${this.nodeExecutable}`);
}
+ // Wrap the executable with "" to avoid space issue in the path.
+ this.nodeExecutable = `"${this.nodeExecutable}"`;
if (useWsl()) {
this.nodeExecutable = await toWslPath(this.nodeExecutable);
}
diff --git a/src/utils/workspaceUtils.ts b/src/utils/workspaceUtils.ts
index df7df0ad..b27a3ddf 100644
--- a/src/utils/workspaceUtils.ts
+++ b/src/utils/workspaceUtils.ts
@@ -64,7 +64,10 @@ export async function getActiveFilePath(uri?: vscode.Uri): Promise
Date: Thu, 11 Jul 2019 20:21:04 +0800
Subject: [PATCH 06/84] chore: Prepare for 0.15.2 (#364)
---
CHANGELOG.md | 8 ++++++++
package-lock.json | 2 +-
package.json | 2 +-
3 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 41a9e7a9..c5e16401 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,14 @@ All notable changes to the "leetcode" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
+##[0.15.2]
+### Added
+- Prompt to open the workspace for LeetCode [#130](https://github.com/jdneo/vscode-leetcode/issues/130)
+- Support deleting sessions [#198](https://github.com/jdneo/vscode-leetcode/issues/130)
+
+### Fixed
+[Bugs fixed](https://github.com/jdneo/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.2+is%3Aclosed+label%3Abug)
+
## [0.15.1]
### Fixed
[Bugs fixed](https://github.com/jdneo/vscode-leetcode/issues?q=is%3Aissue+milestone%3A0.15.1+is%3Aclosed+label%3Abug)
diff --git a/package-lock.json b/package-lock.json
index 46afe0b2..ed6984a3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "vscode-leetcode",
- "version": "0.15.1",
+ "version": "0.15.2",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 5e0005b8..66450123 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "vscode-leetcode",
"displayName": "LeetCode",
"description": "Solve LeetCode problems in VS Code",
- "version": "0.15.1",
+ "version": "0.15.2",
"author": "Sheng Chen",
"publisher": "shengchen",
"license": "MIT",
From e1f3206756c1909c36a3832bec8f010e4e18bf8e Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Fri, 12 Jul 2019 15:16:12 +0800
Subject: [PATCH 07/84] feat: Can select folder to save the LeetCode files
(#365)
---
README.md | 2 +-
docs/README_zh-CN.md | 2 +-
package.json | 2 +-
src/utils/settingUtils.ts | 4 +--
src/utils/uiUtils.ts | 12 +++++++++
src/utils/workspaceUtils.ts | 50 +++++++++++++++++++++++++++++++++++--
6 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index ce36142a..95067331 100644
--- a/README.md
+++ b/README.md
@@ -121,7 +121,7 @@
| `leetcode.defaultLanguage` | Specify the default language used to solve the problem. Supported languages are: `bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`,`rust`, `scala`,`swift` | `N/A` |
| `leetcode.useWsl` | Specify whether to use WSL or not | `false` |
| `leetcode.endpoint` | Specify the active endpoint. Supported endpoints are: `leetcode`, `leetcode-cn` | `leetcode` |
-| `leetcode.workspaceFolder` | Specify the path of the workspace folder to store the problem files. | `${home}/.leetcode` |
+| `leetcode.workspaceFolder` | Specify the path of the workspace folder to store the problem files. | `""` |
| `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: - `${tag}`: Categorize the problem according to their tags.
- `${language}`: Categorize the problem according to their language.
- `${difficulty}`: Categorize the problem according to their difficulty.
For example: `problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | Specify whether the LeetCode status bar will be shown or not. | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | Specify whether the submit and test shortcuts in editor or not. | `true` |
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index be328359..c23ea861 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -121,7 +121,7 @@
| `leetcode.defaultLanguage` | 指定答题时使用的默认语言,可选语言有:`bash`, `c`, `cpp`, `csharp`, `golang`, `java`, `javascript`, `kotlin`, `mysql`, `php`, `python`,`python3`,`ruby`, `rust`, `scala`,`swift` | `N/A` |
| `leetcode.useWsl` | 指定是否启用 WSL | `false` |
| `leetcode.endpoint` | 指定使用的终端,可用终端有:`leetcode`, `leetcode-cn` | `leetcode` |
-| `leetcode.workspaceFolder` | 指定保存文件的工作区目录 | `${home}/.leetcode` |
+| `leetcode.workspaceFolder` | 指定保存文件的工作区目录 | `""` |
| `leetcode.outputFolder` | 指定保存文件时所用的相对文件夹路径。除了用户自定义路径外,也可以使用保留项,包括:- `${tag}`: 根据题目的类别进行分类。
- `${language}`: 根据题目的语言进行分类。
- `${difficulty}`: 根据题目的难度进行分类。
例如:`problem-${tag}-${difficulty}` | N/A |
| `leetcode.enableStatusBar` | 指定是否在 VS Code 下方显示插件状态栏。 | `true` |
| **(Deprecated)** `leetcode.enableShortcuts` | 指定是否在 VS Code 编辑文件下方显示提交和测试的快捷按钮。 | `true` |
diff --git a/package.json b/package.json
index 66450123..bb04635b 100644
--- a/package.json
+++ b/package.json
@@ -314,7 +314,7 @@
"type": "string",
"scope": "application",
"description": "The path of the workspace folder to store the problem files.",
- "default": "${home}/.leetcode"
+ "default": ""
},
"leetcode.outputFolder": {
"type": "string",
diff --git a/src/utils/settingUtils.ts b/src/utils/settingUtils.ts
index b7cb5919..388f31b8 100644
--- a/src/utils/settingUtils.ts
+++ b/src/utils/settingUtils.ts
@@ -1,7 +1,6 @@
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.
-import * as os from "os";
import { workspace, WorkspaceConfiguration } from "vscode";
export function getWorkspaceConfiguration(): WorkspaceConfiguration {
@@ -13,8 +12,7 @@ export function shouldHideSolvedProblem(): boolean {
}
export function getWorkspaceFolder(): string {
- const rawWorkspaceFolder: string = getWorkspaceConfiguration().get("workspaceFolder", "${home}/.leetcode");
- return rawWorkspaceFolder.replace(/\${home}/i, os.homedir());
+ return getWorkspaceConfiguration().get("workspaceFolder", "");
}
export function getEditorShortcuts(): string[] {
diff --git a/src/utils/uiUtils.ts b/src/utils/uiUtils.ts
index 1fec63e3..037b2371 100644
--- a/src/utils/uiUtils.ts
+++ b/src/utils/uiUtils.ts
@@ -92,6 +92,18 @@ export async function showFileSelectDialog(): Promise
return await vscode.window.showOpenDialog(options);
}
+export async function showDirectorySelectDialog(): Promise {
+ const defaultUri: vscode.Uri | undefined = vscode.workspace.rootPath ? vscode.Uri.file(vscode.workspace.rootPath) : undefined;
+ const options: vscode.OpenDialogOptions = {
+ defaultUri,
+ canSelectFiles: false,
+ canSelectFolders: true,
+ canSelectMany: false,
+ openLabel: "Select",
+ };
+ return await vscode.window.showOpenDialog(options);
+}
+
export async function openUrl(url: string): Promise {
vscode.commands.executeCommand("vscode.open", vscode.Uri.parse(url));
}
diff --git a/src/utils/workspaceUtils.ts b/src/utils/workspaceUtils.ts
index b27a3ddf..b77fc3c7 100644
--- a/src/utils/workspaceUtils.ts
+++ b/src/utils/workspaceUtils.ts
@@ -1,13 +1,23 @@
// Copyright (c) jdneo. All rights reserved.
// Licensed under the MIT license.
+import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
-import { getWorkspaceFolder } from "./settingUtils";
+import { IQuickItemEx } from "../shared";
+import { getWorkspaceConfiguration, getWorkspaceFolder } from "./settingUtils";
+import { showDirectorySelectDialog } from "./uiUtils";
import * as wsl from "./wslUtils";
export async function selectWorkspaceFolder(): Promise {
- const workspaceFolderSetting: string = getWorkspaceFolder();
+ let workspaceFolderSetting: string = getWorkspaceFolder();
+ if (workspaceFolderSetting.trim() === "") {
+ workspaceFolderSetting = await determineLeetCodeFolder();
+ if (workspaceFolderSetting === "") {
+ // User cancelled
+ return workspaceFolderSetting;
+ }
+ }
const workspaceFolders: vscode.WorkspaceFolder[] = vscode.workspace.workspaceFolders || [];
let needAsk: boolean = true;
for (const folder of workspaceFolders) {
@@ -70,6 +80,42 @@ function isSubFolder(from: string, to: string): boolean {
return !relative.startsWith("..") && !path.isAbsolute(relative);
}
+async function determineLeetCodeFolder(): Promise {
+ let result: string;
+ const picks: Array> = [];
+ picks.push(
+ {
+ label: `Default location`,
+ detail: `${path.join(os.homedir(), ".leetcode")}`,
+ value: `${path.join(os.homedir(), ".leetcode")}`,
+ },
+ {
+ label: "$(file-directory) Browse...",
+ value: ":browse",
+ },
+ );
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
+ picks,
+ { placeHolder: "Select where you would like to save your LeetCode files" },
+ );
+ if (!choice) {
+ result = "";
+ } else if (choice.value === ":browse") {
+ const directory: vscode.Uri[] | undefined = await showDirectorySelectDialog();
+ if (!directory || directory.length < 1) {
+ result = "";
+ } else {
+ result = directory[0].fsPath;
+ }
+ } else {
+ result = choice.value;
+ }
+
+ getWorkspaceConfiguration().update("workspaceFolder", result, vscode.ConfigurationTarget.Global);
+
+ return result;
+}
+
enum OpenOption {
openInCurrentWindow = "Open in current window",
openInNewWindow = "Open in new window",
From 9b7847588ed84153af23f0c957acb5ade2b76d5a Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Fri, 12 Jul 2019 15:43:13 +0800
Subject: [PATCH 08/84] chore: Fix the changelog format
---
CHANGELOG.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c5e16401..2dd16029 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,7 +3,7 @@ All notable changes to the "leetcode" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
-##[0.15.2]
+## [0.15.2]
### Added
- Prompt to open the workspace for LeetCode [#130](https://github.com/jdneo/vscode-leetcode/issues/130)
- Support deleting sessions [#198](https://github.com/jdneo/vscode-leetcode/issues/130)
From 07ac6fb6b0a6527a4a0ccea02be3625781b89e96 Mon Sep 17 00:00:00 2001
From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon, 15 Jul 2019 14:22:38 +0800
Subject: [PATCH 09/84] chore(deps): bump lodash from 4.17.11 to 4.17.13 (#366)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.11 to 4.17.13.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.11...4.17.13)
Signed-off-by: dependabot[bot]
---
package-lock.json | 6 +++---
package.json | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index ed6984a3..a01167a6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -946,9 +946,9 @@
}
},
"lodash": {
- "version": "4.17.11",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
- "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+ "version": "4.17.13",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.13.tgz",
+ "integrity": "sha512-vm3/XWXfWtRua0FkUyEHBZy8kCPjErNBT9fJx8Zvs+U6zjqPbTUOpkaoum3O5uiA8sm+yNMHXfYkTUHFoMxFNA=="
},
"log-symbols": {
"version": "2.2.0",
diff --git a/package.json b/package.json
index bb04635b..722a0916 100644
--- a/package.json
+++ b/package.json
@@ -390,7 +390,7 @@
"dependencies": {
"fs-extra": "^6.0.1",
"highlight.js": "^9.15.6",
- "lodash": "^4.17.11",
+ "lodash": "^4.17.13",
"markdown-it": "^8.4.2",
"require-from-string": "^2.0.2",
"unescape-js": "^1.1.1",
From 6e37a825f4aef1c88d66f4ebdc346f13d49bb74d Mon Sep 17 00:00:00 2001
From: Sheng Chen
Date: Sat, 17 Aug 2019 14:20:33 +0800
Subject: [PATCH 10/84] docs: Update readme page
---
README.md | 6 +-----
docs/README_zh-CN.md | 6 +-----
docs/imgs/sponsor_coding.png | Bin 138165 -> 0 bytes
3 files changed, 2 insertions(+), 10 deletions(-)
delete mode 100644 docs/imgs/sponsor_coding.png
diff --git a/README.md b/README.md
index 95067331..a1d6e64d 100644
--- a/README.md
+++ b/README.md
@@ -20,11 +20,7 @@
-## Sponsor
-[](https://coding.net/?utm_source=leetcode)
-
-- [English Document](#Requirements)
-- [中文文档](https://github.com/jdneo/vscode-leetcode/blob/master/docs/README_zh-CN.md)
+- English Document | [中文文档](https://github.com/jdneo/vscode-leetcode/blob/master/docs/README_zh-CN.md)
## Requirements
- [VS Code 1.30.1+](https://code.visualstudio.com/)
diff --git a/docs/README_zh-CN.md b/docs/README_zh-CN.md
index c23ea861..619863bd 100644
--- a/docs/README_zh-CN.md
+++ b/docs/README_zh-CN.md
@@ -20,11 +20,7 @@
-## 赞助
-[](https://coding.net/?utm_source=leetcode)
-
-- [English Document](#Requirements)
-- [中文文档](https://github.com/jdneo/vscode-leetcode/blob/master/docs/README_zh-CN.md)
+- [English Document](https://github.com/jdneo/vscode-leetcode#requirements) | 中文文档
## 运行条件
- [VS Code 1.23.0+](https://code.visualstudio.com/)
diff --git a/docs/imgs/sponsor_coding.png b/docs/imgs/sponsor_coding.png
deleted file mode 100644
index 78c47fc0e224c50fcd6b10ece915e10ae36dc1c1..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 138165
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