GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/v_undo.c Lines: 0 14 0.0 %
Date: 2017-11-13 Branches: 0 7 0.0 %

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