--- a/chapters/17.markdown Sun Oct 16 11:00:24 2011 +0400
+++ b/chapters/17.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -119,13 +119,13 @@
code that can be very useful immediately. Run the following commands:
:set statusline=%f " Path to the file
- :set statusline+=%- " Switch to the right side
+ :set statusline+=%= " Switch to the right side
:set statusline+=%l " Current line
:set statusline+=/ " Separator
:set statusline+=%L " Total lines
Now the status line will contain the path to the file on the left side, and the
-current/total lines on the right side. The `%-` code tells Vim that everything
+current/total lines on the right side. The `%=` code tells Vim that everything
coming after that should be aligned (as a whole) to the right instead of the
left.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/26.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,146 @@
+Strings
+=======
+
+The next type of variable we'll look at is the String. Since Vim is all about
+manipulating text you'll be using this one quite a bit.
+
+Run the following command:
+
+ :echom "Hello"
+
+Vim will echo "Hello". So far, so good.
+
+Concatenation
+-------------
+
+One of the most common things you'll want to do with strings is adding them
+together. Run this command:
+
+ :echom "Hello, " + "world"
+
+What happened? Vim displayed "0" for some reason!
+
+Here's the issue: Vim's `+` operator is *only* for Numbers. When you pass
+a string to `+` Vim will try to coerce it to a Number before performing the
+addition. Run the following command:
+
+ :echom "3 mice" + "2 cats"
+
+This time Vim displays "5", because the strings are coerced to the numbers "3"
+and "2" respectively.
+
+When I said "Number" I really *meant* Number. Vim will *not* coerce strings to
+Floats! Try this command to see prove this:
+
+ :echom 10 + "10.10"
+
+Vim displays "20" because it dropped everything after the decimal point when
+coercing "10.10" to a Number.
+
+To combine strings you need to use the concatenation operator. Run the
+following command:
+
+ :echom "Hello, " . "world"
+
+This time Vim displays "Hello, world". `.` is the "concatenate strings"
+operator in Vim, which lets you combine strings. It doesn't add whitespace or
+anything else in between.
+
+Coercion works both ways. Kind of. Try this command:
+
+ :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:
+
+ :echom 10.1 . "foo"
+
+This time Vim throws an error, saying we're using a Float as a String. Vim will
+happily let you use a String as a Float when performing addition, but *won't*
+let you use a Float as a String when concatenating.
+
+The moral of this story is that Vim is a lot like Javascript: it allows you to
+play fast and loose with types sometimes, but it's a really bad idea to do so
+because it will come back to bite you at some point.
+
+When writing Vimscript, make sure you know what the type of each of your
+variables is. If you need to change that type you should use a function to
+explicitly change it, even if it's not strictly necessary at the moment. Don't
+rely on Vim's coercion because at some point you *will* regret it.
+
+Special Characters
+------------------
+
+Like most programming languages, Vimscript lets you use escape sequences in
+strings to represent hard-to-type characters. Run the following command:
+
+ :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:
+
+ :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`):
+
+ :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:
+
+ :echom "foo\nbar"
+
+Vim will display something like "foo^@bar". When you use `echom` with a String
+instead of `echo` Vim will echo the exact characters of the string, which
+sometimes means that it will show a different representation than plain old
+`echo`. `^@` is Vim's way of saying "newline character".
+
+Literal Strings
+---------------
+
+Vim also lets you use "literal strings" to avoid excessive use of escape
+sequences. Run the following command:
+
+ :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:
+
+ :echom 'That''s enough.'
+
+Vim will display "That's enough." Two single quotes is the *only* sequence that
+has special meaning in a literal string.
+
+We'll revisit literal strings when they become most useful, later in the book
+(when we dive into regular expressions).
+
+Truthiness
+----------
+
+You might be wondering how Vim treats strings when used in an `if` statement.
+Run the following command:
+
+ :if "foo"
+ : echo "yes"
+ :else
+ : echo "no"
+ :endif
+
+Vim will display "no". If you're wondering why this happens you should reread
+the chapter on conditionals, because we talked about it there.
+
+Exercises
+---------
+
+Read `:help expr-quote`. Review the list of escape sequences you can use in
+a normal Vim string. Find out how to insert a tab character.
+
+Try to figure out a way to insert a tab character into a string *without* using
+an escape sequence. Read `:help i_CTRL-V` for a hint.
+
+Read `:help literal-string`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/27.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,88 @@
+String Functions
+================
+
+Vim has many built-in functions to manipulate strings. In this chapter we'll
+look at a few of the most important ones.
+
+Length
+------
+
+The first function we'll look at is `strlen`. Run the following command:
+
+ :echom strlen("foo")
+
+Vim displays "3", which is the length of the string "foo". Now try the
+following command:
+
+ :echom len("foo")
+
+Vim once again displays "3". When used with Strings `len` and `strlen` have
+identical effects. We'll come back to `len` later in the book.
+
+Splitting
+---------
+
+Run the following command (note that it's an `echo` and not an `echom`):
+
+ :echo split("one two three")
+
+Vim displays "['one', 'two', 'three']". The `split` function splits a String
+into a List. We'll talk about Lists shortly, but for now don't worry too much
+about them.
+
+You can also tell Vim to use a separator other than "whitespace" for splitting.
+Run the following command:
+
+ :echo split("one,two,three", ",")
+
+Vim will once again display "['one', 'two', 'three']", because the second
+argument to `split` tells it to split the string on the comma character instead
+of on whitespace.
+
+Joining
+-------
+
+Not only can you split strings, you can also join them. Run the following
+command:
+
+ :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:
+
+ :echo join(split("foo bar"), ";")
+
+Vim displays "foo;bar". First we split the string "foo bar" into a list, then
+we joined that list together using a semicolon as the separator.
+
+Lower and Upper Case
+--------------------
+
+Vim has two functions to change the case of Strings. Run the following
+commands:
+
+ :echom tolower("Foo")
+ :echom toupper("Foo")
+
+Vim displays "foo" and "FOO". This should be pretty easy to understand.
+
+In many languages (like Python) a common idiom is to force strings to lowercase
+before comparing them to perform a case-insensitive comparison. In Vimscript
+this isn't necessary because we have the case-insensitive comparison operators.
+Reread the chapter on comparisons if you don't remember those.
+
+It's up to you to decide whether to use `tolower` and `==#`, or just `==?` to
+perform case-sensitive comparisons. There doesn't seem to be any strong
+preference in the Vimscript community. Pick one and stick to it for all of your
+scripts.
+
+Exercises
+---------
+
+Read `:help functions` and skim the list of built-in functions for ones that
+mention the word "String". Use the `/` command to make it easier (remember,
+Vim's help files can be navigated like any other kind of file). There are
+a *lot* of functions here, so don't feel like you need to read the documentation
+for every single one. Just try to get an idea of what's available if you need
+it in the future.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/28.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,65 @@
+Execute
+=======
+
+The `execute` command is used to evaluate a string as if it were a Vimscript
+command. Run the following command:
+
+ :execute "echom 'Hello, world!'"
+
+Vim evaluates `echom 'Hello, world!'` as a command and dutifully echoes it to
+the screen and message log. Execute is a very powerful tool because it lets you
+build commands out of arbitrary strings.
+
+Let's try a more useful example. Prepare by opening a file in Vim, then using
+`:edit "foo.txt"` in the same window to open a new buffer. Now run the
+following command:
+
+ :execute "rightbelow vsplit " . bufname("#")
+
+Vim will open the first file in a vertical split to the right of the second
+file. What happened here?
+
+First, Vim sees builds the command string by concatenating "rightbelow vsplit
+" with the result of the `bufname("#")` call.
+
+We'll look at the function more later, but for now just trust that it returns
+the path of the previous buffer. You can play with it using `echom` if you want
+to see for yourself.
+
+Once `bufname` is evaluated Vim has a string that looks something like
+"rightbelow vsplit bar.txt". The `execute` command evaluates this as
+a Vimscript command which opens the split with the file.
+
+Is Execute Dangerous?
+---------------------
+
+In most programming languages the use of such an "eval" construct to evaluate
+strings as program code is frowned upon, to put it lightly. Vimscript's
+`execute` command doesn't bear the same stigma for two reasons.
+
+First, most Vimscript code only ever takes input from a single person: the user.
+If the user wants to input a tricky string that will cause an `execute` command
+to do something bad, well, it's their computer!
+
+Contrast this with other languages, where programs constantly take input from
+untrusted users. Vim is a unique environment where the normal security concerns
+simple aren't common.
+
+The second reason is that because Vimscript has sometimes arcane and tricky
+syntax, `execute` is often the easiest, most straightforward way to get
+something done. In most other languages using an "eval" construct won't usually
+save you much typing, but in Vimscript it can collapse many lines into a single
+one.
+
+Exercises
+---------
+
+Skim `:help execute` to get an idea of some of the things you can and can't use
+`execute` for. Don't dive too deeply yet -- we're going to revisit it very
+soon.
+
+Read `:help leftabove`, `:help rightbelow`, `:help :split`, and `:help :vsplit`
+(notice the extra colon in the last two topics).
+
+Add a mapping to your `~/.vimrc` file that opens the previous buffer in a split
+of your choosing (vertical/horizontal, above/below/left/right).
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/29.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,101 @@
+Normal
+======
+
+So far we've covered some of the most useful Vimscript commands, but what about
+all the stuff you do on a daily basis in normal mode? Can we somehow use all
+the knowledge we have from editing text in our scripting?
+
+The answer is: "of course". Run the following command:
+
+ :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:
+
+ :normal ggdd
+
+Vim will move to the first line in the file (`gg`) and then delete it (`dd`).
+
+The `normal` command simply takes a sequence of keys and pretends they were
+typed in normal mode. Seems simple enough.
+
+Avoiding Mappings
+-----------------
+
+Run the following command to map the `G` key to something else:
+
+ :nnoremap G dd
+
+Now pressing `G` in normal mode will delete a line. Try this command:
+
+ :normal G
+
+Vim will delete the current line. The `normal` command will take into account
+any mappings that exist.
+
+This means that we need something like the `nnoremap` version of `nmap` for
+`normal`, otherwise we'll never be able to use it since we can't know what keys
+our users have mapped.
+
+Luckily Vim has a `normal!` command that does exactly this. Run this command:
+
+ :normal! G
+
+This time Vim moves to the bottom of the file even though `G` has been mapped.
+
+When writing Vim scripts you should **always** use `normal!`, **never** plain
+old `normal`. You can't trust what keys your users will have mapped in their
+`~/.vimrc` files.
+
+Special Characters
+------------------
+
+If you play around with `normal!` long enough you'll probably notice a problem.
+Try the following command:
+
+ :normal! /foo<cr>
+
+At first glance it may seem like this should perform a search for "foo", but
+you'll see that it doesn't work. The problem is that `normal!` doesn't parse
+special character sequences like `<cr>`.
+
+In this case Vim thinks you wanted to search for the character sequence "f, o,
+o, left angle bracket, c, r, right angle bracket", and thinks that you never
+even pressed return to perform the search!
+
+We'll talk about how to get around this in the next chapter.
+
+Exercises
+---------
+
+Read `:help normal`. The end of it will hint at the topic of the next chapter.
+
+Extra Credit
+------------
+
+If you're not feeling up for a challenge, skip this section. If you are, good
+luck!
+
+Recall what `:help normal` said about undo. Try to make a mapping that will
+delete two lines but let you undo each deletion separately. `nnoremap <leader>d
+dddd` is a good place to start.
+
+You won't actually need `normal!` for this (`nnoremap` will suffice), but it
+illustrates a good point: sometimes reading about one Vim command can spark an
+interest in something unrelated.
+
+If you've never used the `helpgrep` command you'll probably need it now. Read
+`:help helpgrep`. Pay attention to the parts about how to navigate between the
+matches.
+
+Don't worry about patterns yet, we're going to cover them soon. For now it's
+enough to know that you can use something like `foo.*bar` to find lines
+containing that regex in the documentation.
+
+Unfortunately `helpgrep` can be frustrating at times because you need to know
+what words to search for before you can find them! I'll cut you some slack and
+tell you that in this case you're looking for a way to break Vim's undo sequence
+manually, so that the two deletes in your mapping can be undone separately.
+
+In the future, be pragmatic. Sometimes Google is quicker and easier when you
+don't know exactly what you're after.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/30.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,48 @@
+Execute Normal!
+===============
+
+Now that we've seen `execute` and `normal!` we can talk about a common Vimscript
+idiom. Run the following command:
+
+ :execute "normal! gg/foo\<cr>dd"
+
+This will move to the top of the file, search for the first occurrence of "foo",
+and delete the line that contains it.
+
+Previously we tried to use `normal!` with a search command but couldn't enter
+the return needed to actually perform the search. Combining `normal!` with
+`execute` fixes that problem.
+
+`execute` lets you build commands programatically, so you can use Vim's normal
+string escape sequences to generate the non-printing characters you need. Try
+the following command:
+
+ :execute "normal! mqA;\<esc>`q"
+
+What does this do? Let's break it apart:
+
+* `:execute "normal! ..."`: run the sequence of commands as if they were entered
+ in normal mode, ignoring all mappings, and replacing escape sequences with
+ their results.
+* `mq`: store the current location in mark "q".
+* `A`: move to the end of the current line and enter insert mode after the last
+ character.
+* `;`: we're now in insert mode, so just put a literal semicolon in the file.
+* `\<esc>`: this is a string escape sequence which resolves to a press of the
+ escape key, which takes us out of insert mode.
+* ```q``: return to the exact location of mark "q".
+
+It looks a bit scary but it's actually quite useful: it puts a semicolon at the
+end of the current line while leaving your cursor in place. A mapping for this
+could come in handy if you forget a semicolon when writing Javascript, C, or any
+other language with semicolons as statement terminators.
+
+Exercises
+---------
+
+Read `:help expr-quote` again (you've seen it before) to remind yourself how to
+use string escapes to pass special characters to `normal!` with `execute`.
+
+Put down this book for a while before you go on to the next chapter. Get
+a sandwich or a cup of coffee, feed your pets if you have them, and relax for
+a bit before continuing.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/31.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,187 @@
+Basic Regular Expressions
+=========================
+
+Vim is a text editor, which means that a great deal of your Vimscript code will
+be dedicated to working with text. Vim has powerful support for regular
+expressions, but as usual there are some quirks.
+
+Type the following text into a buffer:
+
+ max = 10
+
+ print "Starting"
+
+ for i in range(max):
+ print "Counter:", i
+
+ print "Done"
+
+This is the text we'll use to experiment with Vimscript's regex support.
+
+Highlighting
+------------
+
+Before we start we need to turn on search highlighting so we can see what we're
+doing. Run the following command:
+
+ :set hlsearch incsearch
+
+`hlsearch` tells Vim to highlight all matches in a file when you perform
+a search, and `incsearch` tells Vim to highlight the *next* match while you're
+still typing out your search pattern.
+
+Searching
+---------
+
+Put your cursor at the top of the file and run the following command:
+
+ /print
+
+As you type in each letter, Vim will start highlighting them in the first line.
+When you press return to execute the search *all* the instances of "print" will
+be highlighted and your cursor will be moved to the next match.
+
+Now try running the following command:
+
+ :execute "normal! gg/print\<cr>"
+
+This will go to the top of the file and perform a search for "print", putting us
+at the first match. It does this using `:execute "normal! ..."` which we saw in
+the previous chapter.
+
+To get to the second match in the file you can just add more commands onto the
+end of the string. Run this command:
+
+ :execute "normal! gg/print\<cr>n"
+
+Vim will put the cursor on the second "print" in the buffer (and all the matches
+will be highlighted).
+
+Let's try going in the opposite direction. Run this command:
+
+ :execute "normal! G?print\<cr>"
+
+This time we move to the bottom of the file with `G` and use `?` to search
+backward instead of forward.
+
+All of these searching commands should be familiar -- we're mostly going over
+them to get you used to the `:execute "normal! ..."` idiom, because it will let
+you do anything you know how to do in vanilla Vim in your Vimscript code.
+
+Magic
+-----
+
+The `/` and `?` commands actually take regular expressions, not just literal
+characters. Run the following command:
+
+ :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:
+
+ :execute "normal! gg/for .\\+ in .\\+:\<cr>"
+
+This time Vim highlights the "for" loop as we expected in the first place. Take
+a minute and try to think about what exactly changed before moving on. Remember
+that `execute` takes a String.
+
+The answer is that there are two reasons we needed to write the command like we
+did:
+
+* First, `execute` takes a String, so the double backslashes we used turn into
+ single backslashes by the time they get to `normal!`.
+* Vim, has *four* different "modes" of parsing regular expressions! The default
+ mode requires a backslash before the `+` character to make it mean "1 or more
+ of the preceding character" instead of "a literal plus sign".
+
+You can see this a bit easier by just running the search in Vim directly. Type
+the following command and press return:
+
+ /print .\+
+
+You can see the `\+` working its magic now. The double backslashes were only
+used because we were passing the pattern as a String to `execute`.
+
+Literal Strings
+---------------
+
+As we mentioned in the chapter on Strings, Vim allows you to use single quotes
+to define a "literal string" that passes through characters directly. For
+example, the string `'a\nb'` is four characters long.
+
+Can we use literal strings to avoid having to type those double backslashes?
+Think about this for a minute or two before you move on, because the answer is
+a bit more complicated that you might think.
+
+Try running the following command (note the single quotes and single backslashes
+this time):
+
+ :execute 'normal! gg/for .\+ in .\+:\<cr>'
+
+Vim moves you to the top of the file but doesn't move you to the first match.
+Is this what you expected?
+
+The command doesn't work because we need the `\<cr>` in the pattern to be
+escaped into a real carriage return character, which tells the search command to
+actually run. Because we're in a literal string, it's the equivalent of typing
+`/for .\+ in .\+:\<cr>` in vanilla Vim, which obviously isn't what we want.
+
+All hope is not lost, though! Remember that Vim allows you to concatenate
+strings, so for larger commands we can use this to split apart the string into
+easier to read chunks. Run the following command:
+
+ :execute "normal! gg" . '/for .\+ in .\+:' . "\<cr>"
+
+This concatenates the three smaller strings before sending them to `execute`,
+and lets us use a literal string for the regex while using normal strings for
+everything else.
+
+Very Magic
+----------
+
+You may be wondering about Vimscript's four different modes of regex parsing and
+how they're different from the regular expressions you're used to from languages
+like Python, Perl or Ruby. You can read their documentation if you really want
+to, but if you want the sane, easy solution just read on.
+
+Run the following command:
+
+ :execute "normal! gg" . '/\vfor .+ in .+:' . "\<cr>"
+
+We've split the pattern out from the rest of the command into its own literal
+string again, and this time we started the pattern with `\v`. This tells Vim to
+use its "very magic" regex parsing mode, which is pretty much the same as you're
+used to in any other programming language.
+
+If you simply start all of your regular expressions with `\v` you'll never need
+to worry about Vimscript's three other crazy regex modes.
+
+Exercises
+---------
+
+Read `:help magic` carefully.
+
+Read `:help pattern-overview` to see the kinds of things Vim regexes support.
+Stop after the character classes.
+
+Read `:help match`. Try running the `:match Error /\v.../` command a few times
+by hand.
+
+Edit your `~/.vimrc` file to add a mapping that will use `match` to highlight
+trailing whitespace as an error. A good key to use might be `<leader>w`.
+
+Add another mapping that will clear the match (perhaps `<leader>W`).
+
+Add a normal mode mapping that will automatically insert the `\v` for you
+whenever you begin a search. If you're stuck remember that Vim's mappings are
+extremely simple and you just need to tell it which keys to press when you use
+the mapped key.
+
+Add the `hlsearch` and `incsearch` options to your `~/.vimrc` file, set however
+you prefer.
+
+Read `:help nohlsearch`. Note that this is a *command* and *not* the "off mode"
+setting of `hlsearch`!
+
+Add a mapping to "stop highlighting items from the last search" to your
+`~/.vimrc` file.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/32.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,184 @@
+Case Study: Grep Operator, Part One
+===================================
+
+In this chapter and the next we're going to walk through creating
+a fairly-complicated piece of Vimscript. We'll talk about several things we
+haven't seen before, as well as how some of the things we've studied fit
+together in practice.
+
+As you work through this case study make sure to look up anything unfamiliar
+with `:help`. If you coast through without fully understanding everything you
+won't learn much.
+
+Grep
+----
+
+If you've never used `:grep` you should take a minute to read `:help :grep` and
+`:help :make` now. Read `:help quickfix-window` if you've never used the
+quickfix window before.
+
+In a nutshell: `:grep ...` will run an external grep program with any arguments
+you give, parse the result, and fill the quickfix list for easy use inside of
+Vim.
+
+Our example is going to make it easier to invoke by adding a "grep operator"
+that you can use with any of Vim's built-in (or custom!) motions to select the
+text you want to search for.
+
+Usage
+-----
+
+The first thing you should think about when creating any non-trivial piece of
+Vimscript is: "how will this functionality be used?". Try to come up with
+a smooth, easy, intuitive way for you and your code's users to invoke it.
+
+In this case I'll do that step for you:
+
+* We're going to create a "grep operator" and bind it to `<leader>g`.
+* It will act like any other Vim operator and take a motion, like `w` or `i{`.
+* It will perform the search immediately and open the quickfix window to show
+ the results.
+* It will *not* jump to the first result, because that can be jarring if the
+ first result isn't what you're expecting.
+
+Some examples of how you might end up using it:
+
+* `<leader>giw`: Grep for the word under the cursor.
+* `<leader>giW`: Grep for the WORD under the cursor.
+* `<leader>gi'`: Grep for the contents of the single-quoted string you're
+ currently in.
+* `viwe<leader>g`: Visually select a word, extend the selection to the end of
+ the word after it, then grep for the selected text.
+
+There are many, *many* other ways to use this. It may seem like it will take
+a lot of coding, but actually all we need to do is implement the operator
+functionality -- Vim will handle the rest.
+
+A Preliminary Sketch
+--------------------
+
+One thing that's sometimes helpful when writing tricky bits of Vimscript is to
+simplify your goal and implement that to get an idea of the "shape" your final
+solution will take.
+
+Let's simplify our goal to: "create a mapping to search for the word under the
+cursor". This is useful but should be easier, so we can get something running
+much faster. We'll map this to `<leader>g` for now.
+
+We'll start with a skeleton of the mapping and fill it in as we go. Run this
+command:
+
+ :nnoremap <leader> g :grep -R something .<cr>
+
+If you've read `:help grep` this should be pretty easy to understand. We've
+looked at lots of mappings before, and there's nothing new here.
+
+Obviously we're not done yet, so lets refine this mapping until it meets our
+simplified goal.
+
+The Search Term
+---------------
+
+First we need to search for the word under the cursor, not the string
+"something". Run the following command:
+
+ :nnoremap <leader>g :grep -R <cword> .<cr>
+
+Now try it out. `<cword>` is a special bit of text you can use in Vim's
+command-line mode, and Vim will replace it with "the word under the cursor"
+before running the command.
+
+You can use `<cWORD>` to get a WORD instead of a word. Run this command:
+
+ :nnoremap <leader>g :grep -R <cWORD> .<cr>
+
+Now try the mapping when your cursor is over something like "foo-bar". Vim will
+grep for "foo-bar" instead of just part of the word.
+
+There's still a problem with our search term: if there are any special shell
+characters in it Vim will happily pass them along to the external grep command,
+which will explode (or, worse, do something terrible).
+
+Go ahead and try this to make sure it breaks. Type `foo;ls` into a file and run
+the mapping while your cursor is over it. The grep command will fail, and Vim
+will actually run an `ls` command as well! Clearly this could be bad if the
+word contained a command more dangerous than `ls`.
+
+To try to fix this we'll quote the argument in the grep call. Run this command:
+
+ :nnoremap <leader>g :grep -R '<cWORD>' .<cr>
+
+Most shells treat single-quoted text as (almost) literal, so our mapping is much
+more robust now. However there's still one more problem with the search term!
+Try the mapping on the word "that's". It won't work, because the single quote
+inside the word interferes with the quotes in the grep command!
+
+To get around this we can use Vim's `shellescape` function. Read `:help
+escape()` and `:help shellescape()` to see how it works (it's pretty simple).
+
+Because `shellescape()` works on Vim strings, we'll need to dynamically build
+the command with `execute`. First run the following command to transform the
+`:grep` mapping into `:execute "..."` form:
+
+ :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:
+
+ :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
+contain strange characters.
+
+The process of starting with a trivial bit of Vimscript and transforming it
+little-by-little into something closer to your goal is one you'll find yourself
+using often.
+
+Cleanup
+-------
+
+There are still a couple of small things to take care of before our mapping is
+finished. First, we said that we don't want to go to the first result
+automatically, and we can use `grep!` instead of plain `grep` to do that. Run
+this command:
+
+ :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:
+
+ :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
+window with the search results. All we did was tack `:copen<cr>` onto the end
+of our mapping.
+
+As the finishing touch we'll remove all the grep output Vim displays while
+searching. Run the following command:
+
+ :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
+runs the command that follows it while hiding any messages it would normally
+display.
+
+Exercises
+---------
+
+Add the mapping we just created to your `~/.vimrc` file.
+
+Read `:help :grep`.
+
+Read `:help cnext` and `:help cprevious`. Try them out after using your new
+grep mapping.
+
+Set up mappings for `:cnext` and `:cprevious` to make it easier to quickly run
+through matches.
+
+Read `:help copen`.
+
+Add a height to the `:copen` command in the mapping we created to make sure the
+quickfix window is opened to whatever height you prefer.
+
+Read `:help silent`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/33.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,255 @@
+Case Study: Grep Operator, Part Two
+===================================
+
+Now that we've got a preliminary sketch of our solution, it's time to flesh it
+out into something powerful.
+
+Remember: our original goal was to create a "grep operator". There are a whole
+bunch of new things we need to cover to do this, but we're going to follow the
+same process we did in the last chapter: start with something simple and
+transform it until it does what you need.
+
+Before we start, comment out the mapping we creating the previous chapter from
+your `~/.vimrc` file -- we're going to use the same keystroke for our new
+operator.
+
+Create a File
+-------------
+
+Creating an operator will take a number of commands and typing those out by
+hand will get tedious very quickly. You could add it to your `~/.vimrc` file,
+but let's create a separate file just for this operator instead. It's meaty
+enough to warrant a file of its own.
+
+First, find your Vim `plugin` directory. On Linux or OS X this will be at
+`~/.vim/plugin`. If you're on Windows it will be at TODO. If this directory
+doesn't exist, create it.
+
+Inside `plugin/` create a file named `grep-operator.vim`. This is where you'll
+place the code for this new operator. When you're editing the file you can run
+`:source %` to reload the code at any time. This file will also be loaded each
+time you open Vim just like `~/.vimrc`.
+
+Remember that you *must* write the file before you source it for the changes to
+be seen!
+
+Skeleton
+--------
+
+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`:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+
+ function! GrepOperator(type)
+ echom "Test"
+ endfunction
+
+Write the file and source it with `:source %`. Try it out by pressing
+`<leader>giw` to say "grep inside word". Vim will echo "Test" *after* accepting
+the `iw` motion, which means we've laid out the skeleton.
+
+The function is simple and nothing we haven't seen before, but that mapping is
+a bit more complicated. First we set the `operatorfunc` option to our function,
+and then we run `g@` which calls this function as an operator. This may seem
+a bit convoluted, but it's how Vim works.
+
+For now it's okay to consider this mapping to be black magic. You can delve
+into the detailed documentation later.
+
+Visual Mode
+-----------
+
+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:
+
+ vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>
+
+Write and source the file. Now visually select something and press `<leader>g`.
+Nothing happens, but Vim does echo "Test", so our function is getting called.
+
+We've seen the `<c-u>` in this mapping before but never explained what it did.
+Try visually selecting some text and pressing `:`. Vim will open a command line
+as it usually does when `:` is pressed, but it automatically fills in `'<,'>` at
+the beginning of the line!
+
+Vim is trying to be helpful and inserts this text to make the command you're
+about to run function on the visually selected range. In this case, however, we
+don't want the help. We use `<c-u>` to say "delete from the cursor to the
+beginning of the line", removing the text. This leaves us with a bare `:`,
+ready for the `call` command.
+
+The `call GrepOperator()` is simply a function call like we've seen before, but
+the `visualmode()` we're passing as an argument is new. This function is
+a built-in Vim function that returns a one-character string representing the
+last type of visual mode used: `"v"` for characterwise, `"V"` for
+linewise, and a `ctrl-v` character for blockwise.
+
+Motion Types
+------------
+
+The function we defined takes a `type` argument. We know that when we use the
+operator from visual mode it will be the result of `visualmode()`, but what
+about when we run it as an operator from normal mode?
+
+Edit the function body so the file looks like this:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+ vnoremap <leader>g :<c-u>call GrepOperator(visualmode())<cr>
+
+ function! GrepOperator(type)
+ echom a:type
+ endfunction
+
+Source the file, then go ahead and try it out in a variety of ways. Some
+examples of the output you get are:
+
+* Pressing `viw<leader>g` echoes `v` because we were in characterwise visual
+ mode.
+* Pressing `Vjj<leader>g` echoes `V` because we were in linewise visual mode.
+* Pressing `<leader>giw` echoes `char` because we used a characterwise motion
+ with the operator.
+* Pressing `<leader>gG` echoes `line` because we used a linewise motion with the
+ operator.
+
+Now we know how we can tell the difference between motion types, which will be
+important when we select the text to search for.
+
+Copying the Text
+----------------
+
+Our function is going to need to somehow get access to the text the user wants
+to search for, and the easiest way to do that is to simply copy it. Edit the
+function to look like this:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+ vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
+
+ function! GrepOperator(type)
+ if a:type ==# 'v'
+ execute "normal! `<v`>y"
+ elseif a:type ==# 'char'
+ execute "normal! `[v`]y"
+ else
+ return
+ endif
+
+ echom @@
+ endfunction
+
+Wow. That's a lot of new stuff. Try it out by pressing things like
+`<leader>giw`, `<leader>g2e` and `vi(<leader>g`. Each time Vim will echo the
+text that the motion covers, so clearly we're making progress!
+
+Let's break this new code down one step at a time. First we have an `if`
+statement that checks the `a:type` argument. If the type is `'v'` it was called
+from characterwise visual mode, so we do something to copy the visually-selected
+text.
+
+Notice that we use the case-sensitive comparison `==#`. If we used plain `==`
+and the user has `ignorecase` set it would match `"V"` as well, which is *not*
+what we want. Code defensively!
+
+The second case of the `if` fires if the operator was called from normal mode
+using a characterwise motion.
+
+The final case simply returns. We explicitly ignore the cases of
+linewise/blockwise visual mode and linewise/blockwise motions. Grep doesn't
+search across lines by default, so having a newline in the search pattern
+doesn't make any sense!
+
+Each of our two `if` cases runs a `normal!` command that does two
+things:
+
+* Visually select the range of text we want by:
+ * Moving to mark at the beginning of the range.
+ * Entering characterwise visual mode.
+ * Moving to the mark at the end of the range.
+* Yanking the visually selected text.
+
+Don't worry about the specific marks for now. You'll learn why they need to be
+different when you complete the exercises at the end of this chapter.
+
+The final line of the function echoes the variable `@@`. Remember that
+variables starting with an `@` are registers. `@@` is the "unnamed" register:
+the one that Vim places text into when you yank or delete without specify
+a particular register.
+
+In a nutshell: we select the text to search for, yank it, then echo the yanked
+text.
+
+Escaping the Search Term
+------------------------
+
+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:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+ vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
+
+ function! GrepOperator(type)
+ if a:type ==# 'v'
+ normal! `<v`>y
+ elseif a:type ==# 'char'
+ normal! `[v`]y
+ else
+ return
+ endif
+
+ echom shellescape(@@)
+ endfunction
+
+Write and source the file and try it out by visually selecting some text with
+a special character in it and pressing `<leader>g`. Vim will echo a version of
+the selected text suitable for passing to a shell command.
+
+Running Grep
+------------
+
+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:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+ vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
+
+ function! GrepOperator(type)
+ if a:type ==# 'v'
+ normal! `<v`>y
+ elseif a:type ==# 'char'
+ normal! `[v`]y
+ else
+ return
+ endif
+
+ silent execute "grep! -R " . shellescape(@@) . " ."
+ copen
+ endfunction
+
+This should look familiar. We simply execute the `silent execute "grep! ..."`
+command we came up with in the last chapter. It's even more readable here
+because we're not trying to stuff the entire thing into a `nnoremap` command!
+
+Write and source the file, then try it out and enjoy the fruits of your labor!
+
+Because we've defined a brand new Vim operator we can use it in a lot of
+different ways, such as:
+
+* `viw<leader>g`: Visually select a word, then grep for it.
+* `<leader>g4w`: Grep for the next four words.
+* `<leader>gt;`: Grep until semicolon.
+* `<leader>gi[`: Grep inside square brackets.
+
+This highlights one of the best things about Vim: its editing commands are like
+a language. When you add a new verb it automatically works with (most of) the
+existing nouns and adjectives.
+
+Exercises
+---------
+
+Read `:help visualmode()`.
+
+Read `:help c_ctrl-u`.
+
+Read `:help operatorfunc`.
+
+Read `:help map-operator`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/34.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,97 @@
+Case Study: Grep Operator, Part Three
+=====================================
+
+Our shiny new "grep operator" is working great, but part of writing Vimscript is
+being considerate and making your users' lives easier. We can do two more
+things to make our operator play nicely in the Vim ecosystem.
+
+
+Saving Registers
+----------------
+
+By yanking the text into the unnamed register we destroy anything that was
+previously in there.
+
+This isn't very nice to our users, so let's save the contents of that register
+before we yank and restore it after we've done. Change the code to look like
+this:
+
+ nnoremap <leader>g :set operatorfunc=GrepOperator<cr>g@
+ vnoremap <leader>g :<C-U>call GrepOperator(visualmode())<cr>
+
+ function! GrepOperator(type)
+ let saved_unnamed_register = @@
+
+ if a:type ==# 'v'
+ normal! `<v`>y
+ elseif a:type ==# 'char'
+ normal! `[v`]y
+ else
+ return
+ endif
+
+ silent execute "grep! -R " . shellescape(@@) . " ."
+ copen
+
+ let @@ = saved_unnamed_register
+ endfunction
+
+We've added two `let` statements at the top and bottom of the function. The
+first saves the contents of `@@` into a variable and the second restores it.
+
+Write and source the file. Make sure it works by yanking some text, then
+pressing `<leader>giw` to run our operator, then pressing `p` to paste the text
+you yanked before.
+
+When writing Vim plugins you should *always* strive to save and restore any
+settings or registers your code modifies so you don't surprise and confuse your
+users.
+
+Namespacing
+-----------
+
+Our script created a function named "GrepOperator" in the global namespace.
+This probably isn't a big deal, but when you're writing Vimscript it's far
+better to be safe than sorry.
+
+We can avoid polluting the global namespace by tweaking a couple of lines in our
+code. Edit the file to look like this:
+
+ nnoremap <leader>g :set operatorfunc=<SID>GrepOperator<cr>g@
+ vnoremap <leader>g :<C-U>call <SID>GrepOperator(visualmode())<cr>
+
+ function! s:GrepOperator(type)
+ let saved_unnamed_register = @@
+
+ if a:type ==# 'v'
+ normal! `<v`>y
+ elseif a:type ==# 'char'
+ normal! `[v`]y
+ else
+ return
+ endif
+
+ silent execute "grep! -R " . shellescape(@@) . " ."
+ copen
+
+ let @@ = saved_unnamed_register
+ endfunction
+
+The first three lines of the script have changed. First, we modified the
+function name to start with `s:` which places it in the current script's
+namespace.
+
+We also modified the mappings and prepended the `GrepOperator` function name
+with `<SID>` so they could find the function. If we hadn't done this they would
+have tried to find the function in the global namespace, which wouldn't have
+worked.
+
+Congratulations, our `grep-operator.vim` script is not only extremely useful,
+but it's also a considerate Vimscript citizen!
+
+Exercises
+---------
+
+Read `:help <SID>`.
+
+Treat yourself to a snack. You deserve it!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/35.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,154 @@
+Lists
+=====
+
+We've worked a lot with variables so far, but we haven't talked about aggregates
+at all yet! Vim has two main aggregate types, and we'll look at the first now:
+lists.
+
+Vimscript lists are ordered, heterogeneous collections of elements. Run the
+following command:
+
+ :echo ['foo', 3, 'bar']
+
+Vim displays the list. Lists can of course be nested. Run the following
+command:
+
+ :echo ['foo', [3, 'bar']]
+
+Vim happily displays the list.
+
+Indexing
+--------
+
+Vimscript lists are zero-indexed, and you can get at the elements in the usual
+way. Run this command:
+
+ :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:
+
+ :echo [0, [1, 2]][-2]
+
+Vim displays `0`. The index `-1` refers to the last element in the list, `-2`
+is the second-to-last, and so on.
+
+Slicing
+-------
+
+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:
+
+ :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:
+
+ :echo ['a', 'b', 'c', 'd', 'e'][0:100000]
+
+Vim simply displays the entire list.
+
+Slice indexes can be negative. Try this command:
+
+ :echo ['a', 'b', 'c', 'd', 'e'][-2:-1]
+
+Vim displays "['d', 'e']" (elements -2 and -1).
+
+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:
+
+ :echo ['a', 'b', 'c', 'd', 'e'][:1]
+ :echo ['a', 'b', 'c', 'd', 'e'][3:]
+
+Vim displays "['a', 'b']" and "['d', 'e']".
+
+Like Python, Vimscript allows you to index and slice strings too. Run the
+following command:
+
+ :echo "abcd"[0:2]
+
+Vim displays "abc".
+
+Concatenation
+-------------
+
+You can combine Vim lists with `+`. Try this command:
+
+ 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
+language.
+
+List Functions
+--------------
+
+Vim has a number of built-in functions for working with lists. Run these
+commands:
+
+ :let foo = ['a']
+ :call add(foo, 'b')
+ :echo foo
+
+Vim mutates the list `foo` in-place to append `'b'` and displays "['a', 'b']".
+Now run this command:
+
+ :echo len(foo)
+
+Vim displays "2", the length of the list. Try these commands:
+
+ :echo get(foo, 0, 'default')
+ :echo get(foo, 100, 'default')
+
+Vim displays "a" and "default". The `get` function will get the item at the
+given index from the given list, or return the given default value if the index
+is out of range in the list.
+
+Run this command:
+
+ :echo index(foo, 'b')
+ :echo index(foo, 'nope')
+
+Vim displays "1" and "-1". The `index` function returns the first index of the
+given item in the given list, or `-1` if the item is not in the list.
+
+Now run this command:
+
+ :echo join(foo)
+ :echo join(foo, '---')
+ :echo join([1, 2, 3], '')
+
+Vim displays "a b" and "a---b". `join` will join the items in the given list
+together into a string, separated by the given separator string (or a space if
+none is given), coercing each item to a string if necessary/possible.
+
+Run the following commands:
+
+ :call reverse(foo)
+ :echo foo
+ :call reverse(foo)
+ :echo foo
+
+Vim displays "['b', 'a']" and then "['a', 'b']". `reverse` reverses the given
+list *in place*.
+
+Exercises
+---------
+
+Read `:help List`. All of it. Notice the capital "L".
+
+Read `:help add()`.
+
+Read `:help len()`.
+
+Read `:help get()`.
+
+Read `:help index()`.
+
+Read `:help join()`.
+
+Read `:help reverse()`.
+
+Skim `:help functions` to find some other list-related functions I haven't
+mentioned yet. Run `:match Keyword /\clist/` to case-insensitively highlight
+the word "list" to make it easier to find what you're looking for.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/36.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,59 @@
+Looping
+=======
+
+You might be surprised to realize that we've gone through thirty five chapters
+of a programming language book without even mentioning loops! Vimscript offers
+so many other options for performing actions on text (`normal!`, etc) that loops
+aren't as necessary as they are in most other languages.
+
+Even so, you'll definitely need them some day, so now we'll take a look at the
+two main kinds of loops Vim supports.
+
+For Loops
+---------
+
+The first kind of loop is the `for` loop. This may seem odd if you're used to
+Java, C or Javascript `for` loops, but turns out to be quite elegant. Run the
+following commands:
+
+ :let c = 0
+
+ :for i in [1, 2, 3, 4]
+ : let c += i
+ :endfor
+
+ :echom c
+
+Vim displays "10", which is the result of adding together each element in the
+list. Vimscript `for` loops iterate over lists (or dictionaries, which we'll
+cover later).
+
+There's no equivalent to the C-style `for (int i = 0; i < foo; i++)` loop form in
+Vimscript. This might seem bad at first, but in practice you'll never miss it.
+
+While Loops
+-----------
+
+Vim also supports the classic `while` loop. Run the following commands:
+
+ :let c = 1
+ :let total = 0
+
+ :while c <= 4
+ : let total += c
+ : let c += 1
+ :endwhile
+
+ :echom total
+
+Once again Vim displays "10". This loop should be familiar to just about anyone
+who's programmed before, so we won't spend any time on it. You won't use it
+very often. Keep it in the back of your mind for the rare occasions that you
+want it.
+
+Exercises
+---------
+
+Read `:help for`.
+
+Read `:help while`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/37.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,140 @@
+Dictionaries
+============
+
+The last type of Vimscript variable we'll talk about is the dictionary.
+Vimscript dictionaries are similar to Python's dicts, Ruby's hashes, and
+Javascript's objects.
+
+Dictionaries are created using curly brackets. Values are heterogeneous, but
+*keys are always coerced to strings*. You didn't think things were going to be
+*completely* sane, did you?
+
+Run this command:
+
+ :echo {'a': 1, 100: 'foo'}
+
+Vim displays `{'a': 1, '100': 'foo'}`, which shows that Vimscript does indeed
+coerce keys to strings while leaving values alone.
+
+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:
+
+ :echo {'a': 1, 100: 'foo',}
+
+Once again Vim displays `{'a': 1, '100': 'foo'}`. You should *always* use the
+trailing comma in your dictionaries, *especially* when they're defined on
+multiple lines, because it will make adding new entries less error-prone.
+
+Indexing
+--------
+
+To look up a key in a dictionary you use the same syntax as most languages. Run
+this command:
+
+ :echo {'a': 1, 100: 'foo',}['a']
+
+Vim displays `1`. Try it with a non-string index:
+
+ :echo {'a': 1, 100: 'foo',}[100]
+
+Vim coerces the index to a string before performing the lookup, which makes
+sense since keys can only ever be strings.
+
+Vimscript also supports the Javascript-style "dot" lookup when the key is
+a string consisting only of letters, digits and/or underscores. Try the
+following commands:
+
+ :echo {'a': 1, 100: 'foo',}.a
+ :echo {'a': 1, 100: 'foo',}.100
+
+Vim displays the correct element in both cases. How you choose to index your
+dictionaries is a matter of taste and style.
+
+Assigning and Adding
+--------------------
+
+Adding entries to dictionaries is done by simply assigning them like variables.
+Run this command:
+
+ :let foo = {'a': 1}
+ :let foo.a = 100
+ :let foo.b = 200
+ :echo foo
+
+Vim displays `{'a': 100, 'b': 200}`, which shows that assigning and adding
+entries both work the same way.
+
+Removing Entries
+----------------
+
+There are two ways to remove entries from a dictionary. Run the following
+commands:
+
+ :let test = remove(foo, 'a')
+ :unlet foo.b
+ :echo foo
+ :echo test
+
+Vim displays `{}` and `100`. The `remove` function will remove the entry with
+the given key from the given dictionary and return the removed value. The
+`unlet` command also removes dictionary entries, but you can't use the value.
+
+You cannot remove nonexistent entries from a dictionary. Try running this
+command:
+
+ :unlet foo["asdf"]
+
+Vim throws an error.
+
+The choice of `remove` or `unlet` is mostly a matter of personal taste. If
+pressed I'd recommend using `remove` everywhere because it's more flexible than
+`unlet`. `remove` can do anything `unlet` can do but the reverse isn't true, so
+you can always be consistent if you use `remove`.
+
+Dictionary Functions
+--------------------
+
+Like lists, Vim has a number of built-in functions for working with
+dictionaries. Run the following command:
+
+ :echom get({'a': 100}, 'a', 'default')
+ :echom get({'a': 100}, 'b', 'default')
+
+Vim displays `100` and `default`, just like the `get` function for lists.
+
+You can also check if a given key is present in a given dictionary. Run this
+commands:
+
+ :echom has_key({'a': 100}, 'a')
+ :echom has_key({'a': 100}, 'b')
+
+Vim displays `1` and `0`. Remember that Vimscript treats `0` as falsy and any
+other number as truthy.
+
+You can pull the key-value pairs out of a dictionary with `items`. Run this
+command:
+
+ :echo items({'a': 100, 'b': 200})
+
+Vim will display a nested list that looks something like `[['a', 100], ['b',
+200]]`. As far as I can tell Vimscript dictionaries are *not* guaranteed to be
+ordered, so don't expect that the items you get out of an `items` call will be
+in a specific order!
+
+You can get just the keys or just the values with the `keys` and `values`
+functions. They work as expected -- look them up.
+
+Exercises
+---------
+
+Read `:help Dictionary`. All of it. Notice the capital "D".
+
+Read `:help get()`.
+
+Read `:help has_key()`.
+
+Read `:help items()`.
+
+Read `:help keys()`.
+
+Read `:help values()`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/38.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,200 @@
+Toggling
+========
+
+In one of the first chapters we talked about how to set options in Vim. For
+boolean options we can use `set someoption!` to "toggle" the option. This is
+expecially nice when we create a mapping for that command.
+
+Run the following command:
+
+ :nnoremap <leader>N :setlocal number!<cr>
+
+Try it out by pressing `<leader>N` in normal mode. Vim will toggle the line
+numbers for the current window off and on. Creating a "toggle" mapping like
+this is really handy, because we don't need to have two separate keys to turn
+something off and on.
+
+Unfortunately this only works for boolean options. If we want to toggle
+a non-boolean option we'll need to do a bit more work.
+
+Toggling Options
+----------------
+
+Let's start by creating a function that will toggle an option for us, and
+a mapping that will call it. Put the following into your `~/.vimrc` file (or
+a separate file in `~/.vim/plugin/` if you prefer):
+
+ nnoremap <c-f> :call FoldColumnToggle()<cr>
+
+ function! FoldColumnToggle()
+ echom &foldcolumn
+ endfunction
+
+Write and source the file, then try it out by pressing `<c-f>`. Vim will
+display the current value of the `foldcolumn` option. Go ahead and read `:help
+foldcolumn` if you're unfamiliar with this option.
+
+Let's add in the actual toggling functionality. Edit the code to look like
+this:
+
+ nnoremap <c-f> :call FoldColumnToggle()<cr>
+
+ function! FoldColumnToggle()
+ if &foldcolumn
+ setlocal foldcolumn=0
+ else
+ setlocal foldcolumn=4
+ endif
+ endfunction
+
+Write and source the file and try it out. Each time you press it Vim will
+either show or hide the fold column.
+
+The `if` statement simply checks if `&foldcolumn` is truthy (remember that Vim
+treats the integer 0 as falsy and any other number as truthy). If so, it sets
+it to zero (which hides it). Otherwise it sets it to four. Pretty simple.
+
+You can use a simple function like this to toggle any option where `0` means
+"off" and any other number is "on".
+
+Toggling Other Things
+---------------------
+
+Options aren't the only thing we might want to toggle. One particularly nice
+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:
+
+ nnoremap <c-q> :call QuickfixToggle()<cr>
+
+ function! QuickfixToggle()
+ return
+ endfunction
+
+This mapping doesn't do anything yet. Let's transform it into something
+slightly more useful (but not completely finished yet). Change the code to
+look like this:
+
+ nnoremap <c-q> :call QuickfixToggle()<cr>
+
+ function! QuickfixToggle()
+ copen
+ endfunction
+
+Write and source the file. If you try out the mapping now you'll see that it
+simply opens the quickfix window.
+
+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:
+
+ nnoremap <c-q> :call QuickfixToggle()<cr>
+
+ function! QuickfixToggle()
+ if g:quickfix_is_open
+ cclose
+ let g:quickfix_is_open = 0
+ else
+ copen
+ let g:quickfix_is_open = 1
+ endif
+ endfunction
+
+What we've done is pretty simple -- we're simply storing a global variable
+describing the open/closed state of the quickfix window whenever we call the
+function.
+
+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:
+
+ nnoremap <c-q> :call QuickfixToggle()<cr>
+
+ let g:quickfix_is_open = 0
+
+ function! QuickfixToggle()
+ if g:quickfix_is_open
+ cclose
+ let g:quickfix_is_open = 0
+ else
+ copen
+ let g:quickfix_is_open = 1
+ endif
+ endfunction
+
+Write and source the file, and try the mapping. It works!
+
+Improvements
+------------
+
+Our toggle function works, but has a few problems.
+
+The first is that if the user manually opens or closes the window with `:copen`
+or `:cclose` our global variable doesn't get updated. This isn't really a huge
+problem in practice because most of the time the user will probably be opening
+the window with the mapping, and if not they can always just press it again.
+
+This illustrates an important point about writing Vimscript code: if you try to
+handle every single edge case you'll get bogged down in it and never get any
+work done.
+
+Getting something that works most of the time (and doesn't explode when it
+doesn't work) and getting back to coding is usually better than spending hours
+getting it 100% perfect. The exception is when you're writing a plugin you
+expect many people to use. In that case it's best to spend the time and make it
+bulletproof to keep your users happy and reduce bug reports.
+
+Restoring Windows/Buffers
+-------------------------
+
+The other problem with our function is that if the user runs the mapping when
+they're already in the quickfix window, Vim closes it and dumps them into the
+last split instead of sending them back where they were. This is annoying if
+you just want to check the quickfix window really quick and get back to working.
+
+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:
+
+ nnoremap <c-q> :call QuickfixToggle()<cr>
+
+ let g:quickfix_is_open = 0
+
+ function! QuickfixToggle()
+ if g:quickfix_is_open
+ cclose
+ let g:quickfix_is_open = 0
+ execute g:quickfix_return_to_window . "wincmd w"
+ else
+ let g:quickfix_return_to_window = winnr()
+ copen
+ let g:quickfix_is_open = 1
+ endif
+ endfunction
+
+We've added two new lines in this mapping. One of them (in the `else` clause)
+sets another global variable which saves the current window number before we run
+`:copen`.
+
+The second line (in the `if` clause) executes `wincmd w` with that number
+prepended as a count, which tells Vim to go to that window.
+
+Once again our solution isn't bulletproof, because the user might open or close
+new split between runs of the mapping. Even so, it handles the majority of
+cases so it's good enough for now.
+
+This strategy of manually saving global state would be frowned upon in most
+serious programs, but for tiny little Vimscript functions it's a quick and dirty
+way of getting something mostly working and moving on with your life.
+
+Exercises
+---------
+
+Read `:help foldcolumn`.
+
+Read `:help winnr()`
+
+Read `:help ctrl-w_w`.
+
+Read `:help wincmd`.
+
+Read `:help ctrl-q` and `:help ctrl-f` to see what you overwrote with these
+mappings.
+
+Namespace the functions by adding `s:` and `<SID>` where necessary.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/39.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,228 @@
+Functional Programming
+======================
+
+We're going to take a short break now to talk about a style of programming you
+may have heard of: [functional programming][].
+
+If you've programmed in languages like Python, Ruby or Javascript, or
+*especially* Lisp, Scheme, Clojure or Haskell, you're probably familiar with the
+idea of using functions as variables and using data structures with immutable
+state. If you've never done this before you can safely skip this chapter, but
+I'd encourage you to try it anyway and broaden your horizons!
+
+Vimscript has all the pieces necessary to program in a kind-of-functional style,
+but it's a bit clunky. We can create a few helpers that will make it less
+painful though.
+
+Go ahead and create a `functional.vim` file somewhere so you don't have to keep
+typing everything over and over. This file will be our scratchpad for this
+chapter.
+
+[functional programming]: https://secure.wikimedia.org/wikipedia/en/wiki/Functional_programming
+
+Immutable Data Structures
+-------------------------
+
+Unfortunately Vim doesn't have any immutable collections like Clojure's vectors
+and maps built-in, but by creating some helper functions we can fake it to some
+degree.
+
+Add the following function to your file:
+
+ function! Sorted(l)
+ let new_list = deepcopy(a:l)
+ call sort(new_list)
+ return new_list
+ endfunction
+
+Source and write the file, then run `:echo Sorted([3, 2, 4, 1])` to try it out.
+Vim echoes `[1, 2, 3, 4]`.
+
+How is this different from simply calling the built-in `sort()` function? The
+key is the first line: `let new_list = deepcopy(a:l)`. Vim's `sort()` sorts the
+list *in place*, so we first create a full copy of the list and sort *that* so
+the original list won't be changed.
+
+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:
+
+ function! Reversed(l)
+ let new_list = deepcopy(a:l)
+ call reverse(new_list)
+ return new_list
+ endfunction
+
+ function! Append(l, val)
+ let new_list = deepcopy(a:l)
+ call add(new_list, a:val)
+ return new_list
+ endfunction
+
+ function! Assoc(l, i, val)
+ let new_list = deepcopy(a:l)
+ let newlist[a:i] = a:val
+ return new_list
+ endfunction
+
+ function! Pop(l, i)
+ let new_list = deepcopy(a:l)
+ call remove(new_list, a:i)
+ return new_list
+ endfunction
+
+Each of these functions is exactly the same except for the middle line and the
+arguments they take. Source and write the file and try them out on a few lists.
+
+`Reversed()` takes a list and returns a new list with the elements reversed.
+
+`Append()` returns a new list with the given value appended to the end of the
+old one.
+
+`Assoc()` (short for "associate") returns a new list, with the element at the
+given index replaced by the new value.
+
+`Pop()` returns a new list with the element at the given index removed.
+
+Functions as Variables
+----------------------
+
+Vimscript supports using variables to store functions, but the syntax is a bit
+obtuse. Run the following commands:
+
+ :let Myfunc = function("Append")
+ :echo Myfunc([1, 2], 3)
+
+Vim will display `[1, 2, 3]` as expected. Notice that the variable we used
+started with a capital letter. If a Vimscript variable refers to a function it
+must start with a capital letter.
+
+Functions can be stored in lists just like any other kind of variable. Run the
+following commands:
+
+ :let funcs = [function("Append"), function("Pop")]
+ :echo funcs[1](['a', 'b', 'c'], 1)
+
+Vim displays `['a', 'c']`. The `funcs` variable does *not* need to start with
+a capital letter because it's storing a list, not a function. The contents of
+the list don't matter at all.
+
+Higher-Order Functions
+----------------------
+
+Let's create a few of the most commonly-used higher-order functions. If you're
+not familiar with that term, higher-order functions are functions that take
+*other* functions and do something with them.
+
+We'll begin with the trusty "map" function. Add this to your file:
+
+ function! Mapped(fn, l)
+ let new_list = deepcopy(a:l)
+ call map(new_list, string(a:fn) . '(v:val)')
+ return new_list
+ endfunction
+
+Source and write the file, and try it out by running the following commands:
+
+ :let mylist = [[1, 2], [3, 4]]
+ :echo Mapped(function("Reversed"), mylist)
+
+Vim displays `[[2, 1], [4, 3]]`, which is the results of applying `Reversed()`
+to every element in the list.
+
+How does `Mapped()` work? Once again we create a fresh list with `deepcopy()`,
+do something to it, and return the modified copy -- nothing new there. The
+tricky part is the middle.
+
+`Mapped()` takes two arguments: a funcref (Vim's term for "variable holding
+a function") and a list. We use the built-in `map()` function to perform the
+actual work. Read `:help map()` now to see how it works.
+
+Now we'll create a few other common higher-order functions. Add the following to
+your file:
+
+ function! Filtered(fn, l)
+ let new_list = deepcopy(a:l)
+ call filter(new_list, string(a:fn) . '(v:val)')
+ return new_list
+ endfunction
+
+Try `Filtered()` out with the following commands:
+
+ :let mylist = [[1, 2], [], ['foo'], []]
+ :echo Filtered(function('len'), mylist)
+
+Vim displays `[[1, 2], ['foo']]`.
+
+`Filtered()` takes a predicate function and a list. It returns a copy of the
+list that contains only the elements of the original where the result of calling
+the function on it is "truthy". In this case we use the built-in `len()`
+function, so it filters out all the elements whose length is zero.
+
+Finally we'll create the counterpart to `Filtered()`:
+
+ function! Removed(fn, l)
+ let new_list = deepcopy(a:l)
+ call filter(new_list, '!' . string(a:fn) . '(v:val)')
+ return new_list
+ endfunction
+
+Try it out just like we did with `Filtered()`:
+
+ :let mylist = [[1, 2], [], ['foo'], []]
+ :echo Removed(function('len'), mylist)
+
+Vim displays `[[], []]`. `Removed()` is like `Filtered()` except it only keeps
+elements where the predicate function does *not* return something truthy.
+
+The only difference in the code is the single `'!' . ` we added to the call
+command, which negates the result of the predicate.
+
+Performance
+-----------
+
+You might be thinking that copying lists all over the place is wasteful, since
+Vim has to constantly create new copies and garbage collect old ones.
+
+If so: you're right! Vim's lists don't support the same kind of structural
+sharing as Clojure's vectors, so all those copy operations can be expensive.
+
+Sometimes this will matter. If you're working with enormous lists, things can
+slow down. In real life, though, you might be surprised at how little you'll
+actually notice the difference.
+
+Consider this: as I'm writing this chapter my Vim program is using about 80
+megabytes of memory (and I have a *lot* of plugins installed). My laptop has
+8 *gigabytes* of memory in it. Is the overhead of having a few copies of a list
+around really going to make a noticeable difference? Of course that depends on
+the size of the list, but in most cases the answer will be "no".
+
+To contrast, my Firefox instance with five tabs open is currently using 1.22
+*gigabytes* of RAM.
+
+You'll need to use your own judgement about when this style of programming
+creates unacceptably bad performance. I'd *strongly* encourage you to at least
+give it a fair try though. Using immutable data structures and higher order
+functions can greatly simplify your code and eliminate lots of state-related
+bugs.
+
+Exercises
+---------
+
+Read `:help sort()`.
+
+Read `:help reverse()`.
+
+Read `:help copy()`.
+
+Read `:help deepcopy()`.
+
+Read `:help map()` if you haven't already.
+
+Read `:help function()`.
+
+Modify `Assoc()`, `Pop()`, `Mapped()`, `Filtered()` and `Removed()` to support
+dictionaries. You'll probably need `:help type()` for this.
+
+Implement `Reduced()`.
+
+Pour yourself a glass of your favorite drink. This chapter was intense!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/40.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,80 @@
+Paths
+=====
+
+Vim is a text editor, and text editors (usually) work with text files. Text
+files live on filesystems, and to specify files we use paths. Vimscript has
+a few built-in utilities that can be extremely helpful when you need to work
+with paths.
+
+Absolute Paths
+--------------
+
+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:
+
+ :echom expand('%')
+ :echom expand('%:p')
+ :echom fnamemodify('foo.txt', ':p')
+
+The first command displays the relative path of whatever file you're currently
+editing. `%` means "the current file". Vim supports a bunch of other strings
+you can use with `expand()` as well.
+
+The second command displays the full, absolute path of that file. The `:p` in
+the string tells Vim that you want the absolute path. There are a ton of other
+modifiers you can use.
+
+The third command displays an absolute path to the file `foo.txt` in the current
+directory, regardless of whether that file actually exists. `fnamemodify()` is
+a Vim function that's more flexible than `expand()` in that you can specify any
+file name, not just one of `expand()`'s special strings.
+
+Listing Files
+-------------
+
+You might also want to get a listing of files in a specific directory. Run the
+following command:
+
+ :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:
+
+ :echo split(globpath('.', '*'), '\n')
+
+This time Vim displays a Vimscript list containing each path. If you've got
+newlines in your filenames you're on your own, sorry.
+
+`globpath()`'s wildcards work mostly as you would expect. Run the following
+command:
+
+ :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:
+
+ :echo split(globpath('.', '**'), '\n')
+
+Vim will list all files and directories under the current directory.
+
+`globpath()` is *extremely* powerful. You'll learn more when you complete this
+chapter's exercises.
+
+Exercises
+---------
+
+Read `:help expand()`.
+
+Read `:help fnamemodify()`.
+
+Read `:help filename-modifiers`.
+
+Read `:help simplify()`.
+
+Read `:help resolve()`.
+
+Read `:help globpath()`.
+
+Read `:help wildcards`.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/41.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,59 @@
+Creating a Full Plugin
+======================
+
+We've covered a lot of ground in the last forty or so chapters. In the final
+part of the book we're going to walk through creating a Vim plugin for
+a language from scratch.
+
+This is not for the faint of heart. It's going to take a lot of effort.
+
+If you want to stop now, that's completely fine! You've already learned enough
+to make serious enhancements to your own `~/.vimrc` file and to fix bugs you
+find in other people's plugins.
+
+There's no shame in saying "that's enough for me -- I don't want to spend hours
+of my life creating plugins I won't use very often". Be practical. If you
+can't think of a full plugin you want to make, stop now and come back when you
+do.
+
+If you *do* want to continue make sure you're ready to devote some time. The
+rest of the book is going to be intense, and I'm going to assume you actually
+want to *learn*, not just coast through the chapters reading them on your couch.
+
+Potion
+------
+
+The plugin we're going to make is going to add support for the [Potion][]
+programming language.
+
+Potion is a toy language created by \_why the lucky stiff before his
+disappearance. It's an extremely small language which makes it ideal for our
+purposes.
+
+Potion feels a lot like [Io][], with some ideas from Ruby, Lua and other
+languages mixed in. If you've never tried Io it may seem weird. I strongly
+recommend playing with Potion for at least an hour or two. You won't use it in
+real life, but it might change the way you think and expose you to new ideas.
+
+The current implementation of Potion has a lot of rough edges. For example: if
+you mess up the syntax it usually segfaults. Try not to get too hung up on this
+-- I'll provide you with lots of sample code that works so you can focus mostly
+on the Vimscript and not Potion.
+
+The goal is not to learn Potion (though I think doing so *will* make you
+a better programmer). The goal is to use Potion as a small example so we can
+touch on a lot of different aspects of writing Vim plugins.
+
+Exercises
+---------
+
+Download and install [Potion][]. You're on your own for this one. It should be
+fairly simple.
+
+Make sure you can get the first couple examples in the pamphlet working in the
+Potion interpreter and by putting them in a `.pn` file. If it seems like the
+interpreter isn't working check out [this
+issue](https://github.com/fogus/potion/issues/12) for a possible cause.
+
+[Potion]: http://fogus.github.com/potion/index.html
+[Io]: http://iolanguage.com/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/42.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,129 @@
+Plugin Layout in the Dark Ages
+==============================
+
+The first thing we need to talk about is how to structure our plugin. In the
+past this was a messy affair, but now there's a tool that makes the process of
+installing Vim plugins much, *much* saner.
+
+We need to go over the basic layout first, then we'll talk about how to restore
+our sanity.
+
+Basic Layout
+------------
+
+Vanilla Vim supports splitting plugins into multiple files. There are a number
+of different directories you can create under `~/.vim` that mean various things.
+
+We'll cover the most important directories now, but don't stress out too much
+about them. We'll go over them one at a time as we create our Potion plugin.
+
+Before we continue we need to talk about some vocabulary.
+
+I've been using the word "plugin" to mean "a big ol' hunk of Vimscript that does
+a bunch of related stuff". Vim has a more specific meaning of "plugin", which
+is "a file in `~/.vim/plugins/`".
+
+Most of the time I'll be using the first definition, but if something is unclear
+please [let me know](http://twitter.com/stevelosh/) and I'll try to reword it.
+
+~/.vim/colors/
+--------------
+
+Files inside `~/.vim/colors/` are treated as color schemes. For example: if you
+run `:color mycolors` Vim will look for a file at `~/.vim/colors/mycolors.vim`
+and run it. That file should contain all the Vimscript commands necessary to
+generate your color scheme.
+
+We're not going to cover color schemes in this book. If you want to create your
+own you should copy an existing scheme and modify it. Remember that `:help` is
+your friend.
+
+~/.vim/plugin/
+--------------
+
+Files inside `~/.vim/plugin/` will each be run once *every time* Vim starts.
+These files are meant to contain code that you always want loaded whenever you
+start Vim.
+
+~/.vim/ftdetect/
+----------------
+
+Any files in `~/.vim/ftdetect/` will *also* be run every time you start Vim.
+
+"ftdetect" stands for "filetype detection". The files in this directory should
+set up autocommands that detect and set the `filetype` of files, and *nothing
+else*. This means they should never be more than one or two lines long.
+
+~/.vim/ftplugin/
+----------------
+
+Files in `~/.vim/ftplugin/` are different.
+
+The naming of these files matters. When Vim sets a buffer's `filetype` to
+a value it then looks for a file in `~/.vim/ftplugin/` that matches. For
+example: if you run `set filetype=derp` Vim will look for
+`~/.vim/ftplugin/derp.vim`. If that file exists, it will run it.
+
+Vim also supports directories inside `~/.vim/ftplugin/`. To continue our
+example: `set filetype=derp` will also make Vim run any and all `*.vim` files
+inside `~/.vim/ftplugin/derp/`. This lets you split up your plugin's `ftplugin`
+files into logical groups.
+
+Because these files are run every time a buffer's `filetype` is set they *must*
+only set buffer-local options! If they set options globally they would
+overwrite them for all open buffers!
+
+~/.vim/indent/
+--------------
+
+Files in `~/.vim/indent/` are a lot like `ftplugin` files -- they get loaded
+based on their names.
+
+`indent` files should set options related to indentation for their filetypes,
+and those options should be buffer-local.
+
+Yes, you could simply put this code in the `ftplugin` files, but it's better to
+separate it out so other Vim users will understand what you're doing. It's just
+a convention, but please be a considerate plugin author and follow it.
+
+~/.vim/compiler/
+----------------
+
+Files in `~/.vim/compiler/` work exactly like `indent` files. They should set
+compiler-related options in the current buffer based on their names.
+
+Don't worry about what "compiler-related options" means right now. We'll cover
+that later.
+
+~/.vim/after/
+-------------
+
+The `~/.vim/after/` directory is a bit of a hack. Files in this directory will
+be loaded every time Vim starts, but *after* the files in `~/.vim/plugin/`.
+
+This allows you to override Vim's internal files. In practice you'll rarely
+need this, so don't worry about it until you find yourself thinking "Vim sets
+option X and I want something different".
+
+~/.vim/autoload/
+----------------
+
+The `~/.vim/autoload/` directory is an incredibly important hack. It sounds
+a lot more complicated than it actually is.
+
+In a nutshell: `autoload` is a way to delay the loading of your plugin's code
+until it's actually needed. We'll cover this in more detail later when we
+refactor our plugin's code to take advantage of it.
+
+~/.vim/doc/
+-----------
+
+Finally, the `~/.vim/doc/` directory is where you can add documentation for your
+plugin. Vim has a huge focus on documentation (as evidenced by all the `:help`
+commands we've been running) so it's important to document your plugins.
+
+Exercises
+---------
+
+Reread this chapter. I'm not kidding. Make sure you understand (in a very
+rough way) what each directory we've talked about does.
--- a/outline.org Sun Oct 16 11:00:24 2011 +0400
+++ b/outline.org Sun Nov 13 17:59:27 2011 -0500
@@ -25,21 +25,26 @@
** DONE functions
** DONE function arguments
** DONE numbers
-** TODO strings
-** TODO string functions
-** TODO regexes
-** TODO normal!
-** TODO execute
-** TODO execute normal!
-** TODO lists
-** TODO looping
-** TODO dictionaries
-** TODO paths
+** DONE strings
+** DONE string functions
+** DONE normal!
+** DONE execute
+** DONE execute normal!
+** DONE basic regexes
+** DONE Case Study: GrepMotion
+** DONE lists
+** DONE looping
+** DONE dictionaries
+** DONE toggling
+** DONE functional programming
+** DONE paths
+** TODO advanced regexes
** TODO exceptions
** TODO functions again
** TODO command!
* part 3 - creating a full plugin
-** TODO intro and plugin layout
+** TODO intro
+** TODO plugin layout
** TODO pathogen
** TODO autoload
** TODO folding
--- a/preface.markdown Sun Oct 16 11:00:24 2011 +0400
+++ b/preface.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -6,9 +6,10 @@
That text gets turned into numbers and those numbers bump into other numbers
and *make things happen*.
-To get our ideas out of our heads and the chunks of text we call "programs" we
-use text editors. Full-time programmers will easily spend thousands of hours
-of their lives interacting with their text editor doing many things:
+To get our ideas out of our heads and create the chunks of text we call
+"programs" we use text editors. Full-time programmers will easily spend tens of
+thousands of hours of their lives interacting with their text editor doing many
+things:
* Getting raw text from brains into computers.
* Correcting mistakes in that text.
@@ -25,11 +26,26 @@
Along the way I'll also mention things that aren't strictly about Vimscript, but
are more about learning and being more efficient in general. Learning Vimscript
isn't going to help you much if you wind up fiddling with your editor all day
-instead of working, so you must strike a balance.
+instead of working, so you have to strike a balance.
+
+The style of this book is a bit different from most other books about
+programming languages. Instead of simply presenting you with facts about how
+Vimscript works, it guides you through typing in commands to see what they do.
+
+Frequently the book will lead you into dead ends before explaining the "right
+way" to solve a problem. Most other books don't do this, or only mention the
+sticky issues *after* showing you the solution.
+
+This isn't how things typically happen in the real world, though. Most of the
+time you'll be whipping up a quick piece of Vimscript and run into a quirk of
+the language that you'll need to figure out. By stepping through this process
+in the book instead of glossing over it I hope to get you used to the process of
+dealing with Vimscript's silliness so you're ready when you find other edge
+cases. Practice makes perfect.
Each chapter of the book focuses on a single topic. They're short but packed
with information, so don't just skim them. If you really want to learn the most
-you can from this book, you need to *type in* all of the commands.
+you can you need to *type in* all of the commands.
You may already be an experienced programmer who's used to reading code and
understanding it straight away. If so: it doesn't matter. Learning Vim and
@@ -39,19 +55,22 @@
**Do *all* the exercises.**
-Vimscript is old and has a lot of dusty corners and twisty hallways. One
-configuration option can change how the entire language works.
-
-By typing *every* command in *every* lesson exercise and doing *every* exercise
-you'll discover problems with your Vim build or configuration on the simpler
-commands, which will be easier to diagnose and fix.
+There are two reasons this is so important. First, Vimscript is old and has
+a lot of dusty corners and twisty hallways. One configuration option can change
+how the entire language works. By typing *every* command in *every* lesson
+exercise and doing *every* exercise you'll discover problems with your Vim build
+or configuration on the simpler commands, which will be easier to diagnose and
+fix.
Second, Vimscript *is* Vim. To save a file in Vim, you type `:write` (or `:w`
for short) and press return. To save a file in a Vimscript, you use `write`.
-Mastering a text editor means developing muscle memory, which you simply can't
-get from just reading.
+Many of the Vimscript commands you'll learn can be used in your day-to-day
+editing as well, but they're only helpful if they're in your muscle memory,
+which simply doesn't happen from just reading.
I hope you'll find this book useful. It's *not* meant to be a comprehensive
guide to Vimscript. It's meant to get you comfortable enough with the language
-to read other people's code (with regular side-trips to `:help`) and recognize
-some common pitfalls.
+to write some simple plugins, read other people's code (with regular side-trips
+to `:help`), and recognize some of the common pitfalls.
+
+Good luck!
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/proofreader-volunteers.txt Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,7 @@
+@rhdoenges
+@elazar
+@chartjes
+@robhudson
+@cemicolon
+@execat
+@alesplin
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/scratch.markdown Sun Nov 13 17:59:27 2011 -0500
@@ -0,0 +1,19 @@
+Line Continuation
+-----------------
+
+We're going to stray from the topic for a moment to talk about coding style.
+Put the following code into your `~/.vimrc` file:
+
+ echom "foo" .
+ \ "bar" .
+ \ "baz"
+
+Restart Vim and run `:messages` to see that Vim echoed "foobarbaz" to the
+messages log.
+
+A backslash at the beginning of a line in a Vimscript file tells Vim that this
+line is a continuation of the previous one. This is unlike Python where the
+backslash goes at the *end* of the first line, instead of the beginning of the
+second.
+
+This lets you split long lines for easier readability.