xref: /freebsd/contrib/nvi/vi/v_z.c (revision 5c52a79884070364bfc920fb8e492cfac61ec72f)
1 /*-
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5  *	Keith Bostic.  All rights reserved.
6  *
7  * See the LICENSE file for redistribution information.
8  */
9 
10 #include "config.h"
11 
12 #ifndef lint
13 static const char sccsid[] = "@(#)v_z.c	10.10 (Berkeley) 5/16/96";
14 #endif /* not lint */
15 
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
19 
20 #include <bitstring.h>
21 #include <limits.h>
22 #include <stdio.h>
23 
24 #include "../common/common.h"
25 #include "vi.h"
26 
27 /*
28  * v_z -- [count]z[count][-.+^<CR>]
29  *	Move the screen.
30  *
31  * PUBLIC: int v_z __P((SCR *, VICMD *));
32  */
33 int
34 v_z(sp, vp)
35 	SCR *sp;
36 	VICMD *vp;
37 {
38 	recno_t lno;
39 	u_int value;
40 
41 	/*
42 	 * The first count is the line to use.  If the value doesn't
43 	 * exist, use the last line.
44 	 */
45 	if (F_ISSET(vp, VC_C1SET)) {
46 		lno = vp->count;
47 		if (!db_exist(sp, lno) && db_last(sp, &lno))
48 			return (1);
49 	} else
50 		lno = vp->m_start.lno;
51 
52 	/* Set default return cursor line. */
53 	vp->m_final.lno = lno;
54 	vp->m_final.cno = vp->m_start.cno;
55 
56 	/*
57 	 * The second count is the displayed window size, i.e. the 'z' command
58 	 * is another way to get artificially small windows.  Note, you can't
59 	 * grow beyond the size of the window.
60 	 *
61 	 * !!!
62 	 * A window size of 0 was historically allowed, and simply ignored.
63 	 * This could be much more simply done by modifying the value of the
64 	 * O_WINDOW option, but that's not how it worked historically.
65 	 */
66 	if (F_ISSET(vp, VC_C2SET) && vp->count2 != 0) {
67 		if (vp->count2 > O_VAL(sp, O_WINDOW))
68 			vp->count2 = O_VAL(sp, O_WINDOW);
69 		if (vs_crel(sp, vp->count2))
70 			return (1);
71 	}
72 
73 	switch (vp->character) {
74 	case '-':		/* Put the line at the bottom. */
75 		if (vs_sm_fill(sp, lno, P_BOTTOM))
76 			return (1);
77 		break;
78 	case '.':		/* Put the line in the middle. */
79 		if (vs_sm_fill(sp, lno, P_MIDDLE))
80 			return (1);
81 		break;
82 	case '+':
83 		/*
84 		 * If the user specified a line number, put that line at the
85 		 * top and move the cursor to it.  Otherwise, scroll forward
86 		 * a screen from the current screen.
87 		 */
88 		if (F_ISSET(vp, VC_C1SET)) {
89 			if (vs_sm_fill(sp, lno, P_TOP))
90 				return (1);
91 			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
92 				return (1);
93 		} else
94 			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_PLUS))
95 				return (1);
96 		break;
97 	case '^':
98 		/*
99 		 * If the user specified a line number, put that line at the
100 		 * bottom, move the cursor to it, and then display the screen
101 		 * before that one.  Otherwise, scroll backward a screen from
102 		 * the current screen.
103 		 *
104 		 * !!!
105 		 * Note, we match the off-by-one characteristics of historic
106 		 * vi, here.
107 		 */
108 		if (F_ISSET(vp, VC_C1SET)) {
109 			if (vs_sm_fill(sp, lno, P_BOTTOM))
110 				return (1);
111 			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
112 				return (1);
113 			if (vs_sm_fill(sp, vp->m_final.lno, P_BOTTOM))
114 				return (1);
115 		} else
116 			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_CARAT))
117 				return (1);
118 		break;
119 	default:		/* Put the line at the top for <cr>. */
120 		value = KEY_VAL(sp, vp->character);
121 		if (value != K_CR && value != K_NL) {
122 			v_emsg(sp, vp->kp->usage, VIM_USAGE);
123 			return (1);
124 		}
125 		if (vs_sm_fill(sp, lno, P_TOP))
126 			return (1);
127 		break;
128 	}
129 	return (0);
130 }
131 
132 /*
133  * vs_crel --
134  *	Change the relative size of the current screen.
135  *
136  * PUBLIC: int vs_crel __P((SCR *, long));
137  */
138 int
139 vs_crel(sp, count)
140 	SCR *sp;
141 	long count;
142 {
143 	sp->t_minrows = sp->t_rows = count;
144 	if (sp->t_rows > sp->rows - 1)
145 		sp->t_minrows = sp->t_rows = sp->rows - 1;
146 	TMAP = HMAP + (sp->t_rows - 1);
147 	F_SET(sp, SC_SCR_REDRAW);
148 	return (0);
149 }
150