feat: initial release
This commit is contained in:
17 files changed
+339
No files matched your search
@@ -0,0 +1,92 @@
|
||||
local M = {}
|
||||
|
||||
function M.setup(opts)
|
||||
opts = opts or {}
|
||||
local threshold = opts.threshold or 3
|
||||
local duration = opts.duration or 50
|
||||
local step = math.ceil(1000 / 60)
|
||||
local prev = { 0, 0 }
|
||||
local ns = vim.api.nvim_create_namespace("tiny-spark")
|
||||
|
||||
local trail_chars = opts.chars or { "░", "▒", "▓", "█" }
|
||||
local palette = opts.palette
|
||||
or {
|
||||
{ fg = "#552200" },
|
||||
{ fg = "#cc4400" },
|
||||
{ fg = "#ff8822" },
|
||||
{ fg = "#ffcc44" },
|
||||
{ fg = "#ffffff", bold = true },
|
||||
}
|
||||
for i, def in ipairs(palette) do
|
||||
vim.api.nvim_set_hl(0, "TinySpark" .. i, def)
|
||||
end
|
||||
|
||||
vim.api.nvim_create_autocmd("CursorMoved", {
|
||||
group = vim.api.nvim_create_augroup("tiny-spark", { clear = true }),
|
||||
callback = function()
|
||||
local cur = vim.api.nvim_win_get_cursor(0)
|
||||
local dy = cur[1] - prev[1]
|
||||
local dx = cur[2] - prev[2]
|
||||
local dist = math.abs(dy)
|
||||
local old_prev = { prev[1], prev[2] }
|
||||
prev = cur
|
||||
if dist < threshold then
|
||||
return
|
||||
end
|
||||
|
||||
local buf = vim.api.nvim_get_current_buf()
|
||||
local line_count = vim.api.nvim_buf_line_count(buf)
|
||||
local dir = dy > 0 and 1 or -1
|
||||
|
||||
-- Build trail from origin to destination
|
||||
local trail = {}
|
||||
for i = 0, dist - 1 do
|
||||
local t = dist > 1 and i / (dist - 1) or 1
|
||||
local row = old_prev[1] - 1 + dir * i
|
||||
local col = old_prev[2] + math.floor(dx * t + 0.5)
|
||||
if row >= 0 and row < line_count and col >= 0 then
|
||||
table.insert(trail, { row = row, col = col })
|
||||
end
|
||||
end
|
||||
|
||||
local elapsed = 0
|
||||
local timer = vim.uv.new_timer()
|
||||
timer:start(
|
||||
0,
|
||||
step,
|
||||
vim.schedule_wrap(function()
|
||||
elapsed = elapsed + step
|
||||
vim.api.nvim_buf_clear_namespace(buf, ns, 0, -1)
|
||||
|
||||
if elapsed >= duration or not vim.api.nvim_buf_is_valid(buf) or #trail == 0 then
|
||||
timer:stop()
|
||||
if not timer:is_closing() then
|
||||
timer:close()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- Shrink trail from origin end (remove the dark/far end first)
|
||||
local progress = elapsed / duration
|
||||
local drop = math.floor(#trail * progress)
|
||||
local start = drop + 1
|
||||
|
||||
for i = start, #trail do
|
||||
local p = trail[i]
|
||||
-- t=0 at start of visible trail (dimmest), t=1 at destination (brightest)
|
||||
local t = (#trail - start) > 0 and (i - start) / (#trail - start) or 1
|
||||
local char_idx = math.max(1, math.min(#trail_chars, math.ceil(t * #trail_chars)))
|
||||
local hl_idx = math.max(1, math.min(#palette, math.ceil(t * #palette)))
|
||||
pcall(vim.api.nvim_buf_set_extmark, buf, ns, p.row, 0, {
|
||||
virt_text = { { trail_chars[char_idx], "TinySpark" .. hl_idx } },
|
||||
virt_text_pos = "overlay",
|
||||
virt_text_win_col = p.col,
|
||||
})
|
||||
end
|
||||
end)
|
||||
)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in new issue
Block a user