Files
tiny-spark.nvim/lua/tiny-spark/init.lua
T
swaits a41b935da1
CI / lint (push) Canceled after 0s
CI / test (push) Canceled after 0s
feat: initial release
2026-04-09 17:58:52 -06:00

93 lines
2.9 KiB
Lua

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