ce3080899ffb

Merge.
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Sat, 31 Dec 2011 17:24:53 -0500
parents 8d53ee8e7454 (diff) 067e066fd290 (current diff)
children d64120a6e4a2
branches/tags (none)
files chapters/07.markdown

Changes

--- a/chapters/01.markdown	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/01.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/02.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/03.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/04.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/05.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/06.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/07.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/08.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/09.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/10.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/11.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/12.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/13.markdown	Sat Dec 31 17:24:53 2011 -0500
@@ -8,10 +8,12 @@
 Open your `foo` and `bar` files again, switch to `foo`, and run the following
 command:
 
+    :::vim
     :iabbrev <buffer> --- &mdash;
 
 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/14.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/15.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/16.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/17.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/18.markdown	Sat Dec 31 17:24:53 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
@@ -52,8 +53,9 @@
 FileType for this file and the autocommand only fires when that happens.  In the
 future you won't need to do it manually.
 
-Now lines before and after that autocommand group that look like this:
+Now add lines before and after that autocommand group so that it looks 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/19.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/20.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/21.markdown	Sat Dec 31 17:24:53 2011 -0500
@@ -12,9 +12,10 @@
 Multiple-Line Statements
 ------------------------
 
-Sometimes can't fit a piece of Vimscript on a single line of code.  We saw this
+Sometimes you 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/22.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/23.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/24.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/25.markdown	Sat Dec 31 17:24:53 2011 -0500
@@ -12,25 +12,29 @@
 
 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
 
-Vim will print "15" for the first command, because "18" in octal is equal to
-"18" in decimal.  For the second command Vim treats it as a decimal number, even
+Vim will print "15" for the first command, because "17" in octal is equal to
+"15" in decimal.  For the second command Vim treats it as a decimal number, even
 though it starts with a `0`, because it's not a valid octal number.
 
 Because Vim silently does the wrong thing in this case, I'd recommend avoiding
@@ -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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/26.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/27.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/28.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/29.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/30.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/31.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/32.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/33.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/34.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/35.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/36.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/37.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/38.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/39.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/40.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/43.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/44.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/45.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/46.markdown	Sat Dec 31 17:24:53 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	Fri Nov 18 14:20:33 2011 -0800
+++ b/chapters/47.markdown	Sat Dec 31 17:24:53 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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/48.markdown	Sat Dec 31 17:24:53 2011 -0500
@@ -0,0 +1,147 @@
+Basic Folding
+=============
+
+If you've never used code folding in Vim, you don't know what you're missing.
+Read `:help usr_28` and spend some time playing around with it in your normal
+work.  Come back to this chapter once you've got it in your fingers.
+
+Types of Folding
+----------------
+
+Vim supports six different ways of defining how your text should be folded.
+
+### Manual
+
+You create the folds by hand and they're stored in RAM by Vim.  When you close
+Vim they go away and you have to recreate them the next time you edit the file.
+
+This method can be handy if you combine it with some custom mappings to make it
+easy to create folds.  We won't do that in this book, but keep it in the back
+of your mind in case you run across a case where it could be handy.
+
+### Marker
+
+Vim folds your code based on characters in the actual text.
+
+Usually these characters are put in comments (like `// {{{`), but in some
+languages you can get away with using something in the language's syntax itself,
+like `{` and `}` in Javascript files.
+
+It may seem ugly to clutter up your code with comments that are purely for your
+text editor, but the advantage is that it lets you hand-craft folds for
+a specific file.  This can be really nice if you're working with a large file
+that you want to organize in a very specific way.
+
+### Diff
+
+A special folding mode used when diff'ing files.  We won't talk about this one
+at all because Vim automatically handles it.
+
+### Expr
+
+This lets you use a custom piece of Vimscript to define where folds occur.  It's
+the most powerful method, but also requires the most work.  We'll talk about
+this in the next chapter.
+
+### Indent
+
+Vim uses your code's indentation to determine folds.  Lines at the same
+indentation level fold together, and lines with only whitespace (and blank
+lines) are simply folded with their neighbors.
+
+This is essentially free to use because your code is already indented; all you
+have to do is turn it on.  This will be our first method of adding folding to
+Potion files.
+
+Potion Folding
+--------------
+
+Let's take a look at our sample Potion file once again:
+
+    :::text
+    factorial = (n):
+        total = 1
+        n to 1 (i):
+            total *= i.
+        total.
+
+    10 times (i):
+        i string print
+        '! is: ' print
+        factorial (i) string print
+        "\n" print.
+
+The bodies of the function and loop are both indented.  This means we can get
+some basic folding with very little effort by using indent folding.
+
+Before we start, go ahead and add a comment above the `total *= i.` line so we
+have a nice multiple-line inner block to test with.  You'll learn why we need to
+do this when you do the exercises, but for now just trust me.  The file should
+now look like this:
+
+    :::text
+    factorial = (n):
+        total = 1
+        n to 1 (i):
+            # Multiply the running total.
+            total *= i.
+        total.
+
+    10 times (i):
+        i string print
+        '! is: ' print
+        factorial (i) string print
+        "\n" print.
+
+Create an `ftplugin` folder in your Potion plugin's repository, and create
+a `potion` folder inside that.  Finally, create a `folding.vim` file inside of
+*that*.
+
+Remember that Vim will run the code in this file whenever it sets a buffer's
+`filetype` to `potion` (because it's in a folder named `potion`).
+
+Putting all folding-related code into its own file is generally a good idea and
+will help us keep the various functionality of our plugin organized.
+
+Add the following line to this file:
+
+    :::vim
+    setlocal foldmethod=indent
+
+Close Vim and open the `factorial.pn` file again.  Play around with the new
+folding with `zR`, `zM`, and `za`.
+
+One line of Vimscript gave us some useful folding!  That's pretty cool!
+
+You might notice that the lines inside the inner loop of the `factorial`
+function aren't folded even though they're indented.  What's going on?
+
+It turns out that by default Vim will ignore lines beginning with a `#`
+character when using `indent` folding.  This works great when editing C files
+(where `#` signals a preprocessor directive) but isn't very helpful when you're
+editing other types of files.
+
+Let's add one more line to the `ftplugin/potion/folding.vim` file to fix this:
+
+    :::vim
+    setlocal foldmethod=indent
+    setlocal foldignore=
+
+Close and reopen `factorial.pn` and now the inner block will be folded properly.
+
+Exercises
+---------
+
+Read `:help foldmethod`.
+
+Read `:help fold-manual`.
+
+Read `:help fold-marker` and `:help foldmarker`.
+
+Read `:help fold-indent`.
+
+Read `:help fdl` and `:help foldlevelstart`.
+
+Read `:help foldminlines`.
+
+Read `:help foldignore`.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/49.markdown	Sat Dec 31 17:24:53 2011 -0500
@@ -0,0 +1,761 @@
+Advanced Folding
+================
+
+In the last chapter we used Vim's `indent` folding to add some quick and dirty
+folding to Potion files.
+
+Open `factorial.pn` and make sure all the folds are closed with `zM`.  The file
+should now look something like this:
+
+    :::text
+    factorial = (n):
+    +--  5 lines: total = 1
+
+    10 times (i):
+    +--  4 lines: i string print
+
+Toggle the first fold and it will look like this:
+
+    :::text
+    factorial = (n):
+        total = 1
+        n to 1 (i):
+    +---  2 lines: # Multiply the running total.
+        total.
+
+    10 times (i):
+    +--  4 lines: i string print
+
+This is pretty nice, but I personally prefer to fold the first line of a block
+with its contents.  In this chapter we'll write some custom folding code, and
+when we're done our folds will look like this:
+
+    :::text
+    factorial = (n):
+        total = 1
+    +---  3 lines: n to 1 (i):
+        total.
+
+    +--  5 lines: 10 times (i):
+
+This is more compact and (to me) easier to read.  If you prefer the `indent`
+method that's okay, but do this chapter anyway just to get some practice writing
+Vim folding expressions.
+
+Folding Theory
+--------------
+
+When writing custom folding code it helps to have an idea of how Vim "thinks" of
+folding.  Here are the rules in a nutshell:
+
+* Each line of code in a file has a "foldlevel".  This is always either zero or
+  a positive integer.
+* Lines with a foldlevel of zero are *never* included in any fold.
+* Adjacent lines with the same foldlevel are folded together.
+* If a fold of level X is closed, any subsequent lines with a foldlevel greater
+  than or equal to X are folded along with it until you reach a line with
+  a level less than X.
+
+It's easiest to get a feel for this with an example.  Open a Vim window and
+paste the following text into it.
+
+    :::text
+    a
+        b
+        c
+            d
+            e
+        f
+    g
+
+Turn on `indent` folding by running the following command:
+
+    :::vim
+    :setlocal foldmethod=indent
+
+Play around with the folds for a minute to see how they behave.
+
+Now run the following command to view the foldlevel of line 1:
+
+    :::vim
+    :echom foldmethod(1)
+
+Vim will display `0`.  Now let's find the foldlevel of line 2:
+
+    :::vim
+    :echom foldmethod(2)
+
+Vim will display `1`.  Let's try line 3:
+
+    :::vim
+    :echom foldmethod(3)
+
+Once again Vim displays `1`.  This means that lines 2 and 3 are part of a level
+1 fold.
+
+Here are the foldlevels for each line:
+
+    :::text
+    a           0
+        b       1
+        c       1
+            d   2
+            e   2
+        f       1
+    g           0
+
+Reread the rules at the beginning of this section.  Open and close each fold in
+this file, look at the foldlevels, and make sure you understand why the folds
+behave as they do.
+
+Once you're confident that you understand how every line's foldlevel works to
+create the folding structure, move on to the next section.
+
+
+First: Make a Plan
+------------------
+
+Before we dive into writing code, let's try to sketch out some rough "rules" for
+our folding.
+
+First, lines that are indented should be folded together.  We also want the
+*previous* line folded with them, so that something like this:
+
+    :::text
+    hello = (name):
+        'Hello, ' print
+        name print.
+
+Will fold like this:
+
+    :::text
+    +--  3 lines: hello = (name):
+
+Blank lines should be at the same level as *later* lines, so blank lines at the
+end of a fold won't be included in it.  This means that this:
+
+    :::text
+    hello = (name):
+        'Hello, ' print
+        name print.
+
+    hello('Steve')
+
+Will fold like this:
+
+    :::text
+    +--  3 lines: hello = ():
+
+    hello('Steve')
+
+And *not* like this:
+
+    :::text
+    +--  4 lines: hello = ():
+    hello('Steve')
+
+These rules are a matter of personal preference, but for now this is the way
+we're going to implement folding.
+
+Getting Started
+---------------
+
+Let's get started on our custom folding code by opening Vim with two splits.
+One should contain our `ftplugin/potion/folding.vim` file, and the other should
+contain our sample `factorial.pn`.
+
+In the previous chapter we closed and reopened Vim to make our changes to
+`folding.vim` take effect, but it turns out there's an easier way to do that.
+
+Remember that any files inside `ftplugin/potion/` will be run whenever the
+`filetype` of a buffer is set to `potion`.  This means you can simply run `:set
+ft=potion` in the split containing `factorial.pn` and Vim will reload the
+folding code!
+
+This is much faster than closing and reopening the file every time.  The only
+thing you need to remember is that you have to *save* `folding.vim` to disk,
+otherwise your unsaved changes won't be taken into account.
+
+Expr Folding
+------------
+
+We're going to use Vim's `expr` folding to give us unlimited flexibility in how
+our code is folded.
+
+We can go ahead and remove the `foldignore` from `folding.vim` because it's only
+relevant when using `indent` folding.  We also want to tell Vim to use `expr`
+folding, so change the contents of `folding.vim` to look like this:
+
+    :::vim
+    setlocal foldmethod=expr
+    setlocal foldexpr=GetPotionFold(v:lnum)
+
+    function! GetPotionFold(lnum)
+        return '0'
+    endfunction
+
+The first line simply tells Vim to use `expr` folding.
+
+The second line defines the expression Vim should use to get the foldlevel of
+a line.  When Vim runs the expression it will set `v:lnum` to the line number of
+the line it wants to know about.  Our expression will call a custom function
+with this number as an argument.
+
+Finally we define a dummy function that simply returns `'0'` for every line.
+Note that it's returning a String and not an Integer.  We'll see why shortly.
+
+Go ahead and reload the folding code by saving `folding.vim` and running `:set
+ft=potion` in `factorial.pn`.  Our function returns `'0'` for every line, so
+Vim won't fold anything at all.
+
+Blank Lines
+-----------
+
+Let's take care of the special case of blank lines first.  Modify the
+`GetPotionFold` function to look like this:
+
+    :::vim
+    function! GetPotionFold(lnum)
+        if getline(a:lnum) =~? '\v^\s*$'
+            return '-1'
+        endif
+
+        return '0'
+    endfunction
+
+We've added an `if` statement to take care of the blank lines.  How does it
+work?
+
+First we use `getline(a:lnum)` to get the content of the current line as
+a String.
+
+We compare this to the regex `\v^\s*$`.  Remember that `\v` turns on "very
+magic" ("sane") mode.  This regex will match "beginning of line, any number
+of whitespace characters, end of line".
+
+The comparison is using the case-insensitive match operator `=~?`.  Technically
+we don't have to be worried about case since we're only matching whitespace, but
+I prefer to be more explicit when using comparison operators on Strings.  You
+can use `=~` instead if you prefer.
+
+If you need a refresher on using regular expressions in Vim you should go back
+and reread the "Basic Regular Expressions" chapter and the chapters on the "Grep
+Operator".
+
+If the current line has some non-whitespace characters it won't match and we'll
+just return `'0'` as before.
+
+If the current line *does* match the regex (i.e. is it's empty or just
+whitespace) we return the string `'-1'`.
+
+Earlier I said that a line's foldlevel can be zero or a positive integer, so
+what's happening here?
+
+Special Foldlevels
+------------------
+
+Your custom folding expression can return a foldlevel directly, or return one of
+a few "special" strings that tell Vim how to fold the line without directly
+specifying its level.
+
+`'-1'` is one of these special strings.  It tells Vim that the level of this
+line is "undefined".  Vim will interpret this as "the foldlevel of this line is
+equal to the foldlevel of the line above or below it, whichever is smaller".
+
+This isn't *exactly* what our plan called for, but we'll see that it's close
+enough and will do what we want.
+
+Vim can "chain" these undefined lines together, so if you have two in a row
+followed by a line at level 1, it will set the last undefined line to 1, then
+the next to last to 1, then the first to 1.
+
+When writing custom folding code you'll often find a few types of line that you
+can easily set a specific level for.  Then you'll use `'-1'` (and some other
+special foldlevels we'll see soon) to "cascade" the proper folding levels to the
+rest of the file.
+
+If you reload the folding code for `factorial.pn` Vim *still* won't fold any
+lines together.  This is because all the lines have a foldlevel of either zero
+or "undefined".  The level `0` will "cascade" through the undefined lines and
+eventually all the lines will have their foldlevel set to `0`.
+
+An Indentation Level Helper
+---------------------------
+
+To tackle non-blank lines we'll need to know their indentation level, so let's
+create a small helper function to calculate it for us.  Add the following
+function above `GetPotionFold`:
+
+    :::vim
+    function! IndentLevel(lnum)
+        return indent(a:lnum) / &shiftwidth
+    endfunction
+
+Reload the folding code.  Test out your function by running the following
+command in the `factorial.pn` buffer:
+
+    :::vim
+    :echom IndentLevel(1)
+
+Vim displays `0` because line 1 is not indented.  Now try it on line 2:
+
+    :::vim
+    :echom IndentLevel(2)
+
+This time Vim displays `1`.  Line two has 4 spaces at the beginning, and
+`shiftwidth` is set to 4, so 4 divided by 4 is 1.
+
+`IndentLevel` is fairly straightforward.  The `indent(a:lnum)` returns the
+number of spaces at the beginning of the given line number.  We divide that by
+the `shiftwidth` of the buffer to get the indentation level.
+
+Why did we use `&shiftwidth` instead of just dividing by 4?  If someone prefers
+two-space indentation in their Potion files, dividing by 4 would produce an
+incorrect result.  We use the `shiftwidth` setting to allow for any number of
+spaces per level.
+
+One More Helper
+---------------
+
+It might not be obvious where to go from here.  Let's stop and think about what
+type of information we need to have to figure out how to fold a non-blank line.
+
+We need to know the indentation level of the line itself.  We've got that
+covered with the `IndentLevel` function, so we're all set there.
+
+We'll also need to know the indentation level of the *next non-blank line*,
+because we want to fold the "header" lines with their indented bodies.
+
+Let's write a helper function to get the number of the next non-blank line after
+a given line.  Add the following function above `IndentLevel`:
+
+    :::vim
+    function! s:NextNonBlankLine(lnum)
+        let numlines = line('$')
+        let current = a:lnum + 1
+
+        while current <= numlines
+            if getline(current) =~? '\v\S'
+                return current
+            endif
+
+            let current += 1
+        endwhile
+
+        return -2
+    endfunction
+
+This function is a bit longer, but is pretty simple.  Let's take it
+piece-by-piece.
+
+First we store the total number of lines in the file with `line('$')`.  Check
+out the documentation for `line()` to see how this works.
+
+Next we set the variable `current` to the number of the next line.
+
+We then start a loop that will walk through each line in the file.
+
+If the line matches the regex `\v\S`, which means "match a character that's
+*not* a whitespace character", then it must be non-blank, so we should return
+its line number.
+
+If the line doesn't match, we loop around to the next one.
+
+If the loop gets all the way to the end of the file without ever returning, then
+there are *no* non-blank lines after the current line!  We return `-2` if that
+happens to indicate this.  `-2` isn't a valid line number, so it's an easy way
+to say "sorry, there's no valid result".
+
+We could have returned `-1`, because that's not a valid line number either.
+I could have even picked `0`, since line numbers in Vim start at `1`!  So why
+did I pick `-2`, which seems like a strange choice?
+
+I chose `-2` because we're working with folding code, and `'-1'` (and `'0'`) is
+a special Vim foldlevel string.
+
+When my eyes are reading over this file and I see a `-1` my brain immediately
+thinks "undefined foldlevel".  The same is true with `0`.  I picked `-2` here
+simply to make it obvious that it's *not* a foldlevel, but is instead an
+"error".
+
+If this feels weird to you, you can safely change the `-2` to a `-1` or a `0`.
+It's just a coding style preference.
+
+Finishing the Fold Function
+---------------------------
+
+This is turning out to be quite a long chapter, so let's wrap up the folding
+function.  Change `GetPotionFold` to look like this:
+
+    :::vim
+    function! GetPotionFold(lnum)
+        if getline(a:lnum) =~? '\v^\s*$'
+            return '-1'
+        endif
+
+        let this_indent = IndentLevel(a:lnum)
+        let next_indent = IndentLevel(NextNonBlankLine(a:lnum))
+
+        if next_indent == this_indent
+            return this_indent
+        elseif next_indent < this_indent
+            return this_indent
+        elseif next_indent > this_indent
+            return '>' . next_indent
+        endif
+    endfunction
+
+That's a lot of new code!  Let's step through it to see how it all works.
+
+### Blanks
+
+First we have our check for blank lines.  Nothing's changed there.
+
+If we get past that check we know we're looking at a non-blank line.
+
+### Finding Indentation Levels
+
+Next we use our two helper functions to get the indent level of the current
+line, and the indent level of the next non-blank line.
+
+You might wonder what happens if `NextNonBlankLine` returns our error condition
+of `-2`.  If that happens, `indent(-2)` will be run.  Running `indent()` on
+a nonexistent line number will just return `-1`.  Go ahead and try it yourself
+with `:echom indent(-2)`.
+
+`-1` divided by any `shiftwidth` larger than `1` will return `0`.  This may seem
+like a problem, but it turns out that it won't be.  For now, don't worry about
+it.
+
+### Equal Indents
+
+Now that we have the indentation levels of the current line and the next
+non-blank line, we can compare them and decide how to fold the current line.
+
+Here's the `if` statement again:
+
+    :::vim
+    if next_indent == this_indent
+        return this_indent
+    elseif next_indent < this_indent
+        return this_indent
+    elseif next_indent > this_indent
+        return '>' . next_indent
+    endif
+
+First we check if the two lines have the same indentation level.  If they do, we
+simply return that indentation level as the foldlevel!
+
+An example of this would be:
+
+    :::text
+    a
+    b
+        c
+        d
+    e
+
+If we're looking at the line containing "c", it has an indentation level of 1.
+This is the same as the level of the next non-blank line ("d"), so we return `1`
+as the foldlevel.
+
+If we're looking at "a", it has an indentation level of 0.  This is the same as
+the level of the next non-blank line ("b"), so we return `0` as the foldlevel.
+
+This case fills in two foldlevels in this simple example:
+
+    :::text
+    a       0
+    b       ?
+        c   1
+        d   ?
+    e       ?
+
+By pure luck this also handles the special "error" case of the last line as
+well!  Remember we said that `next_indent` will be `0` if our helper function
+returns `-2`.
+
+In this example the line "e" has an indent level of `0`, and `next_indent` will
+also be set to `0`, so this case matches and returns `0`.  The foldlevels now
+look like this:
+
+    :::text
+    a       0
+    b       ?
+        c   1
+        d   ?
+    e       0
+
+### Lesser Indent Levels
+
+Once again, here's the `if` statement:
+
+    :::vim
+    if next_indent == this_indent
+        return this_indent
+    elseif next_indent < this_indent
+        return this_indent
+    elseif next_indent > this_indent
+        return '>' . next_indent
+    endif
+
+The second part of the `if` checks if the indentation level of the next line is
+*smaller* than the current line.  This would be like line "d" in our example.
+
+If that's the case, we once again return the indentation level of the current
+line.
+
+Now our example looks like this:
+
+    :::text
+    a       0
+    b       ?
+        c   1
+        d   1
+    e       0
+
+You could, of course, combine these two cases with `&&`, but I prefer to keep
+them separate to make it more explicit.  You might feel differently.  It's
+a style issue.
+
+Again, purely by luck, this case handles the other possible "error" case of our
+helper function.  Imagine that we have a file like this:
+
+    :::text
+    a
+        b
+        c
+
+The first case takes care of line "b":
+
+    :::text
+    a       ?
+        b   1
+        c   ?
+
+Line "c" is the last line, and it has an indentation level of 1.  The
+`next_indent` will be set to `0` thanks to our helper functions.  The second
+part of the `if` matches and sets the foldlevel to the current indentation
+level, or `1`:
+
+    :::text
+    a       ?
+        b   1
+        c   1
+
+This works out great, because "b" and "c" will be folded together.
+
+### Greater Indentation Levels
+
+Here's that tricky `if` statement for the last time:
+
+    :::vim
+    if next_indent == this_indent
+        return this_indent
+    elseif next_indent < this_indent
+        return this_indent
+    elseif next_indent > this_indent
+        return '>' . next_indent
+    endif
+
+And our example file:
+
+    :::text
+    a       0
+    b       ?
+        c   1
+        d   1
+    e       0
+
+The only line we haven't figured out is "b", because:
+
+* "b" has an indent level of `0`.
+* "c" has an indent level of `1`.
+* 1 is not equal to 0, nor is 1 less than 0.
+
+The last case checks if the next line has a *larger* indentation level than the
+current one.
+
+This is the case that Vim's `indent` folding gets wrong, and it's the entire
+reason we're writing this custom folding in the first place!
+
+The final case says that when the next line is indented more than the current
+one, it should return a string of a `>` character and the indentation level of
+the *next* line.  What the heck is *that*?
+
+Returning a string like `>1` from the fold expression is another one of Vim's
+"special" foldlevels.  It tells Vim that the current line should *open* a fold
+of the given level.
+
+In this simple example we could have just returned the number, but we'll see
+why this is important shortly.
+
+In this case line "b" will open a fold at level 1, which makes our example look
+like this:
+
+    :::text
+    a       0
+    b       >1
+        c   1
+        d   1
+    e       0
+
+That's exactly what we want!  Hooray!
+
+Review
+------
+
+If you've made it this far you should feel proud of yourself.  Even simple
+folding code like this can be tricky and mind bending.
+
+Before we end, let's go through our original `factorial.pn` code and see how our
+folding expression fills in the foldlevels of its lines.
+
+Here's `factorial.pn` for reference:
+
+    :::text
+    factorial = (n):
+        total = 1
+        n to 1 (i):
+            # Multiply the running total.
+            total *= i.
+        total.
+
+    10 times (i):
+        i string print
+        '! is: ' print
+        factorial (i) string print
+        "\n" print.
+
+First, any blank lines' foldlevels will be set to undefined:
+
+    :::text
+    factorial = (n):
+        total = 1
+        n to 1 (i):
+            # Multiply the running total.
+            total *= i.
+        total.
+                                             undefined
+    10 times (i):
+        i string print
+        '! is: ' print
+        factorial (i) string print
+        "\n" print.
+
+Any lines where the next line's indentation is *equal* to its own are set to its
+own level:
+
+    :::text
+    factorial = (n):
+        total = 1                            1
+        n to 1 (i):
+            # Multiply the running total.    2
+            total *= i.
+        total.
+                                             undefined
+    10 times (i):
+        i string print                       1
+        '! is: ' print                       1
+        factorial (i) string print           1
+        "\n" print.                          1
+
+The same thing happens when the next line's indentation is *less* than the
+current line's: 
+
+    :::text
+    factorial = (n):
+        total = 1                            1
+        n to 1 (i):
+            # Multiply the running total.    2
+            total *= i.                      2
+        total.                               1
+                                             undefined
+    10 times (i):
+        i string print                       1
+        '! is: ' print                       1
+        factorial (i) string print           1
+        "\n" print.                          1
+
+The last case is when the next line's indentation is *greater* than the current
+line's.  When that happens the line's foldlevel is set to *open* a fold of the
+*next* line's foldlevel:
+
+    :::text
+    factorial = (n):                         >1
+        total = 1                            1
+        n to 1 (i):                          >2
+            # Multiply the running total.    2
+            total *= i.                      2
+        total.                               1
+                                             undefined
+    10 times (i):                            >1
+        i string print                       1
+        '! is: ' print                       1
+        factorial (i) string print           1
+        "\n" print.                          1
+
+Now we've got a foldlevel for every line in the file.  All that's left is for
+Vim to resolve any undefined lines.
+
+Earlier I said that undefined lines will take on the smallest foldlevel of
+either of their neighbors.
+
+That's how Vim's manual describes it, but it's not entirely accurate.  If that
+were the case, the blank line in our file would take foldlevel 1, because both
+of its neighbors have a foldlevel of 1.
+
+In reality, the blank line will be given a foldlevel of 0!
+
+The reason for this is that we didn't just set the `10 times (i):` line to
+foldlevel `1` directly.  We told Vim that the line *opens* a fold of level `1`.
+Vim is smart enough to know that this means the undefined line should be set to
+`0` instead of `1`.
+
+The exact logic of this is probably buried deep within Vim's source code.  In
+general Vim behaves pretty intelligently when resolving undefined lines against
+"special" foldlevels, so it will usually do what you want.
+
+Once Vim's resolved the undefined line it has a complete description of how to
+fold each line in the file, which looks like this:
+
+    :::text
+    factorial = (n):                         1
+        total = 1                            1
+        n to 1 (i):                          2
+            # Multiply the running total.    2
+            total *= i.                      2
+        total.                               1
+                                             0
+    10 times (i):                            1
+        i string print                       1
+        '! is: ' print                       1
+        factorial (i) string print           1
+        "\n" print.                          1
+
+That's it, we're done!  Reload the folding code and play around with the fancy
+new folding in `factorial.pn`.
+
+Exercises
+---------
+
+Read `:help foldexpr`.
+
+Read `:help fold-expr`.  Pay particular attention to all the "special" strings
+your expression can return.
+
+Read `:help getline`.
+
+Read `:help indent()`.
+
+Read `:help line()`.
+
+Figure out why it's important that we use `.` to combine the `>` character with
+the number in our folding function.  What would happen if you used `+` instead?
+Why?
+
+We defined our helper functions as global functions, but that's not a good idea.
+Change them to be script-local functions.
+
+Put this book down and go outside for a while to let your brain recover from
+this chapter.
--- a/outline.org	Fri Nov 18 14:20:33 2011 -0800
+++ b/outline.org	Sat Dec 31 17:24:53 2011 -0500
@@ -47,15 +47,15 @@
 ** DONE plugin layout
 ** DONE pathogen
 ** DONE ftdetect
-** TODO syntax
-** TODO autoload
-** TODO folding
+** DONE syntax
+** DONE folding
 ** TODO compilers
 *** makeprg
 *** errorformat
+** TODO autoload
 ** TODO customization
-** TODO documentation
+** TODO dynamic status lines
 ** TODO mapping
-** TODO dynamic status lines
 ** TODO customizing maps
+** TODO documentation
 ** TODO distributing