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