irongit

A Neovim plugin enabling you to solve LeetCode problems.

feat(console): group cases into separate tabs

kawreauthored
parent f49fbe2commit b6c969344eb1099178bfb5f7bbb6e37ce8c4a0b6Browse files

7 files changed, +490 -318

+6-0lua/leetcode/theme/default.lua
@@ -37,6 +37,12 @@ M.get = function()
3737 hint = { fg = hl("DiagnosticHint").fg },
3838 error = { fg = hl("DiagnosticError").fg },
3939
40+ case_ok = { fg = hl("DiagnosticOk").fg, bg = hl("Normal").bg, bold = true },
41+ case_err = { fg = hl("DiagnosticError").fg, bg = hl("Normal").bg, bold = true },
42+
43+ case_focus_ok = { bg = hl("DiagnosticOk").fg, fg = hl("NormalSB").bg, bold = true },
44+ case_focus_err = { bg = hl("DiagnosticError").fg, fg = hl("NormalSB").bg, bold = true },
45+
4046 normal = { fg = hl("Conceal").fg },
4147 alt = { fg = hl("Comment").fg },
4248
+76-26lua/leetcode/ui/console/components/case.lua
@@ -1,44 +1,94 @@
11 local log = require("leetcode.logger")
22 local t = require("leetcode.translator")
3+
34 local Pre = require("leetcode.ui.console.components.pre")
5+local Stdout = require("leetcode.ui.console.components.stdout")
6+local Group = require("leetcode-ui.component.group")
47
58 local NuiLine = require("nui.line")
69
7----@class lc.Result.Case
8-local case = {}
10+---@class lc.Result.Case : lc-ui.Group
11+---@field pre lc-ui.Text
12+---@field stdout lc-ui.Text
13+---@field passed boolean
14+---@field index integer
15+local Case = {}
16+Case.__index = Case
17+setmetatable(Case, Group)
18+
19+local function get_pad(key, max_len) return (" "):rep(max_len + 1 - vim.api.nvim_strwidth(key)) end
20+
21+---@private
22+---@param input string
23+---@return NuiLine
24+function Case:input(input)
25+ local key = t("Input")
26+
27+ local line = NuiLine()
28+ line:append(("%s:%s"):format(key, get_pad(key, self.max_len)))
29+ line:append(input, "leetcode_alt")
30+
31+ return line
32+end
33+
34+---@private
35+---@param output string
36+---@param expected string
37+---@return NuiLine
38+function Case:output(output, expected)
39+ local key = t("Output")
40+
41+ local line = NuiLine()
42+ line:append(("%s:%s"):format(key, get_pad(key, self.max_len)))
43+ line:append(output, "leetcode_alt")
44+
45+ return line
46+end
47+
48+---@private
49+---@param expected string
50+---@param output string
51+---@return NuiLine
52+function Case:expected(expected, output)
53+ local key = t("Expected")
54+
55+ local line = NuiLine()
56+ line:append(("%s:%s"):format(key, get_pad(key, self.max_len)))
57+ line:append(expected, "leetcode_alt")
58+
59+ return line
60+end
961
10----@param index integer
1162 ---@param input string
1263 ---@param output string
1364 ---@param expected string
14----@param passed? boolean
65+---@param std_output string
66+---@param passed boolean
1567 ---
16----@return lc-ui.Text
17-function case:init(index, input, output, expected, passed)
18- local tbl = {}
68+---@return lc.Result.Case
69+function Case:init(input, output, expected, std_output, passed)
70+ local group = Group:init({}, { spacing = 1 })
71+ self = setmetatable(group, self)
1972
20- local match = passed or (output == expected)
21- local icon = match and "" or ""
22- local hi = match and "leetcode_ok" or "leetcode_error"
23- local title_line = NuiLine()
24- title_line:append(icon .. " Case " .. index, hi)
73+ self.max_len = 0
74+ for _, key in ipairs({ "Input", "Output", "Expected" }) do
75+ self.max_len = math.max(self.max_len, vim.api.nvim_strwidth(t(key)))
76+ end
77+
78+ local tbl = {}
79+ table.insert(tbl, self:input(input))
80+ table.insert(tbl, self:output(output, expected))
81+ table.insert(tbl, self:expected(expected, output))
2582
26- local input_line = NuiLine()
27- input_line:append(("%s: "):format(t("Input")))
28- input_line:append(input, "leetcode_alt")
29- table.insert(tbl, input_line)
83+ local pre = Pre:init(nil, tbl)
84+ self:append(pre)
3085
31- local output_line = NuiLine()
32- output_line:append(("%s: "):format(t("Output")))
33- output_line:append(output, "leetcode_alt")
34- table.insert(tbl, output_line)
86+ local stdout = Stdout:init(std_output)
87+ if stdout then self:append(stdout) end
3588
36- local expected_line = NuiLine()
37- expected_line:append(("%s: "):format(t("Expected")))
38- expected_line:append(expected, "leetcode_alt")
39- table.insert(tbl, expected_line)
89+ self.passed = passed
4090
41- return Pre:init(title_line, tbl)
91+ return self
4292 end
4393
44-return case
94+return Case
+88-0lua/leetcode/ui/console/components/cases.lua
@@ -0,0 +1,88 @@
1+local log = require("leetcode.logger")
2+
3+local Group = require("leetcode-ui.component.group")
4+local Text = require("leetcode-ui.component.text")
5+local Case = require("leetcode.ui.console.components.case")
6+
7+local NuiLine = require("nui.line")
8+
9+---@class lc.Cases : lc-ui.Group
10+---@field nav lc-ui.Text
11+---@field case lc-ui.Group
12+---@field cases table<integer, lc.Result.Case>
13+---@field keymaps { mode: string, key: string }
14+---@field idx integer
15+---@field parent lc.Result
16+local Cases = {}
17+Cases.__index = Cases
18+setmetatable(Cases, Group)
19+
20+function Cases:clear()
21+ for _, map in ipairs(self.keymaps) do
22+ pcall(function() self.parent.popup:unmap(map.mode, map.key) end)
23+ end
24+ self.keymaps = {}
25+ Group.clear(self)
26+end
27+
28+function Cases:update_nav()
29+ local cases = NuiLine()
30+
31+ for i, case in ipairs(self.cases) do
32+ local text = NuiLine()
33+ local hl = ("%s%s"):format(self.idx == i and "focus_" or "", case.passed and "ok" or "err")
34+ text:append((" Case (%d) "):format(i), "leetcode_case_" .. hl)
35+
36+ local keymap = { mode = "n", key = tostring(i) }
37+ self.parent.popup:map(keymap.mode, keymap.key, function() self:change(i) end)
38+ table.insert(self.keymaps, keymap)
39+
40+ cases:append(text)
41+ if i ~= #self.cases then cases:append(" ") end
42+ end
43+
44+ self.nav.lines = { cases }
45+end
46+
47+---@param idx integer
48+function Cases:change(idx)
49+ if not self.cases[idx] or idx == self.idx then return end
50+ self.case.components = { self.cases[idx] }
51+ self.idx = idx
52+ self:update_nav()
53+ self.parent:draw()
54+end
55+
56+---@param item lc.runtime
57+---@param testcases string[]
58+---@param parent lc.Result
59+---@return lc.Cases
60+function Cases:init(item, testcases, parent)
61+ local group = Group:init({}, { spacing = 1 })
62+ self = setmetatable(group, self)
63+
64+ self.cases = {}
65+ self.parent = parent
66+ self.keymaps = {}
67+
68+ for i, answer in ipairs(item.code_answer) do
69+ self.cases[i] = Case:init(
70+ testcases[i],
71+ answer,
72+ item.expected_code_answer[i],
73+ item.std_output_list[i],
74+ item.compare_result:sub(i, i) == "1"
75+ )
76+ end
77+
78+ self.nav = Text:init({}, { padding = { top = 1, bot = 1 } })
79+ self:append(self.nav)
80+
81+ self.case = Group:init({})
82+ self:append(self.case)
83+ self:change(1)
84+
85+ return self ---@diagnostic disable-line
86+end
87+
88+return Cases
+3-2lua/leetcode/ui/console/components/pre.lua
@@ -9,12 +9,13 @@ local NuiLine = require("nui.line")
99 local pre = {}
1010 pre.__index = pre
1111
12----@param title NuiText | NuiLine
12+---@param title NuiText | NuiLine | nil
1313 ---@param lines NuiLine[]
1414 ---
1515 ---@return lc-ui.Text
1616 function pre:init(title, lines)
17- local text = Text:init({ title, NuiLine() })
17+ local text = Text:init({})
18+ if title then text:append({ title, NuiLine() }) end
1819
1920 for _, line in ipairs(lines) do
2021 local new_line = NuiLine({ NuiText("\t▎\t", "leetcode_indent") })
+304-0lua/leetcode/ui/console/components/result.lua
@@ -0,0 +1,304 @@
1+local config = require("leetcode.config")
2+local t = require("leetcode.translator")
3+local log = require("leetcode.logger")
4+local Cases = require("leetcode.ui.console.components.cases")
5+
6+local Layout = require("leetcode-ui.layout")
7+local Pre = require("leetcode.ui.console.components.pre")
8+local Group = require("leetcode-ui.component.group")
9+local Text = require("leetcode-ui.component.text")
10+local Stdout = require("leetcode.ui.console.components.stdout")
11+local Case = require("leetcode.ui.console.components.case")
12+
13+local NuiLine = require("nui.line")
14+local NuiText = require("nui.text")
15+
16+---@class lc.ResultLayout : lc-ui.Layout
17+---@field parent lc.Console
18+---@field group lc-ui.Group
19+---@field cases lc.Cases
20+---@field case lc-ui.Group
21+---@field case_idx integer
22+local ResultLayout = {}
23+ResultLayout.__index = ResultLayout
24+setmetatable(ResultLayout, Layout)
25+
26+local function testcases_passed(item)
27+ local correct = item.total_correct ~= vim.NIL and item.total_correct or "0"
28+ local total = item.total_testcases ~= vim.NIL and item.total_testcases or "0"
29+
30+ return ("%d/%d %s"):format(correct, total, t("testcases passed"))
31+end
32+
33+function ResultLayout:handle_accepted(item)
34+ local function perc_hi(perc) return perc >= 50 and "leetcode_ok" or "leetcode_error" end
35+ self.group:set_opts({ spacing = 2 })
36+
37+ local header = Text:init({})
38+ header:append(item._.title .. " 🎉", item._.hl)
39+ self.group:append(header)
40+
41+ -- runtime
42+ local status_runtime = NuiLine()
43+ local runtime_ms = item.display_runtime or vim.split(item.status_runtime, " ")[1] or "NIL"
44+ status_runtime:append(runtime_ms)
45+ status_runtime:append(" ms", "leetcode_alt")
46+
47+ local perc_runtime = NuiLine()
48+ perc_runtime:append(
49+ ("%s %.2f%% "):format(t("Beats"), item.runtime_percentile),
50+ perc_hi(item.runtime_percentile)
51+ )
52+ if config.is_cn then
53+ perc_runtime:append("使用 ")
54+ perc_runtime:append(item.pretty_lang, "Structure")
55+ perc_runtime:append(" 的用户")
56+ else
57+ perc_runtime:append("of users with ")
58+ perc_runtime:append(item.pretty_lang, "Structure")
59+ end
60+
61+ local runtime = Pre:init(NuiText(("󰓅 %s"):format(t("Runtime")), "leetcode_normal"), {
62+ status_runtime,
63+ perc_runtime,
64+ })
65+ self.group:append(runtime)
66+
67+ -- memory
68+ local status_memory = NuiLine()
69+ -- if item.status_memory == "0B" then item.status_memory = "0 MB" end
70+ item.status_memory = item.status_memory:gsub("(%d+)%s*(%a+)", "%1 %2")
71+ -- log.info(item.status_memory)
72+ local s_mem = vim.split(item.status_memory, " ")
73+ status_memory:append(s_mem[1] .. " ")
74+ status_memory:append(s_mem[2], "leetcode_alt")
75+
76+ local perc_mem = NuiLine()
77+ perc_mem:append(
78+ ("%s %.2f%% "):format(t("Beats"), item.memory_percentile),
79+ perc_hi(item.memory_percentile)
80+ )
81+ if config.is_cn then
82+ perc_mem:append("使用 ")
83+ perc_mem:append(item.pretty_lang, "Structure")
84+ perc_mem:append(" 的用户")
85+ else
86+ perc_mem:append("of users with ")
87+ perc_mem:append(item.pretty_lang, "Structure")
88+ end
89+
90+ local memory = Pre:init(NuiText(("󰍛 %s"):format(t("Memory")), "leetcode_normal"), {
91+ status_memory,
92+ perc_mem,
93+ })
94+
95+ self.group:append(memory)
96+end
97+
98+---@private
99+---
100+---@param item lc.runtime
101+function ResultLayout:handle_runtime(item) -- status code = 10
102+ if item._.submission then return self:handle_accepted(item) end
103+
104+ local header = Text:init({})
105+ local h = NuiLine()
106+ h:append(item._.title, item._.hl)
107+ h:append(" | ")
108+ h:append(("%s: %s"):format(t("Runtime"), item.status_runtime), "leetcode_alt")
109+ header:append(h)
110+ self.group:append(header)
111+
112+ self.cases = Cases:init(item, self.parent.testcase.testcases, self.parent.result)
113+ self.group:append(self.cases)
114+end
115+
116+---@private
117+---
118+---@param item lc.submission
119+function ResultLayout:handle_submission_error(item) -- status code = 11
120+ self.group:set_opts({ spacing = 2 })
121+
122+ local header = NuiLine()
123+ header:append(item._.title, item._.hl)
124+ header:append(" | ")
125+ header:append(testcases_passed(item), "leetcode_alt")
126+ self.group:append(Text:init({ header }))
127+
128+ self.case = Case:init(
129+ item.input_formatted,
130+ item.code_output,
131+ item.expected_output,
132+ item.std_output,
133+ false
134+ )
135+ self.group:append(self.case)
136+end
137+
138+---@private
139+---
140+---@param item lc.limit_exceeded_error
141+function ResultLayout:handle_limit_exceeded(item) -- status code = 12,13,14
142+ local header = NuiLine()
143+ header:append(item._.title, item._.hl)
144+ if item._.submission then
145+ header:append(" | ")
146+ header:append(testcases_passed(item), "leetcode_alt")
147+ end
148+ self.group:append(Text:init({ header }))
149+
150+ if item._.submission then
151+ local last_testcase = NuiLine()
152+ last_testcase:append(item.last_testcase:gsub("\n", " "), "leetcode_indent")
153+
154+ local pre_header = NuiLine()
155+ pre_header:append((" %s"):format(t("Last Executed Input")), "leetcode_normal")
156+
157+ local last_exec = Pre:init(pre_header, { last_testcase })
158+ self.group:append(last_exec)
159+
160+ if item.std_output ~= "" then
161+ local stdout = Stdout:init(item.std_output)
162+ if stdout then self.group:append(stdout) end
163+ end
164+ elseif item.std_output_list[#item.std_output_list] ~= "" then
165+ local stdout = Stdout:init(item.std_output_list[#item.std_output_list])
166+ if stdout then self.group:append(stdout) end
167+ end
168+end
169+
170+---@private
171+---
172+---@param item lc.runtime_error
173+function ResultLayout:handle_runtime_error(item) -- status code = 15
174+ local header = NuiLine()
175+ header:append(item._.title, item._.hl)
176+
177+ if item._.submission then
178+ header:append(" | ")
179+ header:append(testcases_passed(item), "leetcode_alt")
180+ end
181+
182+ local tbl = {}
183+ for line in vim.gsplit(item.full_runtime_error, "\n") do
184+ table.insert(tbl, NuiLine():append(line, "leetcode_error"))
185+ end
186+ group:append(Pre:init(header, tbl))
187+
188+ if item._.submission then
189+ local pre_header = NuiLine()
190+ pre_header:append((" %s"):format(t("Last Executed Input")), "leetcode_normal")
191+
192+ local last_testcase = NuiLine()
193+ last_testcase:append(item.last_testcase:gsub("\n", " "), "leetcode_indent")
194+
195+ local last_exec = Pre:init(pre_header, { last_testcase })
196+ group:append(last_exec)
197+ else
198+ local stdout = Stdout:init(item.std_output_list[#item.std_output_list])
199+ if stdout then group:append(stdout) end
200+ end
201+end
202+
203+function ResultLayout:handle_internal_error(item) -- status code = 16
204+ local header = NuiLine()
205+ header:append(item._.title, item._.hl)
206+ local text = Text:init({ header })
207+ self.group:append(text)
208+end
209+
210+---@private
211+---
212+---@param item lc.compile_error
213+function ResultLayout:handle_compile_error(item) -- status code = 20
214+ local header = NuiLine()
215+ header:append(item._.title, item._.hl)
216+ if item._.submission then
217+ header:append(" | ")
218+ header:append(testcases_passed(item), "leetcode_alt")
219+ end
220+
221+ local tbl = {}
222+ for line in vim.gsplit(item.full_compile_error, "\n") do
223+ table.insert(tbl, NuiLine():append(line, "leetcode_error"))
224+ end
225+
226+ self.group:append(Pre:init(header, tbl))
227+end
228+
229+---@param idx integer
230+function ResultLayout:change_case(idx)
231+ if vim.tbl_isempty(self.cases) then return end
232+ if not self.cases[idx] then return end
233+ self.case.components = { self.cases[idx] }
234+ self.parent.result:draw()
235+end
236+
237+---@param item lc.interpreter_response
238+function ResultLayout:handle_res(item)
239+ log.info(item.status_code)
240+ self.group = Group:init({}, { spacing = 1 })
241+
242+ local handlers = {
243+ -- runtime
244+ [10] = function()
245+ self:handle_runtime(item --[[@as lc.runtime]])
246+ end,
247+ [11] = function()
248+ self:handle_submission_error(item --[[@as lc.submission]])
249+ end,
250+
251+ -- memory limit
252+ [12] = function()
253+ self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
254+ end,
255+ -- time limit
256+ [13] = function()
257+ self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
258+ end,
259+ -- output limit
260+ [14] = function()
261+ self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
262+ end,
263+
264+ -- runtime error
265+ [15] = function()
266+ self:handle_runtime_error(item --[[@as lc.runtime_error]])
267+ end,
268+
269+ -- internal error
270+ [16] = function()
271+ self:handle_internal_error(item --[[@as lc.internal_error]])
272+ end,
273+
274+ -- compiler
275+ [20] = function()
276+ self:handle_compile_error(item --[[@as lc.compile_error]])
277+ end,
278+
279+ -- unknown
280+ ["unknown"] = function() log.error("unknown runner status code: " .. item.status_code) end,
281+ };
282+
283+ (handlers[item.status_code] or handlers["unknown"])()
284+ self:append(self.group)
285+end
286+
287+function ResultLayout:clear()
288+ if self.cases then self.cases:clear() end
289+ Layout.clear(self)
290+end
291+
292+---@param parent lc.Console
293+---@param opts? lc-ui.Layout.opts
294+function ResultLayout:init(parent, opts)
295+ local layout = Layout:init({}, opts)
296+
297+ self = setmetatable(layout, self)
298+
299+ self.parent = parent
300+
301+ return self
302+end
303+
304+return ResultLayout
+4-4lua/leetcode/ui/console/components/stdout.lua
@@ -10,14 +10,14 @@ local stdout = {}
1010 ---
1111 ---@return lc-ui.Text | nil
1212 function stdout:init(output)
13- output = output or ""
14- local output_list = vim.split(output, "\n", { trimempty = true })
15-
13+ local output_list = vim.split(output or "", "\n", { trimempty = true })
1614 if vim.tbl_isempty(output_list) then return end
1715
1816 local tbl = {}
1917 for i = 1, #output_list, 1 do
20- table.insert(tbl, NuiLine():append(output_list[i]))
18+ local line = NuiLine()
19+ line:append(output_list[i])
20+ table.insert(tbl, line)
2121 end
2222
2323 return Pre:init(NuiLine():append((" %s"):format(t("Stdout")), "leetcode_alt"), tbl)
+9-286lua/leetcode/ui/console/result.lua
@@ -9,266 +9,27 @@ local Case = require("leetcode.ui.console.components.case")
99 local Group = require("leetcode-ui.component.group")
1010 local Pre = require("leetcode.ui.console.components.pre")
1111 local Layout = require("leetcode-ui.layout")
12+local ResultLayout = require("leetcode.ui.console.components.result")
1213 local Text = require("leetcode-ui.component.text")
1314
1415 local NuiLine = require("nui.line")
1516 local NuiText = require("nui.text")
1617 local NuiPopup = require("nui.popup")
1718
18----@class lc.Result: lc.Console.Popup
19----@field layout lc-ui.Layout
19+---@class lc.Result : lc.Console.Popup
20+---@field layout lc.ResultLayout
2021 local result = {}
2122 result.__index = result
2223 setmetatable(result, console_popup)
2324
24-local function testcases_passed(item)
25- local correct = item.total_correct ~= vim.NIL and item.total_correct or "0"
26- local total = item.total_testcases ~= vim.NIL and item.total_testcases or "0"
27-
28- return ("%d/%d %s"):format(correct, total, t("testcases passed"))
29-end
30-
3125 ---@param hi string
3226 function result:set_popup_border_hi(hi) self.popup.border:set_highlight(hi) end
3327
34-function result:handle_accepted(item)
35- local function perc_hi(perc) return perc >= 50 and "leetcode_ok" or "leetcode_error" end
36- local group = Group:init({}, { spacing = 2 })
37-
38- local header = Text:init({})
39- header:append(item._.title .. " 🎉", item._.hl)
40- group:append(header)
41-
42- -- runtime
43- local status_runtime = NuiLine()
44- local runtime_ms = item.display_runtime or vim.split(item.status_runtime, " ")[1] or "NIL"
45- status_runtime:append(runtime_ms)
46- status_runtime:append(" ms", "leetcode_alt")
47-
48- local perc_runtime = NuiLine()
49- perc_runtime:append(
50- ("%s %.2f%% "):format(t("Beats"), item.runtime_percentile),
51- perc_hi(item.runtime_percentile)
52- )
53- if config.is_cn then
54- perc_runtime:append("使用 ")
55- perc_runtime:append(item.pretty_lang, "Structure")
56- perc_runtime:append(" 的用户")
57- else
58- perc_runtime:append("of users with ")
59- perc_runtime:append(item.pretty_lang, "Structure")
60- end
61-
62- local runtime = Pre:init(NuiText(("󰓅 %s"):format(t("Runtime")), "leetcode_normal"), {
63- status_runtime,
64- perc_runtime,
65- })
66- group:append(runtime)
67-
68- -- memory
69- local status_memory = NuiLine()
70- if item.status_memory == "0B" then item.status_memory = "0 MB" end
71- local s_mem = vim.split(item.status_memory, " ")
72- status_memory:append(s_mem[1] .. " ")
73- status_memory:append(s_mem[2], "leetcode_alt")
74-
75- local perc_mem = NuiLine()
76- perc_mem:append(
77- ("%s %.2f%% "):format(t("Beats"), item.memory_percentile),
78- perc_hi(item.memory_percentile)
79- )
80- if config.is_cn then
81- perc_mem:append("使用 ")
82- perc_mem:append(item.pretty_lang, "Structure")
83- perc_mem:append(" 的用户")
84- else
85- perc_mem:append("of users with ")
86- perc_mem:append(item.pretty_lang, "Structure")
87- end
88-
89- local memory = Pre:init(NuiText(("󰍛 %s"):format(t("Memory")), "leetcode_normal"), {
90- status_memory,
91- perc_mem,
92- })
93- group:append(memory)
94-
95- self.layout:append(group)
96-end
97-
98----@private
99----
100----@param item lc.runtime
101-function result:handle_runtime(item) -- status code = 10
102- if item._.submission then return self:handle_accepted(item) end
103-
104- local group = Group:init({}, { spacing = 1 })
105- local header = Text:init({})
106-
107- local h = NuiLine()
108- h:append(item._.title, item._.hl)
109- h:append(" | ")
110- h:append(("%s: %s"):format(t("Runtime"), item.status_runtime), "leetcode_alt")
111- header:append(h)
112- group:append(header)
113-
114- for i, answer in ipairs(item.code_answer) do
115- local passed = item.compare_result:sub(i, i) == "1"
116-
117- local case = Case:init(
118- i,
119- self.parent.testcase.testcases[i],
120- answer,
121- item.expected_code_answer[i],
122- passed
123- )
124- group:append(case)
125-
126- local stdout = Stdout:init(item.std_output_list[i])
127- if stdout then group:append(stdout) end
128- end
129-
130- self.layout:append(group)
131-end
132-
133----@private
134----
135----@param item lc.submission
136-function result:handle_submission_error(item) -- status code = 11
137- local group = Group:init({}, { spacing = 1 })
138-
139- local header = NuiLine()
140- header:append(item._.title, item._.hl)
141- header:append(" | ")
142- header:append(testcases_passed(item), "leetcode_alt")
143- group:append(Text:init({ header }))
144-
145- local text = Case:init(
146- item.total_correct + 1,
147- item.input_formatted,
148- item.code_output,
149- item.expected_output
150- )
151- group:append(text)
152-
153- if item.std_output then
154- local stdout = Stdout:init(item.std_output)
155- if stdout then group:append(stdout) end
156- end
157-
158- self.layout:append(group)
159-end
160-
161----@private
162----
163----@param item lc.limit_exceeded_error
164-function result:handle_limit_exceeded(item) -- status code = 12,13,14
165- local group = Group:init({}, { spacing = 1 })
166-
167- local header = NuiLine()
168- header:append(item._.title, item._.hl)
169- if item._.submission then
170- header:append(" | ")
171- header:append(testcases_passed(item), "leetcode_alt")
172- end
173- group:append(Text:init({ header }))
174-
175- if item._.submission then
176- local last_testcase = NuiLine()
177- last_testcase:append(item.last_testcase:gsub("\n", " "), "leetcode_indent")
178-
179- local pre_header = NuiLine()
180- pre_header:append((" %s"):format(t("Last Executed Input")), "leetcode_normal")
181-
182- local last_exec = Pre:init(pre_header, { last_testcase })
183- group:append(last_exec)
184-
185- if item.std_output ~= "" then
186- local stdout = Stdout:init(item.std_output)
187- if stdout then group:append(stdout) end
188- end
189- elseif item.std_output_list[1] ~= "" then
190- local stdout = Stdout:init(item.std_output_list[1])
191- if stdout then group:append(stdout) end
192- end
193-
194- self.layout:append(group)
195-end
196-
197----@private
198----
199----@param item lc.runtime_error
200-function result:handle_runtime_error(item) -- status code = 15
201- local group = Group:init({}, { spacing = 1 })
202-
203- local header = NuiLine()
204- header:append(item._.title, item._.hl)
205-
206- if item._.submission then
207- header:append(" | ")
208- header:append(testcases_passed(item), "leetcode_alt")
209- end
210-
211- local tbl = {}
212- for line in vim.gsplit(item.full_runtime_error, "\n") do
213- table.insert(tbl, NuiLine():append(line, "leetcode_error"))
214- end
215- group:append(Pre:init(header, tbl))
216-
217- if item._.submission then
218- local pre_header = NuiLine()
219- pre_header:append((" %s"):format(t("Last Executed Input")), "leetcode_normal")
220-
221- local last_testcase = NuiLine()
222- last_testcase:append(item.last_testcase:gsub("\n", " "), "leetcode_indent")
223-
224- local last_exec = Pre:init(pre_header, { last_testcase })
225- group:append(last_exec)
226- else
227- local stdout = Stdout:init(item.std_output_list[1])
228- if stdout then group:append(stdout) end
229- end
230-
231- self.layout:append(group)
232-end
233-
23428 function result:focus()
23529 if not vim.api.nvim_win_is_valid(self.popup.winid) then return end
23630 vim.api.nvim_set_current_win(self.popup.winid)
23731 end
23832
239-function result:handle_internal_error(item) -- status code = 16
240- local group = Group:init({}, { spacing = 1 })
241-
242- local header = NuiLine()
243- header:append(item._.title, item._.hl)
244- local text = Text:init({ header })
245- group:append(text)
246-
247- self.layout:append(group)
248-end
249-
250----@private
251----
252----@param item lc.compile_error
253-function result:handle_compile_error(item) -- status code = 20
254- local group = Group:init({}, { spacing = 1 })
255-
256- local header = NuiLine()
257- header:append(item._.title, item._.hl)
258- if item._.submission then
259- header:append(" | ")
260- header:append(testcases_passed(item), "leetcode_alt")
261- end
262-
263- local tbl = {}
264- for line in vim.gsplit(item.full_compile_error, "\n") do
265- table.insert(tbl, NuiLine():append(line, "leetcode_error"))
266- end
267-
268- group:append(Pre:init(header, tbl))
269- self.layout:append(group)
270-end
271-
27233 ---@param item lc.interpreter_response
27334 ---
27435 ---@return lc.interpreter_response
@@ -300,49 +61,7 @@ function result:handle(item)
30061 self.layout:clear()
30162 item = self:handle_item(item)
30263 self:set_popup_border_hi(item._.hl)
303-
304- local handlers = {
305- -- runtime
306- [10] = function()
307- self:handle_runtime(item --[[@as lc.runtime]])
308- end,
309- [11] = function()
310- self:handle_submission_error(item --[[@as lc.submission]])
311- end,
312-
313- -- memory limit
314- [12] = function()
315- self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
316- end,
317- -- time limit
318- [13] = function()
319- self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
320- end,
321- -- output limit
322- [14] = function()
323- self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]])
324- end,
325-
326- -- runtime error
327- [15] = function()
328- self:handle_runtime_error(item --[[@as lc.runtime_error]])
329- end,
330-
331- -- internal error
332- [16] = function()
333- self:handle_internal_error(item --[[@as lc.internal_error]])
334- end,
335-
336- -- compiler
337- [20] = function()
338- self:handle_compile_error(item --[[@as lc.compile_error]])
339- end,
340-
341- -- unknown
342- ["unknown"] = function() log.error("unknown runner status code: " .. item.status_code) end,
343- };
344-
345- (handlers[item.status_code] or handlers["unknown"])()
64+ self.layout:handle_res(item)
34665
34766 if item._.submission then
34867 local status = item.status_code == 10 and "ac" or "notac"
@@ -398,7 +117,11 @@ function result:init(parent)
398117
399118 self = setmetatable({
400119 popup = popup,
401- layout = Layout:init({}, {
120+ -- layout = Layout:init({}, {
121+ -- winid = popup.winid,
122+ -- bufnr = popup.bufnr,
123+ -- }),
124+ layout = ResultLayout:init(parent, {
402125 winid = popup.winid,
403126 bufnr = popup.bufnr,
404127 }),