Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cmd): Leet recent #73

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
feat(cmd): Leet recent
  • Loading branch information
kawre committed Mar 9, 2024
commit cb63d9a369c9f7e850864171fed39ceeafa8fea9
7 changes: 7 additions & 0 deletions lua/leetcode-ui/group/page/problems.lua
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ local list = Button("List", {
on_press = cmd.problems,
})

local recent = Button("Recent", {
icon = "",
sc = "i",
on_press = cmd.recent,
})

local random = Button("Random", {
icon = "",
sc = "r",
Expand All @@ -37,6 +43,7 @@ local back = BackButton("menu")

page:insert(Buttons({
list,
recent,
random,
daily,
back,
Expand Down
3 changes: 3 additions & 0 deletions lua/leetcode-ui/popup/console/result.lua
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ function ResultPopup:handle(item)
end
end

local Recent = require("leetcode.cache.recent")
Recent.add(self.console.question.q.title_slug)

self:draw()
end

Expand Down
9 changes: 9 additions & 0 deletions lua/leetcode/cache/problemlist.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ function Problemlist.get()
return Problemlist.read().data
end

---@return table<string, lc.cache.Question>
function Problemlist.get_map()
local map = {}
for _, q in ipairs(Problemlist.get()) do
map[q.title_slug] = q
end
return map
end

---@return lc.cache.payload
function Problemlist.read()
if not file:exists() then
Expand Down
91 changes: 91 additions & 0 deletions lua/leetcode/cache/recent.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
local Object = require("nui.object")
local config = require("leetcode.config")
local log = require("leetcode.logger")

---@alias lc.recent table<string, integer>

---@type Path
local file = config.storage.cache:joinpath(("recent%s"):format(config.is_cn and "_cn" or ""))

---@class lc.Recent
local Recent = Object("LeetRecent")

function Recent.populate()
Recent.write({})
end

---@param recent lc.recent|string
function Recent.write(recent)
file:write("return " .. vim.inspect(recent), "w")
end

---@return lc.recent
function Recent.get()
if not file:exists() then
Recent.populate()
end

local content = file:read()
local chunk = load(content)
return chunk()
end

---@return { slug: string, time: integer }[]
function Recent.sorted()
local recent = Recent.get()

local sorted = {}
for slug, time in pairs(recent) do
table.insert(sorted, { slug = slug, time = time })
end

table.sort(sorted, function(a, b)
return a.time > b.time
end)

return sorted
end

function Recent.convert()
local map = require("leetcode.cache.problemlist").get_map()
local sorted = Recent.sorted()

local recent = {}
for _, item in ipairs(sorted) do
if map[item.slug] then
table.insert(recent, map[item.slug])
end
end
return recent
end

---@param slug string
---@param recent? lc.recent
function Recent.contains(slug, recent)
if not recent then
recent = Recent.get()
end

return recent[slug] == true
end

function Recent.add(slug)
local recent = Recent.get()

recent[slug] = os.time()
Recent.write(recent)

return true
end

function Recent.remove(slug)
local recent = Recent.get()

local tmp = recent[slug]
recent[slug] = nil

Recent.write(recent)
return tmp
end

return Recent
8 changes: 8 additions & 0 deletions lua/leetcode/command/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ function cmd.problems(options)
require("leetcode.pickers.question").pick(p, options)
end

function cmd.recent()
require("leetcode.utils").auth_guard()

-- local p = require("leetcode.cache.problemlist").get()
require("leetcode.pickers.recent").pick()
end

---@param cb? function
function cmd.cookie_prompt(cb)
local cookie = require("leetcode.cache.cookie")
Expand Down Expand Up @@ -631,6 +638,7 @@ cmd.commands = {
},
update = { cmd.update_sessions },
},
recent = { cmd.recent },
list = {
cmd.problems,
_args = arguments.list,
Expand Down
124 changes: 124 additions & 0 deletions lua/leetcode/pickers/recent.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
local log = require("leetcode.logger")
local t = require("leetcode.translator")
local utils = require("leetcode.utils")
local ui_utils = require("leetcode-ui.utils")

local Question = require("leetcode-ui.question")

local pickers = require("telescope.pickers")
local finders = require("telescope.finders")
local conf = require("telescope.config").values
local config = require("leetcode.config")

local entry_display = require("telescope.pickers.entry_display")
local actions = require("telescope.actions")
local action_state = require("telescope.actions.state")

---@param question lc.cache.Question
---
---@return string
local function question_formatter(question)
return ("%s. %s %s %s"):format(
tostring(question.frontend_id),
question.title,
question.title_cn,
question.title_slug
)
end

---@param question lc.cache.Question
local function display_difficulty(question)
local hl = ui_utils.diff_to_hl(question.difficulty)
return { config.icons.square, hl }
end

---@param question lc.cache.Question
local function display_user_status(question)
if question.paid_only then
return config.auth.is_premium and config.icons.hl.unlock or config.icons.hl.lock
end

if question.status == vim.NIL then
return { "" }
end
return config.icons.hl.status[question.status] or { "" }
end

---@param question lc.cache.Question
local function display_question(question)
local index = { question.frontend_id .. ".", "leetcode_normal" }
local title = { utils.translate(question.title, question.title_cn) }
return unpack({ index, title })
end

local displayer = entry_display.create({
separator = " ",
items = {
{ width = 1 },
{ width = 1 },
{ width = 5 },
{ remaining = true },
},
})

local function make_display(entry)
---@type lc.cache.Question
local q = entry.value

return displayer({
display_user_status(q),
display_difficulty(q),
display_question(q),
})
end

local function entry_maker(entry)
return {
value = entry,
display = make_display,
ordinal = question_formatter(entry),
}
end

local theme = require("telescope.themes").get_dropdown({
layout_config = {
width = 100,
height = 20,
},
})

return {
pick = function()
local Recent = require("leetcode.cache.recent")
local questions = Recent.convert()

pickers
.new(theme, {
prompt_title = t("Recent Questions"),
finder = finders.new_table({
results = questions,
entry_maker = entry_maker,
}),
sorter = conf.generic_sorter(theme),
attach_mappings = function(prompt_bufnr, map)
actions.select_default:replace(function()
local selection = action_state.get_selected_entry()
if not selection then
return
end

local q = selection.value
if q.paid_only and not config.auth.is_premium then
return log.warn("Question is for premium users only")
end

actions.close(prompt_bufnr)
Question(q):mount()
end)

return true
end,
})
:find()
end,
}