Vim - Scroll Below the End of the Document - vim

When we edit the last few lines of a document in vim, those lines are displayed at the bottom part of the screen, which is a little uncomfortable for me. Is there a way to scroll below the end of the document, so that the bottom lines in the document can be displayed at the top of the screen? (Currently Sublime Text has such capability.)
I've done some searches, the closest answer I could find is to use "set scrolloff=10". But that is not what I am looking for. Since it doesn't display the bottom lines of the document at the top of the screen.
Thanks in advance!

In addition to #Kent's answer, zz would allow you to bring the current line to the middle of the screen, which in my opinion is more convenient to see the context of the current line of text/code.
Also, zb would bring the current line to the bottom of the screen, which may also help sometimes.

Is there a way to scroll below the end of the document, so that the
bottom lines in the document can be displayed at the top of the
screen?
If I understood your requirement right, zt (or z<cr>) can do that when your cursor on the last line (in fact works on any line, :h zt for details)
example:

In normal mode you can use CTRL-E to scroll down and CTRL-Y to scroll up without moving the position of the cursor (unless the cursor would get pushed off the screen). If you're at the end of the document pressing CTRL-E will scroll past the end until the last line is at the top of the screen. I tend to like this method better than zt or zz since I can see it scrolling rather having the screen just jump ahead.
There are some caveats. For example, CTRL-Y when using the Windows key bindings is mapped to redo. Check out :help scrolling for more info.

In addition to set scrolloff=10, some of the other answers mentioned Ctrl+E.
I wanted the default motion key j to scroll the cursor as normal if the cursor isn't on the last line of the file, and then when the cursor is on the last line, j should scroll the file (in this case using Ctrl+E).
Placing the following in a .vimrc file enables this behaviour.
function! Scroll()
" what count was given with j? defaults to 1 (e.g. 10j to move 10 lines
" down, j the same as 1j)
let l:count = v:count1
" how far from the end of the file is the current cursor position?
let l:distance = line("$") - line(".")
" if the number of times j should be pressed is greater than the number of
" lines until the bottom of the file
if l:count > l:distance
" if the cursor isn't on the last line already
if l:distance > 0
" press j to get to the bottom of the file
execute "normal! " . l:distance . "j"
endif
" then press Ctrl+E for the rest of the count
execute "normal! " . (l:count - l:distance) . "\<C-e>"
" if the count is smaller and the cursor isn't on the last line
elseif l:distance > 0
" press j the requested number of times
execute "normal! " . l:count . "j"
else
" otherwise press Ctrl+E the requested number of times
execute "normal! " . l:count . "\<C-e>"
endif
endfunction
nnoremap j <Cmd>call Scroll()<CR>
nnoremap <Down> <Cmd>call Scroll()<CR>
Note: I'm not an expert Vim scripter, please edit with improvements
The last line also enables the same behaviour for the down arrow key ↓.
For Neovim, putting the following in init.lua would do the same:
local line = vim.fn.line
local nvim_input = vim.api.nvim_input
local function scroll()
-- what count was given with j? defaults to 1 (e.g. 10j to move 10 lines
-- down, j the same as 1j)
local count1 = vim.v.count1
-- how far from the end of the file is the current cursor position?
local distance = line("$") - line(".")
-- if the number of times j should be pressed is greater than the number of
-- lines until the bottom of the file
if count1 > distance then
-- if the cursor isn't on the last line already
if distance > 0 then
-- press j to get to the bottom of the file
nvim_input(distance.."<Down>")
end
-- then press Ctrl+E for the rest of the count
nvim_input((count1 - distance).."<C-e>")
-- if the count is smaller and the cursor isn't on the last line
elseif distance > 0 then
-- press j as much as requested
nvim_input(count1.."<Down>")
else
-- otherwise press Ctrl+E the requested number of times
nvim_input(count1.."<C-e>")
end
end
vim.keymap.set("n", "j", scroll, {
desc = "continue scrolling past end of file with j",
})
vim.keymap.set("n", "<Down>", scroll, {
desc = "continue scrolling past end of file with ↓",
})

Related

Jump to current function declaration from middle of function

Is there a way to jump to the signature of the function my cursor is currently in, then jump back to where I was?
For example, when I have a 1000 line function, where the prefix x + y: refers to line numbers, is there a way from me to jump from my cursor location at x + 555 to the signature at x + 0 then back to where I was at (x + 555):
x + 000: void theFn(int arg) {
x + ...: ...
x + 555: /// where my cursor starts
x + ...: ...
x + 999: }
And, yes, I couldn't agree with you more that there shouldn't be 1000 line functions.
Also, is there a way to automatically jump to the end of function without being at the opening bracket of the function?
Useful motions in such case are [[, ][ and <C-o>.
As we can read in help:
*[[*
[[ [count] sections backward or to the previous '{' in
the first column. |exclusive|
Note that |exclusive-linewise| often applies.
*][*
][ [count] sections forward or to the next '}' in the
first column. |exclusive|
Note that |exclusive-linewise| often applies.
*CTRL-O*
CTRL-O Go to [count] Older cursor position in jump list
(not a motion command).
{not available without the |+jumplist| feature}
In short:
[[ to got to the beginning
<C-o> to go back to previous place
][ to go to end
Those motions will have the desired effect only when braces are in the first column, but from your example seems like this requirement is not met.
In such case at the end of :h section we can read:
If your '{' or '}' are not in the first column, and you would like to use "[["
and "]]" anyway, try these mappings: >
:map [[ ?{<CR>w99[{
:map ][ /}<CR>b99]}
:map ]] j0[[%/{<CR>
:map [] k$][%?}<CR>
Unfortunately, Vim doesn't offer better solution as it doesn't parse syntax.
It may change though as Neovim experiments with Tree-sitter.
It also wouldn't be surprising if there was a plugin which provides better support for such motion.
Tagbar could fit this role:
Toggle Tagbar window
Switch to it
Cursor should be already over the current tag
Press enter
Toggle window
You are at beginning of the function
Use <C-o> to get back
I also once found and had in my config a mapping which could also be useful in such case:
nnoremap <Leader>gd ?\v%(%(if|while|for|switch)\_s*)#<!\([^)]*\)\_[^;(){}]*\zs\{

Copy block of code with increasing index

I have the following function declaration:
function f1(s)
real f1,s
f1 = 1/s
end
I would like to copy the same block but with increasing function name, i.e. f1, f2, f3, ... in order to get this:
function f1(s)
real f1,s
f1 = 1/s
end
function f2(s)
real f2,s
f2 = 1/s
end
function f3(s)
real f3,s
f3 = 1/s
end
My present approach is to copy the block in visual mode, paste it several times and then rename the functions manually. I would like to know how to achieve this faster using Vim. Thanks.
You can always use a recording (see :h recording). Assuming you have a blank line before and after your function and no blank lines in between
// empty line here, cursor here
function f1(s)
real f1,s
f1 = 1/s
end
// empty line here
With the cursor on the empty line above, make a recording to any register you like. Here I'm using register c. Press qc then press y}}Pjw*Ne^Ane^Ane^A{ and exit with q.
Explanation
y} - yank next paragraph
} - move down one paragraph
P - put above this line
j - move one line done
w - move to next word
* - search for word under cursor ( this is the function name here)
N - search backwards ( we moved with * to get the pattern into the register )
e - go to end of word
^A - Ctrl a to increase the number
n - go to next match / search forward ( this is the function name )
e - go to end of word
^A - increase the number
n - go to next match / search forward
e - go to end of word
^A - increase the number
{ - move up one paragraph (same relative position as in the beginning, but at the inserted function f2 )
Now you can use #c to copy the function and increase all numbers. Prefix with the count you want, e.g. 5#c will copy the function 5 times and adjust the numbering.
In case you don't want to remember the string y}}Pjw*Ne^Ane^Ane^A{ you can paste it in the vim buffer. You will have to replace the ^A before yanking though. Delete ^A and when in insert mode press Ctrl va. ( If you are inside a screen session you will have to press Ctrl aa, this is CTRL-a and a)
With the cursor on the line in normal mode press "cY to yank it in register c.
Then you can replay it with #c.
This way you can also modify it or yank it to another register.
Use let #c=y}}Pjw*Ne^Ane^Ane^A{ in your .vimrc to have it always load to register c when starting vim.
I figured out the solution. It may seems complex but does not, cause you have just to copy this function to the clipboard and load the function with:
:#+
Below the function with additional features
fun! CopyAndIncrease()
try
let l:old_copy = getreg('0')
normal yip
let #0 = substitute(#0,'\d\+','\=submatch(0) + 1','g')
exec "normal }O\<Esc>p"
finally
call setreg('0', l:old_copy)
endtry
endfun
command! -nargs=0 CopyIncrease silent call CopyAndIncrease() | exec "normal \<Esc>"
let mapleader = ','
nnoremap <Leader>c :CopyIncrease<CR>
Now pressing ,c Now you can use the keybinding and commands defined in the function.
Function's explanation:
let l:old_copy = getreg('0') -> save copy register
normal yip -> copy block
let #0 ... increase numbers on copy register
exec "normal }O\<Esc>p" -> paste increased block

What are the vim commands that start with g?

g is a prefix to several commands. e.g. goto to move the cursor, but also gqip to format a paragraph. Where is the reference for all commands that are prefixed with g?
Vim's documentation is http://vimdoc.sourceforge.net/. If you go for the HTML docs, you will find |reference_toc| More detailed information for all commands, which includes |index.txt| alphabetical index of all commands, which -- due to an unfortunate quirk with the doc file named index.txt and linked as index.html -- doesn't actually lead to where you would expect it to lead.
Long story short, http://vimdoc.sourceforge.net/htmldoc/vimindex.html#g is the documentation you are looking for ("Commands starting with 'g'").
Alternatively, type :help *g* in Vim.
(Sorry merlin2011 but your list is somewhat incomplete...)
Some reformatting applied:
2.4 Commands starting with 'g'
char note action in Normal mode
------------------------------------------------------------------
g CTRL-A only when compiled with MEM_PROFILE
defined: dump a memory profile
g CTRL-G show information about current cursor
position
g CTRL-H start Select block mode
g CTRL-] |:tjump| to the tag under the cursor
g# 1 like "#", but without using "\<" and "\>"
g$ 1 when 'wrap' off go to rightmost character of
the current line that is on the screen;
when 'wrap' on go to the rightmost character
of the current screen line
g& 2 repeat last ":s" on all lines
g'{mark} 1 like |'| but without changing the jumplist
g`{mark} 1 like |`| but without changing the jumplist
g* 1 like "*", but without using "\<" and "\>"
g0 1 when 'wrap' off go to leftmost character of
the current line that is on the screen;
when 'wrap' on go to the leftmost character
of the current screen line
g8 print hex value of bytes used in UTF-8
character under the cursor
g< display previous command output
g? 2 Rot13 encoding operator
g?? 2 Rot13 encode current line
g?g? 2 Rot13 encode current line
gD 1 go to definition of word under the cursor
in current file
gE 1 go backwards to the end of the previous
WORD
gH start Select line mode
gI 2 like "I", but always start in column 1
gJ 2 join lines without inserting space
["x]gP 2 put the text [from register x] before the
cursor N times, leave the cursor after it
gQ switch to "Ex" mode with Vim editing
gR 2 enter Virtual Replace mode
gU{motion} 2 make Nmove text uppercase
gV don't reselect the previous Visual area
when executing a mapping or menu in Select
mode
g] :tselect on the tag under the cursor
g^ 1 when 'wrap' off go to leftmost non-white
character of the current line that is on
the screen; when 'wrap' on go to the
leftmost non-white character of the current
screen line
ga print ascii value of character under the
cursor
gd 1 go to definition of word under the cursor
in current function
ge 1 go backwards to the end of the previous
word
gf start editing the file whose name is under
the cursor
gF start editing the file whose name is under
the cursor and jump to the line number
following the filename.
gg 1 cursor to line N, default first line
gh start Select mode
gi 2 like "i", but first move to the |'^| mark
gj 1 like "j", but when 'wrap' on go N screen
lines down
gk 1 like "k", but when 'wrap' on go N screen
lines up
gm 1 go to character at middle of the screenline
go 1 cursor to byte N in the buffer
["x]gp 2 put the text [from register x] after the
cursor N times, leave the cursor after it
gq{motion} 2 format Nmove text
gr{char} 2 virtual replace N chars with {char}
gs go to sleep for N seconds (default 1)
gu{motion} 2 make Nmove text lowercase
gv reselect the previous Visual area
gw{motion} 2 format Nmove text and keep cursor
gx execute application for file name under the
cursor (only with |netrw| plugin)
g#{motion} call 'operatorfunc'
g~{motion} 2 swap case for Nmove text
g<Down> 1 same as "gj"
g<End> 1 same as "g$"
g<Home> 1 same as "g0"
g<LeftMouse> same as <C-LeftMouse>
g<MiddleMouse> same as <C-MiddleMouse>
g<RightMouse> same as <C-RightMouse>
g<Up> 1 same as "gk"
note: 1 = cursor movement command; 2 = can be undone/redone
Open vim. Type :help g.
2.4 Commands starting with 'g' g
tag char note action in Normal mode
------------------------------------------------------------------------------
g_CTRL-A g CTRL-A only when compiled with MEM_PROFILE
defined: dump a memory profile
g_CTRL-G g CTRL-G show information about current cursor
position
g_CTRL-H g CTRL-H start Select block mode
g_CTRL-] g CTRL-] :tjump to the tag under the cursor
g# g# 1 like "#", but without using "\<" and "\>"
g$ g$ 1 when 'wrap' off go to rightmost character of
the current line that is on the screen;
when 'wrap' on go to the rightmost character
of the current screen line
g& g& 2 repeat last ":s" on all lines
g' g'{mark} 1 like ' but without changing the jumplist
g` g`{mark} 1 like ` but without changing the jumplist
gstar g* 1 like "*", but without using "\<" and "\>"
g+ g+ go to newer text state N times
g, g, 1 go to N newer position in change list
g- g- go to older text state N times
g0 g0 1 when 'wrap' off go to leftmost character of
the current line that is on the screen;
when 'wrap' on go to the leftmost character
of the current screen line
g8 g8 print hex value of bytes used in UTF-8
character under the cursor
g; g; 1 go to N older position in change list
g< g< display previous command output
The list above has been truncated for readability.

Preserve cursor position when using ==

I am trying to make Vim indent lines like Emacs (that is, "make the current line the correct indent" instead of "insert tab character"). Vim can do this with = (or ==) for one line). I have imap <Tab> <Esc>==i in my .vimrc but this makes the cursor move to the first non-space character on the line. I would like the cursor position to be preserved, so I can just hit tab and go back to typing without having to adjust the cursor again. Is this possible?
Example
What I have now (| represents the cursor):
function f() {
doso|mething();
}
Tab
function f() {
|dosomething();
}
What I would like:
function f() {
doso|mething();
}
Tab
function f() {
doso|mething();
}
Also
function f() {
| dosomething();
}
Tab
function f() {
|dosomething();
}
I don't believe there's an "easy" way to do this (that is, with strictly built-in functionality) but a simple function does it just fine. In your .vimrc file:
function! DoIndent()
" Check if we are at the *very* end of the line
if col(".") == col("$") - 1
let l:needsAppend = 1
else
let l:needsAppend = 0
endif
" Move to location where insert mode was last exited
normal `^
" Save the distance from the first nonblank column
let l:colsFromBlank = col(".")
normal ^
let l:colsFromBlank = l:colsFromBlank - col(".")
" If that distance is less than 0 (cursor is left of nonblank col) make it 0
if l:colsFromBlank < 0
let l:colsFromBlank = 0
endif
" Align line
normal ==
" Move proper number of times to the right if needed
if l:colsFromBlank > 0
execute "normal " . l:colsFromBlank . "l"
endif
" Start either insert or line append
if l:needsAppend == 0
startinsert
else
startinsert!
endif
endfunction
" Map <Tab> to call this function
inoremap <Tab> <ESC>:call DoIndent()<CR>
There's always <C-T> and <C-D> (that is CtrlT and CtrlD) in insert mode to indent and outdent on the fly.
These don't change the cursor position – and they're built-in functionality.
Try using a mark of last insert mode, and use the append command to set the cursor back just where it was before, like:
:imap <Tab> <Esc>==`^a

Jump to the end of a long list of repeated pattern

I have a big file with a lot of lines that share the same pattern, something like this:
dbn.py:206 ... (some other text) <-- I am here
dbn.py:206 ... (some other text)
...
(something I don't know) <-- I want to jump here
Is there a quick way in Vim to jump to the place where the succession of dbp.py:206 ends?
/^\(dbn.py\)\#!
Matches first line which does not start with the text inside the escaped parentheses.
If you want quick access to this you could add a vmap which yanks the visually selected text and inserts it in the right spot (but first escaping it with escape(var, '/').
Try this vmap: vmap <leader>n "hy<Esc>/^\(<C-R>=escape(#h,'/')<CR>\)\#!<CR>
Press n when visually selecting the text you wish to skip and you should be placed on the next first line which does not begin with the selection.
I just write a function to select identical lines:
nnoremap vii :call SelectIdenticalLines()<CR>
fun! SelectIdenticalLines()
let s = getline('.')
let n = line('.')
let i = n
let j = n
while getline(i)==s && i>0
let i-=1
endwhile
while getline(j)==s && j<=line('$')
let j+=1
endwhile
call cursor(i+1, 0)
norm V
call cursor(j-1, 0)
endfun
type vii to select identical lines (feel free to change the key-binding)
type zf to fold them.
type za to toggle folding
It's handy when you want to squeeze several empty line.
It acts like C-x C-o in emacs.
One option is to go to the bottom of the file and search backwards for the last line you want, then go down one:
G ?^dbn\.py:206?+1

Resources