A Neovim plugin enabling you to solve LeetCode problems.
feat: support for rendering images with `image.nvim`
5 files changed, +70 -11
+2-1.neoconf.json
| @@ -7,7 +7,8 @@ | ||
| 7 | 7 | "telescope.nvim", |
| 8 | 8 | "plenary.nvim", |
| 9 | 9 | "nui.nvim", |
| 10 | - "nvim-web-devicons" | |
| 10 | + "nvim-web-devicons", | |
| 11 | + "image.nvim" | |
| 11 | 12 | ] |
| 12 | 13 | } |
| 13 | 14 | } |
+15-0README.md
| @@ -130,6 +130,9 @@ To see full configuration types see [template.lua](./lua/leetcode/config/templat | ||
| 130 | 130 | ---@type fun(question: { lang: string })[] |
| 131 | 131 | LeetQuestionNew = {}, |
| 132 | 132 | }, |
| 133 | + | |
| 134 | + ---@type boolean | |
| 135 | + image_support = false, -- setting this to `true` will disable question description wrap | |
| 133 | 136 | } |
| 134 | 137 | ``` |
| 135 | 138 | |
| @@ -199,6 +202,15 @@ hooks = { | ||
| 199 | 202 | }, |
| 200 | 203 | ``` |
| 201 | 204 | |
| 205 | +### image support | |
| 206 | + | |
| 207 | +Whether to render question description images using [image.nvim] | |
| 208 | + | |
| 209 | +```lua | |
| 210 | +---@type boolean | |
| 211 | +image_support = false, -- setting this to `true` will disable question description wrap | |
| 212 | +``` | |
| 213 | + | |
| 202 | 214 | ## 📋 Commands |
| 203 | 215 | |
| 204 | 216 | ### `Leet` opens menu dashboard |
| @@ -274,10 +286,12 @@ local leet_arg = "leetcode.nvim" | ||
| 274 | 286 | |
| 275 | 287 | return { |
| 276 | 288 | "kawre/leetcode.nvim", |
| 289 | + ... | |
| 277 | 290 | lazy = leet_arg ~= vim.fn.argv()[1], |
| 278 | 291 | opts = { |
| 279 | 292 | arg = leet_arg, |
| 280 | 293 | }, |
| 294 | + ... | |
| 281 | 295 | } |
| 282 | 296 | ``` |
| 283 | 297 | |
| @@ -295,6 +309,7 @@ return { | ||
| 295 | 309 | |
| 296 | 310 | - [alpha-nvim](https://github.com/goolord/alpha-nvim) |
| 297 | 311 | |
| 312 | +[image.nvim]: https://github.com/3rd/image.nvim | |
| 298 | 313 | [lazy.nvim]: https://github.com/folke/lazy.nvim |
| 299 | 314 | [leetcode]: https://leetcode.com |
| 300 | 315 | [leetcode.nvim]: https://github.com/kawre/leetcode.nvim |
+3-0lua/leetcode/config/template.lua
| @@ -93,6 +93,9 @@ local M = { | ||
| 93 | 93 | ---@type fun(question: { lang: string })[] |
| 94 | 94 | LeetQuestionNew = {}, |
| 95 | 95 | }, |
| 96 | + | |
| 97 | + ---@type boolean | |
| 98 | + image_support = false, -- setting this to `true` will disable question description wrap | |
| 96 | 99 | } |
| 97 | 100 | |
| 98 | 101 | return M |
+9-0lua/leetcode/parser/html.lua
| @@ -165,6 +165,15 @@ function Html:handle_link(text, tag_data) | ||
| 165 | 165 | if attr.name == "src" then return attr end |
| 166 | 166 | end, tag_data.attrs)[1] or {} |
| 167 | 167 | link = src.value or "" |
| 168 | + | |
| 169 | + -- local bufnr = vim.api.nvim_get_current_buf() | |
| 170 | + -- local image = image_api.from_url(link, { | |
| 171 | + -- -- buffer = bufnr, | |
| 172 | + -- -- with_virtual_padding = true, | |
| 173 | + -- }, function(image) | |
| 174 | + -- -- | |
| 175 | + -- image:render() | |
| 176 | + -- end) | |
| 168 | 177 | end |
| 169 | 178 | |
| 170 | 179 | local line = NuiLine() |
+41-10lua/leetcode/ui/description.lua
| @@ -1,4 +1,9 @@ | ||
| 1 | 1 | local config = require("leetcode.config") |
| 2 | +local log = require("leetcode.logger") | |
| 3 | + | |
| 4 | +local img_ok, image_api = pcall(require, "image") | |
| 5 | +local img_sup = img_ok and config.user.image_support | |
| 6 | + | |
| 2 | 7 | local parser = require("leetcode.parser") |
| 3 | 8 | |
| 4 | 9 | local Layout = require("leetcode-ui.layout") |
| @@ -15,6 +20,7 @@ local Split = require("nui.split") | ||
| 15 | 20 | ---@field title any |
| 16 | 21 | ---@field layout lc-ui.Layout |
| 17 | 22 | ---@field visible boolean |
| 23 | +---@field images table<string, Image> | |
| 18 | 24 | local description = {} |
| 19 | 25 | description.__index = description |
| 20 | 26 | |
| @@ -45,7 +51,7 @@ function description:mount() | ||
| 45 | 51 | }) |
| 46 | 52 | utils.set_win_opts(self.split.winid, { |
| 47 | 53 | winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder", |
| 48 | - wrap = true, | |
| 54 | + wrap = not img_sup, | |
| 49 | 55 | colorcolumn = "", |
| 50 | 56 | foldlevel = 999, |
| 51 | 57 | foldcolumn = "1", |
| @@ -57,6 +63,9 @@ function description:mount() | ||
| 57 | 63 | spell = false, |
| 58 | 64 | signcolumn = "no", |
| 59 | 65 | }) |
| 66 | + if not img_ok and config.user.image_support then | |
| 67 | + log.error("image.nvim not found but `image_support` is enabled") | |
| 68 | + end | |
| 60 | 69 | |
| 61 | 70 | self:draw() |
| 62 | 71 | self:autocmds() |
| @@ -74,16 +83,37 @@ function description:toggle() | ||
| 74 | 83 | end |
| 75 | 84 | |
| 76 | 85 | function description:draw() |
| 77 | - -- local c = vim.api.nvim_win_get_cursor(self.split.winid) | |
| 78 | 86 | self.layout:draw(self.split) |
| 79 | - -- vim.api.nvim_win_set_cursor(self.split.winid, c) | |
| 87 | + self:draw_imgs() | |
| 80 | 88 | end |
| 81 | 89 | |
| 82 | --- function description:redraw() | |
| 83 | --- local c = vim.api.nvim_win_get_cursor(self.split.winid) | |
| 84 | --- self.layout:draw() | |
| 85 | --- vim.api.nvim_win_set_cursor(self.split.winid, c) | |
| 86 | --- end | |
| 90 | +function description:draw_imgs() | |
| 91 | + if not img_sup then return end | |
| 92 | + | |
| 93 | + local lines = vim.api.nvim_buf_get_lines(self.split.bufnr, 1, -1, false) | |
| 94 | + for i, line in ipairs(lines) do | |
| 95 | + for link in line:gmatch("->%((http[s]?://%S+)%)") do | |
| 96 | + local img = self.images[link] | |
| 97 | + | |
| 98 | + if not img then | |
| 99 | + self.images[link] = {} | |
| 100 | + | |
| 101 | + image_api.from_url(link, { | |
| 102 | + buffer = self.split.bufnr, | |
| 103 | + window = self.split.winid, | |
| 104 | + with_virtual_padding = true, | |
| 105 | + }, function(image) | |
| 106 | + if not image then return end | |
| 107 | + | |
| 108 | + self.images[link] = image | |
| 109 | + image:render({ y = i + 1 }) | |
| 110 | + end) | |
| 111 | + elseif not vim.tbl_isempty(img) then | |
| 112 | + img:clear(true) | |
| 113 | + end | |
| 114 | + end | |
| 115 | + end | |
| 116 | +end | |
| 87 | 117 | |
| 88 | 118 | ---@private |
| 89 | 119 | function description:populate() |
| @@ -147,14 +177,15 @@ function description:init(parent) | ||
| 147 | 177 | focusable = true, |
| 148 | 178 | }) |
| 149 | 179 | |
| 150 | - local obj = setmetatable({ | |
| 180 | + self = setmetatable({ | |
| 151 | 181 | split = split, |
| 152 | 182 | parent = parent, |
| 153 | 183 | layout = {}, |
| 154 | 184 | visible = false, |
| 185 | + images = {}, | |
| 155 | 186 | }, self) |
| 156 | 187 | |
| 157 | - return obj:mount() | |
| 188 | + return self:mount() | |
| 158 | 189 | end |
| 159 | 190 | |
| 160 | 191 | return description |