1

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.

2 Answers 2

1

Not an answer to your question. But thought I'd mention that this exists: https://github.com/terryma/vim-smooth-scroll

2
  • 1
    thanks for sharing, I found a script for this online earlier, but it didn't work perfectly so I modified it. But this one seems to work find, I will use that!
    – simulate
    Commented Nov 9, 2019 at 18:13
  • In fact, I like my version better! It actually does make a difference that the scroll starts slower, because then it is easier for your eyes to catch on to the quick movement. It is easier to follow where you are in the document. Maybe I will see to make a pull request to our fellow terryma.
    – simulate
    Commented Nov 9, 2019 at 23:58
0

I have now just checked manually whether the cursor is at the border of scrolloff, i.e. if it would be scrolled by <C-y> for example or not, and if not, then I move it manually at each iteration with j or k:

function SmoothScroll(up)
  let cursormov=""
  if a:up
    let scrollaction= "normal \<C-y>"
    " now also check how far the cursor is away
    " from the border, including scrolloff
    let offdist = abs((line("w$") - &scrolloff) - line("."))
    if offdist > 0 || line("w0") < &scroll
      let cursormov="normal k"
    endif
  else
    let scrollaction="normal \<C-e>"
    let offdist = abs(line(".") - (line("w0") + &scrolloff))
    if offdist > 0
      let cursormov="normal j"
    endif
  endif
  let s=&scroll " total lines to scroll
  let x=0   " counts from 0 to s
  let T=2 " maximum sleep ms for smoothing
  let a=2 " 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"
      redraw
    end
    let x+=1
    exec scrollaction
    exec cursormov
  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

There may be a more efficient solution though. But this way the cursor also stays in place while smoothly scrolling.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.