= storageUtils.listCodeDir('plugins');
+ this.installed = [];
+ for (let f of file_plugin) {
+ const p = f.data;
+ if (!p) continue;
+ p.file = f.file;
+ p.enabled = stats[p.name];
+ if (!(p.name in stats)) {
+ if (p.builtin) {
+ p.enabled = true;
+ } else {
+ p.enabled = false;
+ }
+ }
+ this.installed.push(p);
+ }
+ // 根据id大小排序, 大的前面
+ this.installed = underscore.sortBy(this.installed, x => -x.id);
+ // 从小的开始init
+ for (let i = this.installed.length - 1; i >= 0; --i) {
+ const p = this.installed[i];
+ if (p.enabled) {
+ p.init();
+ }
+ }
+ // 连成链表状
+ this.plugins = this.installed.filter(x => x.enabled);
+ let last = head;
+ for (let p of this.plugins) {
+ last.setNext(p);
+ last = p;
+ }
+ return true;
+ };
+
+ public setNext(next) {
+ Object.setPrototypeOf(this, next);
+ this.next = next;
+ };
+ public save_all() {
+ for (let p of this.plugins) {
+ p.save();
+ }
+ };
+
+ public getProblems(Translate: boolean, cb) {
+ this.next.getProblems(Translate, cb);
+ }
+ public getQuestionOfToday(cb) {
+ this.next.getQuestionOfToday(cb);
+ }
+
+ public getRatingOnline(cb) {
+ this.next.getRatingOnline(cb);
+ }
+
+ public getTestApi(username, cb) {
+ this.next.getTestApi(username, cb);
+ }
+ public getUserContestP(username, cb) {
+ this.next.getUserContestP(username, cb);
+ }
+ public getProblemsTitle(cb) {
+ this.next.getProblemsTitle(cb);
+ }
+ public createSession(a, cb) {
+ this.next.createSession(a, cb);
+ }
+ public getSessions(cb) {
+ this.next.getSessions(cb);
+ }
+ public activateSession(s, cb) {
+ this.next.activateSession(s, cb);
+
+ }
+ public deleteSession(s, cb) {
+ this.next.deleteSession(s, cb);
+
+ }
+ public updateProblem(a, b) {
+ this.next.updateProblem(a, b);
+
+ }
+ public getSubmissions(s, cb) {
+ this.next.getSubmissions(s, cb);
+
+ }
+ public getSubmission(s, cb) {
+ this.next.getSubmission(s, cb);
+
+ }
+ public submitProblem(s, cb) {
+ this.next.submitProblem(s, cb);
+
+ }
+ public testProblem(s, cb) {
+ this.next.testProblem(s, cb);
+
+ }
+ public login(user, cb) {
+ this.next.login(user, cb);
+
+ }
+ public logout(user, cb) {
+ this.next.logout(user, cb);
+
+ }
+ public githubLogin(user, cb) {
+ this.next.githubLogin(user, cb);
+
+ }
+ public linkedinLogin(user, cb) {
+ this.next.linkedinLogin(user, cb);
+
+ }
+ public cookieLogin(user, cb) {
+ this.next.cookieLogin(user, cb);
+ }
+ public filterProblems(opts, cb) {
+ this.next.filterProblems(opts, cb);
+ }
+
+ public getProblem(keyword, needTranslation, cb) {
+ this.next.getProblem(keyword, needTranslation, cb);
+ }
+
+ public starProblem(problem, starred, cb) {
+ this.next.starProblem(problem, starred, cb);
+ }
+ public exportProblem(problem, opts) {
+ this.next.exportProblem(problem, opts);
+ }
+
+ public getTodayQuestion(cb) {
+ this.next.getTodayQuestion(cb);
+ }
+
+ public getQueryZ(username, cb) {
+ this.next.getQueryZ(username, cb);
+ }
+
+ public getUserContest(username, cb) {
+ this.next.getUserContest(username, cb);
+ }
+}
+
+
+
+export const myPluginBase: MyPluginBase = new MyPluginBase();
diff --git a/src/vsc-leetcode-cli/new_lib/plugins/cache.ts b/src/childProcessCall/plugins/cache.ts
similarity index 55%
rename from src/vsc-leetcode-cli/new_lib/plugins/cache.ts
rename to src/childProcessCall/plugins/cache.ts
index c22f216..e94fbf9 100644
--- a/src/vsc-leetcode-cli/new_lib/plugins/cache.ts
+++ b/src/childProcessCall/plugins/cache.ts
@@ -1,56 +1,86 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/plugins/cache.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+
import { MyPluginBase } from "../my_plugin_base";
-var underscore = require('underscore');
+let underscore = require('underscore');
-import { cache } from "../cache";
+import { storageUtils } from "../storageUtils";
import { helper } from "../helper";
// import { log } from "../log";
import { session } from "../session";
-// const plugin = new Plugin(50, 'cache', '', 'Plugin to provide local cache.');
+
class CachePlugin extends MyPluginBase {
- id = 50
- name = 'cache'
+ id = 50;
+ name = 'cache';
builtin = true;
constructor() {
- super()
+ super();
}
clearCacheIfTchanged = (needTranslation) => {
- const translationConfig = cache.get(helper.KEYS.translation);
+ const translationConfig = storageUtils.getCache(helper.KEYS.translation);
if (!translationConfig || translationConfig['useEndpointTranslation'] != needTranslation) {
- cache.deleteAll();
- cache.set(helper.KEYS.translation, { useEndpointTranslation: needTranslation });
-
+ storageUtils.deleteAllCache();
+ storageUtils.setCache(helper.KEYS.translation, { useEndpointTranslation: needTranslation });
}
- }
+ };
public getProblems = (needTranslation, cb) => {
this.clearCacheIfTchanged(needTranslation);
- const problems = cache.get(helper.KEYS.problems);
+ const problems = storageUtils.getCache(helper.KEYS.problems);
if (problems) {
-
return cb(null, problems);
}
this.next.getProblems(needTranslation, function (e, problems) {
if (e) return cb(e);
- cache.set(helper.KEYS.problems, problems);
+ storageUtils.setCache(helper.KEYS.problems, problems);
return cb(null, problems);
});
};
+ /**
+ * getRatingOnline
+ */
+ public getRatingOnline = (cb) => {
+ const cacheRantingData = storageUtils.getCache(helper.KEYS.ranting_path);
+ if (cacheRantingData) {
+ return cb(null, cacheRantingData);
+ }
+ this.next.getRatingOnline(function (e, ratingData) {
+ if (e) return cb(e);
+ let ratingObj;
+ try {
+ ratingObj = JSON.parse(ratingData);
+ } catch (error) {
+ return cb("JSON.parse(ratingData) error");
+ }
+ storageUtils.setCache(helper.KEYS.ranting_path, ratingObj);
+ return cb(null, ratingObj);
+ });
+ };
+
+
public getProblem = (problem, needTranslation, cb) => {
this.clearCacheIfTchanged(needTranslation);
const k = helper.KEYS.problem(problem);
- const _problem = cache.get(k);
- var that = this;
+ const _problem = storageUtils.getCache(k);
+ let that = this;
if (_problem) {
if (!_problem.desc.includes('')) {
-
+ //
} else if (!['likes', 'dislikes'].every(p => p in _problem)) {
-
+ //
} else {
underscore.extendOwn(problem, _problem);
@@ -66,22 +96,19 @@ class CachePlugin extends MyPluginBase {
};
saveProblem = (problem) => {
- // it would be better to leave specific problem cache being user
- // independent, thus try to reuse existing cache as much as possible
- // after changing user.
const _problem = underscore.omit(problem, ['locked', 'state', 'starred']);
- return cache.set(helper.KEYS.problem(problem), _problem);
+ return storageUtils.setCache(helper.KEYS.problem(problem), _problem);
};
updateProblem = (problem, kv) => {
- const problems = cache.get(helper.KEYS.problems);
+ const problems = storageUtils.getCache(helper.KEYS.problems);
if (!problems) return false;
const _problem = problems.find(x => x.id === problem.id);
if (!_problem) return false;
underscore.extend(_problem, kv);
- return cache.set(helper.KEYS.problems, problems);
+ return storageUtils.setCache(helper.KEYS.problems, problems);
};
login = (user, cb) => {
diff --git a/src/vsc-leetcode-cli/new_lib/plugins/leetcode.cn.ts b/src/childProcessCall/plugins/leetcode.cn.ts
similarity index 74%
rename from src/vsc-leetcode-cli/new_lib/plugins/leetcode.cn.ts
rename to src/childProcessCall/plugins/leetcode.cn.ts
index 7682fbf..1137db9 100644
--- a/src/vsc-leetcode-cli/new_lib/plugins/leetcode.cn.ts
+++ b/src/childProcessCall/plugins/leetcode.cn.ts
@@ -1,26 +1,34 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/plugins/leetcode.cn.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
import { MyPluginBase } from "../my_plugin_base";
-var request = require('request');
+let request = require('request');
import { config } from "../config";
import { session } from "../session";
class LeetCodeCn extends MyPluginBase {
- id = 15
- name = 'leetcode.cn'
+ id = 15;
+ name = 'leetcode.cn';
builtin = true;
constructor() {
- super()
+ super();
}
init() {
- config.fix_cn()
+ config.fix_cn();
};
getProblems = (needTranslation, cb) => {
- var that = this;
+ let that = this;
this.next.getProblems(needTranslation, function (e, problems) {
if (e) return cb(e);
@@ -120,12 +128,12 @@ class LeetCodeCn extends MyPluginBase {
e = checkError(e, resp, 200);
if (e) return cb(e);
- var result: any = {}
- result.titleSlug = body.data.todayRecord[0].question.titleSlug
- result.questionId = body.data.todayRecord[0].question.questionId
- result.fid = body.data.todayRecord[0].question.questionFrontendId
- result.date = body.data.todayRecord[0].data
- result.userStatus = body.data.todayRecord[0].userStatus
+ let result: any = {};
+ result.titleSlug = body.data.todayRecord[0].question.titleSlug;
+ result.questionId = body.data.todayRecord[0].question.questionId;
+ result.fid = body.data.todayRecord[0].question.questionFrontendId;
+ result.date = body.data.todayRecord[0].data;
+ result.userStatus = body.data.todayRecord[0].userStatus;
return cb(null, result);
});
};
@@ -179,59 +187,26 @@ class LeetCodeCn extends MyPluginBase {
});
};
- getTestApi = (value, cb) => {
- const opts = makeOpts(config.sys.urls.graphql);
- opts.headers.Origin = config.sys.urls.base;
-
- const value_array = value.split("-")
-
- opts.json = true;
- opts.body = {
- variables: {
- categorySlug: "",
- skip: value_array[0],
- limit: value_array[1],
- filters: {},
- },
- query: [
- ' query problemsetQuestionList($categorySlug: String, $limit: Int, $skip: Int, $filters: QuestionListFilterInput) {',
- ' problemsetQuestionList(',
- ' categorySlug: $categorySlug',
- ' limit: $limit',
- ' skip: $skip',
- ' filters: $filters',
- ' ) {',
- ' hasMore',
- ' total',
- ' questions {',
- ' frontendQuestionId',
- ' topicTags {',
- ' slug',
- ' }',
- ' }',
- ' }',
- ' }',
- ].join('\n'),
- };
-
-
- request.post(opts, function (e, resp, body) {
-
- e = checkError(e, resp, 200);
- if (e) return cb(e);
- let result = {}
- body.data.problemsetQuestionList.questions.forEach(element => {
- result[element.frontendQuestionId] = {
- topicTags: element.topicTags.map(function (p) { return p.slug; }),
- CompanyTags: element.extra.topCompanyTags.map(function (p) { return p.slug; }),
- }
- })
- return cb(null, result);
+ getRatingOnline = (cb) => {
+ const _request = request.defaults({ jar: true });
+ _request("https://zerotrac.github.io/leetcode_problem_rating/data.json", function (error, _, body) {
+ // console.log(error);
+ // console.log(info);
+ cb(error, body);
});
};
+ getTestApi = (value, _) => {
+ const _request = request.defaults({ jar: true });
+ _request("https://zerotrac.github.io/leetcode_problem_rating/data.json", function (error, info, body) {
+ console.log(error);
+ console.log(info);
+ let a = body;
+ console.log(a, value);
+ });
+ };
}
@@ -243,7 +218,7 @@ function signOpts(opts, user) {
}
function makeOpts(url) {
- var opts: any = {};
+ let opts: any = {};
opts.url = url;
opts.headers = {};
diff --git a/src/vsc-leetcode-cli/new_lib/plugins/leetcode.ts b/src/childProcessCall/plugins/leetcode.ts
similarity index 95%
rename from src/vsc-leetcode-cli/new_lib/plugins/leetcode.ts
rename to src/childProcessCall/plugins/leetcode.ts
index b4de85a..bfaa5d9 100644
--- a/src/vsc-leetcode-cli/new_lib/plugins/leetcode.ts
+++ b/src/childProcessCall/plugins/leetcode.ts
@@ -1,24 +1,34 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/plugins/leetcode.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
-var util = require('util');
-var underscore = require('underscore');
-var request = require('request');
-var prompt_out = require('prompt');
+
+let util = require('util');
+
+let underscore = require('underscore');
+let request = require('request');
+let prompt_out = require('prompt');
import { config } from "../config";
import { helper } from "../helper";
-import { file } from "../file";
+import { storageUtils } from "../storageUtils";
import { log } from "../log";
import { session } from "../session";
import { MyPluginBase } from "../my_plugin_base";
import { Queue } from "../queue";
class LeetCode extends MyPluginBase {
- id = 10
- name = 'leetcode'
+ id = 10;
+ name = 'leetcode';
builtin = true;
constructor() {
- super()
+ super();
}
signOpts(opts, user) {
@@ -56,12 +66,12 @@ class LeetCode extends MyPluginBase {
};
getProblems = (_, cb) => {
- var that = this;
+ let that = this;
let problems = [];
const getCategory = function (category, _, cb) {
that.getCategoryProblems(category, function (e, _problems) {
if (e) {
-
+ //
} else {
problems = problems.concat(_problems);
@@ -82,7 +92,7 @@ class LeetCode extends MyPluginBase {
const opts = this.makeOpts(config.sys.urls.problems.replace('$category', category));
- var that = this
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
if (e) return cb(e);
@@ -148,7 +158,7 @@ class LeetCode extends MyPluginBase {
};
- var that = this
+ let that = this;
request.post(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
@@ -186,11 +196,11 @@ class LeetCode extends MyPluginBase {
lang: problem.lang,
question_id: parseInt(problem.id, 10),
test_mode: false,
- typed_code: file.codeData(problem.file)
+ typed_code: storageUtils.codeData(problem.file)
});
- var that = this
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
@@ -212,7 +222,7 @@ class LeetCode extends MyPluginBase {
return cb(null, body);
});
- }
+ };
verifyResult = (task, queue, cb) => {
@@ -221,7 +231,7 @@ class LeetCode extends MyPluginBase {
opts.url = config.sys.urls.verify.replace('$id', task.id);
- var that = this;
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
@@ -237,7 +247,7 @@ class LeetCode extends MyPluginBase {
}
return cb();
});
- }
+ };
formatResult = (result) => {
const x: any = {
@@ -281,13 +291,13 @@ class LeetCode extends MyPluginBase {
if (x.error.length > 0) x.ok = false;
return x;
- }
+ };
testProblem = (problem, cb) => {
const opts = this.makeOpts(config.sys.urls.test.replace('$slug', problem.slug));
opts.body = { data_input: problem.testcase };
- var that = this
+ let that = this;
this.runCode(opts, problem, function (e, task) {
if (e) return cb(e);
@@ -310,7 +320,7 @@ class LeetCode extends MyPluginBase {
const opts = this.makeOpts(config.sys.urls.submit.replace('$slug', problem.slug));
opts.body = { judge_type: 'large' };
- var that = this
+ let that = this;
this.runCode(opts, problem, function (e, task) {
if (e) return cb(e);
@@ -326,7 +336,7 @@ class LeetCode extends MyPluginBase {
const opts = this.makeOpts(config.sys.urls.submissions.replace('$slug', problem.slug));
opts.headers.Referer = config.sys.urls.problem.replace('$slug', problem.slug);
- var that = this
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
if (e) return cb(e);
@@ -343,7 +353,7 @@ class LeetCode extends MyPluginBase {
getSubmission = (submission, cb) => {
const opts = this.makeOpts(config.sys.urls.submission.replace('$id', submission.id));
- var that = this
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
if (e) return cb(e);
@@ -373,7 +383,7 @@ class LeetCode extends MyPluginBase {
};
- var that = this;
+ let that = this;
request.post(opts, function (e, resp, _) {
e = that.checkError(e, resp, 200);
@@ -387,7 +397,7 @@ class LeetCode extends MyPluginBase {
const opts = this.makeOpts(config.sys.urls.favorites);
- var that = this;
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
@@ -399,7 +409,7 @@ class LeetCode extends MyPluginBase {
};
getUserInfo = (cb) => {
- var that = this;
+ let that = this;
const opts = this.makeOpts(config.sys.urls.graphql);
opts.headers.Origin = config.sys.urls.base;
opts.headers.Referer = config.sys.urls.base;
@@ -435,7 +445,7 @@ class LeetCode extends MyPluginBase {
opts.body = data;
- var that = this;
+ let that = this;
request(opts, function (e, resp, body) {
e = that.checkError(e, resp, 200);
@@ -443,7 +453,7 @@ class LeetCode extends MyPluginBase {
return e ? cb(e) : cb(null, body.sessions);
});
- }
+ };
getSessions = (cb) => {
@@ -470,7 +480,7 @@ class LeetCode extends MyPluginBase {
signin = (user, cb) => {
const isCN = config.app === 'leetcode.cn';
const spin = isCN ? helper.spin('Signing in leetcode.cn') : helper.spin('Signing in leetcode.com');
- var that = this;
+ let that = this;
request(config.sys.urls.login, function (e, resp, _) {
spin.stop();
e = that.checkError(e, resp, 200);
@@ -504,7 +514,7 @@ class LeetCode extends MyPluginBase {
};
getUser = (user, cb) => {
- var that = this;
+ let that = this;
this.getFavorites(function (e, favorites) {
if (!e) {
const f = favorites.favorites.private_favorites.find((f) => f.name === 'Favorite');
@@ -530,7 +540,7 @@ class LeetCode extends MyPluginBase {
};
login = (user, cb) => {
- var that = this;
+ let that = this;
that.signin(user, function (e, user) {
if (e) return cb(e);
that.getUser(user, cb);
@@ -549,10 +559,10 @@ class LeetCode extends MyPluginBase {
sessionId: reSessionResult[1],
sessionCSRF: reCsrfResult[1],
};
- }
+ };
requestLeetcodeAndSave = (request, leetcodeUrl, user, cb) => {
- var that = this;
+ let that = this;
request.get({ url: leetcodeUrl }, function (_, resp, __) {
const redirectUri = resp.request.uri.href;
if (redirectUri !== config.sys.urls.leetcode_redirect) {
@@ -564,7 +574,7 @@ class LeetCode extends MyPluginBase {
session.saveUser(user);
that.getUser(user, cb);
});
- }
+ };
cookieLogin = (user, cb) => {
const cookieData = this.parseCookie(user.cookie, cb);
@@ -578,7 +588,7 @@ class LeetCode extends MyPluginBase {
const urls = config.sys.urls;
const leetcodeUrl = urls.github_login;
const _request = request.defaults({ jar: true });
- var that = this;
+ let that = this;
_request(urls.github_login_request, function (_, __, body) {
const authenticityToken = body.match(/name="authenticity_token" value="(.*?)"/);
@@ -671,7 +681,7 @@ class LeetCode extends MyPluginBase {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
});
- var that = this;
+ let that = this;
_request(urls.linkedin_login_request, function (_, resp, body) {
if (resp.statusCode !== 200) {
diff --git a/src/vsc-leetcode-cli/new_lib/plugins/retry.ts b/src/childProcessCall/plugins/retry.ts
similarity index 83%
rename from src/vsc-leetcode-cli/new_lib/plugins/retry.ts
rename to src/childProcessCall/plugins/retry.ts
index 2c2add7..8ca06fa 100644
--- a/src/vsc-leetcode-cli/new_lib/plugins/retry.ts
+++ b/src/childProcessCall/plugins/retry.ts
@@ -1,13 +1,22 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/plugins/retry.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+
import { MyPluginBase } from "../my_plugin_base";
import { config } from "../config";
import { session } from "../session";
-// var plugin = new Plugin(30, 'retry', '',
-// 'Plugin to retry last failed request if autologin.enable is on.');
+
class RetryPlugin extends MyPluginBase {
- id = 30
- name = 'retry'
+ id = 30;
+ name = 'retry';
builtin = true;
count = {};
@@ -15,7 +24,7 @@ class RetryPlugin extends MyPluginBase {
return config.autologin.enable &&
(e === session.errors.EXPIRED) &&
(this.count[name] || 0) < config.autologin.retry;
- }
+ };
init = () => {
const names = [
'activateSession',
@@ -31,7 +40,7 @@ class RetryPlugin extends MyPluginBase {
'submitProblem',
'starProblem'
];
- var that = this;
+ let that = this;
for (let name of names) {
that.count[name] = 0;
this[name] = function () {
@@ -73,9 +82,9 @@ class RetryPlugin extends MyPluginBase {
this.next.login(user, function (e) {
if (e) {
-
+ //
} else {
-
+ //
}
return cb();
});
diff --git a/src/vsc-leetcode-cli/new_lib/plugins/solution.discuss.ts b/src/childProcessCall/plugins/solution.discuss.ts
similarity index 78%
rename from src/vsc-leetcode-cli/new_lib/plugins/solution.discuss.ts
rename to src/childProcessCall/plugins/solution.discuss.ts
index 8d5cadc..ac24a4f 100644
--- a/src/vsc-leetcode-cli/new_lib/plugins/solution.discuss.ts
+++ b/src/childProcessCall/plugins/solution.discuss.ts
@@ -1,25 +1,28 @@
-var request = require('request');
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/plugins/solution.discuss.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+
+let request = require('request');
import { log } from "../log";
import { session } from "../session";
import { MyPluginBase } from "../my_plugin_base";
-//
-// [Usage]
-//
-// https://github.com/skygragon/leetcode-cli-plugins/blob/master/docs/solution.discuss.md
-//
-// var plugin = new Plugin(200, 'solution.discuss', '',
-// 'Plugin to fetch most voted solution in discussions.');
class SolutionDiscuss extends MyPluginBase {
- id = 200
- name = "solution.discuss"
+ id = 200;
+ name = "solution.discuss";
builtin = true;
constructor() {
- super()
+ super();
}
@@ -28,13 +31,13 @@ class SolutionDiscuss extends MyPluginBase {
this.next.getProblem(problem, needTranslation, function (e, problem) {
if (e || !session.argv.solution) return cb(e, problem);
- var lang = session.argv.lang;
+ let lang = session.argv.lang;
getSolution(problem, lang, function (e, solution) {
if (e) return cb(e);
if (!solution) return log.error('Solution not found for ' + lang);
- var link = URL_DISCUSS.replace('$slug', problem.slug).replace('$id', solution.id);
- var content = solution.post.content.replace(/\\n/g, '\n').replace(/\\t/g, '\t');
+ let link = URL_DISCUSS.replace('$slug', problem.slug).replace('$id', solution.id);
+ let content = solution.post.content.replace(/\\n/g, '\n').replace(/\\t/g, '\t');
log.info();
log.info(problem.name);
@@ -54,15 +57,15 @@ class SolutionDiscuss extends MyPluginBase {
}
-var URL_DISCUSSES = 'https://leetcode.com/graphql';
-var URL_DISCUSS = 'https://leetcode.com/problems/$slug/discuss/$id';
+let URL_DISCUSSES = 'https://leetcode.com/graphql';
+let URL_DISCUSS = 'https://leetcode.com/problems/$slug/discuss/$id';
function getSolution(problem, lang, cb) {
if (!problem) return cb();
if (lang === 'python3') lang = 'python';
- var opts = {
+ let opts = {
url: URL_DISCUSSES,
json: true,
body: {
diff --git a/src/vsc-leetcode-cli/new_lib/queue.ts b/src/childProcessCall/queue.ts
similarity index 72%
rename from src/vsc-leetcode-cli/new_lib/queue.ts
rename to src/childProcessCall/queue.ts
index 1e2f781..1db7165 100644
--- a/src/vsc-leetcode-cli/new_lib/queue.ts
+++ b/src/childProcessCall/queue.ts
@@ -1,15 +1,25 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/queue.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
-var underscore = require('underscore');
+
+
+let underscore = require('underscore');
import { config } from "./config";
export class Queue {
- tasks
- ctx
- onTask
- error
- concurrency
- onDone
+ tasks;
+ ctx;
+ onTask;
+ error;
+ concurrency;
+ onDone;
constructor(tasks, ctx, onTask) {
this.tasks = underscore.clone(tasks) || [];
this.ctx = ctx || {};
diff --git a/src/vsc-leetcode-cli/new_lib/session.ts b/src/childProcessCall/session.ts
similarity index 59%
rename from src/vsc-leetcode-cli/new_lib/session.ts
rename to src/childProcessCall/session.ts
index 164a220..d1737c3 100644
--- a/src/vsc-leetcode-cli/new_lib/session.ts
+++ b/src/childProcessCall/session.ts
@@ -1,9 +1,18 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/session.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
-var moment_out = require('moment');
-var underscore = require('underscore');
+let moment_out = require('moment');
+let underscore = require('underscore');
-import { cache } from "./cache";
+
+import { storageUtils } from "./storageUtils";
import { config } from "./config";
import { helper } from "./helper";
@@ -14,31 +23,26 @@ class Session {
statusCode: -1
}
};
- argv: any = {
-
- }
+ argv: any = {};
constructor() {
-
}
-
-
public getUser = function () {
- return cache.get(helper.KEYS.user);
+ return storageUtils.getCache(helper.KEYS.user);
};
public saveUser = function (user) {
// when auto login enabled, have to save password to re-login later
// otherwise don't dump password for the sake of security.
const _user = underscore.omit(user, config.autologin.enable ? [] : ['pass']);
- cache.set(helper.KEYS.user, _user);
+ storageUtils.setCache(helper.KEYS.user, _user);
};
public deleteUser = function () {
- cache.del(helper.KEYS.user);
+ storageUtils.delCache(helper.KEYS.user);
};
public deleteCodingSession = function () {
- cache.del(helper.KEYS.problems);
+ storageUtils.delCache(helper.KEYS.problems);
};
public isLogin() {
@@ -48,7 +52,7 @@ class Session {
public updateStat = function (k, v) {
// TODO: use other storage if too many stat data
const today = moment_out().format('YYYY-MM-DD');
- const stats = cache.get(helper.KEYS.stat) || {};
+ const stats = storageUtils.getCache(helper.KEYS.stat) || {};
const stat = stats[today] = stats[today] || {};
if (k.endsWith('.set')) {
@@ -58,10 +62,7 @@ class Session {
} else {
stat[k] = (stat[k] || 0) + v;
}
-
- cache.set(helper.KEYS.stat, stats);
+ storageUtils.setCache(helper.KEYS.stat, stats);
};
-
-
}
export const session: Session = new Session();
diff --git a/src/childProcessCall/storageUtils.ts b/src/childProcessCall/storageUtils.ts
new file mode 100644
index 0000000..aae8e5e
--- /dev/null
+++ b/src/childProcessCall/storageUtils.ts
@@ -0,0 +1,242 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/childProcessCall/storageUtils.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, October 27th 2022, 7:43:29 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+
+let fs = require('fs');
+let os = require('os');
+let path = require('path');
+
+let _ = require('underscore');
+let mkdirp = require('mkdirp');
+
+export interface IMETA {
+ id: string
+ fid: string
+ lang: string
+}
+
+//Object.assign({}, defaultMETA, {})
+export const defaultMETA: IMETA = {
+ id: "",
+ fid: "",
+ lang: "",
+};
+
+class StorageUtils {
+ public init() {
+ _.templateSettings = {
+ evaluate: /\{\{(.+?)\}\}/g,
+ interpolate: /\$\{(.+?)\}/g
+ };
+ this.mkdir(this.homeDir());
+ };
+
+ public isWindows() {
+ return process.platform === 'win32';
+ };
+
+ public userHomeDir() {
+ return process.env.HOME || process.env.USERPROFILE;
+ };
+
+ public homeDir() {
+ return path.join(this.userHomeDir(), '.lcpr');
+ };
+
+ public appDir() {
+ const config = require('./config');
+ return path.join(this.homeDir(), config.app || 'leetcode');
+ };
+
+ // 缓存目录
+ public cacheDir() {
+ return path.join(this.appDir(), 'cache');
+ };
+
+ // 代码目录
+ public codeDir(dir) {
+ return path.join(__dirname, dir || '');
+ };
+
+ // 缓存目录文件
+ public cacheFile(k) {
+ return path.join(this.cacheDir(), k + '.json');
+ };
+
+ // public configFile() {
+ // return path.join(this.homeDir(), 'config.json');
+ // };
+
+ // 插件代码目录
+ public listCodeDir(dir) {
+ dir = this.codeDir(dir);
+ let that = this;
+ return this.list(dir).map(function (f) {
+ const fullpath = path.join(dir, f);
+ const ext = path.extname(f);
+ const name = path.basename(f, ext);
+
+ let data = null;
+ switch (ext) {
+ case '.js': data = require(fullpath).pluginObj; break;
+ case '.json': data = JSON.parse(that.getData(fullpath)); break;
+ }
+ return { name: name, data: data, file: f };
+ });
+ };
+
+
+ public initCache() {
+ this.mkdir(this.cacheDir());
+ };
+ public deleteAllCache() {
+ this.listCache().forEach(value => {
+ this.delCache(value.name);
+ });
+ };
+
+ public getCache(k) {
+ const fullpath = this.cacheFile(k);
+ if (!this.exist(fullpath)) return null;
+
+ return JSON.parse(this.getData(fullpath));
+ };
+
+ public setCache(k, v) {
+ const fullpath = this.cacheFile(k);
+ this.write(fullpath, JSON.stringify(v));
+ return true;
+ };
+
+ public delCache(k) {
+ const fullpath = this.cacheFile(k);
+ if (!this.exist(fullpath)) return false;
+
+ this.rm(fullpath);
+ return true;
+ };
+
+ public listCache(): Array {
+ let that = this;
+ return this.list(this.cacheDir())
+ .filter(x => path.extname(x) === '.json')
+ .map(function (filename) {
+ const k = path.basename(filename, '.json');
+ const stat = that.stat(that.cacheFile(k));
+ return {
+ name: k,
+ size: stat.size,
+ mtime: stat.mtime
+ };
+ });
+ };
+
+ public mkdir(fullpath) {
+ if (fs.existsSync(fullpath)) return;
+ mkdirp.sync(fullpath);
+ };
+
+ public exist(fullpath) {
+ return fs.existsSync(fullpath);
+ };
+
+ public rm(fullpath) {
+ return fs.unlinkSync(fullpath);
+ };
+
+ public mv(src, dst) {
+ return fs.renameSync(src, dst);
+ };
+
+ public list(dir) {
+ return fs.readdirSync(dir);
+ };
+
+ public stat(fullpath) {
+ return fs.statSync(fullpath);
+ };
+
+ public write(fullpath, data) {
+ return fs.writeFileSync(fullpath, data);
+ };
+
+ public name(fullpath) {
+ return path.basename(fullpath, path.extname(fullpath));
+ };
+
+ public getData(fullpath) {
+ return fs.existsSync(fullpath) ? fs.readFileSync(fullpath).toString() : null;
+ };
+
+ // 获取要提交测试的数据
+ public codeData(fullpath) {
+ const data = this.getData(fullpath);
+
+ if (data === null) {
+ return null;
+ }
+
+ const lines = data.split(/\r\n|\n|\r/);
+ const start = lines.findIndex(x => x.indexOf('@lc code=start') !== -1);
+ const end = lines.findIndex(x => x.indexOf('@lc code=end') !== -1);
+
+ if (start !== -1 && end !== -1 && start + 1 <= end) {
+ return lines.slice(start + 1, end).join(os.EOL);
+ }
+
+ return data;
+ };
+
+ // 加载输出模板数据
+ public render(tpl, data) {
+ const tplfile = path.join(__dirname, "..", "..", "..", "resources", "templates", tpl + '.tpl');
+ let result = _.template(this.getData(tplfile).replace(/\r\n/g, '\n'))(data);
+ if (this.isWindows()) {
+ result = result.replace(/\n/g, '\r\n');
+ } else {
+ result = result.replace(/\r\n/g, '\n');
+ }
+ return result;
+ };
+
+ public fmt(format, data) {
+ return _.template(format)(data);
+ };
+
+ // public metaByName(filename) {
+ // const m = Object.assign({}, defaultMETA, {});
+
+ // m.id = storageUtils.name(filename).split('.')[0];
+
+
+ // if (filename.endsWith('.py3') || filename.endsWith('.python3.py'))
+ // m.lang = 'python3';
+ // else
+ // m.lang = require('./helper').extToLang(filename);
+
+ // return m;
+ // };
+
+ public meta(filename) {
+ const m = Object.assign({}, defaultMETA, {});
+ const line = this.getData(filename).split('\n').find(x => x.indexOf(' @lc app=') >= 0) || '';
+ // @lc app=leetcode.cn id=剑指 Offer II 116 lang=cpp
+ let id_right = line.split('id=')[1];
+ let lang_cat = id_right.split('lang=');
+ let id = lang_cat[0].trim();
+ let lang = lang_cat[1].trim();
+ m.id = id;
+ m.fid = id;
+ m.lang = lang;
+ return m;
+ };
+
+}
+
+export const storageUtils: StorageUtils = new StorageUtils();
diff --git a/src/codelens/CodeLensController.ts b/src/codelens/CodeLensController.ts
deleted file mode 100644
index b41f28f..0000000
--- a/src/codelens/CodeLensController.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-import { ConfigurationChangeEvent, Disposable, languages, workspace } from "vscode";
-import { customCodeLensProvider, CustomCodeLensProvider } from "./CustomCodeLensProvider";
-
-class CodeLensController implements Disposable {
- private internalProvider: CustomCodeLensProvider;
- private registeredProvider: Disposable | undefined;
- private configurationChangeListener: Disposable;
-
- constructor() {
- this.internalProvider = customCodeLensProvider;
-
- this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
- if (event.affectsConfiguration("leetcode.editor.shortcuts")) {
- this.internalProvider.refresh();
- }
- }, this);
-
- this.registeredProvider = languages.registerCodeLensProvider({ scheme: "file" }, this.internalProvider);
- }
-
- public dispose(): void {
- if (this.registeredProvider) {
- this.registeredProvider.dispose();
- }
- this.configurationChangeListener.dispose();
- }
-}
-
-export const codeLensController: CodeLensController = new CodeLensController();
diff --git a/src/commands/cache.ts b/src/commands/cache.ts
deleted file mode 100644
index 1f6b656..0000000
--- a/src/commands/cache.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-import { leetCodeExecutor } from "../leetCodeExecutor";
-import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";
-
-export async function deleteCache(): Promise {
- try {
- await leetCodeExecutor.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
deleted file mode 100644
index aec9b38..0000000
--- a/src/commands/language.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-import { QuickPickItem, window, workspace, WorkspaceConfiguration } from "vscode";
-import { languages } from "../shared";
-
-export async function switchDefaultLanguage(): Promise {
- const leetCodeConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode-problem-rating");
- const defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage");
- const languageItems: QuickPickItem[] = [];
- for (const language of languages) {
- languageItems.push({
- label: language,
- description: defaultLanguage === language ? "Currently used" : undefined,
- });
- }
- // Put the default language at the top of the list
- languageItems.sort((a: QuickPickItem, b: QuickPickItem) => {
- if (a.description) {
- return Number.MIN_SAFE_INTEGER;
- } else if (b.description) {
- return Number.MAX_SAFE_INTEGER;
- }
- return a.label.localeCompare(b.label);
- });
-
- const selectedItem: QuickPickItem | undefined = await window.showQuickPick(languageItems, {
- placeHolder: "Please the default language",
- ignoreFocusOut: true,
- });
-
- if (!selectedItem) {
- return;
- }
-
- leetCodeConfig.update("defaultLanguage", selectedItem.label, true /* Global */);
- window.showInformationMessage(`Successfully set the default language to ${selectedItem.label}`);
-}
diff --git a/src/commands/list.ts b/src/commands/list.ts
deleted file mode 100644
index 2ba5c36..0000000
--- a/src/commands/list.ts
+++ /dev/null
@@ -1,73 +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 { IProblem, ProblemState, RootNodeSort, UserStatus } from "../shared";
-import * as settingUtils from "../utils/settingUtils";
-import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";
-import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider";
-import { resourcesData } from "../ResourcesData";
-
-export async function listProblems(): Promise {
- try {
- if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
- return [];
- }
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- const showLocked: boolean = !!leetCodeConfig.get("showLocked");
- const useEndpointTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
- 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,
- isFavorite: p.starred,
- locked: p.locked,
- state: parseProblemState(p.state),
- name: p.name,
- difficulty: p.level,
- passRate: p.percent,
- companies: p.companies || [],
- tags: resourcesData.getTagsData(p.fid) || ["Unknown"],
- scoreData: AllScoreData.get(p.fid),
- isSearchResult: false,
- input: "",
- rootNodeSortId: RootNodeSort.ZERO,
- todayData: undefined,
- });
- }
- return problems.reverse();
- } catch (error) {
- await promptForOpenOutputChannel("Failed to list problems. Please open the output channel for details.", DialogType.error);
- return [];
- }
-}
-
-function parseProblemState(stateOutput: string): ProblemState {
- if (!stateOutput) {
- return ProblemState.Unknown;
- }
- switch (stateOutput.trim()) {
- case "v":
- case "✔":
- case "√":
- case "ac":
- return ProblemState.AC;
- case "X":
- case "✘":
- case "×":
- case "notac":
- return ProblemState.NotAC;
- default:
- return ProblemState.Unknown;
- }
-}
diff --git a/src/commands/plugin.ts b/src/commands/plugin.ts
deleted file mode 100644
index b39efc1..0000000
--- a/src/commands/plugin.ts
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// 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 { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
-import { deleteCache } from "./cache";
-
-export async function switchEndpoint(): Promise {
- const isCnEnabled: boolean = getLeetCodeEndpoint() === Endpoint.LeetCodeCN;
- const picks: Array> = [];
- picks.push(
- {
- label: `${isCnEnabled ? "" : "$(check) "}LeetCode`,
- description: "leetcode.com",
- detail: `Enable LeetCode US`,
- value: Endpoint.LeetCode,
- },
- {
- label: `${isCnEnabled ? "$(check) " : ""}力扣`,
- description: "leetcode.cn",
- detail: `启用中国版 LeetCode`,
- value: Endpoint.LeetCodeCN,
- },
- );
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
- if (!choice || choice.value === getLeetCodeEndpoint()) {
- return;
- }
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- try {
- const endpoint: string = choice.value;
- await leetCodeExecutor.switchEndpoint(endpoint);
- await leetCodeConfig.update("endpoint", endpoint, true /* UserSetting */);
- vscode.window.showInformationMessage(`Switched the endpoint to ${endpoint}`);
- } catch (error) {
- await promptForOpenOutputChannel("Failed to switch endpoint. Please open the output channel for details.", DialogType.error);
- }
-
- try {
- await vscode.commands.executeCommand("leetcode.signout");
- await deleteCache();
- await promptForSignIn();
- } catch (error) {
- await promptForOpenOutputChannel("Failed to sign in. Please open the output channel for details.", DialogType.error);
- }
-}
-
-export function getLeetCodeEndpoint(): string {
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- return leetCodeConfig.get("endpoint", Endpoint.LeetCodeCN);
-}
-
-const SORT_ORDER: SortingStrategy[] = [
- SortingStrategy.None,
- SortingStrategy.AcceptanceRateAsc,
- SortingStrategy.AcceptanceRateDesc,
- SortingStrategy.ScoreAsc,
- SortingStrategy.ScoreDesc,
- SortingStrategy.IDDesc,
-];
-
-export async function switchSortingStrategy(): Promise {
- const currentStrategy: SortingStrategy = getSortingStrategy();
- const picks: Array> = [];
- picks.push(
- ...SORT_ORDER.map((s: SortingStrategy) => {
- return {
- label: `${currentStrategy === s ? "$(check)" : " "} ${s}`,
- value: s,
- };
- }),
- );
-
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
- if (!choice || choice.value === currentStrategy) {
- return;
- }
-
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- await leetCodeConfig.update("problems.sortStrategy", choice.value, true);
- await leetCodeTreeDataProvider.refresh();
-}
-
-export function getSortingStrategy(): SortingStrategy {
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- return leetCodeConfig.get("problems.sortStrategy", SortingStrategy.None);
-}
diff --git a/src/commands/session.ts b/src/commands/session.ts
deleted file mode 100644
index 2b26f26..0000000
--- a/src/commands/session.ts
+++ /dev/null
@@ -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
deleted file mode 100644
index 5e127d8..0000000
--- a/src/commands/show.ts
+++ /dev/null
@@ -1,497 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-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 { leetCodeChannel } from "../leetCodeChannel";
-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 { genFileExt, genFileName, getNodeIdFromFile } from "../utils/problemUtils";
-import * as settingUtils from "../utils/settingUtils";
-import { IDescriptionConfiguration } from "../utils/settingUtils";
-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 * as list from "./list";
-import { getLeetCodeEndpoint } from "./plugin";
-
-export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise {
- let node: IProblem;
- if (input instanceof vscode.Uri) {
- const activeFilePath: string = input.fsPath;
- const id: string = await getNodeIdFromFile(activeFilePath);
- if (!id) {
- vscode.window.showErrorMessage(`Failed to resolve the problem id from file: ${activeFilePath}.`);
- return;
- }
- const cachedNode: IProblem | undefined = explorerNodeManager.getNodeById(id);
- if (!cachedNode) {
- vscode.window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`);
- return;
- }
- node = cachedNode;
- // Move the preview page aside if it's triggered from Code Lens
- isSideMode = true;
- } else {
- node = input;
- }
- const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
- const descString: string = await leetCodeExecutor.getDescription(node.qid, needTranslation);
- leetCodePreviewProvider.show(descString, node, isSideMode);
-}
-
-export async function deleteAllCache(): Promise {
- await leetCodeManager.signOut();
- await leetCodeExecutor.removeOldCache();
- await leetCodeExecutor.switchEndpoint(getLeetCodeEndpoint());
- await leetCodeTreeDataProvider.refresh()
-}
-
-
-export async function pickOne(): Promise {
- const problems: IProblem[] = await list.listProblems();
- var randomProblem: IProblem;
-
- const user_score = leetCodeManager.getUserContestScore()
- if (user_score > 0) {
-
- let min_score: number = getPickOneByRankRangeMin();
- let max_score: number = getPickOneByRankRangeMax();
- let temp_problems: IProblem[] = new Array();
- const need_min = user_score + min_score;
- const need_max = user_score + max_score;
- problems.forEach(element => {
- if (element.scoreData?.Rating) {
- if (element.scoreData.Rating >= need_min && element.scoreData.Rating <= need_max) {
- temp_problems.push(element);
- }
- }
- });
- randomProblem = temp_problems[Math.floor(Math.random() * temp_problems.length)];
-
- } else {
- randomProblem = problems[Math.floor(Math.random() * problems.length)];
- }
- if (randomProblem) {
- await showProblemInternal(randomProblem);
- }
-}
-export async function searchScoreRange(): Promise {
- const twoFactor: string | undefined = await vscode.window.showInputBox({
- prompt: "输入分数范围 低分-高分 例如: 1500-1600",
- ignoreFocusOut: true,
- validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
- });
-
- // vscode.window.showErrorMessage(twoFactor || "输入错误");
- const tt = Object.assign({}, SearchNode, {
- value: twoFactor,
- type: SearchSetType.ScoreRange,
- time: Math.floor(Date.now() / 1000)
- })
- explorerNodeManager.insertSearchSet(tt);
- await leetCodeTreeDataProvider.refresh()
-}
-
-export async function searchContest(): Promise {
- const twoFactor: string | undefined = await vscode.window.showInputBox({
- prompt: "单期数 例如: 300 或者 输入期数范围 低期数-高期数 例如: 303-306",
- ignoreFocusOut: true,
- validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
- });
-
- // vscode.window.showErrorMessage(twoFactor || "输入错误");
- const tt = Object.assign({}, SearchNode, {
- value: twoFactor,
- type: SearchSetType.Context,
- time: Math.floor(Date.now() / 1000)
- })
- explorerNodeManager.insertSearchSet(tt);
- await leetCodeTreeDataProvider.refresh()
-}
-
-export async function showProblem(node?: LeetCodeNode): Promise {
- if (!node) {
- return;
- }
- await showProblemInternal(node);
-}
-
-
-export async function searchProblemByID(): Promise {
- if (!leetCodeManager.getUser()) {
- promptForSignIn();
- return;
- }
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
- parseProblemsToPicks(list.listProblems()),
- {
- matchOnDetail: true,
- matchOnDescription: true,
- placeHolder: "Select one problem",
- },
- );
- if (!choice) {
- return;
- }
- await showProblemInternal(choice.value);
-}
-
-
-export async function searchProblem(): Promise {
- if (!leetCodeManager.getUser()) {
- promptForSignIn();
- return;
- }
-
- const picks: Array> = [];
- picks.push(
- {
- label: `题目id查询`,
- detail: `通过题目id查询`,
- value: `byid`,
- },
- {
- label: `分数范围查询`,
- detail: `例如 1500-1600`,
- value: `range`,
- },
- {
- label: `周赛期数查询`,
- detail: `周赛期数查询`,
- value: `contest`,
- },
- // {
- // label: `测试api`,
- // detail: `测试api`,
- // value: `testapi`,
- // }
- // ,
- // {
- // label: `每日一题`,
- // detail: `每日一题`,
- // value: `today`,
- // },
- // {
- // label: `查询自己竞赛信息`,
- // detail: `查询自己竞赛信息`,
- // value: `userContest`,
- // }
- );
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
- picks,
- { title: "选择查询选项" },
- );
- if (!choice) {
- return
- }
- if (choice.value == "byid") {
- await searchProblemByID();
- } else if (choice.value == "range") {
- await searchScoreRange();
- } else if (choice.value == "contest") {
- await searchContest();
- } else if (choice.value == "today") {
- await searchToday();
- } else if (choice.value == "userContest") {
- await searchUserContest();
- } else if (choice.value == "testapi") {
- await testapi();
- }
-
-}
-
-export async function testapi(): Promise {
- if (!leetCodeManager.getUser()) {
- promptForSignIn();
- return;
- }
- try {
- const twoFactor: string | undefined = await vscode.window.showInputBox({
- prompt: "测试数据",
- ignoreFocusOut: true,
- validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
- });
-
- // vscode.window.showErrorMessage(twoFactor || "输入错误");
- const solution: string = await leetCodeExecutor.getTestApi(twoFactor || "")
- const query_result = JSON.parse(solution);
- console.log(query_result);
- } catch (error) {
- leetCodeChannel.appendLine(error.toString());
- await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error);
- }
-}
-
-export async function searchUserContest(): Promise {
- if (!leetCodeManager.getUser()) {
- promptForSignIn();
- return;
- }
- try {
- const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
- const solution: string = await leetCodeExecutor.getUserContest(needTranslation, leetCodeManager.getUser() || "");
- const query_result = JSON.parse(solution);
- const tt: userContestRanKingBase = Object.assign({}, userContestRankingObj, query_result.userContestRanking)
- await leetCodeManager.insertCurrentUserContestInfo(tt);
- leetCodeManager.emit("searchUserContest")
- } catch (error) {
- leetCodeChannel.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()) {
- promptForSignIn();
- return;
- }
- try {
- const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
- const solution: string = await leetCodeExecutor.getTodayQuestion(needTranslation);
- const query_result = JSON.parse(solution);
- // const titleSlug: string = query_result.titleSlug
- // const questionId: string = query_result.questionId
- const fid: string = query_result.fid
- if (fid) {
- const tt = Object.assign({}, SearchNode, {
- value: fid,
- type: SearchSetType.Day,
- time: Math.floor(Date.now() / 1000),
- todayData: query_result,
- })
- explorerNodeManager.insertSearchSet(tt);
- await leetCodeTreeDataProvider.refresh()
- }
-
- } catch (error) {
- leetCodeChannel.appendLine(error.toString());
- await promptForOpenOutputChannel("Failed to fetch today question. Please open the output channel for details.", DialogType.error);
- }
-}
-
-
-export async function showSolution(input: LeetCodeNode | vscode.Uri): Promise {
- let problemInput: string | undefined;
- if (input instanceof LeetCodeNode) { // Triggerred from explorer
- problemInput = input.qid;
- } else if (input instanceof vscode.Uri) { // Triggerred from Code Lens/context menu
- if (wsl.useVscodeNode()) {
- problemInput = `${input.fsPath}`;
- } else {
- problemInput = `"${input.fsPath}"`;
- if (wsl.useWsl()) {
- problemInput = await wsl.toWslPath(input.fsPath);
- }
- }
- } else if (!input) { // Triggerred from command
- problemInput = await getActiveFilePath();
- }
-
- if (!problemInput) {
- vscode.window.showErrorMessage("Invalid input to fetch the solution data.");
- return;
- }
-
- const language: string | undefined = await fetchProblemLanguage();
- if (!language) {
- return;
- }
- try {
- const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
- const solution: string = await leetCodeExecutor.showSolution(problemInput, language, needTranslation);
- leetCodeSolutionProvider.show(unescapeJS(solution));
- } catch (error) {
- leetCodeChannel.appendLine(error.toString());
- await promptForOpenOutputChannel("Failed to fetch the top voted solution. Please open the output channel for details.", DialogType.error);
- }
-}
-
-async function fetchProblemLanguage(): Promise {
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage");
- if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) {
- defaultLanguage = undefined;
- }
- const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use", ignoreFocusOut: true });
- // fire-and-forget default language query
- (async (): Promise => {
- if (language && !defaultLanguage && leetCodeConfig.get("hint.setDefaultLanguage")) {
- const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
- `Would you like to set '${language}' as your default language?`,
- DialogOptions.yes,
- DialogOptions.no,
- DialogOptions.never,
- );
- if (choice === DialogOptions.yes) {
- leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */);
- } else if (choice === DialogOptions.never) {
- leetCodeConfig.update("hint.setDefaultLanguage", false, true /* UserSetting */);
- }
- }
- })();
- return language;
-}
-
-async function showProblemInternal(node: IProblem): Promise {
- try {
- const language: string | undefined = await fetchProblemLanguage();
- if (!language) {
- return;
- }
-
- const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
- const workspaceFolder: string = await selectWorkspaceFolder();
- if (!workspaceFolder) {
- return;
- }
-
- const fileFolder: string = leetCodeConfig
- .get(`filePath.${language}.folder`, leetCodeConfig.get(`filePath.default.folder`, ""))
- .trim();
- const fileName: string = leetCodeConfig
- .get(
- `filePath.${language}.filename`,
- leetCodeConfig.get(`filePath.default.filename`) || genFileName(node, language),
- )
- .trim();
-
- let finalPath: string = path.join(workspaceFolder, fileFolder, fileName);
-
- if (finalPath) {
- finalPath = await resolveRelativePath(finalPath, node, language);
- if (!finalPath) {
- leetCodeChannel.appendLine("Showing problem canceled by user.");
- return;
- }
- }
-
- finalPath = wsl.useWsl() ? await wsl.toWinPath(finalPath) : finalPath;
-
- const descriptionConfig: IDescriptionConfiguration = settingUtils.getDescriptionConfiguration();
- const needTranslation: boolean = settingUtils.shouldUseEndpointTranslation();
-
- await leetCodeExecutor.showProblem(node, language, finalPath, descriptionConfig.showInComment, needTranslation);
- const promises: any[] = [
- vscode.window.showTextDocument(vscode.Uri.file(finalPath), { preview: false, viewColumn: vscode.ViewColumn.One }),
- promptHintMessage(
- "hint.commentDescription",
- 'You can config how to show the problem description through "leetcode.showDescription".',
- "Open settings",
- (): Promise => openSettingsEditor("leetcode.showDescription"),
- ),
- ];
- if (descriptionConfig.showInWebview) {
- promises.push(showDescriptionView(node));
- }
-
- await Promise.all(promises);
- } catch (error) {
- await promptForOpenOutputChannel(`${error} Please open the output channel for details.`, DialogType.error);
- }
-}
-
-async function showDescriptionView(node: IProblem): Promise {
- return previewProblem(node, vscode.workspace.getConfiguration("leetcode-problem-rating").get("enableSideMode", true));
-}
-async function parseProblemsToPicks(p: Promise): Promise>> {
- return new Promise(async (resolve: (res: Array>) => void): Promise => {
- const picks: Array> = (await p).map((problem: IProblem) => Object.assign({}, {
- label: `${parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`,
- description: `QID:${problem.qid}`,
- detail: ((problem.scoreData?.score || "0") > "0" ? ("score: " + problem.scoreData?.score + " , ") : "") + `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`,
- value: problem,
- }));
- resolve(picks);
- });
-}
-
-function parseProblemDecorator(state: ProblemState, locked: boolean): string {
- switch (state) {
- case ProblemState.AC:
- return "$(check) ";
- case ProblemState.NotAC:
- return "$(x) ";
- default:
- return locked ? "$(lock) " : "";
- }
-}
-
-async function resolveRelativePath(relativePath: string, node: IProblem, selectedLanguage: string): Promise {
- let tag: string = "";
- if (/\$\{tag\}/i.test(relativePath)) {
- tag = (await resolveTagForProblem(node)) || "";
- }
-
- let company: string = "";
- if (/\$\{company\}/i.test(relativePath)) {
- company = (await resolveCompanyForProblem(node)) || "";
- }
-
- return relativePath.replace(/\$\{(.*?)\}/g, (_substring: string, ...args: string[]) => {
- const placeholder: string = args[0].toLowerCase().trim();
- switch (placeholder) {
- case "id":
- return node.id;
- case "name":
- return node.name;
- case "camelcasename":
- return _.camelCase(node.name);
- case "pascalcasename":
- return _.upperFirst(_.camelCase(node.name));
- case "kebabcasename":
- case "kebab-case-name":
- return _.kebabCase(node.name);
- case "snakecasename":
- case "snake_case_name":
- return _.snakeCase(node.name);
- case "ext":
- return genFileExt(selectedLanguage);
- case "language":
- return selectedLanguage;
- case "difficulty":
- return node.difficulty.toLocaleLowerCase();
- case "tag":
- return tag;
- case "company":
- return company;
- default:
- const errorMsg: string = `The config '${placeholder}' is not supported.`;
- leetCodeChannel.appendLine(errorMsg);
- throw new Error(errorMsg);
- }
- });
-}
-
-async function resolveTagForProblem(problem: IProblem): Promise {
- if (problem.tags.length === 1) {
- return problem.tags[0];
- }
- return await vscode.window.showQuickPick(
- problem.tags,
- {
- matchOnDetail: true,
- placeHolder: "Multiple tags available, please select one",
- ignoreFocusOut: true,
- },
- );
-}
-
-async function resolveCompanyForProblem(problem: IProblem): Promise {
- if (problem.companies.length === 1) {
- return problem.companies[0];
- }
- return await vscode.window.showQuickPick(problem.companies, {
- matchOnDetail: true,
- placeHolder: "Multiple tags available, please select one",
- ignoreFocusOut: true,
- });
-}
diff --git a/src/commands/star.ts b/src/commands/star.ts
deleted file mode 100644
index 3661149..0000000
--- a/src/commands/star.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-
-// Copyright (c) jdneo. All rights reserved.
-// 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 { hasStarShortcut } from "../utils/settingUtils";
-import { DialogType, promptForOpenOutputChannel } from "../utils/uiUtils";
-
-export async function addFavorite(node: LeetCodeNode): Promise {
- try {
- await leetCodeExecutor.toggleFavorite(node, true);
- await leetCodeTreeDataProvider.refresh();
- if (hasStarShortcut()) {
- customCodeLensProvider.refresh();
- }
- } catch (error) {
- await promptForOpenOutputChannel("Failed to add the problem to favorite. Please open the output channel for details.", DialogType.error);
- }
-}
-
-export async function removeFavorite(node: LeetCodeNode): Promise {
- try {
- await leetCodeExecutor.toggleFavorite(node, false);
- await leetCodeTreeDataProvider.refresh();
- if (hasStarShortcut()) {
- customCodeLensProvider.refresh();
- }
- } catch (error) {
- await promptForOpenOutputChannel("Failed to remove the problem from favorite. Please open the output channel for details.", DialogType.error);
- }
-}
diff --git a/src/commands/submit.ts b/src/commands/submit.ts
deleted file mode 100644
index 34710b6..0000000
--- a/src/commands/submit.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-import * as vscode from "vscode";
-import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider";
-import { leetCodeExecutor } from "../leetCodeExecutor";
-import { leetCodeManager } from "../leetCodeManager";
-import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils";
-import { getActiveFilePath } from "../utils/workspaceUtils";
-import { leetCodeSubmissionProvider } from "../webview/leetCodeSubmissionProvider";
-
-export async function submitSolution(uri?: vscode.Uri): Promise {
- if (!leetCodeManager.getUser()) {
- promptForSignIn();
- return;
- }
-
- const filePath: string | undefined = await getActiveFilePath(uri);
- if (!filePath) {
- return;
- }
-
- try {
- const result: string = await leetCodeExecutor.submitSolution(filePath);
- leetCodeSubmissionProvider.show(result);
- leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent());
- } catch (error) {
- await promptForOpenOutputChannel("Failed to submit the solution. Please open the output channel for details.", DialogType.error);
- return;
- }
-
- leetCodeTreeDataProvider.refresh();
-}
diff --git a/src/commands/test.ts b/src/commands/test.ts
deleted file mode 100644
index 7b0c18e..0000000
--- a/src/commands/test.ts
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-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 { 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";
-
-export async function testSolution(uri?: vscode.Uri): Promise {
- try {
- if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
- return;
- }
-
- const filePath: string | undefined = await getActiveFilePath(uri);
- if (!filePath) {
- return;
- }
- const picks: Array> = [];
- picks.push(
- {
- label: "$(three-bars) Default test cases",
- description: "",
- detail: "Test with the default cases",
- value: ":default",
- },
- {
- label: "$(pencil) Write directly...",
- description: "",
- detail: "Write test cases in input box",
- value: ":direct",
- },
- {
- label: "$(file-text) Browse...",
- description: "",
- detail: "Test with the written cases in file",
- value: ":file",
- },
- {
- label: "All Default test cases...",
- description: "",
- detail: "Test with the all default cases",
- value: ":alldefault",
- },
- );
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
- if (!choice) {
- return;
- }
-
- let result: string | undefined;
- switch (choice.value) {
- case ":default":
- result = await leetCodeExecutor.testSolution(filePath);
- break;
- case ":direct":
- const testString: string | undefined = await vscode.window.showInputBox({
- prompt: "Enter the test cases.",
- validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "Test case must not be empty.",
- placeHolder: "Example: [1,2,3]\\n4",
- ignoreFocusOut: true,
- });
- if (testString) {
- result = await leetCodeExecutor.testSolution(filePath, parseTestString(testString));
- }
- break;
- case ":file":
- const testFile: vscode.Uri[] | undefined = await showFileSelectDialog(filePath);
- 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")));
- } else {
- vscode.window.showErrorMessage("The selected test file must not be empty.");
- }
- }
- break;
- case ":alldefault":
- result = await leetCodeExecutor.testSolution(filePath, undefined, true);
- break;
- default:
- break;
- }
- if (!result) {
- return;
- }
- leetCodeSubmissionProvider.show(result);
- leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent());
- } catch (error) {
- await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error);
- }
-}
-
-export async function testSolutionDefault(uri?: vscode.Uri, allCase?: boolean): Promise {
- try {
- if (leetCodeManager.getStatus() === UserStatus.SignedOut) {
- return;
- }
-
- const filePath: string | undefined = await getActiveFilePath(uri);
- if (!filePath) {
- return;
- }
-
- let result: string | undefined = await leetCodeExecutor.testSolution(filePath, undefined, allCase || false);
- if (!result) {
- return;
- }
- leetCodeSubmissionProvider.show(result);
- leetCodeManager.emit("submit", leetCodeSubmissionProvider.getSubmitEvent());
- } catch (error) {
- await promptForOpenOutputChannel("Failed to test the solution. Please open the output channel for details.", DialogType.error);
- }
-}
-
-
-function parseTestString(test: string): string {
- if (wsl.useWsl() || !isWindows()) {
- if (wsl.useVscodeNode()) {
- return `${test}`;
- }
- return `'${test}'`;
- }
-
- // In windows and not using WSL
- if (usingCmd()) {
- // 一般需要走进这里, 除非改了 环境变量ComSpec的值
- if (wsl.useVscodeNode()) {
- return `${test.replace(/"/g, '\"')}`;
- }
- return `"${test.replace(/"/g, '\\"')}"`;
- } else {
- if (wsl.useVscodeNode()) {
- return `${test.replace(/"/g, '\"')}`;
- }
- return `'${test.replace(/"/g, '\\"')}'`;
- }
-}
diff --git a/src/controller/EventController.ts b/src/controller/EventController.ts
new file mode 100644
index 0000000..4f55adf
--- /dev/null
+++ b/src/controller/EventController.ts
@@ -0,0 +1,21 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/controller/EventController.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Monday, October 31st 2022, 10:16:47 am
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+import { eventService } from "../service/EventService";
+// 事件的控制器
+class EventContorller {
+ /**
+ * 监听事件
+ */
+ public add_event() {
+ eventService.add_event();
+ }
+}
+
+export const eventController: EventContorller = new EventContorller();
diff --git a/src/controller/FileButtonController.ts b/src/controller/FileButtonController.ts
new file mode 100644
index 0000000..c3f5cf0
--- /dev/null
+++ b/src/controller/FileButtonController.ts
@@ -0,0 +1,37 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/controller/FileButtonController.ts
+ * Path: https://github.com/ccagml/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, languages, workspace } from "vscode";
+import { fileButtonService } from "../service/FileButtonService";
+// 文件按钮的控制器
+class FileButtonController implements Disposable {
+
+ private registeredProvider: Disposable | undefined;
+ private configurationChangeListener: Disposable;
+
+ constructor() {
+ this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
+ if (event.affectsConfiguration("leetcode-problem-rating.editor.shortcuts")) {
+ fileButtonService.refresh();
+ }
+ }, this);
+
+ this.registeredProvider = languages.registerCodeLensProvider({ scheme: "file" }, fileButtonService);
+ }
+
+ public dispose(): void {
+ if (this.registeredProvider) {
+ this.registeredProvider.dispose();
+ }
+ this.configurationChangeListener.dispose();
+ }
+}
+
+export const fileButtonController: FileButtonController = new FileButtonController();
diff --git a/src/controller/LoginController.ts b/src/controller/LoginController.ts
new file mode 100644
index 0000000..2d50c0c
--- /dev/null
+++ b/src/controller/LoginController.ts
@@ -0,0 +1,190 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/controller/LoginController.ts
+ * Path: https://github.com/ccagml/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 * as systemUtils from "../utils/SystemUtils";
+import { executeService } from "../service/ExecuteService";
+import { DialogType, Endpoint, IQuickItemEx, loginArgsMapping, UserStatus } from "../model/Model";
+import { createEnvOption } from "../utils/CliUtils";
+import { logOutput, promptForOpenOutputChannel } from "../utils/OutputUtils";
+import { eventService } from "../service/EventService";
+import { window, QuickPickOptions } from "vscode";
+import { statusBarService } from "../service/StatusBarService";
+import { treeDataService } from "../service/TreeDataService";
+import { getLeetCodeEndpoint } from "../utils/ConfigUtils";
+
+
+// 登录控制器
+class LoginContorller {
+ constructor() { }
+
+ // 登录操作
+ public async signIn(): Promise {
+ const picks: Array> = [];
+ let qpOpiton: QuickPickOptions = {
+ title: "正在登录leetcode.com",
+ matchOnDescription: false,
+ matchOnDetail: false,
+ placeHolder: "请选择登录方式 正在登录leetcode.com",
+ };
+ if (getLeetCodeEndpoint() == Endpoint.LeetCodeCN) {
+ picks.push({
+ label: "LeetCode Account",
+ detail: "只能登录leetcode.cn",
+ value: "LeetCode",
+ });
+ qpOpiton.title = "正在登录中文版leetcode.cn";
+ qpOpiton.placeHolder = "请选择登录方式 正在登录中文版leetcode.cn";
+ }
+ picks.push(
+ {
+ label: "Third-Party: GitHub",
+ detail: "Use GitHub account to login",
+ value: "GitHub",
+ },
+ {
+ label: "Third-Party: LinkedIn",
+ detail: "Use LinkedIn account to login",
+ value: "LinkedIn",
+ },
+ {
+ label: "LeetCode Cookie",
+ detail: "Use LeetCode cookie copied from browser to login",
+ value: "Cookie",
+ },
+ );
+ const choice: IQuickItemEx | undefined = await window.showQuickPick(picks, qpOpiton);
+ if (!choice) {
+ return;
+ }
+ const loginMethod: string = choice.value;
+ const commandArg: string | undefined = loginArgsMapping.get(loginMethod);
+ if (!commandArg) {
+ throw new Error(`不支持 "${loginMethod}" 方式登录`);
+ }
+ const isByCookie: boolean = loginMethod === "Cookie";
+ const inMessage: string = isByCookie ? " 通过cookie登录" : "登录";
+ try {
+ const userName: string | undefined = await new Promise(async (resolve: (res: string | undefined) => void, reject: (e: Error) => void): Promise => {
+
+ const leetCodeBinaryPath: string = await executeService.getLeetCodeBinaryPath();
+
+ let childProc: cp.ChildProcess;
+
+ if (systemUtils.useVscodeNode()) {
+ childProc = cp.fork(await executeService.getLeetCodeBinaryPath(), ["user", commandArg], {
+ silent: true,
+ env: createEnvOption(),
+ });
+ } else {
+ if (systemUtils.useWsl()) {
+ childProc = cp.spawn("wsl", [executeService.node, leetCodeBinaryPath, "user", commandArg], { shell: true });
+ } else {
+ childProc = cp.spawn(executeService.node, [leetCodeBinaryPath, "user", commandArg], {
+ shell: true,
+ env: createEnvOption(),
+ });
+ }
+
+ }
+
+ childProc.stdout?.on("data", async (data: string | Buffer) => {
+ data = data.toString();
+ // vscode.window.showInformationMessage(`cc login msg ${data}.`);
+ logOutput.append(data);
+ if (data.includes("twoFactorCode")) {
+ 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",
+ });
+ if (!twoFactor) {
+ childProc.kill();
+ return resolve(undefined);
+ }
+ childProc.stdin?.write(`${twoFactor}\n`);
+ }
+
+ let successMatch;
+ try {
+ successMatch = JSON.parse(data);
+ } catch (e) {
+ successMatch = {};
+ }
+ if (successMatch.code == 100) {
+ childProc.stdin?.end();
+ return resolve(successMatch.user_name);
+ } else if (successMatch.code < 0) {
+ childProc.stdin?.end();
+ return reject(new Error(successMatch.msg));
+ }
+ });
+
+ childProc.stderr?.on("data", (data: string | Buffer) => logOutput.append(data.toString()));
+
+ childProc.on("error", reject);
+ 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",
+ });
+ if (!name) {
+ childProc.kill();
+ return resolve(undefined);
+ }
+ childProc.stdin?.write(`${name}\n`);
+ const pwd: string | undefined = await window.showInputBox({
+ prompt: isByCookie ? "Enter cookie" : "Enter password.",
+ password: true,
+ ignoreFocusOut: true,
+ validateInput: (s: string): string | undefined => s ? undefined : isByCookie ? "Cookie must not be empty" : "Password must not be empty",
+ });
+ if (!pwd) {
+ childProc.kill();
+ return resolve(undefined);
+ }
+ childProc.stdin?.write(`${pwd}\n`);
+ });
+ if (userName) {
+ window.showInformationMessage(`${inMessage} 成功`);
+ eventService.emit("statusChanged", UserStatus.SignedIn, userName);
+ }
+ } catch (error) {
+ promptForOpenOutputChannel(`${inMessage}失败. 请看看控制台输出信息`, DialogType.error);
+ }
+
+ }
+
+ // 登出
+ public async signOut(): Promise {
+ try {
+ await executeService.signOut();
+ window.showInformationMessage("成功登出");
+ eventService.emit("statusChanged", UserStatus.SignedOut, undefined);
+ } catch (error) {
+ // promptForOpenOutputChannel(`Failed to signOut. Please open the output channel for details`, DialogType.error);
+ }
+ }
+
+ // 获取登录状态
+ public async getLoginStatus() {
+ return await statusBarService.getLoginStatus();
+ }
+
+ // 删除所有缓存
+ public async deleteAllCache(): Promise {
+ await this.signOut();
+ await executeService.removeOldCache();
+ await executeService.switchEndpoint(getLeetCodeEndpoint());
+ await treeDataService.refresh();
+ }
+
+}
+
+export const loginContorller: LoginContorller = new LoginContorller();
diff --git a/src/controller/MainController.ts b/src/controller/MainController.ts
new file mode 100644
index 0000000..f5abdaa
--- /dev/null
+++ b/src/controller/MainController.ts
@@ -0,0 +1,42 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/controller/MainController.ts
+ * Path: https://github.com/ccagml/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 systemUtils from "../utils/SystemUtils";
+import { executeService } from "../service/ExecuteService";
+import { ExtensionContext } from "vscode";
+import { treeDataService } from "../service/TreeDataService";
+
+// 做杂活
+class MainContorller {
+ constructor() { }
+
+ /**
+ * 检查运行环境
+ */
+ public async checkNodeEnv(context: ExtensionContext) {
+ if (!systemUtils.useVscodeNode()) {
+ if (!await executeService.checkNodeEnv(context)) {
+ throw new Error("The environment doesn't meet requirements.");
+ }
+ }
+ }
+
+ // 初始化上下文
+ public initialize(context: ExtensionContext) {
+ treeDataService.initialize(context);
+ }
+
+
+ // 删除缓存
+ public async deleteCache() {
+ await executeService.deleteCache();
+ }
+}
+
+export const mainContorller: MainContorller = new MainContorller();
diff --git a/src/controller/TreeViewController.ts b/src/controller/TreeViewController.ts
new file mode 100644
index 0000000..33df1ce
--- /dev/null
+++ b/src/controller/TreeViewController.ts
@@ -0,0 +1,1455 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/controller/TreeViewController.ts
+ * Path: https://github.com/ccagml/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 lodash from "lodash";
+import * as path from "path";
+import * as unescapeJS from "unescape-js";
+import * as vscode from "vscode";
+import { toNumber } from "lodash";
+import { Disposable, Uri, window, QuickPickItem, workspace, WorkspaceConfiguration } from "vscode";
+import { SearchNode, userContestRankingObj, userContestRanKingBase, UserStatus, IProblem, IQuickItemEx, languages, Category, defaultProblem, ProblemState, SortingStrategy, SearchSetTypeName, RootNodeSort, SearchSetType, ISubmitEvent, SORT_ORDER, Endpoint, OpenOption, DialogType, DialogOptions } from "../model/Model";
+import { isHideSolvedProblem, isHideScoreProblem, getDescriptionConfiguration, isUseEndpointTranslation, enableSideMode, getPickOneByRankRangeMin, getPickOneByRankRangeMax, isShowLocked, updateSortingStrategy, getSortingStrategy, getLeetCodeEndpoint, openSettingsEditor } from "../utils/ConfigUtils";
+import { NodeModel } from "../model/NodeModel";
+import { ISearchSet } from "../model/Model";
+import { statusBarService } from "../service/StatusBarService";
+import { previewService } from "../service/PreviewService";
+import { executeService } from "../service/ExecuteService";
+import { getNodeIdFromFile } from "../utils/SystemUtils";
+import { logOutput, promptForOpenOutputChannel, promptForSignIn, promptHintMessage } from "../utils/OutputUtils";
+import { treeDataService } from "../service/TreeDataService";
+import { genFileExt, genFileName } from "../utils/SystemUtils";
+import { IDescriptionConfiguration, isStarShortcut } from "../utils/ConfigUtils";
+import * as systemUtils from "../utils/SystemUtils";
+import { solutionService } from "../service/SolutionService";
+import { eventService } from "../service/EventService";
+import { fileButtonService } from "../service/FileButtonService";
+
+import * as fse from "fs-extra";
+import { submissionService } from "../service/SubmissionService";
+
+
+import * as os from "os";
+import { getVsCodeConfig, getWorkspaceFolder } from "../utils/ConfigUtils";
+
+
+// 视图控制器
+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;
+
+ // 获取当前文件的路径
+ public async getActiveFilePath(uri?: vscode.Uri): Promise {
+ let textEditor: vscode.TextEditor | undefined;
+ if (uri) {
+ textEditor = await vscode.window.showTextDocument(uri, { preview: false });
+ } else {
+ textEditor = vscode.window.activeTextEditor;
+ }
+
+ if (!textEditor) {
+ return undefined;
+ }
+ if (textEditor.document.isDirty && !await textEditor.document.save()) {
+ vscode.window.showWarningMessage("请先保存当前文件");
+ return undefined;
+ }
+ return systemUtils.useWsl() ? systemUtils.toWslPath(textEditor.document.uri.fsPath) : textEditor.document.uri.fsPath;
+ }
+
+ // 提交问题
+ public async submitSolution(uri?: vscode.Uri): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+
+ const filePath: string | undefined = await this.getActiveFilePath(uri);
+ if (!filePath) {
+ return;
+ }
+
+ try {
+ const result: string = await executeService.submitSolution(filePath);
+ submissionService.show(result);
+ eventService.emit("submit", submissionService.getSubmitEvent());
+ } catch (error) {
+ await promptForOpenOutputChannel("提交出错了. 请查看控制台信息~", DialogType.error);
+ return;
+ }
+
+ treeDataService.refresh();
+ }
+
+
+ // 提交测试用例
+ public async testSolution(uri?: vscode.Uri): Promise {
+ try {
+ if (statusBarService.getStatus() === UserStatus.SignedOut) {
+ return;
+ }
+
+ const filePath: string | undefined = await this.getActiveFilePath(uri);
+ if (!filePath) {
+ return;
+ }
+ const picks: Array> = [];
+ picks.push(
+ // {
+ // label: "$(three-bars) Default test cases",
+ // description: "",
+ // detail: "默认用例",
+ // value: ":default",
+ // },
+ {
+ label: "$(pencil) Write directly...",
+ description: "",
+ detail: "输入框的测试用例",
+ value: ":direct",
+ },
+ {
+ label: "$(file-text) Browse...",
+ description: "",
+ detail: "文件中的测试用例",
+ value: ":file",
+ },
+ // {
+ // label: "All Default test cases...",
+ // description: "",
+ // detail: "所有的测试用例",
+ // value: ":alldefault",
+ // },
+ );
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
+ if (!choice) {
+ return;
+ }
+
+ let result: string | undefined;
+ let testString: string | undefined;
+ let testFile: vscode.Uri[] | undefined;
+ switch (choice.value) {
+ case ":default":
+ result = await executeService.testSolution(filePath);
+ break;
+ case ":direct":
+ testString = await vscode.window.showInputBox({
+ prompt: "Enter the test cases.",
+ validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "Test case must not be empty.",
+ placeHolder: "Example: [1,2,3]\\n4",
+ ignoreFocusOut: true,
+ });
+ if (testString) {
+ result = await executeService.testSolution(filePath, this.parseTestString(testString));
+ }
+ break;
+ case ":file":
+ testFile = await this.showFileSelectDialog(filePath);
+ if (testFile && testFile.length) {
+ const input: string = (await fse.readFile(testFile[0].fsPath, "utf-8")).trim();
+ if (input) {
+ result = await executeService.testSolution(filePath, this.parseTestString(input.replace(/\r?\n/g, "\\n")));
+ } else {
+ vscode.window.showErrorMessage("The selected test file must not be empty.");
+ }
+ }
+ break;
+ case ":alldefault":
+ result = await executeService.testSolution(filePath, undefined, true);
+ break;
+ default:
+ break;
+ }
+ if (!result) {
+ return;
+ }
+ submissionService.show(result);
+ eventService.emit("submit", submissionService.getSubmitEvent());
+ } catch (error) {
+ await promptForOpenOutputChannel("提交测试出错了. 请查看控制台信息~", DialogType.error);
+ }
+ }
+ public async showFileSelectDialog(fsPath?: string): Promise {
+ const defaultUri: vscode.Uri | undefined = this.getBelongingWorkspaceFolderUri(fsPath);
+ const options: vscode.OpenDialogOptions = {
+ defaultUri,
+ canSelectFiles: true,
+ canSelectFolders: false,
+ canSelectMany: false,
+ openLabel: "Select",
+ };
+ return await vscode.window.showOpenDialog(options);
+ }
+
+
+ public async testSolutionDefault(uri?: vscode.Uri, allCase?: boolean): Promise {
+ try {
+ if (statusBarService.getStatus() === UserStatus.SignedOut) {
+ return;
+ }
+
+ const filePath: string | undefined = await this.getActiveFilePath(uri);
+ if (!filePath) {
+ return;
+ }
+
+ let result: string | undefined = await executeService.testSolution(filePath, undefined, allCase || false);
+ if (!result) {
+ return;
+ }
+ submissionService.show(result);
+ eventService.emit("submit", submissionService.getSubmitEvent());
+ } catch (error) {
+ await promptForOpenOutputChannel("提交测试出错了. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+ public usingCmd(): boolean {
+ const comSpec: string | undefined = process.env.ComSpec;
+ // 'cmd.exe' is used as a fallback if process.env.ComSpec is unavailable.
+ if (!comSpec) {
+ return true;
+ }
+
+ if (comSpec.indexOf("cmd.exe") > -1) {
+ return true;
+ }
+ return false;
+ }
+
+ public parseTestString(test: string): string {
+ if (systemUtils.useWsl() || !systemUtils.isWindows()) {
+ if (systemUtils.useVscodeNode()) {
+ return `${test}`;
+ }
+ return `'${test}'`;
+ }
+
+ if (this.usingCmd()) {
+ // 一般需要走进这里, 除非改了 环境变量ComSpec的值
+ if (systemUtils.useVscodeNode()) {
+ //eslint-disable-next-line
+ return `${test.replace(/"/g, '\"')}`;
+ }
+ return `"${test.replace(/"/g, '\\"')}"`;
+ } else {
+ if (systemUtils.useVscodeNode()) {
+ //eslint-disable-next-line
+ return `${test.replace(/"/g, '\"')}`;
+ }
+ return `'${test.replace(/"/g, '\\"')}'`;
+ }
+ }
+
+
+ public async switchEndpoint(): Promise {
+ const isCnEnabled: boolean = getLeetCodeEndpoint() === Endpoint.LeetCodeCN;
+ const picks: Array> = [];
+ picks.push(
+ {
+ label: `${isCnEnabled ? "" : "$(check) "}LeetCode`,
+ description: "leetcode.com",
+ detail: `Enable LeetCode.com US`,
+ value: Endpoint.LeetCode,
+ },
+ {
+ label: `${isCnEnabled ? "$(check) " : ""}力扣`,
+ description: "leetcode.cn",
+ detail: `启用中国版 LeetCode.cn`,
+ value: Endpoint.LeetCodeCN,
+ },
+ );
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
+ if (!choice || choice.value === getLeetCodeEndpoint()) {
+ return;
+ }
+ const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
+ try {
+ const endpoint: string = choice.value;
+ await executeService.switchEndpoint(endpoint);
+ await leetCodeConfig.update("endpoint", endpoint, true /* UserSetting */);
+ vscode.window.showInformationMessage(`Switched the endpoint to ${endpoint}`);
+ } catch (error) {
+ await promptForOpenOutputChannel("切换站点出错. 请查看控制台信息~", DialogType.error);
+ }
+
+ try {
+ await vscode.commands.executeCommand("leetcode.signout");
+ await executeService.deleteCache();
+ await promptForSignIn();
+ } catch (error) {
+ await promptForOpenOutputChannel("登录失败. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+
+ public async switchSortingStrategy(): Promise {
+ const currentStrategy: SortingStrategy = getSortingStrategy();
+ const picks: Array> = [];
+ picks.push(
+ ...SORT_ORDER.map((s: SortingStrategy) => {
+ return {
+ label: `${currentStrategy === s ? "$(check)" : " "} ${s}`,
+ value: s,
+ };
+ }),
+ );
+
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
+ if (!choice || choice.value === currentStrategy) {
+ return;
+ }
+
+ await updateSortingStrategy(choice.value, true);
+ await treeDataService.refresh();
+ }
+
+
+ public async addFavorite(node: NodeModel): Promise {
+ try {
+ await executeService.toggleFavorite(node, true);
+ await treeDataService.refresh();
+ if (isStarShortcut()) {
+ fileButtonService.refresh();
+ }
+ } catch (error) {
+ await promptForOpenOutputChannel("添加喜欢题目失败. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+ public async removeFavorite(node: NodeModel): Promise {
+ try {
+ await executeService.toggleFavorite(node, false);
+ await treeDataService.refresh();
+ if (isStarShortcut()) {
+ fileButtonService.refresh();
+ }
+ } catch (error) {
+ await promptForOpenOutputChannel("移除喜欢题目失败. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+ public async listProblems(): Promise {
+ try {
+ if (statusBarService.getStatus() === UserStatus.SignedOut) {
+ return [];
+ }
+
+ const showLockedFlag: boolean = isShowLocked();
+ const useEndpointTranslation: boolean = isUseEndpointTranslation();
+ const result: string = await executeService.listProblems(showLockedFlag, useEndpointTranslation);
+ const all_problem_info = JSON.parse(result);
+ const problems: IProblem[] = [];
+ const AllScoreData = treeDataService.getScoreData();
+ // 增加直接在线获取分数数据
+ const AllScoreDataOnline = await treeDataService.getScoreDataOnline();
+ for (const p of all_problem_info) {
+ problems.push({
+ id: p.fid,
+ qid: p.id,
+ isFavorite: p.starred,
+ locked: p.locked,
+ state: this.parseProblemState(p.state),
+ name: p.name,
+ difficulty: p.level,
+ passRate: p.percent,
+ companies: p.companies || [],
+ tags: treeDataService.getTagsData(p.fid),
+ scoreData: AllScoreDataOnline.get(p.fid) || AllScoreData.get(p.fid),
+ isSearchResult: false,
+ input: "",
+ rootNodeSortId: RootNodeSort.ZERO,
+ todayData: undefined,
+ });
+ }
+ return problems.reverse();
+ } catch (error) {
+ await promptForOpenOutputChannel("获取题目失败. 请查看控制台信息~", DialogType.error);
+ return [];
+ }
+ }
+
+ public parseProblemState(stateOutput: string): ProblemState {
+ if (!stateOutput) {
+ return ProblemState.Unknown;
+ }
+ switch (stateOutput.trim()) {
+ case "v":
+ case "✔":
+ case "√":
+ case "ac":
+ return ProblemState.AC;
+ case "X":
+ case "✘":
+ case "×":
+ case "notac":
+ return ProblemState.NotAC;
+ default:
+ return ProblemState.Unknown;
+ }
+ }
+
+
+ public async switchDefaultLanguage(): Promise {
+ const leetCodeConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode-problem-rating");
+ const defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage");
+ const languageItems: QuickPickItem[] = [];
+ for (const language of languages) {
+ languageItems.push({
+ label: language,
+ description: defaultLanguage === language ? "Currently used" : undefined,
+ });
+ }
+ // Put the default language at the top of the list
+ languageItems.sort((a: QuickPickItem, b: QuickPickItem) => {
+ if (a.description) {
+ return Number.MIN_SAFE_INTEGER;
+ } else if (b.description) {
+ return Number.MAX_SAFE_INTEGER;
+ }
+ return a.label.localeCompare(b.label);
+ });
+
+ const selectedItem: QuickPickItem | undefined = await window.showQuickPick(languageItems, {
+ placeHolder: "请设置默认语言",
+ ignoreFocusOut: true,
+ });
+
+ if (!selectedItem) {
+ return;
+ }
+
+ leetCodeConfig.update("defaultLanguage", selectedItem.label, true /* Global */);
+ window.showInformationMessage(`设置默认语言 ${selectedItem.label} 成功`);
+ }
+
+
+ public isSubFolder(from: string, to: string): boolean {
+ const relative: string = path.relative(from, to);
+ if (relative === "") {
+ return true;
+ }
+ return !relative.startsWith("..") && !path.isAbsolute(relative);
+ }
+
+ public async determineLeetCodeFolder(): Promise {
+ let result: string;
+ const picks: Array> = [];
+ picks.push(
+ {
+ label: `Default location`,
+ detail: `${path.join(os.homedir(), ".leetcode")}`,
+ value: `${path.join(os.homedir(), ".leetcode")}`,
+ },
+ {
+ label: "$(file-directory) Browse...",
+ value: ":browse",
+ },
+ );
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
+ picks,
+ { placeHolder: "Select where you would like to save your LeetCode files" },
+ );
+ if (!choice) {
+ result = "";
+ } else if (choice.value === ":browse") {
+ const directory: vscode.Uri[] | undefined = await this.showDirectorySelectDialog();
+ if (!directory || directory.length < 1) {
+ result = "";
+ } else {
+ result = directory[0].fsPath;
+ }
+ } else {
+ result = choice.value;
+ }
+
+ getVsCodeConfig().update("workspaceFolder", result, vscode.ConfigurationTarget.Global);
+
+ return result;
+ }
+
+ public async showDirectorySelectDialog(fsPath?: string): Promise {
+ const defaultUri: vscode.Uri | undefined = this.getBelongingWorkspaceFolderUri(fsPath);
+ const options: vscode.OpenDialogOptions = {
+ defaultUri,
+ canSelectFiles: false,
+ canSelectFolders: true,
+ canSelectMany: false,
+ openLabel: "Select",
+ };
+ return await vscode.window.showOpenDialog(options);
+ }
+
+ public getBelongingWorkspaceFolderUri(fsPath: string | undefined): vscode.Uri | undefined {
+ let defaultUri: vscode.Uri | undefined;
+ if (fsPath) {
+ const workspaceFolder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(fsPath));
+ if (workspaceFolder) {
+ defaultUri = workspaceFolder.uri;
+ }
+ }
+ return defaultUri;
+ }
+
+
+ public async searchProblem(): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+
+ const picks: Array> = [];
+ picks.push(
+ {
+ label: `题目id查询`,
+ detail: `通过题目id查询`,
+ value: `byid`,
+ },
+ {
+ label: `分数范围查询`,
+ detail: `例如 1500-1600`,
+ value: `range`,
+ },
+ {
+ label: `周赛期数查询`,
+ detail: `周赛期数查询`,
+ value: `contest`,
+ },
+ {
+ label: `测试api`,
+ detail: `测试api`,
+ value: `testapi`,
+ }
+ // ,
+ // {
+ // label: `每日一题`,
+ // detail: `每日一题`,
+ // value: `today`,
+ // },
+ // {
+ // label: `查询自己竞赛信息`,
+ // detail: `查询自己竞赛信息`,
+ // value: `userContest`,
+ // }
+ );
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
+ picks,
+ { title: "选择查询选项" },
+ );
+ if (!choice) {
+ return;
+ }
+ if (choice.value == "byid") {
+ await this.searchProblemByID();
+ } else if (choice.value == "range") {
+ await this.searchScoreRange();
+ } else if (choice.value == "contest") {
+ await this.searchContest();
+ } else if (choice.value == "today") {
+ await this.searchToday();
+ } else if (choice.value == "userContest") {
+ await this.searchUserContest();
+ } else if (choice.value == "testapi") {
+ await this.testapi();
+ }
+
+ }
+
+ public async showSolution(input: NodeModel | vscode.Uri): Promise {
+ let problemInput: string | undefined;
+ if (input instanceof NodeModel) { // Triggerred from explorer
+ problemInput = input.qid;
+ } else if (input instanceof vscode.Uri) { // Triggerred from Code Lens/context menu
+ if (systemUtils.useVscodeNode()) {
+ problemInput = `${input.fsPath}`;
+ } else {
+ problemInput = `"${input.fsPath}"`;
+ if (systemUtils.useWsl()) {
+ problemInput = await systemUtils.toWslPath(input.fsPath);
+ }
+ }
+ } else if (!input) { // Triggerred from command
+ problemInput = await this.getActiveFilePath();
+ }
+
+ if (!problemInput) {
+ vscode.window.showErrorMessage("Invalid input to fetch the solution data.");
+ return;
+ }
+
+ const language: string | undefined = await this.fetchProblemLanguage();
+ if (!language) {
+ return;
+ }
+ try {
+ const needTranslation: boolean = isUseEndpointTranslation();
+ const solution: string = await executeService.showSolution(problemInput, language, needTranslation);
+ solutionService.show(unescapeJS(solution));
+ } catch (error) {
+ logOutput.appendLine(error.toString());
+ await promptForOpenOutputChannel("Failed to fetch the top voted solution. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+
+
+ public async testapi(): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+ try {
+ const twoFactor: string | undefined = await vscode.window.showInputBox({
+ prompt: "测试数据",
+ ignoreFocusOut: true,
+ validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
+ });
+
+ // vscode.window.showErrorMessage(twoFactor || "输入错误");
+ const solution: string = await executeService.getTestApi(twoFactor || "");
+ const query_result = JSON.parse(solution);
+ console.log(query_result);
+ } catch (error) {
+ logOutput.appendLine(error.toString());
+ await promptForOpenOutputChannel("Failed to fetch today question. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+
+ public async searchProblemByID(): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+ const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(
+ this.parseProblemsToPicks(this.listProblems()),
+ {
+ matchOnDetail: true,
+ matchOnDescription: true,
+ placeHolder: "Select one problem",
+ },
+ );
+ if (!choice) {
+ return;
+ }
+ await this.showProblemInternal(choice.value);
+ }
+
+ public async showProblem(node?: NodeModel): Promise {
+ if (!node) {
+ return;
+ }
+ await this.showProblemInternal(node);
+ }
+
+
+ public async pickOne(): Promise {
+ const problems: IProblem[] = await this.listProblems();
+ let randomProblem: IProblem;
+
+ const user_score = statusBarService.getUserContestScore();
+ if (user_score > 0) {
+
+ let min_score: number = getPickOneByRankRangeMin();
+ let max_score: number = getPickOneByRankRangeMax();
+ let temp_problems: IProblem[] = [];
+ const need_min = user_score + min_score;
+ const need_max = user_score + max_score;
+ problems.forEach(element => {
+ if (element.scoreData?.Rating) {
+ if (element.scoreData.Rating >= need_min && element.scoreData.Rating <= need_max) {
+ temp_problems.push(element);
+ }
+ }
+ });
+ randomProblem = temp_problems[Math.floor(Math.random() * temp_problems.length)];
+
+ } else {
+ randomProblem = problems[Math.floor(Math.random() * problems.length)];
+ }
+ if (randomProblem) {
+ await this.showProblemInternal(randomProblem);
+ }
+ }
+
+ public async fetchProblemLanguage(): Promise {
+ const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
+ let defaultLanguage: string | undefined = leetCodeConfig.get("defaultLanguage");
+ if (defaultLanguage && languages.indexOf(defaultLanguage) < 0) {
+ defaultLanguage = undefined;
+ }
+ const language: string | undefined = defaultLanguage || await vscode.window.showQuickPick(languages, { placeHolder: "Select the language you want to use", ignoreFocusOut: true });
+ // fire-and-forget default language query
+ (async (): Promise => {
+ if (language && !defaultLanguage && leetCodeConfig.get("hint.setDefaultLanguage")) {
+ const choice: vscode.MessageItem | undefined = await vscode.window.showInformationMessage(
+ `Would you like to set '${language}' as your default language?`,
+ DialogOptions.yes,
+ DialogOptions.no,
+ DialogOptions.never,
+ );
+ if (choice === DialogOptions.yes) {
+ leetCodeConfig.update("defaultLanguage", language, true /* UserSetting */);
+ } else if (choice === DialogOptions.never) {
+ leetCodeConfig.update("hint.setDefaultLanguage", false, true /* UserSetting */);
+ }
+ }
+ })();
+ return language;
+ }
+
+ public async selectWorkspaceFolder(): Promise {
+ let workspaceFolderSetting: string = getWorkspaceFolder();
+ if (workspaceFolderSetting.trim() === "") {
+ workspaceFolderSetting = await this.determineLeetCodeFolder();
+ if (workspaceFolderSetting === "") {
+ // User cancelled
+ return workspaceFolderSetting;
+ }
+ }
+ let needAsk: boolean = true;
+ await fse.ensureDir(workspaceFolderSetting);
+ for (const folder of vscode.workspace.workspaceFolders || []) {
+ if (this.isSubFolder(folder.uri.fsPath, workspaceFolderSetting)) {
+ needAsk = false;
+ }
+ }
+
+ if (needAsk) {
+ const choice: string | undefined = await vscode.window.showQuickPick(
+ [
+ OpenOption.justOpenFile,
+ OpenOption.openInCurrentWindow,
+ OpenOption.openInNewWindow,
+ OpenOption.addToWorkspace,
+ ],
+ { placeHolder: "The LeetCode workspace folder is not opened in VS Code, would you like to open it?" },
+ );
+
+ // Todo: generate file first
+ switch (choice) {
+ case OpenOption.justOpenFile:
+ return workspaceFolderSetting;
+ case OpenOption.openInCurrentWindow:
+ await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), false);
+ return "";
+ case OpenOption.openInNewWindow:
+ await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.file(workspaceFolderSetting), true);
+ return "";
+ case OpenOption.addToWorkspace:
+ vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders?.length ?? 0, 0, { uri: vscode.Uri.file(workspaceFolderSetting) });
+ break;
+ default:
+ return "";
+ }
+ }
+
+ return systemUtils.useWsl() ? systemUtils.toWslPath(workspaceFolderSetting) : workspaceFolderSetting;
+ }
+
+ public async showProblemInternal(node: IProblem): Promise {
+ try {
+ const language: string | undefined = await this.fetchProblemLanguage();
+ if (!language) {
+ return;
+ }
+
+ const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode-problem-rating");
+ const workspaceFolder: string = await this.selectWorkspaceFolder();
+ if (!workspaceFolder) {
+ return;
+ }
+
+ const fileFolder: string = leetCodeConfig
+ .get(`filePath.${language}.folder`, leetCodeConfig.get(`filePath.default.folder`, ""))
+ .trim();
+ const fileName: string = leetCodeConfig
+ .get(
+ `filePath.${language}.filename`,
+ leetCodeConfig.get(`filePath.default.filename`) || genFileName(node, language),
+ )
+ .trim();
+
+ let finalPath: string = path.join(workspaceFolder, fileFolder, fileName);
+
+ if (finalPath) {
+ finalPath = await this.resolveRelativePath(finalPath, node, language);
+ if (!finalPath) {
+ logOutput.appendLine("Showing problem canceled by user.");
+ return;
+ }
+ }
+
+ finalPath = systemUtils.useWsl() ? await systemUtils.toWinPath(finalPath) : finalPath;
+
+ const descriptionConfig: IDescriptionConfiguration = getDescriptionConfiguration();
+ const needTranslation: boolean = isUseEndpointTranslation();
+
+ 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(
+ "hint.commentDescription",
+ 'You can config how to show the problem description through "leetcode-problem-rating.showDescription".',
+ "Open settings",
+ (): Promise => openSettingsEditor("leetcode-problem-rating.showDescription"),
+ ),
+ ];
+ if (descriptionConfig.showInWebview) {
+ promises.push(this.showDescriptionView(node));
+ }
+
+ await Promise.all(promises);
+ } catch (error) {
+ await promptForOpenOutputChannel(`${error} 请查看控制台信息~`, DialogType.error);
+ }
+ }
+
+ public async showDescriptionView(node: IProblem): Promise {
+ return this.previewProblem(node, enableSideMode());
+ }
+
+ public async previewProblem(input: IProblem | Uri, isSideMode: boolean = false): Promise {
+ let node: IProblem;
+ if (input instanceof Uri) {
+ const activeFilePath: string = input.fsPath;
+ const id: string = await getNodeIdFromFile(activeFilePath);
+ if (!id) {
+ window.showErrorMessage(`Failed to resolve the problem id from file: ${activeFilePath}.`);
+ return;
+ }
+ const cachedNode: IProblem | undefined = treeViewController.getNodeById(id);
+ if (!cachedNode) {
+ window.showErrorMessage(`Failed to resolve the problem with id: ${id}.`);
+ return;
+ }
+ node = cachedNode;
+ // Move the preview page aside if it's triggered from Code Lens
+ isSideMode = true;
+ } else {
+ node = input;
+ }
+ const needTranslation: boolean = isUseEndpointTranslation();
+ const descString: string = await executeService.getDescription(node.qid, needTranslation);
+ previewService.show(descString, node, isSideMode);
+ }
+
+
+ public async searchScoreRange(): Promise {
+ const twoFactor: string | undefined = await vscode.window.showInputBox({
+ prompt: "输入分数范围 低分-高分 例如: 1500-1600",
+ ignoreFocusOut: true,
+ validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
+ });
+
+ // vscode.window.showErrorMessage(twoFactor || "输入错误");
+ const tt = Object.assign({}, SearchNode, {
+ value: twoFactor,
+ type: SearchSetType.ScoreRange,
+ time: Math.floor(Date.now() / 1000)
+ });
+ treeViewController.insertSearchSet(tt);
+ await treeDataService.refresh();
+ }
+
+ public async searchContest(): Promise {
+ const twoFactor: string | undefined = await vscode.window.showInputBox({
+ prompt: "单期数 例如: 300 或者 输入期数范围 低期数-高期数 例如: 303-306",
+ ignoreFocusOut: true,
+ validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
+ });
+
+ // vscode.window.showErrorMessage(twoFactor || "输入错误");
+ const tt = Object.assign({}, SearchNode, {
+ value: twoFactor,
+ type: SearchSetType.Context,
+ time: Math.floor(Date.now() / 1000)
+ });
+ treeViewController.insertSearchSet(tt);
+ await treeDataService.refresh();
+ }
+
+
+
+ public async searchUserContest(): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+ try {
+ const needTranslation: boolean = isUseEndpointTranslation();
+ const solution: string = await executeService.getUserContest(needTranslation, statusBarService.getUser() || "");
+ const query_result = JSON.parse(solution);
+ const tt: userContestRanKingBase = Object.assign({}, userContestRankingObj, query_result.userContestRanking);
+ eventService.emit("searchUserContest", tt);
+ } catch (error) {
+ logOutput.appendLine(error.toString());
+ await promptForOpenOutputChannel("Failed to fetch today question. 请查看控制台信息~", DialogType.error);
+ }
+ }
+ public async searchToday(): Promise {
+ if (!statusBarService.getUser()) {
+ promptForSignIn();
+ return;
+ }
+ try {
+ const needTranslation: boolean = isUseEndpointTranslation();
+ 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
+ const fid: string = query_result.fid;
+ if (fid) {
+ const tt = Object.assign({}, SearchNode, {
+ value: fid,
+ type: SearchSetType.Day,
+ time: Math.floor(Date.now() / 1000),
+ todayData: query_result,
+ });
+ treeViewController.insertSearchSet(tt);
+ await treeDataService.refresh();
+ }
+
+ } catch (error) {
+ logOutput.appendLine(error.toString());
+ await promptForOpenOutputChannel("Failed to fetch today question. 请查看控制台信息~", DialogType.error);
+ }
+ }
+
+
+
+
+ public async parseProblemsToPicks(p: Promise): Promise>> {
+ return new Promise(async (resolve: (res: Array>) => void): Promise => {
+ const picks: Array> = (await p).map((problem: IProblem) => Object.assign({}, {
+ label: `${this.parseProblemDecorator(problem.state, problem.locked)}${problem.id}.${problem.name}`,
+ description: `QID:${problem.qid}`,
+ detail: ((problem.scoreData?.score || "0") > "0" ? ("score: " + problem.scoreData?.score + " , ") : "") + `AC rate: ${problem.passRate}, Difficulty: ${problem.difficulty}`,
+ value: problem,
+ }));
+ resolve(picks);
+ });
+ }
+
+ public parseProblemDecorator(state: ProblemState, locked: boolean): string {
+ switch (state) {
+ case ProblemState.AC:
+ return "$(check) ";
+ case ProblemState.NotAC:
+ return "$(x) ";
+ default:
+ return locked ? "$(lock) " : "";
+ }
+ }
+
+ public async resolveRelativePath(relativePath: string, node: IProblem, selectedLanguage: string): Promise {
+ let tag: string = "";
+ if (/\$\{ tag \} /i.test(relativePath)) {
+ tag = (await this.resolveTagForProblem(node)) || "";
+ }
+
+ let company: string = "";
+ if (/\$\{company\}/i.test(relativePath)) {
+ company = (await this.resolveCompanyForProblem(node)) || "";
+ }
+
+ let errorMsg: string;
+ return relativePath.replace(/\$\{(.*?)\}/g, (_substring: string, ...args: string[]) => {
+ const placeholder: string = args[0].toLowerCase().trim();
+ switch (placeholder) {
+ case "id":
+ return node.id;
+ case "name":
+ return node.name;
+ case "camelcasename":
+ return lodash.camelCase(node.name);
+ case "pascalcasename":
+ return lodash.upperFirst(lodash.camelCase(node.name));
+ case "kebabcasename":
+ case "kebab-case-name":
+ return lodash.kebabCase(node.name);
+ case "snakecasename":
+ case "snake_case_name":
+ return lodash.snakeCase(node.name);
+ case "ext":
+ return genFileExt(selectedLanguage);
+ case "language":
+ return selectedLanguage;
+ case "difficulty":
+ return node.difficulty.toLocaleLowerCase();
+ case "tag":
+ return tag;
+ case "company":
+ return company;
+ default:
+ errorMsg = `The config '${placeholder}' is not supported.`;
+ logOutput.appendLine(errorMsg);
+ throw new Error(errorMsg);
+ }
+ });
+ }
+
+ public async resolveTagForProblem(problem: IProblem): Promise {
+ if (problem.tags.length === 1) {
+ return problem.tags[0];
+ }
+ return await vscode.window.showQuickPick(
+ problem.tags,
+ {
+ matchOnDetail: true,
+ placeHolder: "Multiple tags available, please select one",
+ ignoreFocusOut: true,
+ },
+ );
+ }
+
+ public async resolveCompanyForProblem(problem: IProblem): Promise {
+ if (problem.companies.length === 1) {
+ return problem.companies[0];
+ }
+ return await vscode.window.showQuickPick(problem.companies, {
+ matchOnDetail: true,
+ placeHolder: "Multiple tags available, please select one",
+ ignoreFocusOut: true,
+ });
+ }
+
+
+ public insertSearchSet(tt: ISearchSet) {
+ this.searchSet.set(tt.value, tt);
+ }
+ public clearUserScore() {
+ this.waitUserContest = false;
+ this.waitTodayQuestion = false;
+ this.searchSet = new Map();
+ }
+
+ public checkSubmit(e: ISubmitEvent) {
+ if (e.sub_type == "submit" && e.accepted) {
+ const day_start = new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000; //获取当天零点的时间
+ const day_end = new Date(new Date().setHours(0, 0, 0, 0) + 24 * 60 * 60 * 1000 - 1).getTime() / 1000; //获取当天23:59:59的时间
+ let need_get_today: boolean = false;
+ this.searchSet.forEach(element => {
+ if (element.type == SearchSetType.Day) {
+ if (day_start <= element.time && element.time <= day_end) {
+ if (e.fid == element.value) {
+ need_get_today = true;
+ }
+ }
+ }
+ });
+ if (need_get_today) {
+ this.searchToday();
+ }
+ }
+ }
+
+ public async refreshCheck(): Promise {
+ if (!statusBarService.getUser()) {
+ return;
+ }
+ const day_start = new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000; //获取当天零点的时间
+ const day_end = new Date(new Date().setHours(0, 0, 0, 0) + 24 * 60 * 60 * 1000 - 1).getTime() / 1000; //获取当天23:59:59的时间
+ let need_get_today: boolean = true;
+ this.searchSet.forEach(element => {
+ if (element.type == SearchSetType.Day) {
+ if (day_start <= element.time && element.time <= day_end) {
+ need_get_today = false;
+ } else {
+ this.waitTodayQuestion = false;
+ }
+ }
+ });
+ if (need_get_today && !this.waitTodayQuestion) {
+ this.waitTodayQuestion = true;
+ await this.searchToday();
+ }
+ let user_score = statusBarService.getUserContestScore();
+ if (!user_score && !this.waitUserContest) {
+ this.waitUserContest = true;
+ await this.searchUserContest();
+ }
+ }
+
+ public async refreshCache(): Promise {
+ const temp_searchSet: Map = this.searchSet;
+ const temp_waitTodayQuestion: boolean = this.waitTodayQuestion;
+ const temp_waitUserContest: boolean = this.waitUserContest;
+ this.dispose();
+ let user_score = statusBarService.getUserContestScore();
+ for (const problem of await this.listProblems()) {
+ this.explorerNodeMap.set(problem.id, new NodeModel(problem, true, user_score));
+ for (const company of problem.companies) {
+ this.companySet.add(company);
+ }
+ for (const tag of problem.tags) {
+ this.tagSet.add(tag);
+ }
+ }
+ this.searchSet = temp_searchSet;
+ this.waitTodayQuestion = temp_waitTodayQuestion;
+ this.waitUserContest = temp_waitUserContest;
+ }
+
+ public getRootNodes(): NodeModel[] {
+ let user_score = statusBarService.getUserContestScore();
+ const baseNode: NodeModel[] = [
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.All,
+ name: Category.All,
+ rootNodeSortId: RootNodeSort.All,
+ }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.Difficulty,
+ name: Category.Difficulty,
+ rootNodeSortId: RootNodeSort.Difficulty,
+ }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.Tag,
+ name: Category.Tag,
+ rootNodeSortId: RootNodeSort.Tag,
+ }), false),
+ // new NodeModel(Object.assign({}, defaultProblem, {
+ // id: Category.Company,
+ // name: Category.Company,
+ // rootNodeSortId: RootNodeSort.Company,
+ // }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.Favorite,
+ name: Category.Favorite,
+ rootNodeSortId: RootNodeSort.Favorite,
+ }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.Score,
+ name: Category.Score,
+ rootNodeSortId: RootNodeSort.Score,
+ }), false, user_score),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: Category.Choice,
+ name: Category.Choice,
+ rootNodeSortId: RootNodeSort.Choice,
+ }), false),
+ ];
+ this.searchSet.forEach(element => {
+ if (element.type == SearchSetType.Day) {
+ const curDate = new Date(element.time * 1000);
+ baseNode.push(new NodeModel(Object.assign({}, defaultProblem, {
+ id: element.type,
+ name: "[" + (curDate.getFullYear()) + "-" + (curDate.getMonth() + 1) + "-" + (curDate.getDate()) + "]" + SearchSetTypeName[SearchSetType.Day],
+ input: element.value,
+ isSearchResult: true,
+ rootNodeSortId: RootNodeSort[element.type],
+ todayData: element.todayData
+ }), false));
+ } else {
+ baseNode.push(new NodeModel(Object.assign({}, defaultProblem, {
+ id: element.type,
+ name: SearchSetTypeName[element.type] + element.value,
+ input: element.value,
+ isSearchResult: true,
+ rootNodeSortId: RootNodeSort[element.type],
+ }), false));
+ }
+ });
+ baseNode.sort(function (a: NodeModel, b: NodeModel): number {
+ if (a.rootNodeSortId < b.rootNodeSortId) {
+ return -1;
+ } else if (a.rootNodeSortId > b.rootNodeSortId) {
+ return 1;
+ }
+ return 0;
+ });
+ return baseNode;
+ }
+
+ public getScoreRangeNodes(rank_range: string): NodeModel[] {
+ const sorceNode: NodeModel[] = [];
+ const rank_r: Array = rank_range.split("-");
+ let rank_a = Number(rank_r[0]);
+ let rank_b = Number(rank_r[1]);
+ if (rank_a > 0 && rank_b > 0) {
+ if (rank_a > rank_b) {
+ const rank_c: number = rank_a;
+ rank_a = rank_b;
+ rank_b = rank_c;
+ }
+
+ this.explorerNodeMap.forEach(element => {
+ if (!this.canShow(element)) {
+ return;
+ }
+ if (rank_a <= Number(element.score) && Number(element.score) <= rank_b) {
+ sorceNode.push(element);
+ }
+ });
+ }
+ return this.applySortingStrategy(sorceNode);
+ }
+
+ public canShow(element: NodeModel) {
+ if (isHideSolvedProblem() && element.state === ProblemState.AC) {
+ return false;
+ }
+ if (isHideScoreProblem(element, element.user_score)) {
+ return false;
+ }
+ return true;
+ }
+
+ public getContextNodes(rank_range: string): NodeModel[] {
+ const sorceNode: NodeModel[] = [];
+ const rank_r: Array = rank_range.split("-");
+ let rank_a = Number(rank_r[0]);
+ let rank_b = Number(rank_r[1]);
+ if (rank_a > 0) {
+ this.explorerNodeMap.forEach(element => {
+ if (!this.canShow(element)) {
+ return;
+ }
+ const slu = element.ContestSlug;
+ const slu_arr: Array = slu.split("-");
+ const slu_id = Number(slu_arr[slu_arr.length - 1]);
+ if (rank_b > 0 && rank_a <= slu_id && slu_id <= rank_b) {
+ sorceNode.push(element);
+ } else if (rank_a == slu_id) {
+ sorceNode.push(element);
+ }
+ });
+ }
+ return this.applySortingStrategy(sorceNode);
+ }
+ public getDayNodes(element: NodeModel | undefined): NodeModel[] {
+ const rank_range: string = element?.input || "";
+ const sorceNode: NodeModel[] = [];
+ if (rank_range) {
+ this.explorerNodeMap.forEach(new_node => {
+ if (new_node.id == rank_range) {
+ new_node.todayData = element?.todayData;
+ sorceNode.push(new_node);
+ }
+ });
+ }
+ return this.applySortingStrategy(sorceNode);
+ }
+
+ public getAllNodes(): NodeModel[] {
+ return this.applySortingStrategy(
+ Array.from(this.explorerNodeMap.values()).filter(p => this.canShow(p)),
+ );
+ }
+
+ public getAllDifficultyNodes(): NodeModel[] {
+ const res: NodeModel[] = [];
+ res.push(
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Difficulty}.Easy`,
+ name: "Easy",
+ }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Difficulty}.Medium`,
+ name: "Medium",
+ }), false),
+ new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Difficulty}.Hard`,
+ name: "Hard",
+ }), false),
+ );
+ this.sortSubCategoryNodes(res, Category.Difficulty);
+ return res;
+ }
+
+ 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 NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Score}.${element}`,
+ name: `${element}`,
+ }), false, user_score));
+ }
+ });
+
+ this.sortSubCategoryNodes(res, Category.Score);
+ return res;
+ }
+
+ public getAllChoiceNodes(): NodeModel[] {
+ const res: NodeModel[] = [];
+
+ const all_choice = treeDataService.getChoiceData();
+ all_choice.forEach(element => {
+ res.push(new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Choice}.${element.id}`,
+ name: `${element.name}`,
+ }), false));
+ });
+ this.sortSubCategoryNodes(res, Category.Choice);
+ return res;
+ }
+
+ public getAllCompanyNodes(): NodeModel[] {
+ const res: NodeModel[] = [];
+ for (const company of this.companySet.values()) {
+ res.push(new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Company}.${company}`,
+ name: lodash.startCase(company),
+ }), false));
+ }
+ this.sortSubCategoryNodes(res, Category.Company);
+ return res;
+ }
+
+ public getAllTagNodes(): NodeModel[] {
+ const res: NodeModel[] = [];
+ for (const tag of this.tagSet.values()) {
+ res.push(new NodeModel(Object.assign({}, defaultProblem, {
+ id: `${Category.Tag}.${tag}`,
+ name: lodash.startCase(tag),
+ }), false));
+ }
+ this.sortSubCategoryNodes(res, Category.Tag);
+ return res;
+ }
+
+ public getNodeById(id: string): NodeModel | undefined {
+ return this.explorerNodeMap.get(id);
+ }
+
+ public getFavoriteNodes(): NodeModel[] {
+ const res: NodeModel[] = [];
+ for (const node of this.explorerNodeMap.values()) {
+ if (!this.canShow(node)) {
+ continue;
+ }
+ if (node.isFavorite) {
+ res.push(node);
+ }
+ }
+ return this.applySortingStrategy(res);
+ }
+
+ public getChildrenNodesById(id: string): NodeModel[] {
+ // The sub-category node's id is named as {Category.SubName}
+ const metaInfo: string[] = id.split(".");
+ const res: NodeModel[] = [];
+
+ const choiceQuestionId: Map = new Map();
+ if (metaInfo[0] == Category.Choice) {
+ const all_choice = treeDataService.getChoiceData();
+ all_choice.forEach(element => {
+ if (element.id == metaInfo[1]) {
+ element.questions.forEach(kk => {
+ choiceQuestionId[kk] = true;
+ });
+ return;
+ }
+ });
+ }
+
+ for (const node of this.explorerNodeMap.values()) {
+ if (!this.canShow(node)) {
+ continue;
+ }
+ 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;
+ case Category.Score:
+ if (node.score > "0") {
+ const check_rank = toNumber(metaInfo[1]);
+ const node_rank = toNumber(node.score);
+ if (check_rank <= node_rank && node_rank < check_rank + 100) {
+ res.push(node);
+ }
+ }
+ break;
+ case Category.Choice:
+ if (choiceQuestionId[Number(node.qid)]) {
+ res.push(node);
+ }
+ }
+ }
+ return this.applySortingStrategy(res);
+ }
+
+ public dispose(): void {
+ this.explorerNodeMap.clear();
+ this.companySet.clear();
+ this.tagSet.clear();
+ }
+
+ private sortSubCategoryNodes(subCategoryNodes: NodeModel[], category: Category): void {
+ switch (category) {
+ case Category.Difficulty:
+ subCategoryNodes.sort((a: NodeModel, b: NodeModel): number => {
+ function getValue(input: NodeModel): 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: NodeModel, b: NodeModel): 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;
+ }
+ }
+
+ private applySortingStrategy(nodes: NodeModel[]): NodeModel[] {
+ const strategy: SortingStrategy = getSortingStrategy();
+ switch (strategy) {
+ 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 treeViewController: TreeViewController = new TreeViewController();
diff --git a/src/dao/choiceDao.ts b/src/dao/choiceDao.ts
new file mode 100644
index 0000000..ec3bba4
--- /dev/null
+++ b/src/dao/choiceDao.ts
@@ -0,0 +1,2095 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/dao/choiceDao.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, November 10th 2022, 11:34:10 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+class ChoiceDao {
+
+ public getChoiceData() {
+ return this.choiceData;
+ }
+
+ private choiceData = [
+ {
+ "id": "shopee",
+ "name": "Shopee精选",
+ "questions": [
+ 341,
+ 1000447,
+ 1000446,
+ 1000445,
+ 1000444,
+ 1000443,
+ 232,
+ 871,
+ 102,
+ 101,
+ 15,
+ 460,
+ 456,
+ 448,
+ 179,
+ 432,
+ 48,
+ 37,
+ 20,
+ 146
+ ],
+
+ },
+ {
+ "id": "binary-search",
+ "name": "二分查找",
+ "questions": [
+ 4,
+ 1550,
+ 540,
+ 1056,
+ 33,
+ 34,
+ 35,
+ 1059,
+ 1060,
+ 1083,
+ 2047,
+ 69,
+ 1605,
+ 74,
+ 1612,
+ 1102,
+ 1615,
+ 81,
+ 1621,
+ 1122,
+ 611,
+ 1645,
+ 1134,
+ 1646,
+ 1143,
+ 633,
+ 1149,
+ 644,
+ 1672,
+ 1675,
+ 1679,
+ 658,
+ 1684,
+ 153,
+ 154,
+ 668,
+ 1185,
+ 162,
+ 167,
+ 1192,
+ 1730,
+ 718,
+ 719,
+ 1232,
+ 209,
+ 1753,
+ 222,
+ 1249,
+ 1766,
+ 745,
+ 1771,
+ 1262,
+ 240,
+ 1290,
+ 270,
+ 786,
+ 275,
+ 788,
+ 278,
+ 792,
+ 794,
+ 1307,
+ 287,
+ 802,
+ 1831,
+ 1832,
+ 809,
+ 300,
+ 302,
+ 1326,
+ 1851,
+ 1352,
+ 853,
+ 350,
+ 1374,
+ 352,
+ 1886,
+ 1891,
+ 1384,
+ 363,
+ 367,
+ 882,
+ 374,
+ 378,
+ 894,
+ 1918,
+ 1408,
+ 1413,
+ 1929,
+ 907,
+ 912,
+ 1946,
+ 923,
+ 1957,
+ 1966,
+ 947,
+ 436,
+ 1463,
+ 441,
+ 1468,
+ 1984,
+ 1476,
+ 1486,
+ 2000,
+ 2006,
+ 2018,
+ 2027,
+ 2036,
+ 2045,
+ 1023
+ ],
+
+ },
+ {
+ "id": "lcof",
+ "name": "剑指 Offer",
+ "questions": [
+ 1000228,
+ 1000229,
+ 1000230,
+ 1000231,
+ 1000232,
+ 1000233,
+ 1000234,
+ 1000235,
+ 1000236,
+ 1000237,
+ 1000238,
+ 1000239,
+ 1000240,
+ 1000241,
+ 1000242,
+ 1000243,
+ 1000244,
+ 1000245,
+ 1000246,
+ 1000247,
+ 1000248,
+ 1000249,
+ 1000250,
+ 1000251,
+ 1000252,
+ 1000253,
+ 1000254,
+ 1000255,
+ 1000256,
+ 1000257,
+ 1000258,
+ 1000259,
+ 1000260,
+ 1000261,
+ 1000262,
+ 1000263,
+ 1000264,
+ 1000265,
+ 1000266,
+ 1000267,
+ 1000268,
+ 1000269,
+ 1000270,
+ 1000271,
+ 1000272,
+ 1000273,
+ 1000274,
+ 1000275,
+ 1000276,
+ 1000277,
+ 1000278,
+ 1000279,
+ 1000280,
+ 1000281,
+ 1000282,
+ 1000283,
+ 1000284,
+ 1000285,
+ 1000286,
+ 1000287,
+ 1000288,
+ 1000289,
+ 1000290,
+ 1000291,
+ 1000292,
+ 1000293,
+ 1000294,
+ 1000295,
+ 1000296,
+ 1000297,
+ 1000298,
+ 1000299,
+ 1000300,
+ 1000301,
+ 1000302,
+ 1000303,
+ 1000304,
+ 1000305,
+ 1000306,
+ 1000307,
+ 1000308,
+ 1000309,
+ 1000310,
+ 1000311,
+ 1000312,
+ 1000313,
+ 1000314,
+ 1000315,
+ 1000316,
+ 1000317,
+ 1000318,
+ 1000319,
+ 1000320,
+ 1000321,
+ 1000322,
+ 1000323,
+ 1000324,
+ 1000325,
+ 1000326,
+ 1000327,
+ 1000328,
+ 1000329,
+ 1000330,
+ 1000331,
+ 1000332,
+ 1000333,
+ 1000334,
+ 1000335,
+ 1000336,
+ 1000337,
+ 1000338,
+ 1000339,
+ 1000340,
+ 1000341,
+ 1000342,
+ 1000343,
+ 1000344,
+ 1000345,
+ 1000346,
+ 100273,
+ 100274,
+ 100275,
+ 100276,
+ 100277,
+ 100278,
+ 100279,
+ 100280,
+ 100281,
+ 100282,
+ 100283,
+ 100284,
+ 100285,
+ 100286,
+ 100287,
+ 100288,
+ 100289,
+ 100290,
+ 100291,
+ 100292,
+ 100293,
+ 100294,
+ 100295,
+ 100296,
+ 100297,
+ 100298,
+ 100299,
+ 100300,
+ 100301,
+ 100302,
+ 100303,
+ 100304,
+ 100305,
+ 100306,
+ 100307,
+ 100308,
+ 100309,
+ 100310,
+ 100311,
+ 100312,
+ 100313,
+ 100314,
+ 100315,
+ 100316,
+ 100317,
+ 100318,
+ 100319,
+ 100320,
+ 100321,
+ 100322,
+ 100323,
+ 100324,
+ 100325,
+ 100326,
+ 100327,
+ 100328,
+ 100329,
+ 100330,
+ 100331,
+ 100332,
+ 100333,
+ 100334,
+ 100335,
+ 100336,
+ 100337,
+ 100338,
+ 100339,
+ 100340,
+ 100341,
+ 100342,
+ 100343,
+ 100344,
+ 100345,
+ 100346,
+ 100347
+ ],
+
+ },
+ {
+ "id": "e8X3pBZi",
+ "name": "剑指 Offer(专项突击版)",
+ "questions": [
+ 1000228,
+ 1000229,
+ 1000230,
+ 1000231,
+ 1000232,
+ 1000233,
+ 1000234,
+ 1000235,
+ 1000236,
+ 1000237,
+ 1000238,
+ 1000239,
+ 1000240,
+ 1000241,
+ 1000242,
+ 1000243,
+ 1000244,
+ 1000245,
+ 1000246,
+ 1000247,
+ 1000248,
+ 1000249,
+ 1000250,
+ 1000251,
+ 1000252,
+ 1000253,
+ 1000254,
+ 1000255,
+ 1000256,
+ 1000257,
+ 1000258,
+ 1000259,
+ 1000260,
+ 1000261,
+ 1000262,
+ 1000263,
+ 1000264,
+ 1000265,
+ 1000266,
+ 1000267,
+ 1000268,
+ 1000269,
+ 1000270,
+ 1000271,
+ 1000272,
+ 1000273,
+ 1000274,
+ 1000275,
+ 1000276,
+ 1000277,
+ 1000278,
+ 1000279,
+ 1000280,
+ 1000281,
+ 1000282,
+ 1000283,
+ 1000284,
+ 1000285,
+ 1000286,
+ 1000287,
+ 1000288,
+ 1000289,
+ 1000290,
+ 1000291,
+ 1000292,
+ 1000293,
+ 1000294,
+ 1000295,
+ 1000296,
+ 1000297,
+ 1000298,
+ 1000299,
+ 1000300,
+ 1000301,
+ 1000302,
+ 1000303,
+ 1000304,
+ 1000305,
+ 1000306,
+ 1000307,
+ 1000308,
+ 1000309,
+ 1000310,
+ 1000311,
+ 1000312,
+ 1000313,
+ 1000314,
+ 1000315,
+ 1000316,
+ 1000317,
+ 1000318,
+ 1000319,
+ 1000320,
+ 1000321,
+ 1000322,
+ 1000323,
+ 1000324,
+ 1000325,
+ 1000326,
+ 1000327,
+ 1000328,
+ 1000329,
+ 1000330,
+ 1000331,
+ 1000332,
+ 1000333,
+ 1000334,
+ 1000335,
+ 1000336,
+ 1000337,
+ 1000338,
+ 1000339,
+ 1000340,
+ 1000341,
+ 1000342,
+ 1000343,
+ 1000344,
+ 1000345,
+ 1000346
+ ],
+
+ },
+ {
+ "id": "xb9nqhhg",
+ "name": "剑指 Offer(第 2 版)",
+ "questions": [
+ 100319,
+ 100328,
+ 100327,
+ 100326,
+ 100325,
+ 100324,
+ 100323,
+ 100322,
+ 100321,
+ 100320,
+ 100329,
+ 100318,
+ 100317,
+ 100316,
+ 100315,
+ 100314,
+ 100313,
+ 100312,
+ 100311,
+ 100338,
+ 100347,
+ 100346,
+ 100345,
+ 100344,
+ 100343,
+ 100342,
+ 100341,
+ 100340,
+ 100339,
+ 100310,
+ 100337,
+ 100336,
+ 100335,
+ 100334,
+ 100333,
+ 100332,
+ 100331,
+ 100330,
+ 100282,
+ 100291,
+ 100290,
+ 100289,
+ 100288,
+ 100287,
+ 100286,
+ 100285,
+ 100284,
+ 100283,
+ 100292,
+ 100281,
+ 100280,
+ 100279,
+ 100278,
+ 100277,
+ 100276,
+ 100275,
+ 100274,
+ 100301,
+ 100309,
+ 100308,
+ 100307,
+ 100306,
+ 100305,
+ 100304,
+ 100303,
+ 100302,
+ 100273,
+ 100300,
+ 100299,
+ 100298,
+ 100297,
+ 100296,
+ 100295,
+ 100294,
+ 100293
+ ],
+
+ },
+ {
+ "id": "lccup",
+ "name": "力扣杯竞赛真题集",
+ "questions": [
+ 1000134,
+ 1000222,
+ 1000362,
+ 1000367,
+ 1000368,
+ 1000369,
+ 1000370,
+ 1000371,
+ 1000373,
+ 1000374,
+ 1000375,
+ 1000130,
+ 1000131,
+ 1000132,
+ 1000133,
+ 100094,
+ 1000138,
+ 1000139,
+ 1000140,
+ 1000146,
+ 1000147,
+ 1000056,
+ 1000057,
+ 1000058,
+ 1000059,
+ 100092,
+ 100093,
+ 1000062,
+ 1000063,
+ 1000218,
+ 100107,
+ 1000085,
+ 1000086,
+ 1000087,
+ 1000088,
+ 1000089,
+ 1000090,
+ 1000091,
+ 1052,
+ 1053,
+ 1000093,
+ 1000215,
+ 1000216,
+ 100096,
+ 1058,
+ 1059,
+ 1060,
+ 1061,
+ 1000219,
+ 1000220,
+ 1000223,
+ 1000224,
+ 1000221,
+ 1000359,
+ 1000361,
+ 813,
+ 1069
+ ],
+
+ },
+ {
+ "id": "dynamic-programming",
+ "name": "动态规划",
+ "questions": [
+ 1025,
+ 514,
+ 516,
+ 5,
+ 518,
+ 10,
+ 526,
+ 1042,
+ 1559,
+ 1051,
+ 32,
+ 1057,
+ 546,
+ 1571,
+ 1060,
+ 549,
+ 39,
+ 40,
+ 1063,
+ 42,
+ 1067,
+ 1068,
+ 45,
+ 1583,
+ 562,
+ 53,
+ 55,
+ 568,
+ 62,
+ 63,
+ 64,
+ 576,
+ 70,
+ 72,
+ 1105,
+ 1617,
+ 600,
+ 91,
+ 96,
+ 1129,
+ 1130,
+ 1134,
+ 115,
+ 118,
+ 119,
+ 120,
+ 121,
+ 122,
+ 123,
+ 124,
+ 634,
+ 1669,
+ 646,
+ 647,
+ 650,
+ 139,
+ 140,
+ 651,
+ 1166,
+ 1680,
+ 1170,
+ 152,
+ 664,
+ 1178,
+ 1690,
+ 673,
+ 1196,
+ 174,
+ 688,
+ 1201,
+ 1202,
+ 691,
+ 698,
+ 188,
+ 1213,
+ 1220,
+ 198,
+ 712,
+ 714,
+ 1228,
+ 1744,
+ 1236,
+ 213,
+ 727,
+ 1240,
+ 1242,
+ 221,
+ 1758,
+ 1250,
+ 740,
+ 741,
+ 747,
+ 238,
+ 751,
+ 1263,
+ 1789,
+ 254,
+ 256,
+ 1286,
+ 264,
+ 265,
+ 1296,
+ 279,
+ 1822,
+ 1828,
+ 294,
+ 298,
+ 300,
+ 304,
+ 309,
+ 312,
+ 1851,
+ 322,
+ 1352,
+ 329,
+ 333,
+ 337,
+ 1361,
+ 343,
+ 351,
+ 867,
+ 1893,
+ 361,
+ 877,
+ 368,
+ 1906,
+ 1398,
+ 376,
+ 377,
+ 1402,
+ 1403,
+ 896,
+ 1924,
+ 392,
+ 911,
+ 923,
+ 413,
+ 1437,
+ 416,
+ 418,
+ 930,
+ 938,
+ 435,
+ 954,
+ 446,
+ 1471,
+ 1474,
+ 452,
+ 1989,
+ 967,
+ 1996,
+ 464,
+ 977,
+ 471,
+ 486,
+ 487,
+ 494,
+ 2031,
+ 1008,
+ 1522,
+ 1013,
+ 1017,
+ 1531,
+ 1022,
+ 1535
+ ],
+
+ },
+ {
+ "id": "tusmiple",
+ "name": "图森未来",
+ "questions": [
+ 718,
+ 127,
+ 1005,
+ 1000428,
+ 1000427,
+ 1000426,
+ 1000425,
+ 1000424,
+ 1000423,
+ 726,
+ 522,
+ 973,
+ 1217,
+ 193,
+ 1972,
+ 171,
+ 1957,
+ 36,
+ 27,
+ 1294
+ ],
+
+ },
+ {
+ "id": "graph",
+ "name": "图论",
+ "questions": [
+ 317,
+ 1912,
+ 1389,
+ 877,
+ 365,
+ 871,
+ 869,
+ 1380,
+ 352,
+ 863,
+ 323,
+ 895,
+ 310,
+ 820,
+ 305,
+ 1325,
+ 813,
+ 803,
+ 801,
+ 1309,
+ 1308,
+ 794,
+ 1986,
+ 505,
+ 2040,
+ 2038,
+ 2035,
+ 499,
+ 490,
+ 1492,
+ 1485,
+ 971,
+ 964,
+ 1815,
+ 960,
+ 949,
+ 433,
+ 1456,
+ 1447,
+ 1442,
+ 417,
+ 922,
+ 1428,
+ 1100,
+ 1191,
+ 1701,
+ 1696,
+ 1171,
+ 127,
+ 1661,
+ 1144,
+ 1117,
+ 1613,
+ 1101,
+ 1706,
+ 1085,
+ 1587,
+ 1073,
+ 1576,
+ 547,
+ 1058,
+ 542,
+ 1558,
+ 1039,
+ 721,
+ 1300,
+ 269,
+ 261,
+ 753,
+ 744,
+ 737,
+ 1757,
+ 733,
+ 1753,
+ 210,
+ 1032,
+ 207,
+ 1229,
+ 1738,
+ 200,
+ 1223,
+ 695,
+ 694,
+ 685,
+ 684
+ ],
+
+ },
+ {
+ "id": "bytedancecampus",
+ "name": "字节校园",
+ "questions": [
+ 69,
+ 88,
+ 215,
+ 206,
+ 76,
+ 200,
+ 72,
+ 199,
+ 198,
+ 92,
+ 322,
+ 64,
+ 56,
+ 54,
+ 53,
+ 948,
+ 46,
+ 300,
+ 94,
+ 102,
+ 103,
+ 232,
+ 105,
+ 236,
+ 239,
+ 1000185,
+ 1000182,
+ 1000183,
+ 1000184,
+ 121,
+ 1000186,
+ 1000187,
+ 124,
+ 135,
+ 146,
+ 143,
+ 142,
+ 15,
+ 14,
+ 141,
+ 394,
+ 1000188,
+ 20,
+ 7,
+ 129,
+ 5,
+ 4,
+ 3,
+ 2,
+ 1,
+ 128,
+ 21,
+ 22,
+ 23,
+ 151,
+ 25,
+ 152,
+ 792,
+ 923,
+ 31,
+ 160,
+ 33,
+ 415,
+ 41,
+ 42,
+ 43
+ ],
+
+ },
+ {
+ "id": "ponyai",
+ "name": "小马智行 Pony.ai",
+ "questions": [
+ 15,
+ 1000351,
+ 1000350,
+ 1000349,
+ 92,
+ 1000347,
+ 148,
+ 146,
+ 1105,
+ 1000352,
+ 909,
+ 173,
+ 1000348,
+ 105,
+ 39,
+ 1860,
+ 98,
+ 1441
+ ],
+
+ },
+ {
+ "id": "cmbchina-cc",
+ "name": "招商银行信用卡",
+ "questions": [
+ 33,
+ 124,
+ 103,
+ 88,
+ 199,
+ 198,
+ 322,
+ 64,
+ 53,
+ 41,
+ 1,
+ 415,
+ 923,
+ 22,
+ 21,
+ 20,
+ 15,
+ 7,
+ 5,
+ 3
+ ],
+ },
+ {
+ "id": "data-structures",
+ "name": "数据结构",
+ "questions": [
+ 1,
+ 2,
+ 5,
+ 1032,
+ 15,
+ 1039,
+ 20,
+ 21,
+ 23,
+ 24,
+ 25,
+ 547,
+ 36,
+ 42,
+ 43,
+ 44,
+ 48,
+ 49,
+ 560,
+ 53,
+ 566,
+ 56,
+ 59,
+ 1085,
+ 73,
+ 1609,
+ 75,
+ 82,
+ 83,
+ 84,
+ 1107,
+ 88,
+ 94,
+ 98,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 108,
+ 112,
+ 113,
+ 118,
+ 119,
+ 121,
+ 124,
+ 1661,
+ 128,
+ 1665,
+ 642,
+ 136,
+ 138,
+ 141,
+ 142,
+ 143,
+ 144,
+ 145,
+ 653,
+ 148,
+ 155,
+ 1693,
+ 160,
+ 1701,
+ 169,
+ 173,
+ 1710,
+ 187,
+ 199,
+ 203,
+ 206,
+ 208,
+ 1745,
+ 211,
+ 212,
+ 214,
+ 215,
+ 217,
+ 218,
+ 729,
+ 226,
+ 739,
+ 230,
+ 232,
+ 235,
+ 236,
+ 238,
+ 1774,
+ 240,
+ 242,
+ 761,
+ 253,
+ 766,
+ 768,
+ 261,
+ 783,
+ 784,
+ 281,
+ 290,
+ 803,
+ 295,
+ 297,
+ 305,
+ 817,
+ 1345,
+ 323,
+ 325,
+ 838,
+ 334,
+ 336,
+ 337,
+ 347,
+ 1371,
+ 350,
+ 358,
+ 871,
+ 366,
+ 1903,
+ 369,
+ 378,
+ 892,
+ 383,
+ 387,
+ 394,
+ 402,
+ 409,
+ 922,
+ 415,
+ 1951,
+ 1442,
+ 1450,
+ 435,
+ 448,
+ 450,
+ 451,
+ 452,
+ 454,
+ 456,
+ 2009,
+ 1008,
+ 1014
+ ],
+
+ },
+ {
+ "id": "xb9lfcwi",
+ "name": "程序员面试金典(第 6 版)",
+ "questions": [
+ 100352,
+ 100353,
+ 100354,
+ 100355,
+ 100356,
+ 1000003,
+ 1000004,
+ 1000005,
+ 1000006,
+ 1000007,
+ 1000008,
+ 1000009,
+ 1000010,
+ 1000011,
+ 1000012,
+ 1000013,
+ 1000015,
+ 1000016,
+ 1000017,
+ 1000018,
+ 1000019,
+ 1000020,
+ 1000021,
+ 1000022,
+ 1000023,
+ 1000024,
+ 1000025,
+ 1000026,
+ 1000027,
+ 1000028,
+ 1000029,
+ 1000030,
+ 1000031,
+ 1000032,
+ 1000033,
+ 1000034,
+ 1000035,
+ 1000036,
+ 1000037,
+ 1000038,
+ 1000039,
+ 1000040,
+ 1000041,
+ 1000042,
+ 1000043,
+ 1000044,
+ 1000045,
+ 1000046,
+ 1000047,
+ 1000048,
+ 1000049,
+ 1000050,
+ 1000051,
+ 100158,
+ 100159,
+ 100160,
+ 100161,
+ 100162,
+ 100163,
+ 100164,
+ 100167,
+ 100168,
+ 100169,
+ 100170,
+ 100171,
+ 100172,
+ 100173,
+ 100174,
+ 100175,
+ 100176,
+ 100177,
+ 100178,
+ 100179,
+ 100180,
+ 100181,
+ 100182,
+ 100183,
+ 100184,
+ 100185,
+ 100186,
+ 100187,
+ 100188,
+ 100195,
+ 100196,
+ 100197,
+ 100198,
+ 100199,
+ 100200,
+ 100201,
+ 100202,
+ 100203,
+ 100228,
+ 100229,
+ 100230,
+ 100231,
+ 100232,
+ 100233,
+ 100240,
+ 100241,
+ 100242,
+ 100258,
+ 100259,
+ 100260,
+ 100261,
+ 100262,
+ 100348,
+ 100349,
+ 100350,
+ 100351
+ ],
+
+ },
+ {
+ "id": "algorithms",
+ "name": "算法",
+ "questions": [
+ 1025,
+ 3,
+ 4,
+ 5,
+ 1028,
+ 10,
+ 11,
+ 1036,
+ 1037,
+ 15,
+ 17,
+ 19,
+ 21,
+ 22,
+ 1046,
+ 542,
+ 33,
+ 34,
+ 35,
+ 547,
+ 37,
+ 1059,
+ 39,
+ 40,
+ 42,
+ 45,
+ 46,
+ 47,
+ 557,
+ 51,
+ 53,
+ 55,
+ 567,
+ 2047,
+ 572,
+ 62,
+ 70,
+ 582,
+ 72,
+ 583,
+ 74,
+ 1609,
+ 76,
+ 77,
+ 78,
+ 79,
+ 1101,
+ 82,
+ 85,
+ 90,
+ 91,
+ 617,
+ 1134,
+ 116,
+ 117,
+ 120,
+ 123,
+ 130,
+ 131,
+ 132,
+ 136,
+ 139,
+ 1165,
+ 146,
+ 1171,
+ 149,
+ 153,
+ 159,
+ 673,
+ 162,
+ 167,
+ 1192,
+ 174,
+ 695,
+ 189,
+ 190,
+ 191,
+ 198,
+ 200,
+ 201,
+ 202,
+ 713,
+ 714,
+ 715,
+ 206,
+ 207,
+ 209,
+ 210,
+ 213,
+ 221,
+ 733,
+ 1250,
+ 231,
+ 239,
+ 241,
+ 753,
+ 254,
+ 260,
+ 269,
+ 1300,
+ 278,
+ 792,
+ 283,
+ 286,
+ 287,
+ 800,
+ 300,
+ 301,
+ 813,
+ 309,
+ 310,
+ 315,
+ 322,
+ 329,
+ 337,
+ 340,
+ 343,
+ 344,
+ 865,
+ 874,
+ 893,
+ 895,
+ 384,
+ 394,
+ 908,
+ 410,
+ 413,
+ 416,
+ 417,
+ 1442,
+ 438,
+ 460,
+ 1485,
+ 2019,
+ 486,
+ 1512,
+ 1019,
+ 1023
+ ],
+
+ },
+ {
+ "id": "programming-skills",
+ "name": "编程能力",
+ "questions": [
+ 2,
+ 1031,
+ 8,
+ 525,
+ 23,
+ 535,
+ 28,
+ 43,
+ 556,
+ 48,
+ 49,
+ 1584,
+ 54,
+ 566,
+ 58,
+ 61,
+ 65,
+ 66,
+ 67,
+ 1626,
+ 1630,
+ 1125,
+ 104,
+ 110,
+ 631,
+ 635,
+ 642,
+ 138,
+ 1677,
+ 143,
+ 146,
+ 148,
+ 150,
+ 1176,
+ 155,
+ 1693,
+ 1708,
+ 173,
+ 1713,
+ 191,
+ 1728,
+ 1729,
+ 1736,
+ 713,
+ 202,
+ 715,
+ 208,
+ 209,
+ 211,
+ 214,
+ 1752,
+ 217,
+ 729,
+ 224,
+ 227,
+ 739,
+ 742,
+ 232,
+ 1768,
+ 1774,
+ 241,
+ 242,
+ 244,
+ 758,
+ 251,
+ 764,
+ 255,
+ 1791,
+ 771,
+ 1797,
+ 775,
+ 785,
+ 2322,
+ 281,
+ 282,
+ 283,
+ 295,
+ 297,
+ 303,
+ 304,
+ 307,
+ 325,
+ 838,
+ 1349,
+ 850,
+ 341,
+ 859,
+ 348,
+ 860,
+ 1888,
+ 353,
+ 1894,
+ 369,
+ 1905,
+ 885,
+ 890,
+ 1915,
+ 380,
+ 381,
+ 1406,
+ 1411,
+ 389,
+ 1930,
+ 908,
+ 404,
+ 1434,
+ 1949,
+ 1950,
+ 931,
+ 932,
+ 1955,
+ 937,
+ 946,
+ 1458,
+ 438,
+ 445,
+ 1982,
+ 449,
+ 1477,
+ 459,
+ 460,
+ 1484,
+ 1492,
+ 990,
+ 2015,
+ 1512,
+ 496,
+ 1014,
+ 503,
+ 1018
+ ],
+
+ },
+ {
+ "id": "meituan",
+ "name": "美团真题",
+ "questions": [
+ 1000192,
+ 1000193,
+ 1000194,
+ 1000195,
+ 1000196,
+ 1000197,
+ 1000198,
+ 1000199,
+ 1000200,
+ 1000201,
+ 1000202,
+ 1000203,
+ 1000189,
+ 1000190,
+ 1000191,
+ 257,
+ 100158,
+ 13,
+ 455,
+ 45,
+ 200,
+ 143,
+ 139,
+ 19,
+ 100344,
+ 162,
+ 177,
+ 75,
+ 1036,
+ 71,
+ 475,
+ 42,
+ 51,
+ 440,
+ 25
+ ],
+
+ },
+ {
+ "id": "ke",
+ "name": "贝壳找房",
+ "questions": [
+ 30,
+ 120,
+ 113,
+ 85,
+ 82,
+ 209,
+ 200,
+ 315,
+ 56,
+ 53,
+ 43,
+ 2,
+ 152,
+ 20,
+ 19,
+ 17,
+ 15,
+ 14,
+ 264,
+ 135,
+ 4
+ ],
+
+ },
+ {
+ "id": "efficient-winning",
+ "name": "高效制胜",
+ "questions": [
+ 230,
+ 329,
+ 79,
+ 720,
+ 218,
+ 1120,
+ 97,
+ 483,
+ 1508,
+ 456,
+ 112,
+ 496,
+ 1008,
+ 1013,
+ 119,
+ 121,
+ 122,
+ 416,
+ 3,
+ 11,
+ 524,
+ 15,
+ 18,
+ 20,
+ 279,
+ 28,
+ 1,
+ 803,
+ 167,
+ 42,
+ 53,
+ 825,
+ 322,
+ 70
+ ],
+
+ },
+ {
+ "id": "2cktkvj",
+ "name": "LeetCode 热题 HOT 100",
+ "questions": [
+ 160,
+ 236,
+ 234,
+ 739,
+ 226,
+ 221,
+ 215,
+ 208,
+ 207,
+ 206,
+ 200,
+ 198,
+ 169,
+ 238,
+ 155,
+ 152,
+ 148,
+ 146,
+ 142,
+ 141,
+ 139,
+ 136,
+ 647,
+ 128,
+ 124,
+ 322,
+ 494,
+ 461,
+ 448,
+ 438,
+ 437,
+ 416,
+ 406,
+ 399,
+ 394,
+ 347,
+ 338,
+ 337,
+ 121,
+ 312,
+ 309,
+ 301,
+ 300,
+ 297,
+ 287,
+ 283,
+ 279,
+ 253,
+ 240,
+ 239,
+ 22,
+ 49,
+ 48,
+ 46,
+ 42,
+ 39,
+ 543,
+ 34,
+ 33,
+ 32,
+ 31,
+ 538,
+ 23,
+ 560,
+ 21,
+ 20,
+ 19,
+ 17,
+ 15,
+ 11,
+ 10,
+ 5,
+ 4,
+ 3,
+ 2,
+ 79,
+ 114,
+ 621,
+ 617,
+ 105,
+ 104,
+ 102,
+ 101,
+ 98,
+ 96,
+ 94,
+ 85,
+ 84,
+ 1,
+ 78,
+ 76,
+ 75,
+ 72,
+ 70,
+ 581,
+ 64,
+ 62,
+ 56,
+ 55,
+ 53
+ ],
+
+ },
+ {
+ "id": "7cyqwuv",
+ "name": "力扣杯 - 竞赛合集",
+ "questions": [
+ 1000134,
+ 1000222,
+ 1000362,
+ 1000367,
+ 1000368,
+ 1000369,
+ 1000370,
+ 1000371,
+ 1000373,
+ 1000374,
+ 1000375,
+ 1000130,
+ 1000131,
+ 1000132,
+ 1000133,
+ 100094,
+ 1000138,
+ 1000139,
+ 1000140,
+ 1000146,
+ 1000147,
+ 1000056,
+ 1000057,
+ 1000058,
+ 1000059,
+ 100092,
+ 100093,
+ 1000062,
+ 1000063,
+ 1000216,
+ 100107,
+ 511,
+ 1000085,
+ 1000086,
+ 1000087,
+ 1000088,
+ 1000089,
+ 1000090,
+ 1000091,
+ 1052,
+ 1053,
+ 1000093,
+ 1000215,
+ 100096,
+ 1000218,
+ 1058,
+ 1059,
+ 1060,
+ 1061,
+ 1000219,
+ 1000220,
+ 1000223,
+ 1000224,
+ 1000221,
+ 1000359,
+ 1000361,
+ 1069
+ ],
+
+ },
+ {
+ "id": "ex0k24j",
+ "name": "腾讯精选练习 50 题",
+ "questions": [
+ 217,
+ 46,
+ 53,
+ 54,
+ 59,
+ 61,
+ 62,
+ 70,
+ 78,
+ 206,
+ 215,
+ 88,
+ 89,
+ 557,
+ 344,
+ 230,
+ 231,
+ 104,
+ 235,
+ 236,
+ 237,
+ 238,
+ 121,
+ 122,
+ 124,
+ 146,
+ 4,
+ 5,
+ 7,
+ 8,
+ 9,
+ 136,
+ 11,
+ 141,
+ 14,
+ 15,
+ 16,
+ 142,
+ 2,
+ 20,
+ 21,
+ 148,
+ 23,
+ 26,
+ 155,
+ 160,
+ 33,
+ 292,
+ 169,
+ 43
+ ],
+
+ },
+ {
+ "id": "2ckc81c",
+ "name": "LeetCode 精选 TOP 面试题",
+ "questions": [
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 7,
+ 8,
+ 10,
+ 11,
+ 13,
+ 14,
+ 15,
+ 17,
+ 19,
+ 20,
+ 21,
+ 22,
+ 23,
+ 26,
+ 28,
+ 29,
+ 33,
+ 34,
+ 36,
+ 38,
+ 41,
+ 42,
+ 44,
+ 46,
+ 48,
+ 49,
+ 50,
+ 53,
+ 54,
+ 55,
+ 56,
+ 62,
+ 66,
+ 69,
+ 70,
+ 73,
+ 75,
+ 76,
+ 78,
+ 79,
+ 84,
+ 88,
+ 91,
+ 94,
+ 98,
+ 101,
+ 102,
+ 103,
+ 104,
+ 105,
+ 108,
+ 116,
+ 118,
+ 121,
+ 122,
+ 124,
+ 125,
+ 127,
+ 128,
+ 130,
+ 131,
+ 134,
+ 136,
+ 138,
+ 139,
+ 140,
+ 141,
+ 146,
+ 148,
+ 149,
+ 150,
+ 152,
+ 155,
+ 160,
+ 162,
+ 163,
+ 166,
+ 169,
+ 171,
+ 172,
+ 179,
+ 189,
+ 190,
+ 191,
+ 198,
+ 200,
+ 202,
+ 204,
+ 206,
+ 207,
+ 208,
+ 210,
+ 212,
+ 215,
+ 217,
+ 218,
+ 227,
+ 230,
+ 234,
+ 236,
+ 237,
+ 238,
+ 239,
+ 240,
+ 242,
+ 251,
+ 253,
+ 268,
+ 269,
+ 277,
+ 279,
+ 283,
+ 285,
+ 287,
+ 289,
+ 295,
+ 297,
+ 300,
+ 308,
+ 315,
+ 322,
+ 324,
+ 326,
+ 328,
+ 329,
+ 334,
+ 340,
+ 341,
+ 344,
+ 347,
+ 348,
+ 350,
+ 371,
+ 378,
+ 380,
+ 384,
+ 387,
+ 395,
+ 412,
+ 454
+ ],
+
+ }
+ ];
+}
+
+
+export const choiceDao: ChoiceDao = new ChoiceDao();
+
+
+
+
+
+
diff --git a/src/dao/scoreDao.ts b/src/dao/scoreDao.ts
new file mode 100644
index 0000000..211ac43
--- /dev/null
+++ b/src/dao/scoreDao.ts
@@ -0,0 +1,43 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/dao/scoreDao.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, November 10th 2022, 11:40:22 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
+
+import { IScoreData } from "../model/Model";
+
+
+
+
+class ScoreDao {
+ private scoreBase = require("../../../resources/data.json");
+
+ public getScoreData(onlineData?): Map {
+
+ let nameSiteMapping = new Map();
+ let temp = this.scoreBase as IScoreData[];
+ if (onlineData) {
+ temp = onlineData;
+ }
+ temp.forEach(element => {
+ // Rating
+ // ID
+ // ContestSlug
+ element.score = "" + Math.floor(element.Rating || 0);
+ nameSiteMapping.set("" + element.ID, element);
+ });
+ return nameSiteMapping;
+ }
+}
+
+
+export const scoreDao: ScoreDao = new ScoreDao();
+
+
+
+
+
+
diff --git a/src/ResourcesData.ts b/src/dao/tagsDao.ts
similarity index 82%
rename from src/ResourcesData.ts
rename to src/dao/tagsDao.ts
index 1c568db..42ee915 100644
--- a/src/ResourcesData.ts
+++ b/src/dao/tagsDao.ts
@@ -1,2080 +1,17 @@
-import { IScoreData } from "./shared";
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/dao/tagsDao.ts
+ * Path: https://github.com/ccagml/vscode-leetcode-problem-rating
+ * Created Date: Thursday, November 10th 2022, 11:38:10 pm
+ * Author: ccagml
+ *
+ * Copyright (c) 2022 ccagml . All rights reserved.
+ */
-class ResourcesData {
- private scoreBase = require("../../resources/data.json")
- private choiceData = [
- {
- "id": "shopee",
- "name": "Shopee精选",
- "questions": [
- 341,
- 1000447,
- 1000446,
- 1000445,
- 1000444,
- 1000443,
- 232,
- 871,
- 102,
- 101,
- 15,
- 460,
- 456,
- 448,
- 179,
- 432,
- 48,
- 37,
- 20,
- 146
- ],
+class TagsDao {
- },
- {
- "id": "binary-search",
- "name": "二分查找",
- "questions": [
- 4,
- 1550,
- 540,
- 1056,
- 33,
- 34,
- 35,
- 1059,
- 1060,
- 1083,
- 2047,
- 69,
- 1605,
- 74,
- 1612,
- 1102,
- 1615,
- 81,
- 1621,
- 1122,
- 611,
- 1645,
- 1134,
- 1646,
- 1143,
- 633,
- 1149,
- 644,
- 1672,
- 1675,
- 1679,
- 658,
- 1684,
- 153,
- 154,
- 668,
- 1185,
- 162,
- 167,
- 1192,
- 1730,
- 718,
- 719,
- 1232,
- 209,
- 1753,
- 222,
- 1249,
- 1766,
- 745,
- 1771,
- 1262,
- 240,
- 1290,
- 270,
- 786,
- 275,
- 788,
- 278,
- 792,
- 794,
- 1307,
- 287,
- 802,
- 1831,
- 1832,
- 809,
- 300,
- 302,
- 1326,
- 1851,
- 1352,
- 853,
- 350,
- 1374,
- 352,
- 1886,
- 1891,
- 1384,
- 363,
- 367,
- 882,
- 374,
- 378,
- 894,
- 1918,
- 1408,
- 1413,
- 1929,
- 907,
- 912,
- 1946,
- 923,
- 1957,
- 1966,
- 947,
- 436,
- 1463,
- 441,
- 1468,
- 1984,
- 1476,
- 1486,
- 2000,
- 2006,
- 2018,
- 2027,
- 2036,
- 2045,
- 1023
- ],
-
- },
- {
- "id": "lcof",
- "name": "剑指 Offer",
- "questions": [
- 1000228,
- 1000229,
- 1000230,
- 1000231,
- 1000232,
- 1000233,
- 1000234,
- 1000235,
- 1000236,
- 1000237,
- 1000238,
- 1000239,
- 1000240,
- 1000241,
- 1000242,
- 1000243,
- 1000244,
- 1000245,
- 1000246,
- 1000247,
- 1000248,
- 1000249,
- 1000250,
- 1000251,
- 1000252,
- 1000253,
- 1000254,
- 1000255,
- 1000256,
- 1000257,
- 1000258,
- 1000259,
- 1000260,
- 1000261,
- 1000262,
- 1000263,
- 1000264,
- 1000265,
- 1000266,
- 1000267,
- 1000268,
- 1000269,
- 1000270,
- 1000271,
- 1000272,
- 1000273,
- 1000274,
- 1000275,
- 1000276,
- 1000277,
- 1000278,
- 1000279,
- 1000280,
- 1000281,
- 1000282,
- 1000283,
- 1000284,
- 1000285,
- 1000286,
- 1000287,
- 1000288,
- 1000289,
- 1000290,
- 1000291,
- 1000292,
- 1000293,
- 1000294,
- 1000295,
- 1000296,
- 1000297,
- 1000298,
- 1000299,
- 1000300,
- 1000301,
- 1000302,
- 1000303,
- 1000304,
- 1000305,
- 1000306,
- 1000307,
- 1000308,
- 1000309,
- 1000310,
- 1000311,
- 1000312,
- 1000313,
- 1000314,
- 1000315,
- 1000316,
- 1000317,
- 1000318,
- 1000319,
- 1000320,
- 1000321,
- 1000322,
- 1000323,
- 1000324,
- 1000325,
- 1000326,
- 1000327,
- 1000328,
- 1000329,
- 1000330,
- 1000331,
- 1000332,
- 1000333,
- 1000334,
- 1000335,
- 1000336,
- 1000337,
- 1000338,
- 1000339,
- 1000340,
- 1000341,
- 1000342,
- 1000343,
- 1000344,
- 1000345,
- 1000346,
- 100273,
- 100274,
- 100275,
- 100276,
- 100277,
- 100278,
- 100279,
- 100280,
- 100281,
- 100282,
- 100283,
- 100284,
- 100285,
- 100286,
- 100287,
- 100288,
- 100289,
- 100290,
- 100291,
- 100292,
- 100293,
- 100294,
- 100295,
- 100296,
- 100297,
- 100298,
- 100299,
- 100300,
- 100301,
- 100302,
- 100303,
- 100304,
- 100305,
- 100306,
- 100307,
- 100308,
- 100309,
- 100310,
- 100311,
- 100312,
- 100313,
- 100314,
- 100315,
- 100316,
- 100317,
- 100318,
- 100319,
- 100320,
- 100321,
- 100322,
- 100323,
- 100324,
- 100325,
- 100326,
- 100327,
- 100328,
- 100329,
- 100330,
- 100331,
- 100332,
- 100333,
- 100334,
- 100335,
- 100336,
- 100337,
- 100338,
- 100339,
- 100340,
- 100341,
- 100342,
- 100343,
- 100344,
- 100345,
- 100346,
- 100347
- ],
-
- },
- {
- "id": "e8X3pBZi",
- "name": "剑指 Offer(专项突击版)",
- "questions": [
- 1000228,
- 1000229,
- 1000230,
- 1000231,
- 1000232,
- 1000233,
- 1000234,
- 1000235,
- 1000236,
- 1000237,
- 1000238,
- 1000239,
- 1000240,
- 1000241,
- 1000242,
- 1000243,
- 1000244,
- 1000245,
- 1000246,
- 1000247,
- 1000248,
- 1000249,
- 1000250,
- 1000251,
- 1000252,
- 1000253,
- 1000254,
- 1000255,
- 1000256,
- 1000257,
- 1000258,
- 1000259,
- 1000260,
- 1000261,
- 1000262,
- 1000263,
- 1000264,
- 1000265,
- 1000266,
- 1000267,
- 1000268,
- 1000269,
- 1000270,
- 1000271,
- 1000272,
- 1000273,
- 1000274,
- 1000275,
- 1000276,
- 1000277,
- 1000278,
- 1000279,
- 1000280,
- 1000281,
- 1000282,
- 1000283,
- 1000284,
- 1000285,
- 1000286,
- 1000287,
- 1000288,
- 1000289,
- 1000290,
- 1000291,
- 1000292,
- 1000293,
- 1000294,
- 1000295,
- 1000296,
- 1000297,
- 1000298,
- 1000299,
- 1000300,
- 1000301,
- 1000302,
- 1000303,
- 1000304,
- 1000305,
- 1000306,
- 1000307,
- 1000308,
- 1000309,
- 1000310,
- 1000311,
- 1000312,
- 1000313,
- 1000314,
- 1000315,
- 1000316,
- 1000317,
- 1000318,
- 1000319,
- 1000320,
- 1000321,
- 1000322,
- 1000323,
- 1000324,
- 1000325,
- 1000326,
- 1000327,
- 1000328,
- 1000329,
- 1000330,
- 1000331,
- 1000332,
- 1000333,
- 1000334,
- 1000335,
- 1000336,
- 1000337,
- 1000338,
- 1000339,
- 1000340,
- 1000341,
- 1000342,
- 1000343,
- 1000344,
- 1000345,
- 1000346
- ],
-
- },
- {
- "id": "xb9nqhhg",
- "name": "剑指 Offer(第 2 版)",
- "questions": [
- 100319,
- 100328,
- 100327,
- 100326,
- 100325,
- 100324,
- 100323,
- 100322,
- 100321,
- 100320,
- 100329,
- 100318,
- 100317,
- 100316,
- 100315,
- 100314,
- 100313,
- 100312,
- 100311,
- 100338,
- 100347,
- 100346,
- 100345,
- 100344,
- 100343,
- 100342,
- 100341,
- 100340,
- 100339,
- 100310,
- 100337,
- 100336,
- 100335,
- 100334,
- 100333,
- 100332,
- 100331,
- 100330,
- 100282,
- 100291,
- 100290,
- 100289,
- 100288,
- 100287,
- 100286,
- 100285,
- 100284,
- 100283,
- 100292,
- 100281,
- 100280,
- 100279,
- 100278,
- 100277,
- 100276,
- 100275,
- 100274,
- 100301,
- 100309,
- 100308,
- 100307,
- 100306,
- 100305,
- 100304,
- 100303,
- 100302,
- 100273,
- 100300,
- 100299,
- 100298,
- 100297,
- 100296,
- 100295,
- 100294,
- 100293
- ],
-
- },
- {
- "id": "lccup",
- "name": "力扣杯竞赛真题集",
- "questions": [
- 1000134,
- 1000222,
- 1000362,
- 1000367,
- 1000368,
- 1000369,
- 1000370,
- 1000371,
- 1000373,
- 1000374,
- 1000375,
- 1000130,
- 1000131,
- 1000132,
- 1000133,
- 100094,
- 1000138,
- 1000139,
- 1000140,
- 1000146,
- 1000147,
- 1000056,
- 1000057,
- 1000058,
- 1000059,
- 100092,
- 100093,
- 1000062,
- 1000063,
- 1000218,
- 100107,
- 1000085,
- 1000086,
- 1000087,
- 1000088,
- 1000089,
- 1000090,
- 1000091,
- 1052,
- 1053,
- 1000093,
- 1000215,
- 1000216,
- 100096,
- 1058,
- 1059,
- 1060,
- 1061,
- 1000219,
- 1000220,
- 1000223,
- 1000224,
- 1000221,
- 1000359,
- 1000361,
- 813,
- 1069
- ],
-
- },
- {
- "id": "dynamic-programming",
- "name": "动态规划",
- "questions": [
- 1025,
- 514,
- 516,
- 5,
- 518,
- 10,
- 526,
- 1042,
- 1559,
- 1051,
- 32,
- 1057,
- 546,
- 1571,
- 1060,
- 549,
- 39,
- 40,
- 1063,
- 42,
- 1067,
- 1068,
- 45,
- 1583,
- 562,
- 53,
- 55,
- 568,
- 62,
- 63,
- 64,
- 576,
- 70,
- 72,
- 1105,
- 1617,
- 600,
- 91,
- 96,
- 1129,
- 1130,
- 1134,
- 115,
- 118,
- 119,
- 120,
- 121,
- 122,
- 123,
- 124,
- 634,
- 1669,
- 646,
- 647,
- 650,
- 139,
- 140,
- 651,
- 1166,
- 1680,
- 1170,
- 152,
- 664,
- 1178,
- 1690,
- 673,
- 1196,
- 174,
- 688,
- 1201,
- 1202,
- 691,
- 698,
- 188,
- 1213,
- 1220,
- 198,
- 712,
- 714,
- 1228,
- 1744,
- 1236,
- 213,
- 727,
- 1240,
- 1242,
- 221,
- 1758,
- 1250,
- 740,
- 741,
- 747,
- 238,
- 751,
- 1263,
- 1789,
- 254,
- 256,
- 1286,
- 264,
- 265,
- 1296,
- 279,
- 1822,
- 1828,
- 294,
- 298,
- 300,
- 304,
- 309,
- 312,
- 1851,
- 322,
- 1352,
- 329,
- 333,
- 337,
- 1361,
- 343,
- 351,
- 867,
- 1893,
- 361,
- 877,
- 368,
- 1906,
- 1398,
- 376,
- 377,
- 1402,
- 1403,
- 896,
- 1924,
- 392,
- 911,
- 923,
- 413,
- 1437,
- 416,
- 418,
- 930,
- 938,
- 435,
- 954,
- 446,
- 1471,
- 1474,
- 452,
- 1989,
- 967,
- 1996,
- 464,
- 977,
- 471,
- 486,
- 487,
- 494,
- 2031,
- 1008,
- 1522,
- 1013,
- 1017,
- 1531,
- 1022,
- 1535
- ],
-
- },
- {
- "id": "tusmiple",
- "name": "图森未来",
- "questions": [
- 718,
- 127,
- 1005,
- 1000428,
- 1000427,
- 1000426,
- 1000425,
- 1000424,
- 1000423,
- 726,
- 522,
- 973,
- 1217,
- 193,
- 1972,
- 171,
- 1957,
- 36,
- 27,
- 1294
- ],
-
- },
- {
- "id": "graph",
- "name": "图论",
- "questions": [
- 317,
- 1912,
- 1389,
- 877,
- 365,
- 871,
- 869,
- 1380,
- 352,
- 863,
- 323,
- 895,
- 310,
- 820,
- 305,
- 1325,
- 813,
- 803,
- 801,
- 1309,
- 1308,
- 794,
- 1986,
- 505,
- 2040,
- 2038,
- 2035,
- 499,
- 490,
- 1492,
- 1485,
- 971,
- 964,
- 1815,
- 960,
- 949,
- 433,
- 1456,
- 1447,
- 1442,
- 417,
- 922,
- 1428,
- 1100,
- 1191,
- 1701,
- 1696,
- 1171,
- 127,
- 1661,
- 1144,
- 1117,
- 1613,
- 1101,
- 1706,
- 1085,
- 1587,
- 1073,
- 1576,
- 547,
- 1058,
- 542,
- 1558,
- 1039,
- 721,
- 1300,
- 269,
- 261,
- 753,
- 744,
- 737,
- 1757,
- 733,
- 1753,
- 210,
- 1032,
- 207,
- 1229,
- 1738,
- 200,
- 1223,
- 695,
- 694,
- 685,
- 684
- ],
-
- },
- {
- "id": "bytedancecampus",
- "name": "字节校园",
- "questions": [
- 69,
- 88,
- 215,
- 206,
- 76,
- 200,
- 72,
- 199,
- 198,
- 92,
- 322,
- 64,
- 56,
- 54,
- 53,
- 948,
- 46,
- 300,
- 94,
- 102,
- 103,
- 232,
- 105,
- 236,
- 239,
- 1000185,
- 1000182,
- 1000183,
- 1000184,
- 121,
- 1000186,
- 1000187,
- 124,
- 135,
- 146,
- 143,
- 142,
- 15,
- 14,
- 141,
- 394,
- 1000188,
- 20,
- 7,
- 129,
- 5,
- 4,
- 3,
- 2,
- 1,
- 128,
- 21,
- 22,
- 23,
- 151,
- 25,
- 152,
- 792,
- 923,
- 31,
- 160,
- 33,
- 415,
- 41,
- 42,
- 43
- ],
-
- },
- {
- "id": "ponyai",
- "name": "小马智行 Pony.ai",
- "questions": [
- 15,
- 1000351,
- 1000350,
- 1000349,
- 92,
- 1000347,
- 148,
- 146,
- 1105,
- 1000352,
- 909,
- 173,
- 1000348,
- 105,
- 39,
- 1860,
- 98,
- 1441
- ],
-
- },
- {
- "id": "cmbchina-cc",
- "name": "招商银行信用卡",
- "questions": [
- 33,
- 124,
- 103,
- 88,
- 199,
- 198,
- 322,
- 64,
- 53,
- 41,
- 1,
- 415,
- 923,
- 22,
- 21,
- 20,
- 15,
- 7,
- 5,
- 3
- ],
- },
- {
- "id": "data-structures",
- "name": "数据结构",
- "questions": [
- 1,
- 2,
- 5,
- 1032,
- 15,
- 1039,
- 20,
- 21,
- 23,
- 24,
- 25,
- 547,
- 36,
- 42,
- 43,
- 44,
- 48,
- 49,
- 560,
- 53,
- 566,
- 56,
- 59,
- 1085,
- 73,
- 1609,
- 75,
- 82,
- 83,
- 84,
- 1107,
- 88,
- 94,
- 98,
- 101,
- 102,
- 103,
- 104,
- 105,
- 108,
- 112,
- 113,
- 118,
- 119,
- 121,
- 124,
- 1661,
- 128,
- 1665,
- 642,
- 136,
- 138,
- 141,
- 142,
- 143,
- 144,
- 145,
- 653,
- 148,
- 155,
- 1693,
- 160,
- 1701,
- 169,
- 173,
- 1710,
- 187,
- 199,
- 203,
- 206,
- 208,
- 1745,
- 211,
- 212,
- 214,
- 215,
- 217,
- 218,
- 729,
- 226,
- 739,
- 230,
- 232,
- 235,
- 236,
- 238,
- 1774,
- 240,
- 242,
- 761,
- 253,
- 766,
- 768,
- 261,
- 783,
- 784,
- 281,
- 290,
- 803,
- 295,
- 297,
- 305,
- 817,
- 1345,
- 323,
- 325,
- 838,
- 334,
- 336,
- 337,
- 347,
- 1371,
- 350,
- 358,
- 871,
- 366,
- 1903,
- 369,
- 378,
- 892,
- 383,
- 387,
- 394,
- 402,
- 409,
- 922,
- 415,
- 1951,
- 1442,
- 1450,
- 435,
- 448,
- 450,
- 451,
- 452,
- 454,
- 456,
- 2009,
- 1008,
- 1014
- ],
-
- },
- {
- "id": "xb9lfcwi",
- "name": "程序员面试金典(第 6 版)",
- "questions": [
- 100352,
- 100353,
- 100354,
- 100355,
- 100356,
- 1000003,
- 1000004,
- 1000005,
- 1000006,
- 1000007,
- 1000008,
- 1000009,
- 1000010,
- 1000011,
- 1000012,
- 1000013,
- 1000015,
- 1000016,
- 1000017,
- 1000018,
- 1000019,
- 1000020,
- 1000021,
- 1000022,
- 1000023,
- 1000024,
- 1000025,
- 1000026,
- 1000027,
- 1000028,
- 1000029,
- 1000030,
- 1000031,
- 1000032,
- 1000033,
- 1000034,
- 1000035,
- 1000036,
- 1000037,
- 1000038,
- 1000039,
- 1000040,
- 1000041,
- 1000042,
- 1000043,
- 1000044,
- 1000045,
- 1000046,
- 1000047,
- 1000048,
- 1000049,
- 1000050,
- 1000051,
- 100158,
- 100159,
- 100160,
- 100161,
- 100162,
- 100163,
- 100164,
- 100167,
- 100168,
- 100169,
- 100170,
- 100171,
- 100172,
- 100173,
- 100174,
- 100175,
- 100176,
- 100177,
- 100178,
- 100179,
- 100180,
- 100181,
- 100182,
- 100183,
- 100184,
- 100185,
- 100186,
- 100187,
- 100188,
- 100195,
- 100196,
- 100197,
- 100198,
- 100199,
- 100200,
- 100201,
- 100202,
- 100203,
- 100228,
- 100229,
- 100230,
- 100231,
- 100232,
- 100233,
- 100240,
- 100241,
- 100242,
- 100258,
- 100259,
- 100260,
- 100261,
- 100262,
- 100348,
- 100349,
- 100350,
- 100351
- ],
-
- },
- {
- "id": "algorithms",
- "name": "算法",
- "questions": [
- 1025,
- 3,
- 4,
- 5,
- 1028,
- 10,
- 11,
- 1036,
- 1037,
- 15,
- 17,
- 19,
- 21,
- 22,
- 1046,
- 542,
- 33,
- 34,
- 35,
- 547,
- 37,
- 1059,
- 39,
- 40,
- 42,
- 45,
- 46,
- 47,
- 557,
- 51,
- 53,
- 55,
- 567,
- 2047,
- 572,
- 62,
- 70,
- 582,
- 72,
- 583,
- 74,
- 1609,
- 76,
- 77,
- 78,
- 79,
- 1101,
- 82,
- 85,
- 90,
- 91,
- 617,
- 1134,
- 116,
- 117,
- 120,
- 123,
- 130,
- 131,
- 132,
- 136,
- 139,
- 1165,
- 146,
- 1171,
- 149,
- 153,
- 159,
- 673,
- 162,
- 167,
- 1192,
- 174,
- 695,
- 189,
- 190,
- 191,
- 198,
- 200,
- 201,
- 202,
- 713,
- 714,
- 715,
- 206,
- 207,
- 209,
- 210,
- 213,
- 221,
- 733,
- 1250,
- 231,
- 239,
- 241,
- 753,
- 254,
- 260,
- 269,
- 1300,
- 278,
- 792,
- 283,
- 286,
- 287,
- 800,
- 300,
- 301,
- 813,
- 309,
- 310,
- 315,
- 322,
- 329,
- 337,
- 340,
- 343,
- 344,
- 865,
- 874,
- 893,
- 895,
- 384,
- 394,
- 908,
- 410,
- 413,
- 416,
- 417,
- 1442,
- 438,
- 460,
- 1485,
- 2019,
- 486,
- 1512,
- 1019,
- 1023
- ],
-
- },
- {
- "id": "programming-skills",
- "name": "编程能力",
- "questions": [
- 2,
- 1031,
- 8,
- 525,
- 23,
- 535,
- 28,
- 43,
- 556,
- 48,
- 49,
- 1584,
- 54,
- 566,
- 58,
- 61,
- 65,
- 66,
- 67,
- 1626,
- 1630,
- 1125,
- 104,
- 110,
- 631,
- 635,
- 642,
- 138,
- 1677,
- 143,
- 146,
- 148,
- 150,
- 1176,
- 155,
- 1693,
- 1708,
- 173,
- 1713,
- 191,
- 1728,
- 1729,
- 1736,
- 713,
- 202,
- 715,
- 208,
- 209,
- 211,
- 214,
- 1752,
- 217,
- 729,
- 224,
- 227,
- 739,
- 742,
- 232,
- 1768,
- 1774,
- 241,
- 242,
- 244,
- 758,
- 251,
- 764,
- 255,
- 1791,
- 771,
- 1797,
- 775,
- 785,
- 2322,
- 281,
- 282,
- 283,
- 295,
- 297,
- 303,
- 304,
- 307,
- 325,
- 838,
- 1349,
- 850,
- 341,
- 859,
- 348,
- 860,
- 1888,
- 353,
- 1894,
- 369,
- 1905,
- 885,
- 890,
- 1915,
- 380,
- 381,
- 1406,
- 1411,
- 389,
- 1930,
- 908,
- 404,
- 1434,
- 1949,
- 1950,
- 931,
- 932,
- 1955,
- 937,
- 946,
- 1458,
- 438,
- 445,
- 1982,
- 449,
- 1477,
- 459,
- 460,
- 1484,
- 1492,
- 990,
- 2015,
- 1512,
- 496,
- 1014,
- 503,
- 1018
- ],
-
- },
- {
- "id": "meituan",
- "name": "美团真题",
- "questions": [
- 1000192,
- 1000193,
- 1000194,
- 1000195,
- 1000196,
- 1000197,
- 1000198,
- 1000199,
- 1000200,
- 1000201,
- 1000202,
- 1000203,
- 1000189,
- 1000190,
- 1000191,
- 257,
- 100158,
- 13,
- 455,
- 45,
- 200,
- 143,
- 139,
- 19,
- 100344,
- 162,
- 177,
- 75,
- 1036,
- 71,
- 475,
- 42,
- 51,
- 440,
- 25
- ],
-
- },
- {
- "id": "ke",
- "name": "贝壳找房",
- "questions": [
- 30,
- 120,
- 113,
- 85,
- 82,
- 209,
- 200,
- 315,
- 56,
- 53,
- 43,
- 2,
- 152,
- 20,
- 19,
- 17,
- 15,
- 14,
- 264,
- 135,
- 4
- ],
-
- },
- {
- "id": "efficient-winning",
- "name": "高效制胜",
- "questions": [
- 230,
- 329,
- 79,
- 720,
- 218,
- 1120,
- 97,
- 483,
- 1508,
- 456,
- 112,
- 496,
- 1008,
- 1013,
- 119,
- 121,
- 122,
- 416,
- 3,
- 11,
- 524,
- 15,
- 18,
- 20,
- 279,
- 28,
- 1,
- 803,
- 167,
- 42,
- 53,
- 825,
- 322,
- 70
- ],
-
- },
- {
- "id": "2cktkvj",
- "name": "LeetCode 热题 HOT 100",
- "questions": [
- 160,
- 236,
- 234,
- 739,
- 226,
- 221,
- 215,
- 208,
- 207,
- 206,
- 200,
- 198,
- 169,
- 238,
- 155,
- 152,
- 148,
- 146,
- 142,
- 141,
- 139,
- 136,
- 647,
- 128,
- 124,
- 322,
- 494,
- 461,
- 448,
- 438,
- 437,
- 416,
- 406,
- 399,
- 394,
- 347,
- 338,
- 337,
- 121,
- 312,
- 309,
- 301,
- 300,
- 297,
- 287,
- 283,
- 279,
- 253,
- 240,
- 239,
- 22,
- 49,
- 48,
- 46,
- 42,
- 39,
- 543,
- 34,
- 33,
- 32,
- 31,
- 538,
- 23,
- 560,
- 21,
- 20,
- 19,
- 17,
- 15,
- 11,
- 10,
- 5,
- 4,
- 3,
- 2,
- 79,
- 114,
- 621,
- 617,
- 105,
- 104,
- 102,
- 101,
- 98,
- 96,
- 94,
- 85,
- 84,
- 1,
- 78,
- 76,
- 75,
- 72,
- 70,
- 581,
- 64,
- 62,
- 56,
- 55,
- 53
- ],
-
- },
- {
- "id": "7cyqwuv",
- "name": "力扣杯 - 竞赛合集",
- "questions": [
- 1000134,
- 1000222,
- 1000362,
- 1000367,
- 1000368,
- 1000369,
- 1000370,
- 1000371,
- 1000373,
- 1000374,
- 1000375,
- 1000130,
- 1000131,
- 1000132,
- 1000133,
- 100094,
- 1000138,
- 1000139,
- 1000140,
- 1000146,
- 1000147,
- 1000056,
- 1000057,
- 1000058,
- 1000059,
- 100092,
- 100093,
- 1000062,
- 1000063,
- 1000216,
- 100107,
- 511,
- 1000085,
- 1000086,
- 1000087,
- 1000088,
- 1000089,
- 1000090,
- 1000091,
- 1052,
- 1053,
- 1000093,
- 1000215,
- 100096,
- 1000218,
- 1058,
- 1059,
- 1060,
- 1061,
- 1000219,
- 1000220,
- 1000223,
- 1000224,
- 1000221,
- 1000359,
- 1000361,
- 1069
- ],
-
- },
- {
- "id": "ex0k24j",
- "name": "腾讯精选练习 50 题",
- "questions": [
- 217,
- 46,
- 53,
- 54,
- 59,
- 61,
- 62,
- 70,
- 78,
- 206,
- 215,
- 88,
- 89,
- 557,
- 344,
- 230,
- 231,
- 104,
- 235,
- 236,
- 237,
- 238,
- 121,
- 122,
- 124,
- 146,
- 4,
- 5,
- 7,
- 8,
- 9,
- 136,
- 11,
- 141,
- 14,
- 15,
- 16,
- 142,
- 2,
- 20,
- 21,
- 148,
- 23,
- 26,
- 155,
- 160,
- 33,
- 292,
- 169,
- 43
- ],
-
- },
- {
- "id": "2ckc81c",
- "name": "LeetCode 精选 TOP 面试题",
- "questions": [
- 1,
- 2,
- 3,
- 4,
- 5,
- 7,
- 8,
- 10,
- 11,
- 13,
- 14,
- 15,
- 17,
- 19,
- 20,
- 21,
- 22,
- 23,
- 26,
- 28,
- 29,
- 33,
- 34,
- 36,
- 38,
- 41,
- 42,
- 44,
- 46,
- 48,
- 49,
- 50,
- 53,
- 54,
- 55,
- 56,
- 62,
- 66,
- 69,
- 70,
- 73,
- 75,
- 76,
- 78,
- 79,
- 84,
- 88,
- 91,
- 94,
- 98,
- 101,
- 102,
- 103,
- 104,
- 105,
- 108,
- 116,
- 118,
- 121,
- 122,
- 124,
- 125,
- 127,
- 128,
- 130,
- 131,
- 134,
- 136,
- 138,
- 139,
- 140,
- 141,
- 146,
- 148,
- 149,
- 150,
- 152,
- 155,
- 160,
- 162,
- 163,
- 166,
- 169,
- 171,
- 172,
- 179,
- 189,
- 190,
- 191,
- 198,
- 200,
- 202,
- 204,
- 206,
- 207,
- 208,
- 210,
- 212,
- 215,
- 217,
- 218,
- 227,
- 230,
- 234,
- 236,
- 237,
- 238,
- 239,
- 240,
- 242,
- 251,
- 253,
- 268,
- 269,
- 277,
- 279,
- 283,
- 285,
- 287,
- 289,
- 295,
- 297,
- 300,
- 308,
- 315,
- 322,
- 324,
- 326,
- 328,
- 329,
- 334,
- 340,
- 341,
- 344,
- 347,
- 348,
- 350,
- 371,
- 378,
- 380,
- 384,
- 387,
- 395,
- 412,
- 454
- ],
-
- }
- ]
- private tags_data = {
+ private tagsData = {
"1": { "topicTags": ["array", "hash-table"] },
"2": { "topicTags": ["recursion", "linked-list", "math"] },
"3": { "topicTags": ["hash-table", "string", "sliding-window"] },
@@ -4867,7 +2804,7 @@ class ResourcesData {
"面试题 17.26": { "topicTags": ["array", "hash-table", "sorting"] },
"面试题13": { "topicTags": ["depth-first-search", "breadth-first-search", "dynamic-programming"] },
"面试题59 - II": { "topicTags": ["design", "queue", "monotonic-queue"] }
- }
+ };
private tags_name = {
'array': '数组',
@@ -4942,29 +2879,20 @@ class ResourcesData {
'biconnected-component': '双连接组件',
'strongly-connected-component': '强连接组件'
- }
- public getChoiceData() {
- return this.choiceData
- }
-
- public getScoreData(): Map {
-
- let nameSiteMapping = new Map();
- const temp = this.scoreBase as IScoreData[]
- temp.forEach(element => {
- // Rating
- // ID
- // ContestSlug
- element.score = "" + Math.floor(element.Rating || 0);
- nameSiteMapping.set("" + element.ID, element)
- });
- return nameSiteMapping
- }
+ };
public getTagsData(fid: string): Array {
- return (this.tags_data[fid]?.topicTags || []).map(p => {
- return this.tags_name[p]
- })
+ return (this.tagsData[fid]?.topicTags || []).map(p => {
+ return this.tags_name[p];
+ });
}
+
}
-export const resourcesData: ResourcesData = new ResourcesData();
+
+export const tagsDao: TagsDao = new TagsDao();
+
+
+
+
+
+
diff --git a/src/explorer/explorerNodeManager.ts b/src/explorer/explorerNodeManager.ts
deleted file mode 100644
index 0b5e0e1..0000000
--- a/src/explorer/explorerNodeManager.ts
+++ /dev/null
@@ -1,460 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-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 { shouldHideSolvedProblem, shouldHideScoreProblem } from "../utils/settingUtils";
-import { LeetCodeNode } from "./LeetCodeNode";
-import { ISearchSet } from "../shared";
-import { searchToday, searchUserContest } from "../commands/show";
-import { leetCodeTreeDataProvider } from "./LeetCodeTreeDataProvider";
-import { resourcesData } from "../ResourcesData";
-import { leetCodeManager } from "../leetCodeManager";
-
-class ExplorerNodeManager 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();
- }
-
- public checkSubmit(e: ISubmitEvent) {
- if (e.sub_type == "submit" && e.accepted) {
- const day_start = new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000; //获取当天零点的时间
- const day_end = new Date(new Date().setHours(0, 0, 0, 0) + 24 * 60 * 60 * 1000 - 1).getTime() / 1000; //获取当天23:59:59的时间
- var need_get_today: boolean = false;
- this.searchSet.forEach(element => {
- if (element.type == SearchSetType.Day) {
- if (day_start <= element.time && element.time <= day_end) {
- if (e.fid == element.value) {
- need_get_today = true;
- }
- }
- }
- });
- if (need_get_today) {
- searchToday();
- }
- }
- }
-
- public async refreshCheck(): Promise {
- if (!leetCodeManager.getUser()) {
- return;
- }
- const day_start = new Date(new Date().setHours(0, 0, 0, 0)).getTime() / 1000; //获取当天零点的时间
- const day_end = new Date(new Date().setHours(0, 0, 0, 0) + 24 * 60 * 60 * 1000 - 1).getTime() / 1000; //获取当天23:59:59的时间
- var need_get_today: boolean = true;
- this.searchSet.forEach(element => {
- if (element.type == SearchSetType.Day) {
- if (day_start <= element.time && element.time <= day_end) {
- need_get_today = false;
- } else {
- this.waitTodayQuestion = false
- }
- }
- });
- if (need_get_today && !this.waitTodayQuestion) {
- this.waitTodayQuestion = true
- await searchToday();
- }
- if (!this.user_score && !this.waitUserContest) {
- this.waitUserContest = true;
- await searchUserContest();
- }
- }
-
- public async refreshCache(): Promise {
- const temp_searchSet: Map = this.searchSet
- const temp_waitTodayQuestion: boolean = this.waitTodayQuestion
- const temp_waitUserContest: boolean = this.waitUserContest
- this.dispose();
- for (const problem of await list.listProblems()) {
- this.explorerNodeMap.set(problem.id, new LeetCodeNode(problem, true, this.user_score));
- for (const company of problem.companies) {
- this.companySet.add(company);
- }
- for (const tag of problem.tags) {
- this.tagSet.add(tag);
- }
- }
- this.searchSet = temp_searchSet;
- this.waitTodayQuestion = temp_waitTodayQuestion
- this.waitUserContest = temp_waitUserContest
- }
-
- public getRootNodes(): LeetCodeNode[] {
- const baseNode: LeetCodeNode[] = [
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.All,
- name: Category.All,
- rootNodeSortId: RootNodeSort.All,
- }), false),
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.Difficulty,
- name: Category.Difficulty,
- rootNodeSortId: RootNodeSort.Difficulty,
- }), false),
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.Tag,
- name: Category.Tag,
- rootNodeSortId: RootNodeSort.Tag,
- }), false),
- // new LeetCodeNode(Object.assign({}, defaultProblem, {
- // id: Category.Company,
- // name: Category.Company,
- // rootNodeSortId: RootNodeSort.Company,
- // }), false),
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.Favorite,
- name: Category.Favorite,
- rootNodeSortId: RootNodeSort.Favorite,
- }), false),
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.Score,
- name: Category.Score,
- rootNodeSortId: RootNodeSort.Score,
- }), false, this.user_score),
- new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: Category.Choice,
- name: Category.Choice,
- rootNodeSortId: RootNodeSort.Choice,
- }), false),
- ];
- this.searchSet.forEach(element => {
- if (element.type == SearchSetType.Day) {
- const curDate = new Date(element.time * 1000)
- baseNode.push(new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: element.type,
- name: "[" + (curDate.getFullYear()) + "-" + (curDate.getMonth() + 1) + "-" + (curDate.getDate()) + "]" + SearchSetTypeName[SearchSetType.Day],
- input: element.value,
- isSearchResult: true,
- rootNodeSortId: RootNodeSort[element.type],
- todayData: element.todayData
- }), false));
- } else {
- baseNode.push(new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: element.type,
- name: SearchSetTypeName[element.type] + element.value,
- input: element.value,
- isSearchResult: true,
- rootNodeSortId: RootNodeSort[element.type],
- }), false));
- }
- });
- baseNode.sort(function (a: LeetCodeNode, b: LeetCodeNode): number {
- if (a.rootNodeSortId < b.rootNodeSortId) {
- return -1;
- } else if (a.rootNodeSortId > b.rootNodeSortId) {
- return 1
- }
- return 0;
- })
- return baseNode;
- }
-
- public getScoreRangeNodes(rank_range: string): LeetCodeNode[] {
- const sorceNode: LeetCodeNode[] = []
- const rank_r: Array = rank_range.split("-")
- var rank_a = Number(rank_r[0])
- var rank_b = Number(rank_r[1])
- if (rank_a > 0 && rank_b > 0) {
- if (rank_a > rank_b) {
- const rank_c: number = rank_a
- rank_a = rank_b
- rank_b = rank_c
- }
-
- this.explorerNodeMap.forEach(element => {
- if (!this.canShow(element)) {
- return;
- }
- if (rank_a <= Number(element.score) && Number(element.score) <= rank_b) {
- sorceNode.push(element)
- }
- });
- }
- return this.applySortingStrategy(sorceNode);
- }
-
- public canShow(element: LeetCodeNode) {
- if (shouldHideSolvedProblem() && element.state === ProblemState.AC) {
- return false;
- }
- if (shouldHideScoreProblem(element, element.user_score)) {
- return false;
- }
- return true;
- }
-
- public getContextNodes(rank_range: string): LeetCodeNode[] {
- const sorceNode: LeetCodeNode[] = []
- const rank_r: Array = rank_range.split("-")
- var rank_a = Number(rank_r[0])
- var rank_b = Number(rank_r[1])
- if (rank_a > 0) {
- this.explorerNodeMap.forEach(element => {
- if (!this.canShow(element)) {
- return;
- }
- const slu = element.ContestSlug;
- const slu_arr: Array = slu.split("-")
- const slu_id = Number(slu_arr[slu_arr.length - 1]);
- if (rank_b > 0 && rank_a <= slu_id && slu_id <= rank_b) {
- sorceNode.push(element)
- } else if (rank_a == slu_id) {
- sorceNode.push(element)
- }
- });
- }
- return this.applySortingStrategy(sorceNode);
- }
- public getDayNodes(element: LeetCodeNode | undefined): LeetCodeNode[] {
- const rank_range: string = element?.input || ""
- const sorceNode: LeetCodeNode[] = []
- if (rank_range) {
- this.explorerNodeMap.forEach(new_node => {
- if (new_node.id == rank_range) {
- new_node.todayData = element?.todayData
- sorceNode.push(new_node);
- }
- });
- }
- return this.applySortingStrategy(sorceNode);
- }
-
- public getAllNodes(): LeetCodeNode[] {
- return this.applySortingStrategy(
- Array.from(this.explorerNodeMap.values()).filter(p => this.canShow(p)),
- );
- }
-
- 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 getAllScoreNodes(user_score: number): LeetCodeNode[] {
- const res: LeetCodeNode[] = [];
- 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, {
- id: `${Category.Score}.${element}`,
- name: `${element}`,
- }), false, user_score))
- }
- })
-
- this.sortSubCategoryNodes(res, Category.Score);
- return res;
- }
-
- public getAllChoiceNodes(): LeetCodeNode[] {
- const res: LeetCodeNode[] = [];
-
- const all_choice = resourcesData.getChoiceData();
- all_choice.forEach(element => {
- res.push(new LeetCodeNode(Object.assign({}, defaultProblem, {
- id: `${Category.Choice}.${element.id}`,
- name: `${element.name}`,
- }), false))
- })
- this.sortSubCategoryNodes(res, Category.Choice);
- 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 (!this.canShow(node)) {
- continue;
- }
- if (node.isFavorite) {
- res.push(node);
- }
- }
- return this.applySortingStrategy(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[] = [];
-
- const choiceQuestionId: Map = new Map()
- if (metaInfo[0] == Category.Choice) {
- const all_choice = resourcesData.getChoiceData();
- all_choice.forEach(element => {
- if (element.id == metaInfo[1]) {
- element.questions.forEach(kk => {
- choiceQuestionId[kk] = true
- })
- return
- }
- })
- }
-
- for (const node of this.explorerNodeMap.values()) {
- if (!this.canShow(node)) {
- continue;
- }
- 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;
- case Category.Score:
- if (node.score > "0") {
- const check_rank = toNumber(metaInfo[1]);
- const node_rank = toNumber(node.score);
- if (check_rank <= node_rank && node_rank < check_rank + 100) {
- res.push(node);
- }
- }
- break;
- case Category.Choice:
- if (choiceQuestionId[Number(node.qid)]) {
- res.push(node);
- }
- default:
- break;
- }
- }
- return this.applySortingStrategy(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;
- }
- }
-
- private applySortingStrategy(nodes: LeetCodeNode[]): LeetCodeNode[] {
- 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));
- default: return nodes;
- }
- }
-}
-
-export const explorerNodeManager: ExplorerNodeManager = new ExplorerNodeManager();
diff --git a/src/extension.ts b/src/extension.ts
index 829a168..5ddec09 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -1,96 +1,83 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/extension.ts
+ * Path: https://github.com/ccagml/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 vscode from "vscode";
-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";
-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 { leetCodeChannel } from "./leetCodeChannel";
-import { leetCodeExecutor } from "./leetCodeExecutor";
-import { leetCodeManager } from "./leetCodeManager";
-import { leetCodeStatusBarController } from "./statusbar/leetCodeStatusBarController";
-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 { ExtensionContext, window, commands, Uri } from "vscode";
+import { fileButtonController } from "./controller/FileButtonController";
+import { treeViewController } from "./controller/TreeViewController";
+import { NodeModel } from "./model/NodeModel";
+import { treeDataService } from "./service/TreeDataService";
+import { treeItemDecorationService } from "./service/TreeItemDecorationService";
+import { logOutput, promptForOpenOutputChannel } from "./utils/OutputUtils";
+import { executeService } from "./service/ExecuteService";
+import { eventController } from "./controller/EventController";
+import { statusBarService } from "./service/StatusBarService";
+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";
+import { getLeetCodeEndpoint } from "./utils/ConfigUtils";
+import { DialogType } from "./model/Model";
-export async function activate(context: vscode.ExtensionContext): Promise {
+// 激活插件
+export async function activate(context: ExtensionContext): Promise {
try {
- if (!wsl.useVscodeNode()) {
- if (!await leetCodeExecutor.meetRequirements(context)) {
- throw new Error("The environment doesn't meet requirements.");
- }
- }
-
-
- leetCodeManager.on("statusChanged", () => {
- leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser());
- leetCodeTreeDataProvider.cleanUserScore();
- leetCodeTreeDataProvider.refresh();
- });
- leetCodeManager.on("submit", (e: ISubmitEvent) => {
- leetCodeTreeDataProvider.checkSubmit(e);
- });
-
- leetCodeManager.on("searchUserContest", () => {
- leetCodeStatusBarController.updateStatusBar(leetCodeManager.getStatus(), leetCodeManager.getUser(), leetCodeManager.getUserContestInfo());
- });
-
- leetCodeTreeDataProvider.initialize(context);
+ // 初始化控制器
+ mainContorller.initialize(context);
+ // 检查node环境
+ await mainContorller.checkNodeEnv(context);
+ // 事件监听
+ eventController.add_event();
+ // 资源管理
context.subscriptions.push(
- leetCodeStatusBarController,
- leetCodeChannel,
- leetCodePreviewProvider,
- leetCodeSubmissionProvider,
- leetCodeSolutionProvider,
- leetCodeExecutor,
- markdownEngine,
- 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.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()),
- 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()),
+ statusBarService,
+ logOutput,
+ previewService,
+ submissionService,
+ solutionService,
+ executeService,
+ markdownService,
+ fileButtonController,
+ treeViewController,
+ window.registerFileDecorationProvider(treeItemDecorationService),
+ window.createTreeView("leetCodeExplorer", { treeDataProvider: treeDataService, showCollapseAll: true }),
+ commands.registerCommand("leetcode.deleteCache", () => mainContorller.deleteCache()),
+ commands.registerCommand("leetcode.toggleLeetCodeCn", () => treeViewController.switchEndpoint()),
+ commands.registerCommand("leetcode.signin", () => loginContorller.signIn()),
+ commands.registerCommand("leetcode.signout", () => loginContorller.signOut()),
+ commands.registerCommand("leetcode.previewProblem", (node: NodeModel) => treeViewController.previewProblem(node)),
+ commands.registerCommand("leetcode.showProblem", (node: NodeModel) => treeViewController.showProblem(node)),
+ commands.registerCommand("leetcode.pickOne", () => treeViewController.pickOne()),
+ commands.registerCommand("leetcode.deleteAllCache", () => loginContorller.deleteAllCache()),
+ commands.registerCommand("leetcode.searchScoreRange", () => treeViewController.searchScoreRange()),
+ commands.registerCommand("leetcode.searchProblem", () => treeViewController.searchProblem()),
+ commands.registerCommand("leetcode.showSolution", (input: NodeModel | Uri) => treeViewController.showSolution(input)),
+ commands.registerCommand("leetcode.refreshExplorer", () => treeDataService.refresh()),
+ commands.registerCommand("leetcode.testSolution", (uri?: Uri) => treeViewController.testSolution(uri)),
+ commands.registerCommand("leetcode.testSolutionDefault", (uri?: Uri, allCase?: boolean) => treeViewController.testSolutionDefault(uri, allCase)),
+ commands.registerCommand("leetcode.submitSolution", (uri?: Uri) => treeViewController.submitSolution(uri)),
+ commands.registerCommand("leetcode.switchDefaultLanguage", () => treeViewController.switchDefaultLanguage()),
+ commands.registerCommand("leetcode.addFavorite", (node: NodeModel) => treeViewController.addFavorite(node)),
+ commands.registerCommand("leetcode.removeFavorite", (node: NodeModel) => treeViewController.removeFavorite(node)),
+ commands.registerCommand("leetcode.problems.sort", () => treeViewController.switchSortingStrategy()),
);
- await leetCodeExecutor.switchEndpoint(plugin.getLeetCodeEndpoint());
- await leetCodeManager.getLoginStatus();
+ // 设置站点
+ await executeService.switchEndpoint(getLeetCodeEndpoint());
+ // 获取登录状态
+ await loginContorller.getLoginStatus();
} catch (error) {
- leetCodeChannel.appendLine(error.toString());
+ logOutput.appendLine(error.toString());
promptForOpenOutputChannel("Extension initialization failed. Please open output channel for details.", DialogType.error);
}
}
@@ -98,7 +85,7 @@ export async function activate(context: vscode.ExtensionContext): Promise
export function deactivate(): void {
// Do nothing.
if (0) {
- var a = 0;
+ let a = 0;
console.log(a);
}
}
diff --git a/src/leetCodeChannel.ts b/src/leetCodeChannel.ts
deleted file mode 100644
index fa32ac2..0000000
--- a/src/leetCodeChannel.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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");
-
- public appendLine(message: string): void {
- this.channel.appendLine(message);
- }
-
- public append(message: string): void {
- this.channel.append(message);
- }
-
- public show(): void {
- this.channel.show();
- }
-
- public dispose(): void {
- this.channel.dispose();
- }
-}
-
-export const leetCodeChannel: LeetCodeChannel = new LeetCodeChannel();
diff --git a/src/leetCodeManager.ts b/src/leetCodeManager.ts
deleted file mode 100644
index 2dc42bd..0000000
--- a/src/leetCodeManager.ts
+++ /dev/null
@@ -1,223 +0,0 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
-
-import * as cp from "child_process";
-import { EventEmitter } from "events";
-import * as vscode from "vscode";
-import { leetCodeChannel } from "./leetCodeChannel";
-import { leetCodeExecutor } from "./leetCodeExecutor";
-import { IQuickItemEx, loginArgsMapping, UserStatus, userContestRanKingBase, userContestRankingObj } from "./shared";
-import { createEnvOption } from "./utils/cpUtils";
-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;
- }
-
- 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");
- }
- }
-
- public async signIn(): Promise {
- const picks: Array> = [];
- picks.push(
- {
- label: "LeetCode Account",
- detail: "Use LeetCode account to login (US endpoint is not supported)",
- value: "LeetCode",
- },
- {
- label: "Third-Party: GitHub",
- detail: "Use GitHub account to login",
- value: "GitHub",
- },
- {
- label: "Third-Party: LinkedIn",
- detail: "Use LinkedIn account to login",
- value: "LinkedIn",
- },
- {
- label: "LeetCode Cookie",
- detail: "Use LeetCode cookie copied from browser to login",
- value: "Cookie",
- },
- );
- const choice: IQuickItemEx | undefined = await vscode.window.showQuickPick(picks);
- if (!choice) {
- return;
- }
- const loginMethod: string = choice.value;
- const commandArg: string | undefined = loginArgsMapping.get(loginMethod);
- if (!commandArg) {
- throw new Error(`The login method "${loginMethod}" is not supported.`);
- }
- const isByCookie: boolean = loginMethod === "Cookie";
- const inMessage: string = isByCookie ? "sign in by cookie" : "sign in";
- 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();
-
- var childProc: cp.ChildProcess;
-
- if (wsl.useVscodeNode()) {
- childProc = cp.fork(await leetCodeExecutor.getLeetCodeBinaryPath(), ["user", commandArg], {
- silent: true,
- env: createEnvOption(),
- });
- } else {
- if (wsl.useWsl()) {
- childProc = cp.spawn("wsl", [leetCodeExecutor.node, leetCodeBinaryPath, "user", commandArg], { shell: true })
- } else {
- childProc = cp.spawn(leetCodeExecutor.node, [leetCodeBinaryPath, "user", commandArg], {
- shell: true,
- env: createEnvOption(),
- });
- }
-
- }
-
- childProc.stdout?.on("data", async (data: string | Buffer) => {
- data = data.toString();
- // vscode.window.showInformationMessage(`cc login msg ${data}.`);
- leetCodeChannel.append(data);
- if (data.includes("twoFactorCode")) {
- const twoFactor: string | undefined = await vscode.window.showInputBox({
- prompt: "Enter two-factor code.",
- ignoreFocusOut: true,
- validateInput: (s: string): string | undefined => s && s.trim() ? undefined : "The input must not be empty",
- });
- if (!twoFactor) {
- childProc.kill();
- return resolve(undefined);
- }
- childProc.stdin?.write(`${twoFactor}\n`);
- }
-
- var successMatch;
- try {
- successMatch = JSON.parse(data);
- } catch (e) {
- successMatch = {};
- }
- if (successMatch.code == 100) {
- childProc.stdin?.end();
- return resolve(successMatch.user_name);
- } else if (successMatch.code < 0) {
- childProc.stdin?.end();
- return reject(new Error(successMatch.msg));
- }
- });
-
- childProc.stderr?.on("data", (data: string | Buffer) => leetCodeChannel.append(data.toString()));
-
- childProc.on("error", reject);
- const name: string | undefined = await vscode.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",
- });
- if (!name) {
- childProc.kill();
- return resolve(undefined);
- }
- childProc.stdin?.write(`${name}\n`);
- const pwd: string | undefined = await vscode.window.showInputBox({
- prompt: isByCookie ? "Enter cookie" : "Enter password.",
- password: true,
- ignoreFocusOut: true,
- validateInput: (s: string): string | undefined => s ? undefined : isByCookie ? "Cookie must not be empty" : "Password must not be empty",
- });
- if (!pwd) {
- childProc.kill();
- return resolve(undefined);
- }
- childProc.stdin?.write(`${pwd}\n`);
- });
- if (userName) {
- vscode.window.showInformationMessage(`Successfully ${inMessage}.`);
- this.currentUser = userName;
- this.userStatus = UserStatus.SignedIn;
- this.emit("statusChanged");
- }
- } catch (error) {
- promptForOpenOutputChannel(`Failed to ${inMessage}. Please open the output channel for details`, DialogType.error);
- }
-
- }
-
- 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");
- } 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;
- }
-}
-
-export const leetCodeManager: LeetCodeManager = new LeetCodeManager();
diff --git a/src/shared.ts b/src/model/Model.ts
similarity index 74%
rename from src/shared.ts
rename to src/model/Model.ts
index 37ce32e..170dea0 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: https://github.com/ccagml/vscode-leetcode-problem-rating/src/model/Model.ts
+ * Path: https://github.com/ccagml/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, MessageItem } from "vscode";
+
+export interface IQuickItemEx extends QuickPickItem {
value: T;
}
@@ -173,6 +180,17 @@ export enum SortingStrategy {
IDDesc = "ID (Descending)"
}
+
+export const SORT_ORDER: SortingStrategy[] = [
+ SortingStrategy.None,
+ SortingStrategy.AcceptanceRateAsc,
+ SortingStrategy.AcceptanceRateDesc,
+ SortingStrategy.ScoreAsc,
+ SortingStrategy.ScoreDesc,
+ SortingStrategy.IDDesc,
+];
+
+
export enum SearchSetType {
ScoreRange = "ScoreRange",
Context = "Context",
@@ -197,7 +215,7 @@ export const SearchNode: ISearchSet = {
type: SearchSetType.ScoreRange,
time: 0,
todayData: undefined
-}
+};
export interface userContestRanKingBase {
attendedContestsCount: number, // 参与次数
@@ -227,3 +245,39 @@ export interface ISubmitEvent {
sub_type: string; // test submit
accepted: boolean
}
+
+
+export interface IWebViewOption {
+ title: string;
+ viewColumn: ViewColumn;
+ preserveFocus?: boolean;
+}
+
+
+export enum OpenOption {
+ justOpenFile = "仅打开问题文件",
+ openInCurrentWindow = "在当前VsCode窗口打开",
+ openInNewWindow = "在新的VsCode窗口打开",
+ addToWorkspace = "添加到工作空间",
+}
+
+export enum DialogType {
+ info = "info",
+ warning = "warning",
+ error = "error",
+}
+
+
+export const MessageItemObj: MessageItem = {
+ title: "",
+ isCloseAffordance: false,
+};
+
+
+export const DialogOptions = {
+ open: Object.assign({}, MessageItemObj, { title: "Open" }),
+ yes: Object.assign({}, MessageItemObj, { title: "Yes" }),
+ no: Object.assign({}, MessageItemObj, { title: "No", isCloseAffordance: true }),
+ never: Object.assign({}, MessageItemObj, { title: "Never" }),
+ singUp: Object.assign({}, MessageItemObj, { title: "Sign up" }),
+};
diff --git a/src/explorer/LeetCodeNode.ts b/src/model/NodeModel.ts
similarity index 79%
rename from src/explorer/LeetCodeNode.ts
rename to src/model/NodeModel.ts
index 821517e..39c0e52 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: https://github.com/ccagml/vscode-leetcode-problem-rating/src/model/NodeMOdel.ts
+ * Path: https://github.com/ccagml/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;
@@ -21,11 +28,11 @@ export class LeetCodeNode {
// 每日一题的修正
if (this.todayData) {
- const us = this.todayDataUserStatus
+ const us = this.todayDataUserStatus;
if (us == "FINISH") {
- return ProblemState.AC
+ return ProblemState.AC;
} else {
- return ProblemState.Unknown
+ return ProblemState.Unknown;
}
}
@@ -109,28 +116,28 @@ export class LeetCodeNode {
return this.data.scoreData?.ContestSlug || "";
}
public get scoreData(): IScoreData | undefined {
- return this.data.scoreData
+ return this.data.scoreData;
}
public get isSearchResult(): boolean {
- return this.data.isSearchResult
+ return this.data.isSearchResult;
}
public get input(): string {
return this.data.input || "";
}
// 每日一题的一些信息
public get todayData(): ITodayData | undefined {
- return this.data.todayData
+ return this.data.todayData;
}
public set todayData(s: ITodayData | undefined) {
- this.data.todayData = s
+ this.data.todayData = s;
}
public get todayDataDate(): string {
- return this.data.todayData?.date || ""
+ return this.data.todayData?.date || "";
}
public get todayDataUserStatus(): string {
- return this.data.todayData?.userStatus || ""
+ return this.data.todayData?.userStatus || "";
}
public get qid(): string {
- return this.data.qid || ""
+ return this.data.qid || "";
}
}
diff --git a/src/webview/LeetCodeWebview.ts b/src/service/BaseWebviewService.ts
similarity index 78%
rename from src/webview/LeetCodeWebview.ts
rename to src/service/BaseWebviewService.ts
index 8532c8d..3646604 100644
--- a/src/webview/LeetCodeWebview.ts
+++ b/src/service/BaseWebviewService.ts
@@ -1,11 +1,20 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/webview/BaseWebViewService.ts
+ * Path: https://github.com/ccagml/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, ConfigurationChangeEvent, Disposable, ViewColumn, WebviewPanel, window, workspace } from "vscode";
-import { openSettingsEditor, promptHintMessage } from "../utils/uiUtils";
-import { markdownEngine } from "./markdownEngine";
+import { markdownService } from "./MarkdownService";
+import { IWebViewOption } from "../model/Model";
+import { openSettingsEditor } from "../utils/ConfigUtils";
+import { promptHintMessage } from "../utils/OutputUtils";
-export abstract class LeetCodeWebview implements Disposable {
+export abstract class BaseWebViewService implements Disposable {
protected readonly viewType: string = "leetcode.webview";
protected panel: WebviewPanel | undefined;
@@ -25,7 +34,7 @@ export abstract class LeetCodeWebview implements Disposable {
enableCommandUris: true,
enableFindWidget: true,
retainContextWhenHidden: true,
- localResourceRoots: markdownEngine.localResourceRoots,
+ localResourceRoots: markdownService.localResourceRoots,
});
this.panel.onDidDispose(this.onDidDisposeWebview, this, this.listeners);
this.panel.webview.onDidReceiveMessage(this.onDidReceiveMessage, this, this.listeners);
@@ -61,7 +70,7 @@ export abstract class LeetCodeWebview implements Disposable {
protected async onDidReceiveMessage(_message: any): Promise { /* no special rule */ }
- protected abstract getWebviewOption(): ILeetCodeWebviewOption;
+ protected abstract getWebviewOption(): IWebViewOption;
protected abstract getWebviewContent(): string;
@@ -75,8 +84,3 @@ export abstract class LeetCodeWebview implements Disposable {
}
}
-export interface ILeetCodeWebviewOption {
- title: string;
- viewColumn: ViewColumn;
- preserveFocus?: boolean;
-}
diff --git a/src/service/EventService.ts b/src/service/EventService.ts
new file mode 100644
index 0000000..a89d488
--- /dev/null
+++ b/src/service/EventService.ts
@@ -0,0 +1,49 @@
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/service/EventService.ts
+ * Path: https://github.com/ccagml/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 67%
rename from src/leetCodeExecutor.ts
rename to src/service/ExecuteService.ts
index f16b200..d33ef5e 100644
--- a/src/leetCodeExecutor.ts
+++ b/src/service/ExecuteService.ts
@@ -1,51 +1,58 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/service/executeService.ts
+ * Path: https://github.com/ccagml/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";
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";
-import { executeCommand, executeCommandWithProgress } from "./utils/cpUtils";
-import { DialogOptions, openUrl } from "./utils/uiUtils";
-import * as wsl from "./utils/wslUtils";
-import { toWslPath, useWsl } from "./utils/wslUtils";
-
-class LeetCodeExecutor implements Disposable {
+import { ConfigurationChangeEvent, Disposable, MessageItem, window, workspace } from "vscode";
+import { DialogOptions, DialogType, Endpoint, IProblem, leetcodeHasInited } from "../model/Model";
+import { executeCommand, executeCommandWithProgress } from "../utils/CliUtils";
+import { getNodePath } from "../utils/ConfigUtils";
+import { openUrl, promptForOpenOutputChannel } from "../utils/OutputUtils";
+import * as systemUtils from "../utils/SystemUtils";
+import { toWslPath, useWsl } from "../utils/SystemUtils";
+
+class ExecuteService implements Disposable {
private leetCodeCliResourcesRootPath: string;
private leetCodeCliRootPath: string;
private nodeExecutable: string;
private configurationChangeListener: Disposable;
constructor() {
- // this.leetCodeCliResourcesRootPath = path.join(__dirname, "..", "..", "node_modules", "vsc-leetcode-cli");
- if (!wsl.useVscodeNode()) {
- this.leetCodeCliResourcesRootPath = path.join(__dirname, "..", "..", "resources");
+ // this.leetCodeCliResourcesRootPath = path.join(__dirname, "..", "..", "node_modules", "childProcessCall");
+ if (!systemUtils.useVscodeNode()) {
+ this.leetCodeCliResourcesRootPath = path.join(__dirname, "..", "..", "..", "resources");
}
- this.leetCodeCliRootPath = path.join(__dirname, "..", "..", "out", "src", "vsc-leetcode-cli");
- this.nodeExecutable = this.getNodePath();
+ this.leetCodeCliRootPath = path.join(__dirname, "..", "..", "..", "out", "src", "childProcessCall");
+ this.nodeExecutable = this.initNodePath();
this.configurationChangeListener = workspace.onDidChangeConfiguration((event: ConfigurationChangeEvent) => {
- if (event.affectsConfiguration("leetcode.nodePath")) {
- this.nodeExecutable = this.getNodePath();
+ if (event.affectsConfiguration("leetcode-problem-rating.nodePath")) {
+ this.nodeExecutable = this.initNodePath();
}
}, this);
}
public async getLeetCodeBinaryPath(): Promise {
- if (wsl.useVscodeNode()) {
- return `${path.join(this.leetCodeCliRootPath, "new_lib", "cli.js")}`;
+ if (systemUtils.useVscodeNode()) {
+ return `${path.join(this.leetCodeCliRootPath, "cli.js")}`;
} else {
- if (wsl.useWsl()) {
- return `${await wsl.toWslPath(`"${path.join(this.leetCodeCliResourcesRootPath, "bin", "leetcode")}"`)}`;
+ if (systemUtils.useWsl()) {
+ return `${await systemUtils.toWslPath(`"${path.join(this.leetCodeCliResourcesRootPath, "bin", "leetcode")}"`)}`;
}
return `"${path.join(this.leetCodeCliResourcesRootPath, "bin", "leetcode")}"`;
}
}
- 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();
@@ -72,21 +79,16 @@ class LeetCodeExecutor implements Disposable {
}
return false;
}
- // for (const plugin of supportedPlugins) {
- // try { // Check plugin
- // // await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-e", plugin]);
- // } catch (error) { // Remove old cache that may cause the error download plugin and activate
- // // await this.removeOldCache();
- // // await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "plugin", "-i", plugin]);
- // }
- // }
- // Set the global state HasInited true to skip delete old cache after init
context.globalState.update(leetcodeHasInited, true);
return true;
}
- public async deleteCache(): Promise {
- return await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "cache", "-d"]);
+ public async deleteCache() {
+ try {
+ await this.executeCommandEx(this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "cache", "-d"]);
+ } catch (error) {
+ await promptForOpenOutputChannel("Failed to delete cache. 请查看控制台信息~", DialogType.error);
+ }
}
public async getUserInfo(): Promise {
@@ -124,19 +126,7 @@ class LeetCodeExecutor implements Disposable {
}
}
- /**
- * This function returns solution of a problem identified by input
- *
- * @remarks
- * Even though this function takes the needTranslation flag, it is important to note
- * that as of vsc-leetcode-cli 2.8.0, leetcode-cli doesn't support querying solution
- * on CN endpoint yet. So this flag doesn't have any effect right now.
- *
- * @param input - parameter to pass to cli that can identify a problem
- * @param language - the source code language of the solution desired
- * @param needTranslation - whether or not to use endPoint translation on solution query
- * @returns promise of the solution string
- */
+
public async showSolution(input: string, language: string, needTranslation: boolean): Promise {
// solution don't support translation
const cmd: string[] = [await this.getLeetCodeBinaryPath(), "show", input, "--solution", "-l", language];
@@ -157,6 +147,13 @@ class LeetCodeExecutor implements Disposable {
return solution;
}
+ public async getScoreDataOnline(): Promise {
+ // solution don't support translation
+ const cmd: string[] = [await this.getLeetCodeBinaryPath(), "query", "-c"];
+ const solution: string = await this.executeCommandWithProgressEx("get data from https://zerotrac.github.io/leetcode_problem_rating/data.json", this.nodeExecutable, cmd);
+ return solution;
+ }
+
public async getTestApi(username: string): Promise {
// solution don't support translation
const cmd: string[] = [await this.getLeetCodeBinaryPath(), "query", "-z", username];
@@ -183,25 +180,10 @@ 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 {
- if (wsl.useVscodeNode()) {
+ if (systemUtils.useVscodeNode()) {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "submit", `${filePath}`]);
}
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "submit", `"${filePath}"`]);
@@ -215,18 +197,18 @@ class LeetCodeExecutor implements Disposable {
public async testSolution(filePath: string, testString?: string, allCase?: boolean): Promise {
if (testString) {
- if (wsl.useVscodeNode()) {
+ if (systemUtils.useVscodeNode()) {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `${filePath}`, "-t", `${testString}`]);
}
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-t", `${testString}`]);
}
if (allCase) {
- if (wsl.useVscodeNode()) {
+ if (systemUtils.useVscodeNode()) {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `${filePath}`, "-a"]);
}
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`, "-a"]);
}
- if (wsl.useVscodeNode()) {
+ if (systemUtils.useVscodeNode()) {
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `${filePath}`]);
}
return await this.executeCommandWithProgressEx("Submitting to LeetCode...", this.nodeExecutable, [await this.getLeetCodeBinaryPath(), "test", `"${filePath}"`]);
@@ -249,17 +231,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;
@@ -269,30 +241,29 @@ class LeetCodeExecutor implements Disposable {
this.configurationChangeListener.dispose();
}
- private getNodePath(): string {
- if (wsl.useVscodeNode()) {
- return "node"
+ private initNodePath(): string {
+ if (systemUtils.useVscodeNode()) {
+ return "node";
}
- const extensionConfig: WorkspaceConfiguration = workspace.getConfiguration("leetcode-problem-rating", null);
- return extensionConfig.get("nodePath", "node" /* default value */);
+ return getNodePath();
}
private async executeCommandEx(command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise {
- if (wsl.useWsl()) {
+ if (systemUtils.useWsl()) {
return await executeCommand("wsl", [command].concat(args), options);
}
return await executeCommand(command, args, options);
}
private async executeCommandWithProgressEx(message: string, command: string, args: string[], options: cp.SpawnOptions = { shell: true }): Promise {
- if (wsl.useWsl()) {
+ if (systemUtils.useWsl()) {
return await executeCommandWithProgress(message, "wsl", [command].concat(args), options);
}
return await executeCommandWithProgress(message, command, args, options);
}
public async removeOldCache(): Promise {
- const oldPath: string = path.join(os.homedir(), ".lc");
+ const oldPath: string = path.join(os.homedir(), ".lcpr");
if (await fse.pathExists(oldPath)) {
await fse.remove(oldPath);
}
@@ -300,4 +271,4 @@ class LeetCodeExecutor implements Disposable {
}
-export const leetCodeExecutor: LeetCodeExecutor = new LeetCodeExecutor();
+export const executeService: ExecuteService = new ExecuteService();
diff --git a/src/codelens/CustomCodeLensProvider.ts b/src/service/FileButtonService.ts
similarity index 81%
rename from src/codelens/CustomCodeLensProvider.ts
rename to src/service/FileButtonService.ts
index 3322ed2..d922fae 100644
--- a/src/codelens/CustomCodeLensProvider.ts
+++ b/src/service/FileButtonService.ts
@@ -1,12 +1,18 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/service/FileButtonService.ts
+ * Path: https://github.com/ccagml/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 { explorerNodeManager } from "../explorer/explorerNodeManager";
-import { LeetCodeNode } from "../explorer/LeetCodeNode";
-import { getEditorShortcuts } from "../utils/settingUtils";
+import { treeViewController } from "../controller/TreeViewController";
+import { NodeModel } from "../model/NodeModel";
+import { getEditorShortcuts } from "../utils/ConfigUtils";
-export class CustomCodeLensProvider implements vscode.CodeLensProvider {
+export class FileButtonService implements vscode.CodeLensProvider {
private onDidChangeCodeLensesEmitter: vscode.EventEmitter = new vscode.EventEmitter();
@@ -30,9 +36,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;
@@ -106,4 +112,4 @@ export class CustomCodeLensProvider implements vscode.CodeLensProvider {
}
}
-export const customCodeLensProvider: CustomCodeLensProvider = new CustomCodeLensProvider();
+export const fileButtonService: FileButtonService = new FileButtonService();
diff --git a/src/webview/markdownEngine.ts b/src/service/MarkdownService.ts
similarity index 90%
rename from src/webview/markdownEngine.ts
rename to src/service/MarkdownService.ts
index 4c1db65..a2e8405 100644
--- a/src/webview/markdownEngine.ts
+++ b/src/service/MarkdownService.ts
@@ -1,15 +1,22 @@
-// Copyright (c) jdneo. All rights reserved.
-// Licensed under the MIT license.
+/*
+ * Filename: https://github.com/ccagml/vscode-leetcode-problem-rating/src/service/markdownService.ts
+ * Path: https://github.com/ccagml/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 hljs from "highlight.js";
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 { isWindows } from "../utils/osUtils";
+import { logOutput } from "../utils/OutputUtils";
+import { isWindows } from "../utils/SystemUtils";
-class MarkdownEngine implements vscode.Disposable {
+class MarkdownService implements vscode.Disposable {
private engine: MarkdownIt;
private config: MarkdownConfiguration;
@@ -54,7 +61,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);
}
@@ -163,4 +170,4 @@ class MarkdownConfiguration {
}
}
-export const markdownEngine: MarkdownEngine = new MarkdownEngine();
+export const markdownService: MarkdownService = new MarkdownService();
diff --git a/src/webview/leetCodePreviewProvider.ts b/src/service/PreviewService.ts
similarity index 85%
rename from src/webview/leetCodePreviewProvider.ts
rename to src/service/PreviewService.ts
index 78b4099..ff94145 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: https://github.com/ccagml/vscode-leetcode-problem-rating/src/service/previewService.ts
+ * Path: https://github.com/ccagml/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 { getLeetCodeEndpoint } from "../utils/ConfigUtils";
+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 : ""}