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