示例#1
0
/*
 * vs_divider --
 *	Draw a dividing line between the screen and the output.
 */
static void
vs_divider(SCR *sp)
{
	GS *gp;
	size_t len;

#define	DIVIDESTR	"+=+=+=+=+=+=+=+"
	len =
	    sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
	gp = sp->gp;
	(void)gp->scr_attr(sp, SA_INVERSE, 1);
	(void)gp->scr_addstr(sp, DIVIDESTR, len);
	(void)gp->scr_attr(sp, SA_INVERSE, 0);
}
示例#2
0
/*
 * ex_exec_proc --
 *	Run a separate process.
 *
 * PUBLIC: int ex_exec_proc __P((SCR *, EXCMD *, const char *, const char *, int));
 */
int
ex_exec_proc(SCR *sp, EXCMD *cmdp, const char *cmd, const char *msg, int need_newline)
{
    GS *gp;
    const char *name;
    pid_t pid;

    gp = sp->gp;

    /* We'll need a shell. */
    if (opts_empty(sp, O_SHELL, 0))
        return (1);

    /* Enter ex mode. */
    if (F_ISSET(sp, SC_VI)) {
        if (gp->scr_screen(sp, SC_EX)) {
            ex_wemsg(sp, cmdp->cmd->name, EXM_NOCANON);
            return (1);
        }
        (void)gp->scr_attr(sp, SA_ALTERNATE, 0);
        F_SET(sp, SC_SCR_EX | SC_SCR_EXWROTE);
    }

    /* Put out additional newline, message. */
    if (need_newline)
        (void)ex_puts(sp, "\n");
    if (msg != NULL) {
        (void)ex_puts(sp, msg);
        (void)ex_puts(sp, "\n");
    }
    (void)ex_fflush(sp);

    switch (pid = vfork()) {
    case -1:			/* Error. */
        msgq(sp, M_SYSERR, "vfork");
        return (1);
    case 0:				/* Utility. */
        if (gp->scr_child)
            gp->scr_child(sp);
        if ((name = strrchr(O_STR(sp, O_SHELL), '/')) == NULL)
            name = O_STR(sp, O_SHELL);
        else
            ++name;
        execl(O_STR(sp, O_SHELL), name, "-c", cmd, (char *)NULL);
        msgq_str(sp, M_SYSERR, O_STR(sp, O_SHELL), "execl: %s");
        _exit(127);
    /* NOTREACHED */
    default:			/* Parent. */
        return (proc_wait(sp, (long)pid, cmd, 0, 0));
    }
    /* NOTREACHED */
}
/*
 * ex_init --
 *	Init the screen for ex.
 *
 * PUBLIC: int ex_init __P((SCR *));
 */
int
ex_init(SCR *sp)
{
	GS *gp;

	gp = sp->gp;

	if (gp->scr_screen(sp, SC_EX))
		return (1);
	(void)gp->scr_attr(sp, SA_ALTERNATE, 0);

	sp->rows = O_VAL(sp, O_LINES);
	sp->cols = O_VAL(sp, O_COLUMNS);

	F_CLR(sp, SC_VI);
	F_SET(sp, SC_EX | SC_SCR_EX);
	return (0);
}
示例#4
0
/*
 * vs_ex_resolve --
 *	Deal with ex message output.
 *
 * This routine is called when exiting a colon command to resolve any ex
 * output that may have occurred.
 *
 * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
 */
int
vs_ex_resolve(SCR *sp, int *continuep)
{
	EVENT ev;
	GS *gp;
	VI_PRIVATE *vip;
	sw_t wtype;

	gp = sp->gp;
	vip = VIP(sp);
	*continuep = 0;

	/* If we ran any ex command, we can't trust the cursor position. */
	F_SET(vip, VIP_CUR_INVALID);

	/* Terminate any partially written message. */
	if (vip->lcontinue != 0) {
		vs_output(sp, vip->mtype, ".", 1);
		vip->lcontinue = 0;

		vip->mtype = M_NONE;
	}

	/*
	 * If we switched out of the vi screen into ex, switch back while we
	 * figure out what to do with the screen and potentially get another
	 * command to execute.
	 *
	 * If we didn't switch into ex, we're not required to wait, and less
	 * than 2 lines of output, we can continue without waiting for the
	 * wait.
	 *
	 * Note, all other code paths require waiting, so we leave the report
	 * of modified lines until later, so that we won't wait for no other
	 * reason than a threshold number of lines were modified.  This means
	 * we display cumulative line modification reports for groups of ex
	 * commands.  That seems right to me (well, at least not wrong).
	 */
	if (F_ISSET(sp, SC_SCR_EXWROTE)) {
		if (sp->gp->scr_screen(sp, SC_VI))
			return (1);
	} else
		if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
			F_CLR(sp, SC_EX_WAIT_NO);
			return (0);
		}

	/* Clear the required wait flag, it's no longer needed. */
	F_CLR(sp, SC_EX_WAIT_YES);

	/*
	 * Wait, unless explicitly told not to wait or the user interrupted
	 * the command.  If the user is leaving the screen, for any reason,
	 * they can't continue with further ex commands.
	 */
	if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
		wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
		    SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
		if (F_ISSET(sp, SC_SCR_EXWROTE))
			vs_wait(sp, continuep, wtype);
		else
			vs_scroll(sp, continuep, wtype);
		if (*continuep)
			return (0);
	}

	/* If ex wrote on the screen, refresh the screen image. */
	if (F_ISSET(sp, SC_SCR_EXWROTE))
		F_SET(vip, VIP_N_EX_PAINT);

	/*
	 * If we're not the bottom of the split screen stack, the screen
	 * image itself is wrong, so redraw everything.
	 */
	if (sp->q.cqe_next != (void *)&sp->wp->scrq)
		F_SET(sp, SC_SCR_REDRAW);

	/* If ex changed the underlying file, the map itself is wrong. */
	if (F_ISSET(vip, VIP_N_EX_REDRAW))
		F_SET(sp, SC_SCR_REFORMAT);

	/* Ex may have switched out of the alternate screen, return. */
	(void)gp->scr_attr(sp, SA_ALTERNATE, 1);

	/*
	 * Whew.  We're finally back home, after what feels like years.
	 * Kiss the ground.
	 */
	F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);

	/*
	 * We may need to repaint some of the screen, e.g.:
	 *
	 *	:set
	 *	:!ls
	 *
	 * gives us a combination of some lines that are "wrong", and a need
	 * for a full refresh.
	 */
	if (vip->totalcount > 1) {
		/* Set up the redraw of the overwritten lines. */
		ev.e_event = E_REPAINT;
		ev.e_flno = vip->totalcount >=
		    sp->rows ? 1 : sp->rows - vip->totalcount;
		ev.e_tlno = sp->rows;

		/* Reset the count of overwriting lines. */
		vip->linecount = vip->lcontinue = vip->totalcount = 0;

		/* Redraw. */
		(void)v_erepaint(sp, &ev);
	} else
		/* Reset the count of overwriting lines. */
		vip->linecount = vip->lcontinue = vip->totalcount = 0;

	return (0);
}
示例#5
0
/*
 * vs_output --
 *	Output the text to the screen.
 */
static void
vs_output(SCR *sp, mtype_t mtype, const char *line, int llen)
{
	unsigned char *kp;
	GS *gp;
	VI_PRIVATE *vip;
	size_t chlen, notused;
	int ch, len, rlen, tlen;
	const char *p, *t;
	char *cbp, *ecbp, cbuf[128];

	gp = sp->gp;
	vip = VIP(sp);
	for (p = line, rlen = llen; llen > 0;) {
		/* Get the next physical line. */
		if ((p = memchr(line, '\n', llen)) == NULL)
			len = llen;
		else
			len = p - line;

		/*
		 * The max is sp->cols characters, and we may have already
		 * written part of the line.
		 */
		if (len + vip->lcontinue > sp->cols)
			len = sp->cols - vip->lcontinue;

		/*
		 * If the first line output, do nothing.  If the second line
		 * output, draw the divider line.  If drew a full screen, we
		 * remove the divider line.  If it's a continuation line, move
		 * to the continuation point, else, move the screen up.
		 */
		if (vip->lcontinue == 0) {
			if (!IS_ONELINE(sp)) {
				if (vip->totalcount == 1) {
					(void)gp->scr_move(sp,
					    LASTLINE(sp) - 1, 0);
					(void)gp->scr_clrtoeol(sp);
					(void)vs_divider(sp);
					F_SET(vip, VIP_DIVIDER);
					++vip->totalcount;
					++vip->linecount;
				}
				if (vip->totalcount == sp->t_maxrows &&
				    F_ISSET(vip, VIP_DIVIDER)) {
					--vip->totalcount;
					--vip->linecount;
					F_CLR(vip, VIP_DIVIDER);
				}
			}
			if (vip->totalcount != 0)
				vs_scroll(sp, NULL, SCROLL_W_QUIT);

			(void)gp->scr_move(sp, LASTLINE(sp), 0);
			++vip->totalcount;
			++vip->linecount;

			if (INTERRUPTED(sp))
				break;
		} else
			(void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);

		/* Error messages are in inverse video. */
		if (mtype == M_ERR)
			(void)gp->scr_attr(sp, SA_INVERSE, 1);

		/* Display the line, doing character translation. */
#define	FLUSH {								\
	*cbp = '\0';							\
	(void)gp->scr_addstr(sp, cbuf, cbp - cbuf);			\
	cbp = cbuf;							\
}
		ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
		for (t = line, tlen = len; tlen--; ++t) {
			ch = *t;
			/*
			 * Replace tabs with spaces, there are places in
			 * ex that do column calculations without looking
			 * at <tabs> -- and all routines that care about
			 * <tabs> do their own expansions.  This catches
			 * <tabs> in things like tag search strings.
			 */
			if (ch == '\t')
				ch = ' ';
			chlen = KEY_LEN(sp, ch);
			if (cbp + chlen >= ecbp)
				FLUSH;
			for (kp = KEY_NAME(sp, ch); chlen--;)
				*cbp++ = *kp++;
		}
		if (cbp > cbuf)
			FLUSH;
		if (mtype == M_ERR)
			(void)gp->scr_attr(sp, SA_INVERSE, 0);

		/* Clear the rest of the line. */
		(void)gp->scr_clrtoeol(sp);

		/* If we loop, it's a new line. */
		vip->lcontinue = 0;

		/* Reset for the next line. */
		line += len;
		llen -= len;
		if (p != NULL) {
			++line;
			--llen;
		}
	}

	/* Set up next continuation line. */
	if (p == NULL)
		gp->scr_cursor(sp, &notused, &vip->lcontinue);
}
示例#6
0
/*
 * vs_msg --
 *	Display ex output or error messages for the screen.
 *
 * This routine is the default editor interface for all ex output, and all ex
 * and vi error/informational messages.  It implements the standard strategy
 * of stealing lines from the bottom of the vi text screen.  Screens using an
 * alternate method of displaying messages, e.g. dialog boxes, should set their
 * scr_msg function to the correct function before calling the editor.
 *
 * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
 */
void
vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len)
{
	GS *gp;
	VI_PRIVATE *vip;
	size_t maxcols, oldx, oldy, padding;
	const char *e, *s, *t;

	gp = sp->gp;
	vip = VIP(sp);

	/*
	 * Ring the bell if it's scheduled.
	 *
	 * XXX
	 * Shouldn't we save this, too?
	 */
	if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED)) {
		if (F_ISSET(sp, SC_SCR_VI)) {
			F_CLR(gp, G_BELLSCHED);
			(void)gp->scr_bell(sp);
		} else
			F_SET(gp, G_BELLSCHED);
	}

	/*
	 * If vi is using the error line for text input, there's no screen
	 * real-estate for the error message.  Nothing to do without some
	 * information as to how important the error message is.
	 */
	if (F_ISSET(sp, SC_TINPUT_INFO))
		return;

	/*
	 * Ex or ex controlled screen output.
	 *
	 * If output happens during startup, e.g., a .exrc file, we may be
	 * in ex mode but haven't initialized the screen.  Initialize here,
	 * and in this case, stay in ex mode.
	 *
	 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
	 * forth between ex and vi, but the screen is trashed and we have
	 * to respect that.  Switch to ex mode long enough to put out the
	 * message.
	 *
	 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
	 * the screen, so previous opinions are ignored.
	 */
	if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
		if (!F_ISSET(sp, SC_SCR_EX)) {
			if (F_ISSET(sp, SC_SCR_EXWROTE)) {
				if (sp->gp->scr_screen(sp, SC_EX))
					return;
			} else
				if (ex_init(sp))
					return;
		}

		if (mtype == M_ERR)
			(void)gp->scr_attr(sp, SA_INVERSE, 1);
		(void)printf("%.*s", (int)len, line);
		if (mtype == M_ERR)
			(void)gp->scr_attr(sp, SA_INVERSE, 0);
		(void)fflush(stdout);

		F_CLR(sp, SC_EX_WAIT_NO);

		if (!F_ISSET(sp, SC_SCR_EX))
			(void)sp->gp->scr_screen(sp, SC_VI);
		return;
	}

	/* If the vi screen isn't ready, save the message. */
	if (!F_ISSET(sp, SC_SCR_VI)) {
		(void)vs_msgsave(sp, mtype, line, len);
		return;
	}

	/* Save the cursor position. */
	(void)gp->scr_cursor(sp, &oldy, &oldx);

	/* If it's an ex output message, just write it out. */
	if (mtype == M_NONE) {
		vs_output(sp, mtype, line, len);
		goto ret;
	}

	/*
	 * If it's a vi message, strip the trailing <newline> so we can
	 * try and paste messages together.
	 */
	if (line[len - 1] == '\n')
		--len;

	/*
	 * If a message won't fit on a single line, try to split on a <blank>.
	 * If a subsequent message fits on the same line, write a separator
	 * and output it.  Otherwise, put out a newline.
	 *
	 * Need up to two padding characters normally; a semi-colon and a
	 * separating space.  If only a single line on the screen, add some
	 * more for the trailing continuation message.
	 *
	 * XXX
	 * Assume that periods and semi-colons take up a single column on the
	 * screen.
	 *
	 * XXX
	 * There are almost certainly pathological cases that will break this
	 * code.
	 */
	if (IS_ONELINE(sp))
		(void)msg_cmsg(sp, CMSG_CONT_S, &padding);
	else
		padding = 0;
	padding += 2;

	maxcols = sp->cols - 1;
	if (vip->lcontinue != 0) {
		if (len + vip->lcontinue + padding > maxcols)
			vs_output(sp, vip->mtype, ".\n", 2);
		else  {
			vs_output(sp, vip->mtype, ";", 1);
			vs_output(sp, M_NONE, " ", 1);
		}
	}
	vip->mtype = mtype;
	for (s = line;; s = t) {
		for (; len > 0 && isblank((unsigned char)*s); --len, ++s);
		if (len == 0)
			break;
		if (len + vip->lcontinue > maxcols) {
			for (e = s + (maxcols - vip->lcontinue);
			    e > s && !isblank((unsigned char)*e); --e);
			if (e == s)
				 e = t = s + (maxcols - vip->lcontinue);
			else
				for (t = e; isblank((unsigned char)e[-1]); --e);
		} else
			e = t = s + len;

		/*
		 * If the message ends in a period, discard it, we want to
		 * gang messages where possible.
		 */
		len -= t - s;
		if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
			--e;
		vs_output(sp, mtype, s, e - s);

		if (len != 0)
			vs_output(sp, M_NONE, "\n", 1);

		if (INTERRUPTED(sp))
			break;
	}

ret:	(void)gp->scr_move(sp, oldy, oldx);
	(void)gp->scr_refresh(sp, 0);
}
示例#7
0
文件: vi.c 项目: Alkzndr/freebsd
/*
 * v_init --
 *	Initialize the vi screen.
 */
static int
v_init(SCR *sp)
{
	GS *gp;
	VI_PRIVATE *vip;

	gp = sp->gp;
	vip = VIP(sp);

	/* Switch into vi. */
	if (gp->scr_screen(sp, SC_VI))
		return (1);
	(void)gp->scr_attr(sp, SA_ALTERNATE, 1);

	F_CLR(sp, SC_EX | SC_SCR_EX);
	F_SET(sp, SC_VI);

	/*
	 * Initialize screen values.
	 *
	 * Small windows: see vs_refresh(), section 6a.
	 *
	 * 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 = vip->srows = O_VAL(sp, O_LINES);
	sp->cols = O_VAL(sp, O_COLUMNS);
	sp->t_rows = sp->t_minrows = O_VAL(sp, O_WINDOW);
	if (sp->rows != 1) {
		if (sp->t_rows > sp->rows - 1) {
			sp->t_minrows = sp->t_rows = sp->rows - 1;
			msgq(sp, M_INFO,
			    "214|Windows option value is too large, max is %u",
			    (u_int)sp->t_rows);
		}
		sp->t_maxrows = sp->rows - 1;
	} else
		sp->t_maxrows = 1;
	sp->roff = sp->coff = 0;

	/* Create a screen map. */
	CALLOC_RET(sp, HMAP, SMAP *, SIZE_HMAP(sp), sizeof(SMAP));
	TMAP = HMAP + (sp->t_rows - 1);
	HMAP->lno = sp->lno;
	HMAP->coff = 0;
	HMAP->soff = 1;

	/*
	 * Fill the screen map from scratch -- try and center the line.  That
	 * way if we're starting with a file we've seen before, we'll put the
	 * line in the middle, otherwise, it won't work and we'll end up with
	 * the line at the top.
	 */
	F_SET(sp, SC_SCR_REFORMAT | SC_SCR_CENTER);

	/* Invalidate the cursor. */
	F_SET(vip, VIP_CUR_INVALID);

	/* Paint the screen image from scratch. */
	F_SET(vip, VIP_N_EX_PAINT);

	return (0);
}