summaryrefslogtreecommitdiff
path: root/usr.bin/vi/svi/svi_screen.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/vi/svi/svi_screen.c')
-rw-r--r--usr.bin/vi/svi/svi_screen.c336
1 files changed, 336 insertions, 0 deletions
diff --git a/usr.bin/vi/svi/svi_screen.c b/usr.bin/vi/svi/svi_screen.c
new file mode 100644
index 00000000000..f7d3f88703f
--- /dev/null
+++ b/usr.bin/vi/svi/svi_screen.c
@@ -0,0 +1,336 @@
+/*-
+ * 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 lint
+static char sccsid[] = "@(#)svi_screen.c 8.94 (Berkeley) 8/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 "../vi/vcmd.h"
+#include "svi_screen.h"
+#include "../sex/sex_screen.h"
+
+/*
+ * svi_screen_init --
+ * Initialize a screen.
+ */
+int
+svi_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_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_fmap = svi_fmap;
+ sp->s_position = svi_sm_position;
+ sp->s_rabs = svi_rabs;
+ sp->s_rcm = svi_rcm;
+ sp->s_refresh = svi_refresh;
+ sp->s_scroll = svi_sm_scroll;
+ sp->s_split = svi_split;
+ sp->s_suspend = svi_suspend;
+ sp->s_window = sex_window;
+
+ return (0);
+}
+
+/*
+ * svi_screen_copy --
+ * Copy to a new screen.
+ */
+int
+svi_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_CURSES_INIT));
+ }
+ return (0);
+}
+
+/*
+ * svi_screen_end --
+ * End a screen.
+ */
+int
+svi_screen_end(sp)
+ SCR *sp;
+{
+ SVI_PRIVATE *svp;
+
+ svp = SVP(sp);
+
+ /* Free the screen map. */
+ if (HMAP != NULL)
+ FREE(HMAP, SIZE_HMAP(sp) * sizeof(SMAP));
+
+ /* Free the visual bell string. */
+ if (svp->VB != NULL)
+ free(svp->VB);
+
+ /* Free private memory. */
+ FREE(svp, sizeof(SVI_PRIVATE));
+ sp->svi_private = NULL;
+
+ return (0);
+}
+
+/*
+ * 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.
+ */
+int
+svi_screen_edit(sp, ep)
+ SCR *sp;
+ EXF *ep;
+{
+ SCR *tsp;
+ int ecurses, escreen, force, rval;
+
+ escreen = ecurses = rval = 0;
+
+ /* Initialize curses. */
+ if (svi_curses_init(sp)) {
+ escreen = 1;
+ goto err;
+ }
+ ecurses = 1;
+
+ /*
+ * The resize bit is probably set, as a result of the terminal being
+ * set. We clear it as we just finished initializing the screen.
+ * However, we will want to fill in the map from scratch, so provide
+ * a line number just in case, and set the reformat flag.
+ */
+ HMAP->lno = 1;
+ F_CLR(sp, S_RESIZE);
+ F_SET(sp, S_REFORMAT);
+
+ /*
+ * The historic 4BSD curses had an uneasy relationship with termcap.
+ * Termcap used a static buffer to hold the terminal information,
+ * which was was then used by the curses functions. We want to use
+ * it too, for lots of random things, but we've put it off until after
+ * svi_curses_init:initscr() was called. Do it now.
+ */
+ if (svi_term_init(sp))
+ goto err;
+
+ 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)) {
+ (void)rcv_sync(sp, sp->ep,
+ RCV_EMAIL | RCV_ENDSESSION | RCV_PRESERVE);
+ escreen = 1;
+ goto err;
+ }
+
+ 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))/* File end. */
+ break;
+ /*
+ * !!!
+ * NB: sp->frp may now be NULL, if it was a tmp file.
+ */
+ (void)svi_join(sp, &tsp); /* Find a new screen. */
+ if (tsp == NULL)
+ (void)svi_swap(sp, &tsp, NULL);
+ if (tsp == NULL) {
+ escreen = 1;
+ goto ret;
+ }
+ (void)screen_end(sp); /* Screen end. */
+ sp = tsp;
+ break;
+ case 0: /* Exit vi mode. */
+ svi_dtoh(sp, "Exit from vi");
+ goto ret;
+ 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();
+ }
+ }
+
+ if (0) {
+err: rval = 1;
+ }
+
+ret: if (svi_term_end(sp)) /* Terminal end (uses sp). */
+ rval = 1;
+ if (ecurses && svi_curses_end(sp)) /* Curses end (uses sp). */
+ rval = 1;
+ if (escreen && screen_end(sp)) /* Screen end. */
+ rval = 1;
+ return (rval);
+}
+
+/*
+ * svi_crel --
+ * Change the relative size of the current screen.
+ */
+int
+svi_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_dtoh --
+ * Move all but the current screen to the hidden queue.
+ */
+void
+svi_dtoh(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;
+ }
+ SIGBLOCK(sp->gp);
+ CIRCLEQ_REMOVE(&sp->gp->dq, tsp, q);
+ CIRCLEQ_INSERT_TAIL(&sp->gp->hq, tsp, q);
+ SIGUNBLOCK(sp->gp);
+ }
+ SIGBLOCK(sp->gp);
+ CIRCLEQ_REMOVE(&sp->gp->hq, sp, q);
+ CIRCLEQ_INSERT_TAIL(&sp->gp->dq, sp, q);
+ SIGUNBLOCK(sp->gp);
+ if (hidden > 1)
+ msgq(sp, M_INFO,
+ "%s backgrounded %d screens; use :display to list the screens",
+ emsg, hidden - 1);
+}