Skip to content

Commit e920316

Browse files
authored
refactor: Extract explorer cache related code (LeetCode-OpenSource#301)
1 parent de5f70d commit e920316

File tree

4 files changed

+203
-165
lines changed

4 files changed

+203
-165
lines changed

src/explorer/LeetCodeNode.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { Command } from "vscode";
55
import { IProblem, ProblemState } from "../shared";
66

77
export class LeetCodeNode {
8-
constructor(private data: IProblem, private parentNodeName: string, private isProblemNode: boolean = true) { }
8+
9+
constructor(private data: IProblem, private isProblemNode: boolean = true) { }
910

1011
public get locked(): boolean {
1112
return this.data.locked;
@@ -46,10 +47,6 @@ export class LeetCodeNode {
4647
return this.isProblemNode;
4748
}
4849

49-
public get parentName(): string {
50-
return this.parentNodeName;
51-
}
52-
5350
public get previewCommand(): Command {
5451
return {
5552
title: "Preview Problem",
Lines changed: 21 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,24 @@
11
// Copyright (c) jdneo. All rights reserved.
22
// Licensed under the MIT license.
33

4-
import * as _ from "lodash";
54
import * as os from "os";
65
import * as path from "path";
76
import * as vscode from "vscode";
8-
import * as list from "../commands/list";
9-
import { leetCodeChannel } from "../leetCodeChannel";
107
import { leetCodeManager } from "../leetCodeManager";
11-
import { Category, defaultProblem, IProblem, ProblemState } from "../shared";
12-
import { getWorkspaceConfiguration } from "../utils/workspaceUtils";
8+
import { Category, defaultProblem, ProblemState } from "../shared";
9+
import { explorerNodeManager } from "./explorerNodeManager";
1310
import { LeetCodeNode } from "./LeetCodeNode";
1411

1512
export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCodeNode> {
1613

17-
private treeData: {
18-
Difficulty: Map<string, IProblem[]>,
19-
Tag: Map<string, IProblem[]>,
20-
Company: Map<string, IProblem[]>,
21-
Favorite: IProblem[],
22-
};
23-
2414
private onDidChangeTreeDataEvent: vscode.EventEmitter<any> = new vscode.EventEmitter<any>();
2515
// tslint:disable-next-line:member-ordering
2616
public readonly onDidChangeTreeData: vscode.Event<any> = this.onDidChangeTreeDataEvent.event;
2717

2818
constructor(private context: vscode.ExtensionContext) { }
2919

3020
public async refresh(): Promise<void> {
31-
await this.getProblemData();
21+
await explorerNodeManager.refreshCache();
3222
this.onDidChangeTreeDataEvent.fire();
3323
}
3424

@@ -49,7 +39,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
4939
return {
5040
label: element.isProblem ? `[${element.id}] ${element.name}` : element.name,
5141
tooltip: this.getSubCategoryTooltip(element),
52-
id: `${idPrefix}.${element.parentName}.${element.id}`,
42+
id: `${idPrefix}.${element.id}`,
5343
collapsibleState: element.isProblem ? vscode.TreeItemCollapsibleState.None : vscode.TreeItemCollapsibleState.Collapsed,
5444
contextValue: element.isProblem ? "problem" : element.id.toLowerCase(),
5545
iconPath: this.parseIconPathFromProblemState(element),
@@ -63,91 +53,28 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
6353
new LeetCodeNode(Object.assign({}, defaultProblem, {
6454
id: "notSignIn",
6555
name: "Sign in to LeetCode",
66-
}), "ROOT", false),
56+
}), false),
6757
];
6858
}
6959
if (!element) { // Root view
70-
return [
71-
new LeetCodeNode(Object.assign({}, defaultProblem, {
72-
id: Category.Difficulty,
73-
name: Category.Difficulty,
74-
}), "ROOT", false),
75-
new LeetCodeNode(Object.assign({}, defaultProblem, {
76-
id: Category.Tag,
77-
name: Category.Tag,
78-
}), "ROOT", false),
79-
new LeetCodeNode(Object.assign({}, defaultProblem, {
80-
id: Category.Company,
81-
name: Category.Company,
82-
}), "ROOT", false),
83-
new LeetCodeNode(Object.assign({}, defaultProblem, {
84-
id: Category.Favorite,
85-
name: Category.Favorite,
86-
}), "ROOT", false),
87-
];
60+
return explorerNodeManager.getRootNodes();
8861
} else {
89-
switch (element.name) { // First-level
62+
switch (element.id) { // First-level
9063
case Category.Favorite:
91-
const nodes: IProblem[] = this.treeData[Category.Favorite];
92-
return nodes.map((p: IProblem) => new LeetCodeNode(p, Category.Favorite));
64+
return explorerNodeManager.getFavoriteNodes();
9365
case Category.Difficulty:
66+
return explorerNodeManager.getAllDifficultyNodes();
9467
case Category.Tag:
68+
return explorerNodeManager.getAllTagNodes();
9569
case Category.Company:
96-
return this.composeSubCategoryNodes(element);
97-
default: // Second and lower levels
98-
return element.isProblem ? [] : this.composeProblemNodes(element);
99-
}
100-
}
101-
}
102-
103-
private async getProblemData(): Promise<void> {
104-
// clear cache
105-
this.treeData = {
106-
Difficulty: new Map<string, IProblem[]>(),
107-
Tag: new Map<string, IProblem[]>(),
108-
Company: new Map<string, IProblem[]>(),
109-
Favorite: [],
110-
};
111-
for (const problem of await list.listProblems()) {
112-
// Add favorite problem, no matter whether it is solved.
113-
if (problem.isFavorite) {
114-
this.treeData[Category.Favorite].push(problem);
115-
}
116-
// Hide solved problem in other category.
117-
if (problem.state === ProblemState.AC && getWorkspaceConfiguration().get<boolean>("hideSolved")) {
118-
continue;
70+
return explorerNodeManager.getAllCompanyNodes();
71+
default:
72+
if (element.isProblem) {
73+
return [];
74+
}
75+
return explorerNodeManager.getChildrenNodesById(element.id);
11976
}
120-
121-
this.addProblemToTreeData(problem);
122-
}
123-
}
124-
125-
private composeProblemNodes(node: LeetCodeNode): LeetCodeNode[] {
126-
const map: Map<string, IProblem[]> | undefined = this.treeData[node.parentName];
127-
if (!map) {
128-
leetCodeChannel.appendLine(`Category: ${node.parentName} is not available.`);
129-
return [];
130-
}
131-
const problems: IProblem[] = map.get(node.name) || [];
132-
const problemNodes: LeetCodeNode[] = [];
133-
for (const problem of problems) {
134-
problemNodes.push(new LeetCodeNode(problem, node.name));
13577
}
136-
return problemNodes;
137-
}
138-
139-
private composeSubCategoryNodes(node: LeetCodeNode): LeetCodeNode[] {
140-
const category: Category = node.name as Category;
141-
if (category === Category.Favorite) {
142-
leetCodeChannel.appendLine("No sub-level for Favorite nodes");
143-
return [];
144-
}
145-
const map: Map<string, IProblem[]> | undefined = this.treeData[category];
146-
if (!map) {
147-
leetCodeChannel.appendLine(`Category: ${category} is not available.`);
148-
return [];
149-
}
150-
return this.getSubCategoryNodes(map, category);
15178
}
15279

15380
private parseIconPathFromProblemState(element: LeetCodeNode): string {
@@ -171,16 +98,16 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
17198

17299
private getSubCategoryTooltip(element: LeetCodeNode): string {
173100
// return '' unless it is a sub-category node
174-
if (element.isProblem || !this.treeData[element.parentName]) {
101+
if (element.isProblem || element.id === "ROOT" || element.id in Category) {
175102
return "";
176103
}
177104

178-
const problems: IProblem[] = this.treeData[element.parentName].get(element.id);
105+
const childernNodes: LeetCodeNode[] = explorerNodeManager.getChildrenNodesById(element.id);
179106

180107
let acceptedNum: number = 0;
181108
let failedNum: number = 0;
182-
for (const prob of problems) {
183-
switch (prob.state) {
109+
for (const node of childernNodes) {
110+
switch (node.state) {
184111
case ProblemState.AC:
185112
acceptedNum++;
186113
break;
@@ -195,73 +122,7 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod
195122
return [
196123
`AC: ${acceptedNum}`,
197124
`Failed: ${failedNum}`,
198-
`Total: ${problems.length}`,
125+
`Total: ${childernNodes.length}`,
199126
].join(os.EOL);
200127
}
201-
202-
private addProblemToTreeData(problem: IProblem): void {
203-
this.putProblemToMap(this.treeData.Difficulty, problem.difficulty, problem);
204-
for (const tag of problem.tags) {
205-
this.putProblemToMap(this.treeData.Tag, _.startCase(tag), problem);
206-
}
207-
for (const company of problem.companies) {
208-
this.putProblemToMap(this.treeData.Company, _.startCase(company), problem);
209-
}
210-
}
211-
212-
private putProblemToMap(map: Map<string, IProblem[]>, key: string, problem: IProblem): void {
213-
const problems: IProblem[] | undefined = map.get(key);
214-
if (problems) {
215-
problems.push(problem);
216-
} else {
217-
map.set(key, [problem]);
218-
}
219-
}
220-
221-
private getSubCategoryNodes(map: Map<string, IProblem[]>, category: Category): LeetCodeNode[] {
222-
const subCategoryNodes: LeetCodeNode[] = Array.from(map.keys()).map((subCategory: string) => {
223-
return new LeetCodeNode(Object.assign({}, defaultProblem, {
224-
id: subCategory,
225-
name: subCategory,
226-
}), category.toString(), false);
227-
});
228-
this.sortSubCategoryNodes(subCategoryNodes, category);
229-
return subCategoryNodes;
230-
}
231-
232-
private sortSubCategoryNodes(subCategoryNodes: LeetCodeNode[], category: Category): void {
233-
switch (category) {
234-
case Category.Difficulty:
235-
subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
236-
function getValue(input: LeetCodeNode): number {
237-
switch (input.name.toLowerCase()) {
238-
case "easy":
239-
return 1;
240-
case "medium":
241-
return 2;
242-
case "hard":
243-
return 3;
244-
default:
245-
return Number.MAX_SAFE_INTEGER;
246-
}
247-
}
248-
return getValue(a) - getValue(b);
249-
});
250-
break;
251-
case Category.Tag:
252-
case Category.Company:
253-
subCategoryNodes.sort((a: LeetCodeNode, b: LeetCodeNode): number => {
254-
if (a.name === "Unknown") {
255-
return 1;
256-
} else if (b.name === "Unknown") {
257-
return -1;
258-
} else {
259-
return Number(a.name > b.name) - Number(a.name < b.name);
260-
}
261-
});
262-
break;
263-
default:
264-
break;
265-
}
266-
}
267128
}

0 commit comments

Comments
 (0)
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