Reputation: 7780
When cursor is at middle of screen and i scroll down, the cursor moves upwards on the screen. I don't want it to do that.
How can i scroll without changing cursors on-screen position?
Solution, added after answer:
noremap <C-k> 14j14<C-e>
noremap <C-l> 14k14<C-y>
Upvotes: 39
Views: 15748
Reputation: 81
There are two methods I know of. Add these lines to your .vimrc file (selecting only one of the two methods):
Method 1:
function! s:GetNumScroll(num)
let num_rows = winheight(0)
let num_scroll = a:num
if (a:num == -1)
let num_scroll = (num_rows + 1) / 2
elseif (a:num == -2)
let num_scroll = num_rows
endif
if (num_scroll < 1)
let num_scroll = 1
endif
return num_scroll
endfunction
function! s:RtrnToOrig(before_scr_line)
normal H
let delta = a:before_scr_line - winline()
while (delta != 0)
if (delta < 0)
let delta = winline() - a:before_scr_line
let iter = 1
while (iter <= delta)
execute "normal" "gk"
let iter +=1
endwhile
elseif (delta > 0)
let iter = 1
while (iter <= delta)
execute "normal" "gj"
let iter +=1
endwhile
endif
let delta = a:before_scr_line - winline()
endwhile
endfunction
function! s:scrollUP(num)
let num_scroll = <SID>GetNumScroll(a:num)
let num_rows = winheight(0)
" -------------
let before_scr_line = winline()
normal L
let after_scr_line = winline()
let extra = num_rows - after_scr_line
let extra += num_scroll
" move by 1 to prevent over scrolling
let iter = 1
while (iter <= extra)
execute "normal" "gj"
let iter +=1
endwhile
" -------------
call <SID>RtrnToOrig(before_scr_line)
endfunction
function! s:scrollDN(num)
let num_scroll = <SID>GetNumScroll(a:num)
" -------------
let before_scr_line = winline()
normal H
let after_scr_line = line(".")
execute "normal" "gk"
let after_scr2_line = line(".")
if ( (after_scr_line == after_scr2_line) && (after_scr_line > 1) )
execute "normal" "gk"
endif
let extra = (num_scroll - 1)
let extra += (winline() - 1)
" move by 1 to prevent over scrolling
let iter = 1
while (iter <= extra)
execute "normal" "gk"
let iter +=1
endwhile
" -------------
call <SID>RtrnToOrig(before_scr_line)
endfunction
nmap <silent> <C-J> :call <SID>scrollUP(1)<CR>
nmap <silent> <C-K> :call <SID>scrollDN(1)<CR>
nmap <silent> <C-F> :call <SID>scrollUP(-1)<CR>
nmap <silent> <C-B> :call <SID>scrollDN(-1)<CR>
nmap <silent> <PageDown>:call <SID>scrollUP(-2)<CR>
nmap <silent> <PageUp> :call <SID>scrollDN(-2)<CR>
This uses the normal H, L to go to screen top, bot and the gk, gj commands to move up, down by screen line instead of actual line. Its more complicated than would seem needed just to work correctly when lines are longer than the screen width and wordwrap is on.
Or this method (which has previously been posted in vim tips wiki and on Stack Exchange):
Method 2:
" N<C-D> and N<C-U> idiotically change the scroll setting
function! s:Saving_scrollV(cmd)
let save_scroll = &scroll
execute "normal" a:cmd
let &scroll = save_scroll
endfunction
" move and scroll
nmap <silent> <C-J> :call <SID>Saving_scrollV("1<C-V><C-D>")<CR>
vmap <silent> <C-J> <Esc> :call <SID>Saving_scrollV("gv1<C-V><C-D>")<CR>
nmap <silent> <C-K> :call <SID>Saving_scrollV("1<C-V><C-U>")<CR>
vmap <silent> <C-K> <Esc> :call <SID>Saving_scrollV("gv1<C-V><C-U>")<CR>
nmap <silent> <C-F> :call <SID>Saving_scrollV("<C-V><C-D>")<CR>
vmap <silent> <C-F> <Esc> :call <SID>Saving_scrollV("gv<C-V><C-D>")<CR>
nmap <silent> <PageDown> :call <SID>Saving_scrollV("<C-V><C-D>")<CR>
vmap <silent> <PageDown> <Esc>:call <SID>Saving_scrollV("gv<C-V><C-D>")<CR>
nmap <silent> <C-B> :call <SID>Saving_scrollV("<C-V><C-U>")<CR>
vmap <silent> <C-B> <Esc> :call <SID>Saving_scrollV("gv<C-V><C-U>")<CR>
nmap <silent> <PageUp> :call <SID>Saving_scrollV("<C-V><C-U>")<CR>
vmap <silent> <PageUp> <Esc> :call <SID>Saving_scrollV("gv<C-V><C-U>")<CR>
The only issue I have with the second method is when lines are longer than the screen width and wordwrap is on then the cursor can move up or down some to account for the extra lines from the wrap. Also at the very top and bottom of the file the cursor can move. The first method really attempts to never move the cursor in all cases.
Upvotes: 1
Reputation: 4061
This changes the cursor on-screen position, but does not change the cursor line on-screen position:
noremap <C-k> @="1\<lt>C-D>"<CR>:set scroll=0<CR>
noremap <C-l> @="1\<lt>C-U>"<CR>:set scroll=0<CR>
This however resets the scroll
option, so subsequent <C-D>
and <C-U>
will scroll by half screen. Without set scroll=0
, the scroll
option would have been set to 1, and subsequent <C-D>
and <C-U>
would be scrolling by one line (Vim is weird).
Probably a Vimscript function based on 1<C-D>
and 1<C-U>
would be the best.
Upvotes: 0
Reputation: 1702
ctrl-D and ctrl-U is what you want.
ctrl-D has the same effect as 14j14<C-e>
(just that the number 14 is not hard coded and the amount of movement depends on the actual size of your screen): You move the cursor several lines down in the text but the cursor stays in the middle of the screen.
Similarly ctrl-U works like 14k14<C-y>
.
Addendum: If your screen has 30 lines then the the two are exactly the same.
Upvotes: 13
Reputation: 96101
There are two ways I can think of: ctrl-E and ctrl-Y scroll the buffer without moving the cursor's position relative to the window. I think that is what you want. Also, if you set scrolloff
to a large number, you will get the same effect as ctrl-E and ctrl-Y with the movement keys. scrolloff
setting will make it hard to get the cursor to move vertically relative to the window though. (Use something like :set so=999
, so
is an abbreviation for scrolloff
.)
:help 'scrolloff'
:help scrolling
Upvotes: 49
Reputation: 3053
Try this mapping in .vimrc
map <ScrollWheelUp> 5<C-Y>
map <ScrollWheelDown> 5<C-E>
Upvotes: 1
Reputation: 32283
If you want to both move the cursor and the viewport with the cursor anywhere in the screen, perhaps you should set up some custom key bindings to do both at once.
Such as:
:nnoremap <C-M-u> j<C-e>
This will move the cursor down (j
) and move the viewport (Ctrl-e
) whenever you press Ctrl-Alt-u
(only in normal mode).
Upvotes: 11