4.4BSD/usr/src/contrib/nvi/nvi/svi/svi_screen.c

Compare this file to the similar file:
Show the results in this format:

/*-
 * Copyright (c) 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef lint
static char sccsid[] = "@(#)svi_screen.c	8.1 (Berkeley) 6/12/93";
#endif /* not lint */

#include <sys/types.h>

#include <curses.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "vi.h"
#include "vcmd.h"
#include "recover.h"
#include "svi_screen.h"

static int	 screen_end __P((size_t));
static int	 screen_init __P((SCR *));
static SCR	*svi_next __P((SCR *));

/*
 * We use a single curses window for vi.  The model would be simpler with
 * two windows (one for the text, and one for the modeline) because
 * scrolling the text window down would work correctly then, not affecting
 * the mode line.  As it is we have to play games to make it look right.
 * The reason for this choice is that it would be difficult for curses to
 * optimize the movement, i.e. detect that the downward scroll isn't going
 * to change the modeline, set the scrolling region on the terminal and only
 * scroll the first part of the text window.  (Even if curses did detect it,
 * the set-scrolling-region terminal commands can't be used by curses because
 * it's indeterminate where the cursor ends up after they are sent.)
 */
/*
 * svi --
 *	Main vi curses screen loop.
 */
int
svi(sp, ep, spp)
	SCR *sp, **spp;
	EXF *ep;
{
	SCR *np;
	size_t saved_row;

	if (svi_init(sp))
		return (1);
	do {
		if (screen_init(sp))
			return (1);
		F_CLR(sp, S_RESIZE);		/* XXX block SIGWINCH */

		do {
			F_SET(sp, S_CUR_INVALID);
			if (vi(sp, sp->ep)) {
				F_SET(sp, S_EXIT_FORCE);
				if (F_ISSET(ep, F_RCV_ON)) {
					F_SET(ep, F_RCV_NORM);
					(void)rcv_sync(sp, sp->ep);
				}
			}

			saved_row = INFOLINE(sp);

			switch (F_ISSET(sp, S_MAJOR_CHANGE)) {
			case S_EXIT:
				if (file_stop(sp, sp->ep, 0))
					F_CLR(sp, S_EXIT);
				else
					goto noscreen;
				break;
			case S_EXIT_FORCE:
				if (file_stop(sp, sp->ep, 1))
					F_CLR(sp, S_EXIT_FORCE);
				else
					goto noscreen;
				break;
			case S_FSWITCH_FORCE:
				F_CLR(sp, S_FSWITCH_FORCE);
				if (file_stop(sp, sp->ep, 1))
					break;
				if (sp->enext->refcnt == 0 &&
				    file_start(sp, sp->enext, NULL) == NULL)
					goto noscreen;
				sp->eprev = sp->ep;
				sp->ep = sp->enext;
				if (sp != NULL)
					F_SET(sp, S_REFORMAT);
				break;
			case S_FSWITCH:
				F_CLR(sp, S_FSWITCH);
				if (file_stop(sp, sp->ep, 0))
					break;
				if (sp->enext->refcnt == 0 &&
				    file_start(sp, sp->enext, NULL) == NULL) {
noscreen:				np = svi_next(sp);
					if (scr_end(sp))
						return (1);
					sp = np;
				} else {
					sp->eprev = sp->ep;
					sp->ep = sp->enext;
				}
				if (sp != NULL)
					F_SET(sp, S_REFORMAT);
				break;
			case S_SSWITCH:
				F_CLR(sp, S_SSWITCH);
				sp = sp->snext;
				break;
			case 0:
				break;
			default:
				abort();
			}
		} while (sp != NULL && F_ISSET(sp, S_MODE_VI) &&
		    !F_ISSET(sp, S_EXIT | S_EXIT_FORCE | S_RESIZE));

		if (screen_end(saved_row))
			return (1);
	} while (sp != NULL && F_ISSET(sp, S_MODE_VI) &&
	    !F_ISSET(sp, S_EXIT | S_EXIT_FORCE));
	*spp = sp;
	return (0);
}

/*
 * svi_init --
 *	Initialize a screen.
 */
int
svi_init(sp)
	SCR *sp;
{
	/* Initialize support routines. */
	sp->s_bell		= svi_bell;
	sp->s_busy_cursor	= svi_busy_cursor;
	sp->s_change		= svi_change;
	sp->s_chposition	= svi_chposition;
	sp->s_confirm		= svi_confirm;
	sp->s_down		= svi_sm_down;
	sp->s_ex_cmd		= svi_ex_cmd;
	sp->s_ex_run		= svi_ex_run;
	sp->s_ex_write		= svi_ex_write;
	sp->s_fill		= svi_sm_fill;
	sp->s_get		= svi_get;
	sp->s_position		= svi_sm_position;
	sp->s_refresh		= svi_refresh;
	sp->s_relative		= svi_relative;
	sp->s_split		= svi_split;
	sp->s_suspend		= svi_suspend;
	sp->s_up		= svi_sm_up;
	return (0);
}

/*
 * screen_init --
 *	Initialize curses, the screen structure.
 */
static int
screen_init(sp)
	SCR *sp;
{
	if (initscr() == NULL) {	/* Start the screen. */
		msgq(sp, M_ERR, "Error: initscr failed: %s", strerror(errno));
		return (1);
	}
	raw();				/* No special characters. */
	noecho();			/* No character echo. */
	idlok(stdscr, 1);		/* Use hardware scrolling. */

	/* Initialize line/cols values. */
	sp->rows = sp->w_rows = LINES;
	sp->cols = COLS;		/* LINES, COLS: XXX */
	sp->sc_row = sp->sc_col = 0;
	sp->t_rows = LINES - 1;

	/* Create the screen map. */
	if ((sp->h_smap = malloc(sp->w_rows * sizeof(SMAP))) == NULL)
		return (1);
	sp->t_smap = sp->h_smap + (sp->t_rows - 1);

	/* Turn off any optimizations. */
	sp->olno = OOBLNO;

	return (0);
}

/*
 * screen_end --
 *	Move to the bottom of the screen, end curses.
 */
static int
screen_end(row)
	size_t row;
{
	if (move(row, 0) == OK) {
		clrtoeol();
		refresh();
	}
	endwin();
	return (0);
}

/*
 * svi_next --
 *	Find a related screen to edit.
 */
static SCR *
svi_next(sp)
	SCR *sp;
{
	SCR *p;

	/* If a split screen, add space to parent/child. */
	if ((p = sp->parent) != NULL) {
		p->rows += sp->rows;
		p->t_rows += sp->t_rows + 1;
		p->t_smap = p->h_smap + (p->t_rows - 1);
		if (svi_sm_fill(p, p->ep, p->lno, P_FILL))
			return (NULL);

		F_SET(p, S_REDRAW);
		return (p);
	}
	if ((p = sp->child) != NULL) {
		p->rows += sp->rows;
		p->t_rows += sp->t_rows + 1;
		p->t_smap = p->h_smap + (p->t_rows - 1);
		p->s_off = sp->s_off;
		if (svi_sm_fill(p, p->ep, p->lno, P_FILL))
			return (NULL);

		F_SET(p, S_REDRAW);
		return (p);
	}
	return (NULL);
}