From 52e69bda883d4aa9b183e783bae78a2620528800 Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 10:16:40 +0800 Subject: [PATCH 01/31] logoutput --- package-lock.json | 31 +--- package.json | 8 - src/commands/list.ts | 4 - src/commands/session.ts | 156 ------------------ src/commands/show.ts | 14 +- .../LeetCodeTreeItemDecorationProvider.ts | 6 - src/extension.ts | 12 +- src/leetCodeExecutor.ts | 30 +--- src/leetCodeManager.ts | 6 +- src/statusbar/LeetCodeStatusBarItem.ts | 1 - src/utils/cpUtils.ts | 6 +- .../logOutput.ts} | 9 +- src/utils/uiUtils.ts | 4 +- src/webview/markdownEngine.ts | 4 +- 14 files changed, 28 insertions(+), 263 deletions(-) rename src/{leetCodeChannel.ts => utils/logOutput.ts} (63%) diff --git a/package-lock.json b/package-lock.json index 888f16e..ed8e5e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-leetcode-problem-rating", - "version": "1.1.8", + "version": "1.1.9", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-leetcode-problem-rating", - "version": "1.1.8", + "version": "1.1.9", "license": "MIT", "dependencies": { "ansi-styles": "3.2.1", @@ -22,7 +22,6 @@ "ora": "3.0.0", "prompt": "^1.2.0", "request": "2.88.0", - "require-from-string": "^2.0.2", "underscore": "1.12.1", "unescape-js": "^1.1.4", "wordwrap": "1.0.0" @@ -32,7 +31,6 @@ "@types/lodash": "^4.14.170", "@types/markdown-it": "0.0.7", "@types/node": "^14.14.33", - "@types/require-from-string": "^1.2.0", "@types/vscode": "1.57.0", "chai": "4.2.0", "tslint": "^5.20.1", @@ -121,12 +119,6 @@ "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true }, - "node_modules/@types/require-from-string": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha512-mIDK7lTHc0uW67SxPIqkwCrxmdKBV5aAET560hyZnT8c6Ekp9Aah3GPqe8Pl1Yzn/i2NMYmYv+HiMLwjGDCIAQ==", - "dev": true - }, "node_modules/@types/vscode": { "version": "1.57.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.57.0.tgz", @@ -1309,14 +1301,6 @@ "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -1887,12 +1871,6 @@ "integrity": "sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==", "dev": true }, - "@types/require-from-string": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha512-mIDK7lTHc0uW67SxPIqkwCrxmdKBV5aAET560hyZnT8c6Ekp9Aah3GPqe8Pl1Yzn/i2NMYmYv+HiMLwjGDCIAQ==", - "dev": true - }, "@types/vscode": { "version": "1.57.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.57.0.tgz", @@ -2808,11 +2786,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" - }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", diff --git a/package.json b/package.json index 488a488..c8c488b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,6 @@ "onCommand:leetcode.toggleLeetCodeCn", "onCommand:leetcode.signin", "onCommand:leetcode.signout", - "onCommand:leetcode.manageSessions", "onCommand:leetcode.refreshExplorer", "onCommand:leetcode.pickOne", "onCommand:leetcode.deleteAllCache", @@ -67,11 +66,6 @@ "title": "Sign Out", "category": "LeetCode" }, - { - "command": "leetcode.manageSessions", - "title": "Manage Sessions", - "category": "LeetCode" - }, { "command": "leetcode.refreshExplorer", "title": "Refresh", @@ -773,7 +767,6 @@ "@types/lodash": "^4.14.170", "@types/markdown-it": "0.0.7", "@types/node": "^14.14.33", - "@types/require-from-string": "^1.2.0", "@types/vscode": "1.57.0", "tslint": "^5.20.1", "typescript": "^4.3.2", @@ -784,7 +777,6 @@ "highlight.js": "^10.7.2", "lodash": "^4.17.21", "markdown-it": "12.3.2", - "require-from-string": "^2.0.2", "unescape-js": "^1.1.4", "ansi-styles": "3.2.1", "cheerio": "1.0.0-rc.12", diff --git a/src/commands/list.ts b/src/commands/list.ts index 2ba5c36..f0e3a25 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -21,12 +21,8 @@ export async function listProblems(): Promise { const result: string = await leetCodeExecutor.listProblems(showLocked, useEndpointTranslation); const all_problem_info = JSON.parse(result); const problems: IProblem[] = []; - // const lines: string[] = result.split("\n"); - // const reg: RegExp = /^(.)\s(.{1,2})\s(.)\s\[\s*(\d*)\s*\]\s*(.*)\s*(Easy|Medium|Hard)\s*\((\s*\d+\.\d+ %)\)/; - // const { companies, tags } = await leetCodeExecutor.getCompaniesAndTags(); const AllScoreData = leetCodeTreeDataProvider.getScoreData(); for (const p of all_problem_info) { - // console.log(p) problems.push({ id: p.fid, qid: p.id, diff --git a/src/commands/session.ts b/src/commands/session.ts index 2b26f26..e69de29 100644 --- a/src/commands/session.ts +++ b/src/commands/session.ts @@ -1,156 +0,0 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. - -// import * as vscode from "vscode"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { leetCodeManager } from "../leetCodeManager"; -// import { IQuickItemEx } from "../shared"; -// import { DialogOptions, DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; -import { promptForSignIn } from "../utils/uiUtils"; - -export async function getSessionList(): Promise { - const signInStatus: string | undefined = leetCodeManager.getUser(); - if (!signInStatus) { - promptForSignIn(); - return []; - } - const result: string = await leetCodeExecutor.listSessions(); - const lines: string[] = result.split("\n"); - const sessions: ISession[] = []; - const reg: RegExp = /(.?)\s*(\d+)\s+(.*)\s+(\d+ \(\s*\d+\.\d+ %\))\s+(\d+ \(\s*\d+\.\d+ %\))/; - for (const line of lines) { - const match: RegExpMatchArray | null = line.match(reg); - if (match && match.length === 6) { - sessions.push({ - active: !!(match[1].trim()), - id: match[2].trim(), - name: match[3].trim(), - acQuestions: match[4].trim(), - acSubmits: match[5].trim(), - }); - } - } - return sessions; -} - -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 === ":createSession") { - // await createSession(); - // return; - // } - // if (choice.value === ":deleteSession") { - // await deleteSession(); - // return; - // } - // try { - // 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) { - // await promptForOpenOutputChannel("Failed to switch session. Please open the output channel for details.", DialogType.error); - // } -} - -// 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({}, { -// label: `${s.active ? "$(check) " : ""}${s.name}`, -// description: s.active ? "Active" : "", -// detail: `AC Questions: ${s.acQuestions}, AC Submits: ${s.acSubmits}`, -// value: s, -// })); - -// 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); -// } -// }); -// } - -// 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", -// }); -// if (!session) { -// return; -// } -// try { -// await leetCodeExecutor.createSession(session); -// vscode.window.showInformationMessage("New session created, you can switch to it by clicking the status bar."); -// } catch (error) { -// await promptForOpenOutputChannel("Failed to create session. Please open the output channel for details.", DialogType.error); -// } -// } - -// 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; - name: string; - acQuestions: string; - acSubmits: string; -} diff --git a/src/commands/show.ts b/src/commands/show.ts index 5e127d8..70deaf9 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -7,7 +7,7 @@ import * as unescapeJS from "unescape-js"; import * as vscode from "vscode"; import { explorerNodeManager } from "../explorer/explorerNodeManager"; import { LeetCodeNode } from "../explorer/LeetCodeNode"; -import { leetCodeChannel } from "../leetCodeChannel"; +import { logOutput } from "../utils/logOutput"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IProblem, IQuickItemEx, languages, ProblemState, SearchNode, SearchSetType, userContestRankingObj, userContestRanKingBase } from "../shared"; @@ -227,7 +227,7 @@ export async function testapi(): Promise { const query_result = JSON.parse(solution); console.log(query_result); } catch (error) { - leetCodeChannel.appendLine(error.toString()); + logOutput.appendLine(error.toString()); await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error); } } @@ -245,7 +245,7 @@ export async function searchUserContest(): Promise { await leetCodeManager.insertCurrentUserContestInfo(tt); leetCodeManager.emit("searchUserContest") } catch (error) { - leetCodeChannel.appendLine(error.toString()); + logOutput.appendLine(error.toString()); await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error); } } @@ -273,7 +273,7 @@ export async function searchToday(): Promise { } } catch (error) { - leetCodeChannel.appendLine(error.toString()); + logOutput.appendLine(error.toString()); await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error); } } @@ -310,7 +310,7 @@ export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { if (finalPath) { finalPath = await resolveRelativePath(finalPath, node, language); if (!finalPath) { - leetCodeChannel.appendLine("Showing problem canceled by user."); + logOutput.appendLine("Showing problem canceled by user."); return; } } @@ -465,7 +465,7 @@ async function resolveRelativePath(relativePath: string, node: IProblem, selecte return company; default: const errorMsg: string = `The config '${placeholder}' is not supported.`; - leetCodeChannel.appendLine(errorMsg); + logOutput.appendLine(errorMsg); throw new Error(errorMsg); } }); diff --git a/src/explorer/LeetCodeTreeItemDecorationProvider.ts b/src/explorer/LeetCodeTreeItemDecorationProvider.ts index 90fed1e..2bd92dc 100644 --- a/src/explorer/LeetCodeTreeItemDecorationProvider.ts +++ b/src/explorer/LeetCodeTreeItemDecorationProvider.ts @@ -2,12 +2,6 @@ import { URLSearchParams } from "url"; import { FileDecoration, FileDecorationProvider, ProviderResult, ThemeColor, Uri, workspace, WorkspaceConfiguration } from "vscode"; export class LeetCodeTreeItemDecorationProvider implements FileDecorationProvider { - // private readonly DIFFICULTY_BADGE_LABEL: { [key: string]: string } = { - // easy: "E", - // medium: "M", - // hard: "H", - // }; - private readonly ITEM_COLOR: { [key: string]: ThemeColor } = { easy: new ThemeColor("charts.green"), medium: new ThemeColor("charts.yellow"), diff --git a/src/extension.ts b/src/extension.ts index 829a168..4897a27 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -6,7 +6,6 @@ import { codeLensController } from "./codelens/CodeLensController"; import * as cache from "./commands/cache"; import { switchDefaultLanguage } from "./commands/language"; import * as plugin from "./commands/plugin"; -import * as session from "./commands/session"; import * as show from "./commands/show"; import * as star from "./commands/star"; import * as submit from "./commands/submit"; @@ -15,7 +14,7 @@ import { explorerNodeManager } from "./explorer/explorerNodeManager"; import { LeetCodeNode } from "./explorer/LeetCodeNode"; import { leetCodeTreeDataProvider } from "./explorer/LeetCodeTreeDataProvider"; import { leetCodeTreeItemDecorationProvider } from "./explorer/LeetCodeTreeItemDecorationProvider"; -import { leetCodeChannel } from "./leetCodeChannel"; +import { logOutput } from "./utils/logOutput"; import { leetCodeExecutor } from "./leetCodeExecutor"; import { leetCodeManager } from "./leetCodeManager"; import { leetCodeStatusBarController } from "./statusbar/leetCodeStatusBarController"; @@ -32,12 +31,10 @@ export async function activate(context: vscode.ExtensionContext): Promise try { if (!wsl.useVscodeNode()) { - if (!await leetCodeExecutor.meetRequirements(context)) { + if (!await leetCodeExecutor.checkNodeEnv(context)) { throw new Error("The environment doesn't meet requirements."); } } - - leetCodeManager.on("statusChanged", () => { leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser()); leetCodeTreeDataProvider.cleanUserScore(); @@ -55,7 +52,7 @@ export async function activate(context: vscode.ExtensionContext): Promise context.subscriptions.push( leetCodeStatusBarController, - leetCodeChannel, + logOutput, leetCodePreviewProvider, leetCodeSubmissionProvider, leetCodeSolutionProvider, @@ -69,7 +66,6 @@ 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.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.pickOne", () => show.pickOne()), @@ -90,7 +86,7 @@ export async function activate(context: vscode.ExtensionContext): Promise await leetCodeExecutor.switchEndpoint(plugin.getLeetCodeEndpoint()); await leetCodeManager.getLoginStatus(); } catch (error) { - leetCodeChannel.appendLine(error.toString()); + logOutput.appendLine(error.toString()); promptForOpenOutputChannel("Extension initialization failed. Please open output channel for details.", DialogType.error); } } diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index f16b200..b60dc32 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -5,7 +5,6 @@ import * as cp from "child_process"; import * as fse from "fs-extra"; import * as os from "os"; import * as path from "path"; -import * as requireFromString from "require-from-string"; import { ExtensionContext } from "vscode"; import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace, WorkspaceConfiguration } from "vscode"; import { Endpoint, IProblem, leetcodeHasInited } from "./shared"; @@ -45,7 +44,7 @@ class LeetCodeExecutor implements Disposable { } } - public async meetRequirements(context: ExtensionContext): Promise { + public async checkNodeEnv(context: ExtensionContext): Promise { const hasInited: boolean | undefined = context.globalState.get(leetcodeHasInited); if (!hasInited) { await this.removeOldCache(); @@ -183,21 +182,6 @@ class LeetCodeExecutor implements Disposable { return await this.executeCommandWithProgressEx("Fetching problem description...", this.nodeExecutable, cmd); } - public async listSessions(): Promise { - return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session"]); - } - - public async enableSession(name: string): Promise { - return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "session", "-e", 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 { try { @@ -249,17 +233,7 @@ class LeetCodeExecutor implements Disposable { } await this.executeCommandWithProgressEx("Updating the favorite list...", "node", commandParams); } - // 读取tag 编号看着只有钱1148才有 - public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }, tags: { [key: string]: string[] } }> { - // preprocess the plugin source - const companiesTagsPath: string = path.join(this.leetCodeCliRootPath, "lib", "plugins", "company.js"); - const companiesTagsSrc: string = (await fse.readFile(companiesTagsPath, "utf8")).replace( - "module.exports = plugin", - "module.exports = { COMPONIES, TAGS }", - ); - const { COMPONIES, TAGS } = requireFromString(companiesTagsSrc, companiesTagsPath); - return { companies: COMPONIES, tags: TAGS }; - } + public get node(): string { return this.nodeExecutable; diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 2dc42bd..8b05e31 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -4,7 +4,7 @@ import * as cp from "child_process"; import { EventEmitter } from "events"; import * as vscode from "vscode"; -import { leetCodeChannel } from "./leetCodeChannel"; +import { logOutput } from "./utils/logOutput"; import { leetCodeExecutor } from "./leetCodeExecutor"; import { IQuickItemEx, loginArgsMapping, UserStatus, userContestRanKingBase, userContestRankingObj } from "./shared"; import { createEnvOption } from "./utils/cpUtils"; @@ -107,7 +107,7 @@ class LeetCodeManager extends EventEmitter { childProc.stdout?.on("data", async (data: string | Buffer) => { data = data.toString(); // vscode.window.showInformationMessage(`cc login msg ${data}.`); - leetCodeChannel.append(data); + logOutput.append(data); if (data.includes("twoFactorCode")) { const twoFactor: string | undefined = await vscode.window.showInputBox({ prompt: "Enter two-factor code.", @@ -136,7 +136,7 @@ class LeetCodeManager extends EventEmitter { } }); - childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString())); + childProc.stderr?.on("data", (data: string | Buffer) => logOutput.append(data.toString())); childProc.on("error", reject); const name: string | undefined = await vscode.window.showInputBox({ diff --git a/src/statusbar/LeetCodeStatusBarItem.ts b/src/statusbar/LeetCodeStatusBarItem.ts index e863f1c..d6532e5 100644 --- a/src/statusbar/LeetCodeStatusBarItem.ts +++ b/src/statusbar/LeetCodeStatusBarItem.ts @@ -9,7 +9,6 @@ export class LeetCodeStatusBarItem implements vscode.Disposable { constructor() { this.statusBarItem = vscode.window.createStatusBarItem(); - this.statusBarItem.command = "leetcode.manageSessions"; } public updateStatusBar(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { diff --git a/src/utils/cpUtils.ts b/src/utils/cpUtils.ts index d3e9acc..ba2e43e 100644 --- a/src/utils/cpUtils.ts +++ b/src/utils/cpUtils.ts @@ -3,7 +3,7 @@ import * as cp from "child_process"; import * as vscode from "vscode"; -import { leetCodeChannel } from "../leetCodeChannel"; +import { logOutput } from "./logOutput"; import * as wsl from "../utils/wslUtils"; interface IExecError extends Error { @@ -32,10 +32,10 @@ export async function executeCommand(command: string, args: string[], options: c childProc.stdout?.on("data", (data: string | Buffer) => { data = data.toString(); result = result.concat(data); - leetCodeChannel.append(data); + logOutput.append(data); }); - childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString())); + childProc.stderr?.on("data", (data: string | Buffer) => logOutput.append(data.toString())); childProc.on("error", reject); diff --git a/src/leetCodeChannel.ts b/src/utils/logOutput.ts similarity index 63% rename from src/leetCodeChannel.ts rename to src/utils/logOutput.ts index fa32ac2..e0abfce 100644 --- a/src/leetCodeChannel.ts +++ b/src/utils/logOutput.ts @@ -1,10 +1,7 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. - import * as vscode from "vscode"; -class LeetCodeChannel implements vscode.Disposable { - private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("LeetCode"); +class LogOutput implements vscode.Disposable { + private readonly channel: vscode.OutputChannel = vscode.window.createOutputChannel("LeetCodeProblemRating"); public appendLine(message: string): void { this.channel.appendLine(message); @@ -23,4 +20,4 @@ class LeetCodeChannel implements vscode.Disposable { } } -export const leetCodeChannel: LeetCodeChannel = new LeetCodeChannel(); +export const logOutput: LogOutput = new LogOutput(); diff --git a/src/utils/uiUtils.ts b/src/utils/uiUtils.ts index 9e251a5..082ec8b 100644 --- a/src/utils/uiUtils.ts +++ b/src/utils/uiUtils.ts @@ -3,7 +3,7 @@ import * as vscode from "vscode"; import { getLeetCodeEndpoint } from "../commands/plugin"; -import { leetCodeChannel } from "../leetCodeChannel"; +import { logOutput } from "./logOutput"; import { getWorkspaceConfiguration } from "./settingUtils"; export namespace DialogOptions { @@ -31,7 +31,7 @@ export async function promptForOpenOutputChannel(message: string, type: DialogTy } if (result === DialogOptions.open) { - leetCodeChannel.show(); + logOutput.show(); } } diff --git a/src/webview/markdownEngine.ts b/src/webview/markdownEngine.ts index 4c1db65..14c070b 100644 --- a/src/webview/markdownEngine.ts +++ b/src/webview/markdownEngine.ts @@ -6,7 +6,7 @@ import * as MarkdownIt from "markdown-it"; import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; -import { leetCodeChannel } from "../leetCodeChannel"; +import { logOutput } from "../utils/logOutput"; import { isWindows } from "../utils/osUtils"; class MarkdownEngine implements vscode.Disposable { @@ -54,7 +54,7 @@ class MarkdownEngine implements vscode.Disposable { const stylePaths: string[] = require(path.join(this.config.extRoot, "package.json"))["contributes"]["markdown.previewStyles"]; styles = stylePaths.map((p: string) => vscode.Uri.file(path.join(this.config.extRoot, p)).with({ scheme: "vscode-resource" })); } catch (error) { - leetCodeChannel.appendLine("[Error] Fail to load built-in markdown style file."); + logOutput.appendLine("[Error] Fail to load built-in markdown style file."); } return styles.map((style: vscode.Uri) => ``).join(os.EOL); } From 243a47b566dd4b1f3604e64e5d82213095b0843f Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 11:13:53 +0800 Subject: [PATCH 02/31] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F=20=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/codelens/CustomCodeLensProvider.ts | 2 +- src/commands/list.ts | 4 +- src/commands/show.ts | 16 +++--- src/commands/star.ts | 6 +- src/explorer/explorerNodeManager.ts | 6 +- src/extension.ts | 8 +-- src/leetCodeExecutor.ts | 2 +- src/leetCodeManager.ts | 2 +- src/statusbar/StatusBar.ts | 53 ++++++++++++++++++ ...tCodeStatusBarItem.ts => StatusBarItem.ts} | 14 +++-- src/statusbar/leetCodeStatusBarController.ts | 46 --------------- src/utils/{cpUtils.ts => cliUtils.ts} | 32 ++++------- src/utils/{settingUtils.ts => configUtils.ts} | 56 ++++++++++++------- src/utils/uiUtils.ts | 6 +- src/utils/workspaceUtils.ts | 4 +- src/utils/wslUtils.ts | 2 +- 16 files changed, 139 insertions(+), 120 deletions(-) create mode 100644 src/statusbar/StatusBar.ts rename src/statusbar/{LeetCodeStatusBarItem.ts => StatusBarItem.ts} (73%) delete mode 100644 src/statusbar/leetCodeStatusBarController.ts rename src/utils/{cpUtils.ts => cliUtils.ts} (80%) rename src/utils/{settingUtils.ts => configUtils.ts} (58%) diff --git a/src/codelens/CustomCodeLensProvider.ts b/src/codelens/CustomCodeLensProvider.ts index 3322ed2..6b90d09 100644 --- a/src/codelens/CustomCodeLensProvider.ts +++ b/src/codelens/CustomCodeLensProvider.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; import { explorerNodeManager } from "../explorer/explorerNodeManager"; import { LeetCodeNode } from "../explorer/LeetCodeNode"; -import { getEditorShortcuts } from "../utils/settingUtils"; +import { getEditorShortcuts } from "../utils/configUtils"; export class CustomCodeLensProvider implements vscode.CodeLensProvider { diff --git a/src/commands/list.ts b/src/commands/list.ts index f0e3a25..c628235 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IProblem, ProblemState, RootNodeSort, UserStatus } from "../shared"; -import * as settingUtils from "../utils/settingUtils"; +import * as settingUtils from "../utils/configUtils"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { resourcesData } from "../ResourcesData"; @@ -17,7 +17,7 @@ export async function listProblems(): Promise { } const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating"); const showLocked: boolean = !!leetCodeConfig.get("showLocked"); - const useEndpointTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const useEndpointTranslation: boolean = settingUtils.isUseEndpointTranslation(); const result: string = await leetCodeExecutor.listProblems(showLocked, useEndpointTranslation); const all_problem_info = JSON.parse(result); const problems: IProblem[] = []; diff --git a/src/commands/show.ts b/src/commands/show.ts index 70deaf9..7909eae 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -13,14 +13,14 @@ import { leetCodeManager } from "../leetCodeManager"; import { IProblem, IQuickItemEx, languages, ProblemState, SearchNode, SearchSetType, userContestRankingObj, userContestRanKingBase } from "../shared"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils"; -import * as settingUtils from "../utils/settingUtils"; -import { IDescriptionConfiguration } from "../utils/settingUtils"; +import * as settingUtils from "../utils/configUtils"; +import { IDescriptionConfiguration } from "../utils/configUtils"; import { DialogOptions, DialogType, openSettingsEditor, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/uiUtils"; import { getActiveFilePath, selectWorkspaceFolder } from "../utils/workspaceUtils"; import * as wsl from "../utils/wslUtils"; import { leetCodePreviewProvider } from "../webview/leetCodePreviewProvider"; import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider"; -import { getPickOneByRankRangeMin, getPickOneByRankRangeMax } from "../utils/settingUtils"; +import { getPickOneByRankRangeMin, getPickOneByRankRangeMax } from "../utils/configUtils"; import * as list from "./list"; import { getLeetCodeEndpoint } from "./plugin"; @@ -44,7 +44,7 @@ export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: b } else { node = input; } - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); const descString: string = await leetCodeExecutor.getDescription(node.qid, needTranslation); leetCodePreviewProvider.show(descString, node, isSideMode); } @@ -238,7 +238,7 @@ export async function searchUserContest(): Promise { return; } try { - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); const solution: string = await leetCodeExecutor.getUserContest(needTranslation, leetCodeManager.getUser() || ""); const query_result = JSON.parse(solution); const tt: userContestRanKingBase = Object.assign({}, userContestRankingObj, query_result.userContestRanking) @@ -255,7 +255,7 @@ export async function searchToday(): Promise { return; } try { - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); const solution: string = await leetCodeExecutor.getTodayQuestion(needTranslation); const query_result = JSON.parse(solution); // const titleSlug: string = query_result.titleSlug @@ -306,7 +306,7 @@ export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath; const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration(); - const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation(); + const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); const promises: any[] = [ diff --git a/src/commands/star.ts b/src/commands/star.ts index 3661149..705affc 100644 --- a/src/commands/star.ts +++ b/src/commands/star.ts @@ -6,14 +6,14 @@ import { customCodeLensProvider } from "../codelens/CustomCodeLensProvider"; import { LeetCodeNode } from "../explorer/LeetCodeNode"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { leetCodeExecutor } from "../leetCodeExecutor"; -import { hasStarShortcut } from "../utils/settingUtils"; +import { isStarShortcut } from "../utils/configUtils"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; export async function addFavorite(node: LeetCodeNode): Promise { try { await leetCodeExecutor.toggleFavorite(node, true); await leetCodeTreeDataProvider.refresh(); - if (hasStarShortcut()) { + if (isStarShortcut()) { customCodeLensProvider.refresh(); } } catch (error) { @@ -25,7 +25,7 @@ export async function removeFavorite(node: LeetCodeNode): Promise { try { await leetCodeExecutor.toggleFavorite(node, false); await leetCodeTreeDataProvider.refresh(); - if (hasStarShortcut()) { + if (isStarShortcut()) { customCodeLensProvider.refresh(); } } catch (error) { diff --git a/src/explorer/explorerNodeManager.ts b/src/explorer/explorerNodeManager.ts index 0b5e0e1..839a8de 100644 --- a/src/explorer/explorerNodeManager.ts +++ b/src/explorer/explorerNodeManager.ts @@ -7,7 +7,7 @@ import { Disposable } from "vscode"; import * as list from "../commands/list"; import { getSortingStrategy } from "../commands/plugin"; import { Category, defaultProblem, ProblemState, SortingStrategy, SearchSetTypeName, RootNodeSort, SearchSetType, ISubmitEvent } from "../shared"; -import { shouldHideSolvedProblem, shouldHideScoreProblem } from "../utils/settingUtils"; +import { isHideSolvedProblem, isHideScoreProblem } from "../utils/configUtils"; import { LeetCodeNode } from "./LeetCodeNode"; import { ISearchSet } from "../shared"; import { searchToday, searchUserContest } from "../commands/show"; @@ -200,10 +200,10 @@ class ExplorerNodeManager implements Disposable { } public canShow(element: LeetCodeNode) { - if (shouldHideSolvedProblem() && element.state === ProblemState.AC) { + if (isHideSolvedProblem() && element.state === ProblemState.AC) { return false; } - if (shouldHideScoreProblem(element, element.user_score)) { + if (isHideScoreProblem(element, element.user_score)) { return false; } return true; diff --git a/src/extension.ts b/src/extension.ts index 4897a27..d5e1673 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -17,7 +17,7 @@ import { leetCodeTreeItemDecorationProvider } from "./explorer/LeetCodeTreeItemD import { logOutput } from "./utils/logOutput"; import { leetCodeExecutor } from "./leetCodeExecutor"; import { leetCodeManager } from "./leetCodeManager"; -import { leetCodeStatusBarController } from "./statusbar/leetCodeStatusBarController"; +import { statusBar } from "./statusbar/StatusBar"; import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; import { leetCodePreviewProvider } from "./webview/leetCodePreviewProvider"; import { leetCodeSolutionProvider } from "./webview/leetCodeSolutionProvider"; @@ -36,7 +36,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } } leetCodeManager.on("statusChanged", () => { - leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser()); + statusBar.update(leetCodeManager.getStatus(), leetCodeManager.getUser()); leetCodeTreeDataProvider.cleanUserScore(); leetCodeTreeDataProvider.refresh(); }); @@ -45,13 +45,13 @@ export async function activate(context: vscode.ExtensionContext): Promise }); leetCodeManager.on("searchUserContest", () => { - leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo()); + statusBar.update(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo()); }); leetCodeTreeDataProvider.initialize(context); context.subscriptions.push( - leetCodeStatusBarController, + statusBar, logOutput, leetCodePreviewProvider, leetCodeSubmissionProvider, diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index b60dc32..d1b5604 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -8,7 +8,7 @@ import * as path from "path"; import { ExtensionContext } from "vscode"; import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace, WorkspaceConfiguration } from "vscode"; import { Endpoint, IProblem, leetcodeHasInited } from "./shared"; -import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils"; +import { executeCommand, executeCommandWithProgress } from "./utils/cliUtils"; import { DialogOptions, openUrl } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; import { toWslPath, useWsl } from "./utils/wslUtils"; diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts index 8b05e31..689cfd0 100644 --- a/src/leetCodeManager.ts +++ b/src/leetCodeManager.ts @@ -7,7 +7,7 @@ import * as vscode from "vscode"; import { logOutput } from "./utils/logOutput"; import { leetCodeExecutor } from "./leetCodeExecutor"; import { IQuickItemEx, loginArgsMapping, UserStatus, userContestRanKingBase, userContestRankingObj } from "./shared"; -import { createEnvOption } from "./utils/cpUtils"; +import { createEnvOption } from "./utils/cliUtils"; import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; import * as wsl from "./utils/wslUtils"; import { explorerNodeManager } from "./explorer/explorerNodeManager"; diff --git a/src/statusbar/StatusBar.ts b/src/statusbar/StatusBar.ts new file mode 100644 index 0000000..9dcd026 --- /dev/null +++ b/src/statusbar/StatusBar.ts @@ -0,0 +1,53 @@ +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/statusbar/StatusBar.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + +import { ConfigurationChangeEvent, Disposable, workspace, WorkspaceConfiguration } from "vscode"; +import { UserStatus, userContestRanKingBase } from "../shared"; +import { StatusBarItem } from "./StatusBarItem"; +import { isStatusBar } from "../utils/configUtils"; + +// 状态栏工具 +class StatusBar implements Disposable { + private instance: StatusBarItem; + private configurationChangeListener: Disposable; + + constructor() { + this.instance = new StatusBarItem(); + this.setStatusBarVisibility(); + + this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { + if (event.affectsConfiguration("leetcode-problem-rating.enableStatusBar")) { + this.setStatusBarVisibility(); + } + }, this); + } + + // 更新数据 + public update(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { + this.instance.update(status, user, UserContestInfo); + } + + //销毁数据 + public dispose(): void { + this.instance.dispose(); + this.configurationChangeListener.dispose(); + } + + // 设置可见性 + private setStatusBarVisibility(): void { + if (isStatusBar()) { + this.instance.show(); + } else { + this.instance.hide(); + } + } + +} + +export const statusBar: StatusBar = new StatusBar(); diff --git a/src/statusbar/LeetCodeStatusBarItem.ts b/src/statusbar/StatusBarItem.ts similarity index 73% rename from src/statusbar/LeetCodeStatusBarItem.ts rename to src/statusbar/StatusBarItem.ts index d6532e5..faff7d3 100644 --- a/src/statusbar/LeetCodeStatusBarItem.ts +++ b/src/statusbar/StatusBarItem.ts @@ -1,17 +1,23 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/statusbar/StatusBarItem.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ import * as vscode from "vscode"; import { UserStatus, userContestRanKingBase } from "../shared"; -export class LeetCodeStatusBarItem implements vscode.Disposable { +export class StatusBarItem implements vscode.Disposable { private readonly statusBarItem: vscode.StatusBarItem; constructor() { this.statusBarItem = vscode.window.createStatusBarItem(); } - public updateStatusBar(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { + public update(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { switch (status) { case UserStatus.SignedIn: if (UserContestInfo && UserContestInfo.attendedContestsCount > 0) { diff --git a/src/statusbar/leetCodeStatusBarController.ts b/src/statusbar/leetCodeStatusBarController.ts deleted file mode 100644 index 2a43c32..0000000 --- a/src/statusbar/leetCodeStatusBarController.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. - -import { ConfigurationChangeEvent, Disposable, workspace, WorkspaceConfiguration } from "vscode"; -import { UserStatus, userContestRanKingBase } from "../shared"; -import { LeetCodeStatusBarItem } from "./LeetCodeStatusBarItem"; - -class LeetCodeStatusBarController implements Disposable { - private statusBar: LeetCodeStatusBarItem; - private configurationChangeListener: Disposable; - - constructor() { - this.statusBar = new LeetCodeStatusBarItem(); - this.setStatusBarVisibility(); - - this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { - if (event.affectsConfiguration("leetcode.enableStatusBar")) { - this.setStatusBarVisibility(); - } - }, this); - } - - public updateStatusBar(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { - this.statusBar.updateStatusBar(status, user, UserContestInfo); - } - - public dispose(): void { - this.statusBar.dispose(); - this.configurationChangeListener.dispose(); - } - - private setStatusBarVisibility(): void { - if (this.isStatusBarEnabled()) { - this.statusBar.show(); - } else { - this.statusBar.hide(); - } - } - - private isStatusBarEnabled(): boolean { - const configuration: WorkspaceConfiguration = workspace.getConfiguration("leetcode-problem-rating"); - return configuration.get("enableStatusBar", true); - } -} - -export const leetCodeStatusBarController: LeetCodeStatusBarController = new LeetCodeStatusBarController(); diff --git a/src/utils/cpUtils.ts b/src/utils/cliUtils.ts similarity index 80% rename from src/utils/cpUtils.ts rename to src/utils/cliUtils.ts index ba2e43e..1f6f58e 100644 --- a/src/utils/cpUtils.ts +++ b/src/utils/cliUtils.ts @@ -1,10 +1,17 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/utils/cliUtils.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Monday, October 31st 2022, 10:16:47 am + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import * as cp from "child_process"; import * as vscode from "vscode"; import { logOutput } from "./logOutput"; -import * as wsl from "../utils/wslUtils"; +import * as wsl from "./wslUtils"; interface IExecError extends Error { result?: string; @@ -57,25 +64,6 @@ export async function executeCommand(command: string, args: string[], options: c resolve(result); } }); - - // childProc.on("exit", function (code) { - // console.log("disconnect", code) - // if (code !== 0) { - // console.log('child exit code (spawn)', code); - // return reject(new Error(`Command "${command} ${args.toString()}" failed with exit code "${code}".`)) - // } - // resolve(result); - // }); - - // childProc.on("disconnect", function () { - // console.log("disconnect") - // resolve(result); - // }); - // childProc.on("message", function (message) { - // console.log("message", message) - // resolve(result); - // }); - }); } diff --git a/src/utils/settingUtils.ts b/src/utils/configUtils.ts similarity index 58% rename from src/utils/settingUtils.ts rename to src/utils/configUtils.ts index 01673e8..bbc48a4 100644 --- a/src/utils/settingUtils.ts +++ b/src/utils/configUtils.ts @@ -1,24 +1,33 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/utils/configUtils.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import { workspace, WorkspaceConfiguration } from "vscode"; import { DescriptionConfiguration, IProblem } from "../shared"; -export function getWorkspaceConfiguration(): WorkspaceConfiguration { +// vscode的配置 +export function getVsCodeConfig(): WorkspaceConfiguration { return workspace.getConfiguration("leetcode-problem-rating"); } -export function shouldHideSolvedProblem(): boolean { - return getWorkspaceConfiguration().get("hideSolved", false); +// 隐藏解决题目 +export function isHideSolvedProblem(): boolean { + return getVsCodeConfig().get("hideSolved", false); } - -export function shouldHideScoreProblem(problem: IProblem, user_score: number): boolean { +// 隐藏分数 +export function isHideScoreProblem(problem: IProblem, user_score: number): boolean { // "None", // "Score", // "NoScore", // "ScoreRange" - const config_value: string = getWorkspaceConfiguration().get("hideScore", "None"); + const config_value: string = getVsCodeConfig().get("hideScore", "None"); switch (config_value) { case "Score": if ((problem?.scoreData?.Rating || 0) > 0) { @@ -48,32 +57,41 @@ export function shouldHideScoreProblem(problem: IProblem, user_score: number): b return false; } +// 随机题目最小分数 export function getPickOneByRankRangeMin(): number { - return getWorkspaceConfiguration().get("pickOneByRankRangeMin") || 50; + return getVsCodeConfig().get("pickOneByRankRangeMin") || 50; } +// 随机题目最大分数 export function getPickOneByRankRangeMax(): number { - return getWorkspaceConfiguration().get("pickOneByRankRangeMax") || 150; + return getVsCodeConfig().get("pickOneByRankRangeMax") || 150; } - +// 工作目录 export function getWorkspaceFolder(): string { - return getWorkspaceConfiguration().get("workspaceFolder", ""); + return getVsCodeConfig().get("workspaceFolder", ""); } +// 快捷操作 export function getEditorShortcuts(): string[] { - return getWorkspaceConfiguration().get("editor.shortcuts", ["submit", "case", "allcase", "test", "solution"]); + return getVsCodeConfig().get("editor.shortcuts", ["submit", "case", "allcase", "test", "solution"]); } -export function hasStarShortcut(): boolean { - const shortcuts: string[] = getWorkspaceConfiguration().get("editor.shortcuts", ["submit", "case", "allcase", "test", "solution"]); +export function isStarShortcut(): boolean { + const shortcuts: string[] = getVsCodeConfig().get("editor.shortcuts", ["submit", "case", "allcase", "test", "solution"]); return shortcuts.indexOf("star") >= 0; } -export function shouldUseEndpointTranslation(): boolean { - return getWorkspaceConfiguration().get("useEndpointTranslation", true); +export function isUseEndpointTranslation(): boolean { + return getVsCodeConfig().get("useEndpointTranslation", true); +} + +// 状态栏状态设置 +export function isStatusBar(): boolean { + return getVsCodeConfig().get("enableStatusBar", true); } +// 展示方式 export function getDescriptionConfiguration(): IDescriptionConfiguration { - const setting: string = getWorkspaceConfiguration().get("showDescription", DescriptionConfiguration.InWebView); + const setting: string = getVsCodeConfig().get("showDescription", DescriptionConfiguration.InWebView); const config: IDescriptionConfiguration = { showInComment: false, showInWebview: true, @@ -98,7 +116,7 @@ export function getDescriptionConfiguration(): IDescriptionConfiguration { } // To be compatible with the deprecated setting: - if (getWorkspaceConfiguration().get("showCommentDescription")) { + if (getVsCodeConfig().get("showCommentDescription")) { config.showInComment = true; } diff --git a/src/utils/uiUtils.ts b/src/utils/uiUtils.ts index 082ec8b..b495b28 100644 --- a/src/utils/uiUtils.ts +++ b/src/utils/uiUtils.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; import { getLeetCodeEndpoint } from "../commands/plugin"; import { logOutput } from "./logOutput"; -import { getWorkspaceConfiguration } from "./settingUtils"; +import { getVsCodeConfig } from "./configUtils"; export namespace DialogOptions { export const open: vscode.MessageItem = { title: "Open" }; @@ -59,7 +59,7 @@ export async function promptForSignIn(): Promise { } export async function promptHintMessage(config: string, message: string, choiceConfirm: string, onConfirm: () => Promise): Promise { - if (getWorkspaceConfiguration().get(config)) { + if (getVsCodeConfig().get(config)) { const choiceNoShowAgain: string = "Don't show again"; const choice: string | undefined = await vscode.window.showInformationMessage( message, choiceConfirm, choiceNoShowAgain, @@ -67,7 +67,7 @@ export async function promptHintMessage(config: string, message: string, choiceC if (choice === choiceConfirm) { await onConfirm(); } else if (choice === choiceNoShowAgain) { - await getWorkspaceConfiguration().update(config, false, true /* UserSetting */); + await getVsCodeConfig().update(config, false, true /* UserSetting */); } } } diff --git a/src/utils/workspaceUtils.ts b/src/utils/workspaceUtils.ts index 48105d5..f50d0a2 100644 --- a/src/utils/workspaceUtils.ts +++ b/src/utils/workspaceUtils.ts @@ -6,7 +6,7 @@ import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; import { IQuickItemEx } from "../shared"; -import { getWorkspaceConfiguration, getWorkspaceFolder } from "./settingUtils"; +import { getVsCodeConfig, getWorkspaceFolder } from "./configUtils"; import { showDirectorySelectDialog } from "./uiUtils"; import * as wsl from "./wslUtils"; @@ -116,7 +116,7 @@ async function determineLeetCodeFolder(): Promise { result = choice.value; } - getWorkspaceConfiguration().update("workspaceFolder", result, vscode.ConfigurationTarget.Global); + getVsCodeConfig().update("workspaceFolder", result, vscode.ConfigurationTarget.Global); return result; } diff --git a/src/utils/wslUtils.ts b/src/utils/wslUtils.ts index a785c70..1b8b7ec 100644 --- a/src/utils/wslUtils.ts +++ b/src/utils/wslUtils.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { executeCommand } from "./cpUtils"; +import { executeCommand } from "./cliUtils"; import { isWindows } from "./osUtils"; // 用wsl命令的时候,好像没办法用vscode的node From 7bd6c1f3d1cdfc8f5d0c0e318a4fbfb986720e8e Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 11:15:23 +0800 Subject: [PATCH 03/31] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/statusbar/StatusBar.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/statusbar/StatusBar.ts b/src/statusbar/StatusBar.ts index 9dcd026..7f3c0cf 100644 --- a/src/statusbar/StatusBar.ts +++ b/src/statusbar/StatusBar.ts @@ -7,7 +7,7 @@ * Copyright (c) 2022 ccagml . All rights reserved. */ -import { ConfigurationChangeEvent, Disposable, workspace, WorkspaceConfiguration } from "vscode"; +import { ConfigurationChangeEvent, Disposable, workspace } from "vscode"; import { UserStatus, userContestRanKingBase } from "../shared"; import { StatusBarItem } from "./StatusBarItem"; import { isStatusBar } from "../utils/configUtils"; From 47bb888b48d375793948dffa9754c214eb4d1a4e Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 11:19:48 +0800 Subject: [PATCH 04/31] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/statusbar/StatusBar.ts | 24 ++++++++++++++--- src/statusbar/StatusBarItem.ts | 47 ---------------------------------- 2 files changed, 20 insertions(+), 51 deletions(-) delete mode 100644 src/statusbar/StatusBarItem.ts diff --git a/src/statusbar/StatusBar.ts b/src/statusbar/StatusBar.ts index 7f3c0cf..bfde05c 100644 --- a/src/statusbar/StatusBar.ts +++ b/src/statusbar/StatusBar.ts @@ -7,9 +7,8 @@ * Copyright (c) 2022 ccagml . All rights reserved. */ -import { ConfigurationChangeEvent, Disposable, workspace } from "vscode"; +import { ConfigurationChangeEvent, Disposable, workspace, StatusBarItem, window } from "vscode"; import { UserStatus, userContestRanKingBase } from "../shared"; -import { StatusBarItem } from "./StatusBarItem"; import { isStatusBar } from "../utils/configUtils"; // 状态栏工具 @@ -18,7 +17,7 @@ class StatusBar implements Disposable { private configurationChangeListener: Disposable; constructor() { - this.instance = new StatusBarItem(); + this.instance = window.createStatusBarItem(); this.setStatusBarVisibility(); this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { @@ -28,9 +27,26 @@ class StatusBar implements Disposable { }, this); } + public update_instance(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { + switch (status) { + case UserStatus.SignedIn: + if (UserContestInfo && UserContestInfo.attendedContestsCount > 0) { + this.instance.text = `用户: ${user}, 积分: ${Math.floor(UserContestInfo.rating)}, 名次: ${UserContestInfo.localRanking} / ${UserContestInfo.localTotalParticipants} (${UserContestInfo.topPercentage}%), 全部名次: ${UserContestInfo.globalRanking} / ${UserContestInfo.globalTotalParticipants}`; + } else { + this.instance.text = `user: ${user}`; + } + break; + case UserStatus.SignedOut: + default: + this.instance.text = ""; + break; + } + } + + // 更新数据 public update(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { - this.instance.update(status, user, UserContestInfo); + this.update_instance(status, user, UserContestInfo); } //销毁数据 diff --git a/src/statusbar/StatusBarItem.ts b/src/statusbar/StatusBarItem.ts deleted file mode 100644 index faff7d3..0000000 --- a/src/statusbar/StatusBarItem.ts +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Filename: /home/cc/vscode-leetcode-problem-rating/src/statusbar/StatusBarItem.ts - * Path: /home/cc/vscode-leetcode-problem-rating - * Created Date: Thursday, October 27th 2022, 7:43:29 pm - * Author: ccagml - * - * Copyright (c) 2022 ccagml . All rights reserved. - */ - -import * as vscode from "vscode"; -import { UserStatus, userContestRanKingBase } from "../shared"; - -export class StatusBarItem implements vscode.Disposable { - private readonly statusBarItem: vscode.StatusBarItem; - - constructor() { - this.statusBarItem = vscode.window.createStatusBarItem(); - } - - public update(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { - switch (status) { - case UserStatus.SignedIn: - if (UserContestInfo && UserContestInfo.attendedContestsCount > 0) { - this.statusBarItem.text = `用户: ${user}, 积分: ${Math.floor(UserContestInfo.rating)}, 名次: ${UserContestInfo.localRanking} / ${UserContestInfo.localTotalParticipants} (${UserContestInfo.topPercentage}%), 全部名次: ${UserContestInfo.globalRanking} / ${UserContestInfo.globalTotalParticipants}`; - } else { - this.statusBarItem.text = `user: ${user}`; - } - break; - case UserStatus.SignedOut: - default: - this.statusBarItem.text = ""; - break; - } - } - - public show(): void { - this.statusBarItem.show(); - } - - public hide(): void { - this.statusBarItem.hide(); - } - - public dispose(): void { - this.statusBarItem.dispose(); - } -} From 4084e0fe12834dfbf253853c44068d22c840099f Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 11:20:33 +0800 Subject: [PATCH 05/31] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E6=A0=8F=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/statusbar/StatusBar.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/statusbar/StatusBar.ts b/src/statusbar/StatusBar.ts index bfde05c..15eb25c 100644 --- a/src/statusbar/StatusBar.ts +++ b/src/statusbar/StatusBar.ts @@ -27,6 +27,7 @@ class StatusBar implements Disposable { }, this); } + // 更新状态栏的数据 public update_instance(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { switch (status) { case UserStatus.SignedIn: From e6462c22fe36318129576520dc842aa0262a9c65 Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 11:30:39 +0800 Subject: [PATCH 06/31] =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=A0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/extension.ts | 8 ++++---- .../StatusBar.ts => manager/StatusBarManager.ts} | 8 ++++---- src/utils/configUtils.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename src/{statusbar/StatusBar.ts => manager/StatusBarManager.ts} (91%) diff --git a/src/extension.ts b/src/extension.ts index d5e1673..0e3d4c1 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -17,7 +17,7 @@ import { leetCodeTreeItemDecorationProvider } from "./explorer/LeetCodeTreeItemD import { logOutput } from "./utils/logOutput"; import { leetCodeExecutor } from "./leetCodeExecutor"; import { leetCodeManager } from "./leetCodeManager"; -import { statusBar } from "./statusbar/StatusBar"; +import { statusBarManager } from "./manager/StatusBarManager"; import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; import { leetCodePreviewProvider } from "./webview/leetCodePreviewProvider"; import { leetCodeSolutionProvider } from "./webview/leetCodeSolutionProvider"; @@ -36,7 +36,7 @@ export async function activate(context: vscode.ExtensionContext): Promise } } leetCodeManager.on("statusChanged", () => { - statusBar.update(leetCodeManager.getStatus(), leetCodeManager.getUser()); + statusBarManager.update(leetCodeManager.getStatus(), leetCodeManager.getUser()); leetCodeTreeDataProvider.cleanUserScore(); leetCodeTreeDataProvider.refresh(); }); @@ -45,13 +45,13 @@ export async function activate(context: vscode.ExtensionContext): Promise }); leetCodeManager.on("searchUserContest", () => { - statusBar.update(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo()); + statusBarManager.update(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo()); }); leetCodeTreeDataProvider.initialize(context); context.subscriptions.push( - statusBar, + statusBarManager, logOutput, leetCodePreviewProvider, leetCodeSubmissionProvider, diff --git a/src/statusbar/StatusBar.ts b/src/manager/StatusBarManager.ts similarity index 91% rename from src/statusbar/StatusBar.ts rename to src/manager/StatusBarManager.ts index 15eb25c..fe8fc52 100644 --- a/src/statusbar/StatusBar.ts +++ b/src/manager/StatusBarManager.ts @@ -9,10 +9,10 @@ import { ConfigurationChangeEvent, Disposable, workspace, StatusBarItem, window } from "vscode"; import { UserStatus, userContestRanKingBase } from "../shared"; -import { isStatusBar } from "../utils/configUtils"; +import { enableStatusBar } from "../utils/configUtils"; // 状态栏工具 -class StatusBar implements Disposable { +class StatusBarManager implements Disposable { private instance: StatusBarItem; private configurationChangeListener: Disposable; @@ -58,7 +58,7 @@ class StatusBar implements Disposable { // 设置可见性 private setStatusBarVisibility(): void { - if (isStatusBar()) { + if (enableStatusBar()) { this.instance.show(); } else { this.instance.hide(); @@ -67,4 +67,4 @@ class StatusBar implements Disposable { } -export const statusBar: StatusBar = new StatusBar(); +export const statusBarManager: StatusBarManager = new StatusBarManager(); diff --git a/src/utils/configUtils.ts b/src/utils/configUtils.ts index bbc48a4..41dc43f 100644 --- a/src/utils/configUtils.ts +++ b/src/utils/configUtils.ts @@ -85,7 +85,7 @@ export function isUseEndpointTranslation(): boolean { } // 状态栏状态设置 -export function isStatusBar(): boolean { +export function enableStatusBar(): boolean { return getVsCodeConfig().get("enableStatusBar", true); } From a8282f247a974b22bf868add02420f6a88b7b3b4 Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 13:31:19 +0800 Subject: [PATCH 07/31] setting --- src/commands/list.ts | 4 ++-- src/commands/show.ts | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/commands/list.ts b/src/commands/list.ts index c628235..1aff909 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -5,7 +5,7 @@ import * as vscode from "vscode"; import { leetCodeExecutor } from "../leetCodeExecutor"; import { leetCodeManager } from "../leetCodeManager"; import { IProblem, ProblemState, RootNodeSort, UserStatus } from "../shared"; -import * as settingUtils from "../utils/configUtils"; +import { isUseEndpointTranslation } from "../utils/configUtils"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { resourcesData } from "../ResourcesData"; @@ -17,7 +17,7 @@ export async function listProblems(): Promise { } const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating"); const showLocked: boolean = !!leetCodeConfig.get("showLocked"); - const useEndpointTranslation: boolean = settingUtils.isUseEndpointTranslation(); + const useEndpointTranslation: boolean = isUseEndpointTranslation(); const result: string = await leetCodeExecutor.listProblems(showLocked, useEndpointTranslation); const all_problem_info = JSON.parse(result); const problems: IProblem[] = []; diff --git a/src/commands/show.ts b/src/commands/show.ts index 7909eae..78f188c 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -13,7 +13,7 @@ import { leetCodeManager } from "../leetCodeManager"; import { IProblem, IQuickItemEx, languages, ProblemState, SearchNode, SearchSetType, userContestRankingObj, userContestRanKingBase } from "../shared"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils"; -import * as settingUtils from "../utils/configUtils"; +import { isUseEndpointTranslation, getDescriptionConfiguration } from "../utils/configUtils"; import { IDescriptionConfiguration } from "../utils/configUtils"; import { DialogOptions, DialogType, openSettingsEditor, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/uiUtils"; import { getActiveFilePath, selectWorkspaceFolder } from "../utils/workspaceUtils"; @@ -44,7 +44,7 @@ export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: b } else { node = input; } - const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); + const needTranslation: boolean = isUseEndpointTranslation(); const descString: string = await leetCodeExecutor.getDescription(node.qid, needTranslation); leetCodePreviewProvider.show(descString, node, isSideMode); } @@ -238,7 +238,7 @@ export async function searchUserContest(): Promise { return; } try { - const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); + const needTranslation: boolean = isUseEndpointTranslation(); const solution: string = await leetCodeExecutor.getUserContest(needTranslation, leetCodeManager.getUser() || ""); const query_result = JSON.parse(solution); const tt: userContestRanKingBase = Object.assign({}, userContestRankingObj, query_result.userContestRanking) @@ -255,7 +255,7 @@ export async function searchToday(): Promise { return; } try { - const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); + const needTranslation: boolean = isUseEndpointTranslation(); const solution: string = await leetCodeExecutor.getTodayQuestion(needTranslation); const query_result = JSON.parse(solution); // const titleSlug: string = query_result.titleSlug @@ -306,7 +306,7 @@ export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath; - const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration(); - const needTranslation: boolean = settingUtils.isUseEndpointTranslation(); + const descriptionConfig: IDescriptionConfiguration = getDescriptionConfiguration(); + const needTranslation: boolean = isUseEndpointTranslation(); await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); const promises: any[] = [ From 5d3b952acf9ab4858c7d050d1fe700d4d7e895b3 Mon Sep 17 00:00:00 2001 From: ccagml Date: Thu, 10 Nov 2022 17:22:22 +0800 Subject: [PATCH 08/31] update --- src/ResourcesData.ts | 2 +- src/codelens/CustomCodeLensProvider.ts | 8 +- src/commands/cache.ts | 4 +- src/commands/language.ts | 2 +- src/commands/list.ts | 14 +- src/commands/plugin.ts | 12 +- src/commands/show.ts | 77 ++++----- src/commands/star.ts | 18 +-- src/commands/submit.ts | 19 +-- src/commands/test.ts | 31 ++-- src/controller/EventController.ts | 26 +++ .../LoginController.ts} | 131 +++++----------- src/controller/MainController.ts | 35 +++++ .../TreeViewController.ts} | 148 +++++++++--------- src/extension.ts | 112 ++++++------- src/manager/StatusBarManager.ts | 70 --------- src/{shared.ts => model/Model.ts} | 22 ++- .../LeetCodeNode.ts => model/NodeModel.ts} | 15 +- src/service/EventService.ts | 49 ++++++ .../ExecuteService.ts} | 25 +-- .../PreviewService.ts} | 35 +++-- .../SolutionService.ts} | 35 +++-- src/service/StatusBarService.ts | 136 ++++++++++++++++ .../SubmissionService.ts} | 28 ++-- .../TreeDataService.ts} | 102 +++++------- .../TreeItemDecorationService.ts} | 4 +- .../baseWebviewService.ts} | 25 +-- .../markdownService.ts} | 15 +- src/utils/configUtils.ts | 2 +- src/utils/problemUtils.ts | 2 +- src/utils/workspaceUtils.ts | 2 +- 31 files changed, 675 insertions(+), 531 deletions(-) create mode 100644 src/controller/EventController.ts rename src/{leetCodeManager.ts => controller/LoginController.ts} (54%) create mode 100644 src/controller/MainController.ts rename src/{explorer/explorerNodeManager.ts => controller/TreeViewController.ts} (76%) delete mode 100644 src/manager/StatusBarManager.ts rename src/{shared.ts => model/Model.ts} (90%) rename src/{explorer/LeetCodeNode.ts => model/NodeModel.ts} (91%) create mode 100644 src/service/EventService.ts rename src/{leetCodeExecutor.ts => service/ExecuteService.ts} (94%) rename src/{webview/leetCodePreviewProvider.ts => service/PreviewService.ts} (86%) rename src/{webview/leetCodeSolutionProvider.ts => service/SolutionService.ts} (74%) create mode 100644 src/service/StatusBarService.ts rename src/{webview/leetCodeSubmissionProvider.ts => service/SubmissionService.ts} (76%) rename src/{explorer/LeetCodeTreeDataProvider.ts => service/TreeDataService.ts} (55%) rename src/{explorer/LeetCodeTreeItemDecorationProvider.ts => service/TreeItemDecorationService.ts} (94%) rename src/{webview/LeetCodeWebview.ts => service/baseWebviewService.ts} (82%) rename src/{webview/markdownEngine.ts => service/markdownService.ts} (94%) diff --git a/src/ResourcesData.ts b/src/ResourcesData.ts index 1c568db..e02f46c 100644 --- a/src/ResourcesData.ts +++ b/src/ResourcesData.ts @@ -1,4 +1,4 @@ -import { IScoreData } from "./shared"; +import { IScoreData } from "./model/Model"; class ResourcesData { diff --git a/src/codelens/CustomCodeLensProvider.ts b/src/codelens/CustomCodeLensProvider.ts index 6b90d09..f209ea3 100644 --- a/src/codelens/CustomCodeLensProvider.ts +++ b/src/codelens/CustomCodeLensProvider.ts @@ -2,8 +2,8 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { explorerNodeManager } from "../explorer/explorerNodeManager"; -import { LeetCodeNode } from "../explorer/LeetCodeNode"; +import { treeViewController } from "../controller/TreeViewController"; +import { NodeModel } from "../model/NodeModel"; import { getEditorShortcuts } from "../utils/configUtils"; export class CustomCodeLensProvider implements vscode.CodeLensProvider { @@ -30,9 +30,9 @@ export class CustomCodeLensProvider implements vscode.CodeLensProvider { return undefined; } const nodeId: string | undefined = matchResult[1]; - let node: LeetCodeNode | undefined; + let node: NodeModel | undefined; if (nodeId) { - node = explorerNodeManager.getNodeById(nodeId); + node = treeViewController.getNodeById(nodeId); } let codeLensLine: number = document.lineCount - 1; diff --git a/src/commands/cache.ts b/src/commands/cache.ts index 1f6b656..f3460cd 100644 --- a/src/commands/cache.ts +++ b/src/commands/cache.ts @@ -1,12 +1,12 @@ // Copyright (c) jdneo. All rights reserved. // Licensed under the MIT license. -import { leetCodeExecutor } from "../leetCodeExecutor"; +import { executeService } from "../service/ExecuteService"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; export async function deleteCache(): Promise { try { - await leetCodeExecutor.deleteCache(); + await executeService.deleteCache(); } catch (error) { await promptForOpenOutputChannel("Failed to delete cache. Please open the output channel for details.", DialogType.error); } diff --git a/src/commands/language.ts b/src/commands/language.ts index aec9b38..f5d4aff 100644 --- a/src/commands/language.ts +++ b/src/commands/language.ts @@ -2,7 +2,7 @@ // Licensed under the MIT license. import { QuickPickItem, window, workspace, WorkspaceConfiguration } from "vscode"; -import { languages } from "../shared"; +import { languages } from "../model/Model"; export async function switchDefaultLanguage(): Promise { const leetCodeConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode-problem-rating"); diff --git a/src/commands/list.ts b/src/commands/list.ts index 1aff909..d0a08ea 100644 --- a/src/commands/list.ts +++ b/src/commands/list.ts @@ -2,26 +2,26 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { leetCodeManager } from "../leetCodeManager"; -import { IProblem, ProblemState, RootNodeSort, UserStatus } from "../shared"; +import { executeService } from "../service/ExecuteService"; +import { statusBarService } from "../service/StatusBarService"; +import { IProblem, ProblemState, RootNodeSort, UserStatus } from "../model/Model"; import { isUseEndpointTranslation } from "../utils/configUtils"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; -import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; +import { treeDataService } from "../service/TreeDataService"; import { resourcesData } from "../ResourcesData"; export async function listProblems(): Promise { try { - if (leetCodeManager.getStatus() === UserStatus.SignedOut) { + if (statusBarService.getStatus() === UserStatus.SignedOut) { return []; } const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating"); const showLocked: boolean = !!leetCodeConfig.get("showLocked"); const useEndpointTranslation: boolean = isUseEndpointTranslation(); - const result: string = await leetCodeExecutor.listProblems(showLocked, useEndpointTranslation); + const result: string = await executeService.listProblems(showLocked, useEndpointTranslation); const all_problem_info = JSON.parse(result); const problems: IProblem[] = []; - const AllScoreData = leetCodeTreeDataProvider.getScoreData(); + const AllScoreData = treeDataService.getScoreData(); for (const p of all_problem_info) { problems.push({ id: p.fid, diff --git a/src/commands/plugin.ts b/src/commands/plugin.ts index b39efc1..c8e9cb0 100644 --- a/src/commands/plugin.ts +++ b/src/commands/plugin.ts @@ -2,10 +2,10 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { IQuickItemEx } from "../shared"; -import { Endpoint, SortingStrategy } from "../shared"; +import { treeDataService } from "../service/TreeDataService"; +import { executeService } from "../service/ExecuteService"; +import { IQuickItemEx } from "../model/Model"; +import { Endpoint, SortingStrategy } from "../model/Model"; import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; import { deleteCache } from "./cache"; @@ -33,7 +33,7 @@ export async function switchEndpoint(): Promise { const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating"); try { const endpoint: string = choice.value; - await leetCodeExecutor.switchEndpoint(endpoint); + await executeService.switchEndpoint(endpoint); await leetCodeConfig.update("endpoint", endpoint, true /* UserSetting */); vscode.window.showInformationMessage(`Switched the endpoint to ${endpoint}`); } catch (error) { @@ -82,7 +82,7 @@ export async function switchSortingStrategy(): Promise { const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating"); await leetCodeConfig.update("problems.sortStrategy", choice.value, true); - await leetCodeTreeDataProvider.refresh(); + await treeDataService.refresh(); } export function getSortingStrategy(): SortingStrategy { diff --git a/src/commands/show.ts b/src/commands/show.ts index 78f188c..143cbed 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -5,24 +5,26 @@ import * as _ from "lodash"; import * as path from "path"; import * as unescapeJS from "unescape-js"; import * as vscode from "vscode"; -import { explorerNodeManager } from "../explorer/explorerNodeManager"; -import { LeetCodeNode } from "../explorer/LeetCodeNode"; +import { treeViewController } from "../controller/TreeViewController"; +import { NodeModel } from "../model/NodeModel"; import { logOutput } from "../utils/logOutput"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { leetCodeManager } from "../leetCodeManager"; -import { IProblem, IQuickItemEx, languages, ProblemState, SearchNode, SearchSetType, userContestRankingObj, userContestRanKingBase } from "../shared"; -import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; +import { executeService } from "../service/ExecuteService"; +import { eventContorller } from "../controller/EventController"; +import { loginContorller } from "../controller/LoginController"; +import { IProblem, IQuickItemEx, languages, ProblemState, SearchNode, SearchSetType, userContestRankingObj, userContestRanKingBase } from "../model/Model"; +import { treeDataService } from "../service/TreeDataService"; import { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils"; import { isUseEndpointTranslation, getDescriptionConfiguration } from "../utils/configUtils"; import { IDescriptionConfiguration } from "../utils/configUtils"; import { DialogOptions, DialogType, openSettingsEditor, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/uiUtils"; import { getActiveFilePath, selectWorkspaceFolder } from "../utils/workspaceUtils"; import * as wsl from "../utils/wslUtils"; -import { leetCodePreviewProvider } from "../webview/leetCodePreviewProvider"; -import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider"; +import { previewService } from "../service/PreviewService"; +import { solutionService } from "../service/SolutionService"; import { getPickOneByRankRangeMin, getPickOneByRankRangeMax } from "../utils/configUtils"; import * as list from "./list"; import { getLeetCodeEndpoint } from "./plugin"; +import { statusBarService } from "../service/StatusBarService"; export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise { let node: IProblem; @@ -33,7 +35,7 @@ export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: b vscode.window.showErrorMessage(`Failed to resolve the problem id from file: ${activeFilePath}.`); return; } - const cachedNode: IProblem | undefined = explorerNodeManager.getNodeById(id); + const cachedNode: IProblem | undefined = treeViewController.getNodeById(id); if (!cachedNode) { vscode.window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`); return; @@ -45,15 +47,15 @@ export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: b node = input; } const needTranslation: boolean = isUseEndpointTranslation(); - const descString: string = await leetCodeExecutor.getDescription(node.qid, needTranslation); - leetCodePreviewProvider.show(descString, node, isSideMode); + const descString: string = await executeService.getDescription(node.qid, needTranslation); + previewService.show(descString, node, isSideMode); } export async function deleteAllCache(): Promise { - await leetCodeManager.signOut(); - await leetCodeExecutor.removeOldCache(); - await leetCodeExecutor.switchEndpoint(getLeetCodeEndpoint()); - await leetCodeTreeDataProvider.refresh() + await loginContorller.signOut(); + await executeService.removeOldCache(); + await executeService.switchEndpoint(getLeetCodeEndpoint()); + await treeDataService.refresh() } @@ -61,7 +63,7 @@ export async function pickOne(): Promise { const problems: IProblem[] = await list.listProblems(); var randomProblem: IProblem; - const user_score = leetCodeManager.getUserContestScore() + const user_score = statusBarService.getUserContestScore() if (user_score > 0) { let min_score: number = getPickOneByRankRangeMin(); @@ -98,8 +100,8 @@ export async function searchScoreRange(): Promise { type: SearchSetType.ScoreRange, time: Math.floor(Date.now() / 1000) }) - explorerNodeManager.insertSearchSet(tt); - await leetCodeTreeDataProvider.refresh() + treeViewController.insertSearchSet(tt); + await treeDataService.refresh() } export async function searchContest(): Promise { @@ -115,11 +117,11 @@ export async function searchContest(): Promise { type: SearchSetType.Context, time: Math.floor(Date.now() / 1000) }) - explorerNodeManager.insertSearchSet(tt); - await leetCodeTreeDataProvider.refresh() + treeViewController.insertSearchSet(tt); + await treeDataService.refresh() } -export async function showProblem(node?: LeetCodeNode): Promise { +export async function showProblem(node?: NodeModel): Promise { if (!node) { return; } @@ -128,7 +130,7 @@ export async function showProblem(node?: LeetCodeNode): Promise { export async function searchProblemByID(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } @@ -148,7 +150,7 @@ export async function searchProblemByID(): Promise { export async function searchProblem(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } @@ -211,7 +213,7 @@ export async function searchProblem(): Promise { } export async function testapi(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } @@ -223,7 +225,7 @@ export async function testapi(): Promise { }); // vscode.window.showErrorMessage(twoFactor || "输入错误"); - const solution: string = await leetCodeExecutor.getTestApi(twoFactor || "") + const solution: string = await executeService.getTestApi(twoFactor || "") const query_result = JSON.parse(solution); console.log(query_result); } catch (error) { @@ -233,30 +235,29 @@ export async function testapi(): Promise { } export async function searchUserContest(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } try { const needTranslation: boolean = isUseEndpointTranslation(); - const solution: string = await leetCodeExecutor.getUserContest(needTranslation, leetCodeManager.getUser() || ""); + const solution: string = await executeService.getUserContest(needTranslation, statusBarService.getUser() || ""); const query_result = JSON.parse(solution); const tt: userContestRanKingBase = Object.assign({}, userContestRankingObj, query_result.userContestRanking) - await leetCodeManager.insertCurrentUserContestInfo(tt); - leetCodeManager.emit("searchUserContest") + eventContorller.emit("searchUserContest", tt) } catch (error) { logOutput.appendLine(error.toString()); await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error); } } export async function searchToday(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } try { const needTranslation: boolean = isUseEndpointTranslation(); - const solution: string = await leetCodeExecutor.getTodayQuestion(needTranslation); + const solution: string = await executeService.getTodayQuestion(needTranslation); const query_result = JSON.parse(solution); // const titleSlug: string = query_result.titleSlug // const questionId: string = query_result.questionId @@ -268,8 +269,8 @@ export async function searchToday(): Promise { time: Math.floor(Date.now() / 1000), todayData: query_result, }) - explorerNodeManager.insertSearchSet(tt); - await leetCodeTreeDataProvider.refresh() + treeViewController.insertSearchSet(tt); + await treeDataService.refresh() } } catch (error) { @@ -279,9 +280,9 @@ export async function searchToday(): Promise { } -export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { +export async function showSolution(input: NodeModel | vscode.Uri): Promise { let problemInput: string | undefined; - if (input instanceof LeetCodeNode) { // Triggerred from explorer + if (input instanceof NodeModel) { // Triggerred from explorer problemInput = input.qid; } else if (input instanceof vscode.Uri) { // Triggerred from Code Lens/context menu if (wsl.useVscodeNode()) { @@ -307,8 +308,8 @@ export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise { const descriptionConfig: IDescriptionConfiguration = getDescriptionConfiguration(); const needTranslation: boolean = isUseEndpointTranslation(); - await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); + await executeService.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation); const promises: any[] = [ vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }), promptHintMessage( diff --git a/src/commands/star.ts b/src/commands/star.ts index 705affc..bb95b9d 100644 --- a/src/commands/star.ts +++ b/src/commands/star.ts @@ -3,16 +3,16 @@ // Licensed under the MIT license. import { customCodeLensProvider } from "../codelens/CustomCodeLensProvider"; -import { LeetCodeNode } from "../explorer/LeetCodeNode"; -import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; -import { leetCodeExecutor } from "../leetCodeExecutor"; +import { NodeModel } from "../model/NodeModel"; +import { treeDataService } from "../service/TreeDataService"; +import { executeService } from "../service/ExecuteService"; import { isStarShortcut } from "../utils/configUtils"; import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; -export async function addFavorite(node: LeetCodeNode): Promise { +export async function addFavorite(node: NodeModel): Promise { try { - await leetCodeExecutor.toggleFavorite(node, true); - await leetCodeTreeDataProvider.refresh(); + await executeService.toggleFavorite(node, true); + await treeDataService.refresh(); if (isStarShortcut()) { customCodeLensProvider.refresh(); } @@ -21,10 +21,10 @@ export async function addFavorite(node: LeetCodeNode): Promise { } } -export async function removeFavorite(node: LeetCodeNode): Promise { +export async function removeFavorite(node: NodeModel): Promise { try { - await leetCodeExecutor.toggleFavorite(node, false); - await leetCodeTreeDataProvider.refresh(); + await executeService.toggleFavorite(node, false); + await treeDataService.refresh(); if (isStarShortcut()) { customCodeLensProvider.refresh(); } diff --git a/src/commands/submit.ts b/src/commands/submit.ts index 34710b6..09ec4f7 100644 --- a/src/commands/submit.ts +++ b/src/commands/submit.ts @@ -2,15 +2,16 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { leetCodeManager } from "../leetCodeManager"; +import { treeDataService } from "../service/TreeDataService"; +import { executeService } from "../service/ExecuteService"; +import { eventContorller } from "../controller/EventController"; import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; import { getActiveFilePath } from "../utils/workspaceUtils"; -import { leetCodeSubmissionProvider } from "../webview/leetCodeSubmissionProvider"; +import { submissionService } from "../service/SubmissionService"; +import { statusBarService } from "../service/StatusBarService"; export async function submitSolution(uri?: vscode.Uri): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { promptForSignIn(); return; } @@ -21,13 +22,13 @@ export async function submitSolution(uri?: vscode.Uri): Promise { } try { - const result: string = await leetCodeExecutor.submitSolution(filePath); - leetCodeSubmissionProvider.show(result); - leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent()); + const result: string = await executeService.submitSolution(filePath); + submissionService.show(result); + eventContorller.emit("submit", submissionService.getSubmitEvent()); } catch (error) { await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error); return; } - leetCodeTreeDataProvider.refresh(); + treeDataService.refresh(); } diff --git a/src/commands/test.ts b/src/commands/test.ts index 7b0c18e..9239505 100644 --- a/src/commands/test.ts +++ b/src/commands/test.ts @@ -3,18 +3,19 @@ import * as fse from "fs-extra"; import * as vscode from "vscode"; -import { leetCodeExecutor } from "../leetCodeExecutor"; -import { leetCodeManager } from "../leetCodeManager"; -import { IQuickItemEx, UserStatus } from "../shared"; +import { executeService } from "../service/ExecuteService"; +import { eventContorller } from "../controller/EventController"; +import { IQuickItemEx, UserStatus } from "../model/Model"; import { isWindows, usingCmd } from "../utils/osUtils"; import { DialogType, promptForOpenOutputChannel, showFileSelectDialog } from "../utils/uiUtils"; import { getActiveFilePath } from "../utils/workspaceUtils"; import * as wsl from "../utils/wslUtils"; -import { leetCodeSubmissionProvider } from "../webview/leetCodeSubmissionProvider"; +import { submissionService } from "../service/SubmissionService"; +import { statusBarService } from "../service/StatusBarService"; export async function testSolution(uri?: vscode.Uri): Promise { try { - if (leetCodeManager.getStatus() === UserStatus.SignedOut) { + if (statusBarService.getStatus() === UserStatus.SignedOut) { return; } @@ -57,7 +58,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { let result: string | undefined; switch (choice.value) { case ":default": - result = await leetCodeExecutor.testSolution(filePath); + result = await executeService.testSolution(filePath); break; case ":direct": const testString: string | undefined = await vscode.window.showInputBox({ @@ -67,7 +68,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { ignoreFocusOut: true, }); if (testString) { - result = await leetCodeExecutor.testSolution(filePath, parseTestString(testString)); + result = await executeService.testSolution(filePath, parseTestString(testString)); } break; case ":file": @@ -75,14 +76,14 @@ export async function testSolution(uri?: vscode.Uri): Promise { if (testFile && testFile.length) { const input: string = (await fse.readFile(testFile[0].fsPath, "utf-8")).trim(); if (input) { - result = await leetCodeExecutor.testSolution(filePath, parseTestString(input.replace(/\r?\n/g, "\\n"))); + result = await executeService.testSolution(filePath, parseTestString(input.replace(/\r?\n/g, "\\n"))); } else { vscode.window.showErrorMessage("The selected test file must not be empty."); } } break; case ":alldefault": - result = await leetCodeExecutor.testSolution(filePath, undefined, true); + result = await executeService.testSolution(filePath, undefined, true); break; default: break; @@ -90,8 +91,8 @@ export async function testSolution(uri?: vscode.Uri): Promise { if (!result) { return; } - leetCodeSubmissionProvider.show(result); - leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent()); + submissionService.show(result); + eventContorller.emit("submit", submissionService.getSubmitEvent()); } catch (error) { await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error); } @@ -99,7 +100,7 @@ export async function testSolution(uri?: vscode.Uri): Promise { export async function testSolutionDefault(uri?: vscode.Uri, allCase?: boolean): Promise { try { - if (leetCodeManager.getStatus() === UserStatus.SignedOut) { + if (statusBarService.getStatus() === UserStatus.SignedOut) { return; } @@ -108,12 +109,12 @@ export async function testSolutionDefault(uri?: vscode.Uri, allCase?: boolean): return; } - let result: string | undefined = await leetCodeExecutor.testSolution(filePath, undefined, allCase || false); + let result: string | undefined = await executeService.testSolution(filePath, undefined, allCase || false); if (!result) { return; } - leetCodeSubmissionProvider.show(result); - leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent()); + submissionService.show(result); + eventContorller.emit("submit", submissionService.getSubmitEvent()); } catch (error) { await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error); } diff --git a/src/controller/EventController.ts b/src/controller/EventController.ts new file mode 100644 index 0000000..b821a6e --- /dev/null +++ b/src/controller/EventController.ts @@ -0,0 +1,26 @@ +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/controller/EventController.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Monday, October 31st 2022, 10:16:47 am + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + + +import { EventEmitter } from "events"; +import { eventService } from "../service/EventService"; +class EventContorller extends EventEmitter { + + constructor() { + super(); + } + /** + * 监听事件 + */ + public add_event() { + eventService.add_event() + } +} + +export const eventContorller: EventContorller = new EventContorller(); diff --git a/src/leetCodeManager.ts b/src/controller/LoginController.ts similarity index 54% rename from src/leetCodeManager.ts rename to src/controller/LoginController.ts index 689cfd0..961e0bb 100644 --- a/src/leetCodeManager.ts +++ b/src/controller/LoginController.ts @@ -1,49 +1,27 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/controller/LoginController.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, November 10th 2022, 3:06:12 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ import * as cp from "child_process"; -import { EventEmitter } from "events"; -import * as vscode from "vscode"; -import { logOutput } from "./utils/logOutput"; -import { leetCodeExecutor } from "./leetCodeExecutor"; -import { IQuickItemEx, loginArgsMapping, UserStatus, userContestRanKingBase, userContestRankingObj } from "./shared"; -import { createEnvOption } from "./utils/cliUtils"; -import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; -import * as wsl from "./utils/wslUtils"; -import { explorerNodeManager } from "./explorer/explorerNodeManager"; - -class LeetCodeManager extends EventEmitter { - private currentUser: string | undefined; - private userStatus: UserStatus; - // private readonly successRegex: RegExp = /(?:.*)Successfully .*login as (.*)/i; - // private readonly failRegex: RegExp = /.*\[ERROR\].*/i; - private currentUserContestInfo: userContestRanKingBase; - - constructor() { - super(); - this.currentUser = undefined; - this.userStatus = UserStatus.SignedOut; - } +import * as wsl from "../utils/wslUtils"; +import { executeService } from "../service/ExecuteService"; - public async insertCurrentUserContestInfo(tt: userContestRanKingBase) { - this.currentUserContestInfo = tt; - await explorerNodeManager.update_user_score(tt.rating); - } - public async getLoginStatus(): Promise { - try { - const result: string = await leetCodeExecutor.getUserInfo(); - this.currentUser = this.tryParseUserName(result); - this.userStatus = UserStatus.SignedIn; - if (this.currentUser == undefined) { - this.userStatus = UserStatus.SignedOut; - } - } catch (error) { - this.currentUser = undefined; - this.userStatus = UserStatus.SignedOut; - } finally { - this.emit("statusChanged"); - } - } +import { IQuickItemEx, loginArgsMapping, UserStatus } from "../model/Model"; +import { createEnvOption } from "../utils/cliUtils"; +import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils"; +import { logOutput } from "../utils/logOutput"; +import { eventService } from "../service/EventService"; +import { window } from "vscode"; +import { statusBarService } from "../service/StatusBarService"; + +// 登录 +class LoginContorller { + constructor() { } public async signIn(): Promise { const picks: Array> = []; @@ -69,7 +47,7 @@ class LeetCodeManager extends EventEmitter { value: "Cookie", }, ); - const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks); + const choice: IQuickItemEx | undefined = await window.showQuickPick(picks); if (!choice) { return; } @@ -83,20 +61,20 @@ class LeetCodeManager extends EventEmitter { try { const userName: string | undefined = await new Promise(async (resolve: (res: string | undefined) => void, reject: (e: Error) => void): Promise => { - const leetCodeBinaryPath: string = await leetCodeExecutor.getLeetCodeBinaryPath(); + const leetCodeBinaryPath: string = await executeService.getLeetCodeBinaryPath(); var childProc: cp.ChildProcess; if (wsl.useVscodeNode()) { - childProc = cp.fork(await leetCodeExecutor.getLeetCodeBinaryPath(), ["user", commandArg], { + childProc = cp.fork(await executeService.getLeetCodeBinaryPath(), ["user", commandArg], { silent: true, env: createEnvOption(), }); } else { if (wsl.useWsl()) { - childProc = cp.spawn("wsl", [leetCodeExecutor.node, leetCodeBinaryPath, "user", commandArg], { shell: true }) + childProc = cp.spawn("wsl", [executeService.node, leetCodeBinaryPath, "user", commandArg], { shell: true }) } else { - childProc = cp.spawn(leetCodeExecutor.node, [leetCodeBinaryPath, "user", commandArg], { + childProc = cp.spawn(executeService.node, [leetCodeBinaryPath, "user", commandArg], { shell: true, env: createEnvOption(), }); @@ -109,7 +87,7 @@ class LeetCodeManager extends EventEmitter { // vscode.window.showInformationMessage(`cc login msg ${data}.`); logOutput.append(data); if (data.includes("twoFactorCode")) { - const twoFactor: string | undefined = await vscode.window.showInputBox({ + const twoFactor: string | undefined = await window.showInputBox({ prompt: "Enter two-factor code.", ignoreFocusOut: true, validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty", @@ -139,7 +117,7 @@ class LeetCodeManager extends EventEmitter { childProc.stderr?.on("data", (data: string | Buffer) => logOutput.append(data.toString())); childProc.on("error", reject); - const name: string | undefined = await vscode.window.showInputBox({ + const name: string | undefined = await window.showInputBox({ prompt: "Enter username or E-mail.", ignoreFocusOut: true, validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty", @@ -149,7 +127,7 @@ class LeetCodeManager extends EventEmitter { return resolve(undefined); } childProc.stdin?.write(`${name}\n`); - const pwd: string | undefined = await vscode.window.showInputBox({ + const pwd: string | undefined = await window.showInputBox({ prompt: isByCookie ? "Enter cookie" : "Enter password.", password: true, ignoreFocusOut: true, @@ -162,10 +140,8 @@ class LeetCodeManager extends EventEmitter { childProc.stdin?.write(`${pwd}\n`); }); if (userName) { - vscode.window.showInformationMessage(`Successfully ${inMessage}.`); - this.currentUser = userName; - this.userStatus = UserStatus.SignedIn; - this.emit("statusChanged"); + window.showInformationMessage(`Successfully ${inMessage}.`); + eventService.emit("statusChanged", UserStatus.SignedIn, userName); } } catch (error) { promptForOpenOutputChannel(`Failed to ${inMessage}. Please open the output channel for details`, DialogType.error); @@ -175,49 +151,16 @@ class LeetCodeManager extends EventEmitter { public async signOut(): Promise { try { - await leetCodeExecutor.signOut(); - vscode.window.showInformationMessage("Successfully signed out."); - this.currentUser = undefined; - this.userStatus = UserStatus.SignedOut; - this.currentUserContestInfo = Object.assign({}, userContestRankingObj, {}) - this.emit("statusChanged"); + await executeService.signOut(); + window.showInformationMessage("Successfully signed out."); + eventService.emit("statusChanged", UserStatus.SignedOut, undefined); } catch (error) { - // swallow the error when sign out. - } - } - - public getStatus(): UserStatus { - return this.userStatus; - } - - // 获取竞赛分 - public getUserContestScore(): number { - if (this.currentUserContestInfo.rating > 0) { - return this.currentUserContestInfo.rating } - return 0; - } - - public getUserContestInfo(): userContestRanKingBase | undefined { - return this.currentUserContestInfo; } - public getUser(): string | undefined { - return this.currentUser; - } - - private tryParseUserName(output: string): string | undefined { - var successMatch; - try { - successMatch = JSON.parse(output); - } catch (e) { - successMatch = {}; - } - if (successMatch.code == 100) { - return successMatch.user_name; - } - return undefined; + public async getLoginStatus() { + return await statusBarService.getLoginStatus() } } -export const leetCodeManager: LeetCodeManager = new LeetCodeManager(); +export const loginContorller: LoginContorller = new LoginContorller(); diff --git a/src/controller/MainController.ts b/src/controller/MainController.ts new file mode 100644 index 0000000..b029036 --- /dev/null +++ b/src/controller/MainController.ts @@ -0,0 +1,35 @@ +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/controller/MainController.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, November 10th 2022, 2:18:21 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + +import * as wsl from "../utils/wslUtils"; +import { executeService } from "../service/ExecuteService"; +import { ExtensionContext } from "vscode"; +import { treeDataService } from "../service/TreeDataService"; + +// 做杂活 +class MainContorller { + constructor() { } + + /** + * 检查运行环境 + */ + public async checkNodeEnv(context: ExtensionContext) { + if (!wsl.useVscodeNode()) { + if (!await executeService.checkNodeEnv(context)) { + throw new Error("The environment doesn't meet requirements."); + } + } + } + + public initialize(context: ExtensionContext) { + treeDataService.initialize(context); + } +} + +export const mainContorller: MainContorller = new MainContorller(); diff --git a/src/explorer/explorerNodeManager.ts b/src/controller/TreeViewController.ts similarity index 76% rename from src/explorer/explorerNodeManager.ts rename to src/controller/TreeViewController.ts index 839a8de..fe236f2 100644 --- a/src/explorer/explorerNodeManager.ts +++ b/src/controller/TreeViewController.ts @@ -1,40 +1,39 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/controller/TreeViewController.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import * as _ from "lodash"; import { toNumber } from "lodash"; import { Disposable } from "vscode"; import * as list from "../commands/list"; import { getSortingStrategy } from "../commands/plugin"; -import { Category, defaultProblem, ProblemState, SortingStrategy, SearchSetTypeName, RootNodeSort, SearchSetType, ISubmitEvent } from "../shared"; +import { Category, defaultProblem, ProblemState, SortingStrategy, SearchSetTypeName, RootNodeSort, SearchSetType, ISubmitEvent } from "../model/Model"; import { isHideSolvedProblem, isHideScoreProblem } from "../utils/configUtils"; -import { LeetCodeNode } from "./LeetCodeNode"; -import { ISearchSet } from "../shared"; +import { NodeModel } from "../model/NodeModel"; +import { ISearchSet } from "../model/Model"; import { searchToday, searchUserContest } from "../commands/show"; -import { leetCodeTreeDataProvider } from "./LeetCodeTreeDataProvider"; import { resourcesData } from "../ResourcesData"; -import { leetCodeManager } from "../leetCodeManager"; +import { statusBarService } from "../service/StatusBarService"; -class ExplorerNodeManager implements Disposable { - private explorerNodeMap: Map = new Map(); +class TreeViewController implements Disposable { + private explorerNodeMap: Map = new Map(); private companySet: Set = new Set(); private tagSet: Set = new Set(); private searchSet: Map = new Map(); private waitTodayQuestion: boolean; private waitUserContest: boolean; - private user_score: number; - - public async update_user_score(user_score: number) { - this.user_score = user_score; - await leetCodeTreeDataProvider.refresh() - } public insertSearchSet(tt: ISearchSet) { this.searchSet.set(tt.value, tt); } public clearUserScore() { - this.user_score = 0; this.waitUserContest = false; this.waitTodayQuestion = false; this.searchSet = new Map(); @@ -61,7 +60,7 @@ class ExplorerNodeManager implements Disposable { } public async refreshCheck(): Promise { - if (!leetCodeManager.getUser()) { + if (!statusBarService.getUser()) { return; } const day_start = new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000; //获取当天零点的时间 @@ -80,7 +79,8 @@ class ExplorerNodeManager implements Disposable { this.waitTodayQuestion = true await searchToday(); } - if (!this.user_score && !this.waitUserContest) { + var user_score = statusBarService.getUserContestScore() + if (!user_score && !this.waitUserContest) { this.waitUserContest = true; await searchUserContest(); } @@ -91,8 +91,9 @@ class ExplorerNodeManager implements Disposable { const temp_waitTodayQuestion: boolean = this.waitTodayQuestion const temp_waitUserContest: boolean = this.waitUserContest this.dispose(); + var user_score = statusBarService.getUserContestScore() for (const problem of await list.listProblems()) { - this.explorerNodeMap.set(problem.id, new LeetCodeNode(problem, true, this.user_score)); + this.explorerNodeMap.set(problem.id, new NodeModel(problem, true, user_score)); for (const company of problem.companies) { this.companySet.add(company); } @@ -105,39 +106,40 @@ class ExplorerNodeManager implements Disposable { this.waitUserContest = temp_waitUserContest } - public getRootNodes(): LeetCodeNode[] { - const baseNode: LeetCodeNode[] = [ - new LeetCodeNode(Object.assign({}, defaultProblem, { + public getRootNodes(): NodeModel[] { + var user_score = statusBarService.getUserContestScore() + const baseNode: NodeModel[] = [ + new NodeModel(Object.assign({}, defaultProblem, { id: Category.All, name: Category.All, rootNodeSortId: RootNodeSort.All, }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: Category.Difficulty, name: Category.Difficulty, rootNodeSortId: RootNodeSort.Difficulty, }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: Category.Tag, name: Category.Tag, rootNodeSortId: RootNodeSort.Tag, }), false), - // new LeetCodeNode(Object.assign({}, defaultProblem, { + // new NodeModel(Object.assign({}, defaultProblem, { // id: Category.Company, // name: Category.Company, // rootNodeSortId: RootNodeSort.Company, // }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: Category.Favorite, name: Category.Favorite, rootNodeSortId: RootNodeSort.Favorite, }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: Category.Score, name: Category.Score, rootNodeSortId: RootNodeSort.Score, - }), false, this.user_score), - new LeetCodeNode(Object.assign({}, defaultProblem, { + }), false, user_score), + new NodeModel(Object.assign({}, defaultProblem, { id: Category.Choice, name: Category.Choice, rootNodeSortId: RootNodeSort.Choice, @@ -146,7 +148,7 @@ class ExplorerNodeManager implements Disposable { this.searchSet.forEach(element => { if (element.type == SearchSetType.Day) { const curDate = new Date(element.time * 1000) - baseNode.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + baseNode.push(new NodeModel(Object.assign({}, defaultProblem, { id: element.type, name: "[" + (curDate.getFullYear()) + "-" + (curDate.getMonth() + 1) + "-" + (curDate.getDate()) + "]" + SearchSetTypeName[SearchSetType.Day], input: element.value, @@ -155,7 +157,7 @@ class ExplorerNodeManager implements Disposable { todayData: element.todayData }), false)); } else { - baseNode.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + baseNode.push(new NodeModel(Object.assign({}, defaultProblem, { id: element.type, name: SearchSetTypeName[element.type] + element.value, input: element.value, @@ -164,7 +166,7 @@ class ExplorerNodeManager implements Disposable { }), false)); } }); - baseNode.sort(function (a: LeetCodeNode, b: LeetCodeNode): number { + baseNode.sort(function (a: NodeModel, b: NodeModel): number { if (a.rootNodeSortId < b.rootNodeSortId) { return -1; } else if (a.rootNodeSortId > b.rootNodeSortId) { @@ -175,8 +177,8 @@ class ExplorerNodeManager implements Disposable { return baseNode; } - public getScoreRangeNodes(rank_range: string): LeetCodeNode[] { - const sorceNode: LeetCodeNode[] = [] + public getScoreRangeNodes(rank_range: string): NodeModel[] { + const sorceNode: NodeModel[] = [] const rank_r: Array = rank_range.split("-") var rank_a = Number(rank_r[0]) var rank_b = Number(rank_r[1]) @@ -199,7 +201,7 @@ class ExplorerNodeManager implements Disposable { return this.applySortingStrategy(sorceNode); } - public canShow(element: LeetCodeNode) { + public canShow(element: NodeModel) { if (isHideSolvedProblem() && element.state === ProblemState.AC) { return false; } @@ -209,8 +211,8 @@ class ExplorerNodeManager implements Disposable { return true; } - public getContextNodes(rank_range: string): LeetCodeNode[] { - const sorceNode: LeetCodeNode[] = [] + public getContextNodes(rank_range: string): NodeModel[] { + const sorceNode: NodeModel[] = [] const rank_r: Array = rank_range.split("-") var rank_a = Number(rank_r[0]) var rank_b = Number(rank_r[1]) @@ -231,9 +233,9 @@ class ExplorerNodeManager implements Disposable { } return this.applySortingStrategy(sorceNode); } - public getDayNodes(element: LeetCodeNode | undefined): LeetCodeNode[] { + public getDayNodes(element: NodeModel | undefined): NodeModel[] { const rank_range: string = element?.input || "" - const sorceNode: LeetCodeNode[] = [] + const sorceNode: NodeModel[] = [] if (rank_range) { this.explorerNodeMap.forEach(new_node => { if (new_node.id == rank_range) { @@ -245,24 +247,24 @@ class ExplorerNodeManager implements Disposable { return this.applySortingStrategy(sorceNode); } - public getAllNodes(): LeetCodeNode[] { + public getAllNodes(): NodeModel[] { return this.applySortingStrategy( Array.from(this.explorerNodeMap.values()).filter(p => this.canShow(p)), ); } - public getAllDifficultyNodes(): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getAllDifficultyNodes(): NodeModel[] { + const res: NodeModel[] = []; res.push( - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Difficulty}.Easy`, name: "Easy", }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Difficulty}.Medium`, name: "Medium", }), false), - new LeetCodeNode(Object.assign({}, defaultProblem, { + new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Difficulty}.Hard`, name: "Hard", }), false), @@ -271,14 +273,14 @@ class ExplorerNodeManager implements Disposable { return res; } - public getAllScoreNodes(user_score: number): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getAllScoreNodes(user_score: number): NodeModel[] { + const res: NodeModel[] = []; const score_array: Array = ["3300", "3200", "3100", "3000", "2900", "2800", "2700", "2600", "2500", "2400", "2300", "2200", "2100", "2000", "1900", "1800", "1700", "1600", "1500", "1400", "1300", "1200", "1100"]; score_array.forEach(element => { const temp_num = Number(element); const diff = Math.abs(temp_num - user_score) if (diff <= 200) { - res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + res.push(new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Score}.${element}`, name: `${element}`, }), false, user_score)) @@ -289,12 +291,12 @@ class ExplorerNodeManager implements Disposable { return res; } - public getAllChoiceNodes(): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getAllChoiceNodes(): NodeModel[] { + const res: NodeModel[] = []; const all_choice = resourcesData.getChoiceData(); all_choice.forEach(element => { - res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + res.push(new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Choice}.${element.id}`, name: `${element.name}`, }), false)) @@ -303,10 +305,10 @@ class ExplorerNodeManager implements Disposable { return res; } - public getAllCompanyNodes(): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getAllCompanyNodes(): NodeModel[] { + const res: NodeModel[] = []; for (const company of this.companySet.values()) { - res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + res.push(new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Company}.${company}`, name: _.startCase(company), }), false)); @@ -315,10 +317,10 @@ class ExplorerNodeManager implements Disposable { return res; } - public getAllTagNodes(): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getAllTagNodes(): NodeModel[] { + const res: NodeModel[] = []; for (const tag of this.tagSet.values()) { - res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + res.push(new NodeModel(Object.assign({}, defaultProblem, { id: `${Category.Tag}.${tag}`, name: _.startCase(tag), }), false)); @@ -327,12 +329,12 @@ class ExplorerNodeManager implements Disposable { return res; } - public getNodeById(id: string): LeetCodeNode | undefined { + public getNodeById(id: string): NodeModel | undefined { return this.explorerNodeMap.get(id); } - public getFavoriteNodes(): LeetCodeNode[] { - const res: LeetCodeNode[] = []; + public getFavoriteNodes(): NodeModel[] { + const res: NodeModel[] = []; for (const node of this.explorerNodeMap.values()) { if (!this.canShow(node)) { continue; @@ -344,10 +346,10 @@ class ExplorerNodeManager implements Disposable { return this.applySortingStrategy(res); } - public getChildrenNodesById(id: string): LeetCodeNode[] { + public getChildrenNodesById(id: string): NodeModel[] { // The sub-category node's id is named as {Category.SubName} const metaInfo: string[] = id.split("."); - const res: LeetCodeNode[] = []; + const res: NodeModel[] = []; const choiceQuestionId: Map = new Map() if (metaInfo[0] == Category.Choice) { @@ -408,11 +410,11 @@ class ExplorerNodeManager implements Disposable { this.tagSet.clear(); } - private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void { + private sortSubCategoryNodes(subCategoryNodes: NodeModel[], category: Category): void { switch (category) { case Category.Difficulty: - subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { - function getValue(input: LeetCodeNode): number { + subCategoryNodes.sort((a: NodeModel, b: NodeModel): number => { + function getValue(input: NodeModel): number { switch (input.name.toLowerCase()) { case "easy": return 1; @@ -429,7 +431,7 @@ class ExplorerNodeManager implements Disposable { break; case Category.Tag: case Category.Company: - subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { + subCategoryNodes.sort((a: NodeModel, b: NodeModel): number => { if (a.name === "Unknown") { return 1; } else if (b.name === "Unknown") { @@ -444,17 +446,17 @@ class ExplorerNodeManager implements Disposable { } } - private applySortingStrategy(nodes: LeetCodeNode[]): LeetCodeNode[] { + private applySortingStrategy(nodes: NodeModel[]): NodeModel[] { const strategy: SortingStrategy = getSortingStrategy(); switch (strategy) { - case SortingStrategy.AcceptanceRateAsc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(x.acceptanceRate) - Number(y.acceptanceRate)); - case SortingStrategy.AcceptanceRateDesc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(y.acceptanceRate) - Number(x.acceptanceRate)); - case SortingStrategy.ScoreAsc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(x.score) - Number(y.score)); - case SortingStrategy.ScoreDesc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(y.score) - Number(x.score)); - case SortingStrategy.IDDesc: return nodes.sort((x: LeetCodeNode, y: LeetCodeNode) => Number(y.id) - Number(x.id)); + case SortingStrategy.AcceptanceRateAsc: return nodes.sort((x: NodeModel, y: NodeModel) => Number(x.acceptanceRate) - Number(y.acceptanceRate)); + case SortingStrategy.AcceptanceRateDesc: return nodes.sort((x: NodeModel, y: NodeModel) => Number(y.acceptanceRate) - Number(x.acceptanceRate)); + case SortingStrategy.ScoreAsc: return nodes.sort((x: NodeModel, y: NodeModel) => Number(x.score) - Number(y.score)); + case SortingStrategy.ScoreDesc: return nodes.sort((x: NodeModel, y: NodeModel) => Number(y.score) - Number(x.score)); + case SortingStrategy.IDDesc: return nodes.sort((x: NodeModel, y: NodeModel) => Number(y.id) - Number(x.id)); default: return nodes; } } } -export const explorerNodeManager: ExplorerNodeManager = new ExplorerNodeManager(); +export const treeViewController: TreeViewController = new TreeViewController(); diff --git a/src/extension.ts b/src/extension.ts index 0e3d4c1..139f14e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,7 @@ // Copyright (c) jdneo. All rights reserved. // Licensed under the MIT license. -import * as vscode from "vscode"; +import { ExtensionContext, window, commands, Uri } from "vscode"; import { codeLensController } from "./codelens/CodeLensController"; import * as cache from "./commands/cache"; import { switchDefaultLanguage } from "./commands/language"; @@ -10,81 +10,65 @@ import * as show from "./commands/show"; import * as star from "./commands/star"; import * as submit from "./commands/submit"; import * as test from "./commands/test"; -import { explorerNodeManager } from "./explorer/explorerNodeManager"; -import { LeetCodeNode } from "./explorer/LeetCodeNode"; -import { leetCodeTreeDataProvider } from "./explorer/LeetCodeTreeDataProvider"; -import { leetCodeTreeItemDecorationProvider } from "./explorer/LeetCodeTreeItemDecorationProvider"; +import { treeViewController } from "./controller/TreeViewController"; +import { NodeModel } from "./model/NodeModel"; +import { treeDataService } from "./service/TreeDataService"; +import { treeItemDecorationService } from "./service/TreeItemDecorationService"; import { logOutput } from "./utils/logOutput"; -import { leetCodeExecutor } from "./leetCodeExecutor"; -import { leetCodeManager } from "./leetCodeManager"; -import { statusBarManager } from "./manager/StatusBarManager"; +import { executeService } from "./service/ExecuteService"; +import { eventContorller } from "./controller/EventController"; +import { statusBarService } from "./service/StatusBarService"; import { DialogType, promptForOpenOutputChannel } from "./utils/uiUtils"; -import { leetCodePreviewProvider } from "./webview/leetCodePreviewProvider"; -import { leetCodeSolutionProvider } from "./webview/leetCodeSolutionProvider"; -import { leetCodeSubmissionProvider } from "./webview/leetCodeSubmissionProvider"; -import { markdownEngine } from "./webview/markdownEngine"; -import { ISubmitEvent } from "./shared"; -import * as wsl from "./utils/wslUtils"; +import { previewService } from "./service/PreviewService"; +import { solutionService } from "./service/SolutionService"; +import { submissionService } from "./service/SubmissionService"; +import { markdownService } from "./service/markdownService"; +import { mainContorller } from "./controller/MainController"; +import { loginContorller } from "./controller/LoginController"; -export async function activate(context: vscode.ExtensionContext): Promise { +export async function activate(context: ExtensionContext): Promise { try { - if (!wsl.useVscodeNode()) { - if (!await leetCodeExecutor.checkNodeEnv(context)) { - throw new Error("The environment doesn't meet requirements."); - } - } - leetCodeManager.on("statusChanged", () => { - statusBarManager.update(leetCodeManager.getStatus(), leetCodeManager.getUser()); - leetCodeTreeDataProvider.cleanUserScore(); - leetCodeTreeDataProvider.refresh(); - }); - leetCodeManager.on("submit", (e: ISubmitEvent) => { - leetCodeTreeDataProvider.checkSubmit(e); - }); - - leetCodeManager.on("searchUserContest", () => { - statusBarManager.update(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo()); - }); - - leetCodeTreeDataProvider.initialize(context); + await mainContorller.checkNodeEnv(context); + eventContorller.add_event(); + mainContorller.initialize(context) context.subscriptions.push( - statusBarManager, + statusBarService, logOutput, - leetCodePreviewProvider, - leetCodeSubmissionProvider, - leetCodeSolutionProvider, - leetCodeExecutor, - markdownEngine, + previewService, + submissionService, + solutionService, + executeService, + markdownService, codeLensController, - explorerNodeManager, - vscode.window.registerFileDecorationProvider(leetCodeTreeItemDecorationProvider), - vscode.window.createTreeView("leetCodeExplorer", { treeDataProvider: leetCodeTreeDataProvider, showCollapseAll: true }), - vscode.commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()), - 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.previewProblem", (node: LeetCodeNode) => show.previewProblem(node)), - vscode.commands.registerCommand("leetcode.showProblem", (node: LeetCodeNode) => show.showProblem(node)), - vscode.commands.registerCommand("leetcode.pickOne", () => show.pickOne()), - vscode.commands.registerCommand("leetcode.deleteAllCache", () => show.deleteAllCache()), - vscode.commands.registerCommand("leetcode.searchScoreRange", () => show.searchScoreRange()), - vscode.commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()), - 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.testSolutionDefault", (uri?: vscode.Uri, allCase?: boolean) => test.testSolutionDefault(uri, allCase)), - vscode.commands.registerCommand("leetcode.submitSolution", (uri?: vscode.Uri) => submit.submitSolution(uri)), - vscode.commands.registerCommand("leetcode.switchDefaultLanguage", () => switchDefaultLanguage()), - vscode.commands.registerCommand("leetcode.addFavorite", (node: LeetCodeNode) => star.addFavorite(node)), - vscode.commands.registerCommand("leetcode.removeFavorite", (node: LeetCodeNode) => star.removeFavorite(node)), - vscode.commands.registerCommand("leetcode.problems.sort", () => plugin.switchSortingStrategy()), + treeViewController, + window.registerFileDecorationProvider(treeItemDecorationService), + window.createTreeView("leetCodeExplorer", { treeDataProvider: treeDataService, showCollapseAll: true }), + commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()), + commands.registerCommand("leetcode.toggleLeetCodeCn", () => plugin.switchEndpoint()), + commands.registerCommand("leetcode.signin", () => loginContorller.signIn()), + commands.registerCommand("leetcode.signout", () => loginContorller.signOut()), + commands.registerCommand("leetcode.previewProblem", (node: NodeModel) => show.previewProblem(node)), + commands.registerCommand("leetcode.showProblem", (node: NodeModel) => show.showProblem(node)), + commands.registerCommand("leetcode.pickOne", () => show.pickOne()), + commands.registerCommand("leetcode.deleteAllCache", () => show.deleteAllCache()), + commands.registerCommand("leetcode.searchScoreRange", () => show.searchScoreRange()), + commands.registerCommand("leetcode.searchProblem", () => show.searchProblem()), + commands.registerCommand("leetcode.showSolution", (input: NodeModel | Uri) => show.showSolution(input)), + commands.registerCommand("leetcode.refreshExplorer", () => treeDataService.refresh()), + commands.registerCommand("leetcode.testSolution", (uri?: Uri) => test.testSolution(uri)), + commands.registerCommand("leetcode.testSolutionDefault", (uri?: Uri, allCase?: boolean) => test.testSolutionDefault(uri, allCase)), + commands.registerCommand("leetcode.submitSolution", (uri?: Uri) => submit.submitSolution(uri)), + commands.registerCommand("leetcode.switchDefaultLanguage", () => switchDefaultLanguage()), + commands.registerCommand("leetcode.addFavorite", (node: NodeModel) => star.addFavorite(node)), + commands.registerCommand("leetcode.removeFavorite", (node: NodeModel) => star.removeFavorite(node)), + commands.registerCommand("leetcode.problems.sort", () => plugin.switchSortingStrategy()), ); - await leetCodeExecutor.switchEndpoint(plugin.getLeetCodeEndpoint()); - await leetCodeManager.getLoginStatus(); + await executeService.switchEndpoint(plugin.getLeetCodeEndpoint()); + await loginContorller.getLoginStatus(); } catch (error) { logOutput.appendLine(error.toString()); promptForOpenOutputChannel("Extension initialization failed. Please open output channel for details.", DialogType.error); diff --git a/src/manager/StatusBarManager.ts b/src/manager/StatusBarManager.ts deleted file mode 100644 index fe8fc52..0000000 --- a/src/manager/StatusBarManager.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Filename: /home/cc/vscode-leetcode-problem-rating/src/statusbar/StatusBar.ts - * Path: /home/cc/vscode-leetcode-problem-rating - * Created Date: Thursday, October 27th 2022, 7:43:29 pm - * Author: ccagml - * - * Copyright (c) 2022 ccagml . All rights reserved. - */ - -import { ConfigurationChangeEvent, Disposable, workspace, StatusBarItem, window } from "vscode"; -import { UserStatus, userContestRanKingBase } from "../shared"; -import { enableStatusBar } from "../utils/configUtils"; - -// 状态栏工具 -class StatusBarManager implements Disposable { - private instance: StatusBarItem; - private configurationChangeListener: Disposable; - - constructor() { - this.instance = window.createStatusBarItem(); - this.setStatusBarVisibility(); - - this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => { - if (event.affectsConfiguration("leetcode-problem-rating.enableStatusBar")) { - this.setStatusBarVisibility(); - } - }, this); - } - - // 更新状态栏的数据 - public update_instance(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { - switch (status) { - case UserStatus.SignedIn: - if (UserContestInfo && UserContestInfo.attendedContestsCount > 0) { - this.instance.text = `用户: ${user}, 积分: ${Math.floor(UserContestInfo.rating)}, 名次: ${UserContestInfo.localRanking} / ${UserContestInfo.localTotalParticipants} (${UserContestInfo.topPercentage}%), 全部名次: ${UserContestInfo.globalRanking} / ${UserContestInfo.globalTotalParticipants}`; - } else { - this.instance.text = `user: ${user}`; - } - break; - case UserStatus.SignedOut: - default: - this.instance.text = ""; - break; - } - } - - - // 更新数据 - public update(status: UserStatus, user?: string, UserContestInfo?: userContestRanKingBase | undefined): void { - this.update_instance(status, user, UserContestInfo); - } - - //销毁数据 - public dispose(): void { - this.instance.dispose(); - this.configurationChangeListener.dispose(); - } - - // 设置可见性 - private setStatusBarVisibility(): void { - if (enableStatusBar()) { - this.instance.show(); - } else { - this.instance.hide(); - } - } - -} - -export const statusBarManager: StatusBarManager = new StatusBarManager(); diff --git a/src/shared.ts b/src/model/Model.ts similarity index 90% rename from src/shared.ts rename to src/model/Model.ts index 37ce32e..73d55ba 100644 --- a/src/shared.ts +++ b/src/model/Model.ts @@ -1,9 +1,16 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/model/Model.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ -import * as vscode from "vscode"; -export interface IQuickItemEx extends vscode.QuickPickItem { +import { ViewColumn, QuickPickItem } from "vscode"; + +export interface IQuickItemEx extends QuickPickItem { value: T; } @@ -227,3 +234,10 @@ export interface ISubmitEvent { sub_type: string; // test submit accepted: boolean } + + +export interface IWebViewOption { + title: string; + viewColumn: ViewColumn; + preserveFocus?: boolean; +} diff --git a/src/explorer/LeetCodeNode.ts b/src/model/NodeModel.ts similarity index 91% rename from src/explorer/LeetCodeNode.ts rename to src/model/NodeModel.ts index 821517e..7badcd2 100644 --- a/src/explorer/LeetCodeNode.ts +++ b/src/model/NodeModel.ts @@ -1,10 +1,17 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/model/NodeMOdel.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import { Command, Uri } from "vscode"; -import { IProblem, IScoreData, ITodayData, ProblemState, RootNodeSort } from "../shared"; +import { IProblem, IScoreData, ITodayData, ProblemState, RootNodeSort } from "./Model"; -export class LeetCodeNode { +export class NodeModel { private _u_score; constructor(private data: IProblem, private isProblemNode: boolean = true, userscore: number = 0) { this._u_score = userscore; diff --git a/src/service/EventService.ts b/src/service/EventService.ts new file mode 100644 index 0000000..c6de191 --- /dev/null +++ b/src/service/EventService.ts @@ -0,0 +1,49 @@ +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/service/EventService.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, November 10th 2022, 3:14:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + + + +import { EventEmitter } from "events"; + + +import { UserStatus } from "../model/Model"; +import { ISubmitEvent } from "../model/Model"; +import { statusBarService } from "../service/StatusBarService"; +import { treeDataService } from "../service/TreeDataService"; + +class EventService extends EventEmitter { + + constructor() { + super(); + } + + /** + * 监听事件 + */ + public add_event() { + this.on("statusChanged", (userStatus: UserStatus, userName?: string) => { + statusBarService.update_status(userStatus, userName); + statusBarService.update(); + treeDataService.cleanUserScore(); + treeDataService.refresh(); + }); + this.on("submit", (e: ISubmitEvent) => { + treeDataService.checkSubmit(e); + }); + + this.on("searchUserContest", (tt) => { + statusBarService.update_UserContestInfo(tt) + statusBarService.update(); + treeDataService.refresh() + }); + } +} + +export const eventService: EventService = new EventService(); + diff --git a/src/leetCodeExecutor.ts b/src/service/ExecuteService.ts similarity index 94% rename from src/leetCodeExecutor.ts rename to src/service/ExecuteService.ts index d1b5604..de1ced1 100644 --- a/src/leetCodeExecutor.ts +++ b/src/service/ExecuteService.ts @@ -1,5 +1,12 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/service/executeService.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Monday, October 31st 2022, 10:16:47 am + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import * as cp from "child_process"; import * as fse from "fs-extra"; @@ -7,13 +14,13 @@ import * as os from "os"; import * as path from "path"; import { ExtensionContext } from "vscode"; import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace, WorkspaceConfiguration } from "vscode"; -import { Endpoint, IProblem, leetcodeHasInited } from "./shared"; -import { executeCommand, executeCommandWithProgress } from "./utils/cliUtils"; -import { DialogOptions, openUrl } from "./utils/uiUtils"; -import * as wsl from "./utils/wslUtils"; -import { toWslPath, useWsl } from "./utils/wslUtils"; +import { Endpoint, IProblem, leetcodeHasInited } from "../model/Model"; +import { executeCommand, executeCommandWithProgress } from "../utils/cliUtils"; +import { DialogOptions, openUrl } from "../utils/uiUtils"; +import * as wsl from "../utils/wslUtils"; +import { toWslPath, useWsl } from "../utils/wslUtils"; -class LeetCodeExecutor implements Disposable { +class ExecuteService implements Disposable { private leetCodeCliResourcesRootPath: string; private leetCodeCliRootPath: string; private nodeExecutable: string; @@ -274,4 +281,4 @@ class LeetCodeExecutor implements Disposable { } -export const leetCodeExecutor: LeetCodeExecutor = new LeetCodeExecutor(); +export const executeService: ExecuteService = new ExecuteService(); diff --git a/src/webview/leetCodePreviewProvider.ts b/src/service/PreviewService.ts similarity index 86% rename from src/webview/leetCodePreviewProvider.ts rename to src/service/PreviewService.ts index 78b4099..289fb61 100644 --- a/src/webview/leetCodePreviewProvider.ts +++ b/src/service/PreviewService.ts @@ -1,13 +1,20 @@ -// Copyright (c) jdneo. All rights reserved. -// Licensed under the MIT license. +/* + * Filename: /home/cc/vscode-leetcode-problem-rating/src/service/previewService.ts + * Path: /home/cc/vscode-leetcode-problem-rating + * Created Date: Thursday, October 27th 2022, 7:43:29 pm + * Author: ccagml + * + * Copyright (c) 2022 ccagml . All rights reserved. + */ + import { commands, ViewColumn } from "vscode"; import { getLeetCodeEndpoint } from "../commands/plugin"; -import { Endpoint, IProblem } from "../shared"; -import { ILeetCodeWebviewOption, LeetCodeWebview } from "./LeetCodeWebview"; -import { markdownEngine } from "./markdownEngine"; +import { Endpoint, IProblem, IWebViewOption } from "../model/Model"; +import { BaseWebViewService } from "./baseWebviewService"; +import { markdownService } from "./markdownService"; -class LeetCodePreviewProvider extends LeetCodeWebview { +class PreviewService extends BaseWebViewService { protected readonly viewType: string = "leetcode.preview"; private node: IProblem; @@ -30,7 +37,7 @@ class LeetCodePreviewProvider extends LeetCodeWebview { // } } - protected getWebviewOption(): ILeetCodeWebviewOption { + protected getWebviewOption(): IWebViewOption { if (!this.sideMode) { return { title: `${this.node.name}: Preview`, @@ -72,8 +79,8 @@ class LeetCodePreviewProvider extends LeetCodeWebview { `, }; const { title, url, category, difficulty, likes, dislikes, body } = this.description; - const head: string = markdownEngine.render(`# [${title}](${url})`); - const info: string = markdownEngine.render([ + const head: string = markdownService.render(`# [${title}](${url})`); + const info: string = markdownService.render([ `| Category | Difficulty | Likes | Dislikes |`, `| :------: | :--------: | :---: | :------: |`, `| ${category} | ${difficulty} | ${likes} | ${dislikes} |`, @@ -81,7 +88,7 @@ class LeetCodePreviewProvider extends LeetCodeWebview { const tags: string = [ `
`, `Tags`, - markdownEngine.render( + markdownService.render( this.description.tags .map((t: string) => `[\`${t}\`](https://leetcode.com/tag/${t})`) .join(" | "), @@ -91,20 +98,20 @@ class LeetCodePreviewProvider extends LeetCodeWebview { const companies: string = [ `
`, `Companies`, - markdownEngine.render( + markdownService.render( this.description.companies .map((c: string) => `\`${c}\``) .join(" | "), ), `
`, ].join("\n"); - const links: string = markdownEngine.render(`[Discussion](${this.getDiscussionLink(url)}) | [Solution](${this.getSolutionLink(url)})`); + const links: string = markdownService.render(`[Discussion](${this.getDiscussionLink(url)}) | [Solution](${this.getSolutionLink(url)})`); return ` - ${markdownEngine.getStyles()} + ${markdownService.getStyles()} ${!this.sideMode ? button.style : ""}