vi puzzle

gbergman at ucbtopaz.CC.Berkeley.ARPA gbergman at ucbtopaz.CC.Berkeley.ARPA
Sat Sep 22 16:12:49 AEST 1984


The question was:  if you have set up a vi abbreviation which if
executed creates an infinite loop, such as

	:ab yes yes!
or
	:ab O O'Shaughnessy

how can you unabbreviate these, without leaving vi mode or killing
the editor?  (The reason that these create infinite loops is that
an abbreviation consisting of alphanumeric characters is expanded
when it is typed in vi insert mode preceded and followed by most any
nonalphanumeric characters.  In the above abbreviations, the expansion
begins with the abbreviation followed by a nonalphanumeric character,
and the expansion process is recursive, so this initial segment is again
expanded, and so on.  The difficulty with unabbreviating them is that
bottom-line commands in vi are processed like text-insertions; in
particular, abbreviations are expanded.  Since the "unabbreviate"
command-line is ended with a carriage-return or an escape, which
trigger expansion, an attempt to undo these abbreviations gives
the same infinite loop.)

     I know of two types solutions:

(1)  Create the desired command-line by trickery within the text,
then put it someplace from which it can be executed as a command.
     By what kind of trickery can the command line by created within
the text?  If you try typing "unab yess" and then backspace over the
last "s" and escape, the editor is smart enough to realize that you
have typed the word "yes", and will try to expand it.  But if you
escape after typing "unab yess" and then kill the last "s" with
the command "x", or if you type "unab ye" and escape, then append
an "s", or in any other way create it using two successive commands,
it will not count this as a candidate for expansion, and the desired
line can be achieved.
     To execute this line as a command, my method is to yank or
delete it to a named buffer, e.g. with the command
	"xdd
and the execute this buffer using
	:@x
Another way, pointed out by ihnp4!druxp!mab (Alan Bland) -- the only
person who submitted a solution to this "puzzle" -- is to write the
created command line to a temporary file
	:.w junk
and execute it with the source command
	:so junk

(2)  The other method is based on the fact that abbreviation may be
inhibited by typing ^V before the following character.  Generally
speaking, ^V prevents "special" interpretations of a character; in
this case it prevents a following nonalphanumeric character from
being interpreted as a trigger for abbreviation-expansion.
     This is not a solution in itself.  If you try typing
	:unab yes
and precede your closing carriage-return by a ^V, this will not only
prevent it from triggering the expansion, it will also prevent it from
executing the command-line; instead, you will get a ^M as part of the
command-line.  If you hit another carriage return, the line will be
executed, but since it now says
	:unab yes^M
and yes^M was never made an abbreviation, the editor will merely report
this fact.  Likewise, if you type :unab yes and then ^V followed by
a space and carriage return, you will get something that looks like
the desired line, but in fact it will have a space at the end, and the
editor will notice that yes-space was not abbreviated, and so report.
     However, there is one character which if put in an :unab
command line will not in general be interpreted as part of the
abbreviation.  This is |, which can be used to string bottom-line
commands together, e.g.
	:unab ucb|unab ucla|unab mit|unab hvd
Now if you type in the desired line  :unab yes,  followed by ^V  and
then by  |, and then any other command, for instance the vacuous
command, then your desired command :unab yes  will be entered and
executed.

     (You might wonder how one can put literal |'s into ab or
unab commands.  The answer is, by hitting ^V twice before
the |.  This prevents the special interpretation of ^V and allows
it to be included as an actual character in the command line, so that
at the next stage, where the command line is processed, it will prevent
interpretation of the | as a special symbol.  If in fact you wanted to
have the effect of a ^V appear when the abbreviation is expanded, you
need to hit it four times when executing the command line, while to
get a literal ^V in the expansion of an abbreviation, you would
have to hit it eight times, resulting in the appearance of four ^V's on
your command line, hence two within the abbreviation-output, of which
one prevents the special interpretation of the other when this output
is output.  As another example, suppose you are typing something up
to be lpr'd, and you wish to represent the empty set by its conventional
abbreviation, an overstruck O and /.  You decide to set up an
abbreviation whereby typing the word "es" will produce this effect.
The correct command-line turns out to be of the form
	:ab es O*/
where at the point marked *, you hit ^V either 5 or 7 times.  I leave
it to you to figure out why 5 or 7, but no other counts, will work!

     There are things about the :ab command that I still don't
understand.  For instance, I said that the expansion  of an abbreviation
will be triggered if it is "preceded and followed by "most any
nonalphanumeric character" but the actual situation is
more complicated.  Here are some examples that I have found by
trial and error.  Perhaps someone who can understand the source
code, or who has more patience testing out cases, can tell us the
general rule.  Of course, what works on the machines I use may not work
on yours!
	Let:
		s= space, tab, beginning/end of insert,
		a= alphanumeric
		*= most nonalphanumerics

				abbreviation works if
c o m m a n d		preceded by	&	followed by
			s   a   *		s  a  *
:ab ca California	+   -   +		+  -  +
:ab x  exact		+   -   -		+  -  +
:ab 's possessive	+   +   -		+  -  +
:ab can't cannot	never?
:ab & ampersand		never?

     Note that in all these cases, even those I have never been
able to make work, the abbreviation is "accepted" in the sense
that after the command has been given, the command
	:ab
will show the desired abbreviation among those stored.
     Have fun!

			George Bergman
			Math, UC Berkeley 94720 USA
			...!ucbvax!ucbcartan!gbergman



More information about the Comp.unix.wizards mailing list