A Neovim plugin enabling you to solve LeetCode problems.
fix: improvements
15 files changed, +89 -121
+2-2lua/leetcode/api/auth.lua
| @@ -17,13 +17,13 @@ end | ||
| 17 | 17 | |
| 18 | 18 | local usr_fields = [[ |
| 19 | 19 | id: userId |
| 20 | + name: username | |
| 20 | 21 | is_signed_in: isSignedIn |
| 21 | 22 | is_premium: isPremium |
| 22 | - name: username | |
| 23 | 23 | is_verified: isVerified |
| 24 | 24 | ]] |
| 25 | 25 | |
| 26 | ----@return lc.UserAuth | |
| 26 | +---@return lc.UserStatus | |
| 27 | 27 | function M.user() |
| 28 | 28 | local query = string.format( |
| 29 | 29 | [[ |
+10-0lua/leetcode/api/types.lua
| @@ -311,3 +311,13 @@ | ||
| 311 | 311 | ---@field _ lc.Interpreter.item |
| 312 | 312 | |
| 313 | 313 | ---@alias lc.submission lc.Interpreter.Response.submission |
| 314 | + | |
| 315 | +-------------------------------------------- | |
| 316 | +--- UserStatus | |
| 317 | +-------------------------------------------- | |
| 318 | +---@class lc.UserStatus | |
| 319 | +---@field name string | |
| 320 | +---@field is_signed_in boolean | |
| 321 | +---@field is_premium boolean | |
| 322 | +---@field is_verified boolean | |
| 323 | +---@field id integer |
+5-2lua/leetcode/command.lua
| @@ -66,7 +66,7 @@ end | ||
| 66 | 66 | |
| 67 | 67 | ---Merge configurations into default configurations and set it as user configurations. |
| 68 | 68 | --- |
| 69 | ----@return lc.UserAuth | nil | |
| 69 | +---@return lc.UserStatus | nil | |
| 70 | 70 | function cmd.authenticate() require("leetcode.api.auth").user() end |
| 71 | 71 | |
| 72 | 72 | ---Merge configurations into default configurations and set it as user configurations. |
| @@ -90,7 +90,10 @@ function cmd.random_question() | ||
| 90 | 90 | end |
| 91 | 91 | end |
| 92 | 92 | |
| 93 | -function cmd.menu() vim.api.nvim_set_current_tabpage(_Lc_MenuTabPage) end | |
| 93 | +function cmd.menu() | |
| 94 | + local ok, tabp = pcall(vim.api.nvim_win_get_tabpage, _Lc_Menu.winid) | |
| 95 | + if ok then vim.api.nvim_set_current_tabpage(tabp) end | |
| 96 | +end | |
| 94 | 97 | |
| 95 | 98 | ---@param layout layouts |
| 96 | 99 | function cmd.menu_layout(layout) _Lc_Menu:set_layout(layout) end |
+9-7lua/leetcode/config/init.lua
| @@ -1,5 +1,11 @@ | ||
| 1 | 1 | local template = require("leetcode.config.template") |
| 2 | 2 | |
| 3 | +---@type lc.Question[] | |
| 4 | +_Lc_questions = {} | |
| 5 | + | |
| 6 | +---@type lc-menu | |
| 7 | +_Lc_Menu = {} ---@diagnostic disable-line | |
| 8 | + | |
| 3 | 9 | ---@class lc.Settings |
| 4 | 10 | local config = { |
| 5 | 11 | default = template, |
| @@ -14,14 +20,10 @@ local config = { | ||
| 14 | 20 | |
| 15 | 21 | langs = require("leetcode.config.langs"), |
| 16 | 22 | icons = require("leetcode.config.icons"), |
| 17 | -} | |
| 18 | 23 | |
| 19 | ----@class lc.UserAuth | |
| 20 | ----@field name string | |
| 21 | ----@field is_signed_in boolean | |
| 22 | ----@field is_premium boolean | |
| 23 | ----@field id integer | |
| 24 | -config.auth = {} | |
| 24 | + ---@diagnostic disable-next-line | |
| 25 | + auth = {}, ---@type lc.UserStatus | |
| 26 | +} | |
| 25 | 27 | |
| 26 | 28 | ---Merge configurations into default configurations and set it as user configurations. |
| 27 | 29 | --- |
+3-0lua/leetcode/parser/init.lua
| @@ -1,3 +1,6 @@ | ||
| 1 | +---TODO: 2659 | |
| 2 | +---TODO: https://leetcode.com/problems/make-array-empty/ | |
| 3 | + | |
| 1 | 4 | local Text = require("leetcode-ui.component.text") |
| 2 | 5 | local utils = require("leetcode.parser.utils") |
| 3 | 6 | local log = require("leetcode.logger") |
+9-3lua/leetcode/pickers/question-tabs.lua
| @@ -31,12 +31,18 @@ local function display_difficulty(q) | ||
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | local lang = utils.get_lang(q.lang) |
| 34 | - return { lang.short, hl[q.q.difficulty] } | |
| 34 | + return { lang.icon } | |
| 35 | 35 | end |
| 36 | 36 | |
| 37 | 37 | ---@param question lc.Cache.Question |
| 38 | 38 | local function display_question(question) |
| 39 | - local index = { question.frontend_id .. ".", "leetcode_normal" } | |
| 39 | + local hl = { | |
| 40 | + ["Easy"] = "leetcode_easy", | |
| 41 | + ["Medium"] = "leetcode_medium", | |
| 42 | + ["Hard"] = "leetcode_hard", | |
| 43 | + } | |
| 44 | + | |
| 45 | + local index = { question.frontend_id .. ".", hl[question.difficulty] } | |
| 40 | 46 | local title = { question.title } |
| 41 | 47 | |
| 42 | 48 | return unpack({ index, title }) |
| @@ -46,7 +52,7 @@ local displayer = entry_display.create({ | ||
| 46 | 52 | separator = " ", |
| 47 | 53 | items = { |
| 48 | 54 | { width = 1 }, |
| 49 | - { width = 5 }, | |
| 55 | + { width = 1 }, | |
| 50 | 56 | { width = 5 }, |
| 51 | 57 | { remaining = true }, |
| 52 | 58 | }, |
+9-5lua/leetcode/theme/default.lua
| @@ -1,3 +1,5 @@ | ||
| 1 | +local M = {} | |
| 2 | + | |
| 1 | 3 | ---Get highlight group value by name. |
| 2 | 4 | --- |
| 3 | 5 | ---@param name string String for looking up highlight group. |
| @@ -17,8 +19,8 @@ local function hl(name) | ||
| 17 | 19 | end |
| 18 | 20 | |
| 19 | 21 | ---@alias lc.highlights table<string, table> |
| 20 | ----@type lc.highlights | |
| 21 | -return function() | |
| 22 | +---@return lc.highlights | |
| 23 | +M.get = function() | |
| 22 | 24 | return { |
| 23 | 25 | easy = { fg = "#46c6c2" }, |
| 24 | 26 | medium = { fg = "#fac31d" }, |
| @@ -29,11 +31,11 @@ return function() | ||
| 29 | 31 | hint = { fg = hl("DiagnosticHint").fg }, |
| 30 | 32 | error = { fg = hl("DiagnosticError").fg }, |
| 31 | 33 | |
| 32 | - bold = { bold = true }, | |
| 34 | + alt = { fg = hl("Comment").fg }, | |
| 35 | + normal = { fg = hl("FloatTitle").fg }, | |
| 33 | 36 | italic = { fg = hl("FloatTitle").fg, italic = true }, |
| 37 | + bold = { bold = true }, | |
| 34 | 38 | |
| 35 | - normal = { fg = hl("FloatTitle").fg }, | |
| 36 | - alt = { fg = hl("Comment").fg }, | |
| 37 | 39 | code = { fg = hl("Type").fg, bg = hl("Normal").bg }, |
| 38 | 40 | example = { fg = hl("DiagnosticHint").fg }, |
| 39 | 41 | constraints = { fg = hl("DiagnosticInfo").fg }, |
| @@ -42,3 +44,5 @@ return function() | ||
| 42 | 44 | list = { fg = hl("Tag").fg }, |
| 43 | 45 | } |
| 44 | 46 | end |
| 47 | + | |
| 48 | +return M |
+1-1lua/leetcode/theme/init.lua
| @@ -2,7 +2,7 @@ | ||
| 2 | 2 | local theme = {} |
| 3 | 3 | |
| 4 | 4 | function theme.load() |
| 5 | - local default = require("leetcode.theme.default")() | |
| 5 | + local default = require("leetcode.theme.default").get() | |
| 6 | 6 | for key, t in pairs(default) do |
| 7 | 7 | key = "leetcode_" .. key |
| 8 | 8 | vim.api.nvim_set_hl(0, key, t) |
+3-3lua/leetcode/ui/description.lua
| @@ -32,10 +32,10 @@ function description:mount() | ||
| 32 | 32 | self.visible = true |
| 33 | 33 | self:populate() |
| 34 | 34 | self.split:mount() |
| 35 | - self:draw() | |
| 36 | 35 | |
| 37 | 36 | local utils = require("leetcode-menu.utils") |
| 38 | - utils.apply_opt_local({ | |
| 37 | + utils.apply_opt_local(self.split.winid, { | |
| 38 | + winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder", | |
| 39 | 39 | buflisted = false, |
| 40 | 40 | matchpairs = "", |
| 41 | 41 | swapfile = false, |
| @@ -54,9 +54,9 @@ function description:mount() | ||
| 54 | 54 | list = false, |
| 55 | 55 | spell = false, |
| 56 | 56 | signcolumn = "no", |
| 57 | - winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder", | |
| 58 | 57 | }) |
| 59 | 58 | |
| 59 | + self:draw() | |
| 60 | 60 | self:autocmds() |
| 61 | 61 | return self |
| 62 | 62 | end |
+4-5lua/leetcode/ui/hints.lua
| @@ -11,14 +11,14 @@ local Hints = {} | ||
| 11 | 11 | Hints.__index = Hints |
| 12 | 12 | |
| 13 | 13 | function Hints:mount() |
| 14 | - log.debug(self) | |
| 15 | 14 | self.popup:mount() |
| 15 | + | |
| 16 | 16 | local utils = require("leetcode-menu.utils") |
| 17 | - utils.apply_opt_local({ wrap = true }) | |
| 17 | + utils.apply_opt_local(self.popup.winid, { wrap = true }) | |
| 18 | 18 | |
| 19 | 19 | local NuiTree = require("nui.tree") |
| 20 | - | |
| 21 | 20 | local nodes = {} |
| 21 | + | |
| 22 | 22 | for i, hint in ipairs(self.hints) do |
| 23 | 23 | local node = NuiTree.Node( |
| 24 | 24 | { text = NuiText(" Hint " .. i, "leetcode_hint") }, |
| @@ -39,11 +39,10 @@ function Hints:mount() | ||
| 39 | 39 | nodes = nodes, |
| 40 | 40 | prepare_node = function(node) |
| 41 | 41 | local line = NuiLine() |
| 42 | - | |
| 43 | 42 | line:append(string.rep(" ", node:get_depth() - 1)) |
| 44 | 43 | |
| 45 | 44 | if node:has_children() then |
| 46 | - line:append(node:is_expanded() and " " or " ", "SpecialChar") | |
| 45 | + line:append(node:is_expanded() and " " or " ", "leetcode_list") | |
| 47 | 46 | line:append(node.text) |
| 48 | 47 | else |
| 49 | 48 | if type(node.text) == "string" then |
+0-40lua/leetcode/ui/init.lua
| @@ -18,44 +18,4 @@ end | ||
| 18 | 18 | |
| 19 | 19 | function Ui.input(opts, callback) vim.ui.input(opts, callback) end |
| 20 | 20 | |
| 21 | ---@param question lc.Problem | |
| 22 | -function Ui.open_qot() | |
| 23 | - local qot = api_problems.question_of_today() | |
| 24 | - | |
| 25 | - local popup = Popup({ | |
| 26 | - position = "50%", | |
| 27 | - size = { | |
| 28 | - width = 80, | |
| 29 | - height = 40, | |
| 30 | - }, | |
| 31 | - enter = true, | |
| 32 | - focusable = true, | |
| 33 | - zindex = 50, | |
| 34 | - relative = "editor", | |
| 35 | - border = { | |
| 36 | - padding = { | |
| 37 | - top = 2, | |
| 38 | - bottom = 2, | |
| 39 | - left = 3, | |
| 40 | - right = 3, | |
| 41 | - }, | |
| 42 | - style = "rounded", | |
| 43 | - text = { | |
| 44 | - top = " I am top title ", | |
| 45 | - top_align = "center", | |
| 46 | - bottom = "I am bottom title", | |
| 47 | - bottom_align = "left", | |
| 48 | - }, | |
| 49 | - }, | |
| 50 | - buf_options = { | |
| 51 | - modifiable = true, | |
| 52 | - readonly = false, | |
| 53 | - }, | |
| 54 | - win_options = { | |
| 55 | - winblend = 10, | |
| 56 | - winhighlight = "Normal:Normal,FloatBorder:FloatBorder", | |
| 57 | - }, | |
| 58 | - }) | |
| 59 | -end | |
| 60 | - | |
| 61 | 21 | return Ui |
+19-27lua/leetcode/ui/question.lua
| @@ -52,8 +52,8 @@ function Question:mount() | ||
| 52 | 52 | vim.cmd("$tabe " .. self.file:absolute()) |
| 53 | 53 | |
| 54 | 54 | self.bufnr = vim.api.nvim_get_current_buf() |
| 55 | - _Lc_curr_question = self.bufnr | |
| 56 | - _Lc_questions[_Lc_curr_question] = self | |
| 55 | + self.winid = vim.api.nvim_get_current_win() | |
| 56 | + table.insert(_Lc_questions, self) | |
| 57 | 57 | |
| 58 | 58 | self.description = Description:init(self) |
| 59 | 59 | self.console = Console:init(self) |
| @@ -64,31 +64,23 @@ function Question:mount() | ||
| 64 | 64 | end |
| 65 | 65 | |
| 66 | 66 | function Question:autocmds() |
| 67 | - local group_id = vim.api.nvim_create_augroup("leetcode_questions", { clear = true }) | |
| 68 | - vim.api.nvim_create_autocmd("TabEnter", { | |
| 69 | - group = group_id, | |
| 70 | - callback = function() | |
| 71 | - local questions = utils.curr_question_tabs() | |
| 72 | - | |
| 73 | - local tabpage = vim.api.nvim_get_current_tabpage() | |
| 74 | - for _, q in ipairs(questions) do | |
| 75 | - if q.tabpage == tabpage then _Lc_curr_question = q.question.bufnr end | |
| 76 | - end | |
| 77 | - end, | |
| 78 | - }) | |
| 79 | - | |
| 80 | - local q_group_id = vim.api.nvim_create_augroup("leetcode_question", {}) | |
| 81 | - vim.api.nvim_create_autocmd("BufWinEnter", { | |
| 82 | - group = q_group_id, | |
| 83 | - buffer = self.bufnr, | |
| 84 | - callback = function() self.description.split:show() end, | |
| 85 | - }) | |
| 86 | - | |
| 87 | - vim.api.nvim_create_autocmd("BufWinLeave", { | |
| 88 | - group = q_group_id, | |
| 89 | - buffer = self.bufnr, | |
| 90 | - callback = function() self.description.split:hide() end, | |
| 91 | - }) | |
| 67 | + -- local group_id = vim.api.nvim_create_augroup("leetcode_questions", { clear = true }) | |
| 68 | + | |
| 69 | + -- local q_group_id = vim.api.nvim_create_augroup("leetcode_question", {}) | |
| 70 | + -- vim.api.nvim_create_autocmd("BufWinEnter", { | |
| 71 | + -- group = q_group_id, | |
| 72 | + -- buffer = self.bufnr, | |
| 73 | + -- callback = function() | |
| 74 | + -- log.info("wtf") | |
| 75 | + -- self.description.split:show() | |
| 76 | + -- end, | |
| 77 | + -- }) | |
| 78 | + -- | |
| 79 | + -- vim.api.nvim_create_autocmd("BufWinLeave", { | |
| 80 | + -- group = q_group_id, | |
| 81 | + -- buffer = self.bufnr, | |
| 82 | + -- callback = function() self.description.split:hide() end, | |
| 83 | + -- }) | |
| 92 | 84 | end |
| 93 | 85 | |
| 94 | 86 | function Question:handle_mount() |
+10-8lua/leetcode/utils.lua
| @@ -68,19 +68,21 @@ function utils.curr_question_tabs() | ||
| 68 | 68 | ---@type lc.Question.Tab[] |
| 69 | 69 | local questions = {} |
| 70 | 70 | |
| 71 | - for _, tabp in ipairs(vim.api.nvim_list_tabpages()) do | |
| 72 | - local bufs = vim.fn.tabpagebuflist(tabp) | |
| 73 | - | |
| 74 | - for _, bufnr in ipairs(bufs) do | |
| 75 | - if _Lc_questions[bufnr] then | |
| 76 | - table.insert(questions, { tabpage = tabp, question = _Lc_questions[bufnr] }) | |
| 77 | - end | |
| 78 | - end | |
| 71 | + for _, q in ipairs(_Lc_questions) do | |
| 72 | + local tabp = utils.question_tabp(q) | |
| 73 | + if tabp then table.insert(questions, { tabpage = tabp, question = q }) end | |
| 79 | 74 | end |
| 80 | 75 | |
| 81 | 76 | return questions |
| 82 | 77 | end |
| 83 | 78 | |
| 79 | +---@param q lc.Question | |
| 80 | +---@return integer|nil | |
| 81 | +function utils.question_tabp(q) | |
| 82 | + local ok, tabp = pcall(vim.api.nvim_win_get_tabpage, q.winid) | |
| 83 | + if ok then return tabp end | |
| 84 | +end | |
| 85 | + | |
| 84 | 86 | ---@return lc.Question |
| 85 | 87 | function utils.curr_question() |
| 86 | 88 | local tabp = vim.api.nvim_get_current_tabpage() |