diff --git a/package-lock.json b/package-lock.json index c428eb2b..fdf86b8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -776,7 +776,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { diff --git a/package.json b/package.json index b2a4a853..b582ecb8 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ ], "preview": true, "activationEvents": [ + "onCommand:leetcode.toogleLeetCodeCn", "onCommand:leetcode.signin", "onCommand:leetcode.signout", "onCommand:leetcode.selectSessions", @@ -39,6 +40,12 @@ "main": "./out/src/extension", "contributes": { "commands": [ + { + "command": "leetcode.toogleLeetCodeCn", + "title": "Switch endpoint", + "category": "LeetCode", + "icon": "resources/cn.png" + }, { "command": "leetcode.signin", "title": "Sign in", @@ -114,19 +121,24 @@ "menus": { "view/title": [ { - "command": "leetcode.signin", + "command": "leetcode.toogleLeetCodeCn", "when": "view == leetCodeExplorer", "group": "navigation@0" }, { - "command": "leetcode.searchProblem", + "command": "leetcode.signin", "when": "view == leetCodeExplorer", "group": "navigation@1" }, { - "command": "leetcode.refreshExplorer", + "command": "leetcode.searchProblem", "when": "view == leetCodeExplorer", "group": "navigation@2" + }, + { + "command": "leetcode.refreshExplorer", + "when": "view == leetCodeExplorer", + "group": "navigation@3" } ], "view/item/context": [ @@ -172,7 +184,7 @@ "leetcode.showLocked": { "type": "boolean", "default": false, - "scope": "window", + "scope": "application", "description": "Show locked problems." }, "leetcode.defaultLanguage": { @@ -193,20 +205,30 @@ "scala", "swift" ], - "scope": "window", + "scope": "application", "description": "Default language for solving the problems." }, "leetcode.showSetDefaultLanguageHint": { "type": "boolean", "default": true, - "scope": "window", + "scope": "application", "description": "Show a hint to set the default language." }, "leetcode.useWsl": { "type": "boolean", "default": false, - "scope": "window", + "scope": "application", "description": "Use Node.js inside the Windows Subsystem for Linux." + }, + "leetcode.endpoint": { + "type": "string", + "default": "leetcode", + "scope": "application", + "enum": [ + "leetcode", + "leetcode-cn" + ], + "description": "Endpoint of the user account." } } } @@ -216,7 +238,7 @@ "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./", - "postinstall": "node ./node_modules/vscode/bin/install", + "postinstall": "node ./node_modules/vscode/bin/install && node ./node_modules/leetcode-cli/bin/leetcode plugin -i leetcode.cn", "test": "npm run compile && node ./node_modules/vscode/bin/test", "lint": "tslint --project tsconfig.json -e src/*.d.ts -t verbose" }, diff --git a/resources/cn.png b/resources/cn.png new file mode 100644 index 00000000..4b05c7f2 Binary files /dev/null and b/resources/cn.png differ diff --git a/src/commands/plugin.ts b/src/commands/plugin.ts new file mode 100644 index 00000000..c904728f --- /dev/null +++ b/src/commands/plugin.ts @@ -0,0 +1,60 @@ +"use strict"; + +import * as vscode from "vscode"; +import { leetCodeExecutor } from "../leetCodeExecutor"; +import { IQuickItemEx } from "../shared"; +import { Endpoint } from "../shared"; +import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; + +export async function toogleLeetCodeCn(): Promise { + const isCnEnbaled: boolean = isLeetCodeCnEnabled(); + const picks: Array> = []; + picks.push( + { + label: `${isCnEnbaled ? "$(check) " : ""}On`, + description: "", + detail: `Enable ${Endpoint.LeetCodeCN}.`, + value: "on", + }, + { + label: `${isCnEnbaled ? "" : "$(check) "}Off`, + description: "", + detail: `Disable ${Endpoint.LeetCodeCN}.`, + value: "off", + }, + ); + const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks); + if (!choice) { + return; + } + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + try { + const enabled: boolean = choice.value === "on"; + const endpoint: string = enabled ? Endpoint.LeetCodeCN : Endpoint.LeetCode; + await leetCodeExecutor.toggleLeetCodeCn(enabled); + await leetCodeConfig.update("endpoint", endpoint, true /* UserSetting */); + vscode.window.showInformationMessage(`Switched the endpoint to ${endpoint}`); + } catch (error) { + await promptForOpenOutputChannel("Failed to switch endpoint. Please open the output channel for details.", DialogType.error); + } + + try { + await vscode.commands.executeCommand("leetcode.signout"); + await promptForSignIn(); + } catch (error) { + await promptForOpenOutputChannel("Failed to sign in. Please open the output channel for details.", DialogType.error); + } +} + +export async function initializeEndpoint(): Promise { + await leetCodeExecutor.toggleLeetCodeCn(isLeetCodeCnEnabled()); +} + +export function isLeetCodeCnEnabled(): boolean { + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + const endpoint: string | undefined = leetCodeConfig.get("endpoint"); + if (endpoint && endpoint === Endpoint.LeetCodeCN) { + return true; + } + return false; +} diff --git a/src/extension.ts b/src/extension.ts index 78182b67..e2c59434 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,6 +1,7 @@ "use strict"; import * as vscode from "vscode"; +import * as plugin from "./commands/plugin"; import * as session from "./commands/session"; import * as show from "./commands/show"; import * as submit from "./commands/submit"; @@ -20,6 +21,7 @@ export async function activate(context: vscode.ExtensionContext): Promise context.subscriptions.push( vscode.window.registerTreeDataProvider("leetCodeExplorer", leetCodeTreeDataProvider), + vscode.commands.registerCommand("leetcode.toogleLeetCodeCn", () => plugin.toogleLeetCodeCn()), vscode.commands.registerCommand("leetcode.signin", () => leetCodeManager.signIn()), vscode.commands.registerCommand("leetcode.signout", () => leetCodeManager.signOut()), vscode.commands.registerCommand("leetcode.selectSessions", () => session.selectSession()), @@ -31,6 +33,8 @@ export async function activate(context: vscode.ExtensionContext): Promise vscode.commands.registerCommand("leetcode.submitSolution", (uri?: vscode.Uri) => submit.submitSolution(uri)), ); + await plugin.initializeEndpoint(); + leetCodeManager.on("statusChanged", () => { leetCodeStatusBarItem.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser()); leetCodeTreeDataProvider.refresh(); diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index 20353c03..ad303704 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -30,6 +30,9 @@ export interface ILeetCodeExecutor { /* section for solution command */ submitSolution(filePath: string): Promise; testSolution(filePath: string, testString?: string): Promise; + + /* section for plugin command */ + toggleLeetCodeCn(isEnable: boolean): Promise; } class LeetCodeExecutor implements ILeetCodeExecutor { @@ -109,6 +112,13 @@ class LeetCodeExecutor implements ILeetCodeExecutor { return await this.executeCommandWithProgressEx("Submitting to LeetCode...", "node", [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]); } + public async toggleLeetCodeCn(isEnable: boolean): Promise { + if (isEnable) { + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-e", "leetcode.cn"]); + } + return await this.executeCommandEx("node", [await this.getLeetCodeBinaryPath(), "plugin", "-d", "leetcode.cn"]); + } + private async executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise { if (wsl.useWsl()) { return await executeCommand("wsl", [command].concat(args), options); diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 24ad4ebc..350698e2 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -109,7 +109,7 @@ class LeetCodeManager extends EventEmitter implements ILeetCodeManager { this.userStatus = UserStatus.SignedOut; this.emit("statusChanged"); } catch (error) { - promptForOpenOutputChannel("Failed to sign out. Please open the output channel for details", DialogType.error); + // swallow the error when sign out. } } diff --git a/src/shared.ts b/src/shared.ts index 9a5184ee..3a702452 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -33,3 +33,8 @@ export enum ProblemState { NotAC = 2, Unknown = 3, } + +export enum Endpoint { + LeetCode = "leetcode", + LeetCodeCN = "leetcode-cn", +} diff --git a/src/utils/uiUtils.ts b/src/utils/uiUtils.ts index d95b7567..9aa9ea9a 100644 --- a/src/utils/uiUtils.ts +++ b/src/utils/uiUtils.ts @@ -5,6 +5,7 @@ import * as opn from "opn"; import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; +import { isLeetCodeCnEnabled } from "../commands/plugin"; import { leetCodeChannel } from "../leetCodeChannel"; export namespace DialogOptions { @@ -48,7 +49,11 @@ export async function promptForSignIn(): Promise { await vscode.commands.executeCommand("leetcode.signin"); break; case DialogOptions.singUp: - opn("https://leetcode.com/"); + if (isLeetCodeCnEnabled()) { + opn("https://leetcode-cn.com/"); + } else { + opn("https://leetcode.com/"); + } break; default: break;