⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 svi_screen.c

📁 早期freebsd实现
💻 C
字号:
/*- * Copyright (c) 1993, 1994 *	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 lintstatic char sccsid[] = "@(#)svi_screen.c	8.74 (Berkeley) 4/17/94";#endif /* not lint */#include <sys/types.h>#include <sys/queue.h>#include <sys/time.h>#include <bitstring.h>#include <errno.h>#include <limits.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <termios.h>#include <unistd.h>#include "compat.h"#include <curses.h>#include <db.h>#include <regex.h>#include "vi.h"#include "vcmd.h"#include "excmd.h"#include "svi_screen.h"#include "sex/sex_screen.h"static void	d_to_h __P((SCR *, char *));/* * svi_screen_init -- *	Initialize a screen. */intsvi_screen_init(sp)	SCR *sp;{	/* Initialize support routines. */	sp->s_bell		= svi_bell;	sp->s_bg		= svi_bg;	sp->s_busy		= svi_busy;	sp->s_change		= svi_change;	sp->s_clear		= svi_clear;	sp->s_colpos		= svi_cm_public;	sp->s_column		= svi_column;	sp->s_confirm		= svi_confirm;	sp->s_crel		= svi_crel;	sp->s_down		= svi_sm_down;	sp->s_edit		= svi_screen_edit;	sp->s_end		= svi_screen_end;	sp->s_ex_cmd		= svi_ex_cmd;	sp->s_ex_run		= svi_ex_run;	sp->s_ex_write		= svi_ex_write;	sp->s_fg		= svi_fg;	sp->s_fill		= svi_sm_fill;	sp->s_get		= svi_get;	sp->s_key_read		= sex_key_read;	sp->s_optchange		= svi_optchange;	sp->s_position		= svi_sm_position;	sp->s_rabs		= svi_rabs;	sp->s_rcm		= svi_rcm;	sp->s_refresh		= svi_refresh;	sp->s_split		= svi_split;	sp->s_suspend		= svi_suspend;	sp->s_up		= svi_sm_up;	return (0);}/* * svi_screen_copy -- *	Copy to a new screen. */intsvi_screen_copy(orig, sp)	SCR *orig, *sp;{	SVI_PRIVATE *osvi, *nsvi;	/* Create the private screen structure. */	CALLOC_RET(orig, nsvi, SVI_PRIVATE *, 1, sizeof(SVI_PRIVATE));	sp->svi_private = nsvi;/* INITIALIZED AT SCREEN CREATE. */	/* Invalidate the line size cache. */	SVI_SCR_CFLUSH(nsvi);/* PARTIALLY OR COMPLETELY COPIED FROM PREVIOUS SCREEN. */	if (orig == NULL) {	} else {		osvi = SVP(orig);		nsvi->srows = osvi->srows;		if (osvi->VB != NULL && (nsvi->VB = strdup(osvi->VB)) == NULL) {			msgq(sp, M_SYSERR, NULL);			return (1);		}		F_SET(nsvi, F_ISSET(osvi, SVI_NO_VBELL));	}	return (0);}/* * svi_screen_end -- *	End a screen. */intsvi_screen_end(sp)	SCR *sp;{	int rval;	rval = 0;	/*	 * XXX	 * If this is the last screen, end curses	 * while we still have screen information.	 */	if (sp->q.cqe_prev == (void *)&sp->gp->dq &&	    sp->q.cqe_next == (void *)&sp->gp->dq &&	    sp->gp->hq.cqh_first == (void *)&sp->gp->hq &&	    svi_curses_end(sp))		rval = 1;	/* Free screen map. */	if (HMAP != NULL)		FREE(HMAP, SIZE_HMAP(sp) * sizeof(SMAP));	/* Free visual bell string. */	if (SVP(sp)->VB != NULL)		free(SVP(sp)->VB);	/* Free private memory. */	FREE(SVP(sp), sizeof(SVI_PRIVATE));	sp->svi_private = NULL;	return (rval);}/* * We use a single curses "window" for each vi screen.  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_screen_edit -- *	Main vi curses screen loop. */intsvi_screen_edit(sp, ep)	SCR *sp;	EXF *ep;{	SCR *tsp;	int force;	/* Get refresh to init curses. */	F_SET(sp, S_RESIZE);	for (;;) {		/* Reset the cursor. */		F_SET(SVP(sp), SVI_CUR_INVALID);		/*		 * Run vi.  If vi fails, svi data structures may be		 * corrupted, be extremely careful what you free up.		 */		if (vi(sp, sp->ep)) {			if (F_ISSET(ep, F_RCV_ON)) {				F_SET(ep, F_RCV_NORM);				(void)rcv_sync(sp, sp->ep);			}			(void)file_end(sp, sp->ep, 1);	/* End the file. */			(void)screen_end(sp);		/* End the screen. */			return (1);		}		force = 0;		switch (F_ISSET(sp, S_MAJOR_CHANGE)) {		case S_EXIT_FORCE:			force = 1;			/* FALLTHROUGH */		case S_EXIT:			F_CLR(sp, S_EXIT_FORCE | S_EXIT);			if (file_end(sp, sp->ep, force))/* End the file. */				break;			(void)svi_join(sp, &tsp);	/* Find a new screen. */			if (tsp == NULL)				(void)svi_swap(sp, &tsp, NULL);			(void)screen_end(sp);		/* End the screen. */			if ((sp = tsp) == NULL)		/* Switch. */				return (0);			break;		case 0:					/* Exit vi mode. */			(void)svi_curses_end(sp);	/* End curses. */			d_to_h(sp, "Exit from vi");			return (0);		case S_FSWITCH:				/* File switch. */			F_CLR(sp, S_FSWITCH);			F_SET(sp, S_REFORMAT);			break;		case S_SSWITCH:				/* Screen switch. */			F_CLR(sp, S_SSWITCH);			sp = sp->nextdisp;			break;		default:			abort();		}	}	/* NOTREACHED */}/* * svi_curses_init -- *	Initialize curses. */intsvi_curses_init(sp)	SCR *sp;{	struct termios t;	int ixoff, ixon;	char *p;	/*	 * Vi wants raw mode, excepting flow control characters.  Both	 * cbreak and raw modes have problems for us.  In cbreak mode,	 * we have to turn all the signals off explicitly.  In raw mode,	 * we have to turn flow control back on.  Raw chosen for no strong	 * reason.  In both cases we have to periodically turn various	 * signals on.	 */	if (tcgetattr(STDIN_FILENO, &t)) {		msgq(sp, M_SYSERR, "tcgetattr");		return (1);	}	ixon = t.c_iflag & IXON;	ixoff = t.c_iflag & IXOFF;	errno = 0;#ifdef SYSV_CURSES	/*	 * The SunOS/System V initscr() isn't reentrant.  Don't even think	 * about trying to use it.  It fails in subtle ways (e.g. select(2)	 * on fileno(stdin) stops working).  NB: the options initialization	 * code already called setterm.  We don't care about the SCREEN *	 * returned by newterm, we never have more than one SCREEN at a time	 * anyway.	 */	if (newterm(O_STR(sp, O_TERM), stdout, stdin) == NULL) {		msgq(sp, errno ? M_SYSERR : M_ERR, "newterm failed");		return (1);	}#else	/*	 * Initscr() doesn't provide useful error values or messages.  The	 * reasonable guess is that either malloc failed or the terminal was	 * unknown or lacking some essential feature.  Try and guess so the	 * user isn't even more pissed off because of the error message.	 */	if (initscr() == NULL) {		char kbuf[2048];		msgq(sp, errno ? M_SYSERR : M_ERR, "initscr failed");		if ((p = getenv("TERM")) == NULL || !strcmp(p, "unknown"))			msgq(sp, M_ERR,	"No TERM environment variable set, or TERM set to \"unknown\".");		else if (tgetent(kbuf, p) != 1)			msgq(sp, M_ERR,"%s: unknown terminal type, or terminal lacks necessary features.", p);		else			msgq(sp, M_ERR,		    "%s: terminal type lacks necessary features.", p);		return (1);	}#endif	/*	 * !!!	 * If raw isn't turning off echo and newlines, something's wrong.	 * However, just in case...	 */	noecho();			/* No character echo. */	nonl();				/* No CR/NL translation. */	raw();				/* No special characters. */	idlok(stdscr, 1);		/* Use hardware insert/delete line. */	/* Put the cursor keys into application mode. */	svi_keypad(sp, 1);	/*	 * XXX	 * When we call the curses raw() routine, XON/XOFF flow control is	 * turned off.  Old terminals like to have it, so if it's originally	 * set for the tty, we turn it back on.	 */	if ((ixon || ixoff) && !tcgetattr(STDIN_FILENO, &t)) {		if (ixon)			t.c_iflag |= IXON;		if (ixoff)			t.c_iflag |= IXOFF;		(void)tcsetattr(STDIN_FILENO, TCSASOFT | TCSADRAIN, &t);	}	/*	 * The first screen in the list gets it all.  All other screens	 * are hidden and lose their maps.	 */	d_to_h(sp, "Window resize");	/* Initialize terminal values. */	SVP(sp)->srows = O_VAL(sp, O_LINES);	/*	 * Initialize screen values.	 *	 * Small windows: see svi/svi_refresh.c:svi_refresh, section 3b.	 *	 * Setup:	 *	t_minrows is the minimum rows to display	 *	t_maxrows is the maximum rows to display (rows - 1)	 *	t_rows is the rows currently being displayed	 */	sp->rows = SVP(sp)->srows;	sp->cols = O_VAL(sp, O_COLUMNS);	sp->woff = 0;	sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);	if (sp->t_rows > sp->rows - 1) {		sp->t_minrows = sp->t_rows = sp->rows - 1;		msgq(sp, M_INFO,		    "Windows option value is too large, max is %u", sp->t_rows);	}	sp->t_maxrows = sp->rows - 1;	/* Create the screen map. */	CALLOC(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));	if (HMAP == NULL) {		endwin();		return (1);	}	TMAP = HMAP + (sp->t_rows - 1);	F_SET(sp->gp, G_CURSES_INIT);		/* Curses initialized. */	F_SET(SVP(sp), SVI_CUR_INVALID);	/* Cursor is invalid. */	return (0);}/* * svi_crel -- *	Change the relative size of the current screen. */intsvi_crel(sp, count)	SCR *sp;	long count;{	/* Can't grow beyond the size of the window. */	if (count > O_VAL(sp, O_WINDOW))		count = O_VAL(sp, O_WINDOW);	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, S_REDRAW);	return (0);}/* * svi_curses_end -- *	Move to the bottom of the screen, end curses. */intsvi_curses_end(sp)	SCR *sp;{	/* We get called before anything has been initialized. */	if (!F_ISSET(sp->gp, G_CURSES_INIT))		return (0);	F_CLR(sp->gp, G_CURSES_INIT);	/* Move to the bottom of the screen. */	if (move(INFOLINE(sp), 0) == OK) {		clrtoeol();		refresh();	}	/* Restore the cursor keys to normal mode. */	svi_keypad(sp, 0);	/* End curses window. */	endwin();	return (0);}/* * d_to_h -- *	Move all but the current screen to the hidden queue. */static voidd_to_h(sp, emsg)	SCR *sp;	char *emsg;{	SCR *tsp;	int hidden;	for (hidden = 0;	    (tsp = sp->gp->dq.cqh_first) != (void *)&sp->gp->dq; ++hidden) {		if (_HMAP(tsp) != NULL) {			FREE(_HMAP(tsp), SIZE_HMAP(tsp) * sizeof(SMAP));			_HMAP(tsp) = NULL;		}		CIRCLEQ_REMOVE(&sp->gp->dq, tsp, q);		CIRCLEQ_INSERT_TAIL(&sp->gp->hq, tsp, q);	}	CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);	CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q);	if (hidden > 1)		msgq(sp, M_INFO,	    "%s backgrounded %d screens; use :display to list the screens.",		    emsg, hidden - 1);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -