Thoughts:
Right off the bat Drew tells you not to read the book linearly, to pick at it
here and there. I read it linearly. It is set up like a cookbook, which I
normally don't like at all, but there was enough elaboration with each tip and
the similar tips were grouped together. Not a particularly easy task since
there are so many ways you might get to the same solution with vim, none being
the 'right' way.
Though I didn't take the advice and read it cover to cover, I did do it slowly,
over about two weeks. I tried to pick a few things that I wanted to integrate
and made a point of consciously using them for a few days; many of the habits
stuck. This is the best way to learn vim, bit by bit. Learn one new thing a
day, or a week, and, eventually, you'll have attained mastery, or at least
competence.
On top of this strategy, I also have a list of all the stuff I'd eventually
like to integrate as second nature. This prevents me from ever getting to the
point where I become comfortable without having to be constantly looking for
new tips. This book would be great to poke around in, there will always be
something new, or at least will lead you to a more advanced understanding of
something old, but I rather prefer my making one pass and compiling a TODO
list. I'll probably go through the book again though, maybe even before my
list is empty.
The other key thing to realize is, reading alone is not enough. You get good at
vim the same way you get to Carnegie Hall; practice, practice, practice! You
should always try out new and interesting ways of doing things. By having a
scratch file to work with, which apparently are available online to follow the
book exactly, though I simply made up my own examples, you can fiddle with new
commands without wrecking a real project.
All in all, when you hear people online saying that this is THE vim book, I
think they are right. This book is highly recommended; I was very pleased with
it.
My list of random stuff I want to learn:
-
gU = make all uppercase was one I had been lacking
-
Tim Pope’s commentary.vim plugin provides a
good example.[4] This adds a command for commenting and uncommenting lines of
code in all languages supported by Vim. The commentary command is triggered by
gc{motion}
, which toggles commenting for the specified lines.
-
From insert mode, command line, or bash:
| Keystrokes | Effect
-------------------
`<C-h>` | Delete back one character (backspace)
`<C-w>` | Delete back one word
`<C-u>` | Delete back to start of line
|
| Keystrokes | Effect
-----------+-------
`<C-o>` | Switch to Insert Normal mode
|
-
J
= joins current and next line (can use when I write my 5 sent abstracts that
I want on one line, but type as 5 lines.
-
<C-[>
=
-
In Insert mode, we can press <C-r>0
to paste the text that we just yanked
at the current cursor position.
-
The expression register is addressed by the = symbol. From Insert mode we can
access it by typing <C-r>=
. This opens a prompt at the bottom of the screen
where we can type the expression that we want to evaluate. When done, we hit
<CR>
, and Vim inserts the result at our current position in the document.
-
gv
| Reselect the last visual selection
-
o
| Go to other end of highlighted text
-
use >
for indenting (from visual mode instead of I etc)
-
use 'r' instead of 'I' to add columns of data
-
yyp
then Vr{char}
to underline a line to the exact length
-
Append to end of ragged lines: visual block, $, A{char},
-
:[range]join
Join the specified lines
-
:{number}
= jumps to line number (useful to get to bugs in stack traces)
-
:{+-}{number}
= jumps to line number lines up (-) or down (+)
-
{number}G
= jumps to line number (useful to get to bugs in stack traces)
-
:h range
-
:t
or :co
or :copy
, combined with line numbers, useful in visual mode
-
:move
or :m
works much like :copy
-
Repeating the last Ex command is as easy as pressing @:
-
The :’<,’>normal .
command can be read as follows: “For each line in the
visual selection, execute the Normal mode . command.”
-
:%normal A;
= append a ; at the end of ever line in the file
-
:help @
-
The :read !{cmd}
command lets us direct standard output into a buffer. As
you might expect, the :write !{cmd}
does the inverse: it uses the contents of
the buffer as standard input for the specified {cmd} (see :write_c)
-
The effect of the :write !sh
command is that each line of the current
buffer is executed in the shell. Refer to :h rename-files
:2,$!sort -t',' -k2
-
The :lcd {path}
command lets us set the working directory locally for the
current window.
-
ea
moves to the end of current word and append, think of as end-append
| Keystrokes Current | Keystrokes Current
---------------------+-------------------
`iw` word | `aw` word plus space(s)
`iW` WORD | `aW` WORD plus space(s)
`is` sentence | `as` sentence plus space(s)
`ip` paragraph | `ap` paragraph plus blank line(s)
|
-
Lowercase marks are local to each individual buffer, whereas uppercase marks
are globally accessible.
-
`{mark} (backtick) takes you to the exact place a mark was set
-
'{mark}
(apostrophe) takes you to the beginning of the line a mark was set
on.
-
Table 10. Vim’s Automatic Marks
| Keystrokes | Buffer Contents
---------- +-------------------------------------------
`“` | Position before the last jump within current file
`‘.` | Location of last change
`‘^` | Location of last insertion
`‘[` | Start of last change or yank
`‘]` | End of last change or yank
`‘<` | Start of last visual selection
`‘>` | End of last visual selection
|
-
The %
command lets us jump between opening and closing sets of parentheses
(see %). It works with (), {}, and [], <>
-
Even though matchit ships with the Vim distribution, it’s not enabled by
default. This minimal vimrc would make Vim autoload the matchit plugin on
startup:
| set nocompatible
filetype plugin on
runtime macros/matchit.vim
|
-
The enhancements provided by this plugin are very useful, so I’d recommend
enabling it. Consult matchit-install
for more details.
-
Surround.vim
-
One of my favorite plugins is surround.vim by Tim Pope,[16] which makes
wrapping a selection with a pair of delimiters easy. For example, we could put
the words New York in quote marks:
| Keystrokes | Buffer Contents
-----------+----------------------------------------
`{start}` | cities = ["London", "Berlin", New York]
`vee` | cities = ["London", "Berlin", New York]
`S"` | cities = ["London", "Berlin", "New York"]
|
-
The S"
command is provided by surround.vim, and it can be read as “Surround
the selection with a pair of double quote marks.” We could just as easily use
S)
or S}
if we wanted to wrap the selection with opening and closing
parentheses or braces.
-
We can also use surround.vim to change existing delimiters. For example, we
could change {London} to [London] with the cs}]
command, which can be read as
“Change surrounding {} braces to [] brackets.” Or we could go the other way
with the cs]}
command. It’s a powerful plugin—check it out.
-
:put {reg}
puts/pastes
-
Matching within delimiters:
| Keystrokes | Buffer Contents
------------------------+-----------------------------------------
`{start}` | Match "quoted words"---not quote marks.
`/\v"[^"]+" <CR>` | Match "quoted words"---not quote marks.
`/\v"\zs[^"]+\ze" <CR>` | Match "quoted words"---not quote marks.
|
| Command | Effect
--------+----------------------------------------------------
`n` | Jump to next match, preserving direction and offset
`N` | Jump to previous match, preserving direction and offset
`/<CR>` | Jump forward to next match of same pattern
`?<CR>` | Jump backward to previous match of same pattern
`gn` | Enable character-wise Visual mode and select next search match
`gN` | Enable character-wise Visual mode and select previous search match
|
-
q/
brings up command mode with search history
-
//
runs the last search
-
If we prefix a % at the start of the substitute command, it will be executed
on every line of the file: :%s/going/rolling/g
-
:[range] global[!] /{pattern}/ [cmd]
-
The default range for the :global command is the entire file (%). That sets
it apart from most other Ex commands, including :delete, :substitute, and
:normal, whose range is the current line (. ) by default.
-
The {pattern} field integrates with search history. That means we can leave
it blank and Vim will automatically use the current search pattern.
-
The [cmd] could be any Ex command except for another :global command.
-
We can invert the behavior of the :global
command either by running
:global!
or :vglobal
(mnemonic: invert). Each of these tells Vim to execute
[cmd] on each line that doesn’t match the specified pattern.
-
On the Etymology of Grep
-
Consider this abbreviated form of the :global command:
-
:g/re/p
-
:v/href/d
(:vglobal) can be read as “Delete each line that doesn’t contain
href.”
-
Suppose that we wanted to collect all of the TODO items in one place. We
could view them all at a glance by running this command: :g/TODO
-
let’s yank each line containing the word “TODO” into a register. Then we can
paste the contents of that register into another file and keep them around for
later. We’ll use the a register. First we’ll need to clear it by running
qaq
. Let’s break that down: qa
tells Vim to start recording a macro into
the a register, and then q
stops the recording. We didn’t type anything while
the macro was recording, so the register ends up empty. We can check that by
running the following:
| :reg a
--- Registers ---
"a
|
- Now we can go ahead and yank the TODO comments into the register:
| :g/TODO/yank A
:reg a
"a // TODO: Cache this regexp for certain depths.
// TODO: No matching end code found - warn!
|
-
Here’s an alternative solution: :g/TODO/t$
-
It uses the :t
command, which we met in Tip 29. Rather than appending each
TODO item to a register, we simply copy it to the end of the file. After
running this command, we could jump to the end of the file to review the TODO
items. This technique is more straightforward because it avoids messing around
with registers. But it won’t work as neatly with the :argdo
and :bufdo
commands.
-
':sort'
-
:vimgrep TERM %
searches in the open file
:copen
brings up the matches, to goto the current line.
:cnext
and :cprevious
cycle through matches
Notes:
Table of Contents
Introduction
01: The Vim Way
02: Normal Mode
03: Insert Mode
04: Visual Mode
05: Command-Line Mode
06: Manage Multiple Files
07: Open Files and Save Them to Disk
08: Navigate Inside Files with Motions
09: Navigate Between Files with Jumps
10: Copy and Paste
11: Macros
12: Matching Patterns and Literals
13: Search
14: Substitution
15: Global Commands
16: Index and Navigate Source Code with ctags
17:Compile Code and Navigate Errors with the Quickfix List
18: Search Project-Wide with grep, vimgrep, and Others
19: Dial X for Autocompletion
20: Find and Fix Typos with Vim’s Spell Checker
21: Now What?
Appendix 1
- // Pages numbers from the pdf.
- // Learn to touch type first.
page 39:
- the >G
command increases the indentation from the current line until the
end of the file.
page 44:
| con+cat+these+with+spaces
,f+s + <Esc> # I've remapped f to ,f
;. # so I can use f for easymotion without leader
;.
;.
con + cat + these + with + spaces
|
page 46:
- Perform substitution :s/target/replacement
page 60:
- 10<C-a>
adds ten to the current/next number in line.
page 61:
- Number Formats
-
What follows 007? No, this isn't a James Bond gag; I'm asking what result
would you expect if you added one to 007.
-
If you answered 008, then you might be in for a surprise when you try using
Vim's command on any number with a leading zero. As is the convention in
some programming languages, Vim interprets numerals with a leading zero to be
in octal notation rather than in decimal. In the octal numeric system, 007 +
001 = 010, which looks like the decimal ten but is actually an octal eight.
Confused?
-
If you work with octal numbers frequently, Vim's default behavior might suit
you. If you don't, you probably want to add the following line to your vimrc:
-
set nrformats=
-
This will cause Vim to treat all numerals as decimal, regardless of whether
they are padded with zeros.
page 64:
- Table 2. Vim’s Operator Commands
1
2
3
4
5
6
7
8
9
10
11
12 | Trigger | Effect
----------------
`c` | Change
`d` | Delete
`y` | Yank into register
`g~` | Swap case
`gu` | Make lowercase
`gU` | Make uppercase
`>` | Shift right
`<` | Shift left
`=` | Autoindent
`!` | Filter {motion} lines through an external program
|
page 65:
- when an operator command is invoked in duplicate, it acts upon the current
line. So dd
deletes the current line, while >>
indents it. The gU
command
is a special case. We can make it act upon the current line by running either
gUgU
or the shorthand gUU
.
- Tim Pope’s commentary.vim plugin provides a
good example.[4] This adds a command for commenting and uncommenting lines of
code in all languages supported by Vim. The commentary command is triggered by
gc{motion}
, which toggles commenting for the specified lines.
- If you’re curious about how to create your own custom operators, start by
reading
:help map-operator
- If you’re curious about how to create your own custom motions, start by
reading
:h omap-info
page 68:
- From insert mode, command line, or bash:
| Keystrokes | Effect
-----------+-------
`<C-h>` | Delete back one character (backspace)
`<C-w>` | Delete back one word
`<C-u>` | Delete back to start of line
|
| Keystrokes | Effect
-----------+-------
`<Esc>` | Switch to Normal mode
`<C-[>` | Switch to Normal mode
`<C-o>` | Switch to Insert Normal mode
|
page 71:
- In Insert mode, we can press <C-r>0
to paste the text that we just yanked
at the current cursor position.
page 73:
- The expression register is addressed by the = symbol. From Insert mode we can
access it by typing
<C-r>=
. This opens a prompt at the bottom of the screen
where we can type the expression that we want to evaluate. When done, we hit
<CR>
, and Vim inserts the result at our current position in the document.
page 74:
- We can tell Vim to insert any arbitrary character if we know its numeric
code. From Insert mode, we just have to type <C-v>{code}
, where {code} is the
address of the character that we want to insert. Vim expects the numeric code
to consist of three digits. Suppose, for example, that we wanted to insert an
uppercase “A” character. The character code is 65, so we would have to enter it
as <C- v>065
.
- But what if we wanted to insert a character whose numeric code is longer than
three digits? For example, the Unicode Basic Multilingual Plane has an address
space for up to 65,535 characters. It turns out that we can enter all of these
using a four-digit hexadecimal code if we type
<C-v>u{1234}
(note the u
preceding the digit this time). Let’s say we wanted to insert an inverted
question mark symbol (“¿”), which is represented by the character code 00bf.
From Insert mode, we would just have to type <C-v>u00bf
. See i_CTRL-V_digit
for more details.
If you want to find out the numeric code for any character in your document,
just place the cursor on it and trigger the ga
command.
page 75:
- Table 3. Inserting Unusual Characters
| Keystrokes | Effect
----------------------+-------
`<C-v>{123}` | Insert character by decimal code
`<C-v>u{1234}` | Insert character by hexadecimal code
`<C-v>{nondigit}` | Insert nondigit literally
`<C-k>{char1}{char2}` | Insert character represented by {char1}{char2} digraph
|
page 76:
- :h digraph-table
page 82:
- Visual modes:
| Command | Effect
--------+-------
`v` | Enable character-wise Visual mode
`V` | Enable line-wise Visual mode
`<C-v>` | Enable block-wise Visual mode
`gv` | Reselect the last visual selection
|
page 83:
| Command | Effect
--------+-------
`o` | Go to other end of highlighted text
|
page 88:
- If we want to set up the dot command so that it repeats something useful,
then we’re better off staying out of Visual mode. As a general rule, we should
prefer operator commands over their Visual mode equivalents when working
through a repetitive set of changes.
page 90:
- yyp
then Vr{char}
to underline a line to the exact length
page 93:
- Append to end of ragged lines:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | Keystrokes | Buffer Contents
-------------+-----------------------
{start} | var foo = 1
Normal mode | var bar = 'a'
| var foobar = foo + bar
-------------+-----------------------
<C-v>jj$ | var foo = 1
Visual-Block | var bar = ’a’
| var foobar = foo + bar
-------------+-----------------------
A; | var foo = 1;
Insert mode | var bar = 'a'
| var foobar = foo + bar
-------------+-----------------------
<Esc> | var foo = 1;
Normal mode | var bar = 'a';
| var foobar = foo + bar;
-------------+-----------------------
|
- Table 7. Ex Commands That Operate on the Text in a Buffer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | :[range]delete [x]
Delete specified lines [into register x]
:[range]yank [x]
Yank specified lines [into register x]
:[line]put [x]
Put the text from register x after the specified line
:[range]copy {address}
Copy the specified lines to below the line specified by {address}
:[range]move {address}
Move the specified lines to below the line specified by {address}
:[range]join
Join the specified lines
:[range]normal {commands}
Execute Normal mode {commands} on each specified line
:[range]substitute/{pattern}/{string}/[flags]
Replace occurrences of {pattern} with {string} on each specified line
:[range]global/{pattern}/[cmd]
Execute the Ex command [cmd] on all specified lines where the {pattern} matches
|
page 99:
- :{number}
= jumps to line number (useful to get to bugs in stack traces)
page 100:
- :{range}
= :{start},{end}
= do something over the range
-
.
in range, as in :.,{end}
, = current line
-
%
= all the lines in current file
-
use % with substitute like: :%s/Practical/Pragmatic/
page 101:
- If we press the :
key now [after visually selecting], the command-line
prompt will be prepopulated with the range :’<,’>
. It looks cryptic, but you
can think of it simply as a range standing for the visual selection.
- Vim also accepts a pattern as an address for an Ex command, such as the one
shown here:
| = > :/<html>/,/<\/html>/p
< = 2 <html>
3 <head><title>Practical Vim</title></head>
4 <body><h1>Practical Vim</h1></body>
5 </html>
|
- This looks quite complex, but it follows the usual form for a range:
:{start},{end}. The {start} address in this case is the pattern //, while
the {end} address is /<\/html>/.
page 105:
- So we can read the :6copy.
command as “Make a copy of line 6 and put it
below the current line.”
- We could shorten the
:copy
command to only two letters, as :co
. Or we
can be even more succinct by using the :t
command, which is a synonym for
:copy. As a mnemonic, you can think of it as copy
TO. This table shows a few examples of the :t
command in action:
| Command | Effect
-----------+-------
`:6t.` | Copy line 6 to just below the current line
`:t6` | Copy the current line to just below line 6
`:t.` | Duplicate the current line (similar to Normal mode yyp )
`:t$` | Copy the current line to the end of the file
`:’<,’>t0` | Copy the visually selected lines to the start of the file
|
:move
or :m
works much like :copy
page 106:
- Repeating the last Ex command is as easy as pressing @:
, then @@
for more
repeats
page 108:
- The :’<,’>normal .
command can be read as follows: “For each line in the
visual selection, execute the Normal mode . command.”
:%normal A;
= append a ; at the end of ever line in the file
page 110:
- :help @
page 117:
- Press q:
and meet the command-line window (see cmdwin)
page 118:
- What if halfway through composing an Ex command at the prompt, we realize
that we need more editing power? In Command-Line mode, we can use the
mapping to switch to the command- line window, preserving a copy of the command
that was typed at the prompt. This table summarizes a few of the methods for
summoning the command-line window:
| Command | Action
---------+-------
`q/` | Open the command-line window with history of searches
`q:` | Open the command-line window with history of Ex commands
`ctrl-f` | Switch from Command-Line mode to the command-line window
|
page 119:
- Vim’s :shell
command to start an interactive shell session (see :shell
page 120:
- Suppose that we’re running Vim inside a bash shell and we want to execute a
series of shell commands. Pressing Ctrl - z suspends the process that’s running
Vim and returns control to bash. The Vim process sits idle in the background,
allowing us to interact with our bash session as normal. We can inspect the
list of jobs by running this command:
| => $ jobs
<= [1]+ Stopped vim
|
-
In bash, we can use the fg
command to resume a suspended job, bringing it
back into the foreground. That brings Vim back to life exactly as we left it.
The Ctrl-z
and fg
commands are quicker and easier to use than Vim’s
equivalent :shell and exit commands. For more information, run man bash and
read the section on job control.
-
the :read !{cmd}
command, which puts the output from the {cmd} into our
current buffer (see :read!).
-
The :read !{cmd}
command lets us direct standard output into a buffer. As
you might expect, the :write !{cmd}
does the inverse: it uses the contents of
the buffer as standard input for the specified {cmd} (see :write_c)
page 121:
- The effect of the
:write !sh
command is that each line of the current
buffer is executed in the shell. Refer to :h rename-files
| first name,last name,email
john,smith,john@example.com
drew,neil,drew@vimcasts.org
jane,doe,jane@example.com
|
-
We’ll sort the records by the second field: last name. We can use the -t’,’
option to tell the sort command that fields are separated with commas, and we
can use the -k2 flag to indicate that the second field is to be used for the
sort.
-
The first line of the file contains header information. We want to leave it
at the top of the file, so we’ll exclude it from the sort operation by using a
range of :2,$ . This command line does what we want:
:2,$!sort -t',' -k2
- The records in our CSV file should now be sorted by last name:
| first name,last name,email
jane,doe,jane@example.com
drew,neil,drew@vimcasts.org
john,smith,john@example.com
|
page 122:
- The !{motion}
operator command drops us into Command-Line mode and
prepopulates the [range] with the lines covered by the specified {motion} (see
!). For example, if we place our cursor on line 2 and then invoke !G
, Vim
opens a prompt with the :.,$! range set up for us.
| Command | Effect
-----------------------+-------------------------------------------------------
`:shell` | Start a shell (return to Vim by typing exit)
`:!{cmd}` | Execute {cmd} with the shell
`:read !{cmd}` | Execute {cmd} in the shell and insert its standard output below the cursor
`:[range]write !{cmd}` | Execute {cmd} in the shell with [range] lines as standard input
`:[range]!{filter}` | Filter the specified [range] through external program {filter}
|
page 124:
- batch.vim
| global/href/join
vglobal/ href/delete
%normal A: http:/ /vimcasts.org
%normal yi"$p
%substitute/\v^[^\>]+\>\s//g
|
- We can use the
:source
command to execute the batch.vim script (see
source). Each line of the script is executed as an Ex command, just as though
we had typed it
page 125:
:argdo source batch.vim
- // Need to get all the files into
:args
. Can do this by
opening vim ala vim * (to open all files in directory, or match however). Can
also use :bufdo
and :argadd %
to set up the :args
.
page 140:
| Ex Command | Normal Command Effect
-----------+----------------------
`:clo[se]` | `<C-w>c` Close the active window
`:on[ly]` | `<C-w>o` Keep only the active window, closing all others
|
page 142:
- The :lcd {path}
command lets us set the working directory locally for the
current window.
- Note that
:lcd
applies locally to the current window, not to the current
tab page. If we have a tab page containing two or more split windows, we could
set the local working directory for all of them by running :windo lcd {path}
.
| Command | Effect
----------------------- +-----------------------------
`:tabe[dit] {filename}` | Open {filename} in a new tab
`<C-w>T` | Move the current window into its own tab
`:tabc[lose]` | Close the current tab page and all of its windows
`:tabo[nly]` | Keep the active tab page, closing all others
|
page 155:
- save a read only file as root:
| = > : w !sudo tee % > /dev/null
< = Password:
W12: Warning: File "hosts" has changed and the buffer was
changed in Vim as well
[O]k, (L)oad File, Load (A)ll, (I)gnore All:
|
page 158:
- :h motions
page 163:
- Word motions:
| Command | Move Cursor
--------+------------
`w` | Forward to start of next word
`b` | Backward to start of current/previous word
`e` | Forward to end of current/next word
`ge` | Backward to end of previous word
|
page 172:
| Keystrokes | Buffer Contents
-------------+-----------------
{start} | This phrase [t]akes time but
| eventually gets to the point.
|
`d /ge <CR>` | This phrase [g]ets to the point.
|
page 177:
- text objects:
| Keystrokes Current | Keystrokes Current
---------------------+-------------------
`iw` word | `aw` word plus space(s)
`iW` WORD | `aW` WORD plus space(s)
`is` sentence | `as` sentence plus space(s)
`ip` paragraph | `ap` paragraph plus blank line(s)
|
page 178:
- As a general rule, we could say that the d{motion}
command tends to work
well with aw
, as
, and ap
, whereas the c{motion}
command works better
with iw
and similar.
page 179:
- Lowercase marks are local to each individual buffer, whereas uppercase marks
are globally accessible.
page 180:
- Table 10. Vim’s Automatic Marks
| Keystrokes | Buffer Contents
---------- +-------------------------------------------
`“` | Position before the last jump within current file
`‘.` | Location of last change
`‘^` | Location of last insertion
`‘[` | Start of last change or yank
`‘]` | End of last change or yank
`‘<` | Start of last visual selection
`‘>` | End of last visual selection
|
page 181:
- The %
command lets us jump between opening and closing sets of parentheses
(see %). It works with (), {}, and [], <>
page 182:
| Keystrokes | Buffer Contents
---------- +------------------------------------
`{start}` | cities = %w{London Berlin New\ York}
`dt{` | cities = {London Berlin New\ York}
`%` | cities = {London Berlin New\ York}
`r]` | cities = {London Berlin New\ York]
```` | cities = {London Berlin New\ York]
`r[` | cities = [London Berlin New\ York]
|
page 183:
- Even though matchit ships with the Vim distribution, it’s not enabled by
default. This minimal vimrc would make Vim autoload the matchit plugin on
startup:
| set nocompatible
filetype plugin on
runtime macros/matchit.vim
|
-
The enhancements provided by this plugin are very useful, so I’d recommend
enabling it. Consult matchit-install
for more details.
-
Surround.vim
-
One of my favorite plugins is surround.vim by Tim Pope,[16] which makes
wrapping a selection with a pair of delimiters easy. For example, we could put
the words New York in quote marks:
| Keystrokes | Buffer Contents
-----------+----------------------------------------
`{start}` | cities = ["London", "Berlin", @N@ew York]
`vee` | cities = ["London", "Berlin", New Yor@k@]
`S"` | cities = ["London", "Berlin", "New York"]
|
-
The S"
command is provided by surround.vim, and it can be read as “Surround
the selection with a pair of double quote marks.” We could just as easily use
S)
or S}
if we wanted to wrap the selection with opening and closing
parentheses or braces.
-
We can also use surround.vim to change existing delimiters. For example, we
could change {London} to [London] with the cs}]
command, which can be read as
“Change surrounding {} braces to [] brackets.” Or we could go the other way
with the cs]}
command. It’s a powerful plugin—check it out.
page 190:
- We can inspect the value of the path by running this command:
| = > :set path?
< = path=.,/usr/include,,
|
- In this context, the . stands for the directory of the current file, whereas
the empty string (delimited by two adjacent commas) stands for the working
directory.
page 201:
- In addition to the Normal mode commands, Vim also provides Ex commands for
delete, yank, and put operations. We could cut the current line into register c
by running :delete c
, and then we could paste it below the current line with
the :put c
command.
page 202:
- When we use the y{motion}
command, the specified text is copied not only
into the unnamed register but also into the yank register, which is addressed
by the 0 symbol (see quote0). As the name suggests, the yank register is set
only when we use the y{motion}
command.
page 203:
- When we address a named register with a lowercase letter, it overwrites the
specified register, whereas when we use an uppercase letter, it appends to the
specified register.
page 204:
- The System Clipboard ( "+) and Selection ("*) Registers
| Keystrokes | Buffer Contents
-----------+----------------
`"+` | The X11 clipboard, used with cut, copy, and paste
`"*` | The X11 primary, used with middle mouse button
|
page 205:
| Register | Contents
---------+---------
`"%` | Name of the current file
`"#` | Name of the alternate file
`".` | Last inserted text
`":` | Last Ex command
`"/` | Last search pattern
|
page 236:
- counting with simple vimscript
| Keystrokes Buffer | Contents
-------------------------+------------------
`:let i=1` | [p]artridge in a pear tree
`qa` | [p]artridge in a pear tree
`I<C-r>= i <CR> )<Esc>` | 1)[ ]partridge in a pear tree
`:let i += 1` | 1)[ ]partridge in a pear tree
`q` | 1)[ ]partridge in a pear tree
|
page 252:
- We can reference the captured text as \1 . If our pattern contained more than
one set of parentheses, then we could reference the submatch for each pair of
() by using \1 , \2, and so on, up to \9. The \0 item always refers to the
entire match, whether or not parentheses were used in the pattern.
page 256:
- Matching within delimiters:
| Keystrokes | Buffer Contents
------------------------+-----------------------------------------
`{start}` | Match "quoted words"---not quote marks.
`/\v"[^"]+" <CR>` | Match "quoted words"---not quote marks.
`/\v"\zs[^"]+\ze" <CR>` | Match "quoted words"---not quote marks.
|
- The basic pattern uses a common regex idiom: "[^"]+" . The pattern begins and
ends with a quote mark and then matches one or more characters in between that
are anything but a quote.
page 259:
- Escaping characters by hand is laborious, error-prone work. Fortunately, Vim
script includes a library function that can do the hard work for us:
escape({string}, {chars}) (see escape() i). The {chars} argument specifies
which characters must be escaped with a backslash. If we’re searching forward,
we could call escape(@u, ’/\’), which would prefix each / and \ character with
a backslash. If we were searching backward, we could instead call escape(@u,
’?\’).
- First, make sure that the URL we want to search for is still stored in the u
register. Then we’ll bring up the search prompt by pressing / or ?; either one
will work just fine. Enter the \V literal switch and then type = . That
switches from the search prompt to the expression register prompt. Now we type
this:
| => escape(@u, getcmdtype().'\')
|
- When we press , the escape() function is evaluated, and the returned
value gets inserted into the search field. The getcmdtype() function simply
returns a / symbol if we’re searching forward or a ? symbol if we’re searching
backward (see getcmdtype() i). In Vim script, the . operator performs string
concatenation, so getcmdtype().’\’ produces ’/\’ if we’re searching forward and
’?\’ if we’re searching backward. The end result is that no matter which way
we’re searching, this expression escapes the contents of the u register so that
we can find it.
page 263:
- Searching:
| Command | Effect
--------+----------------------------------------------------
`n` | Jump to next match, preserving direction and offset
`N` | Jump to previous match, preserving direction and offset
`/<CR>` | Jump forward to next match of same pattern
`?<CR>` | Jump backward to previous match of same pattern
`gn` | Enable character-wise Visual mode and select next search match
`gN` | Enable character-wise Visual mode and select previous search match
|
page 268:
- after pressing n
a couple of times, we realize that we’d prefer to place
the cursor at the end of the match. That’s no problem: we could simply run
//e<CR>
. When we leave the search field blank like this, Vim reuses the
pattern from the previous search. So this repeats the last search but with an
offset.
page 273:
- q/
brings up command mode with search history
-
//
runs the last search
-
visual-star.vim
| xnoremap * :<C-u>call <SID>VSetSearch(' /')<CR>/<C-R>=@/<CR><CR>
xnoremap # :<C-u>call <SID>VSetSearch(' ?')<CR>?<C-R>=@/<CR><CR>
function! s:VSetSearch(cmdtype)
let temp = @s
norm! gv"sy
let @/ = '\V' . substitute(escape(@s, a:cmdtype.' \'), '\ n ' , '\\n ' , 'g' )
let @s = temp
endfunction
|
- You can either paste this into your vimrc file directly or install the visual
star search plugin.[22] As well as overriding the * command, we’ve customized
the # command, which searches backward for selected text. The xnoremap keyword
specifies that the mappings should apply to Visual mode but not to Select mode
(see mapmode-x).
page 281:
- The n
flag suppresses the usual substitute behavior, causing the command to
report the number of occurrences that would be affected if we ran the
substitute command. Tip 86, gives an example of usage.
page 282:
- The &
flag simply tells Vim to reuse the same flags from the previous
substitute command.
| Symbol | Represents
-----------------+-------------------------
`\r` | Insert a carriage return
`\t` | Insert a tab character
`\\` | Insert a single backslash
`\1` | Insert the first submatch
`\2` | Insert the second submatch (and so on, up to \9)
`\0` | Insert the entire matched pattern
`&` | Insert the entire matched pattern
`~` | Use {string} from the previous invocation of :substitute
`\={Vim script}` | Evaluate {Vim script} expression; use result as replacement {string}
|
page 284:
- If we prefix a % at the start of the substitute command, it will be executed
on every line of the file: :%s/going/rolling/g
page 285:
- In fact, [when :s///c] Vim helpfully reminds us of
our options with the prompt “y/n/a/q/l/^E/^Y.” This table shows what each
answer means:
| Trigger | Effect
--------+----------------------
`y` | Substitute this match
`n` | Skip this match
`q` | Quit substituting
`l` | “last”—Substitute this match, then quit
`a` | “all”—Substitute this and any remaining matches
`<C-e>` | Scroll the screen up
`<C-y>` | Scroll the screen down
|
page 287:
- Leaving the search field of the substitute command blank instructs Vim to
reuse the most recent search pattern.
- allows us to select any text in our document and then hit the
*
key to
search for the selection. We could then run the substitute command with an
empty search field to replace our selection
page 288:
- Pressing <C-r>/
at the command line pastes the contents of the last search
register in place.
page 290:
- Look at this command:
| => :%s/Pragmatic Vim/Practical Vim/g
|
- Compare it with this sequence of commands:
| => :let @/='Pragmatic Vim'
=> :let @a='Practical Vim'
=> :%s//\=@a/g
|
-
:let @/=’Pragmatic Vim’
is a programmatic way of setting the search
pattern. It has the same effect as executing the search /Pragmatic Vim<CR>
(except that running :let @/=’Pragmatic Vim’
does not create a record in the
search history).
-
Likewise, :let @a=’Practical Vim’ sets the contents of the a register.
page 292:
- :%s//~/&
- This longhand command spells out the following instruction: repeat the last
substitute command using the same flags, the same replacement string, and the
current search pattern, but use the % range. In other words, repeat the last
substitution across the entire file.
page 294:
- We can always specify a new range and replay the substitution using the :&&
command. It doesn’t matter what range was used the last time. :&&
by itself
acts on the current line, :’<,’>&&
acts on the visual selection, and :%&&
acts on the entire file. As we saw already, the g&
command is a handy
shortcut for :%&&
.
page 295:
- The &
command is a synonym for :s, which repeats the last substitution.
Unfortunately, if any flags were used, the &
command disregards them, meaning
that the outcome could be quite different from the previous substitution.
Making &
trigger the :&&
command is more useful. It preserves flags and
therefore produces more consistent results. These mappings fix the &
command
in Normal mode and create a Visual mode equivalent:
| nnoremap & :&&<CR>
xnoremap & :&&<CR>
|
page 296:
| last name,first name,email
neil,drew,drew@vimcasts.org
doe,john,john@example.com
|
- Now suppose that we want to swap the order of the fields so that the email
comes first, then the first name, and finally the last name. We could use this
substitute command to do it:
| => `/\v^([^,]*),([^,]*),([^,]*)$`
=> `:%s//\3,\2,\1`
|
-
In the pattern, [^,] matches anything that isn’t a comma. So ([^,]*) matches
zero or more consecutive non-commas and captures the result as a submatch
-
The result of running this command looks like this:
| email,first name,last name
drew@vimcasts.org,drew,neil
john@example.com,john,doe
|
page 298:
- Arithmetic on searches:
page 299:
| => :let swapper={"dog":"man","man":"dog"}
=> :echo swapper["dog"]
<= man
=> :echo swapper["man"]
<= dog
|
-
When we pass "dog" as a key to our swapper dictionary, it returns "man", and
vice versa.
-
swapping 2 (or more) words with substitute
| => /\v(<man>|<dog>)
=> :%s//\={"dog":"man","man":"dog"}[submatch(1)]/g
|
page 306:
- The :global
command takes the following form (see :g):
-
:[range] global[!] /{pattern}/ [cmd]
-
The default range for the :global command is the entire file (%). That sets
it apart from most other Ex commands, including :delete, :substitute, and
:normal, whose range is the current line (. ) by default.
-
The {pattern} field integrates with search history. That means we can leave
it blank and Vim will automatically use the current search pattern.
-
The [cmd] could be any Ex command except for another :global command.
-
We can invert the behavior of the :global
command either by running
:global!
or :vglobal
(mnemonic: invert). Each of these tells Vim to execute
[cmd] on each line that doesn’t match the specified pattern.
-
On the Etymology of Grep
-
Consider this abbreviated form of the :global command:
-
:g/re/p
-
re stands for regular expression, and p is short for :print, which is the
default [cmd]. If we ignore the / symbols, we find the word “grep.”
page 308:
- Just like with the :substitute command, we can leave the search field of the
:global command blank, and Vim will reuse the last search pattern
:v/href/d
(:vglobal) can be read as “Delete each line that doesn’t contain
href.”
page 309:
- Suppose that we wanted to collect all of the TODO items in one place. We
could view them all at a glance by running this command: :g/TODO
page 310:
- let’s yank each line containing the word “TODO” into a register. Then we can
paste the contents of that register into another file and keep them around for
later. We’ll use the a register. First we’ll need to clear it by running
qaq
. Let’s break that down: qa
tells Vim to start recording a macro into
the a register, and then q
stops the recording. We didn’t type anything while
the macro was recording, so the register ends up empty. We can check that by
running the following:
| :reg a
--- Registers ---
"a
|
- Now we can go ahead and yank the TODO comments into the register:
| :g/TODO/yank A
:reg a
"a // TODO: Cache this regexp for certain depths.
// TODO: No matching end code found - warn!
|
-
The trick here is that we’ve addressed our register with an uppercase A. That
tells Vim to append to the specified register
-
Here’s an alternative solution: :g/TODO/t$
-
It uses the :t
command, which we met in Tip 29. Rather than appending each
TODO item to a register, we simply copy it to the end of the file. After
running this command, we could jump to the end of the file to review the TODO
items. This technique is more straightforward because it avoids messing around
with registers. But it won’t work as neatly with the :argdo
and :bufdo
commands.
page 312:
- ':sort'
page 313:
- :g/{/ .+1,/}/-1 sort
- The { pattern matches the first line of each {} block. For every line that
matches, the :sort command is executed on a [range] that terminates at the end
of the {} block. The end result is that all CSS properties are alphabetized
within each block of rules.
-
A generalized form of this :global command goes like this: :g/{start}/
.,{finish} [cmd]
-
We can read this as “For each range of lines beginning with {start} and
ending with {finish}, run the specified [cmd].”
page 317:
- // ctags
page 337:
- ‘:compiler’ and ‘:make’ Are Not Just for Compiled Languages
-
The words make and compile have particular meanings in the context of a
compiled programming language. But in Vim, the corresponding :make and :compile
commands have more flexible definitions, making them just as applicable for
interpreted languages and markup formats.
-
For example, when working on a LaTeX document, we can configure Vim so that
the :make command compiles our .tex file into a PDF. Or if we’re working with
an interpreted language such as JavaScript, we can have :make run our source
code through JSLint or some other (less opinionated) syntax checker.
Alternatively, we could set up :make so that it runs the test suite.
-
In Vim’s terminology, a compiler is any external program that does something
with our document and produces a list of errors or warnings. The :make command
simply invokes the external compiler and then parses the output to construct a
navigable quickfix list from them.
page 345:
- //vimgrep
-
:vimgrep /TERM/ %
searches in the open file
-
:vimgrep /TERM/g %
matches beyond the first per line (global)
-
:copen
brings up the matches, to goto the current line.
-
:cnext
and :cprevious
cycle through matches
page 346:
- This is the format of the :vimgrep command (:vimgrep): :vim[grep][!]
/{pattern}/[g][j] {file}
- As well as being able to use * and ** wildcards, we can use the ## symbol,
which is expanded to represent the names of each file in the argument list
(cmdline-special i). This allows for an alternative workflow. First, we
populate the argument list with the files we want to inspect. Then we run
:vimgrep across each of the files in the argument list:
| => :args *.txt
=> :vim /going/g ##
|
- We can leave the pattern field empty, which tells :vimgrep to use the current
search pattern.
- We can also append a trailing & symbol to reset any option to its default
value:
:set ignorecase&