ae64d9c11fe7

Execute, normal
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Tue, 25 Oct 2011 00:00:19 -0400
parents 8a5c406b39b8
children 274674dc2025
branches/tags (none)
files chapters/28.markdown chapters/29.markdown chapters/30.markdown

Changes

--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/chapters/28.markdown	Tue Oct 25 00:00:19 2011 -0400
@@ -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	Tue Oct 25 00:00:19 2011 -0400
@@ -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	Tue Oct 25 00:00:19 2011 -0400
@@ -0,0 +1,2 @@
+Execute Normal!
+===============