Because the default Ctrl-B/F or PageUp/Down behaviour usually leaves the cursor somewhere other than where it started, I remapped PageUp and PageDown in my .vimrc to simply move up/down 25 lines.

nnoremap <silent> <PageUp> 25<Up> 
nnoremap <silent> <PageDown> 25<Down>

But if I get to the top of the file the line number goes to 1 and so when I return down to near the original text it is now on the wrong line.

Is there some way to correct for this (perhaps some function for PageUp and PageDown that remembers when it could only go a lesser distance and so the first movement in the opposite direction also goes a lesser distance, or possibly some scheme where a marker is placed at the original spot... although I'd prefer not to have to remember to do that manually every time, just in case I may find myself needing it because I try to scroll too far).

I use Fedora 28 (but I'm pretty sure vi/vim under other systems had this problem of returning to a different line). Ctrl-B/F have the side effect of moving the cursor to the last/first line on the screen, so I often find the process of looking at something off the top of the screen means returning afterwards does not actually return me to the correct line; I have to hit up/down arrows a lot. And PageUp/Down keys are mapped to Ctrl-B/F so have this annoying feature. Using Ctrl-U/D or my simple workaround is usually better, except if I accidentally try to go too far... hence my question of a more general solution.

  • 1
    are you looking for :set nostartofline? Feb 7, 2019 at 10:47
  • No, the cursor ends up on a totally different line after a set of matching PageUp and PageDown keystrokes even when the text on the screen returns to where it was (if the cursor began on one of the middle lines within the screen). I presume this isn't unique to my particular Fedora implementation. It seems so annoying that I presume others have already found a solution to it, one better than my simple workaround that fails if I try to scroll too far.
    – user235510
    Feb 7, 2019 at 20:44
  • 1
    What about this: vim.wikia.com/wiki/Page_up/down_and_keep_cursor_position
    – Ralf
    Feb 7, 2019 at 21:48

3 Answers 3


You can mark the current position of the cursor typing m followed by an alphabet in normal mode which is the register to store it. If you use ma to mark it, you can jump back to this position by `a or 'a. For more details, run :help mark in vim.

If you had used certain commands to navigate the documents, you can also have a look at :help jump-motions in vim.

As quoted there

A "jump" is one of the following commands: "'", "`", "G", "/", "?", "n", "N", "%", "(", ")", "[[", "]]", "{", "}", ":s", ":tag", "L", "M", "H" and the commands that start editing a new file. If you make the cursor "jump" with one of these commands, the position of the cursor before the jump is remembered. You can return to that position with the "''" and "``" command, unless the line containing that position was changed or deleted.


You could use Ctrl+O to go back to the previous positions instead of relying on the standard scrolling commands.

" extracted from my ~/.vim/my/autoload/map/view.vim
" adapt to fit your need.

func! map#view#pagedown(cnt) abort
    let cnt = +a:cnt
    let info = getwininfo(win_getid(winnr()))[0]
    let height = info.height
    if cnt > 0
        if line('$') - info.topline < info.height
            norm! j
        let off = line('.') - info.topline
        let pos = getcurpos()
        exec 'norm! H' . cnt . "\<C-f>"
        let pos[1] = line('.') + off
        call cursor(pos[1:])
    elseif cnt < 0
        let cnt = -cnt
        if info.topline == 1
            norm! k
        let off = line('.') - info.topline
        let pos = getcurpos()
        exec 'norm! L' . cnt . "\<C-b>"
        let pos[1] = getwininfo(win_getid(winnr()))[0].topline + off
        call cursor(pos[1:])

nn <silent> j :<C-u>call map#view#pagedown(v:count1)<CR>
nn <silent> k :<C-u>call map#view#pagedown(-v:count1)<CR>

Edit & Explanation:

Basically the what the function doing is,

  • first save window info and cursor position into variable pos
  • for cnt > 0, first switch to topline, then go pagedown cnt times
  • for cnt < 0, first switch to botline, then go pageup cnt times
  • then adust pos to intended line then call cursor(pos[1:])

In this fashion, you will always go down & up by exact page, which means after k, k, k, j, j, j you will stay at same row & col and difference of line('.') and the topline is the same, which mean you go back to exactly where you are. That's much better/intuitive/consistent than default vim <C-f> & <C-b> or <PageDown> & <PageUp>.

  • An explanation would improve this answer. (And wow does it get my goat to see people write cnt, func, nn instead of spelling out the names.)
    – D. Ben Knoble
    Feb 1 at 19:32

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.