irongit

A Neovim plugin enabling you to solve LeetCode problems.

196 lines5.3 KBLua
1local config = require("leetcode.config")
2local img_ok, image_api = pcall(require, "image")
3local img_sup = img_ok and config.user.image_support
4
5local Group = require("leetcode-ui.group")
6local Padding = require("leetcode-ui.lines.padding")
7local Split = require("leetcode-ui.split")
8local Parser = require("leetcode.parser")
9
10local log = require("leetcode.logger")
11local utils = require("leetcode.utils")
12
13local t = require("leetcode.translator")
14
15---@class lc.ui.Description : lc-ui.Split
16---@field question lc.ui.Question
17---@field images table<string, Image>
18local Description = Split:extend("LeetDescription")
19
20local group_id = vim.api.nvim_create_augroup("leetcode_description", { clear = true })
21
22function Description:autocmds()
23 vim.api.nvim_create_autocmd("WinResized", {
24 group = group_id,
25 buffer = self.bufnr,
26 callback = function()
27 self:draw()
28 end,
29 })
30end
31
32function Description:mount()
33 Description.super.mount(self)
34 self:populate()
35
36 local ui_utils = require("leetcode-ui.utils")
37 ui_utils.buf_set_opts(self.bufnr, {
38 modifiable = false,
39 buflisted = false,
40 matchpairs = "",
41 swapfile = false,
42 buftype = "nofile",
43 filetype = config.name,
44 synmaxcol = 0,
45 })
46 ui_utils.win_set_opts(self.winid, {
47 winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder",
48 wrap = not img_sup,
49 colorcolumn = "",
50 foldlevel = 999,
51 foldcolumn = "1",
52 cursorcolumn = false,
53 cursorline = false,
54 number = false,
55 relativenumber = false,
56 list = false,
57 spell = false,
58 signcolumn = "no",
59 linebreak = true,
60 })
61 ui_utils.win_set_winfixbuf(self.winid)
62
63 if not img_ok and config.user.image_support then
64 log.error("image.nvim not found but `image_support` is enabled")
65 end
66
67 self:draw()
68 self:autocmds()
69 return self
70end
71
72function Description:draw()
73 Description.super.draw(self)
74 self:draw_imgs()
75end
76
77function Description:draw_imgs()
78 if not img_sup then
79 return
80 end
81
82 local lines = vim.api.nvim_buf_get_lines(self.bufnr, 1, -1, false)
83 for i, line in ipairs(lines) do
84 for link in line:gmatch("%((http[s]?://%S+)%)") do
85 local img = self.images[link]
86
87 if not img then
88 self.images[link] = {}
89
90 image_api.from_url(link, {
91 buffer = self.bufnr,
92 window = self.winid,
93 with_virtual_padding = true,
94 }, function(image)
95 if not image then
96 return
97 end
98
99 self.images[link] = image
100 image:render({ y = i + 1 })
101 end)
102 elseif not vim.tbl_isempty(img) then
103 img:clear(true)
104 end
105 end
106 end
107end
108
109function Description:toggle_stats()
110 self.show_stats = not self.show_stats
111 self:populate()
112 self:draw()
113end
114
115---@private
116function Description:populate()
117 local q = self.question.q
118
119 local header = Group({}, {
120 position = "center",
121 })
122
123 header:append(self.question.cache.link or "", "leetcode_alt")
124 header:endgrp()
125
126 header:insert(Padding(1))
127
128 header:append(q.frontend_id .. ". ", "leetcode_normal")
129 header:append(utils.translate(q.title, q.translated_title))
130 if q.is_paid_only then
131 header:append(" " .. t("Premium"), "leetcode_medium")
132 end
133 header:endgrp()
134
135 local show_stats = self.show_stats
136
137 if show_stats then
138 header:append(t(q.difficulty), "leetcode_" .. q.difficulty:lower())
139 else
140 header:append("????", "leetcode_list")
141 end
142
143 if config.icons.hl.status[self.question.cache.status] then
144 local s = config.icons.hl.status[self.question.cache.status]
145 header:append(" "):append(s[1], s[2])
146 end
147
148 header:append((" %s "):format(config.icons.bar))
149
150 local likes = show_stats and q.likes or "___"
151 header:append(likes .. "", "leetcode_alt")
152
153 local dislikes = show_stats and q.dislikes or "___"
154 if not config.is_cn then
155 header:append((" %s "):format(dislikes), "leetcode_alt")
156 end
157
158 header:append((" %s "):format(config.icons.bar))
159
160 local ac_rate = show_stats and q.stats.acRate or "__%"
161 local total_sub = show_stats and q.stats.totalSubmission or "__"
162 header:append(("%s %s %s"):format(ac_rate, t("of"), total_sub), "leetcode_alt")
163 if not vim.tbl_isempty(q.hints) then
164 header:append((" %s "):format(config.icons.bar))
165 header:append("󰛨 " .. t("Hints"), "leetcode_hint")
166 end
167 header:endgrp()
168
169 local contents = Parser:parse(utils.translate(q.content, q.translated_content))
170
171 self.renderer:replace({
172 header,
173 Padding(3),
174 contents,
175 })
176end
177
178---@param parent lc.ui.Question
179function Description:init(parent)
180 Description.super.init(self, {
181 relative = "editor",
182 position = config.user.description.position,
183 size = config.user.description.width,
184 enter = false,
185 focusable = true,
186 })
187
188 self.question = parent
189 self.show_stats = config.user.description.show_stats
190 self.images = {}
191end
192
193---@type fun(parent: lc.ui.Question): lc.ui.Description
194local LeetDescription = Description
195
196return LeetDescription