--- a/chapters/01.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/01.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -9,6 +9,7 @@
Run the following command:
+ :::vim
:echo "Hello, world!"
You should see `Hello, world!` appear at the bottom of the window.
@@ -18,12 +19,14 @@
Now run the following command:
+ :::vim
:echom "Hello again, world!"
You should see `Hello again, world!` appear at the bottom of the window.
To see the difference between these two commands, run one more new command:
+ :::vim
:messages
You should see a list of messages. `Hello, world!` will *not* be in this list,
@@ -42,6 +45,7 @@
your `~/.vimrc` file or another one) you can add comments with the `"`
character, like this:
+ :::vim
" Make space more useful
nnoremap <space> za
--- a/chapters/02.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/02.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,10 +8,12 @@
Run the following command:
+ :::vim
:set number
Line numbers should appear in Vim. Now run this:
+ :::vim
:set nonumber
The line numbers should disappear. `number` is a boolean option -- it can be
@@ -24,10 +26,12 @@
You can also "toggle" boolean options to set them to the *opposite* of whatever
they are now. Run this:
+ :::vim
:set number!
The line numbers should reappear. Now run it again:
+ :::vim
:set number!
They should disappear once more. Adding a `!` (exclamation point or "bang") to
@@ -39,6 +43,7 @@
You can ask Vim what an option is currently set to by using a `?`. Run these
commands and watch what happens after each:
+ :::vim
:set number
:set number?
:set nonumber
@@ -53,6 +58,7 @@
Some options take a value instead of just being off or on. Run the following
commands and watch what happens after each:
+ :::vim
:set number
:set numberwidth=10
:set numberwidth=4
@@ -63,6 +69,7 @@
Try checking what a few other common options are set to:
+ :::vim
:set wrap?
:set numberwidth?
@@ -72,6 +79,7 @@
Finally, you can specify more than one option in the same `:set` command. Try
running this:
+ :::vim
:set number numberwidth=6
Exercises
--- a/chapters/03.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/03.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -10,6 +10,7 @@
Type a few lines of text into a file, then run:
+ :::vim
:map \ x
Put your cursor somewhere in the text and press `\`. Notice how Vim deleted the
@@ -18,6 +19,7 @@
We already have a key for "delete that character under the cursor", so let's
change that mapping to something slightly more useful. Run this command:
+ :::vim
:map \ dd
Now put your cursor on a line somewhere and press `\` again. This time Vim
@@ -29,6 +31,7 @@
You can use `<keyname>` to tell Vim about special keys that are hard to type.
Try running this command:
+ :::vim
:map <space> viw
Put your cursor on a word in your text and press the space bar. Vim will
@@ -36,6 +39,7 @@
You can also map modifier keys like Ctrl and Alt. Run this:
+ :::vim
:map <c-d> dd
Now pressing `Ctrl+d` on your keyboard will run `dd`.
@@ -46,6 +50,7 @@
Remember in the first lesson where we talked about comments? Mapping keys is
one of the places where Vim comments don't work. Try running this command:
+ :::vim
:map <space> viw " Use space to select a word
If you try pressing `<space>` now, something horrible will almost certainly
--- a/chapters/04.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/04.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -12,7 +12,8 @@
Run this command:
- nmap \ dd
+ :::vim
+ :nmap \ dd
Now put your cursor in your text file, make sure you're in normal mode, and
press `\`. Vim will delete the current line.
@@ -23,7 +24,8 @@
Run this command:
- vmap \ U
+ :::vim
+ :vmap \ U
Enter visual mode and select some text, then press `\`. Vim will convert the
text to uppercase!
@@ -50,7 +52,8 @@
Now that we've covered how to map keys in normal and visual mode, let's move on
to insert mode. Run this command:
- imap <c-d> dd
+ :::vim
+ :imap <c-d> dd
You might think that this would let you press `Ctrl+d` whenever you're in insert
mode to delete the current line. This would be nice, because now you don't need
@@ -68,7 +71,8 @@
To make this mapping do what we intended we need to be very explicit. Run this
command to change the mapping:
- imap <c-d> <esc>dd
+ :::vim
+ :imap <c-d> <esc>dd
The `<esc>` is our way of telling Vim to press the Escape key, which will take
us out of insert mode.
@@ -79,7 +83,8 @@
Run one more command to fix the mapping once and for all:
- imap <c-d> <esc>ddi
+ :::vim
+ :imap <c-d> <esc>ddi
The `i` at the end reenters insert mode for us, and our mapping is finally
complete.
--- a/chapters/05.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/05.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,6 +8,7 @@
Run the following commands:
+ :::vim
:nmap - dd
:nmap \ -
@@ -26,6 +27,7 @@
Run this command:
+ :::vim
:nmap dd O<esc>jddk
You might think that this would change `dd` to:
@@ -77,6 +79,7 @@
Vim offers another set of mapping commands that will *not* take mappings into
account when they perform their actions. Run these commands:
+ :::vim
:nmap x dd
:nnoremap \ x
--- a/chapters/06.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/06.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -21,6 +21,7 @@
Unlike Emacs, Vim makes it easy to map more than just single keys. Run these
commands:
+ :::vim
:nnoremap -d dd
:nnoremap -c ddO
@@ -42,6 +43,7 @@
Vim calls this "prefix" key "leader". You can set your leader key to whatever
you like. Run this command:
+ :::vim
:let mapleader = "-"
You can replace `-` with any key you like. I personally like `,` even though it
@@ -50,6 +52,7 @@
When you're creating new mappings you can use `<leader>` to mean "whatever
I have my leader key set to". Run this command:
+ :::vim
:nnoremap <leader>d dd
Now try it out by pressing your leader key and then `d`. Vim will delete the
@@ -78,6 +81,7 @@
We'll talk about how to make mappings for specific types of files later in the
book, but you can go ahead and set your "localleader" now:
+ :::vim
:let maplocalleader = "\\"
Notice that we have to use `\\` and not just `\` because `\` is the escape
--- a/chapters/07.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/07.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -22,6 +22,7 @@
Lets add a mapping that will open our `~/.vimrc` file in a split so we can edit
it and get back to coding. Run this command:
+ :::vim
:nnoremap <leader>ev :vsplit $MYVIMRC<cr>
I like to think of this command as "**e**dit my **v**imrc file".
@@ -94,6 +95,7 @@
Let's add a mapping to make this easier:
+ :::vim
:nnoremap <leader>sv :source $MYVIMRC<cr>
I like to think of this command as "**s**ource my **v**imrc file".
--- a/chapters/08.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/08.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,10 +8,12 @@
We're only going to worry about insert mode abbreviations in this book. Run the
following command:
+ :::vim
:iabbrev adn and
Now enter insert mode and type:
+ :::text
One adn two.
As soon as you hit space after typing the "adn" Vim will replace it with "and".
@@ -19,11 +21,13 @@
Correcting typos like this is a great use for abbreviations. Run these
commands:
+ :::vim
:iabbrev waht what
:iabbrev tehn then
Now enter insert mode again and type:
+ :::text
Well, I don't know waht we should do tehn.
Notice how *both* abbreviations were substituted, even though you didn't type
@@ -36,6 +40,7 @@
after an abbreviation. "Non-keyword character" means any character not in the
`iskeyword` option. Run this command:
+ :::vim
:set iskeyword?
You should see something like `iskeyword=@,48-57,_,192-255`. This format is
@@ -63,6 +68,7 @@
Abbreviations are useful for more than just correcting typos. Let's add a few
more that can help in day-to-day text editing. Run the following commands:
+ :::vim
:iabbrev @@ steve@stevelosh.com
:iabbrev ccopy Copyright 2011 Steve Losh, all rights reserved.
@@ -82,6 +88,7 @@
Run this command:
+ :::vim
:inoremap ssig --<cr>Steve Losh<cr>steve@stevelosh.com
This is a *mapping* intended to let you insert your signature quickly. Try it
@@ -90,6 +97,7 @@
It seems to work great, but there's a problem. Try entering insert mode and
typing this text:
+ :::text
Larry Lessig wrote the book "Remix".
You'll notice that Vim has expanded the `ssig` in Larry's name! Mappings don't
@@ -99,6 +107,7 @@
Remove the mapping and replace it with an abbreviation by running the following
commands:
+ :::vim
:iunmap ssig
:iabbrev ssig --<cr>Steve Losh<cr>steve@stevelosh.com
--- a/chapters/09.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/09.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -10,6 +10,7 @@
Run the following command:
+ :::vim
:nnoremap jk dd
Now make sure you're in normal mode and press `j` followed quickly by `k`. Vim
@@ -22,6 +23,7 @@
This mapping will make it painful to move around our file, so lets remove it.
Run the following command:
+ :::vim
:nunmap jk
Now typing `jk` in normal mode will move down and then up a line as usual.
@@ -32,6 +34,7 @@
You've seen a bunch of simple mappings so far, so it's time to look at something
with a bit more meat to it. Run the following command:
+ :::vim
:nnoremap <leader>" viw<esc>a"<esc>hbi"<esc>lel
Now *that's* an interesting mapping! First, go ahead and try it out. Enter
@@ -41,6 +44,7 @@
How does this work? Let's split it apart into pieces and think of what each one
does:
+ :::vim
viw<esc>a"<esc>hbi"<esc>lel
* `viw`: visually select the current word
--- a/chapters/10.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/10.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -7,6 +7,7 @@
Let's set up one more mapping that will save more wear on your left hand than
any other mapping you ever create. Run the following command:
+ :::vim
:inoremap jk <esc>
Now enter insert mode and type `jk`. Vim will act as if you pressed the escape
@@ -41,6 +42,7 @@
The trick to relearning a mapping is to *force* yourself to use it by
*disabling* the old key(s). Run the following command:
+ :::vim
:inoremap <esc> <nop>
This effectively disables the escape key in insert mode by telling Vim to
--- a/chapters/11.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/11.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -17,6 +17,7 @@
Switch to file `foo` and run the following commands:
+ :::vim
:nnoremap <leader>d dd
:nnoremap <buffer> <leader>x dd
@@ -60,10 +61,12 @@
Switch to file `foo` and run the following command:
+ :::vim
:setlocal wrap
Now switch to file `bar` and run this command:
+ :::vim
:setlocal nowrap
Make your Vim window smaller and you'll see that the lines in `foo` wrap, but
@@ -71,10 +74,12 @@
Let's try another option. Switch to `foo` and run this command:
+ :::vim
:setlocal number
Now switch over to `bar` and run this command:
+ :::vim
:setlocal nonumber
You now have line numbers in `foo` but not in `bar`.
@@ -88,6 +93,7 @@
Before we move on, let's look at a particularly interesting property of local
mappings. Switch over to `foo` and run the following commands:
+ :::vim
:nnoremap <buffer> Q x
:nnoremap Q dd
--- a/chapters/12.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/12.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -15,6 +15,7 @@
Let's change it so that Vim creates files as soon as you edit them. Run the
following command:
+ :::vim
:autocmd BufNewFile * :write
This is a lot to take in, but try it out and see that it works. Run `:edit foo`
@@ -29,6 +30,7 @@
Let's take a closer look at the autocommand we just created:
+ :::text
:autocmd BufNewFile * :write
^ ^ ^
| | |
@@ -55,6 +57,7 @@
when you want the command to fire. Start up a new Vim instance and run the
following command:
+ :::vim
:autocmd BufNewFile *.txt :write
This is almost the same as the last command, but this time it will only apply to
@@ -76,6 +79,7 @@
Let's define another autocommand, this time using a different event. Run the
following command:
+ :::vim
:autocmd BufWrite *.html :normal gg=G
We're getting a bit ahead of ourselves here because we're going to talk about
@@ -85,6 +89,7 @@
Create a new file called `foo.html`. Edit it with Vim and enter the following
text *exactly*, including the whitespace:
+ :::html
<html>
<body>
<p>Hello!</p>
@@ -111,6 +116,7 @@
You can create a single autocommand bound to *multiple* events by separating the
events with a comma. Run this command:
+ :::vim
:autocmd BufWrite,BufRead *.html :normal gg=G
This is almost like our last command, except it will also reindent the code
@@ -121,6 +127,7 @@
together to run a command whenever you open a certain kind of file, regardless
of whether it happens to exist already or not. Run the following command:
+ :::vim
:autocmd BufNewFile,BufRead *.html setlocal nowrap
This will turn line wrapping off whenever you're working on an HTML file.
@@ -134,6 +141,7 @@
Let's set up a few useful mappings for a variety of file types. Run the
following commands:
+ :::vim
:autocmd FileType javascript nnoremap <buffer> <localleader>c I//
:autocmd FileType python nnoremap <buffer> <localleader>c I#
--- a/chapters/13.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/13.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,10 +8,12 @@
Open your `foo` and `bar` files again, switch to `foo`, and run the following
command:
+ :::vim
:iabbrev <buffer> --- —
While still in `foo` enter insert mode and type the following text:
+ :::text
Hello --- world.
Vim will replace the `---` for you. Now switch to `bar` and try it. It should
@@ -26,6 +28,7 @@
Run the following commands:
+ :::vim
:autocmd FileType javascript :iabbrev <buffer> iff if ( ) {}<left><left><left><left><left>
:autocmd FileType python :iabbrev <buffer> iff if:<left>
--- a/chapters/14.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/14.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -3,6 +3,7 @@
A few chapters ago we learned about autocommands. Run the following command:
+ :::vim
:autocmd BufWrite * :echom "Writing buffer!"
Now write your current buffer with `:write` and run `:messages` to view the
@@ -13,6 +14,7 @@
Now run the exact same autocommand again:
+ :::vim
:autocmd BufWrite * :echom "Writing buffer!"
Write your current buffer one more time and run `:messages`. You will see the
@@ -35,11 +37,13 @@
To simulate this, try running the following command:
+ :::vim
:autocmd BufWrite * :sleep 200m
Now write the file. You may or may not notice a slight sluggishness in Vim's
writing time. Now run the command three more times:
+ :::vim
:autocmd BufWrite * :sleep 200m
:autocmd BufWrite * :sleep 200m
:autocmd BufWrite * :sleep 200m
@@ -60,6 +64,7 @@
Open a fresh instance of Vim to clear out the autocommands from before, then run
the following commands:
+ :::vim
:augroup testgroup
: autocmd BufWrite * :echom "Foo"
: autocmd BufWrite * :echom "Bar"
@@ -71,6 +76,7 @@
Write a buffer and check `:messages`. You should see both "Foo" and "Bar". Now
run the following commands:
+ :::vim
:augroup testgroup
: autocmd BufWrite * :echom "Baz"
:augroup END
@@ -92,6 +98,7 @@
If you want to *clear* a group you can use `autocmd!` inside the group. Run the
following commands:
+ :::vim
:augroup testgroup
: autocmd!
: autocmd BufWrite * :echom "Cats"
@@ -109,6 +116,7 @@
Add the follow to your `~/.vimrc` file:
+ :::vim
augroup filetype_html
autocmd!
autocmd FileType html nnoremap <buffer> <localleader>f Vatzf
--- a/chapters/15.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/15.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -11,6 +11,7 @@
Some examples of operators are `d`, `y`, and `c`. For example:
+ :::text
Operator
vvvvvv
dw " Delete to next word
@@ -22,10 +23,12 @@
Vim lets you create new movements that work with all existing commands. Run the
following command:
+ :::vim
:onoremap p i(
Now type the follow text into a buffer:
+ :::python
return person.get_pets(type="cat", fluffy_only=True)
Put your cursor on the word "cat" and type `dp`. What happened? Vim deleted
@@ -40,6 +43,7 @@
We can use this new mapping immediately with all operators. Type the same text
as before into the buffer (or simply undo the change):
+ :::python
return person.get_pets(type="cat", fluffy_only=True)
Put your cursor on the word "cat" and type `cp`. What happened? Vim deleted
@@ -48,10 +52,12 @@
Let's try another example. Run the following command:
+ :::vim
:onoremap b /return<cr>
Now type the following text into a buffer:
+ :::python
def count(i):
i += 1
print i
@@ -82,11 +88,13 @@
Vim isn't in the habit of limiting what you can do, so of course there's a way
around this problem. Run the following command:
+ :::vim
:onoremap in( :<c-u>normal! f(vi(<cr>
This might look frightening, but let's try it out. Enter the following text
into the buffer:
+ :::python
print foo(bar)
Put your cursor somewhere in the word "print" and type `cin(`. Vim will delete
@@ -99,6 +107,7 @@
Let's make a companion "inside last parenthesis" ("previous" woud be a better
word, but it would shadow the "paragraph" movement). Run the following command:
+ :::vim
:onoremap il( :<c-u>normal! F)vi(<cr>
Try it out on some text of your own to make sure it works.
@@ -107,6 +116,7 @@
can ignore for now -- just know that it needs to be there to make the mappings
work in all cases. If we remove that we're left with:
+ :::vim
:normal! F)vi(<cr>
`:normal!` is something we'll talk about in a later chapter, but for now it's
@@ -118,6 +128,7 @@
So now we know that the mapping is essentially just running the last block of
keys:
+ :::vim
F)vi(
This is fairly simple:
--- a/chapters/16.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/16.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -10,6 +10,7 @@
before, don't worry, for our purposes here it's very simple. Type the following
into a file:
+ :::markdown
Topic One
=========
@@ -26,6 +27,7 @@
Lets create some mappings that let us target headings with movements. Run the
following command:
+ :::vim
:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
This mapping is pretty complicated, so put your cursor in one of the paragraphs
@@ -39,6 +41,7 @@
Now we're looking at the remainder of the line:
+ :::vim
:execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
Normal
@@ -47,10 +50,12 @@
The `:normal` command takes a set of characters and performs whatever action
they would do if they were typed in normal mode. Run this command:
+ :::vim
:normal gg
Vim will move you to the top of the file. Now run this command:
+ :::vim
:normal >>
Vim will indent the current line.
@@ -68,11 +73,13 @@
The `execute` takes a string and performs it as a command. Run this:
+ :::vim
:execute "write"
Vim will write your file, just as if you had typed `:write`. Now run this
command:
+ :::vim
:execute "normal! gg"
Vim will run `:normal! gg`, which as we just saw will move you to the top of the
@@ -81,6 +88,7 @@
Look at the following command and try to guess what it will do:
+ :::vim
:normal! gg/a<cr>
It seems like it should:
@@ -104,6 +112,7 @@
If we perform this replacement in our mapping and look at the result we can see
that the mapping is going to perform:
+ :::text
:normal! ?^==\+$<cr>:nohlsearch<cr>kvg_
^^^^ ^^^^
|| ||
@@ -113,6 +122,7 @@
So now `normal!` will execute these characters as if we had typed them in normal
mode. Let's split them apart at the returns to find out what they're doing:
+ :::vim
?^==\+$
:nohlsearch
kvg_
@@ -152,6 +162,7 @@
Let's look at one more mapping before we move on. Run the following command:
+ :::vim
:onoremap ah :<c-u>execute "normal! ?^==\\+\r:nohlsearch\rg_vk0"<cr>
Try it by putting your cursor in a section's text and typing `cah`. This time
@@ -161,12 +172,14 @@
What's different about this mapping? Let's look at them side by side:
+ :::vim
:onoremap ih :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rkvg_"<cr>
:onoremap ah :<c-u>execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0"<cr>
The only difference from the previous mapping is the very end, where we select
the text to operate on:
+ :::vim
kvg_
g_vk0
--- a/chapters/17.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/17.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -5,11 +5,13 @@
window. This is done through the `statusline` option. Run the following
command:
+ :::vim
:set statusline=%f
You should see the path to the file (relative to the current directory) in the
status line. Now run this command:
+ :::vim
:set statusline=%f\ -\ FileType:\ %y
Now you'll see something like "foo.markdown - FileType: [markdown]" in the
@@ -28,6 +30,7 @@
Status lines can get extremely complicated very quickly, so there's a better way
to set them that will let us be more clear. Run the following commands:
+ :::vim
:set statusline=%f " Path to the file
:set statusline+=\ -\ " Separator
:set statusline+=FileType: " Label
@@ -40,6 +43,7 @@
Run the following command:
+ :::vim
:set statusline=%l " Current line
:set statusline+=/ " Separator
:set statusline+=%L " Total lines
@@ -53,6 +57,7 @@
Additional characters can be used in some of the various `%` codes to change how
the information is displayed. Run the following command:
+ :::vim
:set statusline=%4l
The line number in the status line will now be proceeded by enough spaces to
@@ -62,19 +67,23 @@
By default the padding spaces are added on the left side of the value. Run this
command:
+ :::vim
:set statusline=Current:\ %4l\ Total:\ %4L
Your status line will now look like this:
+ :::text
Current: 12 Total: 223
You can use `-` to place padding on the right instead of the left. Run this
command:
+ :::vim
:set statusline=Current:\ %-4l\ Total:\ %-4L
Your status line will now look like this:
+ :::text
Current: 12 Total: 223
This looks much nicer because the numbers are next to their labels.
@@ -82,6 +91,7 @@
For codes that result in a number you can tell Vim to pad with zeros instead of
spaces. Run the following command:
+ :::vim
:set statusline=%04l
Now your status line will read "0012" when on line twelve.
@@ -89,15 +99,18 @@
Finally, you can also set the maximum width of a code's output. Run this
command:
+ :::vim
:set statusline=%F
`%F` displays the *full* path to the current file. Now run this command to
change the maximum width:
+ :::vim
:set statusline=%.20F
The path will be truncated if necessary, looking something like this:
+ :::text
<hapters/17.markdown
This can be useful for preventing paths and other long codes from taking up the
@@ -108,6 +121,7 @@
The general format for a code in a status line is shown in `:help statusline`:
+ :::text
%-0{minwid}.{maxwid}{item}
Everything except the `%` and the item is optional.
@@ -118,6 +132,7 @@
We'll come back to status lines later in the book, but there's one more simple
code that can be very useful immediately. Run the following commands:
+ :::vim
:set statusline=%f " Path to the file
:set statusline+=%= " Switch to the right side
:set statusline+=%l " Current line
--- a/chapters/18.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/18.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -41,6 +41,7 @@
First we need to set up folding for Vimscript files. Add the following lines to
your `~/.vimrc` file:
+ :::vim
augroup filetype_vim
au!
au FileType vim setlocal foldmethod=marker
@@ -54,6 +55,7 @@
Now lines before and after that autocommand group that look like this:
+ :::vim
" Vimscript file settings ---------------------- {{{
augroup filetype_vim
au!
@@ -83,6 +85,7 @@
Vim allows you to use abbreviated names for most commands and options. For
example, both of these commands do exactly the same thing:
+ :::vim
:setlocal wrap
:setl wrap
--- a/chapters/19.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/19.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -11,12 +11,14 @@
Run the following commands:
+ :::vim
:let foo = "bar"
:echo foo
Vim will display "bar". `foo` is now a variable, and we've assigned it
a string: "bar". Now run these commands:
+ :::vim
:let foo = 42
:echo foo
@@ -30,6 +32,7 @@
You can read and set *options* as variables by using a special syntax. Run the
following commands:
+ :::vim
:set textwidth=80
:echo &textwidth
@@ -39,11 +42,13 @@
Let's see how Vim works with boolean options. Run the following commands:
+ :::vim
:set nowrap
:echo &wrap
Vim displays "0". Now try these commands:
+ :::vim
:set wrap
:echo &wrap
@@ -53,6 +58,7 @@
We can also *set* options as variables. Run the following commands:
+ :::vim
:let &textwidth = 100
:set textwidth?
@@ -61,6 +67,7 @@
Why would we want to do this when we could just use `set`? Run the following
commands:
+ :::vim
:let &textwidth = &textwidth + 10
:set textwidth?
@@ -76,10 +83,12 @@
Open two files in separate splits. Run the following command:
+ :::vim
:let &l:number = 1
Now switch to the other file and run this command:
+ :::vim
:let &l:number = 0
Notice that the first window has line numbers and the second does not.
@@ -89,6 +98,7 @@
You can also read and set *registers* as variables. Run the following command:
+ :::vim
:let @a = "hello!"
Now put your cursor somewhere in your text and type `"ap`. This command tells
@@ -97,12 +107,14 @@
Registers can also be read. Run the following command:
+ :::vim
:echo @a
Vim will echo "hello!".
Select a word in your file and yank it with `y`, then run this command:
+ :::vim
:echo @"
Vim will echo the word you just yanked. The `"` register is the "unnamed"
@@ -110,6 +122,7 @@
Perform a search in your file with `/someword`, then run the following command:
+ :::vim
:echo @/
Vim will echo the search pattern you just used. This lets you programmatically
--- a/chapters/20.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/20.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,12 +8,14 @@
Open two buffers in separate splits, then go into one of then and run the
following commands:
+ :::vim
:let b:hello = "world"
:echo hello
As expected, Vim displays "world". Now switch to the other buffer and run the
echo command again:
+ :::vim
:echo hello
This time Vim throws an error, saying it can't find the variable.
--- a/chapters/21.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/21.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -15,6 +15,7 @@
Sometimes can't fit a piece of Vimscript on a single line of code. We saw this
when we talked about autocommand groups. Here's a chunk of code we used before:
+ :::vim
:augroup testgroup
: autocmd BufWrite * :echom "Baz"
:augroup END
@@ -24,6 +25,7 @@
you can separate each line with a pipe character (`|`). Run the following
command:
+ :::vim
:echom "foo" | echom "bar"
Vim will treat that as two separate commands. Use `:messages` to check the log
@@ -38,6 +40,7 @@
Now that we've got that out of the way, run the following commands:
+ :::vim
:if 1
: echom "ONE"
:endif
@@ -45,6 +48,7 @@
Vim will display "ONE", because the integer `1` is "truthy". Now try this
command:
+ :::vim
:if 0
: echom "ZERO"
:endif
@@ -52,6 +56,7 @@
Vim will *not* display "ZERO" because the integer `0` is "falsy". Let's see how
strings behave. Run this command:
+ :::vim
:if "something"
: echom "INDEED"
:endif
@@ -61,6 +66,7 @@
Let's dive a bit further down the rabbit hole. Run this command:
+ :::vim
:if "9024"
: echom "WHAT?!"
:endif
@@ -69,6 +75,7 @@
To try to wrap our heads around what's going on, run the following two commands:
+ :::vim
:echom "hello" + 10
:echom "10hello" + 10
:echom "hello10" + 10
@@ -93,6 +100,7 @@
Vim, like Python, supports both "else" and "else if" clauses. Run the following
commands:
+ :::vim
:if 0
: echom "if"
:elseif "nope!"
--- a/chapters/22.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/22.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -7,12 +7,14 @@
Run the following command:
+ :::vim
:if 10 > 1
: echom "foo"
:endif
Vim will, of course, display "foo". Now run this command:
+ :::vim
:if 10 > 2001
: echom "bar"
:endif
@@ -20,6 +22,7 @@
Vim displays nothing, because `10` is not greater than `2001`. So far
everything works as expected. Run this command:
+ :::vim
:if 10 == 11
: echom "first"
:elseif 10 == 10
@@ -29,6 +32,7 @@
Vim displays "second". Nothing surprising here. Let's try comparing strings.
Run this command:
+ :::vim
:if "foo" == "bar"
: echom "one"
:elseif "foo" == "foo"
@@ -43,6 +47,7 @@
Run the following commands:
+ :::vim
:set noignorecase
:if "foo" == "FOO"
: echom "vim is case insensitive"
@@ -53,6 +58,7 @@
Vim evaluates the `elseif`, so apparently Vimscript is case sensitive. Good to
know, but nothing earth-shattering. Now run these commands:
+ :::vim
:set ignorecase
:if "foo" == "FOO"
: echom "no, it couldn't be"
@@ -83,6 +89,7 @@
Run the following command:
+ :::vim
:set ignorecase
:if "foo" ==? "FOO"
: echom "first"
@@ -93,6 +100,7 @@
Vim displays "first" because `==?` is the "case-insensitive no matter what the
user has set" comparison operator. Now run the following command:
+ :::vim
:set ignorecase
:if "foo" ==# "FOO"
: echom "one"
--- a/chapters/23.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/23.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -6,6 +6,7 @@
Run the following commands:
+ :::vim
:function meow()
You might think this would start defining a function named `Meow`.
@@ -20,24 +21,28 @@
Okay, let's define a function for real this time. Run the following commands:
+ :::vim
:function Meow()
: echom "Meow!"
:endfunction
This time Vim will happily define the function. Let's try running it:
+ :::vim
:call Meow()
Vim will display "Meow!" as expected.
Let's try returning a value. Run the following commands:
+ :::vim
:function GetMeow()
: return "Meow String!"
:endfunction
Now try it out by running this command:
+ :::vim
:echom GetMeow()
Vim will call the function and give the result to `echom`, which will display
@@ -52,6 +57,7 @@
When you want to call a function directly you use the `call` command. Run the
following commands:
+ :::vim
:call Meow()
:call GetMeow()
@@ -62,6 +68,7 @@
The second way to call functions is in expressions. You don't need to use
`call` in this case, you can just name the function. Run the following command:
+ :::vim
:echom GetMeow()
As we saw before, this calls `GetMeow` and passes the return value to `echom`.
@@ -71,6 +78,7 @@
Run the following command:
+ :::vim
:echom Meow()
This will display two lines: "Meow!" and "0". The first obviously comes from
@@ -78,6 +86,7 @@
doesn't return a value, it implicitly return `0`. Let's use this to our
advantage. Run the following commands:
+ :::vim
:function TextwidthIsTooWide()
: if &l:numberwidth ># 80
: return 1
@@ -100,6 +109,7 @@
Let's try using it. Run the following commands:
+ :::vim
:set textwidth=80
:if TextwidthIsTooWide()
: echom "WARNING: Wide text!"
@@ -114,6 +124,7 @@
Because we never explicitly returned a value, Vim returned `0` from the
function, which is falsy. Let's try changing that. Run the following commands:
+ :::vim
:setlocal textwidth=100
:if TextwidthIsTooWide()
: echom "WARNING: Wide text!"
--- a/chapters/24.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/24.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -3,6 +3,7 @@
Vimscript functions can, of course, take arguments. Run the following commands:
+ :::vim
:function DisplayName(name)
: echom "Hello! My name is:"
: echom a:name
@@ -10,6 +11,7 @@
Run the function:
+ :::vim
:call DisplayName("Your Name")
Vim will display two lines: "Hello! My name is:" and "Your Name".
@@ -21,6 +23,7 @@
Let's remove this scope prefix and see how Vim reacts. Run the following
commands:
+ :::vim
:function UnscopedDisplayName(name)
: echom "Hello! My name is:"
: echom name
@@ -39,6 +42,7 @@
Vimscript functions can optionally take variable-length argument lists like
Javascript and Python. Run the following commands:
+ :::vim
:function Varg(...)
: echom a:0
: echom a:1
@@ -69,6 +73,7 @@
You can use varargs together with regular arguments too. Run the following
commands:
+ :::vim
:function Varg2(foo, ...)
: echom a:foo
: echom a:0
@@ -86,6 +91,7 @@
Try running the following commands:
+ :::vim
:function Assign(foo)
: let a:foo = "Nope"
: echom a:foo
@@ -96,6 +102,7 @@
Vim will throw an error, because you can't reassign argument variables. Now run
these commands:
+ :::vim
:function AssignGood(foo)
: let foo_tmp = a:foo
: let foo_tmp = "Yep"
--- a/chapters/25.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/25.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -12,20 +12,24 @@
You can specify Numbers in a few different ways. Run the following command.
+ :::vim
:echom 100
No surprises here -- Vim displays "100". Now run this command:
+ :::vim
:echom 0xff
This time Vim displays "255". You can specify numbers in hex notation by
prefixing them with `0x` or `0X`. Now run this command:
+ :::vim
:echom 010
You can also use octal by starting a number with a `0`. Be careful with this,
because it's easy to make mistakes. Try the following commands:
+ :::vim
:echom 017
:echom 019
@@ -41,6 +45,7 @@
Floats can also be specified in multiple ways. Run the following command:
+ :::vim
:echo 100.1
Notice that we're using `echo` here and not `echom` like we usually to. We'll
@@ -49,20 +54,24 @@
Vim displays "100.1" as expected. You can also use exponential notation. Run
this command:
+ :::vim
:echo 5.45e+3
Vim displays "5450.0". A negative exponent can also be used. Run this command:
+ :::vim
:echo 15.45e-2
Vim displays "0.1545". The `+` or `-` before the power of ten is optional, if
it's omitted the it's assumed to be positive. Run the following command:
+ :::vim
:echo 15.3e9
Vim will display "1.53e10", which is equivalent. The decimal point and number
after it are *not* optional. Run the following command and see that it crashes:
+ :::vim
:echo 5e10
Coercion
@@ -72,6 +81,7 @@
other operation Vim will cast the Number to a Float, resulting in a Float. Run
the following command:
+ :::vim
:echo 2 * 2.0
Vim displays "4.0".
@@ -81,12 +91,14 @@
When dividing two Numbers, the remainder is dropped. Run the following command:
+ :::vim
:echo 3 / 2
Vim displays "1". If you want Vim to perform float point division one of the
numbers needs to be a Float, which will cause the other one to be coerced to
a Float as well. Run this command:
+ :::vim
:echo 3 / 2.0
Vim displays "1.5". The "3" is coerced to a Float, and then normal floating
--- a/chapters/26.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/26.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -6,6 +6,7 @@
Run the following command:
+ :::vim
:echom "Hello"
Vim will echo "Hello". So far, so good.
@@ -16,6 +17,7 @@
One of the most common things you'll want to do with strings is adding them
together. Run this command:
+ :::vim
:echom "Hello, " + "world"
What happened? Vim displayed "0" for some reason!
@@ -24,6 +26,7 @@
a string to `+` Vim will try to coerce it to a Number before performing the
addition. Run the following command:
+ :::vim
:echom "3 mice" + "2 cats"
This time Vim displays "5", because the strings are coerced to the numbers "3"
@@ -32,6 +35,7 @@
When I said "Number" I really *meant* Number. Vim will *not* coerce strings to
Floats! Try this command to see prove this:
+ :::vim
:echom 10 + "10.10"
Vim displays "20" because it dropped everything after the decimal point when
@@ -40,6 +44,7 @@
To combine strings you need to use the concatenation operator. Run the
following command:
+ :::vim
:echom "Hello, " . "world"
This time Vim displays "Hello, world". `.` is the "concatenate strings"
@@ -48,12 +53,14 @@
Coercion works both ways. Kind of. Try this command:
+ :::vim
:echom 10 . "foo"
Vim will display "10foo". First it coerces `10` to a String, then it
concatenates it with the string on the right hand side. Things get a bit
stickier when we're working with Floats, though. Run this command:
+ :::vim
:echom 10.1 . "foo"
This time Vim throws an error, saying we're using a Float as a String. Vim will
@@ -75,23 +82,27 @@
Like most programming languages, Vimscript lets you use escape sequences in
strings to represent hard-to-type characters. Run the following command:
+ :::vim
:echom "foo \"bar\""
The `\"` in the string is replaced with a double quote character, as you would
probably expect. Escape sequences work mostly as you would expect. Run the
following command:
+ :::vim
:echom "foo\\bar"
Vim displays `foo\bar`, because `\\` is the escape sequence for a literal
backslash, just like in most programming languages. Now run the following
command (note that it's an `echo` and *not* an `echom`):
+ :::vim
:echo "foo\nbar"
This time Vim will display two lines, "foo" and "bar", because the `\n` is
replaced with a newline. Now try running this command:
+ :::vim
:echom "foo\nbar"
Vim will display something like "foo^@bar". When you use `echom` with a String
@@ -105,12 +116,14 @@
Vim also lets you use "literal strings" to avoid excessive use of escape
sequences. Run the following command:
+ :::vim
:echom '\n\\'
Vim displays `\n\\`. Using single quotes tells Vim that you want the string
*exactly* as-in, with no escape sequences. The one exception is that two single
quotes in a row will produce a single single quote. Try this command:
+ :::vim
:echom 'That''s enough.'
Vim will display "That's enough." Two single quotes is the *only* sequence that
@@ -125,6 +138,7 @@
You might be wondering how Vim treats strings when used in an `if` statement.
Run the following command:
+ :::vim
:if "foo"
: echo "yes"
:else
--- a/chapters/27.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/27.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -9,11 +9,13 @@
The first function we'll look at is `strlen`. Run the following command:
+ :::vim
:echom strlen("foo")
Vim displays "3", which is the length of the string "foo". Now try the
following command:
+ :::vim
:echom len("foo")
Vim once again displays "3". When used with Strings `len` and `strlen` have
@@ -24,6 +26,7 @@
Run the following command (note that it's an `echo` and not an `echom`):
+ :::vim
:echo split("one two three")
Vim displays "['one', 'two', 'three']". The `split` function splits a String
@@ -33,6 +36,7 @@
You can also tell Vim to use a separator other than "whitespace" for splitting.
Run the following command:
+ :::vim
:echo split("one,two,three", ",")
Vim will once again display "['one', 'two', 'three']", because the second
@@ -45,12 +49,14 @@
Not only can you split strings, you can also join them. Run the following
command:
+ :::vim
:echo join(["foo", "bar"], "...")
Vim will display "foo...bar". Don't worry about the list syntax for now.
`split` and `join` can be paired to great effect. Run the following command:
+ :::vim
:echo join(split("foo bar"), ";")
Vim displays "foo;bar". First we split the string "foo bar" into a list, then
@@ -62,6 +68,7 @@
Vim has two functions to change the case of Strings. Run the following
commands:
+ :::vim
:echom tolower("Foo")
:echom toupper("Foo")
--- a/chapters/28.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/28.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -4,6 +4,7 @@
The `execute` command is used to evaluate a string as if it were a Vimscript
command. Run the following command:
+ :::vim
:execute "echom 'Hello, world!'"
Vim evaluates `echom 'Hello, world!'` as a command and dutifully echoes it to
@@ -14,6 +15,7 @@
`:edit "foo.txt"` in the same window to open a new buffer. Now run the
following command:
+ :::vim
:execute "rightbelow vsplit " . bufname("#")
Vim will open the first file in a vertical split to the right of the second
--- a/chapters/29.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/29.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -7,11 +7,13 @@
The answer is: "of course". Run the following command:
+ :::vim
:normal G
Vim will move your cursor to the last line in the current file, just like
pressing `G` in normal mode would. Now run the following command:
+ :::vim
:normal ggdd
Vim will move to the first line in the file (`gg`) and then delete it (`dd`).
@@ -24,10 +26,12 @@
Run the following command to map the `G` key to something else:
+ :::vim
:nnoremap G dd
Now pressing `G` in normal mode will delete a line. Try this command:
+ :::vim
:normal G
Vim will delete the current line. The `normal` command will take into account
@@ -39,6 +43,7 @@
Luckily Vim has a `normal!` command that does exactly this. Run this command:
+ :::vim
:normal! G
This time Vim moves to the bottom of the file even though `G` has been mapped.
@@ -53,6 +58,7 @@
If you play around with `normal!` long enough you'll probably notice a problem.
Try the following command:
+ :::vim
:normal! /foo<cr>
At first glance it may seem like this should perform a search for "foo", but
--- a/chapters/30.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/30.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -4,6 +4,7 @@
Now that we've seen `execute` and `normal!` we can talk about a common Vimscript
idiom. Run the following command:
+ :::vim
:execute "normal! gg/foo\<cr>dd"
This will move to the top of the file, search for the first occurrence of "foo",
@@ -17,6 +18,7 @@
string escape sequences to generate the non-printing characters you need. Try
the following command:
+ :::vim
:execute "normal! mqA;\<esc>`q"
What does this do? Let's break it apart:
--- a/chapters/31.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/31.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -7,6 +7,7 @@
Type the following text into a buffer:
+ :::python
max = 10
print "Starting"
@@ -30,6 +31,7 @@
Before we start we need to turn on search highlighting so we can see what we're
doing. Run the following command:
+ :::vim
:set hlsearch incsearch
`hlsearch` tells Vim to highlight all matches in a file when you perform
@@ -41,6 +43,7 @@
Put your cursor at the top of the file and run the following command:
+ :::vim
/print
As you type in each letter, Vim will start highlighting them in the first line.
@@ -49,6 +52,7 @@
Now try running the following command:
+ :::vim
:execute "normal! gg/print\<cr>"
This will go to the top of the file and perform a search for "print", putting us
@@ -58,6 +62,7 @@
To get to the second match in the file you can just add more commands onto the
end of the string. Run this command:
+ :::vim
:execute "normal! gg/print\<cr>n"
Vim will put the cursor on the second "print" in the buffer (and all the matches
@@ -65,6 +70,7 @@
Let's try going in the opposite direction. Run this command:
+ :::vim
:execute "normal! G?print\<cr>"
This time we move to the bottom of the file with `G` and use `?` to search
@@ -80,11 +86,13 @@
The `/` and `?` commands actually take regular expressions, not just literal
characters. Run the following command:
+ :::vim
:execute "normal! gg/for .+ in .+:\<cr>"
Vim complains that the pattern is not found! I told you that Vim supports
regular expressions in searches, so what's going on? Try the following command:
+ :::vim
:execute "normal! gg/for .\\+ in .\\+:\<cr>"
This time Vim highlights the "for" loop as we expected in the first place. Take
@@ -103,6 +111,7 @@
You can see this a bit easier by just running the search in Vim directly. Type
the following command and press return:
+ :::vim
/print .\+
You can see the `\+` working its magic now. The double backslashes were only
@@ -122,6 +131,7 @@
Try running the following command (note the single quotes and single backslashes
this time):
+ :::vim
:execute 'normal! gg/for .\+ in .\+:\<cr>'
Vim moves you to the top of the file but doesn't move you to the first match.
@@ -136,6 +146,7 @@
strings, so for larger commands we can use this to split apart the string into
easier to read chunks. Run the following command:
+ :::vim
:execute "normal! gg" . '/for .\+ in .\+:' . "\<cr>"
This concatenates the three smaller strings before sending them to `execute`,
@@ -152,6 +163,7 @@
Run the following command:
+ :::vim
:execute "normal! gg" . '/\vfor .+ in .+:' . "\<cr>"
We've split the pattern out from the rest of the command into its own literal
--- a/chapters/32.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/32.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -68,6 +68,7 @@
We'll start with a skeleton of the mapping and fill it in as we go. Run this
command:
+ :::vim
:nnoremap <leader> g :grep -R something .<cr>
If you've read `:help grep` this should be pretty easy to understand. We've
@@ -82,6 +83,7 @@
First we need to search for the word under the cursor, not the string
"something". Run the following command:
+ :::vim
:nnoremap <leader>g :grep -R <cword> .<cr>
Now try it out. `<cword>` is a special bit of text you can use in Vim's
@@ -90,6 +92,7 @@
You can use `<cWORD>` to get a WORD instead of a word. Run this command:
+ :::vim
:nnoremap <leader>g :grep -R <cWORD> .<cr>
Now try the mapping when your cursor is over something like "foo-bar". Vim will
@@ -106,6 +109,7 @@
To try to fix this we'll quote the argument in the grep call. Run this command:
+ :::vim
:nnoremap <leader>g :grep -R '<cWORD>' .<cr>
Most shells treat single-quoted text as (almost) literal, so our mapping is much
@@ -120,11 +124,13 @@
the command with `execute`. First run the following command to transform the
`:grep` mapping into `:execute "..."` form:
+ :::vim
:nnoremap <leader>g :execute "grep -R '<cWORD>' ."<cr>
Try it out and make sure it still works. If not, find any typos and fix them.
Then run the following command, which uses `shellescape` to fix the search term:
+ :::vim
:nnoremap <leader>g :execute "grep -R " . shellescape("<cWORD>") . " ."<cr>
And now our mapping won't break if the word we're searching for happens to
@@ -142,12 +148,14 @@
automatically, and we can use `grep!` instead of plain `grep` to do that. Run
this command:
+ :::vim
:nnoremap <leader>g :execute "grep! -R " . shellescape("<cWORD>") . " ."<cr>
Try it out again and nothing will seem to happen. Vim has filled the quickfix
window with the results, but we haven't opened it yet. Run the following
command:
+ :::vim
:nnoremap <leader>g :execute "grep! -R " . shellescape("<cWORD>") . " ."<cr>:copen<cr>
Now try the mapping and you'll see that Vim automatically opens the quickfix
@@ -157,6 +165,7 @@
As the finishing touch we'll remove all the grep output Vim displays while
searching. Run the following command:
+ :::vim
:nnoremap <leader>g :silent execute "grep! -R " . shellescape("<cWORD>") . " ."<cr>:copen<cr>
We're done, so try it out and admire your hard work! The `silent` command just
--- a/chapters/33.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/33.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -39,6 +39,7 @@
To create a new Vim operator you'll start with two components: a function and
a mapping. Start by adding the following code to `grep-operator.vim`:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
function! GrepOperator(type)
@@ -63,6 +64,7 @@
We've added the operator to normal mode, but we'll want to be able to use it
from visual mode as well. Add another mapping below the first:
+ :::vim
vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>
Write and source the file. Now visually select something and press `<leader>g`.
@@ -94,6 +96,7 @@
Edit the function body so the file looks like this:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>
@@ -122,6 +125,7 @@
to search for, and the easiest way to do that is to simply copy it. Edit the
function to look like this:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
@@ -184,6 +188,7 @@
Now that we've got the text we need in a Vim string we can escape it like we did
in the previous chapter. Modify the `echom` command so it looks like this:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
@@ -209,6 +214,7 @@
We're finally ready to add the `grep!` command that will perform the actual
search. Replace the `echom` line so the code looks like this:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
--- a/chapters/34.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/34.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -16,6 +16,7 @@
before we yank and restore it after we've done. Change the code to look like
this:
+ :::vim
nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
@@ -57,6 +58,7 @@
We can avoid polluting the global namespace by tweaking a couple of lines in our
code. Edit the file to look like this:
+ :::vim
nnoremap <leader>g :set operatorfunc=<SID>GrepOperator<cr>g@
vnoremap <leader>g :<C-U>call <SID>GrepOperator(visualmode())<cr>
--- a/chapters/35.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/35.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,11 +8,13 @@
Vimscript lists are ordered, heterogeneous collections of elements. Run the
following command:
+ :::vim
:echo ['foo', 3, 'bar']
Vim displays the list. Lists can of course be nested. Run the following
command:
+ :::vim
:echo ['foo', [3, 'bar']]
Vim happily displays the list.
@@ -23,11 +25,13 @@
Vimscript lists are zero-indexed, and you can get at the elements in the usual
way. Run this command:
+ :::vim
:echo [0, [1, 2]][1]
Vim displays "[1, 2]". You can also index from the end of the list, much like
Python. Try this command:
+ :::vim
:echo [0, [1, 2]][-2]
Vim displays `0`. The index `-1` refers to the last element in the list, `-2`
@@ -39,17 +43,20 @@
Vim lists can also be sliced. This will *look* familiar to Python programmers,
but it does *not* always act the same way! Run this command:
+ :::vim
:echo ['a', 'b', 'c', 'd', 'e'][0:2]
Vim displays "['a', 'b', 'c']" (elements 0, 1 and 2). You can safely exceed the
upper bound as well. Try this command:
+ :::vim
:echo ['a', 'b', 'c', 'd', 'e'][0:100000]
Vim simply displays the entire list.
Slice indexes can be negative. Try this command:
+ :::vim
:echo ['a', 'b', 'c', 'd', 'e'][-2:-1]
Vim displays "['d', 'e']" (elements -2 and -1).
@@ -57,6 +64,7 @@
When slicing lists you can leave off the first index to mean "the beginning"
and/or the last index to mean "the end". Run the following commands:
+ :::vim
:echo ['a', 'b', 'c', 'd', 'e'][:1]
:echo ['a', 'b', 'c', 'd', 'e'][3:]
@@ -65,6 +73,7 @@
Like Python, Vimscript allows you to index and slice strings too. Run the
following command:
+ :::vim
:echo "abcd"[0:2]
Vim displays "abc".
@@ -74,7 +83,8 @@
You can combine Vim lists with `+`. Try this command:
- echo ['a', 'b'] + ['c']
+ :::vim
+ :echo ['a', 'b'] + ['c']
Vim, unsurprisingly, displays "['a', 'b', 'c']". There's not much else to say
here -- Vimscript lists are surprisingly sane compared to the rest of the
@@ -86,6 +96,7 @@
Vim has a number of built-in functions for working with lists. Run these
commands:
+ :::vim
:let foo = ['a']
:call add(foo, 'b')
:echo foo
@@ -93,10 +104,12 @@
Vim mutates the list `foo` in-place to append `'b'` and displays "['a', 'b']".
Now run this command:
+ :::vim
:echo len(foo)
Vim displays "2", the length of the list. Try these commands:
+ :::vim
:echo get(foo, 0, 'default')
:echo get(foo, 100, 'default')
@@ -106,6 +119,7 @@
Run this command:
+ :::vim
:echo index(foo, 'b')
:echo index(foo, 'nope')
@@ -114,6 +128,7 @@
Now run this command:
+ :::vim
:echo join(foo)
:echo join(foo, '---')
:echo join([1, 2, 3], '')
@@ -124,6 +139,7 @@
Run the following commands:
+ :::vim
:call reverse(foo)
:echo foo
:call reverse(foo)
--- a/chapters/36.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/36.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -16,6 +16,7 @@
Java, C or Javascript `for` loops, but turns out to be quite elegant. Run the
following commands:
+ :::vim
:let c = 0
:for i in [1, 2, 3, 4]
@@ -36,6 +37,7 @@
Vim also supports the classic `while` loop. Run the following commands:
+ :::vim
:let c = 1
:let total = 0
--- a/chapters/37.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/37.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -11,6 +11,7 @@
Run this command:
+ :::vim
:echo {'a': 1, 100: 'foo'}
Vim displays `{'a': 1, '100': 'foo'}`, which shows that Vimscript does indeed
@@ -19,6 +20,7 @@
Vimscript avoids the stupidity of the Javascript standard and lets you use
a comma after the last element in a dictionary. Run the following command:
+ :::vim
:echo {'a': 1, 100: 'foo',}
Once again Vim displays `{'a': 1, '100': 'foo'}`. You should *always* use the
@@ -31,10 +33,12 @@
To look up a key in a dictionary you use the same syntax as most languages. Run
this command:
+ :::vim
:echo {'a': 1, 100: 'foo',}['a']
Vim displays `1`. Try it with a non-string index:
+ :::vim
:echo {'a': 1, 100: 'foo',}[100]
Vim coerces the index to a string before performing the lookup, which makes
@@ -44,6 +48,7 @@
a string consisting only of letters, digits and/or underscores. Try the
following commands:
+ :::vim
:echo {'a': 1, 100: 'foo',}.a
:echo {'a': 1, 100: 'foo',}.100
@@ -56,6 +61,7 @@
Adding entries to dictionaries is done by simply assigning them like variables.
Run this command:
+ :::vim
:let foo = {'a': 1}
:let foo.a = 100
:let foo.b = 200
@@ -70,6 +76,7 @@
There are two ways to remove entries from a dictionary. Run the following
commands:
+ :::vim
:let test = remove(foo, 'a')
:unlet foo.b
:echo foo
@@ -82,6 +89,7 @@
You cannot remove nonexistent entries from a dictionary. Try running this
command:
+ :::vim
:unlet foo["asdf"]
Vim throws an error.
@@ -97,6 +105,7 @@
Like lists, Vim has a number of built-in functions for working with
dictionaries. Run the following command:
+ :::vim
:echom get({'a': 100}, 'a', 'default')
:echom get({'a': 100}, 'b', 'default')
@@ -105,6 +114,7 @@
You can also check if a given key is present in a given dictionary. Run this
commands:
+ :::vim
:echom has_key({'a': 100}, 'a')
:echom has_key({'a': 100}, 'b')
@@ -114,6 +124,7 @@
You can pull the key-value pairs out of a dictionary with `items`. Run this
command:
+ :::vim
:echo items({'a': 100, 'b': 200})
Vim will display a nested list that looks something like `[['a', 100], ['b',
--- a/chapters/38.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/38.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -7,6 +7,7 @@
Run the following command:
+ :::vim
:nnoremap <leader>N :setlocal number!<cr>
Try it out by pressing `<leader>N` in normal mode. Vim will toggle the line
@@ -24,6 +25,7 @@
a mapping that will call it. Put the following into your `~/.vimrc` file (or
a separate file in `~/.vim/plugin/` if you prefer):
+ :::vim
nnoremap <c-f> :call FoldColumnToggle()<cr>
function! FoldColumnToggle()
@@ -37,6 +39,7 @@
Let's add in the actual toggling functionality. Edit the code to look like
this:
+ :::vim
nnoremap <c-f> :call FoldColumnToggle()<cr>
function! FoldColumnToggle()
@@ -64,6 +67,7 @@
thing to have a mapping for is the quickfix window. Let's start with the same
skeleton as before. Add the following code to your file:
+ :::vim
nnoremap <c-q> :call QuickfixToggle()<cr>
function! QuickfixToggle()
@@ -74,6 +78,7 @@
slightly more useful (but not completely finished yet). Change the code to
look like this:
+ :::vim
nnoremap <c-q> :call QuickfixToggle()<cr>
function! QuickfixToggle()
@@ -86,6 +91,7 @@
To get the "toggling" behavior we're looking for we'll use a quick, dirty
solution: a global variable. Change the code to look like this:
+ :::vim
nnoremap <c-q> :call QuickfixToggle()<cr>
function! QuickfixToggle()
@@ -105,6 +111,7 @@
Write and source the file, and try to run the mapping. Vim will complain that
the variable is not defined yet! Let's fix that by initializing it once:
+ :::vim
nnoremap <c-q> :call QuickfixToggle()<cr>
let g:quickfix_is_open = 0
@@ -152,6 +159,7 @@
To solve this we'll introduce an idiom that comes in handy a lot when writing
Vim plugins. Edit your code to look like this:
+ :::vim
nnoremap <c-q> :call QuickfixToggle()<cr>
let g:quickfix_is_open = 0
--- a/chapters/39.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/39.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -29,6 +29,7 @@
Add the following function to your file:
+ :::vim
function! Sorted(l)
let new_list = deepcopy(a:l)
call sort(new_list)
@@ -46,6 +47,7 @@
This prevents side effects and helps us write code that is easier to reason
about and test. Let's add a few more helper functions in this same style:
+ :::vim
function! Reversed(l)
let new_list = deepcopy(a:l)
call reverse(new_list)
@@ -89,6 +91,7 @@
Vimscript supports using variables to store functions, but the syntax is a bit
obtuse. Run the following commands:
+ :::vim
:let Myfunc = function("Append")
:echo Myfunc([1, 2], 3)
@@ -99,6 +102,7 @@
Functions can be stored in lists just like any other kind of variable. Run the
following commands:
+ :::vim
:let funcs = [function("Append"), function("Pop")]
:echo funcs[1](['a', 'b', 'c'], 1)
@@ -115,6 +119,7 @@
We'll begin with the trusty "map" function. Add this to your file:
+ :::vim
function! Mapped(fn, l)
let new_list = deepcopy(a:l)
call map(new_list, string(a:fn) . '(v:val)')
@@ -123,6 +128,7 @@
Source and write the file, and try it out by running the following commands:
+ :::vim
:let mylist = [[1, 2], [3, 4]]
:echo Mapped(function("Reversed"), mylist)
@@ -140,6 +146,7 @@
Now we'll create a few other common higher-order functions. Add the following to
your file:
+ :::vim
function! Filtered(fn, l)
let new_list = deepcopy(a:l)
call filter(new_list, string(a:fn) . '(v:val)')
@@ -148,6 +155,7 @@
Try `Filtered()` out with the following commands:
+ :::vim
:let mylist = [[1, 2], [], ['foo'], []]
:echo Filtered(function('len'), mylist)
@@ -160,6 +168,7 @@
Finally we'll create the counterpart to `Filtered()`:
+ :::vim
function! Removed(fn, l)
let new_list = deepcopy(a:l)
call filter(new_list, '!' . string(a:fn) . '(v:val)')
@@ -168,6 +177,7 @@
Try it out just like we did with `Filtered()`:
+ :::vim
:let mylist = [[1, 2], [], ['foo'], []]
:echo Removed(function('len'), mylist)
--- a/chapters/40.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/40.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -12,6 +12,7 @@
Sometimes it's handy to be able to get the absolute path of a certain file for
use with external scripts. Run the following commands:
+ :::vim
:echom expand('%')
:echom expand('%:p')
:echom fnamemodify('foo.txt', ':p')
@@ -35,12 +36,14 @@
You might also want to get a listing of files in a specific directory. Run the
following command:
+ :::vim
:echo globpath('.', '*')
Vim will display all of the files and directories in the current directory. The
`globpath()` function returns a string, with each name separated by a newline.
To get a list you'll need to `split()` it yourself. Run this command:
+ :::vim
:echo split(globpath('.', '*'), '\n')
This time Vim displays a Vimscript list containing each path. If you've got
@@ -49,12 +52,14 @@
`globpath()`'s wildcards work mostly as you would expect. Run the following
command:
+ :::vim
:echo split(globpath('.', '*.txt'), '\n')
Vim displays a list of all `.txt` files in the current directory.
You can recursively list files with `**`. Run this command:
+ :::vim
:echo split(globpath('.', '**'), '\n')
Vim will list all files and directories under the current directory.
--- a/chapters/43.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/43.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -41,16 +41,19 @@
called `mycolor.vim` (you can leave it empty for this demonstration). Open Vim
and run this command:
+ :::vim
:color mycolor
Vim will display an error, because it doesn't know to look on your Desktop for
files. Now run this command:
+ :::vim
:set runtimepath=/Users/sjl/Desktop
You'll need to change the path to match the path of your own Desktop, of course.
Now try the color command again:
+ :::vim
:color mycolor
This time Vim doesn't throw an error, because it was able to find the
@@ -85,6 +88,7 @@
Our plugin's repository will wind up looking like this:
+ :::text
potion/
README
LICENSE
@@ -115,5 +119,3 @@
Push the repository up to Bitbucket or GitHub.
Read `:help runtimepath`.
-
-
--- a/chapters/44.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/44.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -5,6 +5,7 @@
plugin. Create a `factorial.pn` file somewhere and put the following Potion
code inside it:
+ :::text
factorial = (n):
total = 1
n to 1 (i):
@@ -21,6 +22,7 @@
the results each time. Go ahead and run it with `potion factorial.pn`. The
output should look like this:
+ :::text
0! is: 0
1! is: 1
2! is: 2
@@ -44,6 +46,7 @@
Open `factorial.pn` in Vim and run the following command:
+ :::vim
:set filetype?
Vim will display `filetype=` because it doesn't know what a `.pn` file is yet.
@@ -52,6 +55,7 @@
Create `ftdetect/potion.vim` in your plugin's repo. Put the following lines
into it:
+ :::vim
au BufNewFile,BufRead *.pn set filetype=potion
This creates a single autocommand: a command to set the filetype of `.pn` files
@@ -64,6 +68,7 @@
Close the `factorial.pn` file and reopen it. Now run the previous command
again:
+ :::vim
:set filetype?
This time Vim displays `filetype=potion`. When Vim started up it loaded the
--- a/chapters/45.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/45.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -8,6 +8,7 @@
Create a `syntax/potion.vim` file in your plugin's repo. Put the following code
into the file:
+ :::vim
if exists("b:current_syntax")
finish
endif
@@ -36,6 +37,7 @@
Replace the placeholder `echom` in the file with the following code:
+ :::vim
syntax keyword potionKeyword to times
highlight link potionKeyword Keyword
@@ -59,6 +61,7 @@
Potion has a bunch of other keywords that we haven't used in our toy program, so
lets edit our syntax file to highlight those too:
+ :::vim
syntax keyword potionKeyword loop times to while
syntax keyword potionKeyword if elsif else
syntax keyword potionKeyword class return
@@ -89,6 +92,7 @@
built-in Potion functions to our highlighting script. Edit the guts of your
syntax file so it looks like this:
+ :::vim
syntax keyword potionKeyword loop times to while
syntax keyword potionKeyword if elsif else
syntax keyword potionKeyword class return
--- a/chapters/46.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/46.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -27,6 +27,7 @@
match it (and the rest of the comment). We'll do this with `syntax match`
instead of `syntax keyword`. Add the following lines to your syntax file:
+ :::vim
syntax match potionComment "\v#.*$"
highlight link potionComment Comment
@@ -64,6 +65,7 @@
Another part of Potion we need regexes to highlight is operators. Add the
following to your syntax file:
+ :::vim
syntax match potionOperator "\v\*\="
syntax match potionOperator "\v/\="
syntax match potionOperator "\v\+\="
@@ -114,6 +116,7 @@
Let's go ahead and add `=` as an operator, now that we've had our lesson:
+ :::vim
syntax match potionOperator "\v\="
Take a second and think about where you need to put this in the syntax file.
--- a/chapters/47.markdown Wed Nov 16 20:50:32 2011 -0500
+++ b/chapters/47.markdown Wed Dec 07 20:16:52 2011 -0500
@@ -14,6 +14,7 @@
world!"`. We should highlight these as strings. To do this we'll use the
`syntax region` command. Add the following to your Potion syntax file:
+ :::vim
syntax region potionString start=/\v"/ skip=/\v\\./ end=/\v"/
highlight link potionString String