71 lines
3.2 KiB
Plaintext
71 lines
3.2 KiB
Plaintext
From: pgf@cayman.COM (Paul Fox)
|
|
Subject: Re: Undoing, Emacs and unlimited files ... summery.
|
|
Date: 27 Jul 92 19:51:02 GMT
|
|
Organization: Cayman Systems Inc., Cambridge Ma
|
|
|
|
nmouawad@waterloo.edu (Naji Mouawad) writes:
|
|
:
|
|
... a nice summary of undo strategies in various editors
|
|
:
|
|
|
|
Gee, if I'd known everyone was going to be so informative, I'd have replied
|
|
to the original posting -- but better late than never: since it's just a
|
|
little different than the other method's described, here's how vile does
|
|
undo:
|
|
|
|
(Note this is a vi-style "one command" undo, which undoes itself -- it is
|
|
not an "infinite" undo.)
|
|
|
|
[ vile uses the linked list method of storage, with dynamically allocated
|
|
text blocks hanging off of each line "header". ]
|
|
|
|
Undo operates by keeping a stack of "changed" lines (i.e. those affected
|
|
by a given command), along with information (more later) as to where they
|
|
should go if an undo is actually required. Thus if a character is deleted
|
|
on a line, a copy of the original line is pushed on the undo stack. If a
|
|
line is deleted, is simply moved to the undo stack. If a line is inserted,
|
|
a "tag" is pushed on the undo stack, which tells us where the corresponding
|
|
deletion should occur at undo time. Only the first change to a line causes a
|
|
copy to be stacked -- at that point, the line is flagged as having been
|
|
copied already, suppressing further copies. Since undo is itself undoable,
|
|
I found it easiest to keep two undo stacks -- when we do an undo, the
|
|
changes we are now undoing are simply put onto the alternate undo stack.
|
|
Multiple undo commands in a row simply cause us to move from one stack of
|
|
changes to the other (rebuilding the other each time).
|
|
|
|
A certain amount of grottiness comes in because what we store as the
|
|
information needed to put the lines back in their place are actually
|
|
pointers to the lines in front and in back of its original location. Since
|
|
these pointers may be invalidated by subsequent changes during the same
|
|
command (if, say, the line following a changed line goes away altogether),
|
|
we need to store some pointer patches on the stack as weil, which, in
|
|
essence, say "when you pop this, go down through the stack and change all
|
|
instances of pointer A to pointer A', because that's its new value". I
|
|
didn't say it was beautiful. I would probably do things differently if I
|
|
were to do it now -- I knew _nothing_ about editors when I started
|
|
converting micro-Emacs to vile.
|
|
|
|
One advantage of this stack approach is that it simply accumulates all
|
|
changes to a buffer until told to clean up the stacks. Thus it was trivial
|
|
to make global operations (:g/str1/s/str2/str3") and macros (like a set of
|
|
commands executed with '@a', or via the keyboard macro-recorder) undoable
|
|
all at once. The first case just worked, and for the second, I simply
|
|
delay the stack cleanup if a macro replay is in progress.
|
|
|
|
Vi connosewers (sp? :-) will note that this is different than the stock vi
|
|
approach, in that it is totally independent of the default yank buffer.
|
|
That is, doing an undo will not affect the contents of the yank buffer. I
|
|
consider this a feature.
|
|
|
|
|
|
paul fox, pgf@cayman.com
|
|
|
|
|
|
(yes, it's available for ftp -- at ftp.cayman.com:/pub/vile)
|
|
|
|
--
|
|
paul fox, pgf@cayman.com, (617)494-1999
|
|
Cayman Systems, 26 Landsdowne St., Cambridge, MA 02139
|
|
|
|
|