I am implementing a smooth scrolling function for <C-u>
and <C-d>
, which just sleeps for a few milliseconds and then moves the screen up (<C-y>
) or down (<C-e>
) one line:
function SmoothScroll(up)
if a:up
let scrollaction= "\<C-y>"
else
let scrollaction="\<C-e>"
endif
let s=&scroll " total lines to scroll
let x=0 " counts from 0 to s
let T=10 " maximum sleep ms for smoothing
let a=3 " smoothing amount
let p=2 " must be at least 2
let m=s/p " number of lines for which is being smoothed
while x < s
let time=T*((x-m)*(x-s+m)*(x+m/a)*(x-s-m/a))/(m*(s-m)*(-m/a)*(s+m/a))
if time > 0
exec "sleep ".time."m"
end
let x+=1
redraw
exec "normal " . scrollaction
endwhile
endfunction
nnoremap <C-U> :call SmoothScroll(1)<Enter>
nnoremap <C-D> :call SmoothScroll(0)<Enter>
inoremap <C-U> <Esc>:call SmoothScroll(1)<Enter>i
inoremap <C-D> <Esc>:call SmoothScroll(0)<Enter>i
The function for time
is visualized here:
https://www.desmos.com/calculator/of6hhoo1p3
The problem now is that <C-y>
and <C-e>
move the cursor when the cursor comes closer to the screen edge than scrolloff
lines. So when you repeatedly <C-y>
, the cursor ends up at least scrolloff
lines above the bottom of the screen. And when you repeatedly <C-e>
the cursor ends up at least scrolloff
lines below the top of the screen. However when I use <C-u>
and <C-d>
I would like the cursor to stay where it is on the screen.
Is there maybe a way to move both cursor and screen at the same time? I do not want to call both <C-y>
and k
for example, because if my scrolloff
variable was greater than half the lines on my screen (to always keep the cursor centered, which I occasionally want to use), then <C-u>
would scroll twice as far.