- Notifications
You must be signed in to change notification settings - Fork670
Enhanced Tree view#94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
(from direct import of leetcode-cli company plugin)
Add unknown label to companies and tags
@Vigilans Thank you for contribution. I will look it later. Also noticed that there are some lint errors according to the CI output, would you mind to fix them first? |
Vigilans commentedJan 23, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The lint errors have been fixed. Note: A default object is used to define // tslint:disable-next-line:typedefexportconstIProblemDefault={favorite:false,locked:false,state:ProblemState.Unknown,id:"",name:"",difficulty:"",passRate:"",companies:[]asstring[],tags:[]asstring[],};exporttypeIProblem=typeofIProblemDefault; The default object is then used to create a new newLeetCodeNode(Object.assign({},list.IProblemDefault,{id:"Root",// parent node namename:"Tag",// current node name}),false), |
Hi@Vigilans, Is there any reason to add accepted/not accepted categories into the explorer? |
Vigilans commentedJan 24, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The Not-AC category shows problems which are submitted but not accepted. If you think them not necessary, I will try to revert this commit. |
Hmm, I think it's a little bit redundant somehow. I better approach might be: having an extension setting that specifies if the explorer will only show unresolved problems or all the problems, then this setting will apply to all the categories. To retrieving all accepted codes, this can be another action in the explorer context menu, which is another story. |
This reverts commit7e00062.
twchn commentedJan 24, 2019
Vigilans commentedJan 24, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
I see. Btw, there are some other changes I plan to contribute, maybe I should open another issue to query you for your opinions_(눈_ 눈」∠)_ |
@taoweicn I will work on this feature later. |
twchn commentedJan 24, 2019
👍 very thankful. |
@Vigilans Contributions are welcome! 👍 Yes Let's open issues and discuss the implementation there first before we create a PR. 😄 |
@Vigilans Could you please send another PR about hiding solved problems? A PR contains several issue fixes will make it too large to review |
@jdneo The |
src/commands/list.ts Outdated
tags: [] as string[], | ||
}; | ||
export type IProblem = typeof IProblemDefault; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
It would be better to put theIProblem
definition andIProblemDefault
to other places instead of in this file.
Let's put them intoshared.ts
, I'll refactor this part later.
src/leetCodeExecutor.ts Outdated
@@ -2,6 +2,7 @@ | |||
// Licensed under the MIT license. | |||
import * as cp from "child_process"; | |||
import * as fs from "fs"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Usefs-extra
src/leetCodeExecutor.ts Outdated
public async getCompaniesAndTags(): Promise<{ companies: { [key: string]: string[] }, tags: { [key: string]: string[] } }> { | ||
// preprocess the plugin source | ||
const componiesTagsPath: string = path.join(await leetCodeExecutor.getLeetCodeRootPath(), "lib", "plugins", "company.js"); | ||
const componiesTagsSrc: string = (await fs.readFileSync(componiesTagsPath, "utf8")).replace( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We can usereadFile
fromfs-extra
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Something went wrong with my usage.fs-extra
is correct.
src/leetCodeExecutor.ts Outdated
"module.exports = { COMPONIES, TAGS }", | ||
); | ||
// require plugin from modified string | ||
const requireFromString: (src: string, path: string) => any = require("require-from-string"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Can we import the module?
For example,npm i --save-dev @types/require-from-string
Then import it instead of using require
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Yeah, thedefinitelyTyped
indeed provides type forrequire-from-string
.import * as requireFromString from "require-from-string";
successfully worked.
src/leetCodeExplorer.ts Outdated
@@ -7,6 +7,8 @@ import * as list from "./commands/list"; | |||
import { leetCodeManager } from "./leetCodeManager"; | |||
import { ProblemState } from "./shared"; | |||
export type Category = "Difficulty" | "Tag" | "Company"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Can we use enum instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
TheLeetCodeTreeDataProvider.treeData
needs the type semantic fromCategory
to preserve the type hint, whereas enum just provides the value semantic.
Without the string union type,this line won't get proper type hint:
constproblems:list.IProblem[]|undefined=this.treeData[parent].get(subCategory);
this.treeData[parent]
will returnany
type.
If we changeCategory
to enum type, then the above line should be rewritten to:
this.treeData[parent.toString()as"Difficulty"|"Tag"|"Company"]
which falls back to where it starts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Have you tried this:
exportenumCategory{Difficulty="Difficulty",Tag="Tag",Company="Company",}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
After trying,Category.Tag.toString()
only returns typestring
.
There is no one-line way to get the type hint here, reference:
https://stackoverflow.com/questions/52370544/parse-string-as-typescript-enum/
https://stackoverflow.com/questions/52393730/typescript-string-literal-union-type-from-enum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
No need to call.toString()
here.
Whenever you want to use the Category value as a string, just usingCategory.xxxx
.
By doing this, you will get the value as a string meanwhile keep the typedef.
I tried using enum here and everything works fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Let's make theCategory
enum type:
exportenumCategory{Difficulty="Difficulty",Tag="Tag",Company="Company",}
Then rewriteline 147 this way:
constcategories:Map<Category,string[]>=newMap<Category,string[]>([[Category.Difficulty,[problem.difficulty]],[Category.Tag,problem.tags],[Category.Company,problem.companies],]);
Follows the iteration:
for(const[parent,children]ofcategories){for(letsubCategoryofchildren){
Here,typeof parent
isCategory
:
Continues theline 156:
constproblems:list.IProblem[]|undefined=this.treeData[parent].get(subCategory);
Sincetypeof parent
isCategory
andthis.treeData
's key type isstring
,get
's type could not be deduced from the usage, and there's no way to useCategory.xxxx
here:
Meanwhile, we couldn't changethis.treeData
type toMap<Category, Map<string, list.IProblem[]>>
since there is a fieldFavorite
which doesn't processed asCategory
and its value type islist.IProblem[]
.
If you insist to use enum here, a workaround could be:
private treeData:{[Category.Difficulty]:Map<string,list.IProblem[]>,[Category.Tag]:Map<string,list.IProblem[]>,[Category.Company]:Map<string,list.IProblem[]>,Favorite:list.IProblem[],};
Nowget
's type could be deduced properly:
Yet I think it complicates what could have been an easy and elegant solution in Typescript.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We need to write more hard-coded strings if using string union here while using enum can get rid of this. That's the reason I prefer using enum here: make the code easier to maintain in the future.
There are many ways to get rid of the special fieldFavorite
. One simple way to do a simple check before getting the map. TS will help us to infer the type during compilation.
src/leetCodeExplorer.ts Outdated
Company: new Map(), | ||
Favorite: [], | ||
}; | ||
for (const problem of await list.listProblems()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I'm thinking that we can filter the accepted problems in the methodlist.listProblems()
. IfhideSolved === true
then only return unaccepted problems.
By doing this, we decouple thethis.leetCodeConfig
with the explorer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
In my opinion,Favorite
group should show all starred problems no matter whether it's accepted or not.
Maybe it could be checked this way inlist.listProblems()
:!problem.favorite && problem.state === ProblemState.AC && hideSolved
->continue
The flaw is that the favorite checking logic is duplicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Hmm, ok, just keep it there first.
src/leetCodeExplorer.ts Outdated
continue; | ||
} | ||
// Add problems according to category | ||
const categories: Array<[Category, string[]]> = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Can we use Map here?
use index to represent theparent-children
relationship is confusing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
We could use Map here this way:
constcategories:Map<Category,string[]>=newMap<Category,string[]>([["Difficulty",[problem.difficulty]],["Tag",problem.tags],["Company",problem.companies],]);
Btw, a better way would be to useObject.entries
here, but it is not supported by es6, which is specified bytsconfig.json
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Let's use Map here.
src/leetCodeExplorer.ts Outdated
for (const [parent, children] of categories) { | ||
for (let subCategory of children) { | ||
// map 'first-second' to 'First Second' | ||
subCategory = subCategory.split("-").map((c: string) => c[0].toUpperCase() + c.slice(1)).join(" "); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
first-second
is not that bad.
Cuz current logic could handlea-b
but nota-b-c
Just leavefirst-second
as it is for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
What doesa-b-c
refer to? The code here could transformbreadth-first-search
toBreadth First Search
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
My bad, it's fine.
src/leetCodeExplorer.ts Outdated
@@ -64,57 +73,100 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider<LeetCod | |||
} | |||
const idPrefix: number = Date.now(); | |||
return { | |||
return { // element.id -> parent node name, element.name -> node name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Why we save parent node name intoelement.id
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
There should be some field to store the parent node name when it is not problem node...since in previous commits you simply setnode.id
andnode.name
the same value, I decided to reuse theid
field to represent some other value.
The reasons for the necessity of parent node name are:
- We should be able to retrieve data from the
LeetCodeTreeDataProvider.treeData
. - One problem will now be added as
LeetCodeNode
at least 3 times(inDifficulty
,Tag
andCompany
), we should be able to distinguish them, hence the following naming rule:
id:`${idPrefix}.${element.id}.${element.name}`,
(idPrefix = Date.now()
just returns same value throughout initialization process)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe we could add a filed in theLeetCodeNode
called 'parentName' to store the parent node info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Will review later
jdneo commentedFeb 2, 2019 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Merged with some refactoring. @Vigilans Thank you for your contribution. The idea is very inspiring! |
Uh oh!
There was an error while loading.Please reload this page.
Introduction
This PR restructures the left side panel's tree view to support following functions:
Favorite
view)Details
leetcode-cli
company plugin.Unknown
.leetcode.hideSolved
setting, which defaults to false.Demonstration
Difficulty, tag, company or favorite:

Problems by tag:

Problems by company:

Favorite problems:
