# HG changeset patch # User Steve Losh # Date 1323307012 18000 # Node ID e66e6a4e104d3e57814263813114995e61609958 # Parent d96929307215c4e54fca5c1e1c546b12f2649184 Add syntax highlighting markers. diff -r d96929307215 -r e66e6a4e104d chapters/01.markdown --- a/chapters/01.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/01.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -9,6 +9,7 @@ Run the following command: + :::vim :echo "Hello, world!" You should see `Hello, world!` appear at the bottom of the window. @@ -18,12 +19,14 @@ Now run the following command: + :::vim :echom "Hello again, world!" You should see `Hello again, world!` appear at the bottom of the window. To see the difference between these two commands, run one more new command: + :::vim :messages You should see a list of messages. `Hello, world!` will *not* be in this list, @@ -42,6 +45,7 @@ your `~/.vimrc` file or another one) you can add comments with the `"` character, like this: + :::vim " Make space more useful nnoremap za diff -r d96929307215 -r e66e6a4e104d chapters/02.markdown --- a/chapters/02.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/02.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,10 +8,12 @@ Run the following command: + :::vim :set number Line numbers should appear in Vim. Now run this: + :::vim :set nonumber The line numbers should disappear. `number` is a boolean option -- it can be @@ -24,10 +26,12 @@ You can also "toggle" boolean options to set them to the *opposite* of whatever they are now. Run this: + :::vim :set number! The line numbers should reappear. Now run it again: + :::vim :set number! They should disappear once more. Adding a `!` (exclamation point or "bang") to @@ -39,6 +43,7 @@ You can ask Vim what an option is currently set to by using a `?`. Run these commands and watch what happens after each: + :::vim :set number :set number? :set nonumber @@ -53,6 +58,7 @@ Some options take a value instead of just being off or on. Run the following commands and watch what happens after each: + :::vim :set number :set numberwidth=10 :set numberwidth=4 @@ -63,6 +69,7 @@ Try checking what a few other common options are set to: + :::vim :set wrap? :set numberwidth? @@ -72,6 +79,7 @@ Finally, you can specify more than one option in the same `:set` command. Try running this: + :::vim :set number numberwidth=6 Exercises diff -r d96929307215 -r e66e6a4e104d chapters/03.markdown --- a/chapters/03.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/03.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -10,6 +10,7 @@ Type a few lines of text into a file, then run: + :::vim :map \ x Put your cursor somewhere in the text and press `\`. Notice how Vim deleted the @@ -18,6 +19,7 @@ We already have a key for "delete that character under the cursor", so let's change that mapping to something slightly more useful. Run this command: + :::vim :map \ dd Now put your cursor on a line somewhere and press `\` again. This time Vim @@ -29,6 +31,7 @@ You can use `` to tell Vim about special keys that are hard to type. Try running this command: + :::vim :map 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 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 viw " Use space to select a word If you try pressing `` now, something horrible will almost certainly diff -r d96929307215 -r e66e6a4e104d chapters/04.markdown --- a/chapters/04.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/04.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -12,7 +12,8 @@ Run this command: - nmap \ dd + :::vim + :nmap \ dd Now put your cursor in your text file, make sure you're in normal mode, and press `\`. Vim will delete the current line. @@ -23,7 +24,8 @@ Run this command: - vmap \ U + :::vim + :vmap \ U Enter visual mode and select some text, then press `\`. Vim will convert the text to uppercase! @@ -50,7 +52,8 @@ Now that we've covered how to map keys in normal and visual mode, let's move on to insert mode. Run this command: - imap dd + :::vim + :imap 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 dd + :::vim + :imap dd The `` 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 ddi + :::vim + :imap ddi The `i` at the end reenters insert mode for us, and our mapping is finally complete. diff -r d96929307215 -r e66e6a4e104d chapters/05.markdown --- a/chapters/05.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/05.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,6 +8,7 @@ Run the following commands: + :::vim :nmap - dd :nmap \ - @@ -26,6 +27,7 @@ Run this command: + :::vim :nmap dd Ojddk 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 diff -r d96929307215 -r e66e6a4e104d chapters/06.markdown --- a/chapters/06.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/06.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -21,6 +21,7 @@ Unlike Emacs, Vim makes it easy to map more than just single keys. Run these commands: + :::vim :nnoremap -d dd :nnoremap -c ddO @@ -42,6 +43,7 @@ Vim calls this "prefix" key "leader". You can set your leader key to whatever you like. Run this command: + :::vim :let mapleader = "-" You can replace `-` with any key you like. I personally like `,` even though it @@ -50,6 +52,7 @@ When you're creating new mappings you can use `` to mean "whatever I have my leader key set to". Run this command: + :::vim :nnoremap 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 diff -r d96929307215 -r e66e6a4e104d chapters/07.markdown --- a/chapters/07.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/07.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -22,6 +22,7 @@ Lets add a mapping that will open our `~/.vimrc` file in a split so we can edit it and get back to coding. Run this command: + :::vim :nnoremap ev :vsplit $MYVIMRC 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 sv :source $MYVIMRC I like to think of this command as "**s**ource my **v**imrc file". diff -r d96929307215 -r e66e6a4e104d chapters/08.markdown --- a/chapters/08.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/08.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,10 +8,12 @@ We're only going to worry about insert mode abbreviations in this book. Run the following command: + :::vim :iabbrev adn and Now enter insert mode and type: + :::text One adn two. As soon as you hit space after typing the "adn" Vim will replace it with "and". @@ -19,11 +21,13 @@ Correcting typos like this is a great use for abbreviations. Run these commands: + :::vim :iabbrev waht what :iabbrev tehn then Now enter insert mode again and type: + :::text Well, I don't know waht we should do tehn. Notice how *both* abbreviations were substituted, even though you didn't type @@ -36,6 +40,7 @@ after an abbreviation. "Non-keyword character" means any character not in the `iskeyword` option. Run this command: + :::vim :set iskeyword? You should see something like `iskeyword=@,48-57,_,192-255`. This format is @@ -63,6 +68,7 @@ Abbreviations are useful for more than just correcting typos. Let's add a few more that can help in day-to-day text editing. Run the following commands: + :::vim :iabbrev @@ steve@stevelosh.com :iabbrev ccopy Copyright 2011 Steve Losh, all rights reserved. @@ -82,6 +88,7 @@ Run this command: + :::vim :inoremap ssig --Steve Loshsteve@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 --Steve Loshsteve@stevelosh.com diff -r d96929307215 -r e66e6a4e104d chapters/09.markdown --- a/chapters/09.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/09.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -10,6 +10,7 @@ Run the following command: + :::vim :nnoremap jk dd Now make sure you're in normal mode and press `j` followed quickly by `k`. Vim @@ -22,6 +23,7 @@ This mapping will make it painful to move around our file, so lets remove it. Run the following command: + :::vim :nunmap jk Now typing `jk` in normal mode will move down and then up a line as usual. @@ -32,6 +34,7 @@ You've seen a bunch of simple mappings so far, so it's time to look at something with a bit more meat to it. Run the following command: + :::vim :nnoremap " viwa"hbi"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 viwa"hbi"lel * `viw`: visually select the current word diff -r d96929307215 -r e66e6a4e104d chapters/10.markdown --- a/chapters/10.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/10.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -7,6 +7,7 @@ Let's set up one more mapping that will save more wear on your left hand than any other mapping you ever create. Run the following command: + :::vim :inoremap jk 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 This effectively disables the escape key in insert mode by telling Vim to diff -r d96929307215 -r e66e6a4e104d chapters/11.markdown --- a/chapters/11.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/11.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -17,6 +17,7 @@ Switch to file `foo` and run the following commands: + :::vim :nnoremap d dd :nnoremap 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 Q x :nnoremap Q dd diff -r d96929307215 -r e66e6a4e104d chapters/12.markdown --- a/chapters/12.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/12.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -15,6 +15,7 @@ Let's change it so that Vim creates files as soon as you edit them. Run the following command: + :::vim :autocmd BufNewFile * :write This is a lot to take in, but try it out and see that it works. Run `:edit foo` @@ -29,6 +30,7 @@ Let's take a closer look at the autocommand we just created: + :::text :autocmd BufNewFile * :write ^ ^ ^ | | | @@ -55,6 +57,7 @@ when you want the command to fire. Start up a new Vim instance and run the following command: + :::vim :autocmd BufNewFile *.txt :write This is almost the same as the last command, but this time it will only apply to @@ -76,6 +79,7 @@ Let's define another autocommand, this time using a different event. Run the following command: + :::vim :autocmd BufWrite *.html :normal gg=G We're getting a bit ahead of ourselves here because we're going to talk about @@ -85,6 +89,7 @@ Create a new file called `foo.html`. Edit it with Vim and enter the following text *exactly*, including the whitespace: + :::html

Hello!

@@ -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 c I// :autocmd FileType python nnoremap c I# diff -r d96929307215 -r e66e6a4e104d chapters/13.markdown --- a/chapters/13.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/13.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,10 +8,12 @@ Open your `foo` and `bar` files again, switch to `foo`, and run the following command: + :::vim :iabbrev --- — 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 iff if ( ) {} :autocmd FileType python :iabbrev iff if: diff -r d96929307215 -r e66e6a4e104d chapters/14.markdown --- a/chapters/14.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/14.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -3,6 +3,7 @@ A few chapters ago we learned about autocommands. Run the following command: + :::vim :autocmd BufWrite * :echom "Writing buffer!" Now write your current buffer with `:write` and run `:messages` to view the @@ -13,6 +14,7 @@ Now run the exact same autocommand again: + :::vim :autocmd BufWrite * :echom "Writing buffer!" Write your current buffer one more time and run `:messages`. You will see the @@ -35,11 +37,13 @@ To simulate this, try running the following command: + :::vim :autocmd BufWrite * :sleep 200m Now write the file. You may or may not notice a slight sluggishness in Vim's writing time. Now run the command three more times: + :::vim :autocmd BufWrite * :sleep 200m :autocmd BufWrite * :sleep 200m :autocmd BufWrite * :sleep 200m @@ -60,6 +64,7 @@ Open a fresh instance of Vim to clear out the autocommands from before, then run the following commands: + :::vim :augroup testgroup : autocmd BufWrite * :echom "Foo" : autocmd BufWrite * :echom "Bar" @@ -71,6 +76,7 @@ Write a buffer and check `:messages`. You should see both "Foo" and "Bar". Now run the following commands: + :::vim :augroup testgroup : autocmd BufWrite * :echom "Baz" :augroup END @@ -92,6 +98,7 @@ If you want to *clear* a group you can use `autocmd!` inside the group. Run the following commands: + :::vim :augroup testgroup : autocmd! : autocmd BufWrite * :echom "Cats" @@ -109,6 +116,7 @@ Add the follow to your `~/.vimrc` file: + :::vim augroup filetype_html autocmd! autocmd FileType html nnoremap f Vatzf diff -r d96929307215 -r e66e6a4e104d chapters/15.markdown --- a/chapters/15.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/15.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -11,6 +11,7 @@ Some examples of operators are `d`, `y`, and `c`. For example: + :::text Operator vvvvvv dw " Delete to next word @@ -22,10 +23,12 @@ Vim lets you create new movements that work with all existing commands. Run the following command: + :::vim :onoremap p i( Now type the follow text into a buffer: + :::python return person.get_pets(type="cat", fluffy_only=True) Put your cursor on the word "cat" and type `dp`. What happened? Vim deleted @@ -40,6 +43,7 @@ We can use this new mapping immediately with all operators. Type the same text as before into the buffer (or simply undo the change): + :::python return person.get_pets(type="cat", fluffy_only=True) Put your cursor on the word "cat" and type `cp`. What happened? Vim deleted @@ -48,10 +52,12 @@ Let's try another example. Run the following command: + :::vim :onoremap b /return 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( :normal! f(vi( 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( :normal! F)vi( 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( `: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: diff -r d96929307215 -r e66e6a4e104d chapters/16.markdown --- a/chapters/16.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/16.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -10,6 +10,7 @@ before, don't worry, for our purposes here it's very simple. Type the following into a file: + :::markdown Topic One ========= @@ -26,6 +27,7 @@ Lets create some mappings that let us target headings with movements. Run the following command: + :::vim :onoremap ih :execute "normal! ?^==\\+$\r:nohlsearch\rkvg_" 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_" 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 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! ?^==\+$:nohlsearchkvg_ ^^^^ ^^^^ || || @@ -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 :execute "normal! ?^==\\+\r:nohlsearch\rg_vk0" 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 :execute "normal! ?^==\\+$\r:nohlsearch\rkvg_" :onoremap ah :execute "normal! ?^==\\+$\r:nohlsearch\rg_vk0" The only difference from the previous mapping is the very end, where we select the text to operate on: + :::vim kvg_ g_vk0 diff -r d96929307215 -r e66e6a4e104d chapters/17.markdown --- a/chapters/17.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/17.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -5,11 +5,13 @@ window. This is done through the `statusline` option. Run the following command: + :::vim :set statusline=%f You should see the path to the file (relative to the current directory) in the status line. Now run this command: + :::vim :set statusline=%f\ -\ FileType:\ %y Now you'll see something like "foo.markdown - FileType: [markdown]" in the @@ -28,6 +30,7 @@ Status lines can get extremely complicated very quickly, so there's a better way to set them that will let us be more clear. Run the following commands: + :::vim :set statusline=%f " Path to the file :set statusline+=\ -\ " Separator :set statusline+=FileType: " Label @@ -40,6 +43,7 @@ Run the following command: + :::vim :set statusline=%l " Current line :set statusline+=/ " Separator :set statusline+=%L " Total lines @@ -53,6 +57,7 @@ Additional characters can be used in some of the various `%` codes to change how the information is displayed. Run the following command: + :::vim :set statusline=%4l The line number in the status line will now be proceeded by enough spaces to @@ -62,19 +67,23 @@ By default the padding spaces are added on the left side of the value. Run this command: + :::vim :set statusline=Current:\ %4l\ Total:\ %4L Your status line will now look like this: + :::text Current: 12 Total: 223 You can use `-` to place padding on the right instead of the left. Run this command: + :::vim :set statusline=Current:\ %-4l\ Total:\ %-4L Your status line will now look like this: + :::text Current: 12 Total: 223 This looks much nicer because the numbers are next to their labels. @@ -82,6 +91,7 @@ For codes that result in a number you can tell Vim to pad with zeros instead of spaces. Run the following command: + :::vim :set statusline=%04l Now your status line will read "0012" when on line twelve. @@ -89,15 +99,18 @@ Finally, you can also set the maximum width of a code's output. Run this command: + :::vim :set statusline=%F `%F` displays the *full* path to the current file. Now run this command to change the maximum width: + :::vim :set statusline=%.20F The path will be truncated if necessary, looking something like this: + :::text 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" diff -r d96929307215 -r e66e6a4e104d chapters/23.markdown --- a/chapters/23.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/23.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -6,6 +6,7 @@ Run the following commands: + :::vim :function meow() You might think this would start defining a function named `Meow`. @@ -20,24 +21,28 @@ Okay, let's define a function for real this time. Run the following commands: + :::vim :function Meow() : echom "Meow!" :endfunction This time Vim will happily define the function. Let's try running it: + :::vim :call Meow() Vim will display "Meow!" as expected. Let's try returning a value. Run the following commands: + :::vim :function GetMeow() : return "Meow String!" :endfunction Now try it out by running this command: + :::vim :echom GetMeow() Vim will call the function and give the result to `echom`, which will display @@ -52,6 +57,7 @@ When you want to call a function directly you use the `call` command. Run the following commands: + :::vim :call Meow() :call GetMeow() @@ -62,6 +68,7 @@ The second way to call functions is in expressions. You don't need to use `call` in this case, you can just name the function. Run the following command: + :::vim :echom GetMeow() As we saw before, this calls `GetMeow` and passes the return value to `echom`. @@ -71,6 +78,7 @@ Run the following command: + :::vim :echom Meow() This will display two lines: "Meow!" and "0". The first obviously comes from @@ -78,6 +86,7 @@ doesn't return a value, it implicitly return `0`. Let's use this to our advantage. Run the following commands: + :::vim :function TextwidthIsTooWide() : if &l:numberwidth ># 80 : return 1 @@ -100,6 +109,7 @@ Let's try using it. Run the following commands: + :::vim :set textwidth=80 :if TextwidthIsTooWide() : echom "WARNING: Wide text!" @@ -114,6 +124,7 @@ Because we never explicitly returned a value, Vim returned `0` from the function, which is falsy. Let's try changing that. Run the following commands: + :::vim :setlocal textwidth=100 :if TextwidthIsTooWide() : echom "WARNING: Wide text!" diff -r d96929307215 -r e66e6a4e104d chapters/24.markdown --- a/chapters/24.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/24.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -3,6 +3,7 @@ Vimscript functions can, of course, take arguments. Run the following commands: + :::vim :function DisplayName(name) : echom "Hello! My name is:" : echom a:name @@ -10,6 +11,7 @@ Run the function: + :::vim :call DisplayName("Your Name") Vim will display two lines: "Hello! My name is:" and "Your Name". @@ -21,6 +23,7 @@ Let's remove this scope prefix and see how Vim reacts. Run the following commands: + :::vim :function UnscopedDisplayName(name) : echom "Hello! My name is:" : echom name @@ -39,6 +42,7 @@ Vimscript functions can optionally take variable-length argument lists like Javascript and Python. Run the following commands: + :::vim :function Varg(...) : echom a:0 : echom a:1 @@ -69,6 +73,7 @@ You can use varargs together with regular arguments too. Run the following commands: + :::vim :function Varg2(foo, ...) : echom a:foo : echom a:0 @@ -86,6 +91,7 @@ Try running the following commands: + :::vim :function Assign(foo) : let a:foo = "Nope" : echom a:foo @@ -96,6 +102,7 @@ Vim will throw an error, because you can't reassign argument variables. Now run these commands: + :::vim :function AssignGood(foo) : let foo_tmp = a:foo : let foo_tmp = "Yep" diff -r d96929307215 -r e66e6a4e104d chapters/25.markdown --- a/chapters/25.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/25.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -12,20 +12,24 @@ You can specify Numbers in a few different ways. Run the following command. + :::vim :echom 100 No surprises here -- Vim displays "100". Now run this command: + :::vim :echom 0xff This time Vim displays "255". You can specify numbers in hex notation by prefixing them with `0x` or `0X`. Now run this command: + :::vim :echom 010 You can also use octal by starting a number with a `0`. Be careful with this, because it's easy to make mistakes. Try the following commands: + :::vim :echom 017 :echom 019 @@ -41,6 +45,7 @@ Floats can also be specified in multiple ways. Run the following command: + :::vim :echo 100.1 Notice that we're using `echo` here and not `echom` like we usually to. We'll @@ -49,20 +54,24 @@ Vim displays "100.1" as expected. You can also use exponential notation. Run this command: + :::vim :echo 5.45e+3 Vim displays "5450.0". A negative exponent can also be used. Run this command: + :::vim :echo 15.45e-2 Vim displays "0.1545". The `+` or `-` before the power of ten is optional, if it's omitted the it's assumed to be positive. Run the following command: + :::vim :echo 15.3e9 Vim will display "1.53e10", which is equivalent. The decimal point and number after it are *not* optional. Run the following command and see that it crashes: + :::vim :echo 5e10 Coercion @@ -72,6 +81,7 @@ other operation Vim will cast the Number to a Float, resulting in a Float. Run the following command: + :::vim :echo 2 * 2.0 Vim displays "4.0". @@ -81,12 +91,14 @@ When dividing two Numbers, the remainder is dropped. Run the following command: + :::vim :echo 3 / 2 Vim displays "1". If you want Vim to perform float point division one of the numbers needs to be a Float, which will cause the other one to be coerced to a Float as well. Run this command: + :::vim :echo 3 / 2.0 Vim displays "1.5". The "3" is coerced to a Float, and then normal floating diff -r d96929307215 -r e66e6a4e104d chapters/26.markdown --- a/chapters/26.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/26.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -6,6 +6,7 @@ Run the following command: + :::vim :echom "Hello" Vim will echo "Hello". So far, so good. @@ -16,6 +17,7 @@ One of the most common things you'll want to do with strings is adding them together. Run this command: + :::vim :echom "Hello, " + "world" What happened? Vim displayed "0" for some reason! @@ -24,6 +26,7 @@ a string to `+` Vim will try to coerce it to a Number before performing the addition. Run the following command: + :::vim :echom "3 mice" + "2 cats" This time Vim displays "5", because the strings are coerced to the numbers "3" @@ -32,6 +35,7 @@ When I said "Number" I really *meant* Number. Vim will *not* coerce strings to Floats! Try this command to see prove this: + :::vim :echom 10 + "10.10" Vim displays "20" because it dropped everything after the decimal point when @@ -40,6 +44,7 @@ To combine strings you need to use the concatenation operator. Run the following command: + :::vim :echom "Hello, " . "world" This time Vim displays "Hello, world". `.` is the "concatenate strings" @@ -48,12 +53,14 @@ Coercion works both ways. Kind of. Try this command: + :::vim :echom 10 . "foo" Vim will display "10foo". First it coerces `10` to a String, then it concatenates it with the string on the right hand side. Things get a bit stickier when we're working with Floats, though. Run this command: + :::vim :echom 10.1 . "foo" This time Vim throws an error, saying we're using a Float as a String. Vim will @@ -75,23 +82,27 @@ Like most programming languages, Vimscript lets you use escape sequences in strings to represent hard-to-type characters. Run the following command: + :::vim :echom "foo \"bar\"" The `\"` in the string is replaced with a double quote character, as you would probably expect. Escape sequences work mostly as you would expect. Run the following command: + :::vim :echom "foo\\bar" Vim displays `foo\bar`, because `\\` is the escape sequence for a literal backslash, just like in most programming languages. Now run the following command (note that it's an `echo` and *not* an `echom`): + :::vim :echo "foo\nbar" This time Vim will display two lines, "foo" and "bar", because the `\n` is replaced with a newline. Now try running this command: + :::vim :echom "foo\nbar" Vim will display something like "foo^@bar". When you use `echom` with a String @@ -105,12 +116,14 @@ Vim also lets you use "literal strings" to avoid excessive use of escape sequences. Run the following command: + :::vim :echom '\n\\' Vim displays `\n\\`. Using single quotes tells Vim that you want the string *exactly* as-in, with no escape sequences. The one exception is that two single quotes in a row will produce a single single quote. Try this command: + :::vim :echom 'That''s enough.' Vim will display "That's enough." Two single quotes is the *only* sequence that @@ -125,6 +138,7 @@ You might be wondering how Vim treats strings when used in an `if` statement. Run the following command: + :::vim :if "foo" : echo "yes" :else diff -r d96929307215 -r e66e6a4e104d chapters/27.markdown --- a/chapters/27.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/27.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -9,11 +9,13 @@ The first function we'll look at is `strlen`. Run the following command: + :::vim :echom strlen("foo") Vim displays "3", which is the length of the string "foo". Now try the following command: + :::vim :echom len("foo") Vim once again displays "3". When used with Strings `len` and `strlen` have @@ -24,6 +26,7 @@ Run the following command (note that it's an `echo` and not an `echom`): + :::vim :echo split("one two three") Vim displays "['one', 'two', 'three']". The `split` function splits a String @@ -33,6 +36,7 @@ You can also tell Vim to use a separator other than "whitespace" for splitting. Run the following command: + :::vim :echo split("one,two,three", ",") Vim will once again display "['one', 'two', 'three']", because the second @@ -45,12 +49,14 @@ Not only can you split strings, you can also join them. Run the following command: + :::vim :echo join(["foo", "bar"], "...") Vim will display "foo...bar". Don't worry about the list syntax for now. `split` and `join` can be paired to great effect. Run the following command: + :::vim :echo join(split("foo bar"), ";") Vim displays "foo;bar". First we split the string "foo bar" into a list, then @@ -62,6 +68,7 @@ Vim has two functions to change the case of Strings. Run the following commands: + :::vim :echom tolower("Foo") :echom toupper("Foo") diff -r d96929307215 -r e66e6a4e104d chapters/28.markdown --- a/chapters/28.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/28.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -4,6 +4,7 @@ The `execute` command is used to evaluate a string as if it were a Vimscript command. Run the following command: + :::vim :execute "echom 'Hello, world!'" Vim evaluates `echom 'Hello, world!'` as a command and dutifully echoes it to @@ -14,6 +15,7 @@ `:edit "foo.txt"` in the same window to open a new buffer. Now run the following command: + :::vim :execute "rightbelow vsplit " . bufname("#") Vim will open the first file in a vertical split to the right of the second diff -r d96929307215 -r e66e6a4e104d chapters/29.markdown --- a/chapters/29.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/29.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -7,11 +7,13 @@ The answer is: "of course". Run the following command: + :::vim :normal G Vim will move your cursor to the last line in the current file, just like pressing `G` in normal mode would. Now run the following command: + :::vim :normal ggdd Vim will move to the first line in the file (`gg`) and then delete it (`dd`). @@ -24,10 +26,12 @@ Run the following command to map the `G` key to something else: + :::vim :nnoremap G dd Now pressing `G` in normal mode will delete a line. Try this command: + :::vim :normal G Vim will delete the current line. The `normal` command will take into account @@ -39,6 +43,7 @@ Luckily Vim has a `normal!` command that does exactly this. Run this command: + :::vim :normal! G This time Vim moves to the bottom of the file even though `G` has been mapped. @@ -53,6 +58,7 @@ If you play around with `normal!` long enough you'll probably notice a problem. Try the following command: + :::vim :normal! /foo At first glance it may seem like this should perform a search for "foo", but diff -r d96929307215 -r e66e6a4e104d chapters/30.markdown --- a/chapters/30.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/30.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -4,6 +4,7 @@ Now that we've seen `execute` and `normal!` we can talk about a common Vimscript idiom. Run the following command: + :::vim :execute "normal! gg/foo\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;\`q" What does this do? Let's break it apart: diff -r d96929307215 -r e66e6a4e104d chapters/31.markdown --- a/chapters/31.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/31.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -7,6 +7,7 @@ Type the following text into a buffer: + :::python max = 10 print "Starting" @@ -30,6 +31,7 @@ Before we start we need to turn on search highlighting so we can see what we're doing. Run the following command: + :::vim :set hlsearch incsearch `hlsearch` tells Vim to highlight all matches in a file when you perform @@ -41,6 +43,7 @@ Put your cursor at the top of the file and run the following command: + :::vim /print As you type in each letter, Vim will start highlighting them in the first line. @@ -49,6 +52,7 @@ Now try running the following command: + :::vim :execute "normal! gg/print\" 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\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\" 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 .+:\" 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 .\\+:\" 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 .\+:\' 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 .\+:' . "\" 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 .+:' . "\" We've split the pattern out from the rest of the command into its own literal diff -r d96929307215 -r e66e6a4e104d chapters/32.markdown --- a/chapters/32.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/32.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -68,6 +68,7 @@ We'll start with a skeleton of the mapping and fill it in as we go. Run this command: + :::vim :nnoremap g :grep -R something . 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 g :grep -R . Now try it out. `` is a special bit of text you can use in Vim's @@ -90,6 +92,7 @@ You can use `` to get a WORD instead of a word. Run this command: + :::vim :nnoremap g :grep -R . 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 g :grep -R '' . 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 g :execute "grep -R '' ." 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 g :execute "grep -R " . shellescape("") . " ." 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 g :execute "grep! -R " . shellescape("") . " ." 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 g :execute "grep! -R " . shellescape("") . " .":copen 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 g :silent execute "grep! -R " . shellescape("") . " .":copen We're done, so try it out and admire your hard work! The `silent` command just diff -r d96929307215 -r e66e6a4e104d chapters/33.markdown --- a/chapters/33.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/33.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -39,6 +39,7 @@ To create a new Vim operator you'll start with two components: a function and a mapping. Start by adding the following code to `grep-operator.vim`: + :::vim nnoremap g :set operatorfunc=GrepOperatorg@ 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 g :call GrepOperator(visualmode()) Write and source the file. Now visually select something and press `g`. @@ -94,6 +96,7 @@ Edit the function body so the file looks like this: + :::vim nnoremap g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) @@ -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 g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) @@ -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 g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) @@ -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 g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) diff -r d96929307215 -r e66e6a4e104d chapters/34.markdown --- a/chapters/34.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/34.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -16,6 +16,7 @@ before we yank and restore it after we've done. Change the code to look like this: + :::vim nnoremap g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) @@ -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 g :set operatorfunc=GrepOperatorg@ vnoremap g :call GrepOperator(visualmode()) diff -r d96929307215 -r e66e6a4e104d chapters/35.markdown --- a/chapters/35.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/35.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,11 +8,13 @@ Vimscript lists are ordered, heterogeneous collections of elements. Run the following command: + :::vim :echo ['foo', 3, 'bar'] Vim displays the list. Lists can of course be nested. Run the following command: + :::vim :echo ['foo', [3, 'bar']] Vim happily displays the list. @@ -23,11 +25,13 @@ Vimscript lists are zero-indexed, and you can get at the elements in the usual way. Run this command: + :::vim :echo [0, [1, 2]][1] Vim displays "[1, 2]". You can also index from the end of the list, much like Python. Try this command: + :::vim :echo [0, [1, 2]][-2] Vim displays `0`. The index `-1` refers to the last element in the list, `-2` @@ -39,17 +43,20 @@ Vim lists can also be sliced. This will *look* familiar to Python programmers, but it does *not* always act the same way! Run this command: + :::vim :echo ['a', 'b', 'c', 'd', 'e'][0:2] Vim displays "['a', 'b', 'c']" (elements 0, 1 and 2). You can safely exceed the upper bound as well. Try this command: + :::vim :echo ['a', 'b', 'c', 'd', 'e'][0:100000] Vim simply displays the entire list. Slice indexes can be negative. Try this command: + :::vim :echo ['a', 'b', 'c', 'd', 'e'][-2:-1] Vim displays "['d', 'e']" (elements -2 and -1). @@ -57,6 +64,7 @@ When slicing lists you can leave off the first index to mean "the beginning" and/or the last index to mean "the end". Run the following commands: + :::vim :echo ['a', 'b', 'c', 'd', 'e'][:1] :echo ['a', 'b', 'c', 'd', 'e'][3:] @@ -65,6 +73,7 @@ Like Python, Vimscript allows you to index and slice strings too. Run the following command: + :::vim :echo "abcd"[0:2] Vim displays "abc". @@ -74,7 +83,8 @@ You can combine Vim lists with `+`. Try this command: - echo ['a', 'b'] + ['c'] + :::vim + :echo ['a', 'b'] + ['c'] Vim, unsurprisingly, displays "['a', 'b', 'c']". There's not much else to say here -- Vimscript lists are surprisingly sane compared to the rest of the @@ -86,6 +96,7 @@ Vim has a number of built-in functions for working with lists. Run these commands: + :::vim :let foo = ['a'] :call add(foo, 'b') :echo foo @@ -93,10 +104,12 @@ Vim mutates the list `foo` in-place to append `'b'` and displays "['a', 'b']". Now run this command: + :::vim :echo len(foo) Vim displays "2", the length of the list. Try these commands: + :::vim :echo get(foo, 0, 'default') :echo get(foo, 100, 'default') @@ -106,6 +119,7 @@ Run this command: + :::vim :echo index(foo, 'b') :echo index(foo, 'nope') @@ -114,6 +128,7 @@ Now run this command: + :::vim :echo join(foo) :echo join(foo, '---') :echo join([1, 2, 3], '') @@ -124,6 +139,7 @@ Run the following commands: + :::vim :call reverse(foo) :echo foo :call reverse(foo) diff -r d96929307215 -r e66e6a4e104d chapters/36.markdown --- a/chapters/36.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/36.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -16,6 +16,7 @@ Java, C or Javascript `for` loops, but turns out to be quite elegant. Run the following commands: + :::vim :let c = 0 :for i in [1, 2, 3, 4] @@ -36,6 +37,7 @@ Vim also supports the classic `while` loop. Run the following commands: + :::vim :let c = 1 :let total = 0 diff -r d96929307215 -r e66e6a4e104d chapters/37.markdown --- a/chapters/37.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/37.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -11,6 +11,7 @@ Run this command: + :::vim :echo {'a': 1, 100: 'foo'} Vim displays `{'a': 1, '100': 'foo'}`, which shows that Vimscript does indeed @@ -19,6 +20,7 @@ Vimscript avoids the stupidity of the Javascript standard and lets you use a comma after the last element in a dictionary. Run the following command: + :::vim :echo {'a': 1, 100: 'foo',} Once again Vim displays `{'a': 1, '100': 'foo'}`. You should *always* use the @@ -31,10 +33,12 @@ To look up a key in a dictionary you use the same syntax as most languages. Run this command: + :::vim :echo {'a': 1, 100: 'foo',}['a'] Vim displays `1`. Try it with a non-string index: + :::vim :echo {'a': 1, 100: 'foo',}[100] Vim coerces the index to a string before performing the lookup, which makes @@ -44,6 +48,7 @@ a string consisting only of letters, digits and/or underscores. Try the following commands: + :::vim :echo {'a': 1, 100: 'foo',}.a :echo {'a': 1, 100: 'foo',}.100 @@ -56,6 +61,7 @@ Adding entries to dictionaries is done by simply assigning them like variables. Run this command: + :::vim :let foo = {'a': 1} :let foo.a = 100 :let foo.b = 200 @@ -70,6 +76,7 @@ There are two ways to remove entries from a dictionary. Run the following commands: + :::vim :let test = remove(foo, 'a') :unlet foo.b :echo foo @@ -82,6 +89,7 @@ You cannot remove nonexistent entries from a dictionary. Try running this command: + :::vim :unlet foo["asdf"] Vim throws an error. @@ -97,6 +105,7 @@ Like lists, Vim has a number of built-in functions for working with dictionaries. Run the following command: + :::vim :echom get({'a': 100}, 'a', 'default') :echom get({'a': 100}, 'b', 'default') @@ -105,6 +114,7 @@ You can also check if a given key is present in a given dictionary. Run this commands: + :::vim :echom has_key({'a': 100}, 'a') :echom has_key({'a': 100}, 'b') @@ -114,6 +124,7 @@ You can pull the key-value pairs out of a dictionary with `items`. Run this command: + :::vim :echo items({'a': 100, 'b': 200}) Vim will display a nested list that looks something like `[['a', 100], ['b', diff -r d96929307215 -r e66e6a4e104d chapters/38.markdown --- a/chapters/38.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/38.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -7,6 +7,7 @@ Run the following command: + :::vim :nnoremap N :setlocal number! Try it out by pressing `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 :call FoldColumnToggle() function! FoldColumnToggle() @@ -37,6 +39,7 @@ Let's add in the actual toggling functionality. Edit the code to look like this: + :::vim nnoremap :call FoldColumnToggle() 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 :call QuickfixToggle() function! QuickfixToggle() @@ -74,6 +78,7 @@ slightly more useful (but not completely finished yet). Change the code to look like this: + :::vim nnoremap :call QuickfixToggle() 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 :call QuickfixToggle() 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 :call QuickfixToggle() 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 :call QuickfixToggle() let g:quickfix_is_open = 0 diff -r d96929307215 -r e66e6a4e104d chapters/39.markdown --- a/chapters/39.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/39.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -29,6 +29,7 @@ Add the following function to your file: + :::vim function! Sorted(l) let new_list = deepcopy(a:l) call sort(new_list) @@ -46,6 +47,7 @@ This prevents side effects and helps us write code that is easier to reason about and test. Let's add a few more helper functions in this same style: + :::vim function! Reversed(l) let new_list = deepcopy(a:l) call reverse(new_list) @@ -89,6 +91,7 @@ Vimscript supports using variables to store functions, but the syntax is a bit obtuse. Run the following commands: + :::vim :let Myfunc = function("Append") :echo Myfunc([1, 2], 3) @@ -99,6 +102,7 @@ Functions can be stored in lists just like any other kind of variable. Run the following commands: + :::vim :let funcs = [function("Append"), function("Pop")] :echo funcs[1](['a', 'b', 'c'], 1) @@ -115,6 +119,7 @@ We'll begin with the trusty "map" function. Add this to your file: + :::vim function! Mapped(fn, l) let new_list = deepcopy(a:l) call map(new_list, string(a:fn) . '(v:val)') @@ -123,6 +128,7 @@ Source and write the file, and try it out by running the following commands: + :::vim :let mylist = [[1, 2], [3, 4]] :echo Mapped(function("Reversed"), mylist) @@ -140,6 +146,7 @@ Now we'll create a few other common higher-order functions. Add the following to your file: + :::vim function! Filtered(fn, l) let new_list = deepcopy(a:l) call filter(new_list, string(a:fn) . '(v:val)') @@ -148,6 +155,7 @@ Try `Filtered()` out with the following commands: + :::vim :let mylist = [[1, 2], [], ['foo'], []] :echo Filtered(function('len'), mylist) @@ -160,6 +168,7 @@ Finally we'll create the counterpart to `Filtered()`: + :::vim function! Removed(fn, l) let new_list = deepcopy(a:l) call filter(new_list, '!' . string(a:fn) . '(v:val)') @@ -168,6 +177,7 @@ Try it out just like we did with `Filtered()`: + :::vim :let mylist = [[1, 2], [], ['foo'], []] :echo Removed(function('len'), mylist) diff -r d96929307215 -r e66e6a4e104d chapters/40.markdown --- a/chapters/40.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/40.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -12,6 +12,7 @@ Sometimes it's handy to be able to get the absolute path of a certain file for use with external scripts. Run the following commands: + :::vim :echom expand('%') :echom expand('%:p') :echom fnamemodify('foo.txt', ':p') @@ -35,12 +36,14 @@ You might also want to get a listing of files in a specific directory. Run the following command: + :::vim :echo globpath('.', '*') Vim will display all of the files and directories in the current directory. The `globpath()` function returns a string, with each name separated by a newline. To get a list you'll need to `split()` it yourself. Run this command: + :::vim :echo split(globpath('.', '*'), '\n') This time Vim displays a Vimscript list containing each path. If you've got @@ -49,12 +52,14 @@ `globpath()`'s wildcards work mostly as you would expect. Run the following command: + :::vim :echo split(globpath('.', '*.txt'), '\n') Vim displays a list of all `.txt` files in the current directory. You can recursively list files with `**`. Run this command: + :::vim :echo split(globpath('.', '**'), '\n') Vim will list all files and directories under the current directory. diff -r d96929307215 -r e66e6a4e104d chapters/43.markdown --- a/chapters/43.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/43.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -41,16 +41,19 @@ called `mycolor.vim` (you can leave it empty for this demonstration). Open Vim and run this command: + :::vim :color mycolor Vim will display an error, because it doesn't know to look on your Desktop for files. Now run this command: + :::vim :set runtimepath=/Users/sjl/Desktop You'll need to change the path to match the path of your own Desktop, of course. Now try the color command again: + :::vim :color mycolor This time Vim doesn't throw an error, because it was able to find the @@ -85,6 +88,7 @@ Our plugin's repository will wind up looking like this: + :::text potion/ README LICENSE @@ -115,5 +119,3 @@ Push the repository up to Bitbucket or GitHub. Read `:help runtimepath`. - - diff -r d96929307215 -r e66e6a4e104d chapters/44.markdown --- a/chapters/44.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/44.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -5,6 +5,7 @@ plugin. Create a `factorial.pn` file somewhere and put the following Potion code inside it: + :::text factorial = (n): total = 1 n to 1 (i): @@ -21,6 +22,7 @@ the results each time. Go ahead and run it with `potion factorial.pn`. The output should look like this: + :::text 0! is: 0 1! is: 1 2! is: 2 @@ -44,6 +46,7 @@ Open `factorial.pn` in Vim and run the following command: + :::vim :set filetype? Vim will display `filetype=` because it doesn't know what a `.pn` file is yet. @@ -52,6 +55,7 @@ Create `ftdetect/potion.vim` in your plugin's repo. Put the following lines into it: + :::vim au BufNewFile,BufRead *.pn set filetype=potion This creates a single autocommand: a command to set the filetype of `.pn` files @@ -64,6 +68,7 @@ Close the `factorial.pn` file and reopen it. Now run the previous command again: + :::vim :set filetype? This time Vim displays `filetype=potion`. When Vim started up it loaded the diff -r d96929307215 -r e66e6a4e104d chapters/45.markdown --- a/chapters/45.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/45.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -8,6 +8,7 @@ Create a `syntax/potion.vim` file in your plugin's repo. Put the following code into the file: + :::vim if exists("b:current_syntax") finish endif @@ -36,6 +37,7 @@ Replace the placeholder `echom` in the file with the following code: + :::vim syntax keyword potionKeyword to times highlight link potionKeyword Keyword @@ -59,6 +61,7 @@ Potion has a bunch of other keywords that we haven't used in our toy program, so lets edit our syntax file to highlight those too: + :::vim syntax keyword potionKeyword loop times to while syntax keyword potionKeyword if elsif else syntax keyword potionKeyword class return @@ -89,6 +92,7 @@ built-in Potion functions to our highlighting script. Edit the guts of your syntax file so it looks like this: + :::vim syntax keyword potionKeyword loop times to while syntax keyword potionKeyword if elsif else syntax keyword potionKeyword class return diff -r d96929307215 -r e66e6a4e104d chapters/46.markdown --- a/chapters/46.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/46.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -27,6 +27,7 @@ match it (and the rest of the comment). We'll do this with `syntax match` instead of `syntax keyword`. Add the following lines to your syntax file: + :::vim syntax match potionComment "\v#.*$" highlight link potionComment Comment @@ -64,6 +65,7 @@ Another part of Potion we need regexes to highlight is operators. Add the following to your syntax file: + :::vim syntax match potionOperator "\v\*\=" syntax match potionOperator "\v/\=" syntax match potionOperator "\v\+\=" @@ -114,6 +116,7 @@ Let's go ahead and add `=` as an operator, now that we've had our lesson: + :::vim syntax match potionOperator "\v\=" Take a second and think about where you need to put this in the syntax file. diff -r d96929307215 -r e66e6a4e104d chapters/47.markdown --- a/chapters/47.markdown Wed Nov 16 20:50:32 2011 -0500 +++ b/chapters/47.markdown Wed Dec 07 20:16:52 2011 -0500 @@ -14,6 +14,7 @@ world!"`. We should highlight these as strings. To do this we'll use the `syntax region` command. Add the following to your Potion syntax file: + :::vim syntax region potionString start=/\v"/ skip=/\v\\./ end=/\v"/ highlight link potionString String