terryma / vim-smooth-scroll

Make scrolling in Vim more pleasant
312 stars 36 forks source link

Incorrect behaviour with wrapped text #22

Open manu0600 opened 3 years ago

manu0600 commented 3 years ago

When a line is too long to fit the screen and wrap to the next visible line (it appears as multiple lines on the screen, even though there is only one line number), as seen on the attached screenshot, the command Ctrl-e and Ctrl-y on which the plugin is based make a jump of more than one visible line. The result is when I have many wrapped lines in a text, the smooth scroll scrolls much more than intended, rendering it useless. Screenshot_20200923_102613

Is there a way to change this behavior to the command Ctrl-e and Ctrl-y in the vimrc ? or any other command that can replace it ?

kevinlawler commented 2 years ago

this is the basic fix. if you were integrating it in the production plugin you'd do a few things better.

nmap <silent> <c-u> :call <SID>wrapped_smooth_scroll_page('u',1,4)<CR>
nmap <silent> <c-d> :call <SID>wrapped_smooth_scroll_page('d',1,4)<CR>
nmap <silent> <c-b> :call <SID>wrapped_smooth_scroll_page('u',0,4)<CR>
nmap <silent> <c-f> :call <SID>wrapped_smooth_scroll_page('d',0,4)<CR>

function! s:wrapped_smooth_scroll_page(...)
  " kcl: 2021.10.12 scroll smoothly in the presence of `wrap`
  " Idea: It's actually "logical screen units" so c-f and c-b want to move you to the next one, which will depend on the lines you can't see (and their length/wrapping, and folds) (consider also a case where one line spans multiple screens, but vim cannot put a partial visible line at the top of the screen. minimum 1 line works.) Idea: go up until [what was] the top line is past the bottom, stop at zero, simple `while()`.
  " Remark: It would be better if we could pre-calculate the total lines and pass the total as a batch command to smooth_scroll, or handle ourselves. I suspect any pending delay after a long scroll is due to this, from incorrect buildup

  let lines = 1
  let frames = 1
  let msdelay = 4

  let updown = 'd'
  let half = 0

  if a:0 > 0
    let updown = a:1
  endif

  if a:0 > 1
    let half = a:2
  endif

  if a:0 > 2
    let msdelay = a:3
  endif

  if 'ud' !~# updown
    echom 'Error: Mode string must be either [u]p or [d]own.'
    return
  endif

  let top = line('w0')
  let bottom = line('w$')

  let middle = top + ((bottom - top) / 2)

  let i = 0
  let minimal = 1

  if updown ==# 'u'

    let target = half ? middle : top

    while (line('.') > 1 ) && (i < minimal || target <= line('w$') - &scrolloff)
      call smooth_scroll#up(lines, msdelay, frames)
      let i += 1
    endwhile

  else

    let target = half ? middle : bottom

    while (line('.') <= line('$') ) && (i < minimal || line('w0') + &scrolloff <= target)
      call smooth_scroll#down(lines, msdelay, frames)
      let i += 1
    endwhile

  endif

endfunction