Motion
Below are some advanced motion tips beyond basic hjkl, ^$ and wWeE motion
0: move to the very beginning of the line^: move to the first non-blank character of the lineI: move to the first non-blank character of the line and enter insert modeA: move to the last character of the line and enter insert mode%: jump to the corresponding pair (e.g., matching parentheses, brackets, braces, or quotes)Ctrl+d: move half page downCtrl+u: move half page upf<char>: move forward to the next occurrence of<char>F<char>: move backward to the previous occurrence of<char>t<char>: move forward until before the next occurrence of<char>T<char>: move backward until after the previous occurrence of<char>*: move forward to the next occurrence of the current word#: move backward to the previous occurrence of the current wordg*: move forward to the next occurrence of the current word, including partial matchesg#: move backward to the previous occurrence of the current word, including partial matches
After using any of *#g*g#, n repeats the search in the same direction.
EasyMotion
EasyMotion is a plugin of Vim. It’s highly recommended to move cursor with it.
Installation
To install EasyMotion, we utilize a plugin manager called Vim-Plug. Install the plugin manager first:
curl --proxy http://127.0.0.1:10809 -fLo ~/.vim/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim
Update your ~/.vimrc file:
call plug#begin()
Plug 'easymotion/vim-easymotion'
call plug#end()
Note: If you’re behind a proxy, you may need to configure it:
# Configure git proxy (if needed)
git config --global http.https://github.com.proxy http://127.0.0.1:10809
# Configure curl proxy (if needed)
export http_proxy=http://127.0.0.1:10809
export https_proxy=http://127.0.0.1:10809
Start Vim and in command mode issue :PlugInstall to install the plugins according to your ~/.vimrc file. Once done, start Vim and try <leader><leader>w to verify if EasyMotion works. The default leader key is <leader> (typically \ or ,).
Usage
Some commonly used keystrokes:
<leader><leader>w- Jump to start of words forward<leader><leader>b- Jump to start of words backward<leader><leader>j- Jump to lines below<leader><leader>k- Jump to lines above
Configuration for Bidirectional Motion
EasyMotion provides bidirectional motion. Configure key bindings in ~/.vimrc:
" Other configuration in ~/.vimrc
" Bidirectional word motion
nmap <Leader><Leader>w <Plug>(easymotion-bd-w)
nmap gw <Plug>(easymotion-bd-w)
" Bidirectional word-end motion
nmap <Leader><Leader>e <Plug>(easymotion-bd-e)
nmap ge <Plug>(easymotion-bd-e)
Grammar
Vim supports <num> <operation> syntax. For example, 5yy copies the current line and the following 4 lines.
Vim also supports <operation> <motion> syntax. For example, c$ changes from the current position to the end of the line.
Text Objects
Vim supports text objects to further improve productivity. Text objects allow you to operate on linguistic units (words, sentences, paragraphs) rather than character positions.
Common text objects:
| Text Object | Description |
|---|---|
iw / aw |
inner/around word |
is / as |
inner/around sentence |
ip / ap |
inner/around paragraph |
it / at |
inner/around tag |
i<delimiters> / a<delimiters> |
inner/around delimiters (quotes, brackets, etc.) |
Common delimiter examples:
i"/a"- inside/around double quotesi'/a'- inside/around single quotesi(/a(- inside/around parenthesesi[/a[- inside/around bracketsi{/a{- inside/around braces
<operation> <text object> is supported in Vim. For example:
yiw- yank (copy) the current wordci"- change the content inside the current quotesdaw- delete (remove) the current word including surrounding whitespaceca"- change the content around the current quotes (including the quotes themselves)
Why use text objects?
- More intuitive than character-based motions
- Works with varying content sizes automatically
- Less prone to errors from incorrect character counts
- Consistent behavior regardless of content length
Unnecessary Motion
With some shortcuts and the Vim ‘grammar’ concept, many motions become unnecessary. Here are some examples:
Insert mode shortcuts:
A- move to end of line and enter insert mode (no need for$a)I- move to first non-blank character and enter insert mode (no need for^i)o- open a new line below and enter insert modeO- open a new line above and enter insert mode
Text object operations:
ci"- change inside quotes (works even if cursor is outside the quotes, searches forward)da"- delete around quotes (removes quotes and their content)ca"- change around quotes (replaces quotes and their content)
Why ci" works without being inside the quote:
Vim’s text object operations perform a forward search to find the target. This means:
- If you’re already inside the quote, it targets the current pair
- If you’re outside the quote, it finds the next matching pair
- It does not perform backward search
Comparison table:
| Command | Behavior | Note |
|---|---|---|
ci" |
Change inside quotes | Searches forward, even from outside |
ca" |
Change around quotes | Includes the quotes themselves |
da" |
Delete around quotes | Removes quotes and content |
di" |
Delete inside quotes | Removes content only, keeps quotes |
caw |
Change around word | Includes surrounding whitespace |
ciw |
Change inside word | Only the word characters |
Common pitfalls to avoid:
- Using
d$when you could useD(delete to end of line) - Using
^iwhen you could useI(insert at start of line) - Using
a"when you meanti"(includes extra quotes unexpectedly)
Command Mode
Command‑line mode (also called Ex mode) allows you to run colon commands beyond simple commands like :q, :w, etc. Many practical operations can be done with command mode. :help ex-cmd-index shows the list of EX commands
==============================================================================
6. EX commands ex-cmd-index :index
This is a brief but complete listing of all the ":" commands, without
mentioning any arguments. The optional part of the command name is inside [].
The commands are sorted on the non-optional part of their name.
tag command action
------------------------------------------------------------------------------
: : nothing
:range :{range} go to last line in {range}
:! :! filter lines or execute an external command
:!! :!! repeat last ":!" command
:# :# same as ":number"
:& :& repeat last ":substitute"
:star :* execute contents of a register
:< :< shift lines one 'shiftwidth' left
:= := print the cursor line number
:> :> shift lines one 'shiftwidth' right
...
To view help for a specific command, use :help :<cmd>, e.g. :help :s. To get word completion in command mode, use Ctrl-d and TAB key**.
Range
A range defines the set of lines an Ex command operates on. The syntax is <start_position>,<end_position>, for example
1, 5- lines 1 through 51,.- from the first line to the current line.,$- from the current line to the end of the buffer.-1,.+1- one line above to one line below the cursor
In Visual mode, when multiple lines are selected, pressing : will enter command mode with :'<,'> shown in the command mode prompt. '<,'> represents from the entire first line to the entire last line of the selected multiple lines.
Similary '[,'] represents from the entire first line to the entire last line of the most recently changed area.
Move Lines
To move the current line and the next 3 lines to the bottom of the file:
:.,.+3m$
To move lines 1–4 to the current cursor position:
:1,4m.
The m command places the moved lines after the destination line.
Copy Lines
To copy lines, use co command. For example, below command copies the current line with 1 line ‘context’ to the bottom of the buffer:
:.-1,.+1co$
Contents Substitution
To replace text in the entire buffer, use s command:
:%s#Hello#Hi#g
Some useful options
g— replace all matches on each linei— ignore casec— confirm each substitution
Global Command
Sometimes, instead of using range, we need to perform the operation on matching items. For example, to get a “clean” version of Nginx configuration, we need to delete all comment lines in the configuration file.
:g/^#/d
Explanation
gmeans to globally apply the command, so the entire buffer is impacted.^#is the regular expression to match the leading pond sign, aka the comment line.dmeans to delete the matching lines.
To operate on non‑matching lines, use v. For example, to copy all non‑comment lines to the bottom:
:v/^#/co$
Shell Interaction
In Vim command-line mode, you can execute shell command directly using exclamation mark like :!<shell_cmd>
:!date
Read from Command Output
To read the output of a shell command into the current buffer, use :r with !:
:r !date
Beyond that, Vim can read the output of any program that writes to STDOUT:
:r !python my_script.py
Treat Contents as Command String to Execute
If a line contains a shell command such as ls ~/Videos, you can send it to shell as a command to execute using !!. Once entered, you will be navigated to the command mode with below command prompt
:.!
Appending a shell name (e.g., sh) runs the line through that shell:
:.!sh
This replaces the command string in the buffer with the output produced by the shell.
Marks
A mark labels a specific position in a file so you can quickly jump back to it or use it in Ex commands. Create a mark with m<letter>. Notes:
- Lowercase marks (a–z) are local to the current file
- Uppercase marks (A–Z) are global across files
To jump to a mark
'ajump to the line of marka- ‘
ajump to the exact position of marka, considering the mark created on the position like the second character of the line
Use Marks with Commands
Marks can be used as line addresses in command mode. If mark a is set on a line:
:'am.- move the marked line to the current line:'aco$- copy the marked line to the end of the buffer:'ad- delete the marked line
Register & Macro
Register Basics
Registers are containers that store text for later retrieval. View all registers with :registers or :reg:
:reg
Type Name Content
c "" ?asdf ad
c "0 ??
l "1 asdfa1234asdf^J
l "2 1234asdf^J
l "3 9866756^J
l "4 asdfasd1234^J879-0iasdf^J
l "5 asdfasdfasdf^Jasdfasd1234^J
l "6 ^J
l "7 adsf 134 asdf^J
Notes:
cmeans characterwiselmeans linewise
To use a register:
- in normal mode: use
"<reg_name>, such as"addto cut the current line intoaregister - in insert mode: use
Ctrl-r<reg_name>, such asCtrl-rato paste the contents stored inaregister
Register types:
- unamed register
- numbered registers
- named registers
Unamed Register
The unnamed register ("") is used when no register is specified. For example, dd stores the deleted line in “”.
A practical use case - surrounding a word with quotes:
ciw- ‘cut’ the word into unnamed register"- the opening quoteCtrl-r "- read the unnamed register"- the closing quote
Numbered Registers
Numbered registers "0 – "9 behave as follows:
"0- contains the last yanked contents (y), including characterwise and linewise"1to"9- deletion history (dd), linewise only, newest in"1
These registers can help recover mistakenly deleted lines.
Named Registers
Named registers "a–"z and "A–"Z provide 52 registers total. They can store characterwise or linewise text, and they can also store macros.
Use Macro to Repeat Operations
Macros are recorded in named registers as characterwise. To record a macro, in normal mode perform
q<named register>- start recording- perform desired operation
q- stop recording@<named register>- replay the macro
To edit a macro stored in a register:
:let @<named_register>='Ctrl-r <named_register>- insert the macro contents for modification- edit as needed
- press ENTER to save
Replay the most recently executed macro with @@.
Undo, Redo & Repeat
Keystrokes:
- Undo:
u - Redo:
Ctrl-r - Repeat:
.
Notice the difference between redo and repeat
- Redo - re-apply an undone change
- Repeat - re-execute the last change command
Example: if a line is deleted with dd
urestores the deleted line.deletes the current line again
Work with Multiple Files
Netrw is Vim’s built‑in file explorer. Open it with :Exp. To open and edit a file directly, use :e <file>.
To open a file in a split windows, use
:sp <file>- horizontal split:vs <file>- vertical split
To move betwen windows, using Ctrl-w followed by
h- move the cursor to the left windowj- move the cursor to the bottom windowk- move the cursor to the top windowl- move the cursor to the right window
Buffer
File contents are loaded into buffers before being written to disk. View all buffers with :buffers.
:buffers
2 "lab.scala" line 2
3 #a "sample.scala" line 1
4 %a "lab2.scala" line 1
Explanation
- To open a specific buffer in the current winwdow, use
b <buffer_number>. For instance,b 2to open “lab.scala” in the current window a- the active buffer (visible in at least one window)%- the current buffer (visible in the current window)#- alternative buffer (last visited buffer)
To delete a buffer, use :bd <buffer_number>.
Options
Options can be configured in command‑line mode using :set <option>. Common useful options:
hls- highlight search matchesnu- show absolute line numbersrnu- show relative line numbersnu rnu- show relative line numbers with an absolute line number on the current line
ic- ignore case when searching
To toggle an option, use :set <option>!. For example :set hls! to disable search highlighting.
Use Vim Key Binding Elsewhere
Vim keybindings can be used in many other applications to improve productivity. Examples include:
- Tmux — a terminal multiplexer with Vim‑style navigation
- VS Code Vim — an extension that enables Vim keybindings in Visual Studio Code
- Vifm — a file manager with native Vim‑like commands
- Vimium — a browser extension that brings Vim navigation to Chrome and Firefox