示例#1
0
/*
 * vs_resolve --
 *	Deal with message output.
 *
 * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
 */
int
vs_resolve(SCR *sp, SCR *csp, int forcewait)
{
	EVENT ev;
	GS *gp;
	WIN *wp;
	MSGS *mp;
	VI_PRIVATE *vip;
	size_t oldy, oldx;
	int redraw;

	/*
	 * Vs_resolve is called from the main vi loop and the refresh function
	 * to periodically ensure that the user has seen any messages that have
	 * been displayed and that any status lines are correct.  The sp screen
	 * is the screen we're checking, usually the current screen.  When it's
	 * not, csp is the current screen, used for final cursor positioning.
	 */
	gp = sp->gp;
	wp = sp->wp;
	vip = VIP(sp);
	if (csp == NULL)
		csp = sp;

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

	/* Ring the bell if it's scheduled. */
	if (F_ISSET(gp, G_BELLSCHED)) {
		F_CLR(gp, G_BELLSCHED);
		(void)gp->scr_bell(sp);
	}

	/* Display new file status line. */
	if (F_ISSET(sp, SC_STATUS)) {
		F_CLR(sp, SC_STATUS);
		msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
	}

	/* Report on line modifications. */
	mod_rpt(sp);

	/*
	 * Flush any saved messages.  If the screen isn't ready, refresh
	 * it.  (A side-effect of screen refresh is that we can display
	 * messages.)  Once this is done, don't trust the cursor.  That
	 * extra refresh screwed the pooch.
	 */
	if (gp->msgq.lh_first != NULL) {
		if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
			return (1);
		while ((mp = gp->msgq.lh_first) != NULL) {
			wp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
			LIST_REMOVE(mp, q);
			free(mp->buf);
			free(mp);
		}
		F_SET(vip, VIP_CUR_INVALID);
	}

	switch (vip->totalcount) {
	case 0:
		redraw = 0;
		break;
	case 1:
		/*
		 * If we're switching screens, we have to wait for messages,
		 * regardless.  If we don't wait, skip updating the modeline.
		 */
		if (forcewait)
			vs_scroll(sp, NULL, SCROLL_W);
		else
			F_SET(vip, VIP_S_MODELINE);

		redraw = 0;
		break;
	default:
		/*
		 * If >1 message line in use, prompt the user to continue and
		 * repaint overwritten lines.
		 */
		vs_scroll(sp, NULL, SCROLL_W);

		ev.e_event = E_REPAINT;
		ev.e_flno = vip->totalcount >=
		    sp->rows ? 1 : sp->rows - vip->totalcount;
		ev.e_tlno = sp->rows;

		redraw = 1;
		break;
	}

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

	/* Redraw. */
	if (redraw)
		(void)v_erepaint(sp, &ev);

	/* Restore the cursor position. */
	(void)gp->scr_move(csp, oldy, oldx);

	return (0);
}
示例#2
0
/*
 * vs_wait --
 *	Prompt the user to continue.
 */
static void
vs_wait(SCR *sp, int *continuep, sw_t wtype)
{
	EVENT ev;
	VI_PRIVATE *vip;
	const char *p;
	GS *gp;
	size_t len;

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

	(void)gp->scr_move(sp, LASTLINE(sp), 0);
	if (IS_ONELINE(sp))
		p = msg_cmsg(sp, CMSG_CONT_S, &len);
	else
		switch (wtype) {
		case SCROLL_W_QUIT:
			p = msg_cmsg(sp, CMSG_CONT_Q, &len);
			break;
		case SCROLL_W_EX:
			p = msg_cmsg(sp, CMSG_CONT_EX, &len);
			break;
		case SCROLL_W:
			p = msg_cmsg(sp, CMSG_CONT, &len);
			break;
		default:
			abort();
			/* NOTREACHED */
		}
	(void)gp->scr_addstr(sp, p, len);

	++vip->totalcount;
	vip->linecount = 0;

	(void)gp->scr_clrtoeol(sp);
	(void)gp->scr_refresh(sp, 0);

	/* Get a single character from the terminal. */
	if (continuep != NULL)
		*continuep = 0;
	for (;;) {
		if (v_event_get(sp, &ev, 0, 0))
			return;
		if (ev.e_event == E_CHARACTER)
			break;
		if (ev.e_event == E_INTERRUPT) {
			ev.e_c = CH_QUIT;
			F_SET(gp, G_INTERRUPTED);
			break;
		}
		(void)gp->scr_bell(sp);
	}
	switch (wtype) {
	case SCROLL_W_QUIT:
		if (ev.e_c == CH_QUIT)
			F_SET(gp, G_INTERRUPTED);
		break;
	case SCROLL_W_EX:
		if (ev.e_c == ':' && continuep != NULL)
			*continuep = 1;
		break;
	case SCROLL_W:
		break;
	}
}
示例#3
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);
}