Preface
Vim Reference Guide is intended as a concise learning resource for beginner to intermediate level Vim users. It has more in common with cheatsheets than a typical text book. Most features are presented using a sample usage. Topics like Regular Expressions and Macros have more detailed explanations and examples due to their complexity.
The features covered in this guide are shaped and limited by my own experiences since 2007. You might expect me to have already become an expert, but I'm not there yet (nor do I have a pressing need for such expertise). The earlier version of this guide was written in 2017 and I did an extensive rework to get it fit for publication. A large portion of that time was spent correcting my understanding of Vim commands, going through user and reference manuals, getting good at using the built-in help, learning new features and so on.
Prerequisites
I do give a brief introduction to get started with using Vim, but having prior experience would be ideal before using this resource. As a minimum requirement, you should be able to use vimtutor on your own.
You are also expected to get comfortable with reading manuals, searching online, visiting external links provided for further reading, tinkering with the illustrated examples, asking for help when you are stuck and so on. In other words, be proactive and curious instead of just consuming the content passively.
See my Vim curated list for links to tutorials, books, interactive resources, cheatsheets, tips, tricks, forums and so on.
Conventions
- This guide is based on Vim version 9.1 and some instructions assume Unix/Linux like operating systems. Where possible, details and resources are mentioned for other platforms.
- I prefer using GVim, so you might find some differences if you are using Vim.
- Built-in help command examples are also linked to an online version. For example, clicking :h usr_toc.txt will take you to table of contents for Vim User Manual.
:h usr_toc.txtis also a command that you can use from within Vim. - External links are provided throughout the book for exploring some topics in more depth.
- My vim_reference repo has markdown source and other details related to the book. If you are not familiar with the
gitcommand, click the Code button on the webpage to get the files.
How to use this guide
- Since many chapters take the form of cheatsheet with examples, this is a densely packed guide. Feel free to skim read some sections (because you already know them, not applicable for your use cases, etc), but try not to skip them entirely.
- If you are not able to understand a particular feature, go through the Vim user manual for that topic first. Each chapter has related documentation links at the top and external learning resources are often mentioned at the end of command descriptions.
- Practice the commands multiple times to build muscle memory.
- Building your own cheatsheet is highly recommended. You wouldn't need to refer most of the basic commands often, so you'll end up with a manageable reference sheet. As you continue to build muscle memory, you can prune the cheatsheet further.
- This guide covers a lot, but not everything. So, you'll need to learn from other resources too and add to your personal cheatsheet.
Acknowledgements
- Vim help files — user and reference manuals
- /r/vim/ and vi.stackexchange — helpful forums
- tex.stackexchange — for help on pandoc and
texrelated questions - canva — cover image
- Warning and Info icons by Amada44 under public domain
- oxipng, pngquant and svgcleaner — for optimizing images
- Rodrigo Girão Serrão — for feedback and suggestions
- Andy — for cover image suggestions
Feedback and Errata
I would highly appreciate it if you'd let me know how you felt about this book. It could be anything from a simple thank you, pointing out a typo, mistakes in code snippets, which aspects of the book worked for you (or didn't!) and so on. Reader feedback is essential and especially so for self-published authors.
You can reach me via:
- Issue Manager: https://github.com/learnbyexample/vim_reference/issues
- E-mail: learnbyexample.net@gmail.com
- Twitter: https://twitter.com/learn_byexample
Author info
Sundeep Agarwal is a lazy being who prefers to work just enough to support his modest lifestyle. He accumulated vast wealth working as a Design Engineer at Analog Devices and retired from the corporate world at the ripe age of twenty-eight. Unfortunately, he squandered his savings within a few years and had to scramble trying to earn a living. Against all odds, selling programming ebooks saved his lazy self from having to look for a job again. He can now afford all the fantasy ebooks he wants to read and spends unhealthy amount of time browsing the internet.
When the creative muse strikes, he can be found working on yet another programming ebook (which invariably ends up having at least one example with regular expressions). Researching materials for his ebooks and everyday social media usage drowned his bookmarks, so he maintains curated resource lists for sanity sake. He is thankful for free learning resources and open source tools. His own contributions can be found at https://github.com/learnbyexample.
List of books: https://learnbyexample.github.io/books/
License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Code snippets are available under MIT License.
Resources mentioned in Acknowledgements section above are available under original licenses.
Book version
2.0
See Version_changes.md to track changes across book versions.
Introduction
Back in 2007, I had a rough beginning as a design engineer at a semiconductor company in terms of using software tools. Linux command line, Vim and Perl were all new to me. I distinctly remember progressing from dd (delete current line) to d↓ (delete current line as well as the line below) and feeling happy that it reduced time spent on editing. Since I was learning on the job, I didn't know about count prefix or the various ways I could've deleted all the lines from the beginning of the file to the line containing a specific phrase. Or even better, I could've automated editing multiple files if I had been familiar with sed or progressed that far with Perl.
I also remember that we got a two-sided printed cheatsheet that we kept pinned to our cabins. That was one of the ways I kept adding commands to my repertoire. But, I didn't have a good insight to Vim's philosophy and I didn't know how to apply many of the cheatsheet commands. At some point, I decided to read the Vim book by Steve Oualline and that helped a lot, but it was also too long and comprehensive for me to read it all. My memory is hazy after that, and I don't recall what other resources I used. However, I'm sure I didn't effectively utilize built-in help. Nor did I know about stackoverflow or /r/vim until after I left my job in 2014.
Still, I knew enough to conduct a few Vim learning sessions for my colleagues. That came in handy when I got chances to teach Vim as part of a scripting course for college students. From 2016 to 2018, I started maintaining my tutorials on Linux command line, Vim and scripting languages as GitHub repos. As you might guess, I then started polishing these materials and published them as ebooks. This is an ongoing process, with Vim Reference Guide being the twelfth ebook.
Why Vim?
You've probably already heard that Vim is a text editor, powerful one at that. Vim's editing features feel like a programming language and you can customize the editor using scripting languages. Apart from a plethora of editing commands and support for regular expressions, you can also incorporate external commands. To sum it up, most editing tasks can be managed from within Vim itself instead of having to write a script.
Now, you might wonder, what is this need for complicated editing features? Why does a text editor require programming capabilities? Why is there even a requirement to learn how to use a text editor? Isn't it enough to have the ability to enter text, use keys like Backspace/Delete/Home/End/Arrow/etc, menubar, toolbar, some shortcuts, a search and replace feature and so on? A simple and short answer — to reduce repetitive manual task.
What I like the most about Vim:
- Lightweight and fast
- Modal editing helps me to think logically based on the type of editing task
- Composing commands and the ability to record them for future use
- Settings customization and creating new commands
- Integration with shell commands
There's a huge ecosystem of plugins, packages and colorschemes as well, but I haven't used them much. I've used Vim for a long time, but not really a power user. I prefer using GVim, tab pages, mouse, arrow keys, etc. So, if you come across tutorials and books suggesting you should avoid using them, remember that they are only subjective preferences.
Here are some more opinions by those who enjoy using Vim:
Should everybody use Vim? Is it suitable for all kinds of editing tasks? I'd say no. There are plenty of other well established text editors and new ones are coming up all the time. The learning curve isn't worth it for everybody. If Vim wasn't being used at job, I probably wouldn't have bothered with it. Don't use Vim for the wrong reasons article discusses this topic in more detail.
Installation
I use the following command on Ubuntu (a Linux distribution):
sudo apt install vim vim-gui-common
- :h usr_90.txt — user manual for installation on different platforms, common issues, upgrading, uninstallation, etc
- vi.stackexchange: How can I get a newer version of Vim? — building from source, using distribution packages, etc
See https://github.com/vim/vim for source code and other details.
Ice Breaker
Open a terminal and follow these steps:
gvim ip.txtopens a file namedip.txtfor editing- You can also use
vimif you prefer terminal instead of GUI, or ifgvimis not available
- You can also use
- Press
ikey (yes, the lowercase alphabeti, not some alien key) - Start typing, for example
What a weird editor - Press
Esckey - Press
:key - Type
wq - Press
Enterkey cat ip.txt— sanity check to see what you typed was saved or not
Phew, what a complicated procedure to write a simple line of text, isn't it? This is the most challenging and confusing part for a Vim newbie. Here's a brief explanation for the above steps:
- Vim is a modal editor. You have to be aware which mode you are in and use commands or type text accordingly
- When you first launch Vim, it starts in Normal mode (primarily used for editing and moving around)
- Pressing
ikey is one of the ways to enter Insert mode (where you type the text you want to save in a file) - After you've entered the text, you need to save the file. To do so, you have to go back to Normal mode first by pressing the
Esckey - Then, you have to go to yet another mode! Pressing
:key brings up the Command-line mode and awaits further instruction wqis a combination of write and quit commands- use
wq ip.txtif you forgot to specify the filename while launching Vim, or perhaps if you opened Vim from the Start menu instead of a terminal
- use
Enterkey completes the command you've typed
If you launched GVim, you'll likely have Menu and Tool bars, which would've helped with operations like saving, quitting, etc. Nothing wrong with using them, but this book will not discuss those operations. In fact, you'll learn how to configure Vim to hide them in the Customizing Vim chapter.
Don't proceed any further if you aren't comfortable with the above steps. Take help of youtube videos if you must. Master this basic procedure and you will be ready for Vim awesomeness that'll be discussed in the coming sections and chapters.
Material presented here is based on GVim (GUI), which has a few subtle differences compared to Vim (TUI). See this stackoverflow thread for more details.
Options and details related to opening Vim from the command line will be discussed in the CLI options chapter.
Built-in tutor
gvimtutorcommand that opens a tutorial session with lessons to get started with Vim- don't worry if something goes wrong as you'll be working with a temporary file
- use
vimtutorifgvimis not available - pro-tip: go through this short tutorial multiple times, spread over multiple days and make copious notes for future reference
Next step is :h usr_02.txt, which provides enough information about editing files with Vim.
See also vimtutor-sequel, which provides advanced lessons.
Built-in help
Vim comes with comprehensive user and reference manuals. The user manual reads like a text book and reference manual has more details than you are likely to need. There's also an online site with these help contents, which will be linked as appropriate throughout this book.
- You can access built-in help in several ways:
- type
:helpfrom Normal mode (or just the:hshort form) - GVim has a
Helpmenu - press
F1key from Normal mode
- type
- :h usr_toc.txt table of contents for User Manual
- Task oriented explanations, from simple to complex. Reads from start to end like a book
- :h reference_toc table of contents for Reference Manual
- Precise description of how everything in Vim works
- :h quickref quick reference guide
- :h help-summary effectively using help depending on the topic/feature you are interested in
- :h version9.txt what's new in Vim 9
- See also VimLog, a ChangeLog for Vim
Here's a neat table from :h help-context:
| WHAT | PREPEND | EXAMPLE |
|---|---|---|
| Normal mode command | :help x |
|
| Visual mode command | v_ |
:help v_u |
| Insert mode command | i_ |
:help i_<Esc> |
| Command-line command | : |
:help :quit |
| Command-line editing | c_ |
:help c_<Del> |
| Vim command argument | - |
:help -r |
| Option | ' |
:help 'textwidth' |
| Regular expression | / |
:help /[ |
You can go through a copy of the documentation online at https://vimhelp.org/. As shown above, all the
:hhints in this book will also be linked to the appropriate online help section.
Vim learning resources
As mentioned in the Preface chapter, this Vim Reference Guide is more like a cheatsheet instead of a typical book for learning Vim. In addition to built-in features already mentioned in the previous sections, here are some resources you can use:
Tutorials
- Vim primer — learn Vim in a way that will stay with you for life
- Vim galore — everything you need to know about Vim
- Learn Vim progressively — short introduction that covers a lot
- Vim from the ground up — article series for beginners to expert users
Books
Interactive
- OpenVim — interactive tutorial
- Vim Adventures — learn Vim by playing a game
- Learn vim and learn it fast — interactive lessons designed to help you get better at Vim faster
See my Vim curated list for a more complete list of learning resources, cheatsheets, tips, tricks, forums, etc.
Modes of Operation
As mentioned earlier, Vim is a modal editor. This book will mainly discuss these four modes:
- Insert mode
- Normal mode
- Visual mode
- Command-line mode
This section provides a brief description for these modes. Separate chapters will discuss their features in more detail.
For a complete list of modes, see :h vim-modes-intro and :h mode-switching. See also this comprehensive illustration of navigating modes.
Insert mode
This is the mode where the required text is typed. There are also commands available for moving around, deleting, autocompletion, etc.
Pressing the Esc key takes you back to the Normal mode.
Normal mode
This is the default mode when Vim is opened. This mode is used to run commands for operations like cut, copy, paste, recording, moving around, etc. This is also known as the Command mode.
Visual mode
Visual mode is used to edit text by selecting them first. Selection can either be done using mouse or visual commands.
Pressing the Esc key takes you back to the Normal mode.
Command-line mode
This mode is used to perform file operations like save, quit, search, replace, execute shell commands, etc. An operation is completed by pressing the Enter key after which the mode changes back to the Normal mode. The Esc key can be used to ignore whatever is typed and return to the Normal mode.
The space at the bottom of the screen used for this mode is referred to as Command-line area. It is usually a single line, but can expand for cases like auto completion, shell commands, etc.
Identifying the current mode
- In Insert mode, you get a blinking
|cursor- also,
-- INSERT --can be seen on the left hand side of the Command-line area
- also,
- In Normal mode, you get a blinking rectangular block cursor, something like this █
- In Visual mode, the Command-line area shows
-- VISUAL --or-- VISUAL LINE --or-- VISUAL BLOCK --according to the visual command used - In Command-line mode, the cursor is of course in the Command-line area
See also :h 'showmode' setting.
Vim philosophy and features
Commands discussed in this section will be covered again in later chapters. The idea here is to give you a brief introduction to modes and notable Vim features. See also:
- Best introduction to Vi and its core editing concepts explained as a language (this stackoverflow thread also has numerous Vim tips and tricks)
- Seven habits of effective text editing
As a programmer, I love how composable Vim commands are. For example, you can do this in Normal mode:
dGdelete from the current line to the end of the file- where
dis the delete command awaiting further instruction - and
Gis a motion command to move to the last line of the file
- where
yGcopy from the current line to the end of the file- where
yis the yank (copy) command awaiting further instruction
- where
Most Normal mode commands accept a count prefix. For example:
3ppaste the copied content three times5xdelete the character under the cursor and 4 characters to its right (total 5 characters)3followed byCtrl+aadd3to the number under the cursor
There are context aware operations too. For example:
diwdelete a word regardless of where the cursor is on that wordya}copy all characters within{}including the{}characters
If you are a fan of selecting text before editing them, you can use the Visual mode. There are several commands you can use to start Visual mode. If enabled, you can even use mouse to select the required portions.
~invert the case of the visually selected text (i.e. lowercase becomes UPPERCASE and vice versa)gfollowed byCtrl+afor visually selected lines, increment numbers by1for the first line, by2for the second line, by3for the third line and so on
The Command-line mode is useful for file level operations, search and replace, changing Vim configurations, talking to external commands and so on.
/searchpatternsearch the given pattern in the forward direction:g/call/ddelete all lines containingcall:g/cat/ s/animal/mammal/greplaceanimalwithmammalonly for the lines containingcat:3,8! sortsort only lines3to8(uses an external commandsort):set incsearchhighlights the current match as you type the search pattern
Changes to Vim configurations from the Command-line mode are applicable only for that particular session. You can use the vimrc file to load the settings at startup.
colorscheme murphya dark themeset tabstop=4width for the tab character (default is8)nnoremap <F5> :%y+<CR>mapF5key to copy everything to the system clipboard in Normal modeinoreabbrev teh theautomatically correcttehtothein Insert mode
There are many more Vim features that'd help you with text processing and customizing the editor to your needs, some of which you'll get to know in the coming chapters.
Finally, you can apply your Vim skills elsewhere too. Vim-like features have been adopted across a huge variety of applications and plugins, for example:
- less command supports vim-like navigation
- Extensible vi layer for Emacs
- Vimium (browser extension), qutebrowser (keyboard-driven browser with vim-like navigation), etc
- JetBrains IdeaVim, VSCodeVim, etc
- Huge list of Vim-like applications and plugins
Vim's history
See Where Vim Came From if you are interested in knowing Vim's history that traces back to the 1960s with qed, ed, etc.
Chapters
Here's a list of remaining chapters:
- Insert mode
- Normal mode
- Command-line mode
- Visual mode
- Regular Expressions
- Macro
- Customizing Vim
- CLI options
Insert mode
This is the mode where the required text is typed. There are also commands available for moving around, deleting, autocompletion, etc.
Documentation links:
- :h usr_24.txt — overview of the most often used Insert mode commands
- :h insert.txt — reference manual for Insert and Replace mode
Recall that you need to add
i_prefix for built-in help on Insert mode commands, for example :h i_CTRL-P.
Motion keys and commands
←move left by one character within the current line→move right by one character within the current line↓move down by one line↑move up by one lineCtrl+←andCtrl+→move to the start of the current/previous and next word respectively- From :h word "A word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space"
- you can also use
Shiftkey instead ofCtrl
Homemove to the start of the lineEndmove to the end of the linePageUpmove up by one screenPageDownmove down by one screenCtrl+Homemove to the start of the fileCtrl+Endmove to the end of the file
You can use the
whichwrapsetting (wwfor short) to allow←and→arrow keys to cross lines. For example,:set ww+=[,]tells Vim to allow left and right arrow keys to move across lines in Insert mode (+=is used here to preserve existing options for thewhichwrapsetting).
Deleting
Deletedelete the character after the cursorBackspacedelete the character before the cursorCtrl+halso deletes the character before the cursor
Ctrl+wdelete characters before the cursor until the start of a word- From :h word "A word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space"
Ctrl+udelete all the characters before the cursor in the current line, preserves indentation if any- if you have typed some characters in an existing line, this will delete characters till the starting point of the modification
Autocomplete word
Ctrl+pautocomplete word based on matching words in the backward directionCtrl+nautocomplete word based on matching words in the forward direction
If more than one word matches, they are displayed using a popup menu. You can take further action using the following options:
↑and↓move up and down the list, but doesn't change the autocompleted textCtrl+pandCtrl+nmove up and down the list as well as change the autocompleted text to that particular selectionCtrl+yconfirm the current selection (the popup menu disappears)- you can also use the
Enterkey for confirmation if you have used the arrow keys to move through the popup list
- you can also use the
Typing any character will make the popup menu disappear and insert whatever character you had typed.
Autocomplete line
Ctrl+xfollowed byCtrl+lautocomplete line based on matching lines in the backward direction
If more than one line matches, they are displayed using a popup menu. In addition to the options seen in the previous section, you can also use
Ctrl+lto move up the list.
Autocomplete assist
Ctrl+ecancels autocomplete- you'll retain the text you had typed before invoking autocomplete
See :h ins-completion for more details and other autocomplete features. See :h 'complete' setting for customizing autocomplete commands.
Execute a Normal mode command
Ctrl+oexecute a Normal mode command and return to Insert modeCtrl+ofollowed byAmoves the cursor to the end of the current lineCtrl+ofollowed by3jmoves the cursor three lines belowCtrl+ofollowed byceclear till the end of the word
Indenting
Ctrl+tindent the current lineCtrl+dunindent the current line0followed byCtrl+ddeletes all indentation in the current line
Cursor can be anywhere in the line for the above features. Indentation depends on the
shiftwidthsetting. See :h 'shiftwidth' for more details.
Insert register contents
Ctrl+rhelps to insert the contents of a registerCtrl+rfollowed by%inserts the current file nameCtrl+rfollowed byainserts the content of"aregister
Ctrl+rfollowed by=allows you to insert the result of an expressionCtrl+rfollowed by=12+1012and thenEnterkey inserts1024Ctrl+rfollowed by=strftime("%Y/%m/%d")and thenEnterkey inserts the current date, for example2022/02/02
From :h 24.6:
If the register contains characters such as
<BS>or other special characters, they are interpreted as if they had been typed from the keyboard. If you do not want this to happen (you really want the<BS>to be inserted in the text), use the commandCTRL-R CTRL-R {register}.
Registers will be discussed in more details in the Normal mode chapter. See :h usr_41.txt to get started with Vim script.
Insert special characters
Ctrl+vhelps to insert special keys literallyCtrl+vfollowed byEscgives^[Ctrl+vfollowed byEntergives^M
Ctrl+qalias forCtrl+v, helps if it is mapped to do something else
You'll see a practical usage of this command in the Macro chapter. You can also specify the character using decimal, octal or hexadecimal formats. See :h 24.8 for more details.
Insert digraphs
Ctrl+khelps to insert digraphs (two character combinations used to represent a single character, such characters are usually not available on the keyboard)Ctrl+kfollowed byYegives¥
You can use
:digraphsto get a list of combinations and their respective characters. You can also define your own combinations using the:digraphcommand. See :h 24.9 for more details.
Normal mode
Make sure you are in Normal mode before trying out the commands in this chapter. Press Esc key to return to Normal mode from other modes. Press Esc again if needed.
Documentation links:
- :h usr_03.txt — moving around
- :h usr_04.txt — making small changes
- :h motion.txt — reference manual for motion commands
- :h change.txt — reference manual for commands that delete or change text
- :h undo.txt — reference manual for undo and redo
Arrow motions
The four arrow keys can be used in Vim to move around, just like other text editors. Vim also maps them to four letters in Normal mode.
hor←move left by one character within the current linejor↓move down by one linekor↑move up by one linelor→move right by one character within the current line
Vim offers a plethora of motion commands. Several sections will discuss them later in this chapter.
You can use the
whichwrapsetting to allow←and→arrow keys to cross lines. For example,:set ww+=<,>tells Vim to allow left and right arrow keys to move across lines in Normal and Visual modes. Addhandlto this comma separated list if want those commands to cross lines as well.
Cut
There are various ways to delete text. All of these commands can be prefixed with a count value. d and c commands can accept any of the motion commands. Only arrow motion examples are shown in this section, many more variations will be discussed later in this chapter.
dddelete the current line2dddelete the current line and the line below it (total 2 lines)djord↓can also be used
10dddelete the current line and 9 lines below it (total 10 lines)dkdelete the current line and the line above itd↑can also be used
d3kdelete the current line and 3 lines above it (total 4 lines)3dkcan also be used
Ddelete from the current character to the end of line (same asd$, where$is a motion command to move to the end of line)xdelete only the current character under the cursor (same asdl)5xdelete the character under the cursor and 4 characters to its right (total 5 characters)Xdelete the character before the cursor (same asdh)- if the cursor is on the first character in the line, deleting would depend on the
whichwrapsetting as discussed earlier
- if the cursor is on the first character in the line, deleting would depend on the
5Xdelete 5 characters to the left of the cursorccdelete the current line and change to Insert mode- indentation will be preserved depending on the
autoindentsetting
- indentation will be preserved depending on the
4ccdelete the current line and 3 lines below it and change to Insert mode (total 4 lines)Cdelete from the current character to the end of line and change to Insert modesdelete only the character under the cursor and change to Insert mode (same ascl)5sdelete the character under the cursor and 4 characters to its right and change to Insert mode (total 5 characters)Sdelete the current line and change to Insert mode (same ascc)- indentation will be preserved depending on the
autoindentsetting
- indentation will be preserved depending on the
You can also select text (using mouse or visual commands) and then press
dorxorcorsto delete the selected portions. Example usage will be discussed in the Visual mode chapter.
The deleted portions can also be pasted elsewhere using the paste command (discussed later in this chapter).
Copy
There are various ways to copy text using the yank command y.
yycopy the current lineYalso copies the current line
y$copy from the current character to the end of line- use
:nnoremap Y y$if you wantYto behave similarly to theDcommand
- use
2yycopy the current line and the line below it (total 2 lines)yjandy↓can also be used
10yycopy the current line and 9 lines below it (total 10 lines)ykcopy the current line and the line above ity↑can also be used
You can also select text (using mouse or visual commands) and then press
yto copy them.
Paste
The put (paste) command p is used after cut or copy operations.
ppaste the copied content once- if the copied text was line based, content is pasted below the current line
- if the copied text was part of a line, content is pasted to the right of the cursor
Ppaste the copied content once- if the copied text was line based, content is pasted above the current line
- if the copied text was part of a line, content is pasted to the left of the cursor
3pand3Ppaste the copied content three times]ppaste the copied content likepcommand, but changes the indentation level to match the current line[ppaste the copied content likePcommand, but changes the indentation level to match the current line
Undo
uundo last change- press
uagain for further undos
- press
Uundo latest changes on last edited line- press
Uagain to redo changes
- press
See :h 32.3 for details on
g-andg+commands that you can use to undo branches.
Redo
Ctrl+rredo a change undone byuUredo changes undone byU
Replace characters
Often, you just need to change one character. For example, changing i to j, 2 to 4 and so on.
rjreplace the character under the cursor withjryreplace the character under the cursor withy3rareplace the character under cursor as well as the two characters to the right withaaa- the command will entirely fail if there aren't sufficient characters to match the count
To replace multiple characters with different characters, use R.
Rlionfollowed byEscreplace the character under cursor and three characters to the right withlionEsckey marks the completion ofRcommandBackspacekey will act as an undo command to give back the character that was replaced- if you are replacing at the end of a line, the line will be automatically extended if needed
The advantage of r and R commands is that you remain in the Normal mode, without needing to switch to Insert mode and back.
Repeat a change
.the dot command repeats the last change- If the last change was
2dd(delete current line and the line below), dot key will repeat2dd - If the last change was
5x(delete current character and four characters to the right), dot key will repeat5x - If the last change was
C123<Esc>and dot key is pressed, it will clear from the current character to the end of the line, insert123and go back to Normal mode
From :h 4.3:
The
.command works for all changes you make, except foru(undo),CTRL-R(redo) and commands that start with a colon (:).
See :h repeat.txt for complex repeats, using Vim scripts, etc.
Open new line
oopen a new line below the current line and change to Insert modeOopen a new line above the current line and change to Insert mode
Indentation of the new line depends on the
autoindent,smartindentandcindentsettings.
Moving within the current line
0move to the beginning of the current line (i.e. column number 1)- you can also use the
Homekey
- you can also use the
^move to the beginning of the first non-blank character of the current line (useful for indented lines)$move to the end of the current line- you can also use the
Endkey 3$move to the end of 2 lines below the current line
- you can also use the
g_move to the last non-blank character of the current line3|move to the third column character|is same as0or1|
Moving within long lines that are spread over multiple screen lines:
g0move to the beginning of the current screen lineg^move to the first non-blank character of the current screen lineg$move to the end of the current screen linegjmove down by one screen line, prefix a count to move down by that many screen linesgkmove up by one screen line, prefix a count to move up by that many screen linesgmmove to the middle of the current screen line- Note that this is based on the screen width, not the number of characters in the line!
gMmove to the middle of the current line- Note that this is based on the total number of characters in the line
See :h left-right-motions for more details.
Character motions
These commands allow you to move based on a single character search, within the current line only.
f(move forward to the next occurrence of character(fbmove forward to the next occurrence of characterb3f"move forward to the third occurrence of character"t;move forward to the character just before;3txmove forward to the character just before the third occurrence of characterxFamove backward to the characteraTamove backward to the character just aftera;repeat the previous character motion in the same direction,repeat the previous character motion in the opposite direction- for example,
tcbecomesTcand vice versa
- for example,
Note that the previously used count prefix wouldn't be repeated with the
;or,commands, but you can use a new count prefix. If you pressed a wrong motion command, use theEsckey to abandon the search instead of continuing with the wrongly chosen command.
Word motions
Definitions from :h word and :h WORD are quoted below:
word A word consists of a sequence of letters, digits and underscores, or a sequence of other non-blank characters, separated with white space (spaces, tabs,
<EOL>). This can be changed with theiskeywordoption. An empty line is also considered to be a word.
WORD A WORD consists of a sequence of non-blank characters, separated with white space. An empty line is also considered to be a WORD.
wmove to the start of the next wordWmove to the start of the next WORD192.1.168.43;hellois considered a single WORD, but has multiple words
bmove to the beginning of the current word if the cursor is not at the start of word. Otherwise, move to the beginning of the previous wordBmove to the beginning of the current WORD if the cursor is not at the start of WORD. Otherwise, move to the beginning of the previous WORDemove to the end of the current word if cursor is not at the end of word. Otherwise, move to the end of next wordEmove to the end of the current WORD if cursor is not at the end of WORD. Otherwise, move to the end of next WORDgemove to the end of the previous wordgEmove to the end of the previous WORD3wmove 3 words forward- Similarly, a number can be prefixed for all the other commands mentioned above
All of these motions will work across lines. For example, if the cursor is on the last word of a line, pressing
wwill move to the start of the first word in the next line.
Text object motions
(move backward a sentence)move forward a sentence{move backward a paragraph}move forward a paragraph
More such text objects will be discussed later under the Context editing section. See :h object-motions for a complete list of such motions.
Moving within the current file
ggmove to the first non-blank character of the first lineGmove to the first non-blank character of the last line5Gmove to the first non-blank character of the fifth line- As an alternative, you can use
:5followed byEnterkey (Command-line mode)
- As an alternative, you can use
50%move to halfway point- you can use other percentages as needed
%move to matching pair of brackets like(),{}and[]- This will work across lines and nesting is taken into consideration as well
- If the cursor is on a non-bracket character and a bracket character is present later in the line, the
%command will move to the matching pair of that character (which could be present in some other line too) - Use the
matchpairsoption to customize the matching pairs. For example,:set matchpairs+=<:>will match<>as well
It is also possible to match a pair of keywords like HTML tags, if-else, etc with
%. See :h matchit-install for details.
Moving within the visible window
Hmove to the first non-blank character of the top (home) line of the visible windowMmove to the first non-blank character of the middle line of the visible windowLmove to the first non-blank character of the bottom (low) line of the visible window
Scrolling
Ctrl+dscroll half a page downCtrl+uscroll half a page upCtrl+fscroll one page forwardCtrl+bscroll one page backwardCtrlfollowed by Mouse Scroll scroll one page forward or backward
Reposition the current line
Ctrl+escroll up by a lineCtrl+yscroll down by a linezzreposition the current line to the middle of the visible window- useful to see context around lines that are nearer to the top/bottom of the visible window
ztreposition the current line to the top of the visible windowzbreposition the current line to the bottom of the visible window
See :h 'scrolloff' option if you want to always show context around the current line.
Indenting
>and<indent commands, waits for motion commands similar todory>>indent the current line3>>indent the current line and two lines below (same as>2j)>kindent the current line and the line above>}indent till the end of the paragraph<<unindent the current line5<<unindent the current line and four lines below (same as<4j)<2kunindent the current line and two lines above=auto indent code, use motion commands to indicate the portion to be indented=4jauto indent the current line and four lines below=ipauto indent the current paragraph (you'll learn aboutiplater in the Context editing section)
Indentation depends on the
shiftwidthsetting. See :h shift-left-right, :h = and :h 'shiftwidth' for more details.
You can indent/unindent the same selection multiple times using a number prefix in the Visual mode.
Mark frequently used locations
mamark a location in the file using the alphabeta- you can use any of the 26 alphabets
- use lowercase alphabets to work within the current file
- use uppercase alphabets to work from any file
:markswill show a list of the existing marks
`amove to the exact location marked bya'amove to the first non-blank character of the line marked bya'Amove to the first non-blank character of the line marked byA(this will work for any file where the mark was set)d`adelete from the current character to the character marked bya- marks can be paired with any command that accept motions like
d,y,>, etc
- marks can be paired with any command that accept motions like
Motion commands that take you across lines (for example,
10G) will automatically save the location you jumped from in the default`mark. You can move back to that exact location using``or the first non-blank character using'`. Note that the arrow and word motions aren't considered for the default mark even if they move across lines.
See :h mark-motions for more ways to use marks.
Jumping back and forth
This is helpful if you are moving around often while editing a large file, moving between different buffers, etc. From :h jump-motions:
The following commands are jump commands:
',`,G,/,?,n,N,%,(,),[[,]],{,},:s,:tag,L,M,Hand the commands that start editing a new file.When making a change the cursor position is remembered. One position is remembered for every change that can be undone, unless it is close to a previous change.
Ctrl+onavigate to the previous location in the jump list (oas in old)Ctrl+inavigate to the next location in the jump list (iandoare usually next to each other)g;go to the previous change locationg,go to the newer change locationgiplace the cursor at the same position where it was left last time in the Insert mode
Use
:jumpsand:changesto view the jump and change lists respectively. See :h jump-motions for more details.
Edit with motion
From :h usr_03.txt:
You first type an operator command. For example,
dis the delete operator. Then you type a motion command like4lorw. This way you can operate on any text you can move over.
dGdelete from the current line to the end of the filedggdelete from the current line to the beginning of the filed`adelete from the current character up to the location marked byad%delete up to the matching pairs for(),{},[], etccedelete till the end of word and change to Insert modecwwill also work the same asce, this inconsistency is based on Vi behavior- use
:nnoremap cw dwiif you don't want the old behavior
ylcopy the character under the cursoryfccopy from the character under the cursor up to the next occurrence ofcin the same lined)delete up to the end of the sentence
From :h usr_03.txt:
Whether the character under the cursor is included depends on the command you used to move to that character. The reference manual calls this "exclusive" when the character isn't included and "inclusive" when it is. The
$command moves to the end of a line. Thed$command deletes from the cursor to the end of the line. This is an inclusive motion, thus the last character of the line is included in the delete operation.
Context editing
You have seen examples for combining motions such as w, % and f with editing commands like d, c and y. Such combination of commands require precise positioning to be effective.
Vim also provides a list of handy context based options to make certain editing use cases easier using the i and a text object selections. You can easily remember the difference between these two options by thinking i as inner and a as around.
diwdelete a word regardless of where the cursor is on that word- Equivalent to using
dewhen the cursor is on the first character of the word
- Equivalent to using
diWdelete a WORD regardless of where the cursor is on that WORDdawdelete a word regardless of where the cursor is on that word as well as a space character to the left/right of the word depending on its position in the current sentencedisdelete a sentence regardless of where the cursor is on that sentenceyascopy a sentence regardless of where the cursor is on that sentence as well as a space character to the left/rightcipdelete a paragraph regardless of where the cursor is on that paragraph and change to Insert modeditdelete all characters within HTML/XML tags, nesting is taken care as well- see :h tag-blocks for details about corner cases
di"delete all characters within a pair of double quotes, regardless of where the cursor is within the quotesda'delete all characters within a pair of single quotes along with the quote charactersci(delete all characters within()and change to Insert mode- Works even if the parentheses are spread over multiple lines, nesting is taken care as well
ya}copy all characters within{}including the{}characters- Works even if the braces are spread over multiple lines, nesting is taken care as well
You can use a count prefix for nested cases. For example,
c2i{will clear the inner braces (including the braces, and this could be nested too) and then only the text between braces for the next level.
See :h text-objects for more details.
Named registers
You can use lowercase alphabets a-z to save some content for future use. You can also append some more content to those registers by using the corresponding uppercase alphabets A-Z at a later stage.
"ayycopy the current line to the"aregister"Ayjappend the current line and the line below to the"aregister"ayyfollowed by"Ayjwill result in total three lines in the"aregister
"appaste content from the"aregister"eyiwcopy word under the cursor to the"eregister
You can use
:reg(short for:registers) to view the contents of the registers. Specifying one or more characters (next to each other as a single string) will display contents only for those registers.
The named registers are also used for saving macros (will be discussed in the Macro chapter). You can record an empty macro to clear the contents, for example
qbqclears the"bregister.
Special registers
Vim has nine other types of registers for different use cases. Here are some of them:
"all yanked/deleted text is stored in this register- So, the
pcommand is same as specifying""p
- So, the
"0yanked text is stored in this register- A possible use case: yank some content, delete something else and then paste the yanked content using
"0p
- A possible use case: yank some content, delete something else and then paste the yanked content using
"1to"9deleted contents are stored in these registers and get shifted with each new deletion"1ppaste the contents of last deletion"2ppaste the contents of last but one deletion
"+this register is used to work with the system clipboard contentsgg"+yGcopy entire file contents to the clipboard"+ppaste content from the clipboard
"*this register stores visually selected text- contents of this register can be pasted using middle mouse button click or
"*porShift+Insert
- contents of this register can be pasted using middle mouse button click or
"_black hole register, when you want to delete something without saving it anywhere
Further reading
- :h registers
- stackoverflow: How to use Vim registers
- stackoverflow: Using registers on Command-line mode
- Advanced Vim registers
Search word nearest to the cursor
*searches the word nearest to the cursor in the forward direction (matches only the whole word)Shiftfollowed by left mouse click can also be used in GVim
g*searches the word nearest to the cursor in the forward direction (matches as part of another word as well)- for example, if you apply this command on the word
the, you'll also get matches forthem,lather, etc
- for example, if you apply this command on the word
#searches the word nearest to the cursor in the backward direction (matches only the whole word)g#searches the word nearest to the cursor in the backward direction (matches as part of another word as well)
Join lines
Jjoins the current line and the next line- the deleted
<EOL>character is replaced with a space, unless there are trailing spaces or the next line starts with a)character - indentation from the lines being joined are removed, except the current line
- the deleted
3Jjoins the current line and next two lines with one space in between the linesgJjoins the current line and the next line<EOL>character is deleted (space character won't be added)- indentation won't be removed
![]()
joinspaces,cpoptionsandformatoptionssettings will affect the behavior of these commands. See :h J and scroll down for more details.
Changing case
~invert the case of the character under the cursor (i.e. lowercase becomes UPPERCASE and vice versa)g~followed by motion command to invert the case of those characters- for example:
g~e,g~$,g~iw, etc
- for example:
gufollowed by motion command to change the case of those characters to lowercase- for example:
gue,gu$,guiw, etc
- for example:
gUfollowed by motion command to change the case of those characters to UPPERCASE- for example:
gUe,gU$,gUiw, etc
- for example:
Increment and Decrement numbers
Ctrl+aincrement the number under the cursor or the first occurrence of a number to the right of the cursorCtrl+xdecrement the number under the cursor or the first occurrence of a number to the right of the cursor3followed byCtrl+aadds3to the number1000followed byCtrl+xsubtracts1000from the number
Numbers prefixed with
0,0xand0bwill be treated as octal, hexadecimal and binary respectively (you can also use uppercase forxandb).
Decimal numbers prefixed with
-will be treated as negative numbers. For example, usingCtrl+aon-100will give you-99. While this is handy, this trips me up often when dealing with date formats like 2021-12-07.
Miscellaneous
gfopens a file using the path under the cursor- See :h gf and :h suffixesadd for more details
- See :h window-tag if you want to open the file under the cursor as a split window, new tab and other usecases
Ctrl+gdisplay file information like name, number of lines, etc at the bottom of the screen- See :h CTRL-G for more details and related commands
gfollowed byCtrl+gdisplay information about the current location of the cursor (column, line, word, character and byte counts)gashows the codepoint value of the character under the cursor in decimal, octal and hexadecimal formatsg?followed by motion command to change those characters withrot13transformationg?eon start ofhelloword will change it touryybg?eon start ofuryybword will change it tohello
Switching modes
Normal to Insert mode
iplace the cursor to the left of the current character (insert)aplace the cursor to the right of the current character (append)Iplace the cursor before the first non-blank character of the line (helpful for indented lines)gIplace the cursor before the first column of the linegiplace the cursor at the same position where it was left last time in the Insert modeAplace the cursor at the end of the lineoopen a new line below the current line and change to Insert modeOopen a new line above the current line and change to Insert modesdelete the character under the cursor and change to Insert modeSdelete the current line and change to Insert modecccan also be used- indentation will be preserved depending on the
autoindentsetting
Cdelete from the current character to the end of line and change to Insert mode
Normal to Command-line mode
:change to Command-line mode, awaits further commands/change to Command-line mode for searching in the forward direction?change to Command-line mode for searching in the backward direction
Normal to Visual mode
vvisually select the current characterVvisually select the current lineCtrl+vvisually select columngvselect previously highlighted visual area
See :h mode-switching for a complete table. See also this comprehensive illustration of navigating modes.
Command-line mode
An operation in Command-line mode is completed by pressing the Enter key after which the mode changes back to the Normal mode. Press Esc key to ignore whatever is typed and return to the Normal mode.
Documentation links:
- :h usr_05.txt — set your settings
- :h usr_07.txt — editing more than one file
- :h usr_08.txt — splitting windows
- :h usr_10.txt — making big changes
- :h usr_21.txt — go away and come back
- :h 3.8 — simple searches
- :h cmdline.txt — reference manual for Command-line mode
- :h windows.txt — reference manual for Editing with multiple windows and buffers
Add
:orc_prefix for built-in help on Command-line mode, for example :h :w and :h c_CTRL-R. Use single quotes around options, :h 'autoindent' for example.
Save changes
:wsave changes (:wis short for:write):w filenameprovide a filename if it is a new file or if you want to save to another file:w >> filenameappend to an existing file (w!will create a new file if it doesn't exist):wasave all the changed buffers (:wais short for:wall)
Appending
!forces Vim to override errors, provided you have the appropriate permissions. For example, if you have edited a read-only file,:wwill result in an error and:w!will save the changes. Another case where you'll get an error is:w filenameif the file already exists. Using:w! filenamewill override the error.
By default, the entire file content is used for these commands. You can use a range (discussed later in this chapter) to work with selective lines.
Quit Vim
:qquit the current window (:qis short for:quit)- if other windows/tabs are present, they will remain open
- you will get an error message if there are unsaved changes
:qaquit all (:qais short for:quitall)- you will get an error message if there are unsaved changes
:confirm qasimilar to quit all, but prompts for every file that has unsaved changes
Combining Save and Quit
:wqsave changes and quit:wqasave changes for all files and quit
Append
!to override errors. Not all errors can be skipped, for example unsaved changes on a file that hasn't been named yet.
Working with buffers and tabs
Multiple files can be opened in Vim within the same tab page and/or in different tabs. From :h windows-intro:
- A buffer is the in-memory text of a file.
- A window is a viewport on a buffer.
- A tab page is a collection of windows.
Buffers
:erefreshes the current buffer (:eis short for:edit):e filenameopen a particular file by its path, in the same window:e #switch back to the previous buffer, won't work if that buffer is not named:e#can also be used (no space betweeneand#)
Ctrl+6switch back to the previous buffer, works even if that buffer is not namedCtrl+^can also be used
:e #1open the first buffer:e #2open the second buffer, and so on:buffersshow all buffers:lsor:filescan also be used
:bnopen the next file in the buffer list (:bnis short for:bnext)- opens the first buffer if you are on the last buffer
:bpopen the previous file in the buffer list (:bpis short for:bprevious)- opens the last buffer if you are on the first buffer
Use
:set hiddenif you want to switch to another buffer even if there are unsaved changes in the current buffer. Instead of this setting, you can also use:hide edit filenameto hide the current unsaved buffer. You'll still get an error if you try to quit Vim without saving such buffers, unless you use the!modifier.
See :h 'autowrite' option if you want to automatically save changes when moving to another buffer.
See :h 22.4 and :h buffer-hidden for user and reference manuals on working with buffer lists.
Tabs
:tabe filenameopen the given file in a new tab (:tabeis short for:tabedit)- if
filenameisn't specified, you'll get an unnamed empty window - by default, the new tab is opened to the right of the current tab
:0tabeopen as the first tab:$tabeopen as the last tab- see :h :tabe for more details and features
- if
:tabnswitch to the next tab (:tabnis short for:tabnext)- if tabs to the right are exhausted, switch to the first tab
gtandCtrl+Page Downcan also be used2gtswitch to the second tab (the number specified is absolute, not relative)
:tabpswitch to the previous tab (:tabpis short for:tabprevious)- if tabs to the left are exhausted, switch to the last tab
gTandCtrl+Page Upcan also be used
:tabrswitch to the first tab (:tabris short for:tabrewind):tabfirstcan also be used
:tablswitch to the last tab (:tablis short for:tablast):tabm Nmove the current tab to afterNtabs from the start (:tabmis short for:tabmove):tabm 0move the current tab to the beginning:tabmmove the current tab to the end
:tabm +Nmove the current tabNpositions to the right:tabm -Nmove the current tabNpositions to the left
Splitting
:split filenameopen file for editing in a new horizontal window, above the current window- you can also use
:spinstead of:split :set splitbelowopen horizontal splits below the current window
- you can also use
:vsplit filenameopen file for editing in a new vertical window, to the left of the current window- you can also use
:vsinstead of:vsplit :set splitrightopen vertical splits to the right of the current window
- you can also use
Ctrl+wfollowed bywswitch to the below/right window for horizontal/vertical splits respectivelyCtrl+wfollowed byCtrl+walso performs the same function- switches to the first split if you are on the last split
Ctrl+wfollowed byWswitch to the above/left window for horizontal/vertical splits respectively- switches to the last split if you are on the first split
Ctrl+wfollowed byhjklor arrow keys, switch in the respective directionCtrl+wfollowed bytorbswitch to the top (first) or bottom (last) windowCtrl+wfollowed byHJKL(uppercase), moves the current split to the farthest possible location in the respective direction
Vim adds a highlighted horizontal bar containing the filename for each split.
Edit all buffers
If multiple buffers are open and you want to apply a common editing task for all of them, one option is to use the bufdo command.
:silent! bufdo %s/search/replace/g | updateperform substitution across all the bufferssilentskips displaying normal messages!skips error messages
- It is not an efficient way to open buffers just to search and replace a pattern across multiple files. Use tools like
sed,awkandperlinstead.- See my book list if you'd like to learn about such tools.
- See :h :bufdo, :h :windo and :h :silent for more details.
Further reading
- How to change multiple files
- stackoverflow: Effectively work with multiple files
- When to use Buffers and when to use Tabs
- :h argument-list — for working only with the files provided as Vim CLI arguments
Setting options
From :h options.txt:
Vim has a number of internal variables and switches which can be set to achieve special effects. These options come in three forms:
- boolean can only be on or off
- number has a numeric value
- string has a string value
Here are examples for each of these forms:
:set cursorlinehighlight the line containing the cursor:set history=200increase default history from 50 to 200:set ww+=[,]allow left and right arrow keys to move across lines in Insert mode+=allows you to append to an existing string value
Usage guidelines:
set {option}switch on the given boolean setting:set expandtabuse spaces for tab expansion
set {option}!toggle the given boolean setting:set expandtab!if previously tabs were expanded, it will be turned off and vice versaset inv{option}can also be used
set no{option}switch off the given boolean setting:set noexpandtabdisable expanding tab to spaces
set {option}?get the current value of the given option (works for all three forms):set expandtab?output will beexpandtabornoexpandtabdepending on whether it is switched on or off
set {option}get the current value of number or string option- for example, try
:set historyor:set ww
- for example, try
See :h options.txt for a complete list of usage guidelines and available options.
Search
/searchpatternsearch the given pattern in the forward direction?searchpatternsearch the given pattern in the backward directionEscignore the currently typed pattern and return to Normal modenmove to the next match in the same direction as the last search- if you used
/for searching,nwill move in the forward direction - if you used
?for searching,nwill move in the backward direction
- if you used
Nmove to the next match in the opposite direction of the last search/followed byEnterrepeat the last search in the forward direction?followed byEnterrepeat the last search in the backward directionCtrl+ccancel the search if it is taking too long
By default, the cursor is placed at the starting character of the match. There are various options to place the cursor at other locations:
/searchpattern/splace the cursor at the start of the match- same as
/searchpatternor/searchpattern/s+0 - you can also use
b(begin) instead ofs, but it'll change tosafter the command is executed
- same as
/searchpattern/s+2place the cursor2characters after the start of the match (i.e. the third character of the match)/searchpattern/s-2place the cursor2characters before the start of the match/searchpattern/eplace the cursor at the end of the match/searchpattern/e+4place the cursor4characters after the end of the match/searchpattern/e-4place the cursor4characters before the end of the match/searchpattern/+3place the cursor3lines below the match/searchpattern/-3place the cursor3lines above the match
Highlight settings:
:set hlsearchhighlight the matched patterns:set nohlsearchdo not highlight matched patterns:set hlsearch!toggle the highlight setting:set hlsearch?check what is the current highlight setting:set incsearchhighlights current match as you type the pattern, the screen is updated automatically as needed- other matching portions will be highlighted based on
hlsearchsettings - if you press
Escinstead ofEnter, you'll end up where you originally started before the search
- other matching portions will be highlighted based on
:nohclear the currently highlighted patterns, if any (:nohis short for:nohlsearch)
Using an empty pattern will repeat the last searched pattern. So, you can use something like
//s+3to repeat the last search with this new offset. Empty pattern can be used with substitution command as well (discussed later in this chapter). See :h last-pattern for more details.
You can prefix a count value to the
/,?,nandNcommands. Also, searching will automatically wrap around when it reaches the top or bottom of the file contents, unless you set thenowrapscanoption.
Characters like
.,^,$, etc have special meaning in thesearchpattern. These will be discussed in detail in the Regular Expressions chapter.
Range
By default, certain commands like :d and :s apply to the current line whereas commands like :w and :perldo apply to the entire file. You can prefix a range to change the lines that are acted upon.
:ddelete the current line (:dis short for the:deletecommand):.w filenamesave the current line (represented by.) to the given filename- recall that by default
:wworks on the entire file
- recall that by default
:5ddelete the fifth line:$ddelete the last line (represented by$):25m0move the twenty-fifth line to the start of the file (:mis short for the:movecommand)- the number following
mis the line number after which you want to place the lines specified by the range - use
:t(or:coor:copy) command if you want to copy instead of moving
- the number following
:2,10ddelete the second to tenth lines (comma is used here to separate the start and end ranges):5,$ddelete the fifth line to the last line:5,$-1ddelete the fifth line to the last but one line:%ddelete all the lines (%is a shortcut for the1,$range):/pat1/,/pat2/ddelete the matching range of lines in the forward direction from the current cursor position (forward because/is used)- if there are multiple matches, only the first such range will be deleted
- use
?pattern?to find a match in the backward direction - you can also mix these two types of direction if needed
:/pat1/;+1ddelete the line matchingpat1as well as the line after (total2lines)- using
;will set the line matched by the first pair of the range as the current line for the second pair
- using
:/pat1/;-2ddelete the line matchingpat1as well as two lines before (total3lines):5;/pat1/ddelete from the fifth line to a line matchingpat1after the fifth line- note the use of
;again here, the search will be based on the current cursor line if you use,instead of;
- note the use of
:'a,'bddelete from the line marked byato the line marked byb
If you press
:after a visual selection, you'll automatically get:'<,'>as the visual range. If you prefix a number before pressing:, you'll get a range with that many lines — for example10:will give you:.,.+9as the range.
See :h 10.3 and :h cmdline-ranges for more details.
See :h ex-cmd-index for a complete list of
:commands.
Search and Replace
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]General syntax for the s command (short for substitute) is shown above. Space between the range and s is optional, which you can use for readability.
: s/a/b/replace the first occurrence ofawithbon the current line only- you can also use
:. s/a/b/(recall that.represents the current line) - the delimiter after the replacement string is optional in this case
- you can also use
:2 s/apple/Mango/ireplace the first occurrence ofapplewithMangoon the second line onlyiflag matches thesearchpatterncase insensitively
:3,6 s/call/jump/greplace all the occurrences ofcallwithjumpon lines3to6gflag performs search and replace for all the matching occurrences
:5,$ s/call/jump/greplace all the occurrences ofcallwithjumpfrom the fifth line to the end of the file:% s/call/jump/greplace all the occurrences ofcallin the file withjump- recall that
%is a shortcut for the range1,$
- recall that
You can leave the
searchpatternas empty to reuse the previously searched pattern, which could be from/,?,*,scommand, etc. See :h last-pattern for more details.
See the Regular Expressions chapter for more details on the substitute command.
Editing lines filtered by a pattern
:[range]g[lobal]/{pattern}/[cmd]General syntax for the g command (short for global) is shown above. This command is used to edit lines that are first filtered based on a searchpattern. You can use g! or v to act on lines not satisfying the filtering condition.
:g/call/ddelete all lines containingcall- similar to the
dNormal mode command, the deleted contents will be saved to the default"register :g/call/d ain addition to the default register, the deleted content will also be stored in the"aregister:g/call/d _deleted content won't be saved anywhere, since it uses the black hole register
- similar to the
:g/^#/t0copy all lines starting with#to the start of the file:1,5 g/call/ddelete all lines containingcallonly for the first five lines:v/jump/ddelete all lines not containingjump- same as
:g!/jump/d
- same as
:g/cat/ s/animal/mammal/greplaceanimalwithmammalonly for the lines containingcat:.,.+20 g/^#/ normal >>indent the current line and the next20lines only if the line starts with#- Note the use of
normalwhen you need to use Normal mode commands on the filtered lines - Use
normal!if you don't want user defined mappings to be considered
- Note the use of
In addition to the
/delimiter, you can also use any single byte character other than alphabets,\,"or|.
See :h :g for more details.
Shell commands
You can also use shell commands from within Vim (assuming you have access to these commands).
:!lsexecute the given shell command and display its output- the results are displayed as part of an expanded Command-line area, doesn't change contents of the file
:.! datereplace the current line with the output of the given command- pressing
!!in Normal mode will also result in:.! !waits for motion similar to thedandycommands,!Gwill give:.,$!
- pressing
:%! sortsort all the lines- recall that
%is a shortcut for the range1,$ - note that this executes an external command, not the built-in
:sortcommand
- recall that
:3,8! sortsort only lines3to8:r! dateinsert output of the given command below the current line:r report.loginsert contents of the given file below the current line- Note that
!is not used here since there is no shell command
- Note that
:.!grep '^Help ' %replace the current line with all the lines starting withHelpin the current file%here refers to the current file contents
:shopen a shell session within Vim- use the
exitcommand to quit the session
- use the
Terminal mode
:terminalopen a new terminal window as a horizontal split- the terminal window opens above the current window unless
splitbelowoption is set - you can then use shell commands as you would normally do from a terminal
- the terminal window opens above the current window unless
:vertical :terminalopen a new terminal window as a vertical split- the terminal window opens to the left of the current window unless
splitrightoption is set
- the terminal window opens to the left of the current window unless
Ctrl+wfollowed byworCtrl+wmove to the next window- helps you to easily switch back and forth if you have one text editing window and one terminal window
- see the Splitting section discussed earlier in this chapter for more such commands
Ctrl+wfollowed byNgoes to Terminal-Normal mode which will help you to move around using Normal mode commands, copy text, etc (note that you need to use uppercaseNhere)Ctrl+\followed byCtrl+nanother way to go to Terminal-Normal mode:tnoremap <Esc> <C-w>NmapEsckey to go to Terminal-Normal mode (use of maps will be discussed in more detail in the Customizing Vim chapter)
Ctrl+wfollowed by:go to Command-line mode from terminal window
Depending on your shell, you can use the
exitcommand to end the terminal session.Ctrl+dmight work too.
There are lot of features in this mode, see :h terminal.txt for more details.
Line number settings
:set numberprefix line numbers- this is a visual guideline, doesn't modify the text
- see :h 'numberwidth' for setting the width of the prefix
:set number!toggle number setting:set nonumberdon't use line number prefix:set relativenumberprefix line numbers relative to the current line- current line is assigned
0, lines above and below the current line are assigned1, two lines above and below are assigned2and so on - useful visual guide for commands like
11yy,6>>,9j, etc
- current line is assigned
:set relativenumber!toggle relative number setting:set norelativenumberdon't use relative line number prefix
See :h 5.9 for user manual about often used options.
Sessions
:mksession proj.vimsave the current Vim session with details like cursor position, file list, layout, etc- you can customize things to be saved using the
sessionoptionssetting - for example,
:set sessionoptions+=resizewill save resized window information as well
- you can customize things to be saved using the
:mksession! proj.vimoverwrite existing session:source proj.vimrestore Vim session fromproj.vimfilevim -S proj.vimrestore a session from the command line when launching Vim
See :h 21.4, :h views-sessions and :h 'sessionoptions' for more details.
See stackoverflow: How to save and restore multiple different sessions in Vim? for custom settings to automate the save and restore process and other tips and tricks. See also Learn-Vim: Views, Sessions, and Viminfo.
Viminfo
From :h 21.3:
After editing for a while you will have text in registers, marks in various files, a command line history filled with carefully crafted commands. When you exit Vim all of this is lost. But you can get it back! The
viminfofile is designed to store status information:
- Command-line and Search pattern history
- Text in registers
- Marks for various files
- The buffer list
- Global variables
Each time you exit Vim it will store this information in a file, the
viminfofile. When Vim starts again, theviminfofile is read and the information restored.
The :mksession command doesn't save the viminfo file. You'll have to save and restore this file separately:
:wviminfo! proj.viminfosave the current internal Viminfo contents to the given file- if
!isn't used, you'll get a merged output based on the current internal Viminfo contents and the file contents
- if
:rviminfo! proj.viminforestore Viminfo fromproj.viminfofile!overwrites any existing internal settingsvim -i proj.viminforestore Viminfo from the command line when launching Vim
See :h viminfo-read-write for more details.
Motion, editing and completion commands
Once you are in Command-line mode (after typing : or / or ?), you can use the commands discussed below. Many of these commands are similar to those available in the Insert mode.
←and→move the cursor left and right respectively by one character- you can also use the mouse to position the cursor
Ctrl+←andCtrl+→move the cursor left and right respectively by one WORD- you can also use the
Shiftkey instead ofCtrl - Note that in Insert mode this command moves by word, not WORD
- you can also use the
Ctrl+borHomemove to the beginningCtrl+eorEndmove to the endCtrl+wdelete word before the cursorCtrl+udelete all characters before the cursorCtrl+rinsert register contentsCtrl+rfollowed by%inserts the current file nameCtrl+rfollowed byainserts the content of"aregister
Ctrl+rfollowed by=allows you to insert the result of an expressionCtrl+rfollowed by=12+1012and thenEnterkey inserts1024Ctrl+rfollowed by=strftime("%Y/%m/%d")and thenEnterkey inserts the current date, for example2022/02/02
Ctrl+dshow completions based on the characters typed so farTabautocomplete based on the characters typed so far, pressing this key multiple times will cycle through the completions- behavior can be customized using the
wildmodesetting
- behavior can be customized using the
Ctrl+ccancel and go back to Normal modeEsccancel and go back to Normal mode, depends oncpoptionssetting
See :h usr_20.txt for a nice tutorial on working effectively in the Command-line mode. See :h cmdline-editing and :h cmdline-completion for more details.
Command-line history
There are separate history lists for : commands, searchpattern, etc. These lists make it easy to reuse (after modifications if necessary) previously executed commands.
↑and↓move through the history lists- if you have already typed some characters, you will get only the commands starting with those characters
See :h cmdline-history for more details. You can change the number of entries that are remembered using the
historysetting.
Command-line window
You can also view, edit and execute the history of commands using a special Command-line window. You can open this special window from Normal mode as well as Command-line mode. This window will be in Normal mode by default, which will allow you to move around easily. You can also edit any of the history commands if you wish.
q:window for:commands (from Normal mode)q/andq?window for search patterns (from Normal mode)Ctrl+fuse this shortcut if you are already in the Command-line mode, opens appropriate:or search pattern windows automatically, any text you've typed so far will be preserved as the most recent commandEnterto execute the command under the cursorCtrl+ccontinue editing the command under the cursor in the usual Command-line area, the window will still be visible:qquit the window and go to Normal mode
See :h cmdline-window for more details. You can change the number of entries that are remembered using the
historysetting.
Visual mode
Visual mode allows you to perform editing tasks on selected portions of text. There are various visual commands to select the text of interest. If enabled, you can also use your mouse to select the desired portions.
Documentation links:
- :h 4.4 — visual mode
- :h 10.5 — visual block mode
- :h visual.txt — reference manual for visual mode
Recall that you need to add
v_prefix for built-in help on Visual mode commands, for example :h v_o.
Selection
vvisually select the current character, use any motion command to extend the selectionveselects till the end of a wordvipselects a paragraph (text object) and so on
Vvisually select the current line, you can extend this using motion commandsVggselects the current line and then extends to the start of the file
Ctrl+vvisually select columnsCtrl+vfollowed by3j2lselects a 4x3 block- you can also select using the mouse and then press
Ctrl+v
gvselect previously highlighted visual areaomove the cursor to the diagonally opposite corner of the visual selectionOmove the cursor to the other corner of the current line in visual block selectionEscgo back to Normal mode
Pressing
$in block selection will select until the end of lines for the selected area, even if the lines have different number of characters. This will continue to be the case if you extend the selection with up/down motions.
Editing
ddelete the selected textyyank (copy) the selected textpreplace the selected text with contents of the default"register- See :h v_p for more details, corner cases, uppercase
Pcommand behavior, etc
- See :h v_p for more details, corner cases, uppercase
cclear the selected text and change to Insert mode- for block selection, you can type some text and press the
Esckey to replicate that text across all the visually selected lines
- for block selection, you can type some text and press the
Csimilar tocbut clears till the end of lines before changing to Insert modeIfor block selection, pressI, type some text and press theEsckey to replicate that text across all lines to the left of the column- text will not be inserted for lines shorter than the starting column of selection
- if you type a multiline text, it will not get replicated
Afor block selection, pressA, type some text and press theEsckey to replicate that text across all lines to the right of the column- if
$was used for selection, text will be inserted only after the end of respective lines - otherwise, text will be inserted after the selected column and space characters will used to extend shorter lines if any
- if you type a multiline text, it will not get replicated
- if
rareplace every character of the selected text witha:perform Command-line mode editing commands likeg,s,!,normal, etc on the selected textJandgJjoin lines using the same rules as seen in Normal mode
Press
Ctrl+cif you've typed text after usingIorAbut don't want to replicate the text across all the lines.
See :h visual-operators for a complete list of commands.
Search and Select
gnsearch the last used pattern in the forward direction and visually select the matched portion- selects the current match if the cursor is anywhere within the matching portion
- extends the visual selection if Visual mode is already active
gNsearch the last used pattern in the backward direction and visually select the matched portioncgnheregnacts as the motion for the Normal mode commandc- since this is considered as a single change, pressing
.will change the next match in the forward direction - whereas, if you apply
cwith Normal mode motion, you'll have to first usen(orNdepending on the direction) and then use the.command to repeat the change
- since this is considered as a single change, pressing
Searching will automatically wrap around when it reaches the top or bottom of the file contents, unless you set the
nowrapscanoption.
Indenting
>indent the visual selection once3>indent the visual selection three times<unindent the visual selection once=auto indent code
Consider the following unindented code:
for(i=1; i<5; i++) { for(j=i; j<10; j++) { statements } statements }
Here's the result after applying vip= (you can also use =ip if you prefer Normal mode).
for(i=1; i<5; i++) { for(j=i; j<10; j++) { statements } statements }
For block selection, space will be inserted before the starting column of the block.
Indentation depends on the
shiftwidthsetting. See :h shift-left-right, :h = and :h 'shiftwidth' for more details.
Changing Case
~invert the case of the visually selected text (i.e. lowercase becomes UPPERCASE and vice versa)Uchange the visually selected text to UPPERCASEuchange the visually selected text to lowercase
Increment and Decrement numbers
Ctrl+aincrement by15followed byCtrl+aincrement by5Ctrl+xdecrement by1gfollowed byCtrl+aincrement by1for the first line, by2for the second line, by3for the third line and so on2gfollowed byCtrl+aincrement by2for the first line, by4for the second line, by6for the third line and so on (i.e. repeat the process specified by the count prefix)gfollowed byCtrl+xdecrement by1for the first line, by2for the second line, by3for the third line and so on
The visual selection should cover the numeric portion you wish to increment or decrement. If there are multiple numbers in a visually selected line, only the first number will be affected.
Example for g followed by Ctrl+a:
# before item[0] item[0] item[0] # after item[1] item[2] item[3]
Example for g followed by Ctrl+x:
# before item[12] item[16] item[22] # after item[11] item[14] item[19]
Example for 3g followed by Ctrl+a:
# before item[12] item[16] item[22] # after item[15] item[22] item[31]
Regular Expressions
This chapter will discuss regular expressions (regexp) and related features in detail. As discussed in earlier chapters:
/searchpatternsearch the given pattern in the forward direction?searchpatternsearch the given pattern in the backward direction:range s/searchpattern/replacestring/flagssearch and replace:sis short for the:substitutecommand- the delimiter after the
replacestringportion is optional if you are not using flags
Documentation links:
- :h usr_27.txt — search commands and patterns
- :h pattern-searches — reference manual for Patterns and search commands
- :h :substitute — reference manual for the
:substitutecommand
Recall that you need to add the
/prefix for built-in help on regular expressions, :h /^ for example.
Flags
greplace all occurrences within a matching line- by default, only the first matching portion will be replaced
cask for confirmation before each replacementiignore case forsearchpatternIdon't ignore case forsearchpattern
These flags are applicable for the substitute command but not the / or ? searches. Flags can also be combined, for example:
s/cat/Dog/gireplace every occurrence ofcatwithDog- Case is ignored, so
Cat,cAt,CAT, etc will also be replaced - Note that
idoesn't affect the case of the replacement string
- Case is ignored, so
See :h s_flags for a complete list of flags and more details about them.
Anchors
By default, regexp will match anywhere in the text. You can use line and word anchors to specify additional restrictions regarding the position of matches. These restrictions are made possible by assigning special meaning to certain characters and escape sequences. The characters with special meaning are known as metacharacters in regular expressions parlance. In case you need to match those characters literally, you need to escape them with a \ character (discussed in the Escaping metacharacters section later in this chapter).
^restricts the match to the start-of-line^ThismatchesThis is a samplebut notDo This
$restricts the match to the end-of-line)$matchesapple (5)but notdef greeting():
^$match empty lines\<patternrestricts the match to the start of a word- word characters include alphabets, digits and underscore
\<hismatcheshisorto-hisorhistorybut notthisor_hist
pattern\>restricts the match to the end of a wordhis\>matcheshisorto-hisorthisbut nothistoryor_hist
\<pattern\>restricts the match between the start of a word and end of a word\<his\>matcheshisorto-hisbut notthisorhistoryor_hist
End-of-line can be
\r(carriage return),\n(newline) or\r\ndepending on your operating system and thefileformatsetting.
See :h pattern-atoms for more details.
Dot metacharacter
.match any single character other than end-of-linec.tmatchescatorcotorc2torc^torc.torc;tbut notcantoractorsit
\_.match any single character, including end-of-line
As seen above, matching end-of-line character requires special attention. Which is why examples and descriptions in this chapter will assume you are operating line wise unless otherwise mentioned. You'll later see how
\_is used in many more places to include end-of-line in the matches.
Greedy Quantifiers
Quantifiers can be applied to literal characters, the dot metacharacter, groups, backreferences and character classes. Basic examples are shown below, more will be discussed in the sections to follow.
*match zero or more timesabc*matchesaborabcorabcccorabccccccbut notbcError.*validmatchesError: invalid inputbut notvalid Errors/a.*b/X/replacestable bottle buswithtXus
\+match one or more timesabc\+matchesabcorabcccbut notaborbc
\?match zero or one times\=can also be used, helpful if you are searching backwards with the?commandabc\?matchesaborabc. This will matchabcccorabccccccas well, but only theabcportions/abc\?/X/replacesabccwithXc
\{m,n}matchmtontimes (inclusive)ab\{1,4}cmatchesabcorabbcorxabbbczbut notacorabbbbbc- if you are familiar with BRE, you can also use
\{m,n\}(ending brace is escaped)
\{m,}match at leastmtimesab\{3,}cmatchesxabbbczorabbbbbcbut notacorabcorabbc
\{,n}match up tontimes (including0times)ab\{,2}cmatchesabcoracorabbcbut notxabbbczorabbbbbc
\{n}match exactlyntimesab\{3}cmatchesxabbbczbut notabbcorabbbbbc
Greedy quantifiers will consume as much as possible, provided the overall pattern is also matched. That's how the Error.*valid example worked. If .* had consumed everything after Error, there wouldn't be any more characters to try to match valid. How the regexp engine handles matching varying amount of characters depends on the implementation details (backtracking, NFA, etc).
See :h pattern-overview for more details.
If you are familiar with other regular expression flavors like Perl, Python, etc, you'd be surprised by the use of
\in the above examples. If you use the\vvery magic modifier (discussed later in this chapter), the\won't be needed.
Non-greedy Quantifiers
Non-greedy quantifiers match as minimally as possible, provided the overall pattern is also matched.
\{-}match zero or more times as minimally as possibles/t.\{-}a/X/greplacesthat is quite a fabricated talewithXX fabricaXle- the matching portions are
tha,t is quite aandted ta
- the matching portions are
s/t.*a/X/greplacesthat is quite a fabricated talewithXlesince*is greedy
\{-m,n}matchmtontimes as minimally as possiblemorncan be left out as seen in the previous sections/.\{-2,5}/X/replaces123456789withX3456789(here.matched 2 times)s/.\{-2,5}6/X/replaces123456789withX789(here.matched 5 times)
See :h pattern-overview and stackoverflow: non-greedy matching for more details.
Character Classes
To create a custom placeholder for a limited set of characters, you can enclose them inside the [] metacharacters. Character classes have their own versions of metacharacters and provide special predefined sets for common use cases.
[aeiou]match any lowercase vowel character[^aeiou]match any character other than lowercase vowels[a-d]match any ofaorborcord- the range metacharacter
-can be applied between any two characters
- the range metacharacter
\amatch any alphabet character[a-zA-Z]\Amatch other than alphabets[^a-zA-Z]\lmatch lowercase alphabets[a-z]\Lmatch other than lowercase alphabets[^a-z]\umatch uppercase alphabets[A-Z]\Umatch other than uppercase alphabets[^A-Z]\dmatch any digit character[0-9]\Dmatch other than digits[^0-9]\omatch any octal character[0-7]\Omatch other than octals[^0-7]\xmatch any hexadecimal character[0-9a-fA-F]\Xmatch other than hexadecimals[^0-9a-fA-F]\hmatch alphabets and underscore[a-zA-Z_]\Hmatch other than alphabets and underscore[^a-zA-Z_]\wmatch any word character (alphabets, digits, underscore)[a-zA-Z0-9_]- this definition is same as seen earlier with word boundaries
\Wmatch other than word characters[^a-zA-Z0-9_]\smatch space and tab characters[ \t]\Smatch other than space and tab characters[^ \t]
Here are some examples with character classes:
c[ou]tmatchescotorcut\<[ot][on]\>matchesoooronortoortnas whole words only^[on]\{2,}$matchesnoornonornoonoronetc as whole lines onlys/"[^"]\+"/X/greplaces"mango" and "(guava)"withX and Xs/\d\+/-/greplacesSample123string777numberswithSample-string-numberss/\<0*[1-9]\d\{2,}\>/X/greplaces0501 035 26 98234withX 035 26 X(numbers >=100 with optional leading zeros)s/\W\+/ /greplacesload2;err_msg--\antwithload2 err_msg ant
To include the end-of-line character, use
\_instead of\for any of the above escape sequences. For example,\_swill help you match across lines. Similarly, use\_[]for bracketed classes.
![]()
The above escape sequences do not have special meaning within bracketed classes. For example,
[\d\s]will only match\ordors. You can use named character sets in such scenarios. For example,[[:digit:][:blank:]]to match digits or space or tab characters. See :h :alnum: for full list and more details.
The predefined sets are also better in terms of performance compared to bracketed versions. And there are more such sets than the ones discussed above. See :h character-classes for more details.
Alternation and Grouping
Alternation helps you to match multiple terms and they can have their own anchors as well (since each alternative is a regexp pattern). Often, there are some common things among the regular expression alternatives. In such cases, you can group them using a pair of parentheses metacharacters. Similar to a(b+c)d = abd+acd in maths, you get a(b|c)d = abd|acd in regular expressions.
\|match either of the specified patternsmin\|maxmatchesminormaxone\|two\|threematchesoneortwoorthree\<par\>\|er$matches the whole wordparor a line ending wither
\(pattern\)group a pattern to apply quantifiers, create a terser regexp by taking out common elements, etca\(123\|456\)bis equivalent toa123b\|a456bhand\(y\|ful\)matcheshandyorhandfulhand\(y\|ful\)\?matcheshandorhandyorhandful\(to\)\+matchestoortotoortototoand so onre\(leas\|ceiv\)\?edmatchesreedorreleasedorreceived
There can be tricky situations when using alternation. Say, you want to match are or spared — which one should get precedence? The bigger word spared or the substring are inside it or based on something else? The alternative which matches earliest in the input gets precedence, irrespective of the order of the alternatives.
s/are\|spared/X/greplacesrare spared areawithrX X Xas/spared\|are/X/gwill also give the same result
In case of matches starting from the same location, for example spa and spared, the leftmost alternative gets precedence. Sort by longest term first if don't want shorter terms to take precedence.
s/spa\|spared/**/greplacesspared sparewith**red **res/spared\|spa/**/greplacesspared sparewith** **re
Backreference
The groupings seen in the previous section are also known as capture groups. The string captured by these groups can be referred later using a backreference \N where N is the capture group you want. Backreferences can be used in both search and replacement sections.
\(pattern\)capture group for later use via backreferences\%(pattern\)non-capturing group- leftmost group is
1, second leftmost group is2and so on (maximum9groups) \1backreference to the first capture group\2backreference to the second capture group\9backreference to the ninth capture group&or\0backreference to the entire matched portion
Here are some examples:
\(\a\)\1matches two consecutive repeated alphabets likeee,TT,ppand so on- recall that
\arefers to[a-zA-Z]
- recall that
\(\a\)\1\+matches two or more consecutive repeated alphabets likeee,ttttt,PPPPPPPPand so ons/\d\+/(&)/greplaces52 apples 31 mangoeswith(52) apples (31) mangoes(surround digits with parentheses)s/\(\w\+\),\(\w\+\)/\2,\1/greplacesgood,bad 42,24withbad,good 24,42(swap words separated by comma)s/\(_\)\?_/\1/greplaces_fig __123__ _bat_withfig _123_ bat(reduce__to_and delete if it is a single_)s/\(\d\+\)\%(abc\)\+\(\d\+\)/\2:\1/replaces12abcabcabc24with24:12(match digits separated by one or moreabcsequences, swap the numbers with:as the separator)- note the use of non-capturing group for
abcsince it isn't needed later s/\(\d\+\)\(abc\)\+\(\d\+\)/\3:\1/does the same if only capturing groups are used
- note the use of non-capturing group for
Referring to the text matched by a capture group with a quantifier will give only the last match, not the entire match. Use a capture group around the grouping and quantifier together to get the entire matching portion. In such cases, the inner grouping is an ideal candidate to use non-capturing group.
s/a \(\d\{3}\)\+/b (\1)/replacesa 123456789withb (789)a 4839235will be replaced withb (923)5
s/a \(\%(\d\{3}\)\+\)/b (\1)/replacesa 123456789withb (123456789)a 4839235will be replaced withb (483923)5
Lookarounds
Lookarounds help to create custom anchors and add conditions within the searchpattern. These assertions are also known as zero-width patterns because they add restrictions similar to anchors and are not part of the matched portions.
Vim's syntax is different than those usually found in programming languages like Perl, Python and JavaScript. The syntax starting with
\@is always added as a suffix to the pattern atom used in the assertion. For example,(?!\d)and(?<=pat.*)in other languages are specified as\d\@!and\(pat.*\)\@<=respectively in Vim.
\@!negative lookahead assertionice\d\@!matchesiceas long as it is not immediately followed by a digit character, for exampleiceoriced!oricet5orice.123but notice42orice123s/ice\d\@!/X/greplacesiceiceice2withXXice2s/par\(.*\<par\>\)\@!/X/greplacesparwithXas long as whole wordparis not present later in the line, for exampleparse and par and sparseis converted toparse and X and sXseat\(\(go\)\@!.\)*parmatchescat,dog,parrotbut notcat,god,parrot(i.e. matchatfollowed byparas long asgoisn't present in between, this is an example of negating a grouping)
\@<!negative lookbehind assertion_\@<!icematchesiceas long as it is not immediately preceded by a_character, for exampleiceor_(ice)or42icebut not_ice\(cat.*\)\@<!dogmatchesdogas long ascatis not present earlier in the line, for examplefox,parrot,dog,catbut notfox,cat,dog,parrot
\@=positive lookahead assertionice\d\@=matchesiceas long as it is immediately followed by a digit character, for exampleice42orice123but noticeoriced!oricet5orice.123s/ice\d\@=/X/greplacesice ice_2 ice2 icedwithice ice_2 X2 iced
\@<=positive lookbehind assertion_\@<=icematchesiceas long as it is immediately preceded by a_character, for example_iceor(_ice)but noticeor_(ice)or42ice
![]()
![]()
You can also specify the number of bytes to search for lookbehind patterns. This will significantly speed up the matching process. You have to specify the number between the
@and<characters. For example,_\@1<=icewill lookback only one byte beforeicefor matching purposes.\(cat.*\)\@10<!dogwill lookback only ten bytes beforedogto check the given assertion.
Atomic Grouping
As discussed earlier, both greedy and non-greedy quantifiers will try to satisfy the overall pattern by varying the amount of characters matched by the quantifiers. You can use atomic grouping to safeguard a pattern from further backtracking. Similar to lookarounds, you need to use \@> as a suffix, for example \(pattern\)\@>.
s/\(0*\)\@>\d\{3,\}/(&)/greplaces only numbers >= 100 irrespective of any number of leading zeros, for example0501 035 154is converted to(0501) 035 (154)\(0*\)\@>matches the0character zero or more times, but it will not give up this portion to satisfy overall patterns/0*\d\{3,\}/(&)/greplaces0501 035 154with(0501) (035) (154)(here035is matched because0*will match zero times to satisfy the overall pattern)
s/\(::.\{-}::\)\@>par//replacesfig::1::spar::2::par::3withfig::1::spar::3\(::.\{-}::\)\@>will match only from::to the very next::s/::.\{-}::par//replacesfig::1::spar::2::par::3withfig::3(matches from the first::to the first occurrence of::par)
Set start and end of the match
Some of the positive lookbehind and lookahead usage can be replaced with \zs and \ze respectively.
\zsset the start of the match (portion before\zswon't be part of the match)s/\<\w\zs\w*\W*//greplacessea eat car rat eel teawithsecret- same as
s/\(\<\w\)\@<=\w*\W*//gors/\(\<\w\)\w*\W*/\1/g
\zeset the end of the match (portion after\zewon't be part of the match)s/ice\ze\d/X/greplacesice ice_2 ice2 icedwithice ice_2 X2 iced- same as
s/ice\d\@=/X/gors/ice\(\d\)/X\1/g
As per :h \zs and :h \ze, these "Can be used multiple times, the last one encountered in a matching branch is used."
Magic modifiers
These escape sequences change certain aspects of the syntax and behavior of the search pattern that comes after such a modifier. You can use multiple such modifiers as needed for particular sections of the pattern.
Magic and nomagic
\mmagic mode (this is the default setting)\Mnomagic mode.,*and~are no longer metacharacters (compared to magic mode)\.,\*and\~will make them to behave as metacharacters^and$would still behave as metacharacters\Ma.bmatches onlya.b\Ma\.bmatchesa.bas well asa=bora<boracbetc
Very magic
The default syntax of Vim regexp has only a few metacharacters like ., *, ^ and $. If you are familiar with regexp usage in programming languages such as Perl, Python and JavaScript, you can use \v to get a similar syntax in Vim. This will allow the use of more metacharacters such as (), {}, +, ? and so on without having to prefix them with a \ metacharacter. From :h magic documentation:
Use of
\vmeans that after it, all ASCII characters except0-9,a-z,A-Zand_have special meaning
\v<his>matcheshisorto-hisbut notthisorhistoryor_hista<b.*\v<end>matchesc=a<b #endbut notc=a<b #bending- note that
\vis used aftera<bto avoid having to escape the first<
- note that
\vone|two|threematchesoneortwoorthree\vabc+matchesabcorabcccbut notaborbcs/\vabc?/X/replacesabccwithXcs/\vt.{-}a/X/greplacesthat is quite a fabricated talewithXX fabricaXle\vab{3}cmatchesxabbbczbut notabbcorabbbbbcs/\v(\w+),(\w+)/\2,\1/greplacesgood,bad 42,24withbad,good 24,42- compare this to the default mode:
s/\(\w\+\),\(\w\+\)/\2,\1/g
- compare this to the default mode:
Very nomagic
From :h magic documentation:
Use of
\Vmeans that after it, only a backslash and terminating character (usually/or?) have special meaning
\V^.*{}$matches^.*{}$literally\V^.*{}$\.\*abcdmatches^.*{}$literally only ifabcdis found later in the line\V^.*{}$\m.*abcdcan also be used
\V\^ThismatchesThis is a samplebut notDo This\V)\$matchesapple (5)but notdef greeting():
Case sensitivity
These will override flags and settings, if any. Unlike the magic modifiers, you cannot apply \c or \C for a specific portion of the pattern.
\ccase insensitive search\cthismatchesthisorThisorTHIsand so onth\cisorthis\cand so on will also result in the same behavior
\Ccase sensitive search\Cthismatch exactlythisbut notThisorTHIsand so onth\Cisorthis\Cand so on will also result in the same behavior
s/\Ccat/dog/gireplacescat Cat CATwithdog Cat CATsince theiflag gets overridden
Changing Case
These can be used in the replacement section:
\uUppercases the next character\UUPPERCASES the following characters\llowercases the next character\Llowercases the following characters\eor\Ewill end further case changes\Lor\Uwill also override any existing conversion
Examples:
s/\<\l/\u&/greplaceshello. how are you?withHello. How Are You?- recall that
\lin the search section is equivalent to[a-z]
- recall that
s/\<\L/\l&/greplacesHELLO. HOW ARE YOU?withhELLO. hOW aRE yOU?- recall that
\Lin the search section is equivalent to[A-Z]
- recall that
s/\v(\l)_(\l)/\1\u\2/greplacesaug_price next_linewithaugPrice nextLines/.*/\L&/replacesHaVE a nICe dAywithhave a nice days/\a\+/\u\L&/greplacesHeLLo:bYe gOoD:beTTErwithHello:Bye Good:Betters/\a\+/\L\u&/gcan also be used in this case
s/\v(\a+)(:\a+)/\L\1\U\2/greplacesHi:bYe gOoD:baDwithhi:BYE good:BAD
Alternate delimiters
From :h substitute documentation:
Instead of the
/which surrounds the pattern and replacement string, you can use any other single-byte character, but not an alphanumeric character,\,"or|. This is useful if you want to include a/in the search pattern or replacement string.
s#/home/learnbyexample/#\~/#replaces/home/learnbyexample/reportswith~/reports- compare this with
s/\/home\/learnbyexample\//\~\//
- compare this with
Escape sequences
Certain characters like tab, carriage return, newline, etc have escape sequences to represent them. Additionally, any character can be represented using their codepoint value in decimal, octal and hexadecimal formats. Unlike character set escape sequences like \w, these can be used inside character classes as well. If the escape sequences behave differently in searchpattern and replacestring portions, they'll be highlighted in the descriptions below.
\ttab character\bbackspace character\rmatches carriage return forsearchpattern, produces newline forreplacestring\nmatches end-of-line forsearchpattern, produces ASCII NUL forreplacestring\ncan also match\ror\r\n(where\ris carriage return) depending upon thefileformatsetting
\%dmatches character specified by decimal digits\%d39matches the single quote character
\%omatches character specified by octal digits\%o47matches the single quote character
\%xmatches character specified by hexadecimal digits (max 2 digits)\%x27matches the single quote character
\%umatches character specified by hexadecimal digits (max 4 digits)\%Umatches character specified by hexadecimal digits (max 8 digits)
Using
\%sequences to insert characters inreplacestringhasn't been implemented yet. See vi.stackexchange: Replace with hex character for workarounds.
See ASCII code table for a handy cheatsheet with all the ASCII characters and conversion tables. See codepoints for Unicode characters.
Escaping metacharacters
To match the metacharacters literally (including character class metacharacters like -), i.e. to remove their special meaning, prefix those characters with a \ (backslash) character. To indicate a literal \ character, use \\. Depending on the pattern, you can also use a different magic modifier to reduce the need for escaping. Assume default magicness for the below examples unless otherwise specified.
^and$do not require escaping if they are used out of positionb^2matchesa^2 + b^2 - C*3$4matchesthis ebook is priced $40\^supermatches^superscript(you need the\here since^is at the customary position)
[and]do not require escaping if only one of them is usedb[1matchesab[12342]matchesxyz42] =b\[123]orb[123\]matchesab[123] = d
[in the substitute command requires careful considerations/b[1/X/replacesb[1/X/with nothings/b\[1/X/replacesab[123withaX23
\Va*b.cora\*b\.cmatchesa*b.c&in the replacement section requires escaping to represent it literallys/and/\&/replacesapple and mangowithapple & mango
The following can be used to match character class metacharacters literally in addition to escaping them with a \ character:
-can be specified at the start or end of the list, for example[-0-5]and[a-z-]^should be other than the first character, for example[+a^.]]should be the first character, for example[]a-z]and[^]a]
Replacement expressions
\=whenreplacestringstarts with\=, it is treated as an expressions/date:\zs/\=strftime("%Y-%m-%d")/appends the current date- for example, changes
date:todate:2024-06-25
- for example, changes
s/\d\+/\=submatch(0)*2/gmultiplies matching numbers by 2- for example, changes
4 and 10to8 and 20 submatch()function is similar to backreferences,0gives the entire matched string,1refers to the first capture group and so on
- for example, changes
s/\(.*\)\zs/\=" = " . eval(submatch(1))/appends result of an expression- for example, changes
10 * 2 - 3to10 * 2 - 3 = 17 .is the string concatenation operatoreval()here executes the contents of the first capture group as an expression
- for example, changes
s/"[^"]\+"/\=substitute(submatch(0), '[aeiou]', '\u&', 'g')/gaffects vowels only inside double quotes- for example, changes
"mango" and "guava"to"mAngO" and "gUAvA" substitute()function works similarly to thescommand- first argument is the text to work on
- second argument is similar to
searchpattern - third argument is similar to
replacestring - fourth argument is flags, use an empty string if not required
- see :h substitute() for more details and differences compared to the
scommand
- for example, changes
perldo s/\d+/$&*2/gechanges4 and 10to8 and 20- useful if you are familiar with Perl regular expressions and the
perlinterface is available with your Vim installation - note that the default range is
1,$(thescommand works only on the current line by default) - see :h perldo for restrictions and more details
- useful if you are familiar with Perl regular expressions and the
See :h usr_41.txt for details about Vim script.
See :h sub-replace-expression for more details.
See also stackoverflow: find all occurrences and replace with user input.
Miscellaneous
\%Vmatch inside the visual area onlys/\%V10/20/greplaces10with20only inside the visual area- without
\%V, the replacement would happen anywhere on the lines covered by the visual selection
\%[set]match zero or more of these characters in the same order, as much as possiblespa\%[red]matchesspaorsparorspareorspared(longest match wins)- same as
\vspa(red|re|r)?or\vspa(red?|r)?and so on
- same as
ap\%[[pt]ly]matchesaporapporapplorapplyoraptoraptloraptly
\_^and\_$restrict the match to start-of-line and end-of-line respectively, useful for multiline patterns\%^and\%$restrict the match to start-of-file and end-of-file respectively~represents the last replacement strings/apple/banana/followed by/~will search forbananas/apple/banana/followed bys/fig/(~)/will use(banana)as the replacement string
Further Reading
- vi.stackexchange: How to find and replace in Vim without having to type the original word? — lots of tips and tricks
- vi.stackexchange: How to replace each match with incrementing counter?
- vi.stackexchange: What is the rationale for \r and \n meaning different things in s command? and stackoverflow: Why is \r a newline for Vim?
- stackoverflow: What does this regex mean?
Macro
The . repeat command repeats only the last change. And it gets overwritten with every change. The q command allows you to record a sequence of commands and execute them later whenever you need. You can make it recursive, add a count prefix, combine it with Command-line mode commands and so on. Powerful indeed!
With so many built-in features, sometimes it isn't easy to choose. I prefer the substitute command to macros if both of them can be used for the given problem, especially if the processing doesn't require multiple lines to be considered at once for the solution. That said, macros are more flexible, having an inherent advantage of being able to easily integrate numerous Vim commands. Also, macros allow you to progress in smaller chunks, which might be easier compared to a complicated regexp based solution.
Documentation links:
- :h 10.1 — record and playback commands
- :h complex-repeat — reference manual for
qand related commands
Macro usage steps
Here's a rough overview of the q command usage. Working examples will be discussed in later sections.
- Press
qto start the recording - Use any alphanumeric character as the register to store the recording (for example,
a) - Execute command sequence to accomplish the required task
- Press
qagain to stop the recording - Press
@a(the register used in step 2) to execute the recorded command sequence5@aexecute the macro5times@@repeat the last executed macro
Command-line area will show
recording @aafter step 2 and this indicator vanishes after step 4.
Note that these registers are shared across recording, delete and yank commands. You'll see how this helps to modify a recording later, but you should also be careful not to mix them if you want separate recording and paste use cases. As mentioned earlier in the Normal mode chapter, uppercase registers will append to existing content in lowercase registers.
See also vi.stackexchange: Can I repeat a macro with the "dot operator"? (one of the solutions will allow you to use the
.command to execute a macro immediately after recording as well).
Example 1
The qwceHello^[q macro recording clears text till the end of the word and inserts Hello. Here's a breakdown of this command sequence:
qstart recordingwregister used to save the macrocechange till the end of the wordHelloinsert these characters^[this is a single character that denotes theEsckey- in other words, press
Esckey for this step, don't type the^and[characters - you'll see this representation if you paste the contents of the
"wregister using"wp
- in other words, press
qstop recording
After you've recorded the macro, you can execute this command sequence anywhere else you need it. For example, if the cursor is on the fourth character of the text Hi-there and @w is pressed, you'll get Hi-Hello.
Modifying a macro
As mentioned earlier, registers are shared across recording, delete and yank commands. When you call a macro using @, the register content is treated as the sequence of commands to be executed. So, editing a register's content will automatically update the behavior of the macro as well. Knowing that you can modify a macro also helps if you make a mistake — you can choose to finish the recording and update later instead of restarting the recording.
Suppose you want to use 'Hello!' instead of Hello for the macro discussed in the previous section. Here's one possible way to make the changes:
"wppaste the contents of"wregister- you should get
ceHello^[
- you should get
ce'Hello'!^[modify the text as needed"wyupdate the contents of"wregister after visually selecting the modified text or using motion commands in Normal mode
After you've modified the register contents, check if it is working as expected. For example, if the cursor is on the fourth character of the text Hi-there and @w is pressed, you should now get Hi-'Hello'!.
In case you wish to create a new macro from scratch by just typing the required text instead of using the
qcommand, you'll findCtrl+v(or theCtrl+qalias) useful to insert keys likeEscandEnter. To do so, pressCtrl+vfollowed by the required key. You'll get^[forEsc,^MforEnterand so on.
![]()
let @w = "ce'Hello'!^["adding this line to thevimrcfile will load the"wregister with the given text at startup.
Example 2
Suppose you forgot to add curly braces for single statement control structures in a Perl program:
# syntax error if($word eq reverse $word) print "$word is a palindrome\n"; # corrected code if($word eq reverse $word) { print "$word is a palindrome\n"; }
qpo{^[jo}^[q is one way to do it:
qpstart recording and use registerpoopen a new line{insert the{character^[go back to Normal mode (Esckey)jmove down one lineoopen another line}insert the}character^[go back to Normal mode (Esckey)qstop recording
Having a macro will help you apply this correction whenever you forget braces for single statement control structures.
Note that
{and}will be indented based on style settings for that particular filetype.
Example 3
I used F`r[f`s]()^["*P macro to replace `:h <topic>` with a hyperlink to the corresponding online help page for this ebook. Assume the cursor is somewhere within the :h <topic> text portion surrounded by backticks (markdown formatting for inline code). This has to be changed to [:h <topic>](link) (markdown formatting for hyperlinks).
F`move cursor to the starting backtickr[replace backtick with[f`move cursor to the ending backticks]()replace backtick with]()^[go back to Normal mode (Esckey)"*Ppaste contents of the last highlighted text selection- note the use of uppercase
Pto paste content to the left of the cursor
- note the use of uppercase
Once the macro was recorded, I just had to select the url from the browser for each help topic and execute the macro. I used n to navigate in the markdown files after using :h as the search pattern.
Motion and Filter
If you have to apply the same macro for text portions that are next to each other, you can add motion commands at the end of the macro for reaching the next text portion. The motion command could be arrow motions, searching using / and so on. Doing so will allow you to use a count prefix to apply the macro for all the text portions in one shot. This assumes that you can easily count the number of text portions. For example, consider this Python snippet where you want to change single line definitions to multiple lines:
def square(n): return n ** 2 def cube(n): return n ** 3 def isodd(n): return n % 2 == 1
You can do a recording as usual, select these lines visually (or use a range) and then apply the macro using normal @d in Command-line mode. Or, you could add a motion to automatically go to the next line and use a count prefix as described below.
qd0f:lr^M>>o^[jq is one way to achieve this:
0f:lMove to beginning of the line and then move the cursor to the character after the first occurrence of:(which is a space character in the above snippet)- this also assumes that there won't be any
:character as part of the function arguments
- this also assumes that there won't be any
r^Mreplace the space character with a newline character>>indent the line- note that this won't be required if indentation is automatically applied based on Python syntax
o^[open a new line and go back to Normal modejmove to the next line (this makes it possible to use the count prefix)
After recording, you can use 3@d on the first line to get the output as shown below:
def square(n): return n ** 2 def cube(n): return n ** 3 def isodd(n): return n % 2 == 1
Suppose the Python function definitions discussed above aren't next to each other but can be found anywhere in the Python script file. In such cases, if you are able to reliably identify the lines using a regexp filter, you can use the :g command.
qdf:lr^M>>o^[qsimplified macro0not required since the cursor starts at the beginning- no need to move to the next line
:g/^def .*): / normal @dapply the macro for filtered lines:%s/^def .*):\zs \(.*\)/\r\t\1\r/if you are comfortable with regexp, you could also just use the substitution command like this one instead
Recursive recording
Suppose it isn't easy to count the number of text portions and filtering is complicated too. In such cases, you might be able to use recursive recording that continues to execute the macro until one of the steps fails. Similar to recursive function calls, you have to call the macro from within the recording. Consider this Python snippet where you want to change single line definitions to multiple lines:
def square(n): return n ** 2 def cube(n): return n ** 3 def isodd(n): return n % 2 == 1 print(square(12))
qr0f:lr^M>>o^[j@rq is one way to achieve this. The only addition here is @r at the end of the recording compared to the solution discussed in the previous section. For the fourth line with print() function, the macro will stop when it doesn't find the : character. It would've stopped even if a : was found, provided it was the last character, since the l motion would've failed.
Using @r on the first line of the above snippet would give the following output:
def square(n): return n ** 2 def cube(n): return n ** 3 def isodd(n): return n % 2 == 1 print(square(12))
![]()
Note that the register being used here must be empty before you start the recording, otherwise you might see some unwanted changes when you type
@rwhile recording. To ensure this register is empty, you can useqrq(i.e. record an empty macro) before you record the recursive macro.
If the
:scommand is part of the recording and you do not want the macro to stop if the search pattern isn't found, you can use theeflag.
Here are some more examples:
- vi.stackexchange: How do I stop a recursive macro at the end of the line? — one of the examples shows how to incorporate Vimscript, so you get full programming capabilities like variables,
ifcontrol structure and so on - vi.stackexchange: How to reverse every 4 lines?
- vi.stackexchange: Correct all spelling mistakes in the document
Exercise
Given the following text:
# Introduction # Normal mode # Command Line mode # Visual mode
Use a macro (or the substitute command if you prefer) to get the modified text as shown below:
* [Introduction](#introduction) * [Normal mode](#normal-mode) * [Command Line mode](#command-line-mode) * [Visual mode](#visual-mode)
Further Reading
Customizing Vim
Settings like indentation and keyword-pairs can vary between different programming languages and file types. You might need to adapt style guides based on client requirements. Or perhaps, you wish to create or override commands to suit your preferences.
This chapter will discuss how you can customize Vim for different purposes. Some of the settings will be specific to GVim.
Documentation links:
- :h usr_05.txt — set your settings
- :h usr_40.txt — make new commands
- :h usr_41.txt — write a Vim script
- :h usr_43.txt — using filetypes
- :h options.txt — reference manual for Options
- :h map.txt — reference manual for Key mapping, abbreviations and user-defined commands
- :h autocmd.txt — reference manual for Automatic commands
Editing vimrc
From :h usr_41.txt and :h vimrc-intro:
The Vim script language is used for the startup vimrc file, syntax files, and many other things.
The vimrc file can contain all the commands that you type after a colon. The simplest ones are for setting options.
This chapter only covers some use cases. You'll see what some of the settings do, how to use mappings, abbreviations and so on. Not much will be discussed about the programming aspects of Vim script. Make sure you have a vimrc file using the following details:
:e $MYVIMRCif you already have avimrcfile, you can use this predefined variable to open it- :h vimrc to find out where the
vimrcfile should be located for your OS :source $MYVIMRCapply changes from within your current Vim session
To view a sample
vimrcfile, I have one on GitHub. More resources are mentioned in the Further Reading section at the end of this chapter.
defaults.vim
If you haven't created a vimrc file, the defaults.vim file that comes with Vim installation will be used. This file aims to provide saner defaults like enabling syntax highlighting, filetype settings and so on.
source $VIMRUNTIME/defaults.vimadd this to yourvimrcfile if you want to keep these defaults- :h defaults.vim-explained describes the settings provided by
defaults.vim
Alternatively, you can copy only the parts you want to retain from the defaults.vim file to your vimrc file.
General Settings
![]()
setsyntax and guidelines were introduced in the Setting options section.
set history=200increase default history from 50 to 200- as mentioned in the Command-line mode chapter, there are separate history lists for
:commands, search patterns, etc
- as mentioned in the Command-line mode chapter, there are separate history lists for
set nobackupdisable backup filesset noswapfiledisable swap filescolorscheme murphya dark theme- you can use
:colorschemefollowed by a space and then pressTaborCtrl+dto get a list of the available color schemes
- you can use
set showcmdCommand-line area will show partial Normal mode commands and character/line/block-selection for Visual modeset wildmode=longest,list,fullusebash-like tab completion- first tab will complete as much as possible
- second tab will provide a list
- third and subsequent tabs will cycle through the completion options
![]()
:h 'history'will give you the documentation for the given option (note the use of single quotes).
You can use these settings from the Command-line mode as well, but will be active for the current Vim session only. Settings specified in the
vimrcfile will be loaded automatically at startup. You can also load a different file as thevimrc, which will be discussed in the CLI options chapter.
Further Reading
- stackoverflow: Vim backup files
- stackoverflow: Disabling swap files
- stackoverflow: How to set persistent Undo
Text and Indent Settings
filetype plugin indent onenables loading ofpluginandindentfiles- these files become active based on the type of the file to influence syntax highlighting, indentation, etc
:echo $VIMRUNTIMEgives your installation directory (indentandplugindirectories would be present in this path)- see :h vimrc-filetype, :h :filetype-overview and :h filetype.txt for more details
set autoindentcopy indent from the current line when starting a new line- useful for files not affected by the
indentsetting - see also :h smartindent
- useful for files not affected by the
set textwidth=80guideline for Vim to automatically move to a new line with80characters as the limit- white space is used to break lines, so a line can still be greater than the limit if there's no white space
- default is
0which disables this setting
set colorcolumn=80create a highlighted vertical bar at column number80- use
highlight ColorColumnsetting to customize the color for this vertical bar - see vi.stackexchange: Keeping lines to less than 80 characters for more details
- use
set shiftwidth=4number of spaces to use for indentation (default is8)set tabstop=4width for the tab character (default is8)set expandtabuse spaces for tab expansionset cursorlinehighlight the line containing the cursor
Search Settings
set hlsearchhighlight all matching portions- using
:noh(short for:nohlsearch) will clear the currently highlighted portions
- using
set incsearchhighlights current match as you type the pattern, the screen is updated automatically as needed- pressing the
Enterkey would move the cursor to the matched portion - pressing the
Esckey would keep the cursor at the current location - other matching terms will be highlighted based on the
hlsearchsetting
- pressing the
Custom mapping
Mapping helps you to create new commands or redefine existing ones. You can restrict such mappings for specific modes as well. Only the following settings will be discussed in this chapter:
nnoremapNormal mode non-nested, non-recursive mappingxnoremapVisual mode non-nested, non-recursive mappinginoremapInsert mode non-nested, non-recursive mappinginoreabbrevInsert mode non-nested, non-recursive abbreviation
The following will not be discussed, but you might find it useful to know or explore further:
nmap,xmap,imapandiabbrevallows nested and recursive mappingsnunmap,xunmap,iunmapandiunabbrevunmaps the given command (usually used from Command-line mode to temporarily disable a mapping, will be available again on startup if it was defined invimrc)- use
mapclearinstead ofunmapto clear all the mappings for that particular mode
- use
onoremap(oromap) map a motion or text object to be used with commands likedorycommandhelps you create a Command-line mode command, see :h 40.2 and :h user-commands for details
![]()
:nmap,:xmap,:imapand:iabwill list all the current mappings for that particular mode. You can provide an argument to display the mapping for that particular command, for example:nmap Y. See :h key-mapping and :h map-overview for reference manuals.
Normal mode
nnoremap <F2> :w<CR>pressF2function key to save changes<F2>represents theF2function key and<CR>represents theEnterkey- I chose
F2since it is close to theEsckey (F1opens help page)
nnoremap <F3> :wq<CR>pressF3to save changes and quitnnoremap <F4> ggdGpressF4to delete everythingnnoremap <F5> :%y+<CR>pressF5to copy everything to the system clipboardnnoremap <left> <nop>do nothing when the←arrow key is pressed- likewise, you can map the other arrow keys to do nothing
nnoremap Y y$changeYto behave similarly toDandCnnoremap / /\vadd very magic mode modifier for forward direction searchnnoremap ? ?\vadd very magic mode modifier for backward direction searchnnoremap <silent> <Space> :noh<CR><Space>pressSpacekey to clear the currently highlighted portions<silent>modifier executes the command without displaying in the Command-line area- Note that this mapping also retains the default behavior of the
Spacekey
nnoremap <A-1> 1gtpressAlt+1to switch to the first tab- I prefer this to make switching tabs consistent with browser and terminal shortcuts
nnoremap <A-2> 2gtpressAlt+2to switch to the second tab and so on
See :h map-which-keys to know which keys are not already Vim commands, which ones are not commonly used, etc.
See :h key-notation for a list of keys that can be represented using the
<>notation.
Map leader
Normal mode commands are already crowded, so if you are looking to create new commands, using a leader mapping can help you out. You can define a key that'll serve as a prefix for these new set of commands. By default, the backslash key is used as the leader key.
nnoremap <Leader>f gg=Gifmapleaderhasn't been set, using\fwill auto indent the code for the whole filelet mapleader = ";"change the leader key to;nnoremap <Leader>f gg=Gthis will now require;fsince the leader key was changed
See learnvimscriptthehardway: Leaders for more examples and details.
Insert mode
inoremap <F2> <C-o>:w<CR>pressF2to save changes in Insert mode as wellCtrl+ois used here to execute a command and return back to Insert mode automaticallyimap <F2> <C-o><F2>can also be used if you've already defined the Normal mode mapping
inoremap <C-f> <Esc>eapressCtrl+fto move to the end of the word- I'd prefer
Ctrl+ebut that is useful to cancel autocompletion
- I'd prefer
inoremap <C-b> <C-Left>pressCtrl+bto move to the beginning of the wordinoremap <C-a> <End>pressCtrl+ato move to the end of the lineinoremap <C-s> <Home>pressCtrl+sto move to the start of the lineinoremap <C-v> <C-o>"+ppressCtrl+vto paste from the clipboard- If you need
Ctrl+vfunctionality, theCtrl+qalias can be used to insert characters likeEnterkey (but this alias may not work in some terminals)
- If you need
inoremap <C-l> <C-x><C-l>pressCtrl+lto autocomplete matching lines- See :h i_CTRL-x and :h ins-completion for all the features offered by
Ctrl+x
- See :h i_CTRL-x and :h ins-completion for all the features offered by
Use
noremap!if you want a mapping to work in both Insert and Command-line modes.
Visual mode
xnoremap * y/<C-R>"<CR>press*to search the visually selected text in the forward direction- recall that
Ctrl+rhelps you insert register contents in Command-line mode
- recall that
xnoremap # y?<C-R>"<CR>press#to search the visually selected text in the backward direction
Note that
xnoremapis used here sincevnoremapaffects both Visual and Select modes.
Abbreviations
Abbreviations are usually used to correct typos and insert frequently used text. From :h abbreviations documentation:
An abbreviation is only recognized when you type a non-keyword character. This can also be the
<Esc>that ends insert mode or the<CR>that ends a command. The non-keyword character which ends the abbreviation is inserted after the expanded abbreviation. An exception to this is the character<C-]>, which is used to expand an abbreviation without inserting any extra characters.
-
inoreabbrev p #!/usr/bin/env perl<CR>use strict;<CR>use warnings;<CR>expandpto the text as shown in the code snippet below- you can trigger the abbreviation completion using non-keyword characters such as
Esc,SpaceandEnterkeys, punctuation characters and so on - use
Ctrl+]to expand the abbreviation without adding anything extra
#!/usr/bin/env perl use strict; use warnings;
- you can trigger the abbreviation completion using non-keyword characters such as
-
inoreabbrev py #!/usr/bin/env python3expandpyto#!/usr/bin/env python3- this might cause issues if you need
pyliterally (for example,script.py) - you can use something like
[por@pinstead
- this might cause issues if you need
-
inoreabbrev teh theautomatically correcttehtypo tothe -
inoreabbrev @a always @()<CR>begin<CR>end<Esc>2k$expand@ato the text as shown in the code snippet below- this one works best when you type
@afollowed by theEsckey to place the cursor at the end of the first line
- this one works best when you type
-
:abbreviateor:ablist all abbreviations
See :h 24.7 for more details about using abbreviations.
Matching Pairs
set matchpairs+=<:>add<>to the list of pairs matched by the%command in Normal mode
To match keywords like
if-elsepairs with%, you can use thematchit.vimplugin. This supports filetypes such as HTML, Vim, LaTeX, XML, etc. See :h matchit-install for more details.
GUI options
set guioptions-=mremove menu barset guioptions-=Tremove tool bar
See :h guioptions for more details.
Third-party customizations
![]()
See :h 'runtimepath' to know the path within which you can add the plugins and packages discussed in this section.
~/.vimis commonly used on Unix/Linux systems.
Make sure to backup your directory (~/.vim for example) and the vimrc file, so that you can easily apply your customizations on a new machine.
plugin
Some plugins are loaded by default. Some come with Vim installation but you have to explicitly enable them. You can also write your own or add plugins written by others. From :h add-plugin:
Vim's functionality can be extended by adding plugins. A plugin is nothing more than a Vim script file that is loaded automatically when Vim starts.
There are two types of plugins:
global plugin: Used for all kinds of files
filetype plugin: Only used for a specific type of file
If you want to add a global plugin created by you or someone else, place it in the plugin directory. If you don't have that directory yet, you can create it using the below command (assuming Unix/Linux):
$ mkdir -p ~/.vim/plugin $ cp plugin_file.vim ~/.vim/plugin/
If you have multiple related plugin files, you can put them under a subdirectory:
$ mkdir -p ~/.vim/plugin/python $ cp file_1.vim file_2.vim ~/.vim/plugin/python/
If you want to add plugins that should work based on a specific filetype, add them to the ftplugin directory:
$ mkdir -p ~/.vim/ftplugin $ cp ftplugin_file.vim ~/.vim/ftplugin/
package
Packages make it easy to manage projects that require multiple plugins, use a version controlled repository directly and so on. See :h packages for more details. From :h add-package:
A package is a set of files that you can add to Vim. There are two kinds of packages: optional and automatically loaded on startup.
The Vim distribution comes with a few packages that you can optionally use. For example, the matchit plugin.
packadd! matchitenablematchitpackage- this plugin comes with Vim, see :h matchit for further details
!is used to prevent loading this plugin when Vim is started with the--nopluginCLI option
vim-surround is used here as an example for a third-party package. Installation instructions (provided in this repository) are shown below, assuming you want to enable this package at startup:
# 'pack' is the directory for packages # 'tpope' subdirectory is useful to group all packages by this author # 'start' means this package will be loaded at startup $ mkdir -p ~/.vim/pack/tpope/start # go to the directory and clone the git repository # you can then update the repository when new changes are needed $ cd ~/.vim/pack/tpope/start $ git clone https://github.com/tpope/vim-surround.git
When you start Vim after the above steps, vim-surround will be automatically active. Couple of examples are shown below, see the repository linked above for more details.
ysiw]will surround a word with[], for examplehelloto[hello]cs"'will change text surrounded by double quotes to single quotes, for example"hi bye"to'hi bye'
If you want to enable this package optionally, put it under opt directory instead of start.
# 'opt' makes it optional $ mkdir -p ~/.vim/pack/tpope/opt $ cd ~/.vim/pack/tpope/opt $ git clone https://github.com/tpope/vim-surround.git
:packadd vim-surroundenable this package from Command-line modepackadd! vim-surroundenable this package invimrc(usually under some condition)
color scheme
There are different ways to add a new color scheme. The simplest is to copy the theme.vim file to the ~/.vim/colors directory. Or, follow the installation steps provided by the theme creators. Here are couple of solarized themes you can check out:
After installation, you can use the :colorscheme command to set the new theme. If the theme offers multiple variations, you might need additional settings like set background=dark or set background=light. See the installation instructions provided in the above repositories for more details.
See Where to put what section under :h packages for more details about installation directories.
See also this collection of awesome color schemes for Vim.
autocmd
From :h 40.3:
An autocommand is a command that is executed automatically in response to some event, such as a file being read or written or a buffer change.
Autocommands are very powerful. Use them with care and they will help you avoid typing many commands. Use them carelessly and they will cause a lot of trouble.
Syntax from the reference manual is shown below:
:au[tocmd] [group] {event} {aupat} [++once] [++nested] {cmd}Here's an example for Python files:
augroup pyg
autocmd!
" add Python shebang for a new buffer with .py extension
" py abbreviation was discussed earlier in this chapter
autocmd BufNewFile *.py normal ipy
" Black command is provided by a Python code formatter plugin
autocmd BufWritePre *.py Black
augroup END
autocmd BufNewFile *.py normal ipyBufNewFileevent that triggers on editing a file that doesn't already exist*.pyfilenames ending with.py(similar to shell wildcards)normal ipycommand to be executed (normalis needed here since by default commands are treated as Command-line mode)
autocmd BufWritePre *.py BlackBufWritePreevent that triggers on writing a fileBlackcommand to be executed (see black vim plugin documentation for more details)
augrouphelps you to group related autocommandsautocmd!removes all autocommands within a group (pygin the above example)- useful to avoid autocommands getting defined again when you source the
vimrcfile
- useful to avoid autocommands getting defined again when you source the
:autocmdlist all autocommands, you can provide arguments to narrow down this listing
![]()
Note that in earlier versions of Vim, double quotes is used for comments as shown in the above snippet. You'll need to use the
#character instead forvim9script. See vim9-conversion-aid for upgrading old scripts.
See also:
- :h 40.3 for user manual, :h :autocmd and :h autocmd-groups for reference manuals
- :h autocmd-events for a list of events
- learnvimscriptthehardway: autocmd tutorial
- learnvimscriptthehardway: augroup tutorial
Further Reading
- Learn Vimscript the Hard Way — book on Vimscript and customizing Vim (written for
version 7.3) - Vimscript cheatsheet
- Vim Awesome — a directory of Vim plugins
vimrcreference, tips and generation- stackoverflow: useful vimrc tips
- vi.stackexchange: How do I debug my vimrc file?
- vim-sensible
- minimal vimrc for new users
- Vim Configuration From Scratch
- vimconfig — generate
vimrcby selecting options
- vi.stackexchange: Open filename under cursor in a new tab (or split)
- stackoverflow: Open filename under cursor based on current filetype
- stackoverflow: Information regarding Vim history
- stackoverflow: Indenting all the files in a folder
CLI options
This chapter discusses some of the options you can use when starting Vim from the command line. A Unix/Linux distribution is assumed for the examples shown in this chapter. Syntax and features might vary for other platforms like Windows.
Documentation links:
- :h vim-arguments — reference manual for Vim arguments
Recall that you need to add
-prefix for built-in help on CLI options, :h -y for example.
Default
gvimopens a new unnamed buffer when a filename is not specifiedgvim script.pyopensscript.py- creates a blank buffer if
script.pydoesn't exist, file will be created only after you explicitly issue write commands
- creates a blank buffer if
gvim report.log power.log area.logopens the specified files- first file (
report.loghere) will be the current buffer
- first file (
gvim -- *.txtif filenames can start with-, use--to prevent such files from being treated as an option
Help
gvim -hbrief description of the options- not all options are discussed in this chapter, so you can use this to view the full list
Tabs and Splits
gvim -p *.logopens the specified files as separate tab pages- by default, you can open a maximum of
10pages, use thetabpagemaxsetting if you want to change this number
- by default, you can open a maximum of
gvim -o *.logopens the specified files as horizontal splitsgvim -O *.logopens the specified files as vertical splits
You can append a number to each of these options to specify how many tabs or splits you want. For example,
gvim -p3 *.pyopens three tabs irrespective of the number of input files. Empty buffers will be used if there aren't enough input files to satisfy the given number.
Easy mode
gvim -yopens in Insert mode and behaves like a click-and-type editor- useful for those who just want a simple text editor
- or, perhaps you can prank Vim users by setting
alias vim='vim -y' - use
Ctrl+lorCtrl+oif you want to use Normal mode commands
See also novim-mode plugin, which aims to make Vim behave more like a normal editor.
Readonly and Restricted modes
gvim -RReadonly mode- changes can still be made and saved despite warning messages
- for example, by using
:w!
gvim -Mstricter Readonly mode- changes cannot be made unless
:set modifiableis used - file cannot be saved until
:set writeis used
- changes cannot be made unless
gvim -ZRestricted mode- commands using external shell are not allowed
- for example, you won't be able to use
:!ls
Cursor position
gvim + script.pyopensscript.pyand the cursor is placed on the last linegvim +25 script.pyopensscript.pyand the cursor is placed on the 25th line- if the number goes beyond the available lines in the file, the cursor will be placed on the last line
gvim +/while script.pyopensscript.pyand the cursor is placed on the first line containing the given pattern- if the pattern is not found, the cursor will be placed on the last line
- use
gvim +1 +/patternto force the search to start from the first line, otherwise cursor position stored inviminfowill be used (if applicable)
Execute command
gvim -callows you to execute the Command-line mode command passed as an argumentgvim -c '%s/search/replace/g' script.pyopensscript.pyand performs the given substitute operationgvim -c 'normal =G' script.pyopensscript.pyand auto indents the entire file content
As per :h -c, "You can use up to 10
+or-carguments in a Vim command. They are executed in the order given. A-Sargument counts as a-cargument as well"
![]()
--cmdoption is similar to the-coption, but executes the command before loading anyvimrcfiles.
Quickfix
gvim -q <(grep -Hn 'search' *.py)interactively edit the matching lines fromgrepoutput-Hand-noptions provide filename and line number prefix for the matching lines- use
:cnand:cpto navigate to the next and previous occurrences respectively - Command-line area at the bottom will show the number of matches and filenames
- you can also use
gvim -q fileif you had saved thegrepoutput to that file
gvim -q error.logedit source code based on compiler output containing filenames and line numbers for the error locations- here, the
error.logis assumed to be the filename used to save the error messages
- here, the
See Vim and the quickfix list and stackoverflow: How do you use Vim's quickfix feature? to learn more about this feature.
See :h quickfix for documentation.
Vimrc and Plugins
gvim -u fileuses the given file for initialization instead ofvimrcfiles- useful to test plugins, apply a different
vimrcbased on which project you are working on, etc
- useful to test plugins, apply a different
gvim -u NONEall initializations are skippedgvim -u DEFAULTSsimilar toNONE, butdefaults.vimis loadedgvim -u NORCsimilar toNONE, but plugins are loadedgvim --nopluginonly plugins are not loaded
Here's a neat table from :h --noplugin:
| argument | vimrc | plugins | defaults.vim |
|---|---|---|---|
| (nothing) | yes | yes | yes |
-u NONE |
no | no | no |
-u DEFAULTS |
no | no | yes |
-u NORC |
no | yes | no |
--noplugin |
yes | no | yes |
Session and Viminfo
gvim -S proj.vimrestore a session using the previously saved session file- see :h Session for more details
gvim -i proj.viminforestore Viminfo from the given file- this file will also be used instead of the default
viminfofile to save information - see :h viminfo-read-write for more details
- this file will also be used instead of the default