A Neovim plugin enabling you to solve LeetCode problems.
feat(config)!: replace `directory` with `storage` table
9 files changed, +86 -57
+18-5lua/leetcode-ui/question.lua
| @@ -34,11 +34,25 @@ end | ||
| 34 | 34 | ---@private |
| 35 | 35 | function Question:create_file() |
| 36 | 36 | local lang = utils.get_lang(self.lang) |
| 37 | - local alt = lang.alt and ("-" .. lang.alt) or "" | |
| 37 | + local alt = lang.alt and ("." .. lang.alt) or "" | |
| 38 | + | |
| 39 | + -- handle legacy file names first | |
| 40 | + local fn_legacy = -- | |
| 41 | + ("%s.%s-%s.%s"):format(self.q.frontend_id, self.q.title_slug, lang.slug, lang.ft) | |
| 42 | + self.file = config.storage.home:joinpath(fn_legacy) | |
| 43 | + | |
| 44 | + if self.file:exists() then -- | |
| 45 | + return self.file:absolute() | |
| 46 | + end | |
| 47 | + | |
| 38 | 48 | local fn = ("%s.%s%s.%s"):format(self.q.frontend_id, self.q.title_slug, alt, lang.ft) |
| 49 | + self.file = config.storage.home:joinpath(fn) | |
| 39 | 50 | |
| 40 | - self.file = config.home:joinpath(fn) | |
| 41 | - if not self.file:exists() then self.file:write(self:get_snippet(), "w") end | |
| 51 | + if not self.file:exists() then -- | |
| 52 | + self.file:write(self:get_snippet(), "w") | |
| 53 | + end | |
| 54 | + | |
| 55 | + return self.file:absolute() | |
| 42 | 56 | end |
| 43 | 57 | |
| 44 | 58 | ---@private |
| @@ -88,8 +102,7 @@ Question.unmount = vim.schedule_wrap(function(self) | ||
| 88 | 102 | end) |
| 89 | 103 | |
| 90 | 104 | function Question:handle_mount() |
| 91 | - self:create_file() | |
| 92 | - vim.cmd("$tabe " .. self.file:absolute()) | |
| 105 | + vim.cmd("$tabe " .. self:create_file()) | |
| 93 | 106 | |
| 94 | 107 | -- https://github.com/kawre/leetcode.nvim/issues/14 |
| 95 | 108 | if self.lang == "rust" then pcall(require("rust-tools.standalone").start_standalone_client) end |
+10-44lua/leetcode.lua
| @@ -3,10 +3,11 @@ local config = require("leetcode.config") | ||
| 3 | 3 | ---@class lc.LeetCode |
| 4 | 4 | local leetcode = {} |
| 5 | 5 | |
| 6 | -function leetcode.should_skip() | |
| 6 | +---@param arg string | |
| 7 | +function leetcode.should_skip(arg) | |
| 7 | 8 | if vim.fn.argc() ~= 1 then return true end |
| 8 | 9 | |
| 9 | - local usr_arg, arg = config.user.arg, vim.fn.argv()[1] | |
| 10 | + local usr_arg = vim.fn.argv()[1] | |
| 10 | 11 | if usr_arg ~= arg then return true end |
| 11 | 12 | |
| 12 | 13 | local lines = vim.api.nvim_buf_get_lines(0, 0, -1, true) |
| @@ -19,48 +20,15 @@ function leetcode.should_skip() | ||
| 19 | 20 | return false |
| 20 | 21 | end |
| 21 | 22 | |
| 22 | -function leetcode.setup_cmds() | |
| 23 | - local cmd = require("leetcode.command") | |
| 24 | - cmd.setup() | |
| 25 | -end | |
| 26 | - | |
| 27 | -function leetcode.validate() | |
| 28 | - local utils = require("leetcode.utils") | |
| 29 | - | |
| 30 | - assert(vim.fn.has("nvim-0.9.0") == 1, "Neovim >= 0.9.0 required") | |
| 23 | +function leetcode.setup_cmds() require("leetcode.command").setup() end | |
| 31 | 24 | |
| 32 | - if not utils.get_lang(config.lang) then -- | |
| 33 | - ---@type lc.lang[] | |
| 34 | - local lang_slugs = vim.tbl_map(function(lang) return lang.slug end, config.langs) | |
| 25 | +---@param cfg lc.UserConfig | |
| 26 | +function leetcode.start(cfg) | |
| 27 | + if leetcode.should_skip(cfg.arg or config.default.arg) then return end | |
| 35 | 28 | |
| 36 | - local matches = {} | |
| 37 | - for _, slug in ipairs(lang_slugs) do | |
| 38 | - local percent = slug:match(config.lang) or config.lang:match(slug) | |
| 39 | - if percent then table.insert(matches, slug) end | |
| 40 | - end | |
| 41 | - | |
| 42 | - if not vim.tbl_isempty(matches) then | |
| 43 | - local log = require("leetcode.logger") | |
| 44 | - log.warn("Did you mean: { " .. table.concat(matches, ", ") .. " }?") | |
| 45 | - end | |
| 46 | - | |
| 47 | - error("Unsupported Language: " .. config.lang) | |
| 48 | - end | |
| 49 | -end | |
| 50 | - | |
| 51 | -function leetcode.start() | |
| 52 | - if leetcode.should_skip() then return end | |
| 53 | - | |
| 54 | - leetcode.validate() | |
| 55 | - | |
| 56 | - local path = require("plenary.path") | |
| 57 | - config.home = path:new(config.user.directory) ---@diagnostic disable-line | |
| 58 | - config.home:mkdir() | |
| 59 | - | |
| 60 | - config.cache_dir = path:new(vim.fn.stdpath("cache") .. "/leetcode/") ---@diagnostic disable-line | |
| 61 | - config.cache_dir:mkdir() | |
| 29 | + config.apply(cfg or {}) | |
| 62 | 30 | |
| 63 | - vim.api.nvim_set_current_dir(config.home:absolute()) | |
| 31 | + vim.api.nvim_set_current_dir(config.storage.home:absolute()) | |
| 64 | 32 | |
| 65 | 33 | leetcode.setup_cmds() |
| 66 | 34 | config.load_plugins() |
| @@ -77,14 +45,12 @@ end | ||
| 77 | 45 | |
| 78 | 46 | ---@param cfg? lc.UserConfig |
| 79 | 47 | function leetcode.setup(cfg) |
| 80 | - config.apply(cfg or {}) | |
| 81 | - | |
| 82 | 48 | local group_id = vim.api.nvim_create_augroup("leetcode_start", { clear = true }) |
| 83 | 49 | vim.api.nvim_create_autocmd("VimEnter", { |
| 84 | 50 | group = group_id, |
| 85 | 51 | pattern = "*", |
| 86 | 52 | nested = true, |
| 87 | - callback = leetcode.start, | |
| 53 | + callback = function() leetcode.start(cfg or {}) end, | |
| 88 | 54 | }) |
| 89 | 55 | end |
| 90 | 56 |
+1-1lua/leetcode/cache/cookie.lua
| @@ -3,7 +3,7 @@ local log = require("leetcode.logger") | ||
| 3 | 3 | |
| 4 | 4 | local config = require("leetcode.config") |
| 5 | 5 | ---@type Path |
| 6 | -local file = config.cache_dir:joinpath(("cookie%s"):format(config.is_cn and "_cn" or "")) | |
| 6 | +local file = config.storage.cache:joinpath(("cookie%s"):format(config.is_cn and "_cn" or "")) | |
| 7 | 7 | |
| 8 | 8 | local hist = {} |
| 9 | 9 |
+1-1lua/leetcode/cache/problemlist.lua
| @@ -6,7 +6,7 @@ local config = require("leetcode.config") | ||
| 6 | 6 | local interval = config.user.cache.update_interval |
| 7 | 7 | |
| 8 | 8 | ---@type Path |
| 9 | -local file = config.cache_dir:joinpath(("problemlist%s"):format(config.is_cn and "_cn" or "")) | |
| 9 | +local file = config.storage.cache:joinpath(("problemlist%s"):format(config.is_cn and "_cn" or "")) | |
| 10 | 10 | |
| 11 | 11 | ---@type { at: integer, payload: lc.cache.payload } |
| 12 | 12 | local hist = nil |
+45-2lua/leetcode/config/init.lua
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | local template = require("leetcode.config.template") |
| 2 | +local P = require("plenary.path") | |
| 2 | 3 | |
| 3 | 4 | ---@type lc.ui.Question[] |
| 4 | 5 | _Lc_questions = {} |
| @@ -16,9 +17,8 @@ local config = { | ||
| 16 | 17 | is_cn = false, |
| 17 | 18 | debug = false, |
| 18 | 19 | lang = "cpp", |
| 19 | - home = {}, ---@type Path | |
| 20 | - cache_dir = {}, ---@type Path | |
| 21 | 20 | version = "1.0.1", |
| 21 | + storage = {}, ---@type table<string, Path> | |
| 22 | 22 | |
| 23 | 23 | translator = false, |
| 24 | 24 | |
| @@ -33,10 +33,53 @@ local config = { | ||
| 33 | 33 | --- |
| 34 | 34 | ---@param cfg lc.UserConfig Configurations to be merged. |
| 35 | 35 | function config.apply(cfg) |
| 36 | + cfg.storage = cfg.storage or {} | |
| 37 | + | |
| 38 | + -- deprecate `directory` config | |
| 39 | + if cfg.directory then | |
| 40 | + local log = require("leetcode.logger") | |
| 41 | + log.warn("Config: `directory` is deprecated. Use `storage.home` instead.") | |
| 42 | + cfg.storage.home = cfg.directory | |
| 43 | + end | |
| 44 | + | |
| 45 | + cfg.storage = vim.tbl_map(vim.fn.expand, cfg.storage) | |
| 46 | + | |
| 36 | 47 | config.user = vim.tbl_deep_extend("force", config.default, cfg) |
| 37 | 48 | |
| 38 | 49 | config.debug = config.user.debug or false ---@diagnostic disable-line |
| 39 | 50 | config.lang = config.user.lang |
| 51 | + | |
| 52 | + config.validate() | |
| 53 | + | |
| 54 | + config.storage.home = P:new(config.user.storage.home) ---@diagnostic disable-line | |
| 55 | + config.storage.home:mkdir() | |
| 56 | + | |
| 57 | + config.storage.cache = P:new(config.user.storage.cache) ---@diagnostic disable-line | |
| 58 | + config.storage.cache:mkdir() | |
| 59 | +end | |
| 60 | + | |
| 61 | +function config.validate() | |
| 62 | + local utils = require("leetcode.utils") | |
| 63 | + | |
| 64 | + assert(vim.fn.has("nvim-0.9.0") == 1, "Neovim >= 0.9.0 required") | |
| 65 | + | |
| 66 | + if not utils.get_lang(config.lang) then -- | |
| 67 | + ---@type lc.lang[] | |
| 68 | + local lang_slugs = vim.tbl_map(function(lang) return lang.slug end, config.langs) | |
| 69 | + | |
| 70 | + local matches = {} | |
| 71 | + for _, slug in ipairs(lang_slugs) do | |
| 72 | + local percent = slug:match(config.lang) or config.lang:match(slug) | |
| 73 | + if percent then table.insert(matches, slug) end | |
| 74 | + end | |
| 75 | + | |
| 76 | + if not vim.tbl_isempty(matches) then | |
| 77 | + local log = require("leetcode.logger") | |
| 78 | + log.warn("Did you mean: { " .. table.concat(matches, ", ") .. " }?") | |
| 79 | + end | |
| 80 | + | |
| 81 | + error("Unsupported Language: " .. config.lang) | |
| 82 | + end | |
| 40 | 83 | end |
| 41 | 84 | |
| 42 | 85 | function config.load_plugins() |
+1-1lua/leetcode/config/langs.lua
| @@ -33,7 +33,7 @@ return { | ||
| 33 | 33 | color = "#306998", |
| 34 | 34 | ft = "py", |
| 35 | 35 | comment = "#", |
| 36 | - alt = "py2", | |
| 36 | + alt = "python2", | |
| 37 | 37 | }, |
| 38 | 38 | { |
| 39 | 39 | lang = "Python3", |
+7-2lua/leetcode/config/template.lua
| @@ -39,6 +39,8 @@ | ||
| 39 | 39 | |
| 40 | 40 | ---@alias lc.inject { before?: string|string[], after?: string|string[] } |
| 41 | 41 | |
| 42 | +---@alias lc.storage table<"cache"|"home", string> | |
| 43 | + | |
| 42 | 44 | ---@class lc.UserConfig |
| 43 | 45 | local M = { |
| 44 | 46 | ---@type string |
| @@ -53,8 +55,11 @@ local M = { | ||
| 53 | 55 | translate_problems = true, ---@type boolean |
| 54 | 56 | }, |
| 55 | 57 | |
| 56 | - ---@type string | |
| 57 | - directory = vim.fn.stdpath("data") .. "/leetcode/", | |
| 58 | + ---@type lc.storage | |
| 59 | + storage = { | |
| 60 | + home = vim.fn.stdpath("data") .. "/leetcode/", | |
| 61 | + cache = vim.fn.stdpath("cache") .. "/leetcode/", | |
| 62 | + }, | |
| 58 | 63 | |
| 59 | 64 | ---@type boolean |
| 60 | 65 | logging = true, |
+2-0lua/leetcode/pickers/question.lua
| @@ -104,11 +104,13 @@ local function filter_questions(questions, opts) | ||
| 104 | 104 | |
| 105 | 105 | ---@param q lc.cache.Question |
| 106 | 106 | return vim.tbl_filter(function(q) |
| 107 | + local flag = true | |
| 107 | 108 | if opts.difficulty then |
| 108 | 109 | if not vim.tbl_contains(opts.difficulty, q.difficulty:lower()) then return false end |
| 109 | 110 | end |
| 110 | 111 | |
| 111 | 112 | if opts.status then |
| 113 | + if not q.status then return true end | |
| 112 | 114 | if not vim.tbl_contains(opts.status, q.status) then return false end |
| 113 | 115 | end |
| 114 | 116 |
+1-1lua/leetcode/runner/init.lua
| @@ -3,7 +3,7 @@ local interpreter = require("leetcode.api.interpreter") | ||
| 3 | 3 | local config = require("leetcode.config") |
| 4 | 4 | |
| 5 | 5 | ---@type Path |
| 6 | -local leetbody = config.cache_dir:joinpath("body") | |
| 6 | +local leetbody = config.storage.cache:joinpath("body") | |
| 7 | 7 | leetbody:touch() |
| 8 | 8 | |
| 9 | 9 | ---@class lc.Runner |