]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/nvi/vi/v_undo.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / nvi / vi / v_undo.c
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *      Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9
10 #include "config.h"
11
12 #ifndef lint
13 static const char sccsid[] = "$Id: v_undo.c,v 10.6 2001/06/25 15:19:36 skimo Exp $";
14 #endif /* not lint */
15
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19
20 #include <bitstring.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "../common/common.h"
28 #include "vi.h"
29
30 /*
31  * v_Undo -- U
32  *      Undo changes to this line.
33  *
34  * PUBLIC: int v_Undo __P((SCR *, VICMD *));
35  */
36 int
37 v_Undo(SCR *sp, VICMD *vp)
38 {
39         /*
40          * Historically, U reset the cursor to the first column in the line
41          * (not the first non-blank).  This seems a bit non-intuitive, but,
42          * considering that we may have undone multiple changes, anything
43          * else (including the cursor position stored in the logging records)
44          * is going to appear random.
45          */
46         vp->m_final.cno = 0;
47
48         /*
49          * !!!
50          * Set up the flags so that an immediately subsequent 'u' will roll
51          * forward, instead of backward.  In historic vi, a 'u' following a
52          * 'U' redid all of the changes to the line.  Given that the user has
53          * explicitly discarded those changes by entering 'U', it seems likely
54          * that the user wants something between the original and end forms of
55          * the line, so starting to replay the changes seems the best way to
56          * get to there.
57          */
58         F_SET(sp->ep, F_UNDO);
59         sp->ep->lundo = BACKWARD;
60
61         return (log_setline(sp));
62 }
63
64 /*
65  * v_undo -- u
66  *      Undo the last change.
67  *
68  * PUBLIC: int v_undo __P((SCR *, VICMD *));
69  */
70 int
71 v_undo(SCR *sp, VICMD *vp)
72 {
73         EXF *ep;
74
75         /* Set the command count. */
76         VIP(sp)->u_ccnt = sp->ccnt;
77
78         /*
79          * !!!
80          * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u'
81          * undid the last undo.  However, if there has been a change since
82          * the last undo/redo, we always do an undo.  To make this work when
83          * the user can undo multiple operations, we leave the old semantic
84          * unchanged, but make '.' after a 'u' do another undo/redo operation.
85          * This has two problems.
86          *
87          * The first is that 'u' didn't set '.' in historic vi.  So, if a
88          * user made a change, realized it was in the wrong place, does a
89          * 'u' to undo it, moves to the right place and then does '.', the
90          * change was reapplied.  To make this work, we only apply the '.'
91          * to the undo command if it's the command immediately following an
92          * undo command.  See vi/vi.c:getcmd() for the details.
93          *
94          * The second is that the traditional way to view the numbered cut
95          * buffers in vi was to enter the commands "1pu.u.u.u. which will
96          * no longer work because the '.' immediately follows the 'u' command.
97          * Since we provide a much better method of viewing buffers, and
98          * nobody can think of a better way of adding in multiple undo, this
99          * remains broken.
100          *
101          * !!!
102          * There is change to historic practice for the final cursor position
103          * in this implementation.  In historic vi, if an undo was isolated to
104          * a single line, the cursor moved to the start of the change, and
105          * then, subsequent 'u' commands would not move it again. (It has been
106          * pointed out that users used multiple undo commands to get the cursor
107          * to the start of the changed text.)  Nvi toggles between the cursor
108          * position before and after the change was made.  One final issue is
109          * that historic vi only did this if the user had not moved off of the
110          * line before entering the undo command; otherwise, vi would move the
111          * cursor to the most attractive position on the changed line.
112          *
113          * It would be difficult to match historic practice in this area. You
114          * not only have to know that the changes were isolated to one line,
115          * but whether it was the first or second undo command as well.  And,
116          * to completely match historic practice, we'd have to track users line
117          * changes, too.  This isn't worth the effort.
118          */
119         ep = sp->ep;
120         if (!F_ISSET(ep, F_UNDO)) {
121                 F_SET(ep, F_UNDO);
122                 ep->lundo = BACKWARD;
123         } else if (!F_ISSET(vp, VC_ISDOT))
124                 ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD;
125
126         switch (ep->lundo) {
127         case BACKWARD:
128                 return (log_backward(sp, &vp->m_final));
129         case FORWARD:
130                 return (log_forward(sp, &vp->m_final));
131         default:
132                 abort();
133         }
134         /* NOTREACHED */
135 }