119304Speter/*- 219304Speter * Copyright (c) 1992, 1993, 1994 319304Speter * The Regents of the University of California. All rights reserved. 419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996 519304Speter * Keith Bostic. All rights reserved. 619304Speter * 719304Speter * See the LICENSE file for redistribution information. 819304Speter */ 919304Speter 1019304Speter#include "config.h" 1119304Speter 1219304Speter#ifndef lint 13254225Speterstatic const char sccsid[] = "$Id: v_undo.c,v 10.6 2001/06/25 15:19:36 skimo Exp $"; 1419304Speter#endif /* not lint */ 1519304Speter 1619304Speter#include <sys/types.h> 1719304Speter#include <sys/queue.h> 1819304Speter#include <sys/time.h> 1919304Speter 2019304Speter#include <bitstring.h> 2119304Speter#include <errno.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 2419304Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter 2719304Speter#include "../common/common.h" 2819304Speter#include "vi.h" 2919304Speter 3019304Speter/* 3119304Speter * v_Undo -- U 3219304Speter * Undo changes to this line. 3319304Speter * 3419304Speter * PUBLIC: int v_Undo __P((SCR *, VICMD *)); 3519304Speter */ 3619304Speterint 37254225Speterv_Undo(SCR *sp, VICMD *vp) 3819304Speter{ 3919304Speter /* 4019304Speter * Historically, U reset the cursor to the first column in the line 4119304Speter * (not the first non-blank). This seems a bit non-intuitive, but, 4219304Speter * considering that we may have undone multiple changes, anything 4319304Speter * else (including the cursor position stored in the logging records) 4419304Speter * is going to appear random. 4519304Speter */ 4619304Speter vp->m_final.cno = 0; 4719304Speter 4819304Speter /* 4919304Speter * !!! 5019304Speter * Set up the flags so that an immediately subsequent 'u' will roll 5119304Speter * forward, instead of backward. In historic vi, a 'u' following a 5219304Speter * 'U' redid all of the changes to the line. Given that the user has 5319304Speter * explicitly discarded those changes by entering 'U', it seems likely 5419304Speter * that the user wants something between the original and end forms of 5519304Speter * the line, so starting to replay the changes seems the best way to 5619304Speter * get to there. 5719304Speter */ 5819304Speter F_SET(sp->ep, F_UNDO); 5919304Speter sp->ep->lundo = BACKWARD; 6019304Speter 6119304Speter return (log_setline(sp)); 6219304Speter} 6319304Speter 6419304Speter/* 6519304Speter * v_undo -- u 6619304Speter * Undo the last change. 6719304Speter * 6819304Speter * PUBLIC: int v_undo __P((SCR *, VICMD *)); 6919304Speter */ 7019304Speterint 71254225Speterv_undo(SCR *sp, VICMD *vp) 7219304Speter{ 7319304Speter EXF *ep; 7419304Speter 7519304Speter /* Set the command count. */ 7619304Speter VIP(sp)->u_ccnt = sp->ccnt; 7719304Speter 7819304Speter /* 7919304Speter * !!! 8019304Speter * In historic vi, 'u' toggled between "undo" and "redo", i.e. 'u' 8119304Speter * undid the last undo. However, if there has been a change since 8219304Speter * the last undo/redo, we always do an undo. To make this work when 8319304Speter * the user can undo multiple operations, we leave the old semantic 8419304Speter * unchanged, but make '.' after a 'u' do another undo/redo operation. 8519304Speter * This has two problems. 8619304Speter * 8719304Speter * The first is that 'u' didn't set '.' in historic vi. So, if a 8819304Speter * user made a change, realized it was in the wrong place, does a 8919304Speter * 'u' to undo it, moves to the right place and then does '.', the 9019304Speter * change was reapplied. To make this work, we only apply the '.' 9119304Speter * to the undo command if it's the command immediately following an 9219304Speter * undo command. See vi/vi.c:getcmd() for the details. 9319304Speter * 9419304Speter * The second is that the traditional way to view the numbered cut 9519304Speter * buffers in vi was to enter the commands "1pu.u.u.u. which will 9619304Speter * no longer work because the '.' immediately follows the 'u' command. 9719304Speter * Since we provide a much better method of viewing buffers, and 9819304Speter * nobody can think of a better way of adding in multiple undo, this 9919304Speter * remains broken. 10019304Speter * 10119304Speter * !!! 10219304Speter * There is change to historic practice for the final cursor position 10319304Speter * in this implementation. In historic vi, if an undo was isolated to 10419304Speter * a single line, the cursor moved to the start of the change, and 10519304Speter * then, subsequent 'u' commands would not move it again. (It has been 10619304Speter * pointed out that users used multiple undo commands to get the cursor 10719304Speter * to the start of the changed text.) Nvi toggles between the cursor 10819304Speter * position before and after the change was made. One final issue is 10919304Speter * that historic vi only did this if the user had not moved off of the 11019304Speter * line before entering the undo command; otherwise, vi would move the 11119304Speter * cursor to the most attractive position on the changed line. 11219304Speter * 11319304Speter * It would be difficult to match historic practice in this area. You 11419304Speter * not only have to know that the changes were isolated to one line, 11519304Speter * but whether it was the first or second undo command as well. And, 11619304Speter * to completely match historic practice, we'd have to track users line 11719304Speter * changes, too. This isn't worth the effort. 11819304Speter */ 11919304Speter ep = sp->ep; 12019304Speter if (!F_ISSET(ep, F_UNDO)) { 12119304Speter F_SET(ep, F_UNDO); 12219304Speter ep->lundo = BACKWARD; 12319304Speter } else if (!F_ISSET(vp, VC_ISDOT)) 12419304Speter ep->lundo = ep->lundo == BACKWARD ? FORWARD : BACKWARD; 12519304Speter 12619304Speter switch (ep->lundo) { 12719304Speter case BACKWARD: 12819304Speter return (log_backward(sp, &vp->m_final)); 12919304Speter case FORWARD: 13019304Speter return (log_forward(sp, &vp->m_final)); 13119304Speter default: 13219304Speter abort(); 13319304Speter } 13419304Speter /* NOTREACHED */ 13519304Speter} 136