[Chapter 31] 31.4 vi @-Functions
Author: Jerry Peek, Tim O'Reilly & Mike Loukides
Date: 1998-08-04T21:46:12Z

#

| Chapter 31 Creating Custom Commands in vi |

## 31.4 vi @-Functions

The vi map command (31.2) lets you define keymaps: short names for a series of one or more other commands. You can enter `:map` to define a keymap while you're editing a file with vi. But if you make a mistake, you usually have to re-enter the whole `:map` command to correct the problem.

`@`-functions (say "at-functions") give you another way to define complex commands. You can define 26 `@`-functions named `@a` through `@z`. They're stored in named buffers (30.5). So if you're also using named buffers for copying and pasting text, you'll need to share them with your `@`-functions.

### 31.4.1 Defining and Using Simple @-Functions

To define an `@`-function:

1. Enter the command(s) you want to execute onto one or more lines of the file you're editing.

2. Yank or delete the line(s) into a named buffer with a command like `"ay$` or `"bD`.

3. To use the function, type a command like `@a` or `@b`. You can repeat the function by typing `@@` or a dot (`.`). Use `u` or `U` to undo the effects of the `@`-function.

Here's an example. You're editing a long HTML file with lines like these:

>     <STRONG>Some heading here</STRONG>
>     <STRONG>Another heading here</STRONG>

When you see one of those lines, you need to change the `STRONG`s to either `H3` or `H4`. A global substitution with `:%s` won't do the job because some lines need `H3` and others need `H4`; you have to decide line-by-line as you work through the file. So you define the function `@a` to change a line to `H3`, and `@b` to change to `H4`.

To design an `@`-function, start by thinking how you'd make the changes by hand. You'd probably move to the start of the line with `0`, move to the right one character with `l`, type `cw` to change the word `STRONG`, and type in `H3` (or `H4`). Then press ESC to return to command mode. Go to the end of the line with `$`, move to the character after the slash with `T/`, then change the second `STRONG` the way you fixed the first one.

To define the function, open a new empty line of your file (go into text-input mode). Then type the keystrokes that will make the `H3` changes; type CTRL-v before each ESC or RETURN (31.6). When you're done, press ESC again to go to command mode. Because the commands for the `H4` change are similar, the easiest way to make them is by copying and pasting the line for `H3` (by typing `yy` and `p`)-then edit the copy. The pair of command lines should look like this (where `^[` stands for the `[CTRL-v]` `[ESC]` keys):

>     0lcwH3^[$T/cwH3^[
>     0lcwH4^[$T/cwH4^[

Move to the start of the first line and delete it into the a buffer by typing `"aD`. Go to the next line and type `"bD`. (This will leave two empty lines; delete them with `dd` if you'd like.) Now, when you type `@a`, it will execute the commands to change a line to `H3`; typing `@b` on a line will change it to have `H4`. Move through your file (maybe with a search: `/STRONG` ... `n` ...), typing `@a` or `@b` as you go. Or use `@@` to make the same change you made on a previous line.

### 31.4.2 Combining @-Functions

An `@`-function can execute other `@`-functions. For example, here are four lines ready for storing as `@a` through `@d`:

>     0l@c$T/@c   ...becomes @a
>     0l@d$T/@d   ...becomes @b
>     cwH3^[   ...becomes @c
>     cwH4^[   ...becomes @d

See that the definition of `@a` has `@c` in it twice? When you execute `@a`, it will do `0l` to move to the second character on the line, then do `@c` to change the word to `H3`, move to the end of the line and use `@c` again. Calling one `@`-function from another can save re-typing repetitive commands.

A disadvantage is that `@@` won't always work as you might expect. If you type `@a` to make a change in one place, then move somewhere else and type `@@`, the `@@` will do what `@c` does (instead of what you might have wanted, `@a`). That's because the `@a` function finishes by doing a `@c`.

### 31.4.3 Reusing a Definition

You don't have to delete the definition line into a buffer with `dd`. If you think you might need to fine-tune the command, you can yank (copy) it into a buffer with a command like `"ay$`. Then, if you need to revise the command, re-edit the line and type `"ay$` to put the revised version into the buffer. Or use `"by$` to copy the revised line into another buffer.

### 31.4.4 Newlines in an @-Function

Stored `@`-functions can span multiple lines. For example, if you delete the following four lines with `"z4dd`, typing `@z` will open a new line below (`o`) and insert four new lines of text:

>     oThis is the new line one.
>     This is the new line two.
>     This is the third line.
>     This is the fourth.^[

After you execute the function with `@z`, your cursor will move to the line below the new fourth line. Why? Because you included the newlines (RETURNs) in the buffer; each RETURN moves down a line - including the RETURN after the last ESC.

If you don't want that, there are two ways to fix it:

- Delete the first three lines, including the newlines, into the buffer by typing `"z3dd`. Delete the fourth line, without its newline, and append it to the buffer by typing `"ZD`. (An uppercase letter like `Z` appends to a named buffer. `D` deletes all of a line except the newline.)

  Some versions of vi will delete four lines, without the last newline, when you use `"z4D`.

- Type all of the text onto a single line; embed the newlines in that line by typing `[CTRL-v]` `[RETURN]` between each finished line. It'll look like this:

  >     oThis is the new line one.^MThis is the new line two.^MThis is the new...

  Delete that long line into your buffer with `"zD`. Because `D` doesn't delete the final newline, your cursor will stay at the end of the fourth new line after you execute the `@z`.

- JP

31.3 What You Lose When You Use map! |  | 31.5 Keymaps for Pasting into a Window Running vi