diff --git a/src/explorer/LeetCodeNode.ts b/src/explorer/LeetCodeNode.ts index 3f685b70..67aad324 100644 --- a/src/explorer/LeetCodeNode.ts +++ b/src/explorer/LeetCodeNode.ts @@ -5,7 +5,8 @@ import { Command } from "vscode"; import { IProblem, ProblemState } from "../shared"; export class LeetCodeNode { - constructor(private data: IProblem, private parentNodeName: string, private isProblemNode: boolean = true) { } + + constructor(private data: IProblem, private isProblemNode: boolean = true) { } public get locked(): boolean { return this.data.locked; @@ -46,10 +47,6 @@ export class LeetCodeNode { return this.isProblemNode; } - public get parentName(): string { - return this.parentNodeName; - } - public get previewCommand(): Command { return { title: "Preview Problem", diff --git a/src/explorer/LeetCodeTreeDataProvider.ts b/src/explorer/LeetCodeTreeDataProvider.ts index 09f47530..c04346d6 100644 --- a/src/explorer/LeetCodeTreeDataProvider.ts +++ b/src/explorer/LeetCodeTreeDataProvider.ts @@ -1,26 +1,16 @@ // Copyright (c) jdneo. All rights reserved. // Licensed under the MIT license. -import * as _ from "lodash"; import * as os from "os"; import * as path from "path"; import * as vscode from "vscode"; -import * as list from "../commands/list"; -import { leetCodeChannel } from "../leetCodeChannel"; import { leetCodeManager } from "../leetCodeManager"; -import { Category, defaultProblem, IProblem, ProblemState } from "../shared"; -import { getWorkspaceConfiguration } from "../utils/workspaceUtils"; +import { Category, defaultProblem, ProblemState } from "../shared"; +import { explorerNodeManager } from "./explorerNodeManager"; import { LeetCodeNode } from "./LeetCodeNode"; export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider { - private treeData: { - Difficulty: Map, - Tag: Map, - Company: Map, - Favorite: IProblem[], - }; - private onDidChangeTreeDataEvent: vscode.EventEmitter = new vscode.EventEmitter(); // tslint:disable-next-line:member-ordering public readonly onDidChangeTreeData: vscode.Event = this.onDidChangeTreeDataEvent.event; @@ -28,7 +18,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider { - await this.getProblemData(); + await explorerNodeManager.refreshCache(); this.onDidChangeTreeDataEvent.fire(); } @@ -49,7 +39,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider new LeetCodeNode(p, Category.Favorite)); + return explorerNodeManager.getFavoriteNodes(); case Category.Difficulty: + return explorerNodeManager.getAllDifficultyNodes(); case Category.Tag: + return explorerNodeManager.getAllTagNodes(); case Category.Company: - return this.composeSubCategoryNodes(element); - default: // Second and lower levels - return element.isProblem ? [] : this.composeProblemNodes(element); - } - } - } - - private async getProblemData(): Promise { - // clear cache - this.treeData = { - Difficulty: new Map(), - Tag: new Map(), - Company: new Map(), - Favorite: [], - }; - for (const problem of await list.listProblems()) { - // Add favorite problem, no matter whether it is solved. - if (problem.isFavorite) { - this.treeData[Category.Favorite].push(problem); - } - // Hide solved problem in other category. - if (problem.state === ProblemState.AC && getWorkspaceConfiguration().get("hideSolved")) { - continue; + return explorerNodeManager.getAllCompanyNodes(); + default: + if (element.isProblem) { + return []; + } + return explorerNodeManager.getChildrenNodesById(element.id); } - - this.addProblemToTreeData(problem); - } - } - - private composeProblemNodes(node: LeetCodeNode): LeetCodeNode[] { - const map: Map | undefined = this.treeData[node.parentName]; - if (!map) { - leetCodeChannel.appendLine(`Category: ${node.parentName} is not available.`); - return []; - } - const problems: IProblem[] = map.get(node.name) || []; - const problemNodes: LeetCodeNode[] = []; - for (const problem of problems) { - problemNodes.push(new LeetCodeNode(problem, node.name)); } - return problemNodes; - } - - private composeSubCategoryNodes(node: LeetCodeNode): LeetCodeNode[] { - const category: Category = node.name as Category; - if (category === Category.Favorite) { - leetCodeChannel.appendLine("No sub-level for Favorite nodes"); - return []; - } - const map: Map | undefined = this.treeData[category]; - if (!map) { - leetCodeChannel.appendLine(`Category: ${category} is not available.`); - return []; - } - return this.getSubCategoryNodes(map, category); } private parseIconPathFromProblemState(element: LeetCodeNode): string { @@ -171,16 +98,16 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider, key: string, problem: IProblem): void { - const problems: IProblem[] | undefined = map.get(key); - if (problems) { - problems.push(problem); - } else { - map.set(key, [problem]); - } - } - - private getSubCategoryNodes(map: Map, category: Category): LeetCodeNode[] { - const subCategoryNodes: LeetCodeNode[] = Array.from(map.keys()).map((subCategory: string) => { - return new LeetCodeNode(Object.assign({}, defaultProblem, { - id: subCategory, - name: subCategory, - }), category.toString(), false); - }); - this.sortSubCategoryNodes(subCategoryNodes, category); - return subCategoryNodes; - } - - private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void { - switch (category) { - case Category.Difficulty: - subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { - function getValue(input: LeetCodeNode): number { - switch (input.name.toLowerCase()) { - case "easy": - return 1; - case "medium": - return 2; - case "hard": - return 3; - default: - return Number.MAX_SAFE_INTEGER; - } - } - return getValue(a) - getValue(b); - }); - break; - case Category.Tag: - case Category.Company: - subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { - if (a.name === "Unknown") { - return 1; - } else if (b.name === "Unknown") { - return -1; - } else { - return Number(a.name > b.name) - Number(a.name < b.name); - } - }); - break; - default: - break; - } - } } diff --git a/src/explorer/explorerNodeManager.ts b/src/explorer/explorerNodeManager.ts new file mode 100644 index 00000000..dcf1cc09 --- /dev/null +++ b/src/explorer/explorerNodeManager.ts @@ -0,0 +1,178 @@ +// Copyright (c) jdneo. All rights reserved. +// Licensed under the MIT license. + +import * as _ from "lodash"; +import { Disposable } from "vscode"; +import * as list from "../commands/list"; +import { Category, defaultProblem } from "../shared"; +import { LeetCodeNode } from "./LeetCodeNode"; + +class ExplorerNodeManager implements Disposable { + private explorerNodeMap: Map = new Map(); + private companySet: Set = new Set(); + private tagSet: Set = new Set(); + + public async refreshCache(): Promise { + this.dispose(); + for (const problem of await list.listProblems()) { + this.explorerNodeMap.set(problem.id, new LeetCodeNode(problem)); + for (const company of problem.companies) { + this.companySet.add(company); + } + for (const tag of problem.tags) { + this.tagSet.add(tag); + } + } + } + + public getRootNodes(): LeetCodeNode[] { + return [ + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Difficulty, + name: Category.Difficulty, + }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Tag, + name: Category.Tag, + }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Company, + name: Category.Company, + }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Favorite, + name: Category.Favorite, + }), false), + ]; + } + + public getAllDifficultyNodes(): LeetCodeNode[] { + const res: LeetCodeNode[] = []; + res.push( + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: `${Category.Difficulty}.Easy`, + name: "Easy", + }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: `${Category.Difficulty}.Medium`, + name: "Medium", + }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: `${Category.Difficulty}.Hard`, + name: "Hard", + }), false), + ); + this.sortSubCategoryNodes(res, Category.Difficulty); + return res; + } + + public getAllCompanyNodes(): LeetCodeNode[] { + const res: LeetCodeNode[] = []; + for (const company of this.companySet.values()) { + res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + id: `${Category.Company}.${company}`, + name: _.startCase(company), + }), false)); + } + this.sortSubCategoryNodes(res, Category.Company); + return res; + } + + public getAllTagNodes(): LeetCodeNode[] { + const res: LeetCodeNode[] = []; + for (const tag of this.tagSet.values()) { + res.push(new LeetCodeNode(Object.assign({}, defaultProblem, { + id: `${Category.Tag}.${tag}`, + name: _.startCase(tag), + }), false)); + } + this.sortSubCategoryNodes(res, Category.Tag); + return res; + } + + public getNodeById(id: string): LeetCodeNode | undefined { + return this.explorerNodeMap.get(id); + } + + public getFavoriteNodes(): LeetCodeNode[] { + const res: LeetCodeNode[] = []; + for (const node of this.explorerNodeMap.values()) { + if (node.isFavorite) { + res.push(node); + } + } + return res; + } + + public getChildrenNodesById(id: string): LeetCodeNode[] { + // The sub-category node's id is named as {Category.SubName} + const metaInfo: string[] = id.split("."); + const res: LeetCodeNode[] = []; + for (const node of this.explorerNodeMap.values()) { + switch (metaInfo[0]) { + case Category.Company: + if (node.companies.indexOf(metaInfo[1]) >= 0) { + res.push(node); + } + break; + case Category.Difficulty: + if (node.difficulty === metaInfo[1]) { + res.push(node); + } + break; + case Category.Tag: + if (node.tags.indexOf(metaInfo[1]) >= 0) { + res.push(node); + } + break; + default: + break; + } + } + return res; + } + + public dispose(): void { + this.explorerNodeMap.clear(); + this.companySet.clear(); + this.tagSet.clear(); + } + + private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void { + switch (category) { + case Category.Difficulty: + subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { + function getValue(input: LeetCodeNode): number { + switch (input.name.toLowerCase()) { + case "easy": + return 1; + case "medium": + return 2; + case "hard": + return 3; + default: + return Number.MAX_SAFE_INTEGER; + } + } + return getValue(a) - getValue(b); + }); + break; + case Category.Tag: + case Category.Company: + subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => { + if (a.name === "Unknown") { + return 1; + } else if (b.name === "Unknown") { + return -1; + } else { + return Number(a.name > b.name) - Number(a.name < b.name); + } + }); + break; + default: + break; + } + } +} + +export const explorerNodeManager: ExplorerNodeManager = new ExplorerNodeManager(); diff --git a/src/extension.ts b/src/extension.ts index 877ff90c..2ebefd9b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,6 +10,7 @@ import * as session from "./commands/session"; import * as show from "./commands/show"; 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 { leetCodeChannel } from "./leetCodeChannel"; @@ -44,6 +45,7 @@ export async function activate(context: vscode.ExtensionContext): Promise leetCodeExecutor, markdownEngine, codeLensController, + explorerNodeManager, vscode.window.createTreeView("leetCodeExplorer", { treeDataProvider: leetCodeTreeDataProvider, showCollapseAll: true }), vscode.commands.registerCommand("leetcode.deleteCache", () => cache.deleteCache()), vscode.commands.registerCommand("leetcode.toggleLeetCodeCn", () => plugin.switchEndpoint()), pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy