I would like to keep my cursor centered vertically as I type away in insert mode even when I reach the end of the buffer I am editing (at which point I would like the virtual lines starting with ~ to populate the screen, or something similar). From this question, I understand that it may be impossible to do this at the top of the file, but since I almost always edit at the bottom, I was wondering if it is possible to maintain this behavior at the bottom of the file. Specifically, this is the behavior I would like to have:

  1. As I type or scroll in insert or normal mode at the middle of a long file, the cursor should remain vertically centered.
  2. As I reach the bottom, I would like the cursor to remain vertically centered and the screen be populated with virtual lines.
  3. If I type at the top, I don't mind the cursor not being vertically centered.

Here is what I have tried:

  1. set scrolloff = 999. This works well in the middle of the file, but does not work at the bottom.
  2. Remapping scroll keys to append the zz command. This works well in normal mode even at the end of the file, but does not work in insert mode.
  3. Running zz in an autocmd in insert mode. Specifically, I tried both of the following:
au InsertCharPre * norm zz
au TextChangedI,TextChangedP * norm zz

Both work, but both have the one weird effect. At the end of a line, whenever I type something, the cursor is positioned before the inserted character. That is, representing cursor with |,

End of line|        <- I type the character '.' here
End of line|.       <- The cursor is now positioned before the '.'

Note that this happens only at the end of a line. At the middle of a line, things seem to work fine. This seems to be a quirk of norm, and maybe somehow running different commands in the autocmd based on weather the cursor is at the end of the line will work, but I feel like there should be a shorter way to achieve what I want.

Any help is much appreciated.


Normal mode

For normal mode, rather than remapping scroll commands, I would use an autocommand:

augroup KeepCentered
  autocmd CursorMoved * normal! zz
augroup END

Insert mode

For insert mode, as you've discovered, simple autocommands won't suffice. Instead, note that there are very few keystrokes that can cause the cursor to change lines when in insert mode: you can remap these to keep the cursor line centred:

inoremap <CR> <C-\><C-O><C-E><CR>
inoremap <BS> <BS><C-O>zz
nnoremap o <C-E>o

(I don't use the arrow keys, but if you use these in insert mode, you can remap <up> and <down> similarly.)

  • Thanks for the answer. This almost works, but has only one problem: when editing /* * */ style comment blocks, the single space worth of indent inserted after the middle * is gone. I could add something like .<bs><c-o>zz instead, but then other problems happen. Please look at this other question I posted: link
    – Diggs
    Jun 18 '20 at 15:31
  • @Diggs I updated my answer to use <C-\><C-O> instead, which solves the issue you raise.
    – Rich
    Jun 18 '20 at 15:37
  • but this prevents auto closing of comment blocks by just typing /. At the and of the comment block, If I type /, I get ` * /` when I want to have ` */`.
    – Diggs
    Jun 18 '20 at 15:51
  • @Diggs see my update.
    – Rich
    Jun 18 '20 at 21:06
  • @Diggs and see my updated update for a simpler solution!
    – Rich
    Jun 18 '20 at 21:17

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.