6

So I have read :help scroll-cursor and really like zz, which puts the line your cursor is on in the middle of your window.

I'm looking for help to make a mapping that would perform similar to zz but puts the line my cursor is on at 20% of the window height (or 25%, 30% etc).


Edit:

Thanks to ZyX and Drasill, I was able to modify his function to get the desired functionality:

function ScrollToPercent(percent)
    let movelines=winheight(0)*a:percent/100

    if has("float") && type(movelines)==type(0.0)
        let movelines=float2nr(movelines)
    endif

    let oldso=&so
    execute ":set so=" . movelines
    execute "normal! zt"
    execute ":set so=" . oldso
endfunction
Nick Canzoneri
  • 3,684
  • 1
  • 21
  • 17

4 Answers4

13

This is not specifically an answer to your question, but you might like the scrolloff option.

For example: :set scrolloff=5 will always leave 5 visible lines at the start and the end of your window.

So, when you use zt or zb, your cursor will go 5 lines under top (or 5 lines above bottom, respectively), which can almost be your desired 20%.

I personally love this setting.

:help scrolloff
OmarOthman
  • 1,588
  • 2
  • 17
  • 35
Drasill
  • 3,479
  • 25
  • 30
5

function ScrollToPercent(percent)
    let curlnr=line('.')
    let targetlnr=line('w0')+(winheight(0)*a:percent/100)
    let movelines=targetlnr-curlnr
    if movelines<0
        let motion='k'
        let movelines=-movelines
    elseif movelines>0
        let motion='j'
    else
        return 0
    endif
    if has("float") && type(movelines)==type(0.0)
         let movelines=float2nr(movelines)
    endif
    execute "normal! ".movelines.motion
endfunction
Sorry, this function changes the current line, while you need to change the window position of the current line. Here is the right one:

function! ScrollToPercent(percent)
    let movelines=winheight(0)*(50-a:percent)/100
    echo movelines
    if movelines<0
        let motion='k'
        let rmotion='j'
        let movelines=-movelines
    elseif movelines>0
        let motion='j'
        let rmotion='k'
    else
        return 0
    endif
    if has('float') && type(movelines)==type(0.0)
        let movelines=float2nr(movelines)
    endif
    execute 'normal! zz'.movelines.motion.'zz'.movelines.rmotion
endfunction

Put this function in your .vimrc and define a mapping, such as:

nnoremap z%2 :<C-u>call ScrollToPercent(20)<CR>
ZyX
  • 49,123
  • 7
  • 101
  • 128
  • Thanks for the example, but this function only moves the cursor, not the cursor and the line under the cursor. See my above edit for my end result. – Nick Canzoneri Jun 23 '10 at 17:54
  • @Nick Canzoneri Just was updating my function while you was writing this comment. – ZyX Jun 23 '10 at 17:55
2

Somewhat related, I've got ^J mapped to move the cursor down one line & then recenter the screen:

map <C-J> jzz
map <C-K> kzz

You could subsitute in your scroll-to-percent mapping in place of zz.

Anyway, this has the effect of leaving the cursor in the middle of the screen while text scrolls by behind it - I often use this instead of normal j/k.

John Hart
  • 5,097
  • 2
  • 17
  • 11
0

I take it you know about zb and zt which scrolls the current line to the bottom or top, respectively?

Walter
  • 7,159
  • 1
  • 27
  • 30