Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Merged
jdneo merged 14 commits intoLeetCode-OpenSource:masterfromVigilans:tag-search
Feb 2, 2019
Merged

Enhanced Tree view#94

jdneo merged 14 commits intoLeetCode-OpenSource:masterfromVigilans:tag-search
Feb 2, 2019

Conversation

Vigilans
Copy link
Contributor

@VigilansVigilans commentedJan 23, 2019
edited
Loading

Introduction

This PR restructures the left side panel's tree view to support following functions:

Details

  • Company and tag filtering is achieved through theleetcode-clicompany plugin.
  • Problems with no tag or company knowledge are labeled asUnknown.
  • Solved problems can be hidden throughleetcode.hideSolved setting, which defaults to false.

Demonstration

Difficulty, tag, company or favorite:
image

Problems by tag:
image

Problems by company:
image

Favorite problems:
image

@jdneo
Copy link
Member

@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
Copy link
ContributorAuthor

Vigilans commentedJan 23, 2019
edited
Loading

The lint errors have been fixed.


Note: A default object is used to defineIProblem type, so I suppressed the typedef requirement here:

// 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 newIProblem with default properties:

newLeetCodeNode(Object.assign({},list.IProblemDefault,{id:"Root",// parent node namename:"Tag",// current node name}),false),

@jdneo
Copy link
Member

Hi@Vigilans,

Is there any reason to add accepted/not accepted categories into the explorer?

@Vigilans
Copy link
ContributorAuthor

Vigilans commentedJan 24, 2019
edited
Loading

The Not-AC category shows problems which are submitted but not accepted.
For AC category, I wonder if there will be some mechanisms like retrieving all accepted codes of one problem locally or remotely. For now, this category seems redundant...

If you think them not necessary, I will try to revert this commit.

@jdneo
Copy link
Member

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.

@twchn
Copy link

@jdneo Yeah, the feature I mentioned. 😄#95

@Vigilans
Copy link
ContributorAuthor

Vigilans commentedJan 24, 2019
edited
Loading

I see. Btw, there are some other changes I plan to contribute, maybe I should open another issue to query you for your opinions_(눈_ 눈」∠)_

@Vigilans
Copy link
ContributorAuthor

@taoweicn I will work on this feature later.

@twchn
Copy link

@taoweicn I will work on this feature later.

👍 very thankful.

@jdneo
Copy link
Member

@Vigilans Contributions are welcome! 👍

Yes Let's open issues and discuss the implementation there first before we create a PR. 😄

@jdneo
Copy link
Member

@Vigilans Could you please send another PR about hiding solved problems?

A PR contains several issue fixes will make it too large to review

@Vigilans
Copy link
ContributorAuthor

@jdneo Thehiding solved feature is implemented with only 15 lines of code in 2 files, and is part of the tree view.
Personally I think there is not much burden in reviewing this feature, unless more requirements are introduced. Next time I will take care of it when committing new changes_(:зゝ∠)_

tags: [] as string[],
};

export type IProblem = typeof IProblemDefault;
Copy link
Member

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.

@@ -2,6 +2,7 @@
// Licensed under the MIT license.

import * as cp from "child_process";
import * as fs from "fs";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Usefs-extra

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(
Copy link
Member

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.

Copy link
ContributorAuthor

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.

"module.exports = { COMPONIES, TAGS }",
);
// require plugin from modified string
const requireFromString: (src: string, path: string) => any = require("require-from-string");
Copy link
Member

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

Copy link
ContributorAuthor

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.

@@ -7,6 +7,8 @@ import * as list from "./commands/list";
import { leetCodeManager } from "./leetCodeManager";
import { ProblemState } from "./shared";

export type Category = "Difficulty" | "Tag" | "Company";
Copy link
Member

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?

Copy link
ContributorAuthor

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.

Copy link
Member

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",}

Copy link
ContributorAuthor

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

Copy link
Member

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.

Copy link
ContributorAuthor

@VigilansVigilansJan 31, 2019
edited
Loading

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:
image

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:
image

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:
image

Yet I think it complicates what could have been an easy and elegant solution in Typescript.

Copy link
Member

@jdneojdneoFeb 2, 2019
edited
Loading

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.

Company: new Map(),
Favorite: [],
};
for (const problem of await list.listProblems()) {
Copy link
Member

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

Copy link
ContributorAuthor

@VigilansVigilansJan 24, 2019
edited
Loading

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.

Copy link
Member

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.

continue;
}
// Add problems according to category
const categories: Array<[Category, string[]]> = [
Copy link
Member

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

Copy link
ContributorAuthor

@VigilansVigilansJan 24, 2019
edited
Loading

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.

Copy link
Member

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.

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(" ");
Copy link
Member

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.

Copy link
ContributorAuthor

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.

Copy link
Member

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.

@@ -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
Copy link
Member

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?

Copy link
ContributorAuthor

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:

  1. We should be able to retrieve data from theLeetCodeTreeDataProvider.treeData.
  2. One problem will now be added asLeetCodeNode 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)

Copy link
Member

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.

Copy link
Member

@jdneojdneo left a comment
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Will review later

@jdneojdneo merged commit24a59a3 intoLeetCode-OpenSource:masterFeb 2, 2019
@jdneo
Copy link
Member

jdneo commentedFeb 2, 2019
edited
Loading

Merged with some refactoring.

@Vigilans Thank you for your contribution. The idea is very inspiring!

Vigilans reacted with thumbs up emoji

@VigilansVigilans deleted the tag-search branchMarch 14, 2019 06:15
ringcrl pushed a commit to ringcrl/vscode-leetcode that referenced this pull requestApr 21, 2019
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@jdneojdneojdneo left review comments

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

3 participants
@Vigilans@jdneo@twchn

[8]ページ先頭

©2009-2025 Movatter.jp