1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
local Dir = {
UP = 1,
DOWN = 2,
}
local function smooth_scroll(dir)
local view, start_pos, buf_line_count, win_height =
vim.fn.winsaveview(),
vim.api.nvim_win_get_cursor(0),
vim.api.nvim_buf_line_count(0),
vim.api.nvim_win_get_height(0)
local duration, sleep_duration = 100, 16 -- 60 fps
local max_distance = dir == Dir.DOWN and buf_line_count - start_pos[1] or start_pos[1] - 1
local distance = math.min(max_distance, math.floor(win_height / 2))
local steps_number = math.ceil(duration / sleep_duration) -- We want a movement every `sleep_duration` msec
local step = distance / steps_number
for i = 1, steps_number do
vim.defer_fn(function()
local offset = math.ceil(step * i) * (dir == Dir.DOWN and 1 or -1)
local new_pos = { start_pos[1] + offset, start_pos[2] }
vim.api.nvim_win_set_cursor(0, new_pos)
local new_topline = math.max(1, view.topline + offset)
if buf_line_count - new_topline >= win_height then -- don't move viewport beyond eof (DOWN) or first line (UP)
vim.fn.winrestview({ lnum = view.lnum + offset, topline = new_topline }) -- move viewport
end
end, sleep_duration * i)
end
end
vim.api.nvim_create_user_command("ScrollSmoothDown", function()
smooth_scroll(Dir.DOWN)
end, { desc = "Scroll down smoothly" })
vim.api.nvim_create_user_command("ScrollSmoothUp", function()
smooth_scroll(Dir.UP)
end, { desc = "Scroll up smoothly" })
|