예제 #1
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);
}
예제 #2
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);
}
예제 #3
0
/*
 * v_key --
 *	Return the next event.
 */
static gcret_t
v_key(SCR *sp, VICMD *vp, int events_ok, u_int32_t ec_flags)
{
	EVENT *evp;
	u_int32_t quote;

	for (evp = &vp->ev, quote = 0;;) {
		if (v_event_get(sp, evp, 0, ec_flags | quote))
			return (GC_FATAL);
		quote = 0;

		switch (evp->e_event) {
		case E_CHARACTER:
			/*
			 * !!!
			 * Historically, ^V was ignored in the command stream,
			 * although it had a useful side-effect of interrupting
			 * mappings.  Adding a quoting bit to the call probably
			 * extends historic practice, but it feels right.
			 */
			if (evp->e_value == K_VLNEXT) {
				quote = EC_QUOTED;
				break;
			}
			return (GC_OK);
		case E_ERR:
		case E_EOF:
			return (GC_FATAL);
		case E_INTERRUPT:
			/*
			 * !!!
			 * Historically, vi beeped on command level interrupts.
			 *
			 * Historically, vi exited to ex mode if no file was
			 * named on the command line, and two interrupts were
			 * generated in a row.  (I figured you might want to
			 * know that, just in case there's a quiz later.)
			 */
			(void)sp->gp->scr_bell(sp);
			return (GC_INTERRUPT);
		case E_REPAINT:
			if (v_erepaint(sp, evp))
				return (GC_FATAL);
			break;
		case E_WRESIZE:
			/*
			 * !!!
			 * We don't do anything here, just return an error.
			 * The vi loop will return because of this, and then
			 * the main loop will realize that we had to restart
			 * the world and will call the vi loop again.
			 */
			return (GC_ERR);
		case E_IPCOMMAND:
			if (events_ok)
				return (GC_EVENT);
			/* FALLTHROUGH */
		default:
			v_event_err(sp, evp);
			return (GC_ERR);
		}
	}
	/* NOTREACHED */
}