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