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_z.c,v 10.13 2011/12/02 17:26:59 zy 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 <limits.h>
2219304Speter#include <stdio.h>
2319304Speter
2419304Speter#include "../common/common.h"
2519304Speter#include "vi.h"
2619304Speter
2719304Speter/*
2819304Speter * v_z -- [count]z[count][-.+^<CR>]
2919304Speter *	Move the screen.
3019304Speter *
3119304Speter * PUBLIC: int v_z __P((SCR *, VICMD *));
3219304Speter */
3319304Speterint
34254225Speterv_z(SCR *sp, VICMD *vp)
3519304Speter{
3619304Speter	recno_t lno;
37254225Speter	e_key_t value;
3819304Speter
3919304Speter	/*
4019304Speter	 * The first count is the line to use.  If the value doesn't
4119304Speter	 * exist, use the last line.
4219304Speter	 */
4319304Speter	if (F_ISSET(vp, VC_C1SET)) {
4419304Speter		lno = vp->count;
4519304Speter		if (!db_exist(sp, lno) && db_last(sp, &lno))
4619304Speter			return (1);
4719304Speter	} else
4819304Speter		lno = vp->m_start.lno;
4919304Speter
5019304Speter	/* Set default return cursor line. */
5119304Speter	vp->m_final.lno = lno;
5219304Speter	vp->m_final.cno = vp->m_start.cno;
5319304Speter
5419304Speter	/*
5519304Speter	 * The second count is the displayed window size, i.e. the 'z' command
5619304Speter	 * is another way to get artificially small windows.  Note, you can't
5719304Speter	 * grow beyond the size of the window.
5819304Speter	 *
5919304Speter	 * !!!
6019304Speter	 * A window size of 0 was historically allowed, and simply ignored.
6119304Speter	 * This could be much more simply done by modifying the value of the
6219304Speter	 * O_WINDOW option, but that's not how it worked historically.
6319304Speter	 */
6419304Speter	if (F_ISSET(vp, VC_C2SET) && vp->count2 != 0) {
6519304Speter		if (vp->count2 > O_VAL(sp, O_WINDOW))
6619304Speter			vp->count2 = O_VAL(sp, O_WINDOW);
6719304Speter		if (vs_crel(sp, vp->count2))
6819304Speter			return (1);
6919304Speter	}
7019304Speter
7119304Speter	switch (vp->character) {
7219304Speter	case '-':		/* Put the line at the bottom. */
7319304Speter		if (vs_sm_fill(sp, lno, P_BOTTOM))
7419304Speter			return (1);
7519304Speter		break;
7619304Speter	case '.':		/* Put the line in the middle. */
7719304Speter		if (vs_sm_fill(sp, lno, P_MIDDLE))
7819304Speter			return (1);
7919304Speter		break;
8019304Speter	case '+':
8119304Speter		/*
8219304Speter		 * If the user specified a line number, put that line at the
8319304Speter		 * top and move the cursor to it.  Otherwise, scroll forward
8419304Speter		 * a screen from the current screen.
8519304Speter		 */
8619304Speter		if (F_ISSET(vp, VC_C1SET)) {
8719304Speter			if (vs_sm_fill(sp, lno, P_TOP))
8819304Speter				return (1);
8919304Speter			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
9019304Speter				return (1);
9119304Speter		} else
9219304Speter			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_PLUS))
9319304Speter				return (1);
9419304Speter		break;
9519304Speter	case '^':
9619304Speter		/*
9719304Speter		 * If the user specified a line number, put that line at the
9819304Speter		 * bottom, move the cursor to it, and then display the screen
9919304Speter		 * before that one.  Otherwise, scroll backward a screen from
10019304Speter		 * the current screen.
10119304Speter		 *
10219304Speter		 * !!!
10319304Speter		 * Note, we match the off-by-one characteristics of historic
10419304Speter		 * vi, here.
10519304Speter		 */
10619304Speter		if (F_ISSET(vp, VC_C1SET)) {
10719304Speter			if (vs_sm_fill(sp, lno, P_BOTTOM))
10819304Speter				return (1);
10919304Speter			if (vs_sm_position(sp, &vp->m_final, 0, P_TOP))
11019304Speter				return (1);
11119304Speter			if (vs_sm_fill(sp, vp->m_final.lno, P_BOTTOM))
11219304Speter				return (1);
11319304Speter		} else
11419304Speter			if (vs_sm_scroll(sp, &vp->m_final, sp->t_rows, Z_CARAT))
11519304Speter				return (1);
11619304Speter		break;
11719304Speter	default:		/* Put the line at the top for <cr>. */
11819304Speter		value = KEY_VAL(sp, vp->character);
11919304Speter		if (value != K_CR && value != K_NL) {
12019304Speter			v_emsg(sp, vp->kp->usage, VIM_USAGE);
12119304Speter			return (1);
12219304Speter		}
12319304Speter		if (vs_sm_fill(sp, lno, P_TOP))
12419304Speter			return (1);
12519304Speter		break;
12619304Speter	}
12719304Speter	return (0);
12819304Speter}
12919304Speter
13019304Speter/*
13119304Speter * vs_crel --
13219304Speter *	Change the relative size of the current screen.
13319304Speter *
13419304Speter * PUBLIC: int vs_crel __P((SCR *, long));
13519304Speter */
13619304Speterint
137254225Spetervs_crel(SCR *sp, long int count)
13819304Speter{
13919304Speter	sp->t_minrows = sp->t_rows = count;
14019304Speter	if (sp->t_rows > sp->rows - 1)
14119304Speter		sp->t_minrows = sp->t_rows = sp->rows - 1;
14219304Speter	TMAP = HMAP + (sp->t_rows - 1);
14319304Speter	F_SET(sp, SC_SCR_REDRAW);
14419304Speter	return (0);
14519304Speter}
146