aboutsummaryrefslogtreecommitdiff
path: root/vi/v_z.c
blob: 93b946dfa4eb304b8b3c020b1eba0269c26c21fb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*-
 * Copyright (c) 1992, 1993, 1994
 *	The Regents of the University of California.  All rights reserved.
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
 *	Keith Bostic.  All rights reserved.
 *
 * See the LICENSE file for redistribution information.
 */

#include "config.h"

#include <sys/types.h>
#include <sys/queue.h>
#include <sys/time.h>

#include <bitstring.h>
#include <limits.h>
#include <stdio.h>

#include "../common/common.h"
#include "vi.h"

/*
 * v_z -- [count]z[count][-.+^<CR>]
 *	Move the screen.
 *
 * PUBLIC: int v_z(SCR *, VICMD *);
 */
int
v_z(SCR *sp, VICMD *vp)
{
	recno_t lno;
	e_key_t value;

	/*
	 * The first count is the line to use.  If the value doesn't
	 * exist, use the last line.
	 */
	if (F_ISSET(vp, VC_C1SET)) {
		lno = vp->count;
		if (!db_exist(sp, lno) && db_last(sp, &lno))
			return (1);
	} else
		lno = vp->m_start.lno;

	/* Set default return cursor line. */
	vp->m_final.lno = lno;
	vp->m_final.cno = vp->m_start.cno;

	/*
	 * The second count is the displayed window size, i.e. the 'z' command
	 * is another way to get artificially small windows.  Note, you can't
	 * grow beyond the size of the window.
	 *
	 * !!!
	 * A window size of 0 was historically allowed, and simply ignored.
	 * This could be much more simply done by modifying the value of the
	 * O_WINDOW option, but that's not how it worked historically.
	 */
	if (F_ISSET(vp, VC_C2SET) && vp->count2 != 0) {
		if (vp->count2 > O_VAL(sp, O_WINDOW))
			vp->count2 = O_VAL(sp, O_WINDOW);
		if (vs_crel(sp, vp->count2))
			return (1);
	}

	switch (vp->character) {
	case '-':		/* Put the line at the bottom. */
		if (vs_sm_fill(sp, lno, P_BOTTOM))
			return (1);
		break;
	case '.':		/* Put the line in the middle. */
		if (vs_sm_fill(sp, lno, P_MIDDLE))
			return (1);
		break;
	case '+':
		/*
		 * If the user specified a line number, put that line at the
		 * top and move the cursor to it.  Otherwise, scroll forward
		 * a screen from the current screen.
		 */
		if (F_ISSET(vp, VC_C1SET)) {
			if (vs_sm_fill(sp, lno, P_TOP))
				return (1);
			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
				return (1);
		} else
			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_PLUS))
				return (1);
		break;
	case '^':
		/*
		 * If the user specified a line number, put that line at the
		 * bottom, move the cursor to it, and then display the screen
		 * before that one.  Otherwise, scroll backward a screen from
		 * the current screen.
		 *
		 * !!!
		 * Note, we match the off-by-one characteristics of historic
		 * vi, here.
		 */
		if (F_ISSET(vp, VC_C1SET)) {
			if (vs_sm_fill(sp, lno, P_BOTTOM))
				return (1);
			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
				return (1);
			if (vs_sm_fill(sp, vp->m_final.lno, P_BOTTOM))
				return (1);
		} else
			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_CARAT))
				return (1);
		break;
	default:		/* Put the line at the top for <cr>. */
		value = KEY_VAL(sp, vp->character);
		if (value != K_CR && value != K_NL) {
			v_emsg(sp, vp->kp->usage, VIM_USAGE);
			return (1);
		}
		if (vs_sm_fill(sp, lno, P_TOP))
			return (1);
		break;
	}
	return (0);
}

/*
 * vs_crel --
 *	Change the relative size of the current screen.
 *
 * PUBLIC: int vs_crel(SCR *, long);
 */
int
vs_crel(SCR *sp, long int count)
{
	sp->t_minrows = sp->t_rows = count;
	if (sp->t_rows > sp->rows - 1)
		sp->t_minrows = sp->t_rows = sp->rows - 1;
	TMAP = HMAP + (sp->t_rows - 1);
	F_SET(sp, SC_SCR_REDRAW);
	return (0);
}