A Neovim plugin enabling you to solve LeetCode problems.
feat: store testcase snapshots
5 files changed, +44 -21
+3-3lua/leetcode-ui/group/cases.lua
| @@ -59,11 +59,11 @@ function Cases:init(item, parent) | ||
| 59 | 59 | self.console = parent |
| 60 | 60 | |
| 61 | 61 | local total = item.total_testcases ~= vim.NIL and item.total_testcases or 0 |
| 62 | + local testcases = parent.testcase:by_id(item.submission_id) | |
| 63 | + | |
| 62 | 64 | for i = 1, total do |
| 63 | 65 | self.cases[i] = Case({ |
| 64 | - -- TODO: cache the testcases on submission, | |
| 65 | - -- so it doesn't get out of sync | |
| 66 | - input = self.console.testcase.testcases[i], | |
| 66 | + input = testcases[i], | |
| 67 | 67 | output = item.code_answer[i], |
| 68 | 68 | expected = item.expected_code_answer[i], |
| 69 | 69 | std_output = item.std_output_list[i], |
+30-15lua/leetcode-ui/popup/console/testcase.lua
| @@ -5,40 +5,53 @@ local t = require("leetcode.translator") | ||
| 5 | 5 | |
| 6 | 6 | ---@class lc.ui.Console.TestcasePopup : lc.ui.Console.Popup |
| 7 | 7 | ---@field testcases table<string[]> |
| 8 | +---@field testcase_len integer | |
| 8 | 9 | ---@field extmarks integer[] |
| 10 | +---@field snapshots table<string, string[]> | |
| 9 | 11 | local Testcase = ConsolePopup:extend("LeetTestcasePopup") |
| 10 | 12 | |
| 11 | 13 | function Testcase:content() |
| 12 | - self.testcases = {} | |
| 14 | + local lines = vim.api.nvim_buf_get_lines(self.bufnr, 0, -1, false) | |
| 15 | + lines = vim.tbl_filter(function(line) return line ~= "" end, lines) | |
| 16 | + return table.concat(lines, "\n") | |
| 17 | +end | |
| 18 | + | |
| 19 | +function Testcase:snapshot(id, data) -- | |
| 20 | + if not data.test_case then return end | |
| 21 | + self.testcases[id] = data.test_case | |
| 22 | +end | |
| 23 | + | |
| 24 | +---@return string[][] | |
| 25 | +function Testcase:by_id(id) -- | |
| 26 | + local testcases = {} ---@type string[][] | |
| 13 | 27 | |
| 14 | - local tbl = vim.api.nvim_buf_get_lines(self.bufnr, 0, -1, false) | |
| 15 | - local str = table.concat(tbl, "\n") | |
| 28 | + local i, n = 0, self.testcase_len | |
| 29 | + for case in vim.gsplit(self.testcases[id] or "", "\n") do | |
| 30 | + local j = math.floor(i / n) + 1 | |
| 16 | 31 | |
| 17 | - local testcases = {} | |
| 18 | - for tcase in vim.gsplit(str, "\n\n") do | |
| 19 | - local s = vim.split(tcase, "\n") | |
| 32 | + if not testcases[j] then testcases[j] = {} end | |
| 33 | + table.insert(testcases[j], case) | |
| 20 | 34 | |
| 21 | - table.insert(self.testcases, s) | |
| 22 | - testcases = vim.list_extend(testcases, s) | |
| 35 | + i = i + 1 | |
| 23 | 36 | end |
| 24 | 37 | |
| 25 | 38 | return testcases |
| 26 | 39 | end |
| 27 | 40 | |
| 28 | 41 | function Testcase:populate() |
| 29 | - local tbl = {} | |
| 30 | - for i, case in ipairs(self.console.question.q.testcase_list) do | |
| 31 | - if i ~= 1 then table.insert(tbl, "") end | |
| 42 | + local lines = {} | |
| 32 | 43 | |
| 33 | - table.insert(self.testcases, vim.split(case, "\n")) | |
| 44 | + local t_list = self.console.question.q.testcase_list | |
| 45 | + self.testcase_len = #vim.split(t_list[1] or "", "\n") | |
| 34 | 46 | |
| 47 | + for i, case in ipairs(t_list) do | |
| 48 | + if i ~= 1 then table.insert(lines, "") end | |
| 35 | 49 | for s in vim.gsplit(case, "\n", { trimempty = true }) do |
| 36 | - table.insert(tbl, s) | |
| 50 | + table.insert(lines, s) | |
| 37 | 51 | end |
| 38 | 52 | end |
| 39 | 53 | |
| 40 | - vim.api.nvim_buf_set_lines(self.bufnr, 0, -1, false, tbl) | |
| 41 | - | |
| 54 | + vim.api.nvim_buf_set_lines(self.bufnr, 0, -1, false, lines) | |
| 42 | 55 | return self:draw_extmarks() |
| 43 | 56 | end |
| 44 | 57 | |
| @@ -140,6 +153,7 @@ function Testcase:mount() | ||
| 140 | 153 | |
| 141 | 154 | self.testcases = {} |
| 142 | 155 | self.extmarks = {} |
| 156 | + self.testcase_len = 0 | |
| 143 | 157 | |
| 144 | 158 | self:autocmds() |
| 145 | 159 | self:populate() |
| @@ -172,6 +186,7 @@ function Testcase:init(parent) | ||
| 172 | 186 | |
| 173 | 187 | self.testcases = {} |
| 174 | 188 | self.extmarks = {} |
| 189 | + self.testcase_len = 0 | |
| 175 | 190 | |
| 176 | 191 | self:populate() |
| 177 | 192 | end |
+2-1lua/leetcode/api/interpreter.lua
| @@ -83,8 +83,9 @@ function interpreter.run(submit, q, body, callback) | ||
| 83 | 83 | end |
| 84 | 84 | callback(nil, nil, err) |
| 85 | 85 | else |
| 86 | - q.console.result:clear() | |
| 87 | 86 | local id = submit and res.submission_id or res.interpret_id |
| 87 | + q.console.testcase:snapshot(id, res) | |
| 88 | + q.console.result:clear() | |
| 88 | 89 | interpreter.listener(id, callback) |
| 89 | 90 | end |
| 90 | 91 | end, |
+8-1lua/leetcode/logger/spinner/init.lua
| @@ -50,7 +50,7 @@ function spinner:spin() | ||
| 50 | 50 | |
| 51 | 51 | self.index = (self.index + 1) % #stype.frames |
| 52 | 52 | |
| 53 | - local fps = 1000 / #stype.frames | |
| 53 | + local fps = math.floor(1000 / #stype.frames) | |
| 54 | 54 | vim.defer_fn(function() self:spin() end, fps) |
| 55 | 55 | end |
| 56 | 56 | |
| @@ -63,6 +63,9 @@ function spinner:set(msg, lvl, opts) | ||
| 63 | 63 | if msg then self:update(msg) end |
| 64 | 64 | lvl = lvl or vim.log.levels.INFO |
| 65 | 65 | |
| 66 | + local log = require("leetcode.logger") | |
| 67 | + log.debug(self.noti) | |
| 68 | + | |
| 66 | 69 | opts = vim.tbl_deep_extend("force", { |
| 67 | 70 | hide_from_history = true, |
| 68 | 71 | title = config.name, |
| @@ -97,6 +100,10 @@ function spinner:stop(msg, success, opts) | ||
| 97 | 100 | |
| 98 | 101 | self.spinner = nil |
| 99 | 102 | local lvl = vim.log.levels[success and "INFO" or "ERROR"] |
| 103 | + | |
| 104 | + local log = require("leetcode.logger") | |
| 105 | + log.debug({ noti = self.noti, msg = "spinner stop" }) | |
| 106 | + | |
| 100 | 107 | self:set(msg, lvl, opts) |
| 101 | 108 | end |
| 102 | 109 |
+1-1lua/leetcode/runner/init.lua
| @@ -36,7 +36,7 @@ function Runner:handle(submit) | ||
| 36 | 36 | lang = question.lang, |
| 37 | 37 | typed_code = self.question:lines(submit), |
| 38 | 38 | question_id = question.q.id, |
| 39 | - data_input = not submit and table.concat(question.console.testcase:content(), "\n") or nil, | |
| 39 | + data_input = not submit and question.console.testcase:content(), | |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | local judge = Judge:init() |