When I press zz at the end of file, the line is displayed at the center of screen by having many empty lines


having empty lines beyond end of file is great, but this is too much. Is there a way to limit the number of empty lines being displayed with zz when approaching the end of file? Say I want at most 10 empty lines beyond the end of file, if zz can not center a line using no more than 10 empty lines, so be it.

Please let me know if I did not make myself clear. Thank you in advance!

  • 1
    I think zb will do what you want? You could remap zz to call zb if it would display empty lines and zz otherwise, but not sure if it's worth it 😅 – Martin Tournoij Jun 16 '20 at 3:31
  • @MartinTournoij Sorry I was not quite clear, I have updated my question! Thanks! – zyy Jun 16 '20 at 4:18
  • :h map-<expr> and :h line(), plus a bit of imagination... – Matt Jun 16 '20 at 5:25

If you're willing to bring a function into the mix I whipped this up. I won't pretend it's super pretty or slick but it seems to do the trick...

func! ModifiedZZ()
    norm! zz
    let max_gap = 10
    let adjust_trigger = 5
    let to_scr_end = winheight(0) - winline()
    let to_buf_end = getpos('$')[1] - getpos('.')[1]
    if to_buf_end < adjust_trigger && to_scr_end > max_gap
        exe "norm! " . (to_scr_end - max_gap) . "\<c-y>"

Along with this override of zz...

nnoremap zz :call ModifiedZZ()<cr>

The script checks cursor position relative to end of buffer and its distance to the bottom of the screen right after the zz movement.

If the cursor is within 5 lines of the end of the buffer but there's a gap of more than 10 between the cursor and window edge then the screen is shifted down, shrinking the gap to no more than 10.

You can tune it by adjusting adjust_trigger and/or max_gap.

Update: Here's a cleaned up, simplified and improved version of the function. With the original function, the logic for adjusting the screen is wacky. Where text will end up afterwards is hard to predict and depends on where the cursor is (though it does fulfill the main objective of limiting the number of gap lines).

With the version below, if after zz is run the number of empty/gap lines is more than l:max_gap_lines then the script will adjust the buffer so that the number of gap lines is exactly l:max_gap_lines. (If line wrapping is turned on and there are wrapping lines after the cursor there may be slight discrepancies...but, hey, this is a freebie what do you want? ;)

What that means is that the function will position the buffer text identically for any cursor position that would cause the baseline zz operation to show more gap lines than allowed. For all other cursor positions the function will operate exactly like baseline zz.

Just try it, you'll see what I mean. :)

func! ModifiedZZ()
    " maximum allowed gap lines (lines beyond buffer text)
    let l:max_gap_lines = 10

    norm! zz
    let l:to_scr_end = winheight(0) - winline()
    let l:to_buf_end = getpos('$')[1] - getpos('.')[1]

    let l:adjustment = l:to_scr_end - l:to_buf_end - l:max_gap_lines
    if l:adjustment > 0
        exe "norm! " . l:adjustment . "\<c-y>"

Notice that there's only one tunable value in this version.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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