Tips parsed from Reddit weekly tip threads.
I'm not sure how well known this is, but when I was first shown it blew my mind. Create a directory in ~/.vim named undodir then put this in your .vimrc and you'll be able to undo changes to a file after closing and reopening:
set undofile
set undodir=~/.vim/undodir
I just realized I never saw this little thing anywhere. Basically I wanted to have extra indication where focus is. So this little snippet will show cursorline only in Vim window with focus, this includes application windows as well.
augroup highlight_follows_focus
autocmd!
autocmd WinEnter * set cursorline
autocmd WinLeave * set nocursorline
augroup END
augroup highligh_follows_vim
autocmd!
autocmd FocusGained * set cursorline
autocmd FocusLost * set nocursorline
augroup END
Let me start with this snippet that automatically opens the location/quickfix window whenever a location/quickfix command is executed and there's a valid location/quickfix list.
augroup autoquickfix
autocmd!
autocmd QuickFixCmdPost [^l]* cwindow
autocmd QuickFixCmdPost l* lwindow
augroup END
select whatever's just been pasted, or read into the buffer via :r! etc.
nnoremap gV `[V`]
[I
list all the lines where the word under the cursor occurs.
edit to add: ]I
will list from the current cursor position rather than the start of the file = [I
Make arrow keys do something useful, resize the viewports accordingly.
nnoremap <Left> :vertical resize +2<CR>
nnoremap <Right> :vertical resize -2<CR>
nnoremap <Up> :resize -2<CR>
nnoremap <Down> :resize +2<CR>
Poor man's TagBar:
:g/func/#<CR>
Slightly more powerful variants (lists includes too, may require a bit of setup):
:ilist /func<CR>
:dlist /<CR>
If you're at the beginning of a line you can type ci" and it'll automatically go to first set of "" quotes (same with ''). Once I realized this it saved me soo much time. Instead of going f"ci" you can just type ci" right away.
Not sure how popular this is but pressing
Edit1: As many have pointed out, you can also invoke this via q:, q? and q: which I forgot to mention. However, since I invoke it usually mid-command, I find
Edit: A small gif for visual benefit - https://asciinema.org/a/0gutmej8i4ccnaovym5uqmwwu
If you've searched for something and want to replace it, you don't have to type it in again in the command-line:
s//text_to_replace_with
instead of
s/prev_searched_text/text_to_replace_with
A very nice feature of vim is its integration with terminal programs to modify the current buffer.
For this you put :%! <command-name>
in command mode
For example,
:%! sort -k2
will sort the buffer based on column 2
:%! column -t
will format the text in columns - useful when working with tabular data
:%! markdown
will change the current markdown file to html
You get the idea.
Sometimes you want to paste text without leaving insert mode. In insert mode, ctrl+r followed by a register number will paste that register. This is also useful when you're in vim's command-line. I particularly use this with vim's "%" register, which stores the current file name, when I want to save a backup version of a file: ":w ctrl+r %" expands to ":w ctrl+r myfile.txt" and then I just append ".backup" to it and save.
I personally advocate for learning vim's basic commands. A very useful normal command is gv. At the same time is so simple! Here, straight from :help gv:
gv Start Visual mode with the same area as the previous
area and the same mode.
In Visual mode the current and the previous Visual
area are exchanged.
After using "p" or "P" in Visual mode the text that
was put will be selected.
Vim already has lots of very useful text-objects but we are pigs… we always want more. Here are 24:
for char in [ '_', '.', ':', ',', ';', '<bar>', '/', '<bslash>', '*', '+', '%', '`' ]
execute 'xnoremap i' . char . ' :<C-u>normal! T' . char . 'vt' . char . '<CR>'
execute 'onoremap i' . char . ' :normal vi' . char . '<CR>'
execute 'xnoremap a' . char . ' :<C-u>normal! F' . char . 'vf' . char . '<CR>'
execute 'onoremap a' . char . ' :normal va' . char . '<CR>'
endfor
starstar! ** -- this is magic! It can be used in tons of places. Want to open a file in your path and think you need ctrl-p or some other plugin, you don't!
:e **/*part<tab>
if you are lazy (as I am), you can just map it
nnoremap <leader>e :e **/*
Quick wildcard searching over your whole tree, wow!
But, it gets even better, opening files 1 by 1 is exhausting! Lets open all the markdown files in our tree!
:arga **/*.md
But... damnit, now all those files are in buffers, how will I ever switch to the one I want...
You can use wildcards with full path
:b */*<tab>
But, I am too lazy to type that each time, so a mapping to the secure again (and this one lists them by default with C-d)
nnoremap <leader>b :b */*<C-d>
https://github.com/tpope/vim-abolish
Lets you use :S/cat/dog/ to turn:
cat CAT Cat
into
dog DOG Dog
Use abbreviations to add computable but common items like timestamps:
" Insert mode ddate adds date stamp
iab <expr> ddate strftime("%b %d - %a")
In insertmode typing ddate will result with: Apr 11 - Mon using the string formating above. I use this all the time for daily notes.
The new-ish :cdo command. Combine this with vimgrep or other searching plugins and you can quickly apply mods to each match result that is listed in the quickfix. Combine :cdo with normal mode and you have some serious magic. For example, Piggybacking on the other suggestion about vim-abolish, I recently used this:
:cdo normal e2wcrs
to quickly do camel to snake conversion for a set of match lines in my qf (where my qf match lines were based on searching for "foo::")
foo::SomeClass
to
foo::some_class
The "crs" is provided by vim-abolish to do the camel-->snake conversion.
To paste text into the current buffer without using "set paste" at a *nix system:
:r!cat
Press Ctrl+d when done. Simple, but useful.
Everyone probs already knows, this, but you can do
:mks ~/mysession.vim
then
vim -S ~/mysession.vim
When opening vim to load all your tabs, files and windows back just how they were.
Literally only just found this out:c
While in insert mode, Ctrl-d decreases indentation, Ctrl-t increases it, and Ctrl-m (also Ctrl-j) inserts a newline. Maybe these are well known; I wasn't aware of them until recently and find them quite convenient.
Note from editor Ctrl-f "fixes" indentation in insert mode too.
In the replacement section of the :s command, & corresponds to the whole matched pattern. It can be uppercased with \U and lowercased with \L: :s#aaaaaaa#\U&#
Weekly text-objects:
" line text-objects
xnoremap il g_o0
omap il :<C-u>normal vil<CR>
xnoremap al $o0
omap al :<C-u>normal val<CR>
" buffer text-object
xnoremap i% GoggV
omap i% :<C-u>normal vi%<CR>
:b# -- stupidly simple but useful, lets you swap back and forth between buffers, I use it bound to
nnoremap <leader>q :b#<cr>
Yank and paste a line without moving the cursor.
:10t.
will paste line 10 to current position. Relative numbers works as well.
:-10t.
I find this easier to do than jumping around in the file, yanking and jumping back.
As you all probably know, we can replace occurrences of a word in a file using the :%s/search/replace/g Ex command. Something I learned recently is that we can actually tell Vim to prompt us for a confirmation before replacing each word using :%s/search/replace/gc (notice the c at the end for confirm).
Here's a screenshot to illustrate the feature. We can press y to replace the current occurrence of the word or n to to skip it. Simple.
We can also press a to replace all words, q to abort (quit), and l to change the current occurrence of the word and then immediately abort (as in, this is the last change you want to make before aborting).
Just like in Normal mode, we can scroll up and down using Control + Y and Control + E respectively.
I can't say this feature revolutionized my workflow but I was giddy when I learned about it 😆!
Update: Here's a practical demonstration of this feature in action (that is a link to a specific timestamp namely, 14:13)
For an easy "repeat macro over all selected lines" you can use the following mapping:
vnoremap @ :norm@
I got this one from /u/cherryberryterry a couple of weeks ago.
This is for people who use relative line numbers:
nnoremap <expr> k (v:count > 1 ? "m'" . v:count : '') . 'k'
nnoremap <expr> j (v:count > 1 ? "m'" . v:count : '') . 'j'
It adds motions like 25j and 30k to the jump list, so you can cycle through them with control-o and control-i.
If you edit a lot of text files (for example, if you use Vim to write your emails), you might want to tweak your formatlistpat to recognize and format lists better. I have the following in ~/.vim/after/ftplugin/text.vim:
setlocal formatlistpat=^\\s*[\\[({]\\\?\\([0-9]\\+\\\|[iIvVxXlLcCdDmM]\\+\\\|[a-zA-Z]\\)[\\]:.)}]\\s\\+\\\|^\\s*[-+o*]\\s\\+
It will recognize lists starting with numbers, letters, roman numerals, symbols like +, -, etc. As an example of how this works, say I have the following list:
1. Et dolor quia qui omnis inventore. Quos voluptatem quae sit sint dicta qui beatae totam. Quibusdam qui occaecati voluptatibus id.
XXV. Nemo aut est quo optio et culpa rerum. Non totam aut sint placeat non. Et repellat eveniet molestiae. Eius dolorem molestiae non asperiores suscipit dolor dolorem.
(a) Eaque dolor qui perferendis. Impedit consequatur sit qui. Qui molestiae ut nemo magni quo veritatis voluptatem. Ut aliquid tenetur recusandae necessitatibus quas est nesciunt. Fugiat quis aut est impedit hic architecto. Ut et maiores soluta est ipsa cum autem itaque.
+ Ut dignissimos molestiae ducimus rerum dolores aut. Dolorum alias molestiae nam sed laudantium. Culpa dolorum iste quo harum ipsa quidem. Qui ea ratione et.
Now, if I use gq to format these lines, I get:
1. Et dolor quia qui omnis inventore. Quos voluptatem quae sit sint
dicta qui beatae totam. Quibusdam qui occaecati voluptatibus id.
XXV. Nemo aut est quo optio et culpa rerum. Non totam aut sint
placeat non. Et repellat eveniet molestiae. Eius dolorem
molestiae non asperiores suscipit dolor dolorem.
(a) Eaque dolor qui perferendis. Impedit consequatur sit qui. Qui
molestiae ut nemo magni quo veritatis voluptatem. Ut aliquid
tenetur recusandae necessitatibus quas est nesciunt. Fugiat quis
aut est impedit hic architecto. Ut et maiores soluta est ipsa
cum autem itaque.
+ Ut dignissimos molestiae ducimus rerum dolores aut. Dolorum alias
molestiae nam sed laudantium. Culpa dolorum iste quo harum ipsa
quidem. Qui ea ratione et.
Note that you'll also need the n flag in your formatoptions to tell Vim that numbered lists should be recognized (:help fo-table).
Add a # comment block:
nnoremap <leader>b :center 80<CR>hhv0r#A<SPACE><ESC>40A#<ESC>d80<BAR>YppVr#kk.
Run this on a word, like "INIT", and you will get:
################################################################################
##################################### INIT #####################################
################################################################################
Have to give credit to Doorknob: http://vi.stackexchange.com/a/421/307
Tired of .swp files being strewn all around your folders? Create a directory and point to it in your .vimrc . For instance, create ~/.swp_files folder. Then in your .vimrc add:
set backupdir=~/.swp_files
set directory=~/.swp_files
Much more convenient to have a single directory to check...and I usually end up just deleting .swp files anyways. I don't think they've once saved me from a crash/power outage, but this is a safer solution than set noswapfile.
EDIT: Forgot to mention yesterday, if you share your .vimrc across users (notably, root), then you will get errors if you don't create/link the .swp_files directory for that user. It's not catastrophic or anything, but you may wind up without .swp files for that user (but you will see an error message when opening vim).
If you want your cursor to stay in the middle of the screen when browsing long files, you can set scroll on with
set so=999
Now the page will move around while the cursor stays centered.
:cq
exits vim immediately like :qa!, but with nonzero exit code. This is useful if you are calling vim from some other application and you want to abort. I often use this to abort git commits, moreutil's vidir and the like. Unfortunately, it doesn't work with all applications.
And don't get tempted to just use it as a quicker :qa!, that's just wrong :)
If you've ever wanted to wrap some text foo with some other, arbitrary text using c{motion} (change) followed by
foo
bar
if you put the cursor on foo and do ciw(
(foo)
(foo)
instead of
(foo)
(bar)
The solution is to do
Do you want an actionable TOC of your markdown file?
:g/^#/#
Do you want an actionable overview of your code?
:g/def /#
:g/func/#
I'm not a textwrap user and I like to keep most of my lines under the 80 character mark. So when I (for example) paste a long line into vim, I can use gq
You can use 'suffixes' to give certain filenames less priority in the wildmenu. I set suffixes+=.sty,.bst,*.cls while editing LaTeX since I rarely edit anything other than the LaTeX or BiBTeX source. There's also 'wildignore' to completely ignore certain files (one downside of this is that file name completions in the insert mode using CTRL-X CTRL-F will also be affected).
Editors note: set suffixesadd+=.js,.ml is useful too
Read the user manual. I don't mean that with any snark, it is a sincere tip. The Vim documentation is two parts, (1) user manual, (2) reference manual. The user manual is well worth reading, and far too few people do it.
- :h user-manual
- http://vimdoc.sourceforge.net/htmldoc/usr_toc.html
- http://nathangrigg.net/vimhelp/vimhelp.pdf (this is a PDF of the entire vim docs, colorized and smartly crosslinked -- of course includes the user manual).
You are going to spend hundreds, maybe even thousands of hours using Vim -- take the time to read the basic manual and your time will be far better spent.
While visually selecting a block, press 'o' to switch to the other end of the block. This lets you adjust either the starting or ending positions of the block until you're ready to issue a command. That is, you can expand or contract either end of the visual block, you're not stuck changing just one end.
:browse oldfiles or :bro ol
Thanks to the Netrw plugin (default in vim) you can do ssh remote work out of the box:
:e dav://machine[:port]/path uses cadaver
:e fetch://[user@]machine/path uses fetch
:e ftp://[user@]machine[[:#]port]/path uses ftp autodetects <.netrc>
:e http://[user@]machine/path uses http uses wget
:e rcp://[user@]machine/path uses rcp
:e rsync://[user@]machine[:port]/path uses rsync
:e scp://[user@]machine[[:#]port]/path uses scp
:e sftp://[user@]machine/path uses sftp
Of course you can use whichever of the above to just open a remote folder directly. If you don't know netrw very well but use some file tree plugin (like NERDTree) I really recommend checking out the plugin as it might be enough for most people and it's already built-in.
Executing >3j will shift the current line and the three lines below it to the right. Subsequently, . will repeat the shift over the same lines as expected. On the other hand, executing and repeating >3k will not operate over the same lines because the cursor is moved to the first shifted line after the shift operation.
Here's a gif of the issue: http://i.imgur.com/SRUpnEP.gif (>3k.. is demonstrated with and without the below "fix")
onoremap
Use | to chain commands.
E.g. :sp|e test will open a horizontal split containing a session to edit test
Editors note: :w|so % is useful when editing vimrc
Use g to rearrange lines. The classic example is that you can reverse lines with :5,25g/^/m4, but you can also swap lines around out like :'<,'>g/LOG/m-2 which turns:
doTheThing();
LOG.message('doing the thing');
doSomethingElse();
LOG.message('doing something else');
into:
LOG.message('doing the thing');
doTheThing();
LOG.message('doing something else');
doSomethingElse();
Changing the m (move) to a t (copy) inserts lines like with :'<,'>g/LOG/t-2|+2s/doing/did/ (note you can use | to string commands together in the context of the :g), which, given the same input, yields:
LOG.message('doing the thing');
doTheThing();
LOG.message('did the thing');
LOG.message('doing something else');
doSomethingElse();
LOG.message('did something else');
If you want to use the current word in the command window, e.g. to do a substitution, you can press Ctrl-R followed by Ctrl-W.
Example: :%s/<C-r><C-w>/newword/
This is a simple one but I really like it because I don't like holding Shift for LONG_VARIABLE_NAMES.
" make last typed word uppercase
inoremap <c-u> <esc>viwUea
inoremap <Plug>UpCase <Esc>hgUaweA
imap ;u <Plug>UpCase
I have this: :H topic will open an 80 columns vertical split containing the help page. The complete argument ensures that the completion works exactly like the :h command.
command! -complete=help -nargs=1 H call VerticalHelp(<f-args>)
function! VerticalHelp(topic)
execute "vertical botright help " . a:topic
execute "vertical resize 78"
endfunction
Edit: autocompletion* thanks /u/_ntnn
I can't believe I just found this, where have you been all my life!
" make . work with visually selected lines
vnoremap . :norm.<CR>
Most people probably now that you can use gv to reselect the last visual selection or pasted texted.
But in visual mode gv can cycle between the two last visual selections!
Make directory(ies) if they don't exist when creating a new buffer/file.
function! <SID>AutoMkdir() abort
let l:dir = expand('<afile>:p:h')
let l:file = expand('<afile>:t')
if !isdirectory(l:dir)
call mkdir(l:dir, 'p')
silent execute 'bw ' . l:dir . '/' . l:file
silent execute 'e ' . l:dir . '/' . l:file
endif
endfunction
augroup AutoMkdir
autocmd!
autocmd BufWritePre,FileWritePre,BufNewFile *
\ call <SID>AutoMkdir()
augroup END
Same thing here but with user input.
First, how to create a scratch window:
command! SC vnew | setlocal nobuflisted buftype=nofile bufhidden=wipe noswapfile
Second, how to execute arbitrary vimscript from a buffer:
- Yank what you want to execute.
- :@"
And now you have a nice low-rent vimscript playground.
:set cc=80
will show a vertical ruler at column 80.
syntime on was a revelation to me. I turns out to be a great way to identify errant plugins and macros that bog down your vim.