irongit

A Neovim plugin enabling you to solve LeetCode problems.

stylua indent width=4

kawreauthored
parent 39af86ccommit 2af51c9759b0fba67d022ec5410c9f02708ac8f2Browse files

21 files changed, +412 -410

+1-1.stylua.toml
@@ -1,7 +1,7 @@
11 column_width = 100
22 line_endings = "Unix"
33 indent_type = "Spaces"
4-indent_width = 2
4+indent_width = 4
55 quote_style = "ForceDouble"
66 call_parentheses = "Always"
77 collapse_simple_statement = "Always"
+11-11lua/leetcode.lua
@@ -5,19 +5,19 @@ local M = {}
55
66 ---@param cfg? lc.Config
77 function M.setup(cfg)
8- config.apply(cfg or {})
8+ config.apply(cfg or {})
99
10- vim.cmd([[highlight LcProblemEasy guifg=##00b8a3]])
11- vim.cmd([[highlight LcProblemMedium guifg=#ffb800]])
12- vim.cmd([[highlight LcProblemHard guifg=#ef4743]])
10+ vim.cmd([[highlight LcProblemEasy guifg=##00b8a3]])
11+ vim.cmd([[highlight LcProblemMedium guifg=#ffb800]])
12+ vim.cmd([[highlight LcProblemHard guifg=#ef4743]])
1313
14- vim.api.nvim_create_autocmd("VimEnter", {
15- pattern = "*",
16- nested = true,
17- callback = function()
18- if config.user.invoke_name == vim.fn.expand("%") then api.cmd.leetcode() end
19- end,
20- })
14+ vim.api.nvim_create_autocmd("VimEnter", {
15+ pattern = "*",
16+ nested = true,
17+ callback = function()
18+ if config.user.invoke_name == vim.fn.expand("%") then api.cmd.leetcode() end
19+ end,
20+ })
2121 end
2222
2323 return M
+53-53lua/leetcode/api/command/init.lua
@@ -12,68 +12,68 @@ local path = require("plenary.path")
1212 local M = {}
1313
1414 function M.lc_problems()
15- local _, res = assert(pcall(cache.problems.read))
16-
17- ui.pick_one(
18- res,
19- "Select a Problem",
20- cache.problems.formatter,
21-
22- ---@param problem lc.Problem
23- function(problem)
24- if not problem then return end
25-
26- local dir = config.user.directory .. "/solutions/"
27- local fn = problem.index .. "." .. problem.title_slug .. ".java"
28- local file = path:new(dir .. fn)
29-
30- if not file:exists() then
31- local editor_data = gql.question.editor_data(problem.title_slug)
32-
33- local code
34- if editor_data.code_snippets ~= vim.NIL then
35- for _, v in ipairs(editor_data.code_snippets) do
36- if v.langSlug == config.user.lang or v.langSlug == config.user.sql then
37- code = v.code
38- break
15+ local _, res = assert(pcall(cache.problems.read))
16+
17+ ui.pick_one(
18+ res,
19+ "Select a Problem",
20+ cache.problems.formatter,
21+
22+ ---@param problem lc.Problem
23+ function(problem)
24+ if not problem then return end
25+
26+ local dir = config.user.directory .. "/solutions/"
27+ local fn = problem.index .. "." .. problem.title_slug .. ".java"
28+ local file = path:new(dir .. fn)
29+
30+ if not file:exists() then
31+ local editor_data = gql.question.editor_data(problem.title_slug)
32+
33+ local code
34+ if editor_data.code_snippets ~= vim.NIL then
35+ for _, v in ipairs(editor_data.code_snippets) do
36+ if v.langSlug == config.user.lang or v.langSlug == config.user.sql then
37+ code = v.code
38+ break
39+ end
40+ end
41+ end
42+
43+ if not code then
44+ log.error("failed to fetch code snippet")
45+ else
46+ file:write(code, "w")
47+ end
3948 end
40- end
41- end
42-
43- if not code then
44- log.error("failed to fetch code snippet")
45- else
46- file:write(code, "w")
47- end
48- end
4949
50- vim.cmd("cd " .. dir)
51- vim.cmd("e " .. file:absolute())
50+ vim.cmd("cd " .. dir)
51+ vim.cmd("e " .. file:absolute())
5252
53- ui.create_leetcode_win(problem)
54- end
55- )
53+ ui.create_leetcode_win(problem)
54+ end
55+ )
5656 end
5757
5858 function M.leetcode()
59- M.authenticate()
60- dashboard.setup()
61- vim.cmd("Alpha | bd#")
59+ M.authenticate()
60+ dashboard.setup()
61+ vim.cmd("Alpha | bd#")
6262 end
6363
6464 function M.cookie_prompt()
65- local cookie = require("leetcode.cache.cookie")
66-
67- ui.input(
68- "Enter cookie",
69- ---@param cookie_str string
70- function(cookie_str)
71- if not cookie_str then return end
72-
73- cookie.new(cookie_str)
74- require("leetcode.ui.dashboard").update()
75- end
76- )
65+ local cookie = require("leetcode.cache.cookie")
66+
67+ ui.input(
68+ "Enter cookie",
69+ ---@param cookie_str string
70+ function(cookie_str)
71+ if not cookie_str then return end
72+
73+ cookie.new(cookie_str)
74+ require("leetcode.ui.dashboard").update()
75+ end
76+ )
7777 end
7878
7979 ---Merge configurations into default configurations and set it as user configurations.
+12-12lua/leetcode/api/headers.lua
@@ -1,19 +1,19 @@
11 local M = {}
22
33 M.get = function()
4- local cookie = require("leetcode.cache.cookie").read()
4+ local cookie = require("leetcode.cache.cookie").read()
55
6- return {
7- ["Cookie"] = cookie and string.format(
8- "LEETCODE_SESSION=%s;csrftoken=%s",
9- cookie.leetcode_session,
10- cookie.csrftoken
11- ) or "",
12- ["Content-Type"] = "application/json",
13- ["Accept"] = "application/json",
14- ["x-csrftoken"] = cookie and cookie.csrftoken or nil,
15- ["Referer"] = "https://leetcode.com",
16- }
6+ return {
7+ ["Cookie"] = cookie and string.format(
8+ "LEETCODE_SESSION=%s;csrftoken=%s",
9+ cookie.leetcode_session,
10+ cookie.csrftoken
11+ ) or "",
12+ ["Content-Type"] = "application/json",
13+ ["Accept"] = "application/json",
14+ ["x-csrftoken"] = cookie and cookie.csrftoken or nil,
15+ ["Referer"] = "https://leetcode.com",
16+ }
1717 end
1818
1919 return M
+1-1lua/leetcode/api/init.lua
@@ -1,6 +1,6 @@
11 ---@class lc.Api
22 local Api = {
3- cmd = require("leetcode.api.command"),
3+ cmd = require("leetcode.api.command"),
44 }
55
66 return Api
+17-17lua/leetcode/cache/cookie.lua
@@ -12,23 +12,23 @@ local M = {}
1212 ---
1313 ---@return lc.Cookie
1414 function M.new(cookie_str)
15- local _, t = assert(pcall(M.parse, cookie_str))
15+ local _, t = assert(pcall(M.parse, cookie_str))
1616
17- if not file:exists() then file:touch() end
18- file:write(cookie_str, "w")
17+ if not file:exists() then file:touch() end
18+ file:write(cookie_str, "w")
1919
20- return t
20+ return t
2121 end
2222
2323 ---@return lc.Cookie | nil
2424 function M.read()
25- local r_ok, contents = pcall(path.read, file)
26- if not r_ok then return end
25+ local r_ok, contents = pcall(path.read, file)
26+ if not r_ok then return end
2727
28- local n_ok, cookie = pcall(M.new, contents)
29- if not n_ok then return end
28+ local n_ok, cookie = pcall(M.new, contents)
29+ if not n_ok then return end
3030
31- return cookie
31+ return cookie
3232 end
3333
3434 function M.delete() file:rm() end
@@ -36,17 +36,17 @@ function M.delete() file:rm() end
3636 ---@param cookie_str string
3737 ---
3838 function M.parse(cookie_str)
39- local cookie = {}
39+ local cookie = {}
4040
41- local csrf_ok, csrf = pcall(string.match, cookie_str, "csrftoken=[^;]+")
42- assert(csrf_ok and csrf, "Bad csrf token format")
43- cookie.csrftoken = csrf:sub(11)
41+ local csrf_ok, csrf = pcall(string.match, cookie_str, "csrftoken=[^;]+")
42+ assert(csrf_ok and csrf, "Bad csrf token format")
43+ cookie.csrftoken = csrf:sub(11)
4444
45- local ls_ok, ls = pcall(string.match, cookie_str, "LEETCODE_SESSION=[^;]+")
46- assert(ls_ok and ls, "Bad leetcode session token format")
47- cookie.leetcode_session = ls:sub(18)
45+ local ls_ok, ls = pcall(string.match, cookie_str, "LEETCODE_SESSION=[^;]+")
46+ assert(ls_ok and ls, "Bad leetcode session token format")
47+ cookie.leetcode_session = ls:sub(18)
4848
49- return cookie
49+ return cookie
5050 end
5151
5252 return M
+3-3lua/leetcode/cache/init.lua
@@ -1,8 +1,8 @@
11 ---@class lc.Cache
22 local Cache = {
3- cookie = require("leetcode.cache.cookie"),
4- problems = require("leetcode.cache.problems"),
5- -- solutions = require("leetcode.cache.solutions"),
3+ cookie = require("leetcode.cache.cookie"),
4+ problems = require("leetcode.cache.problems"),
5+ -- solutions = require("leetcode.cache.solutions"),
66 }
77
88 return Cache
+30-30lua/leetcode/cache/problems.lua
@@ -16,62 +16,62 @@ local file = path:new(config.user.directory .. "/.problems")
1616 local M = {}
1717
1818 local function populate()
19- file:touch()
20- local problems = assert(gql.problems.all())
21- file:write(vim.json.encode(problems), "w")
19+ file:touch()
20+ local problems = assert(gql.problems.all())
21+ file:write(vim.json.encode(problems), "w")
2222 end
2323
2424 ---@return lc.Problem[] | nil
2525 function M.read()
26- async.run(M.update)
26+ async.run(M.update)
2727
28- local contents = file:read()
28+ local contents = file:read()
2929
30- local ok, problems = pcall(M.parse, contents)
31- if not ok then return end
30+ local ok, problems = pcall(M.parse, contents)
31+ if not ok then return end
3232
33- return problems
33+ return problems
3434 end
3535
3636 function M.update()
37- local stats = file:_stat()
37+ local stats = file:_stat()
3838
39- if vim.tbl_isempty(stats) then
40- assert(populate())
41- return
42- end
39+ if vim.tbl_isempty(stats) then
40+ assert(populate())
41+ return
42+ end
4343
44- local mod_time = stats.mtime.sec
45- local curr_time = os.time()
44+ local mod_time = stats.mtime.sec
45+ local curr_time = os.time()
4646
47- if (curr_time - mod_time) > 60 * 60 * 24 * 7 then
48- -- logger.info("Updating cache. This way take a while...")
49- assert(populate())
50- end
47+ if (curr_time - mod_time) > 60 * 60 * 24 * 7 then
48+ -- logger.info("Updating cache. This way take a while...")
49+ assert(populate())
50+ end
5151 end
5252
5353 ---@param problem lc.Problem
5454 ---
5555 ---@return string
5656 M.formatter = function(problem)
57- return string.format(
58- "%d. %s (%d%%, %s)",
59- problem.index,
60- problem.title,
61- problem.ac_rate,
62- problem.difficulty
63- )
57+ return string.format(
58+ "%d. %s (%d%%, %s)",
59+ problem.index,
60+ problem.title,
61+ problem.ac_rate,
62+ problem.difficulty
63+ )
6464 end
6565
6666 ---@param problems_str string
6767 ---
6868 ---@return lc.Problem[]
6969 function M.parse(problems_str)
70- ---@type boolean, lc.Problem[]
71- local ok, problems = pcall(vim.json.decode, problems_str)
72- assert(ok)
70+ ---@type boolean, lc.Problem[]
71+ local ok, problems = pcall(vim.json.decode, problems_str)
72+ assert(ok)
7373
74- return problems
74+ return problems
7575 end
7676
7777 return M
+5-5lua/leetcode/config/init.lua
@@ -2,8 +2,8 @@ local template = require("leetcode.config.template")
22
33 ---@class lc.Settings
44 local Config = {
5- name = "leetcode.nvim",
6- debug = true,
5+ name = "leetcode.nvim",
6+ debug = true,
77 }
88
99 ---Default configurations.
@@ -23,10 +23,10 @@ Config.auth = nil
2323 ---
2424 ---@param cfg lc.Config Configurations to be merged.
2525 function Config.apply(cfg)
26- Config.user = vim.tbl_deep_extend("force", template, cfg)
26+ Config.user = vim.tbl_deep_extend("force", template, cfg)
2727
28- local ok, notify = pcall(require, "notify")
29- if ok then vim.notify = notify end
28+ local ok, notify = pcall(require, "notify")
29+ if ok then vim.notify = notify end
3030 end
3131
3232 ---Merge configurations into default configurations and set it as user configurations.
+16-16lua/leetcode/config/template.lua
@@ -1,26 +1,26 @@
11 ---@class lc.Config
22 local M = {
3- ---@type string
4- domain = "com",
3+ ---@type string
4+ domain = "com",
55
6- ---@type string
7- invoke_name = "leetcode.nvim",
6+ ---@type string
7+ invoke_name = "leetcode.nvim",
88
9- ---@type string
10- lang = "java",
9+ ---@type string
10+ lang = "java",
1111
12- ---@type
13- ---| "pythondata"
14- ---| "mysql"
15- ---| "mssql"
16- ---| "oraclesql"
17- sql = "mysql",
12+ ---@type
13+ ---| "pythondata"
14+ ---| "mysql"
15+ ---| "mssql"
16+ ---| "oraclesql"
17+ sql = "mysql",
1818
19- ---@type string
20- directory = vim.fn.stdpath("data") .. "/leetcode",
19+ ---@type string
20+ directory = vim.fn.stdpath("data") .. "/leetcode",
2121
22- ---@type boolean
23- logging = true,
22+ ---@type boolean
23+ logging = true,
2424 }
2525
2626 return M
+6-6lua/leetcode/graphql/auth.lua
@@ -12,7 +12,7 @@ local M = {}
1212
1313 ---@return lc.UserStatus | nil
1414 function M.user_status()
15- local query = [[
15+ local query = [[
1616 query globalData {
1717 userStatus {
1818 userId
@@ -26,13 +26,13 @@ function M.user_status()
2626 }
2727 ]]
2828
29- local ok, res = pcall(gql.query, query)
30- if not ok then return end
29+ local ok, res = pcall(gql.query, query)
30+ if not ok then return end
3131
32- local status = res["userStatus"]
33- config.authenticate(status)
32+ local status = res["userStatus"]
33+ config.authenticate(status)
3434
35- return res["userStatus"]
35+ return res["userStatus"]
3636 end
3737
3838 return M
+3-3lua/leetcode/graphql/init.lua
@@ -1,8 +1,8 @@
11 ---@class lc.Graphql
22 local Gql = {
3- problems = require("leetcode.graphql.problems"),
4- question = require("leetcode.graphql.question"),
5- auth = require("leetcode.graphql.auth"),
3+ problems = require("leetcode.graphql.problems"),
4+ question = require("leetcode.graphql.question"),
5+ auth = require("leetcode.graphql.auth"),
66 }
77
88 return Gql
+15-15lua/leetcode/graphql/problems.lua
@@ -6,7 +6,7 @@ local M = {}
66
77 ---@return integer
88 function M.total_num()
9- local query = [[
9+ local query = [[
1010 query problemsetQuestionList {
1111 problemsetQuestionList: questionList(
1212 categorySlug: ""
@@ -17,18 +17,18 @@ function M.total_num()
1717 }
1818 ]]
1919
20- local total = gql.query(query)["problemsetQuestionList"]["total"]
20+ local total = gql.query(query)["problemsetQuestionList"]["total"]
2121
22- return total
22+ return total
2323 end
2424
2525 ---@return lc.Problem[]
2626 function M.all()
27- local variables = {
28- limit = 3000,
29- }
27+ local variables = {
28+ limit = 3000,
29+ }
3030
31- local query = [[
31+ local query = [[
3232 query problemsetQuestionList($limit: Int) {
3333 problemsetQuestionList: questionList(
3434 categorySlug: ""
@@ -46,14 +46,14 @@ function M.all()
4646 }
4747 ]]
4848
49- local ok, res = pcall(gql.query, query, variables)
50- assert(ok)
49+ local ok, res = pcall(gql.query, query, variables)
50+ assert(ok)
5151
52- return res["problemsetQuestionList"]["questions"]
52+ return res["problemsetQuestionList"]["questions"]
5353 end
5454
5555 function M.question_of_today()
56- local query = [[
56+ local query = [[
5757 query questionOfToday {
5858 activeDailyCodingChallengeQuestion {
5959 userStatus
@@ -73,12 +73,12 @@ function M.question_of_today()
7373 }
7474 ]]
7575
76- local ok, res = pcall(gql.query, query)
77- assert(ok)
76+ local ok, res = pcall(gql.query, query)
77+ assert(ok)
7878
79- logger.inspect(res)
79+ logger.inspect(res)
8080
81- return res["activeDailyCodingChallengeQuestion"]
81+ return res["activeDailyCodingChallengeQuestion"]
8282 end
8383
8484 return M
+19-19lua/leetcode/graphql/question.lua
@@ -10,11 +10,11 @@ local M = {}
1010 ---
1111 ---@return lc.Question.Content
1212 function M.content(title_slug)
13- local variables = {
14- titleSlug = title_slug,
15- }
13+ local variables = {
14+ titleSlug = title_slug,
15+ }
1616
17- local query = [[
17+ local query = [[
1818 query questionContent($titleSlug: String!) {
1919 question(titleSlug: $titleSlug) {
2020 content
@@ -24,19 +24,19 @@ function M.content(title_slug)
2424 }
2525 ]]
2626
27- local ok, res = pcall(gql.query, query, variables)
28- assert(ok)
27+ local ok, res = pcall(gql.query, query, variables)
28+ assert(ok)
2929
30- return res["question"]
30+ return res["question"]
3131 end
3232
3333 ---@param title_slug string
3434 function M.editor_data(title_slug)
35- local variables = {
36- titleSlug = title_slug,
37- }
35+ local variables = {
36+ titleSlug = title_slug,
37+ }
3838
39- local query = [[
39+ local query = [[
4040 query questionEditorData($titleSlug: String!) {
4141 question(titleSlug: $titleSlug) {
4242 questionId
@@ -54,19 +54,19 @@ function M.editor_data(title_slug)
5454 }
5555 ]]
5656
57- local ok, res = pcall(gql.query, query, variables)
58- assert(ok)
57+ local ok, res = pcall(gql.query, query, variables)
58+ assert(ok)
5959
60- return res["question"]
60+ return res["question"]
6161 end
6262
6363 ---@param title_slug string
6464 function M.title(title_slug)
65- local variables = {
66- titleSlug = title_slug,
67- }
65+ local variables = {
66+ titleSlug = title_slug,
67+ }
6868
69- local query = [[
69+ local query = [[
7070 query questionTitle($titleSlug: String!) {
7171 question(titleSlug: $titleSlug) {
7272 questionId
@@ -82,7 +82,7 @@ function M.title(title_slug)
8282 }
8383 ]]
8484
85- return gql.query(query, variables)["question"]
85+ return gql.query(query, variables)["question"]
8686 end
8787
8888 return M
+10-10lua/leetcode/graphql/utils.lua
@@ -13,18 +13,18 @@ local M = {}
1313 ---
1414 ---@return table
1515 function M.query(query, variables)
16- local response = curl.post(endpoint, {
17- headers = headers.get(),
18- body = vim.json.encode({
19- query = query,
20- variables = variables or {},
21- }),
22- })
16+ local response = curl.post(endpoint, {
17+ headers = headers.get(),
18+ body = vim.json.encode({
19+ query = query,
20+ variables = variables or {},
21+ }),
22+ })
2323
24- local ok, data = pcall(vim.json.decode, response["body"])
25- assert(ok and data and data["data"], "Failed to query data")
24+ local ok, data = pcall(vim.json.decode, response["body"])
25+ assert(ok and data and data["data"], "Failed to query data")
2626
27- return data["data"]
27+ return data["data"]
2828 end
2929
3030 return M
+4-4lua/leetcode/logger/init.lua
@@ -7,8 +7,8 @@ local Logger = {}
77 ---@param msg string
88 ---@param lvl? integer
99 Logger.log = function(msg, lvl)
10- if not config.user.logging then return end
11- vim.notify(msg, lvl or levels.INFO, { title = config.name })
10+ if not config.user.logging then return end
11+ vim.notify(msg, lvl or levels.INFO, { title = config.name })
1212 end
1313
1414 ---@param msg string
@@ -25,8 +25,8 @@ Logger.error = function(msg) Logger.log(msg, levels.ERROR) end
2525
2626 ---@param msg string
2727 Logger.debug = function(msg)
28- if not config.debug then return end
29- Logger.log(msg, levels.DEBUG)
28+ if not config.debug then return end
29+ Logger.log(msg, levels.DEBUG)
3030 end
3131
3232 return Logger
+1-1lua/leetcode/ui/components/init.lua
@@ -1,6 +1,6 @@
11 ---@class lc.Ui.Components
22 local Components = {
3- problem = require("leetcode.ui.components.problem"),
3+ problem = require("leetcode.ui.components.problem"),
44 }
55
66 return Components
+54-52lua/leetcode/ui/components/problem.lua
@@ -11,89 +11,91 @@ local M = {}
1111
1212 ---@param title any
1313 function M.title(title)
14- local line = Line()
14+ local line = Line()
1515
16- line:append(title.questionFrontendId .. ". " .. title.title)
16+ line:append(title.questionFrontendId .. ". " .. title.title)
1717
18- return line
18+ return line
1919 end
2020
2121 ---@param title_slug string
2222 function M.link(title_slug)
23- local line = Line()
23+ local line = Line()
2424
25- line:append("https://leetcode.com/problems/" .. title_slug .. "/", "Comment")
26- line:append("")
25+ line:append("https://leetcode.com/problems/" .. title_slug .. "/", "Comment")
26+ line:append("")
2727
28- return line
28+ return line
2929 end
3030
3131 ---@param title any
3232 function M.stats(title)
33- local line = Line()
34-
35- line:append(
36- title.difficulty,
37- title.difficulty == "Easy" and "DiagnosticOk"
38- or title.difficulty == "Medium" and "DiagnosticWarn"
39- or "DiagnosticError"
40- )
41- line:append(" | ")
42- line:append(title.likes .. "  ", "Comment")
43- line:append(title.dislikes .. "  ", "Comment")
44-
45- return line
33+ local line = Line()
34+
35+ line:append(
36+ title.difficulty,
37+ title.difficulty == "Easy" and "DiagnosticOk"
38+ or title.difficulty == "Medium" and "DiagnosticWarn"
39+ or "DiagnosticError"
40+ )
41+ line:append(" | ")
42+ line:append(title.likes .. "  ", "Comment")
43+ line:append(title.dislikes .. "  ", "Comment")
44+
45+ return line
4646 end
4747
4848 ---@param content any
4949 function M.content(content)
50- local line = Line()
50+ local line = Line()
5151
52- local s = vim.split(content.content, "\n\n<p>&nbsp;</p>\n", { trimempty = true })
52+ local s = vim.split(content.content, "\n\n", { trimempty = true })
5353
54- local desc = M.description(s[1])
55- local exam = M.examples(s[2])
56- local cons = M.constrains(s[3])
57- local foll = M.follow_up(s[4])
54+ for _, v in ipairs(s) do
55+ log.info(v)
56+ end
57+
58+ -- local desc = M.description(s[1])
59+ -- line:append(desc)
60+
61+ -- local exam = M.examples(s[2])
62+ -- local cons = M.constrains(s[3])
63+ -- local foll = M.follow_up(s[4])
5864
59- line:append({ desc, exam, cons, foll })
65+ -- line:append({ desc, exam, cons, foll })
6066
61- return line
67+ return line
6268 end
6369
6470 ---@param p string
6571 local parse_paragraph = function(p)
66- -- for s in vim.gsplit(p, " ", { trimempty = true }) do
67- -- log.info(s)
68- -- end
69-
70- local ts = vim.treesitter
71- local parser = ts.get_string_parser(p, "html")
72-
73- local tree = parser:parse()[1]
74- local function get_text(node)
75- local text = {}
76- for _, child in ipairs(node) do
77- if child:type() == "text" then
78- table.insert(text, child:subtree_text())
79- elseif child:named() then
80- table.insert(text, get_text(child))
81- end
72+ local ts = vim.treesitter
73+ local parser = ts.get_string_parser(p, "html")
74+ local tree = parser:parse()[1]
75+
76+ local t = {}
77+ local function get_text(node, text)
78+ for child in node:iter_children() do
79+ if child:type() == "text" then
80+ local txt = ts.get_node_text(child, p)
81+ table.insert(text, txt)
82+ elseif child:named() then
83+ get_text(child, text)
84+ end
85+ end
8286 end
83- return table.concat(text)
84- end
85- local text = get_text(tree:root())
87+ get_text(tree:root(), t)
8688
87- log.info(text)
89+ return table.concat(t, " ")
8890 end
8991
9092 ---@param description string
9193 function M.description(description)
92- local lines = { "Description:" }
94+ local lines = { "Description:" }
9395
94- for v in vim.gsplit(description, "\n\n", { trimempty = true }) do
95- parse_paragraph(utils.strip_html_tag(v, "p"))
96- end
96+ -- for v in vim.gsplit(description, "\n\n", { trimempty = true }) do
97+ return parse_paragraph(description)
98+ -- end
9799 end
98100
99101 ---@param examples string
+106-106lua/leetcode/ui/dashboard.lua
@@ -6,130 +6,130 @@ local log = require("leetcode.logger")
66 local M = {}
77
88 local header = {
9- type = "text",
10- val = {
11- [[ /$$ /$$ /$$$$$$ /$$ ]],
12- [[| $$ | $$ /$$__ $$ | $$ ]],
13- [[| $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ ]],
14- [[| $$ /$$__ $$/$$__ $|_ $$_/ | $$ /$$__ $$/$$__ $$/$$__ $$]],
15- [[| $$ | $$$$$$$| $$$$$$$$ | $$ | $$ | $$ \ $| $$ | $| $$$$$$$$]],
16- [[| $$ | $$_____| $$_____/ | $$ /$| $$ $| $$ | $| $$ | $| $$_____/]],
17- [[| $$$$$$$| $$$$$$| $$$$$$$ | $$$$| $$$$$$| $$$$$$| $$$$$$| $$$$$$$]],
18- [[|________/\_______/\_______/ \___/ \______/ \______/ \_______/\_______/]],
19- },
20- opts = {
21- position = "center",
22- hl = "Keyword",
23- },
9+ type = "text",
10+ val = {
11+ [[ /$$ /$$ /$$$$$$ /$$ ]],
12+ [[| $$ | $$ /$$__ $$ | $$ ]],
13+ [[| $$ /$$$$$$ /$$$$$$ /$$$$$$ | $$ \__/ /$$$$$$ /$$$$$$$ /$$$$$$ ]],
14+ [[| $$ /$$__ $$/$$__ $|_ $$_/ | $$ /$$__ $$/$$__ $$/$$__ $$]],
15+ [[| $$ | $$$$$$$| $$$$$$$$ | $$ | $$ | $$ \ $| $$ | $| $$$$$$$$]],
16+ [[| $$ | $$_____| $$_____/ | $$ /$| $$ $| $$ | $| $$ | $| $$_____/]],
17+ [[| $$$$$$$| $$$$$$| $$$$$$$ | $$$$| $$$$$$| $$$$$$| $$$$$$| $$$$$$$]],
18+ [[|________/\_______/\_______/ \___/ \______/ \______/ \_______/\_______/]],
19+ },
20+ opts = {
21+ position = "center",
22+ hl = "Keyword",
23+ },
2424 }
2525
2626 local notifications = {
27- type = "text",
28- val = {},
29- opts = {
30- position = "center",
31- hl = "DiagnosticInfo",
32- },
27+ type = "text",
28+ val = {},
29+ opts = {
30+ position = "center",
31+ hl = "DiagnosticInfo",
32+ },
3333 }
3434
3535 local buttons = {
36- type = "group",
37- val = {},
38- opts = {
39- spacing = 1,
40- },
36+ type = "group",
37+ val = {},
38+ opts = {
39+ spacing = 1,
40+ },
4141 }
4242
4343 local footer = {
44- type = "text",
45- val = {},
46- opts = {
47- position = "center",
48- hl = "Number",
49- },
44+ type = "text",
45+ val = {},
46+ opts = {
47+ position = "center",
48+ hl = "Number",
49+ },
5050 }
5151
5252 function M.setup()
53- local auth = config.auth
54- local is_signed_in = auth and auth.is_signed_in
55-
56- local alpha = require("alpha")
57- local dashboard = require("alpha.themes.dashboard")
58-
59- notifications.val = not is_signed_in and { " Sign in to use LeetCode.nvim" } or {}
60-
61- buttons.val = is_signed_in
62- and {
63- dashboard.button(
64- "p",
65- " " .. " All Problems",
66- "<cmd>lua require('leetcode.api').cmd.lc_problems()<CR>"
67- ),
68- dashboard.button(
69- "t",
70- "󰃭 " .. " Question of today",
71- "<cmd>lua require('leetcode.api').gql.problems.question_of_today()<CR>"
72- ),
73- dashboard.button("r", " " .. " Recent problems", ""),
74- dashboard.button(
75- "c",
76- "󰆘 " .. " Update cookie",
77- "<cmd>lua require('leetcode.api').cmd.cookie_prompt()<cr>"
78- ),
79- dashboard.button(
80- "s",
81- " " .. " Sign out",
82- "<cmd>lua require('leetcode.utils').remove_cookie()<cr>"
83- ),
84- dashboard.button("q", "󰩈 " .. " Exit LeetCode", "<cmd>qa<CR>"),
85- }
86- or {
87- dashboard.button(
88- "s",
89- " " .. " Sign in (By Cookie)",
90- "<cmd>lua require('leetcode.api').cmd.cookie_prompt()<cr>"
91- ),
92- dashboard.button("q", "󰩈 " .. " Exit LeetCode", "<cmd>qa!<CR>"),
53+ local auth = config.auth
54+ local is_signed_in = auth and auth.is_signed_in
55+
56+ local alpha = require("alpha")
57+ local dashboard = require("alpha.themes.dashboard")
58+
59+ notifications.val = not is_signed_in and { " Sign in to use LeetCode.nvim" } or {}
60+
61+ buttons.val = is_signed_in
62+ and {
63+ dashboard.button(
64+ "p",
65+ " " .. " All Problems",
66+ "<cmd>lua require('leetcode.api').cmd.lc_problems()<CR>"
67+ ),
68+ dashboard.button(
69+ "t",
70+ "󰃭 " .. " Question of today",
71+ "<cmd>lua require('leetcode.api').gql.problems.question_of_today()<CR>"
72+ ),
73+ dashboard.button("r", " " .. " Recent problems", ""),
74+ dashboard.button(
75+ "c",
76+ "󰆘 " .. " Update cookie",
77+ "<cmd>lua require('leetcode.api').cmd.cookie_prompt()<cr>"
78+ ),
79+ dashboard.button(
80+ "s",
81+ " " .. " Sign out",
82+ "<cmd>lua require('leetcode.utils').remove_cookie()<cr>"
83+ ),
84+ dashboard.button("q", "󰩈 " .. " Exit LeetCode", "<cmd>qa<CR>"),
85+ }
86+ or {
87+ dashboard.button(
88+ "s",
89+ " " .. " Sign in (By Cookie)",
90+ "<cmd>lua require('leetcode.api').cmd.cookie_prompt()<cr>"
91+ ),
92+ dashboard.button("q", "󰩈 " .. " Exit LeetCode", "<cmd>qa!<CR>"),
93+ }
94+
95+ footer.val = is_signed_in and "Signed in as: " .. auth.username or ""
96+
97+ local section = {
98+ header = header,
99+ notifications = notifications,
100+ buttons = buttons,
101+ footer = footer,
93102 }
94103
95- footer.val = is_signed_in and "Signed in as: " .. auth.username or ""
96-
97- local section = {
98- header = header,
99- notifications = notifications,
100- buttons = buttons,
101- footer = footer,
102- }
103-
104- local cfg = {
105- layout = {
106- -- header
107- { type = "padding", val = 2 },
108- section.header,
109-
110- -- notifications
111- { type = "padding", val = 2 },
112- section.notifications,
113- { type = "padding", val = 2 },
114-
115- -- buttons
116- section.buttons,
117-
118- --footer
119- section.footer,
120- },
121- opts = {
122- margin = 5,
123- },
124- }
104+ local cfg = {
105+ layout = {
106+ -- header
107+ { type = "padding", val = 2 },
108+ section.header,
109+
110+ -- notifications
111+ { type = "padding", val = 2 },
112+ section.notifications,
113+ { type = "padding", val = 2 },
114+
115+ -- buttons
116+ section.buttons,
117+
118+ --footer
119+ section.footer,
120+ },
121+ opts = {
122+ margin = 5,
123+ },
124+ }
125125
126- alpha.setup(cfg)
126+ alpha.setup(cfg)
127127 end
128128
129129 function M.update()
130- utils.alpha_move_cursor_top()
131- M.setup()
132- pcall(vim.cmd, "AlphaRedraw")
130+ utils.alpha_move_cursor_top()
131+ M.setup()
132+ pcall(vim.cmd, "AlphaRedraw")
133133 end
134134
135135 return M
+36-36lua/leetcode/ui/init.lua
@@ -10,59 +10,59 @@ local Ui = {}
1010 ---@param fn? fun(table)
1111 ---@param callback fun(table)
1212 function Ui.pick_one(items, prompt, fn, callback)
13- vim.ui.select(items, {
14- prompt = prompt or "",
15- format_item = fn or function(item) return item end,
16- telescope = require("telescope.themes").get_dropdown(),
17- }, callback)
13+ vim.ui.select(items, {
14+ prompt = prompt or "",
15+ format_item = fn or function(item) return item end,
16+ telescope = require("telescope.themes").get_dropdown(),
17+ }, callback)
1818 end
1919
2020 function Ui.input(opts, callback) vim.ui.input(opts, callback) end
2121
2222 ---@param problem lc.Problem
2323 function Ui.create_leetcode_win(problem)
24- local start_win = vim.api.nvim_get_current_win()
24+ local start_win = vim.api.nvim_get_current_win()
2525
26- local Split = require("nui.split")
27- local split = Split({
28- relative = "win",
29- position = "left",
30- size = "30%",
31- })
32- split:mount()
26+ local Split = require("nui.split")
27+ local split = Split({
28+ relative = "win",
29+ position = "left",
30+ size = "30%",
31+ })
32+ split:mount()
3333
34- local title = gql.question.title(problem.title_slug)
35- local content = gql.question.content(problem.title_slug)
34+ local title = gql.question.title(problem.title_slug)
35+ local content = gql.question.content(problem.title_slug)
3636
37- local win = vim.api.nvim_get_current_win() -- We save our navigation window handle...
38- local buf = vim.api.nvim_get_current_buf() -- ...and it's buffer handle.
37+ local win = vim.api.nvim_get_current_win() -- We save our navigation window handle...
38+ local buf = vim.api.nvim_get_current_buf() -- ...and it's buffer handle.
3939
40- vim.api.nvim_buf_set_name(buf, "LeetCode")
40+ vim.api.nvim_buf_set_name(buf, "LeetCode")
4141
42- vim.api.nvim_buf_set_option(buf, "filetype", "leetcode.nvim")
43- vim.api.nvim_buf_set_option(buf, "swapfile", false)
44- vim.api.nvim_buf_set_option(buf, "buftype", "nofile")
45- vim.api.nvim_buf_set_option(buf, "buflisted", false)
46- -- vim.api.nvim_buf_set_option(buf, "modifiable", true)
42+ vim.api.nvim_buf_set_option(buf, "filetype", "leetcode.nvim")
43+ vim.api.nvim_buf_set_option(buf, "swapfile", false)
44+ vim.api.nvim_buf_set_option(buf, "buftype", "nofile")
45+ vim.api.nvim_buf_set_option(buf, "buflisted", false)
46+ -- vim.api.nvim_buf_set_option(buf, "modifiable", true)
4747
48- vim.api.nvim_win_set_option(win, "wrap", true)
49- vim.api.nvim_win_set_option(win, "number", false)
50- vim.api.nvim_win_set_option(win, "signcolumn", "no")
48+ vim.api.nvim_win_set_option(win, "wrap", true)
49+ vim.api.nvim_win_set_option(win, "number", false)
50+ vim.api.nvim_win_set_option(win, "signcolumn", "no")
5151
52- vim.api.nvim_buf_set_keymap(buf, "n", "<esc>", "<cmd>hide<CR>", { noremap = true })
53- vim.api.nvim_buf_set_keymap(buf, "n", "q", "<cmd>hide<CR>", { noremap = true })
52+ vim.api.nvim_buf_set_keymap(buf, "n", "<esc>", "<cmd>hide<CR>", { noremap = true })
53+ vim.api.nvim_buf_set_keymap(buf, "n", "q", "<cmd>hide<CR>", { noremap = true })
5454
55- local line = require("nui.line")()
56- line:append("")
55+ local line = require("nui.line")()
56+ line:append("")
5757
58- components.problem.link(problem.title_slug):render(buf, -1, 1)
59- line:render(buf, -1, 2)
58+ components.problem.link(problem.title_slug):render(buf, -1, 1)
59+ line:render(buf, -1, 2)
6060
61- components.problem.title(title):render(buf, -1, 3)
62- components.problem.stats(title):render(buf, -1, 4)
63- line:render(buf, -1, 5)
61+ components.problem.title(title):render(buf, -1, 3)
62+ components.problem.stats(title):render(buf, -1, 4)
63+ line:render(buf, -1, 5)
6464
65- components.problem.content(content):render(buf, -1, 6)
65+ components.problem.content(content):render(buf, -1, 6)
6666 end
6767
6868 return Ui
+9-9lua/leetcode/utils.lua
@@ -2,14 +2,14 @@
22 local Utils = {}
33
44 function Utils.remove_cookie()
5- require("leetcode.cache.cookie").delete()
6- require("leetcode.ui.dashboard").update()
5+ require("leetcode.cache.cookie").delete()
6+ require("leetcode.ui.dashboard").update()
77 end
88
99 function Utils.alpha_move_cursor_top()
10- local curr_win = vim.api.nvim_get_current_win()
11- vim.api.nvim_win_set_cursor(curr_win, { 1, 0 })
12- require("alpha").move_cursor(curr_win)
10+ local curr_win = vim.api.nvim_get_current_win()
11+ vim.api.nvim_win_set_cursor(curr_win, { 1, 0 })
12+ require("alpha").move_cursor(curr_win)
1313 end
1414
1515 ---Extracts an HTML tag from a string.
@@ -23,11 +23,11 @@ function Utils.get_html_tag(str) return str:match("^<(.-)>") end
2323 ---
2424 ---@return string
2525 function Utils.strip_html_tag(str, tag)
26- local regex = string.format("^<%s>(.*)</%s>$", tag, tag)
27- assert(str:match(regex))
26+ local regex = string.format("^<%s>(.*)</%s>$", tag, tag)
27+ assert(str:match(regex))
2828
29- local offset = 3 + tag:len()
30- return str:sub(offset, str:len() - offset)
29+ local offset = 3 + tag:len()
30+ return str:sub(offset, str:len() - offset)
3131 end
3232
3333 return Utils