From c71b0579a84e4613f79bbcc2e79ca2a27895aec5 Mon Sep 17 00:00:00 2001 From: XzZZzX02 Date: Fri, 15 Nov 2024 10:51:23 +0800 Subject: [PATCH 1/5] feat: add custom code snippets support for LeetCode problems --- package.json | 6 ++++++ src/leetCodeExecutor.ts | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 53552b7..1e35657 100644 --- a/package.json +++ b/package.json @@ -705,6 +705,12 @@ "default": true, "scope": "application", "description": "Allow LeetCode to report anonymous usage data to improve the product." + }, + "leetcode.codeSnippets": { + "type": "string", + "default": "", + "scope": "application", + "description": "Custom code snippets for LeetCode problems." } } } diff --git a/src/leetCodeExecutor.ts b/src/leetCodeExecutor.ts index d2332c7..3f11247 100644 --- a/src/leetCodeExecutor.ts +++ b/src/leetCodeExecutor.ts @@ -1,6 +1,7 @@ // Copyright (c) jdneo. All rights reserved. // Licensed under the MIT license. +import * as vscode from "vscode"; import * as cp from "child_process"; import * as fse from "fs-extra"; import * as os from "os"; @@ -110,7 +111,19 @@ class LeetCodeExecutor implements Disposable { if (!await fse.pathExists(filePath)) { await fse.createFile(filePath); - const codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, cmd); + let codeTemplate: string = await this.executeCommandWithProgressEx("Fetching problem data...", this.nodeExecutable, cmd); + const lines = codeTemplate.split(/\r?\n/); + const targetIndex = lines.findIndex(line => line.includes('// @lc code=start')); + const codeSnippet: string = vscode.workspace.getConfiguration('leetcode').get('codeSnippets', ''); + if (targetIndex !== -1 && codeSnippet.trim() !== '') { + let insertIndex = targetIndex; + while (insertIndex - 1 >= 0 && lines[insertIndex - 1].trim() === '') { + lines.splice(insertIndex - 1, 1); + insertIndex--; + } + lines.splice(insertIndex, 0, codeSnippet); + } + codeTemplate = lines.join('\n'); await fse.writeFile(filePath, codeTemplate); } } From beefdc6c5b5e40c1d73767a3df33f69992c6ad8e Mon Sep 17 00:00:00 2001 From: XzZZzX02 Date: Sun, 17 Nov 2024 02:33:29 +0800 Subject: [PATCH 2/5] feat: update version and add daily challenge feature --- package-lock.json | 4 +-- package.json | 26 ++++++--------- src/commands/show.ts | 11 +++++++ src/extension.ts | 3 +- src/request/query-daily-challange.ts | 13 ++++++++ src/shared.ts | 49 ++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 19 deletions(-) create mode 100644 src/request/query-daily-challange.ts diff --git a/package-lock.json b/package-lock.json index 2ac17cf..aa5d515 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "vscode-leetcode", - "version": "0.18.1", + "version": "0.18.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "vscode-leetcode", - "version": "0.18.1", + "version": "0.18.4", "license": "MIT", "dependencies": { "axios": "^1.6.8", diff --git a/package.json b/package.json index 1e35657..11a8bb7 100644 --- a/package.json +++ b/package.json @@ -25,22 +25,6 @@ "interview" ], "preview": true, - "activationEvents": [ - "onCommand:leetcode.toggleLeetCodeCn", - "onCommand:leetcode.signin", - "onCommand:leetcode.signout", - "onCommand:leetcode.manageSessions", - "onCommand:leetcode.refreshExplorer", - "onCommand:leetcode.pickOne", - "onCommand:leetcode.showProblem", - "onCommand:leetcode.previewProblem", - "onCommand:leetcode.searchProblem", - "onCommand:leetcode.testSolution", - "onCommand:leetcode.submitSolution", - "onCommand:leetcode.switchDefaultLanguage", - "onCommand:leetcode.problems.sort", - "onView:leetCodeExplorer" - ], "main": "./out/src/extension", "contributes": { "commands": [ @@ -141,6 +125,11 @@ "title": "Sort Problems", "category": "LeetCode", "icon": "$(sort-precedence)" + }, + { + "command": "leetcode.pickDaily", + "title": "Pick Daily Chanllenge", + "category": "LeetCode" } ], "viewsContainers": { @@ -223,6 +212,11 @@ "command": "leetcode.removeFavorite", "when": "view == leetCodeExplorer && viewItem == problem-favorite", "group": "inline" + }, + { + "command": "leetcode.pickDaily", + "when": "view == leetCodeExplorer", + "group": "leetcode@4" } ], "commandPalette": [ diff --git a/src/commands/show.ts b/src/commands/show.ts index eccf557..122d479 100644 --- a/src/commands/show.ts +++ b/src/commands/show.ts @@ -30,6 +30,7 @@ import { leetCodeSolutionProvider } from "../webview/leetCodeSolutionProvider"; import * as list from "./list"; import { getLeetCodeEndpoint } from "./plugin"; import { globalState } from "../globalState"; +import { queryDailyChallenge } from "../request/query-daily-challange"; export async function previewProblem(input: IProblem | vscode.Uri, isSideMode: boolean = false): Promise { let node: IProblem; @@ -70,6 +71,16 @@ export async function pickOne(): Promise { await showProblemInternal(randomProblem); } +export async function pickDailyChallenge(): Promise { + const dailyChallengeID: string = await queryDailyChallenge(); + const node: IProblem | undefined = explorerNodeManager.getNodeById(dailyChallengeID); + if (!node) { + vscode.window.showErrorMessage(`No daily challenge found for today.`); + return; + } + await showProblemInternal(node); +} + export async function showProblem(node?: LeetCodeNode): Promise { if (!node) { return; diff --git a/src/extension.ts b/src/extension.ts index 439673f..7a899e0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -97,7 +97,8 @@ export async function activate(context: vscode.ExtensionContext): Promise 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()) + vscode.commands.registerCommand("leetcode.problems.sort", () => plugin.switchSortingStrategy()), + vscode.commands.registerCommand("leetcode.pickDaily", () => show.pickDailyChallenge()) ); await leetCodeExecutor.switchEndpoint(plugin.getLeetCodeEndpoint()); diff --git a/src/request/query-daily-challange.ts b/src/request/query-daily-challange.ts new file mode 100644 index 0000000..d71409d --- /dev/null +++ b/src/request/query-daily-challange.ts @@ -0,0 +1,13 @@ +import {getUrl, getDailyQueryStr, getDailyProblemID} from "../shared"; +import {LcAxios} from "../utils/httpUtils"; + +export const queryDailyChallenge = async (): Promise => { + return LcAxios(getUrl("graphql"), { + method: "POST", + data: { + query: getDailyQueryStr(), + variables: {}, + operationName: 'questionOfToday' + }, + }).then((res) => getDailyProblemID(res)); +}; diff --git a/src/shared.ts b/src/shared.ts index e8b59d8..95d3bbf 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -2,6 +2,7 @@ // Licensed under the MIT license. import * as vscode from "vscode"; +import { AxiosResponse } from "axios"; export interface IQuickItemEx extends vscode.QuickPickItem { value: T; @@ -156,3 +157,51 @@ export const getUrl = (key: string) => { return urls[key]; } }; + +export const getEndpoint = (): string => { + const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); + return leetCodeConfig.get("endpoint", Endpoint.LeetCode); +} + + +export const getDailyQueryStr = (): string => { + const dailyQueryStrs = { + LeetCode: ` + query questionOfToday { + activeDailyCodingChallengeQuestion { + question { + frontendQuestionId: questionFrontendId + } + } + } + `, + LeetCodeCN: ` + query questionOfToday { + todayRecord { + question { + frontendQuestionId: questionFrontendId + } + } + } + ` + } + const point: string = getEndpoint(); + switch (point) { + case Endpoint.LeetCodeCN: + return dailyQueryStrs.LeetCodeCN; + case Endpoint.LeetCode: + return dailyQueryStrs.LeetCode; + } + return ""; +} + +export const getDailyProblemID = (res: AxiosResponse): string => { + const point = getEndpoint(); + switch (point) { + case Endpoint.LeetCodeCN: + return res.data.data.todayRecord[0].question.frontendQuestionId; + case Endpoint.LeetCode: + return res.data.data.todayRecord[0].question.frontendQuestionId; + } + return ""; +} From 0696a48d554584fe73870eb3b6108755bb0d4d41 Mon Sep 17 00:00:00 2001 From: XzZZzX02 Date: Sun, 17 Nov 2024 22:12:43 +0800 Subject: [PATCH 3/5] feat: add daily challenge category and implement related node retrieval --- src/explorer/LeetCodeTreeDataProvider.ts | 2 ++ src/explorer/explorerNodeManager.ts | 10 ++++++++++ src/shared.ts | 1 + 3 files changed, 13 insertions(+) diff --git a/src/explorer/LeetCodeTreeDataProvider.ts b/src/explorer/LeetCodeTreeDataProvider.ts index 9c29894..f6adc72 100644 --- a/src/explorer/LeetCodeTreeDataProvider.ts +++ b/src/explorer/LeetCodeTreeDataProvider.ts @@ -85,6 +85,8 @@ export class LeetCodeTreeDataProvider implements vscode.TreeDataProvider = new Map(); @@ -53,6 +54,10 @@ class ExplorerNodeManager implements Disposable { id: Category.Favorite, name: Category.Favorite, }), false), + new LeetCodeNode(Object.assign({}, defaultProblem, { + id: Category.Daily, + name: Category.Daily, + }), false) ]; } @@ -148,6 +153,11 @@ class ExplorerNodeManager implements Disposable { return this.applySortingStrategy(res); } + public async getDailyChallengeNode(): Promise { + const dailyChallengeID: string = await queryDailyChallenge(); + return this.getNodeById(dailyChallengeID) ? [this.getNodeById(dailyChallengeID)!] : []; + } + public dispose(): void { this.explorerNodeMap.clear(); this.companySet.clear(); diff --git a/src/shared.ts b/src/shared.ts index 95d3bbf..bb15215 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -102,6 +102,7 @@ export enum Category { Tag = "Tag", Company = "Company", Favorite = "Favorite", + Daily = "Daily Challenge" } export const supportedPlugins: string[] = ["company", "solution.discuss", "leetcode.cn"]; From cac44adaef47c4836519c7c946d740649ff3b61f Mon Sep 17 00:00:00 2001 From: XzZZzX02 Date: Sun, 17 Nov 2024 22:22:39 +0800 Subject: [PATCH 4/5] feat: refactor endpoint retrieval and enhance daily challenge query handling --- src/commands/plugin.ts | 5 ++- src/request/query-daily-challange.ts | 46 ++++++++++++++++++++++++++- src/shared.ts | 47 +--------------------------- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/src/commands/plugin.ts b/src/commands/plugin.ts index d2ed4b6..94e9ff4 100644 --- a/src/commands/plugin.ts +++ b/src/commands/plugin.ts @@ -4,7 +4,7 @@ import * as vscode from "vscode"; import { leetCodeTreeDataProvider } from "../explorer/LeetCodeTreeDataProvider"; import { leetCodeExecutor } from "../leetCodeExecutor"; -import { IQuickItemEx } from "../shared"; +import { getEndpoint, IQuickItemEx } from "../shared"; import { Endpoint, SortingStrategy } from "../shared"; import { DialogType, promptForOpenOutputChannel, promptForSignIn } from "../utils/uiUtils"; import { deleteCache } from "./cache"; @@ -50,8 +50,7 @@ export async function switchEndpoint(): Promise { } export function getLeetCodeEndpoint(): string { - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - return leetCodeConfig.get("endpoint", Endpoint.LeetCode); + return getEndpoint(); } const SORT_ORDER: SortingStrategy[] = [ diff --git a/src/request/query-daily-challange.ts b/src/request/query-daily-challange.ts index d71409d..251b888 100644 --- a/src/request/query-daily-challange.ts +++ b/src/request/query-daily-challange.ts @@ -1,5 +1,49 @@ -import {getUrl, getDailyQueryStr, getDailyProblemID} from "../shared"; +import {getUrl, getEndpoint, Endpoint} from "../shared"; import {LcAxios} from "../utils/httpUtils"; +import {AxiosResponse} from "axios"; + + +export const getDailyQueryStr = (): string => { + const dailyQueryStrs = { + LeetCode: ` + query questionOfToday { + activeDailyCodingChallengeQuestion { + question { + frontendQuestionId: questionFrontendId + } + } + } + `, + LeetCodeCN: ` + query questionOfToday { + todayRecord { + question { + frontendQuestionId: questionFrontendId + } + } + } + ` + } + const point: string = getEndpoint(); + switch (point) { + case Endpoint.LeetCodeCN: + return dailyQueryStrs.LeetCodeCN; + case Endpoint.LeetCode: + return dailyQueryStrs.LeetCode; + } + return ""; +} + +export const getDailyProblemID = (res: AxiosResponse): string => { + const point = getEndpoint(); + switch (point) { + case Endpoint.LeetCodeCN: + return res.data.data.todayRecord[0].question.frontendQuestionId; + case Endpoint.LeetCode: + return res.data.data.todayRecord[0].question.frontendQuestionId; + } + return ""; +} export const queryDailyChallenge = async (): Promise => { return LcAxios(getUrl("graphql"), { diff --git a/src/shared.ts b/src/shared.ts index bb15215..e155e04 100644 --- a/src/shared.ts +++ b/src/shared.ts @@ -2,7 +2,6 @@ // Licensed under the MIT license. import * as vscode from "vscode"; -import { AxiosResponse } from "axios"; export interface IQuickItemEx extends vscode.QuickPickItem { value: T; @@ -148,8 +147,7 @@ export const urlsCn = { }; export const getUrl = (key: string) => { - const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); - const point = leetCodeConfig.get("endpoint", Endpoint.LeetCode); + const point = getEndpoint(); switch (point) { case Endpoint.LeetCodeCN: return urlsCn[key]; @@ -163,46 +161,3 @@ export const getEndpoint = (): string => { const leetCodeConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("leetcode"); return leetCodeConfig.get("endpoint", Endpoint.LeetCode); } - - -export const getDailyQueryStr = (): string => { - const dailyQueryStrs = { - LeetCode: ` - query questionOfToday { - activeDailyCodingChallengeQuestion { - question { - frontendQuestionId: questionFrontendId - } - } - } - `, - LeetCodeCN: ` - query questionOfToday { - todayRecord { - question { - frontendQuestionId: questionFrontendId - } - } - } - ` - } - const point: string = getEndpoint(); - switch (point) { - case Endpoint.LeetCodeCN: - return dailyQueryStrs.LeetCodeCN; - case Endpoint.LeetCode: - return dailyQueryStrs.LeetCode; - } - return ""; -} - -export const getDailyProblemID = (res: AxiosResponse): string => { - const point = getEndpoint(); - switch (point) { - case Endpoint.LeetCodeCN: - return res.data.data.todayRecord[0].question.frontendQuestionId; - case Endpoint.LeetCode: - return res.data.data.todayRecord[0].question.frontendQuestionId; - } - return ""; -} From 90e9670956aa6d8517ca3b74a4f78e0d05103950 Mon Sep 17 00:00:00 2001 From: XzZZzX02 Date: Sun, 17 Nov 2024 22:54:59 +0800 Subject: [PATCH 5/5] fix --- package.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/package.json b/package.json index 11a8bb7..427d885 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,22 @@ "interview" ], "preview": true, + "activationEvents": [ + "onCommand:leetcode.toggleLeetCodeCn", + "onCommand:leetcode.signin", + "onCommand:leetcode.signout", + "onCommand:leetcode.manageSessions", + "onCommand:leetcode.refreshExplorer", + "onCommand:leetcode.pickOne", + "onCommand:leetcode.showProblem", + "onCommand:leetcode.previewProblem", + "onCommand:leetcode.searchProblem", + "onCommand:leetcode.testSolution", + "onCommand:leetcode.submitSolution", + "onCommand:leetcode.switchDefaultLanguage", + "onCommand:leetcode.problems.sort", + "onView:leetCodeExplorer" + ], "main": "./out/src/extension", "contributes": { "commands": [