A Neovim plugin enabling you to solve LeetCode problems.
| 1 | local Cases = require("leetcode-ui.group.cases") |
| 2 | local Header = require("leetcode-ui.lines.header") |
| 3 | local utils = require("leetcode.utils") |
| 4 | local SimilarQuestions = require("leetcode-ui.group.similar-questions") |
| 5 | |
| 6 | local Renderer = require("leetcode-ui.renderer") |
| 7 | local Pre = require("leetcode-ui.group.pre") |
| 8 | local Input = require("leetcode-ui.group.pre.input") |
| 9 | local Stdout = require("leetcode-ui.group.pre.stdout") |
| 10 | local Case = require("leetcode-ui.group.case") |
| 11 | |
| 12 | local Line = require("leetcode-ui.line") |
| 13 | local Lines = require("leetcode-ui.lines") |
| 14 | |
| 15 | local config = require("leetcode.config") |
| 16 | local t = require("leetcode.translator") |
| 17 | local log = require("leetcode.logger") |
| 18 | |
| 19 | ---@class lc.ui.Result : lc.ui.Renderer |
| 20 | ---@field parent lc.ui.Console |
| 21 | ---@field group lc.ui.Group |
| 22 | ---@field cases lc.ui.Cases |
| 23 | ---@field case lc.ui.Case |
| 24 | local ResultLayout = Renderer:extend("LeetResultLayout") |
| 25 | |
| 26 | |
| 27 | self:set_opts({ spacing = 2 }) |
| 28 | |
| 29 | local -- |
| 30 | if perc >= 50 then |
| 31 | return "leetcode_ok" |
| 32 | elseif perc >= 10 then |
| 33 | return nil |
| 34 | elseif perc >= 0 then |
| 35 | return "leetcode_error" |
| 36 | end |
| 37 | end |
| 38 | |
| 39 | local header = Header(item) |
| 40 | self:insert(header) |
| 41 | |
| 42 | -------------------------------------------- |
| 43 | --- Runtime |
| 44 | -------------------------------------------- |
| 45 | local runtime = Lines() |
| 46 | local runtime_ms = item.display_runtime or vim.split(item.status_runtime, " ")[1] or "NIL" |
| 47 | runtime:append(runtime_ms):append(" ms", "leetcode_alt") |
| 48 | runtime:endl() |
| 49 | |
| 50 | runtime:append( |
| 51 | ("%s %.2f%% "):format(t("Beats"), item.runtime_percentile), |
| 52 | perc_hi(item.runtime_percentile) |
| 53 | ) |
| 54 | |
| 55 | local lang = utils.get_lang_by_name(item.pretty_lang) |
| 56 | local lang_text = { item.pretty_lang, "Structure" } |
| 57 | if lang then |
| 58 | lang_text = { lang.icon .. " " .. lang.lang, lang.hl or "Structure" } |
| 59 | end |
| 60 | |
| 61 | if config.translator then |
| 62 | runtime |
| 63 | :append("使用 ", "leetcode_normal") |
| 64 | :append(unpack(lang_text)) |
| 65 | :append(" 的用户", "leetcode_normal") |
| 66 | else |
| 67 | runtime:append("of users with ", "leetcode_normal"):append(unpack(lang_text)) |
| 68 | end |
| 69 | |
| 70 | local runtime_title = Line():append(" " .. t("Runtime")) |
| 71 | self:insert(Pre(runtime_title, runtime)) |
| 72 | |
| 73 | -------------------------------------------- |
| 74 | --- Memory |
| 75 | -------------------------------------------- |
| 76 | local memory = Lines() |
| 77 | item.status_memory = item.status_memory:gsub("(%d+)%s*(%a+)", "%1 %2") |
| 78 | local s_mem = vim.split(item.status_memory, " ") |
| 79 | memory:append(s_mem[1] .. " "):append(s_mem[2], "leetcode_alt") |
| 80 | memory:endl() |
| 81 | |
| 82 | memory:append( |
| 83 | ("%s %.2f%% "):format(t("Beats"), item.memory_percentile), |
| 84 | perc_hi(item.memory_percentile) |
| 85 | ) |
| 86 | if config.translator then |
| 87 | memory |
| 88 | :append("使用 ", "leetcode_normal") |
| 89 | :append(unpack(lang_text)) |
| 90 | :append(" 的用户", "leetcode_normal") |
| 91 | else |
| 92 | memory:append("of users with ", "leetcode_normal"):append(unpack(lang_text)) |
| 93 | end |
| 94 | |
| 95 | local memory_title = Line():append(" " .. t("Memory")) |
| 96 | self:insert(Pre(memory_title, memory)) |
| 97 | |
| 98 | -------------------------------------------- |
| 99 | --- More challenges |
| 100 | -------------------------------------------- |
| 101 | if not vim.tbl_isempty(self.parent.question.q.similar or {}) then |
| 102 | local title_txt = (" %s"):format(t("More challenges")) |
| 103 | local more_title = Line():append(title_txt, "leetcode_normal") |
| 104 | local similar = SimilarQuestions(self.parent.question.q.similar) |
| 105 | self:insert(Pre(more_title, similar)) |
| 106 | end |
| 107 | end |
| 108 | |
| 109 | ---@private |
| 110 | --- |
| 111 | ---@param item lc.runtime |
| 112 | -- status code = 10 |
| 113 | if item._.submission then |
| 114 | return self:handle_accepted(item) |
| 115 | end |
| 116 | |
| 117 | local header = Header(item) |
| 118 | self:insert(header) |
| 119 | |
| 120 | local cases = Cases(item, self.parent) |
| 121 | self:insert(cases) |
| 122 | end |
| 123 | |
| 124 | ---@private |
| 125 | --- |
| 126 | ---@param item lc.submission |
| 127 | -- status code = 11 |
| 128 | local header = Header(item) |
| 129 | self:insert(header) |
| 130 | |
| 131 | self:insert(Case({ ---@diagnostic disable-line |
| 132 | input = vim.split(item.input, "\n"), |
| 133 | raw_input = item.last_testcase, |
| 134 | output = item.code_output, |
| 135 | expected = item.expected_output, |
| 136 | std_output = item.std_output, |
| 137 | }, false, self.parent.question)) |
| 138 | end |
| 139 | |
| 140 | ---@private |
| 141 | --- |
| 142 | ---@param item lc.limit_exceeded_error |
| 143 | -- status code = 12,13,14 |
| 144 | local header = Header(item) |
| 145 | self:insert(header) |
| 146 | |
| 147 | if item._.submission then |
| 148 | local input = Input( |
| 149 | (" %s"):format(t("Last Executed Input")), |
| 150 | vim.split(item.last_testcase, "\n"), |
| 151 | self.parent.question.q.meta_data.params |
| 152 | ) |
| 153 | self:insert(input) |
| 154 | |
| 155 | local stdout = Stdout(item.std_output or "") |
| 156 | self:insert(stdout) |
| 157 | elseif item.std_output_list then |
| 158 | local stdout = Stdout(item.std_output_list[#item.std_output_list]) |
| 159 | self:insert(stdout) |
| 160 | end |
| 161 | end |
| 162 | |
| 163 | ---@private |
| 164 | --- |
| 165 | ---@param item lc.runtime_error |
| 166 | -- status code = 15 |
| 167 | local header = Header(item) |
| 168 | |
| 169 | local lines = Lines() |
| 170 | for line in vim.gsplit(item.full_runtime_error, "\n") do |
| 171 | lines:append(line, "leetcode_error"):endl() |
| 172 | end |
| 173 | self:insert(Pre(header, lines)) |
| 174 | |
| 175 | if item._.submission then |
| 176 | local pre_header = Line() |
| 177 | pre_header:append((" %s"):format(t("Last Executed Input")), "leetcode_normal") |
| 178 | |
| 179 | local last_testcase = Line() |
| 180 | last_testcase:append(item.last_testcase:gsub("\n", " "), "leetcode_indent") |
| 181 | |
| 182 | local last_exec = Pre(pre_header, last_testcase) |
| 183 | self:insert(last_exec) |
| 184 | |
| 185 | local stdout = Stdout(item.std_output or "") |
| 186 | self:insert(stdout) |
| 187 | elseif item.std_output_list then |
| 188 | local stdout = Stdout(item.std_output_list[#item.std_output_list]) |
| 189 | self:insert(stdout) |
| 190 | end |
| 191 | end |
| 192 | |
| 193 | -- status code = 16 |
| 194 | local header = Header(item) |
| 195 | self:insert(header) |
| 196 | end |
| 197 | |
| 198 | ---@private |
| 199 | --- |
| 200 | ---@param item lc.compile_error |
| 201 | -- status code = 20 |
| 202 | local header = Header(item) |
| 203 | |
| 204 | local lines = Lines() |
| 205 | for line in vim.gsplit(item.full_compile_error, "\n") do |
| 206 | lines:append(line, "leetcode_error"):endl() |
| 207 | end |
| 208 | |
| 209 | local pre = Pre(header, lines) |
| 210 | self:insert(pre) |
| 211 | end |
| 212 | |
| 213 | ---@param item lc.interpreter_response |
| 214 | |
| 215 | self:clear() |
| 216 | self:set_opts({ spacing = 1 }) |
| 217 | |
| 218 | local handlers = { |
| 219 | -- runtime |
| 220 | [10] = function() |
| 221 | self:handle_runtime(item --[[@as lc.runtime]]) |
| 222 | end, |
| 223 | [11] = function() |
| 224 | self:handle_submission_error(item --[[@as lc.submission]]) |
| 225 | end, |
| 226 | |
| 227 | -- memory limit |
| 228 | [12] = function() |
| 229 | self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]]) |
| 230 | end, |
| 231 | -- time limit |
| 232 | [13] = function() |
| 233 | self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]]) |
| 234 | end, |
| 235 | -- output limit |
| 236 | [14] = function() |
| 237 | self:handle_limit_exceeded(item --[[@as lc.limit_exceeded_error]]) |
| 238 | end, |
| 239 | |
| 240 | -- runtime error |
| 241 | [15] = function() |
| 242 | self:handle_runtime_error(item --[[@as lc.runtime_error]]) |
| 243 | end, |
| 244 | |
| 245 | -- internal error |
| 246 | [16] = function() |
| 247 | self:handle_internal_error(item --[[@as lc.internal_error]]) |
| 248 | end, |
| 249 | |
| 250 | -- compiler |
| 251 | [20] = function() |
| 252 | self:handle_compile_error(item --[[@as lc.compile_error]]) |
| 253 | end, |
| 254 | |
| 255 | -- unknown |
| 256 | ["unknown"] = function() |
| 257 | log.error("unknown runner status code: " .. item.status_code) |
| 258 | end, |
| 259 | } |
| 260 | |
| 261 | local handler = handlers[item.status_code] |
| 262 | if handler then |
| 263 | handler() |
| 264 | else |
| 265 | handlers["unknown"]() |
| 266 | end |
| 267 | end |
| 268 | |
| 269 | ---@param parent lc.ui.Console |
| 270 | |
| 271 | ResultLayout.super.init(self, {}, { spacing = 1 }) |
| 272 | |
| 273 | self.parent = parent |
| 274 | end |
| 275 | |
| 276 | ---@type fun(parent: lc.ui.Console): lc.ui.Result |
| 277 | local LeetResultLayout = ResultLayout |
| 278 | |
| 279 | return LeetResultLayout |