[comp.unix.questions] VI Summary and intro to macro writing

" Smith) (01/22/88)

	Here it is... I will follow up in a few weeks or so, some of this
material needs to be explained better, but I did want to get this out
now.

				dan

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by ceylon!daniel on Thu Jan 21 08:22:47 PST 1988
# Contents:  README vicoms.doc macros.doc sample_exrc
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
	Wow. Enough mail reached me to justify posting this. This is
a shar of a vi summary and a short tutorial on writing macros. I have
also included a sample .exrc file that I use for programming.

	Thank Yous:

	I owe thanks to a couple of people who recently posted vi info
to the net. A good summary came from: (very well laid out)

	maart@cs.vu.nl (Maarten Litmaath)
	VU Informatica, Amsterdam

	A macro package with lots of files also was helpful. Thanks also
to:

Greg McGary --		gmcgary@ecd.sun.com
			gmcgary@suneast.uu.net

	For developing mkid, gid, aid, eid, and co. My macros allow you
to quickly use the ID database that mkid generates.

	Forward:

	It's amazing how much power there is in vi, once you get past
the initial learning bunny slope :-) There are many complete summaries
out there, but fewer sources of info about macros. I'd like to help
change that... I'll update this soon, but want to post what I have
now.

			dan

dan smith, island graphics, marin co., ca  | "My opinions: you can borrow them,
uucp: ..!ucbvax!ucbcad!island!daniel       |  but don't take them out bowling"
uucp: ..!ptsfa!unicom!daniel !well!daniels |  (415) 332 FAST (h) 491 1000 (w)
@//E*O*F README//
chmod u=rw,g=r,o=r README
 
echo x - vicoms.doc
sed 's/^@//' > "vicoms.doc" <<'@//E*O*F vicoms.doc//'
		commands for the editor VI

		command mode (hit escape (ESC))

	cursor positioning

h	left
j	down
+	down
l	right
k	up
-	up
<space>	right
<return>down one line

H	home line (top of window, not necessarily file)
M	middle line of window
L	last line of window

b	back a word
B	back a word (real words, punctuation doesn't count)
w	next word
W	next word (real words, punctuation doesn't count)
3w	skip three words
0	beginning of line
$	end of line
^	(caret character)...first non-blank character on the line.
{	previous paragraph, section
}	next paragraph, section
^D	scroll half screen down		note: (use control key when you 
^F	screen down			see '^' and a letter, and
^U	scroll half screen up		press both at the same time, you do not
^B	screen up			press the shift key)
					('x' means type x)

1G	top of file
(any number)G...go to (any line) of file -- ex: 5g goes to line 5
G	end of file
''	(two single quotes)...return to previous line or mark (long distance)
``	(two back quotes)..return to same place in a line "   "
t	forward to just before a character
T	backward to just after a character
	These are handy for things such as:

	dto	(delete all of the characters on this line up to (but
		not including) the letter 'o')

^G	what line am I on? shows file, status, line number, total lines, %

	searches

/text	search for "text"
	hit 'n' for next occcurence
	hit 'N' for previous occcurence
?text	?text search backwards for "text"
	?  by itself, change from forwards <-> backwards search

	local searches (usually used on same line as you are on)

fx	search forwards for the next letter "x"..use a semicolon ";" or ","
	to keep searching (the "," reverses direction of search)
Fx	search backwards for the next letter "x"..use a semicolon ";" ","
	to keep searching (the "," reverses direction of search)

	undo

u	is undo, and you can undo an undo...
U	is "undo everything that I have done to this line since I have
	landed on it..."

	marking and returning

m(any alpha character)	mark a place
'(any alpha character)	return to a place (line)
`(any alpha character)	return to a place exactly (see below)
	hit "ma" to set up a mark with the letter "a"
	to get back...'a
	'a takes you back to the first non-blank space on that line, while `a
	takes you to that character exactly

marks can be used to specify the scope of a change...such as d'a or >'a
more on that later...

	buffers...

all changes are saved into a buffer, and are retrieved with an undo (u or U)
or a put (p or P)

y, c, and d are for yank, change, and delete, and are operators
yy, cc, and dd affect entire lines

w, b, 0, $, {, }, are how you determine the extent (scope) of 
	  a change, as well as any motion operator such as H, M, L, etc.

/ and ? are used for searches, and can be used to delete, yank, or change
up to the phrase you specify.

	example: d/would<return> deletes up to (but
	not including) the next occurrence of the word "would". If you
	want to make it line specific (go to the line of the word "would")
	you would use d/would/+0<return> (d/dog/+10 would delete up to the line
	with "dog", plus the 10 lines that follow)

changes or copies are set up by [optional number][operator][scope]
such as 2d}...which would delete the next two paragraphs

examples:

x	delete character
xp	transpose characters
ddp	transpose lines
yy	yank line
15yy	yank 15 lines
yM	yank from here to the middle line of window
yw	yank word to end
yb	yank word to beginning
y0	yank to beginning of line   ...all yanks and x's go into buffer 1
y$	yank to end of line
p	put buffer on line below
P	put buffer on line above
cc	change line
cw	change word
3dw	delete 3 words (goes into the temporary buffer)
dd	delete line     "    "     "     "
5dd	delete 5 lines  "    "     "     "
dH	delete from here to the top line of the window (top of screen)
dL	delete from here to the bottom line of the window (bottom of screen)
3yy	yank three lines     "     "     "

	numbered and named buffers

The last 9 changes you have made are saved in the buffers named 1-9.
For example, you would retrieve the change before last by entering "2p
(use the quote) to dump out whatever is in buffer 2. As a special case,
you can repeatedly press the dot key '.' and dump out all the buffers
until you run out of saves or get to buffer 9, whichever happens first.

example: "1p........  would dump all of the last 9 deletions that you have
	 made.

	alpha named buffers

setting up.."[alpha named buffer][optional number][delete or yank operation]
example..."add   delete a line INTO buffer "a"
	  "b5yy  yank 5 lines INTO buffer "b"

using the buffer..."[name you gave the buffer][p or P]
example..."ap    put contents of buffer "a" below

appending to a buffer... you can gather text from many locations into one 
	named buffer, just capitalize the name of the buffer:

	"Ayy	...now, move somewhere else, then...
	"Ayy	...move somewhere else, and try:
	"ap

	you should see the lines from the two different locations.

	When using named buffers, choose letters that have some mnemonic
value to you. If I were yanking the line "The quick young dolphin jumped
over the lazy bagpipes", I would probably use "nyy - the 'n' for "nonsense".

Named buffers and numbered buffers are quick ways to transfer text between
files if you are switching back and forth between two or more. (unmap the
home key via :unmap ^^ (home key or control caret), and you can toggle
between two files by hitting the home key. This would be the last thing in
your .exrc)

	example: moving text between two files...

	have the home key unmapped (in .exrc "unmap ^^" (type ^V<home key>
	or ^V<control caret> while editing .exrc... you should see "^^")...
	go into a scratch file...start up another file (:e fooby)... notice
	that you can toggle between the two files by typing the home
	key (usually if a terminal doesn't have one, control caret (a shifted
	'6'  for most terminals) will do it)... toggle between the two files
	a few times to get familiar with it... go to one of the files,
	and delete a few lines into a buffer via:

	"a3dd

	...then toggle into the other file, and enter:

	"ap

	If all went well, you have just transferred lines from one file to
	another. The same works for yanks ("a3yy). I found out only recently
	that using the buffers 1-9 works too:

	3dd, toggle with home key, then "1p

	I find it handy to mark a place very quickly via mm (mark this spot,
to be referenced by 'm), go to another place, and to use a named buffer via:

	"ay'm	(yank into buffer 'a' whatever is between here and the mark 'm')

	quick changes

r	replace single character
R	replace mode...type over old text and clobber it
2s	substitute whatever I type (until I hit ESC) for the next two characters
xs	I'm going to change the next "x" characters, you may type more than 
	"x" characters in your substitution.
S	is synonomous with "cc"...change effects an entire line.
tilde '~'	change case of current char.
>>	shift current line over right by a shiftwidth (usually a tab)
<<	shift current line over left by a shiftwidth (usually a tab)
	>L would shift all of the lines from where you are to the bottom of
	the screen to the right...
	50<< left shifts 50 lines...

	getting into text input mode

a	append
A	append at the end of line
i	insert
I	insert at first non blank character of line 
o	open line below
O	open line above

	Using things like s, S, cc, C, etc... are also ways of getting
	into text input mode.

^D	backtab (insert mode only)
^V	follow it with a control combination to insert a control char. into text
ESC	hit to get back into command mode

	file manipulations and others...all from command mode

:w	write file
:wq	write file and quit
ZZ	another way to write file and quit
:e	filename   edit file
:e!	filename   insist on editing file, a way to start with a fresh
		copy of the current file name, WITHOUT any of the changes
		that you may have just made.

:r	read in a file after the current line (merge)
:q	quit
:q!	really quit! don't save changes!
:w!	overwrite a protected file
:n	edit next file in arg list (:se ar gives the list of files)
:rew	rewind back to first file 
:!<shell command> you don't have to leave vi to do something like
	finding out the date or compiling a program.
	The second time you do the same command, you can say ":!!"
	to repeat that command.

:1,$!fmt..pipe the text through the formatting program "fmt", if you
	don't like what you see, hit 'u' for undo...
	this works for many commands, you can do something like
	:40,50!nroff -ms to see how lines 40 through 50 will format
	with the program "nroff" using the "ms" macro package.
	You could also do something like :'a,'b!nroff -ms if you
	have a mark 'a' and a mark 'b'. (first address must be lower
	than the second as far as which line it refers to in the buffer)

:%!fmt....A shorthand for doing the same thing as above. If '%" is being
	used as an address, then it means "the whole file", otherwise
	it expands to be the filename of the current buffer...

	try:

	:!wc %

	now try: (read below first...)

	:%!wc

	(*here*) remember...'u' is undo, and 'U' is "undo everything that I
	have done to this line since I have landed on it..."

!! two exclamations given from command mode. You follow this with
   a unix command that has some output, and the output is inserted into
   your text, clobbering the current line. You should set up a blank line
   before calling this mechanism. See below for a different way of doing this.

   ex: open a blank line, then hit escape, then enter "!!date"

   Actually, if you want to read the output of a command into the file,
   :r !command works  (it runs the command and puts the output into your
   buffer).  There is also the opposite, :w !command, which sends the buffer
   as input for the command (useful for :w !more, or something like that).

			notes

"^" and a letter and means to use and the control key...ex: ^D means "control d"
I haven't mentioned a lot, and this file needs to be better organized and
more comprehensive, on the other hand, this should keep a
beginner->intermediate level VI user going for a little while :-)

	mail comments to "island!daniel", special thanks to David Vezie (dv) for
clarification and spotting gremlins.

dan smith, island graphics, marin co., ca  | "My opinions: you can borrow them,
uucp: ..!ucbvax!ucbcad!island!daniel       |  but don't take them out bowling"
uucp: ..!ptsfa!unicom!daniel !well!daniels |  (415) 332 FAST (h) 491 1000 (w)
@//E*O*F vicoms.doc//
chmod u=rw,g=rx,o=rx vicoms.doc
 
echo x - macros.doc
sed 's/^@//' > "macros.doc" <<'@//E*O*F macros.doc//'
Part 2 of a series:

			
		more commands for the VI editor

		Part two:

		macros and abbreviations

	Macros and abbreviations are ways for you to customize vi to
suit your way of doing things, as opposed to you having to change your
editing habits to accomodate vi. There are two types of macros, those
that work in the input mode, and those that work from the command mode.
Abbreviations only work in the input mode.

	Where to use macros:

	I use macros for things that I like to do frequently, where the
existing key sequence for getting something done gets to be too tedious.
If you are in vi right now, hit the colon key, and type in "map",
like this:

		:map

	After hitting return, you'll see the macros that you currently
have access to in the command mode. You should at least see four, one
each for up, down, left, and right. Let's make a simple one to add to
this list...you type in the colon to get the ex prompt ":"

		:map g ^G     <--- that's a "control G"

	When you've hit return, you'll have created a new definition for
the "g" key. Go ahead and hit the g key a couple times, move the cursor
a couple of lines, and try the g key again. You've made it so that
you don't have to hit control g to get this result anymore, which is
a slight improvement. Let's try a more useful example:

		:map @m :w^M:!more %^M

	This can be slightly confusing at first to try to type in, so
I'll explain the business about the control M. When you are in vi, and
want to represent a control character, instead of performing the action that it
would usually do, you preceed that character with a control V (think
of it as control V for "view", as in "view the next character"). Thus,
the preceeding example becomes "colon, w, control V, return (which prints
the ^M character), colon, ! (meaning: we're going to run a unix command
from vi), more, % (which is vi's way of saying "the current file"),
another ^M (same sequence (control V return) as before).

	Now, what does this all do? First, I used "@m" to define the
keys that I will hit for my macro. On the adm5 terminals I learned
unix on, it is very convenient to hit "@" and then "m" very quickly.
Now that I use a Wyse 50, I find the '[' and ']' characters very handy
for defining macros - this is an issue best suited for the user to figure
out what is comfortable. The rhs (right hand side of the macro) says
"write the file by ":w^M", and then do another command by hitting the ":",
Hit the "!" to show that we're doing a unix command, and run the current
file that we have in vi (represented by vi as "%") through "more"
by saying ":!more %^M"" Now let's do a fun one.

	:map ^> I ^[^

	This one is typed as:

	control V, control greater than, space, I, space, control V,
	escape, and then a caret (^), return

	it appears as:

	:map ^N I ^[^

	and that is perfectly ok.

	Try this one out now, while you have it on the screen in front
of you, if you goof somehow, you can hit ^C (for now on, a "^" in
front of a letter most often means it is a control key combination) to get out.

	 This last macro shoves a whole line over to the right by
inserting a space in front of it, and leaves the cursor on the first
non-blank character on the line. I chose ^> because to me it symbolizes
the direction that I am trying to move something, and it is also a
close relative of ">>", which shifts a line over by a tab. This macro
has the counterpart:

	:map ^< ^X

	and appears as

	:map ^L ^X     <--- not a control x

	which is typed as (left hand side) control V, control less than,
and the rhs (right hand side) is not a control X, even though
it appears as such. It is a caret, and then a capital X.

	This macro shoves the whole line to the left by one space (or
tab if there is one in the text) until it can't anymore.

	I will come back to macros for temporary use.


		saving macros...the .exrc file

	It's nice to be able to play around with macros for now, but
it would be even better to have them ready to go everytime you want
to use vi for something. Fortunately, there is such a mechanism, and
it involves a file called .exrc that is in every directory where you
want to have vi set up a certain way. Look at an .exrc file by using
the public domaing pager "less", or by view'ing it (view .exrc (view
is vi without the ability to write back changes).

	You should have a .exrc file in every directory where you'll be using
vi with any consistent set of macros that you develop. Vi reads the file upon
starting up, but you can also "source" a file while you are already in
vi by saying:

	:so .exrc

	After that, you can take a look at the present macros by entering
":map". 

		Macros in input mode

	The macros I just discussed all work in the command mode, a couple
of them enter the input mode to do something, and then hit escape by them-
selves to keep you in the command mode. There is another flavor of macros,
and these are called "input macros". They work the same way as command
mode macros, but they can be invoked as you are typing along. A sample
one could be:

	:map! ^W ^]:w^Mi 

	Which would write out the file as you are going along, with a
small pause...it is typed as ^V, escape, :w, ^V, return, i.

There are many more macros that could be done in this mode, but you need
to avoid ^S...it will make the terminal appear to freeze, when in fact it
is just waiting for you to hit ^Q in order to resume (you use this
combination to look through a long file that is being catted. A strong point
in favor of using input macros is that they can consist of many characters.
Let's say that you are a C, Fortran, Pascal, or Logo user, and you
want some sort of way to speed up writing statements that print out
a phrase. If we are dealing with pascal, we could do this:

	:map! @wr writeln ('');^[hhi

	in C:

	:map! @pf print ("");^[hhi

	in Fortran

	:map! @wr write (6,)'^[hi

and so on... I think you get the idea. A more advanced use is
to place some text in a buffer (a la: "ayy), and then have that buffer
copied out from within a macro, making for a different result from the
macro every time. Let's say I copy this next sentence with "nyy

	the time has come for all good men to tie their shoes.

and let's assume we have the following macro (I'll use the
command mode form here):

	:map @w "npOprintf ("^[JxA");^[^

this results in:

	printf ("the time has come for all good men to tie their shoes.");

The macro comes out different every time, depending on what you
put into buffer n. Before I take a break from macros, let me share some
things that I've found:

	There is a limit to how many macros you can define, depending on
the total amount of characters that exist in all of your macros put together.
I find that 1024 characters total for all macros is a common limit. I changed
a local copy of vi to handle 4096... not that I am using that many yet,
but I like to be flexible :-)

	Macros can be recursive, and can also call other macros. This can
be fun, and confusing.

	Try to write macros that you are really going to use, if they look
impressive, but you never use them because you can't remember them, it takes
that much more time every time you start up vi to set something up that
is going to waste.

	If you want to get into a whole series of commands, have a macro
source a file...the file can consist of unix and vi commands, and can
even define and undefine macros as you go!

	To undefine a macro, you say :unm <macro name>, or for an input mode
macro, you would say :unm! <macro name>

		Abbreviations

	Abbreviations are much easier to understand than macros. Here is
a simple one:

	:ab HT hi there!

	Once this is set up, you type in "HT", and then hit the space bar,
return key, a "*", " " " (quote), or one of many other keys. They transform
what you have just typed into what you want them to become. I will warn
you, but you may still run into this problem someday: Don't make an
abbreviation that is easy to confuse with something you want to type
normally! It can take a few seconds of watching an abbreviation appear,
get deleted by you, and have it reappear before you figure out a way around
it. You need to experience the annoyance this can cause to fully appreciate
what I'm saying! It will seem that this word or phrase will not want
to go away! In other words, use groupings such as "wrn" for "writeln",
or "prc" for procedure. You will soon discover what you are most comfortable
with.

	Another thing about abbreviations is that they leave a space just
after they transform themselves, such as:

	:ab wrn writeln ('

	which is mildly annoying. A last example is that abbreviations
can do something that is very routine, such as:

	:ab wneof while not eof do^M  begin^M 

	There is a final space after the second return, and the output
is:
		while not eof do
		  begin
		    (cursor)

	with the cursor resting where the next statement should go.

	I'll post a file soon that goes into more detail. For now,
I've included a uuencoded sample of my .exrc. To use it:

	touch .sample		(these two lines are neceesary if you
	chmod 666 .sample	are working with a stubborn version of 
				uudecode)

	uudecode sample_exrc

	(go into vi)

	:so .sample

	Note that the character " is a comment line... do not have
lines in your .exrc that are blank.

	This wraps up an introduction to macros and abbreviations, 
please mail all questions, comments, complaints, and so forth to:

dan smith, island graphics, marin co., ca  | "My opinions: you can borrow them,
uucp: ..!ucbvax!ucbcad!island!daniel       |  but don't take them out bowling"
uucp: ..!ptsfa!unicom!daniel !well!daniels |  (415) 332 FAST (h) 491 1000 (w)

@//E*O*F macros.doc//
chmod u=rw,g=r,o=r macros.doc
 
echo x - sample_exrc
sed 's/^@//' > "sample_exrc" <<'@//E*O*F sample_exrc//'
begin 666 .sample
M;6%P(%MA(#IA<@T*(@HB"7-E87)C:"!F;W(@=&AE(&YE>'0@;V-C=7)E;F-E
M(&]F('1H92!P871T97)N(&-U<G-O<B!I<R!R97-T:6YG(&]N"FUA<"!=+R!D
M95!O&VDO&W B>F1D0'H*(@HB"6=R97 @9F]R(&%L;"!O8V-U<F5N8V5S(&]F
M('1H92!P871T97)N(&-U<G-O<B!I<R!R97-T:6YG"B();VX@:6X@=&AI<R!F
M:6QE+BXN"FUA<"!;+R!M>F1E4&\;:3HA9W)E<" M;B ;<&$@)2 6?" O=7-R
M+VQO8V%L+V)I;B]L97-S&R)Z9&1 >F!Z"B(*(@D@=&%K92!T:&4@;F5X="!W
M;W)D(&%N9"!U<V4@:70@87,@:6YP=70@=&\@86ED("AA<')O<&]S(&ED*2XN
M+@IM87 @76$@;7IE8F1E4$\;:3HA86ED(!MP82 6?" O=7-R+VQO8V%L+V)I
M;B]L97-S&R)Z9&1 >F!Z"B(*(@ET86ME('1H92!N97AT('=O<F0@86YD('5S
M92!I="!A<R!I;G!U="!T;R!E:60N+BX*;6%P(%UE(&5B9&503QMI.B%E:60@
M&W B>F1D0'H*(@HB"2!T86ME('1H92!N97AT('=O<F0@86YD('5S92!I="!A
M<R!I;G!U="!T;R!G:60@*&=R97 @:60I+BXN"FUA<"!=9R!M>F5B9&503QMI
M.B%G:60@&W!A(!9\("]U<W(O;&]C86PO8FEN+VQE<W,;(GID9$!Z8'H*(@HB
M"6=E="!A('-A=F5D('-C<F5E;B!F<F]M('-O;64@<')O8V5S<R!R=6X@8GD@
M(G-C<F5E;B(*;6%P(%US(#IR("]U<W(R+W!E;W!L92]D86YI96PO=&5X="]S
M8W)E96YS+VAA<F1C;W!Y+@IM87 @76,@;6TG8SHN+"=M('<A("]U<W(R+W!E
M;W!L92]D86YI96PO<W)C+RYC=70-"FUA<"!=;B Z;@T*;6%P(%UP(#IR("]U
M<W(R+W!E;W!L92]D86YI96PO<W)C+RYC=70-"FUA<"!;<" Z<&]P#0IM87 @
M77$@.G$-"FUA<"!==" Z=&$@"FUA<"!==R Z=PT*(@HB"7=R:71E(&$@8F%C
M:W5P(&9I;&4N+BX*;6%P(%MW(#IW(2 E+F)A:PT*(@HB"6-O;6UE;G0@82!L
M:6YE"FUA<"!=*B!/+RH;:F\J+QL*(@HB"75N8V]M;65N="!A(&QI;F4*;6%P
M(%LJ(&MD9&ID9 IM87 @%R Z=PT>"FUA<"! <R Z<V5T('-H96QL/2]B:6XO
M8W-H#0IM87 @0$!S(#IS970@<VAE;&P]+V)I;B]S: T*=6YM87 @'@IS92!R
(97!O<G0],0H@
 
end
@//E*O*F sample_exrc//
chmod u=rw,g=r,o=r sample_exrc
echo getting .sample file...
touch .sample
chmod 777 .sample
uudecode sample_exrc
chmod 644 .sample
exit 0