Skip to content

Commit b13daa7

Browse files
committed
feat: better mount and reset lines on random and daily
1 parent 55d4313 commit b13daa7

File tree

5 files changed

+138
-96
lines changed

5 files changed

+138
-96
lines changed

lua/leetcode-ui/lines/button/menu/exit.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function MenuExitButton:init()
88
MenuExitButton.super.init(self, "Exit", {
99
icon = "󰩈",
1010
sc = "q",
11-
on_press = vim.cmd.quitall,
11+
on_press = function() vim.cmd("qa!") end,
1212
})
1313
end
1414

lua/leetcode-ui/question.lua

Lines changed: 121 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,11 @@ local log = require("leetcode.logger")
1616
---@field console lc.ui.Console
1717
---@field lang string
1818
---@field cache lc.cache.Question
19+
---@field reset boolean
1920
local Question = Object("LeetQuestion")
2021

2122
---@param raw? boolean
22-
function Question:get_snippet(raw)
23+
function Question:snippet(raw)
2324
local snippets = self.q.code_snippets ~= vim.NIL and self.q.code_snippets or {}
2425
local snip = vim.tbl_filter(function(snip) return snip.lang_slug == self.lang end, snippets)[1]
2526
if not snip then return end
@@ -28,7 +29,30 @@ function Question:get_snippet(raw)
2829
return raw and code or self:injector(code)
2930
end
3031

31-
function Question:create_file()
32+
---@param code? string
33+
function Question:set_lines(code)
34+
if not vim.api.nvim_buf_is_valid(self.bufnr) then return end
35+
36+
pcall(vim.cmd.undojoin)
37+
local s_i, e_i = self:range()
38+
code = code and code or (self:snippet(true) or "")
39+
vim.api.nvim_buf_set_lines(self.bufnr, s_i - 1, e_i, false, vim.split(code, "\n"))
40+
end
41+
42+
function Question:reset_lines()
43+
if not self.reset then return end
44+
45+
local new_lines = self:snippet(true) or ""
46+
47+
vim.schedule(function() --
48+
log.info("Previous code found, resetting…\nTo undo, simply press `u`")
49+
end)
50+
51+
self:set_lines(new_lines)
52+
end
53+
54+
---@return string path, boolean? existed
55+
function Question:path()
3256
local lang = utils.get_lang(self.lang)
3357
local alt = lang.alt and ("." .. lang.alt) or ""
3458

@@ -38,47 +62,39 @@ function Question:create_file()
3862
self.file = config.storage.home:joinpath(fn_legacy)
3963

4064
if self.file:exists() then --
41-
return self.file:absolute()
65+
return self.file:absolute(), true
4266
end
4367

4468
local fn = ("%s.%s%s.%s"):format(self.q.frontend_id, self.q.title_slug, alt, lang.ft)
4569
self.file = config.storage.home:joinpath(fn)
70+
local existed = true
4671

4772
if not self.file:exists() then --
48-
self.file:write(self:get_snippet(), "w")
73+
self.file:write(self:snippet(), "w")
74+
existed = false
4975
end
5076

51-
return self.file:absolute()
77+
return self.file:absolute(), existed
5278
end
5379

54-
---@param new_tabp? boolean
55-
---@return boolean was_loaded
56-
function Question:create_buffer(new_tabp)
57-
local file_name = self:create_file()
80+
function Question:create_buffer()
81+
local path, existed = self:path()
5882

59-
local buf = vim.fn.bufadd(file_name)
60-
assert(buf ~= 0, "Failed to create buffer")
83+
vim.cmd("$tabe " .. path)
6184

62-
self.bufnr = buf
63-
if vim.fn.bufloaded(self.bufnr) == 1 then
64-
return true
65-
else
66-
vim.fn.bufload(self.bufnr)
67-
end
85+
self.bufnr = vim.api.nvim_get_current_buf()
86+
self.winid = vim.api.nvim_get_current_win()
6887

69-
local cmd
70-
if new_tabp then
71-
cmd = ("$tabe %s"):format(file_name)
72-
else
73-
cmd = ("edit %s"):format(file_name)
74-
end
88+
vim.api.nvim_set_option_value("buflisted", true, { buf = self.bufnr })
7589

7690
local i = self:fold_range()
77-
if i then cmd = cmd .. (" | %d,%dfold"):format(1, i) end
78-
79-
vim.api.nvim_exec2(cmd, {})
91+
if i then --
92+
pcall(vim.cmd, ("%d,%dfold"):format(1, i))
93+
end
8094

81-
return false
95+
if existed then --
96+
self:reset_lines()
97+
end
8298
end
8399

84100
---@param before boolean
@@ -99,7 +115,7 @@ function Question:inject(before)
99115
end
100116

101117
if res and res ~= "" then
102-
return before and (res .. "\n\n") or ("\n\n" .. res)
118+
return before and (res .. "\n") or ("\n" .. res)
103119
else
104120
return nil
105121
end
@@ -109,50 +125,62 @@ end
109125
function Question:injector(code)
110126
local lang = utils.get_lang(self.lang)
111127

112-
local inj_before = self:inject(true) or ""
113-
local inj_after = self:inject(false) or ""
128+
local parts = {
129+
("%s @leet start"):format(lang.comment),
130+
code,
131+
("%s @leet end"):format(lang.comment),
132+
}
114133

115-
return inj_before --
116-
.. ("%s @leet start\n"):format(lang.comment)
117-
.. code
118-
.. ("\n%s @leet end"):format(lang.comment)
119-
.. inj_after
120-
end
134+
local before = self:inject(true)
135+
if before then table.insert(parts, 1, before) end
121136

122-
---@param pre? boolean
123-
function Question:_unmount(pre)
124-
self.info:unmount()
125-
self.console:unmount()
126-
self.description:unmount()
137+
local after = self:inject(false)
138+
if after then table.insert(parts, after) end
127139

128-
if not pre and vim.api.nvim_buf_is_valid(self.bufnr) then
129-
vim.api.nvim_buf_delete(self.bufnr, { force = true })
130-
end
140+
return table.concat(parts, "\n")
141+
end
131142

132-
if vim.api.nvim_win_is_valid(self.winid) then --
133-
vim.api.nvim_win_close(self.winid, true)
143+
function Question:unmount()
144+
if vim.v.dying ~= 0 then --
145+
return
134146
end
135147

136-
_Lc_questions = vim.tbl_filter(function(q) return q.bufnr ~= self.bufnr end, _Lc_questions)
148+
vim.schedule(function()
149+
self.info:unmount()
150+
self.console:unmount()
151+
self.description:unmount()
152+
153+
if vim.api.nvim_buf_is_valid(self.bufnr) then
154+
vim.api.nvim_buf_delete(self.bufnr, { force = true, unload = false })
155+
end
156+
157+
_Lc_questions = vim.tbl_filter(function(q) --
158+
return q.bufnr ~= self.bufnr
159+
end, _Lc_questions)
137160

138-
self = nil
161+
self = nil
162+
end)
139163
end
140164

141-
---@param self lc.ui.Question
142-
---@param pre? boolean
143-
Question.unmount = vim.schedule_wrap(function(self, pre) self:_unmount(pre) end)
165+
function Question:_unmount()
166+
if vim.api.nvim_win_is_valid(self.winid) then vim.api.nvim_win_close(self.winid, true) end
167+
end
144168

145-
function Question:handle_mount()
146-
self:create_buffer(true)
169+
local group = vim.api.nvim_create_augroup("leetcode_questions", { clear = true })
170+
function Question:autocmds()
171+
vim.api.nvim_create_autocmd("WinClosed", {
172+
group = group,
173+
buffer = self.bufnr,
174+
callback = function() self:unmount() end,
175+
})
176+
end
147177

148-
self.winid = vim.api.nvim_get_current_win()
178+
function Question:handle_mount()
179+
self:create_buffer()
149180

150181
table.insert(_Lc_questions, self)
151182

152-
vim.api.nvim_create_autocmd("QuitPre", {
153-
buffer = self.bufnr,
154-
callback = function() self:unmount(true) end,
155-
})
183+
self:autocmds()
156184

157185
self.description = Description(self):mount()
158186
self.console = Console(self)
@@ -173,7 +201,7 @@ function Question:mount()
173201
end
174202
self.q = q
175203

176-
if self:get_snippet() then
204+
if self:snippet() then
177205
self:handle_mount()
178206
else
179207
local msg = ("Snippet for `%s` not found. Select a different language"):format(self.lang)
@@ -232,37 +260,55 @@ end
232260
---@param self lc.ui.Question
233261
---@param lang lc.lang
234262
Question.change_lang = vim.schedule_wrap(function(self, lang)
235-
if vim.api.nvim_get_current_win() ~= self.winid then
236-
vim.api.nvim_set_current_win(self.winid)
237-
end
238-
239263
local old_lang, old_bufnr = self.lang, self.bufnr
240-
self.lang = lang
241264

242-
local ok, was_loaded = pcall(Question.create_buffer, self)
243-
if ok then
244-
vim.api.nvim_buf_set_option(old_bufnr, "buflisted", false)
245-
vim.api.nvim_buf_set_option(self.bufnr, "buflisted", true)
265+
local ok, err = pcall(function()
266+
self.lang = lang
267+
local path, existed = self:path()
268+
269+
self.bufnr = vim.fn.bufadd(path)
270+
assert(self.bufnr ~= 0, "Failed to create buffer " .. path)
246271

247-
if was_loaded then
248-
vim.api.nvim_win_set_buf(self.winid, self.bufnr)
249-
else
272+
local loaded = vim.api.nvim_buf_is_loaded(self.bufnr)
273+
vim.fn.bufload(self.bufnr)
274+
275+
vim.api.nvim_win_set_buf(self.winid, self.bufnr)
276+
277+
vim.api.nvim_set_option_value("buflisted", false, { buf = old_bufnr })
278+
vim.api.nvim_set_option_value("buflisted", true, { buf = self.bufnr })
279+
280+
local i = self:fold_range()
281+
if i then --
282+
pcall(vim.cmd, ("%d,%dfold"):format(1, i))
283+
end
284+
285+
if existed then --
286+
self:reset_lines()
287+
end
288+
289+
if not loaded then --
250290
utils.exec_hook("question_enter", self)
251291
end
252-
else
253-
log.error("Changing language failed")
292+
293+
self:autocmds()
294+
end)
295+
296+
if not ok then
297+
log.error("Failed to change language\n" .. err)
254298
self.lang = old_lang
255299
self.bufnr = old_bufnr
256300
end
257301
end)
258302

259303
---@param problem lc.cache.Question
260-
function Question:init(problem)
304+
---@param reset boolean
305+
function Question:init(problem, reset)
261306
self.cache = problem
262307
self.lang = config.lang
308+
self.reset = reset and true or false
263309
end
264310

265-
---@type fun(question: lc.cache.Question): lc.ui.Question
311+
---@type fun(question: lc.cache.Question, reset?: boolean): lc.ui.Question
266312
local LeetQuestion = Question
267313

268314
return LeetQuestion

lua/leetcode/command/init.lua

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ function cmd.delete_cookie()
9090
cookie.delete()
9191
end
9292

93-
cmd.q_close_all = vim.schedule_wrap(function()
93+
cmd.q_close_all = function()
9494
local utils = require("leetcode.utils")
9595
local qs = utils.question_tabs()
9696

9797
for _, tabp in ipairs(qs) do
98-
tabp.question:unmount()
98+
tabp.question:_unmount()
9999
end
100-
end)
100+
end
101101

102102
cmd.expire = vim.schedule_wrap(function()
103103
local tabp = api.nvim_get_current_tabpage()
@@ -127,7 +127,7 @@ function cmd.qot()
127127
problems.question_of_today(function(qot, err)
128128
if err then return log.err(err) end
129129
local problemlist = require("leetcode.cache.problemlist")
130-
Question(problemlist.get_by_title_slug(qot.title_slug)):mount()
130+
Question(problemlist.get_by_title_slug(qot.title_slug), true):mount()
131131
end)
132132
end
133133

@@ -151,7 +151,7 @@ function cmd.random_question(opts)
151151

152152
local item = problems.get_by_title_slug(q.title_slug) or {}
153153
local Question = require("leetcode-ui.question")
154-
Question(item):mount()
154+
Question(item, true):mount()
155155
end
156156

157157
function cmd.start_with_cmd()
@@ -281,8 +281,7 @@ function cmd.reset()
281281
local q = utils.curr_question()
282282
if not q then return end
283283

284-
local snip = q:get_snippet(true)
285-
utils.set_question_lines(q, snip)
284+
q:set_lines()
286285
end
287286

288287
function cmd.last_submit()
@@ -303,8 +302,8 @@ function cmd.last_submit()
303302
return
304303
end
305304

306-
if type(res) == "table" and res.code and api.nvim_buf_is_valid(q.bufnr) then
307-
utils.set_question_lines(q, res.code)
305+
if type(res) == "table" and res.code then
306+
q:set_lines(res.code)
308307
else
309308
log.error("Something went wrong")
310309
end
@@ -359,7 +358,7 @@ function cmd.inject()
359358
end
360359

361360
if end_i == nil then
362-
log.error("`@leet start` not found")
361+
log.error("`@leet end` not found")
363362
else
364363
local after = q:inject(false)
365364
if after then

lua/leetcode/pickers/question.lua

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ return {
124124
}),
125125
sorter = conf.generic_sorter(theme),
126126
attach_mappings = function(prompt_bufnr, map)
127-
actions.select_default:replace(function()
127+
local function mount_question(reset)
128128
local selection = action_state.get_selected_entry()
129129
if not selection then return end
130130

@@ -134,8 +134,12 @@ return {
134134
end
135135

136136
actions.close(prompt_bufnr)
137-
Question(q):mount()
138-
end)
137+
Question(q, reset):mount()
138+
end
139+
140+
actions.select_default:replace(function() mount_question() end)
141+
map({ "n", "i" }, "<C-Enter>", function() mount_question(true) end)
142+
139143
return true
140144
end,
141145
})

0 commit comments

Comments
 (0)