missing pieces in previous patch
[nvi.git] / vi / vs_msg.c
blob458c86814e66cc699564f9673967238c006491f2
1 /*-
2 * Copyright (c) 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1992, 1993, 1994, 1995, 1996
5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
8 */
10 #include "config.h"
12 #ifndef lint
13 static const char sccsid[] = "$Id: vs_msg.c,v 10.83 2001/06/09 18:26:32 skimo Exp $ (Berkeley) $Date: 2001/06/09 18:26:32 $";
14 #endif /* not lint */
16 #include <sys/types.h>
17 #include <sys/queue.h>
18 #include <sys/time.h>
20 #include <bitstring.h>
21 #include <ctype.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
27 #include "../common/common.h"
28 #include "vi.h"
30 typedef enum {
31 SCROLL_W, /* User wait. */
32 SCROLL_W_EX, /* User wait, or enter : to continue. */
33 SCROLL_W_QUIT /* User wait, or enter q to quit. */
35 * SCROLL_W_QUIT has another semantic
36 * -- only wait if the screen is full
38 } sw_t;
40 static void vs_divider __P((SCR *));
41 static void vs_msgsave __P((SCR *, mtype_t, char *, size_t));
42 static void vs_output __P((SCR *, mtype_t, const char *, int));
43 static void vs_scroll __P((SCR *, int *, sw_t));
44 static void vs_wait __P((SCR *, int *, sw_t));
47 * vs_busy --
48 * Display, update or clear a busy message.
50 * This routine is the default editor interface for vi busy messages. It
51 * implements a standard strategy of stealing lines from the bottom of the
52 * vi text screen. Screens using an alternate method of displaying busy
53 * messages, e.g. X11 clock icons, should set their scr_busy function to the
54 * correct function before calling the main editor routine.
56 * PUBLIC: void vs_busy __P((SCR *, const char *, busy_t));
58 void
59 vs_busy(sp, msg, btype)
60 SCR *sp;
61 const char *msg;
62 busy_t btype;
64 GS *gp;
65 VI_PRIVATE *vip;
66 static const char flagc[] = "|/-\\";
67 struct timeval tv;
68 size_t len, notused;
69 const char *p;
71 /* Ex doesn't display busy messages. */
72 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE))
73 return;
75 gp = sp->gp;
76 vip = VIP(sp);
79 * Most of this routine is to deal with the screen sharing real estate
80 * between the normal edit messages and the busy messages. Logically,
81 * all that's needed is something that puts up a message, periodically
82 * updates it, and then goes away.
84 switch (btype) {
85 case BUSY_ON:
86 ++vip->busy_ref;
87 if (vip->totalcount != 0 || vip->busy_ref != 1)
88 break;
90 /* Initialize state for updates. */
91 vip->busy_ch = 0;
92 (void)gettimeofday(&vip->busy_tv, NULL);
94 /* Save the current cursor. */
95 (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx);
97 /* Display the busy message. */
98 p = msg_cat(sp, msg, &len);
99 (void)gp->scr_move(sp, LASTLINE(sp), 0);
100 (void)gp->scr_addstr(sp, p, len);
101 (void)gp->scr_cursor(sp, &notused, &vip->busy_fx);
102 (void)gp->scr_clrtoeol(sp);
103 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
104 break;
105 case BUSY_OFF:
106 if (vip->busy_ref == 0)
107 break;
108 --vip->busy_ref;
111 * If the line isn't in use for another purpose, clear it.
112 * Always return to the original position.
114 if (vip->totalcount == 0 && vip->busy_ref == 0) {
115 (void)gp->scr_move(sp, LASTLINE(sp), 0);
116 (void)gp->scr_clrtoeol(sp);
118 (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx);
119 break;
120 case BUSY_UPDATE:
121 if (vip->totalcount != 0 || vip->busy_ref == 0)
122 break;
124 /* Update no more than every 1/8 of a second. */
125 (void)gettimeofday(&tv, NULL);
126 if (((tv.tv_sec - vip->busy_tv.tv_sec) * 1000000 +
127 (tv.tv_usec - vip->busy_tv.tv_usec)) < 125000)
128 return;
129 vip->busy_tv = tv;
131 /* Display the update. */
132 if (vip->busy_ch == sizeof(flagc) - 1)
133 vip->busy_ch = 0;
134 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
135 (void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1);
136 (void)gp->scr_move(sp, LASTLINE(sp), vip->busy_fx);
137 break;
139 (void)gp->scr_refresh(sp, 0);
143 * vs_home --
144 * Home the cursor to the bottom row, left-most column.
146 * PUBLIC: void vs_home __P((SCR *));
148 void
149 vs_home(sp)
150 SCR *sp;
152 (void)sp->gp->scr_move(sp, LASTLINE(sp), 0);
153 (void)sp->gp->scr_refresh(sp, 0);
157 * vs_update --
158 * Update a command.
160 * PUBLIC: void vs_update __P((SCR *, const char *, const CHAR_T *));
162 void
163 vs_update(SCR *sp, const char *m1, const CHAR_T *m2)
165 GS *gp;
166 size_t len, mlen, oldx, oldy;
167 CONST char *np;
168 size_t nlen;
170 gp = sp->gp;
173 * This routine displays a message on the bottom line of the screen,
174 * without updating any of the command structures that would keep it
175 * there for any period of time, i.e. it is overwritten immediately.
177 * It's used by the ex read and ! commands when the user's command is
178 * expanded, and by the ex substitution confirmation prompt.
180 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
181 if (m2 != NULL)
182 INT2CHAR(sp, m2, STRLEN(m2) + 1, np, nlen);
183 (void)ex_printf(sp,
184 "%s\n", m1 == NULL? "" : m1, m2 == NULL ? "" : np);
185 (void)ex_fflush(sp);
189 * Save the cursor position, the substitute-with-confirmation code
190 * will have already set it correctly.
192 (void)gp->scr_cursor(sp, &oldy, &oldx);
194 /* Clear the bottom line. */
195 (void)gp->scr_move(sp, LASTLINE(sp), 0);
196 (void)gp->scr_clrtoeol(sp);
199 * XXX
200 * Don't let long file names screw up the screen.
202 if (m1 != NULL) {
203 mlen = len = strlen(m1);
204 if (len > sp->cols - 2)
205 mlen = len = sp->cols - 2;
206 (void)gp->scr_addstr(sp, m1, mlen);
207 } else
208 len = 0;
209 if (m2 != NULL) {
210 mlen = STRLEN(m2);
211 if (len + mlen > sp->cols - 2)
212 mlen = (sp->cols - 2) - len;
213 (void)gp->scr_waddstr(sp, m2, mlen);
216 (void)gp->scr_move(sp, oldy, oldx);
217 (void)gp->scr_refresh(sp, 0);
221 * vs_msg --
222 * Display ex output or error messages for the screen.
224 * This routine is the default editor interface for all ex output, and all ex
225 * and vi error/informational messages. It implements the standard strategy
226 * of stealing lines from the bottom of the vi text screen. Screens using an
227 * alternate method of displaying messages, e.g. dialog boxes, should set their
228 * scr_msg function to the correct function before calling the editor.
230 * PUBLIC: void vs_msg __P((SCR *, mtype_t, char *, size_t));
232 void
233 vs_msg(sp, mtype, line, len)
234 SCR *sp;
235 mtype_t mtype;
236 char *line;
237 size_t len;
239 GS *gp;
240 VI_PRIVATE *vip;
241 size_t maxcols, oldx, oldy, padding;
242 const char *e, *s, *t;
244 gp = sp->gp;
245 vip = VIP(sp);
248 * Ring the bell if it's scheduled.
250 * XXX
251 * Shouldn't we save this, too?
253 if (F_ISSET(sp, SC_TINPUT_INFO) || F_ISSET(gp, G_BELLSCHED))
254 if (F_ISSET(sp, SC_SCR_VI)) {
255 F_CLR(gp, G_BELLSCHED);
256 (void)gp->scr_bell(sp);
257 } else
258 F_SET(gp, G_BELLSCHED);
261 * If vi is using the error line for text input, there's no screen
262 * real-estate for the error message. Nothing to do without some
263 * information as to how important the error message is.
265 if (F_ISSET(sp, SC_TINPUT_INFO))
266 return;
269 * Ex or ex controlled screen output.
271 * If output happens during startup, e.g., a .exrc file, we may be
272 * in ex mode but haven't initialized the screen. Initialize here,
273 * and in this case, stay in ex mode.
275 * If the SC_SCR_EXWROTE bit is set, then we're switching back and
276 * forth between ex and vi, but the screen is trashed and we have
277 * to respect that. Switch to ex mode long enough to put out the
278 * message.
280 * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to
281 * the screen, so previous opinions are ignored.
283 if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)) {
284 if (!F_ISSET(sp, SC_SCR_EX))
285 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
286 if (sp->gp->scr_screen(sp, SC_EX))
287 return;
288 } else
289 if (ex_init(sp))
290 return;
292 if (mtype == M_ERR)
293 (void)gp->scr_attr(sp, SA_INVERSE, 1);
294 (void)printf("%.*s", (int)len, line);
295 if (mtype == M_ERR)
296 (void)gp->scr_attr(sp, SA_INVERSE, 0);
297 (void)fflush(stdout);
299 F_CLR(sp, SC_EX_WAIT_NO);
301 if (!F_ISSET(sp, SC_SCR_EX))
302 (void)sp->gp->scr_screen(sp, SC_VI);
303 return;
306 /* If the vi screen isn't ready, save the message. */
307 if (!F_ISSET(sp, SC_SCR_VI)) {
308 (void)vs_msgsave(sp, mtype, line, len);
309 return;
312 /* Save the cursor position. */
313 (void)gp->scr_cursor(sp, &oldy, &oldx);
315 /* If it's an ex output message, just write it out. */
316 if (mtype == M_NONE) {
317 vs_output(sp, mtype, line, len);
318 goto ret;
322 * If it's a vi message, strip the trailing <newline> so we can
323 * try and paste messages together.
325 if (line[len - 1] == '\n')
326 --len;
329 * If a message won't fit on a single line, try to split on a <blank>.
330 * If a subsequent message fits on the same line, write a separator
331 * and output it. Otherwise, put out a newline.
333 * Need up to two padding characters normally; a semi-colon and a
334 * separating space. If only a single line on the screen, add some
335 * more for the trailing continuation message.
337 * XXX
338 * Assume that periods and semi-colons take up a single column on the
339 * screen.
341 * XXX
342 * There are almost certainly pathological cases that will break this
343 * code.
345 if (IS_ONELINE(sp))
346 (void)msg_cmsg(sp, CMSG_CONT_S, &padding);
347 else
348 padding = 0;
349 padding += 2;
351 maxcols = sp->cols - 1;
352 if (vip->lcontinue != 0)
353 if (len + vip->lcontinue + padding > maxcols)
354 vs_output(sp, vip->mtype, ".\n", 2);
355 else {
356 vs_output(sp, vip->mtype, ";", 1);
357 vs_output(sp, M_NONE, " ", 1);
359 vip->mtype = mtype;
360 for (s = line;; s = t) {
361 for (; len > 0 && isblank(*s); --len, ++s);
362 if (len == 0)
363 break;
364 if (len + vip->lcontinue > maxcols) {
365 for (e = s + (maxcols - vip->lcontinue);
366 e > s && !isblank(*e); --e);
367 if (e == s)
368 e = t = s + (maxcols - vip->lcontinue);
369 else
370 for (t = e; isblank(e[-1]); --e);
371 } else
372 e = t = s + len;
375 * If the message ends in a period, discard it, we want to
376 * gang messages where possible.
378 len -= t - s;
379 if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.')
380 --e;
381 vs_output(sp, mtype, s, e - s);
383 if (len != 0)
384 vs_output(sp, M_NONE, "\n", 1);
386 if (INTERRUPTED(sp))
387 break;
390 ret: (void)gp->scr_move(sp, oldy, oldx);
391 (void)gp->scr_refresh(sp, 0);
395 * vs_output --
396 * Output the text to the screen.
398 static void
399 vs_output(sp, mtype, line, llen)
400 SCR *sp;
401 mtype_t mtype;
402 const char *line;
403 int llen;
405 char *kp;
406 GS *gp;
407 VI_PRIVATE *vip;
408 size_t chlen, notused;
409 int ch, len, rlen, tlen;
410 const char *p, *t;
411 char *cbp, *ecbp, cbuf[128];
413 gp = sp->gp;
414 vip = VIP(sp);
415 for (p = line, rlen = llen; llen > 0;) {
416 /* Get the next physical line. */
417 if ((p = memchr(line, '\n', llen)) == NULL)
418 len = llen;
419 else
420 len = p - line;
423 * The max is sp->cols characters, and we may have already
424 * written part of the line.
426 if (len + vip->lcontinue > sp->cols)
427 len = sp->cols - vip->lcontinue;
430 * If the first line output, do nothing. If the second line
431 * output, draw the divider line. If drew a full screen, we
432 * remove the divider line. If it's a continuation line, move
433 * to the continuation point, else, move the screen up.
435 if (vip->lcontinue == 0) {
436 if (!IS_ONELINE(sp)) {
437 if (vip->totalcount == 1) {
438 (void)gp->scr_move(sp,
439 LASTLINE(sp) - 1, 0);
440 (void)gp->scr_clrtoeol(sp);
441 (void)vs_divider(sp);
442 F_SET(vip, VIP_DIVIDER);
443 ++vip->totalcount;
444 ++vip->linecount;
446 if (vip->totalcount == sp->t_maxrows &&
447 F_ISSET(vip, VIP_DIVIDER)) {
448 --vip->totalcount;
449 --vip->linecount;
450 F_CLR(vip, VIP_DIVIDER);
453 if (vip->totalcount != 0)
454 vs_scroll(sp, NULL, SCROLL_W_QUIT);
456 (void)gp->scr_move(sp, LASTLINE(sp), 0);
457 ++vip->totalcount;
458 ++vip->linecount;
460 if (INTERRUPTED(sp))
461 break;
462 } else
463 (void)gp->scr_move(sp, LASTLINE(sp), vip->lcontinue);
465 /* Error messages are in inverse video. */
466 if (mtype == M_ERR)
467 (void)gp->scr_attr(sp, SA_INVERSE, 1);
469 /* Display the line, doing character translation. */
470 #define FLUSH { \
471 *cbp = '\0'; \
472 (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \
473 cbp = cbuf; \
475 ecbp = (cbp = cbuf) + sizeof(cbuf) - 1;
476 for (t = line, tlen = len; tlen--; ++t) {
477 ch = *t;
479 * Replace tabs with spaces, there are places in
480 * ex that do column calculations without looking
481 * at <tabs> -- and all routines that care about
482 * <tabs> do their own expansions. This catches
483 * <tabs> in things like tag search strings.
485 if (ch == '\t')
486 ch = ' ';
487 chlen = KEY_LEN(sp, ch);
488 if (cbp + chlen >= ecbp)
489 FLUSH;
490 for (kp = KEY_NAME(sp, ch); chlen--;)
491 *cbp++ = *kp++;
493 if (cbp > cbuf)
494 FLUSH;
495 if (mtype == M_ERR)
496 (void)gp->scr_attr(sp, SA_INVERSE, 0);
498 /* Clear the rest of the line. */
499 (void)gp->scr_clrtoeol(sp);
501 /* If we loop, it's a new line. */
502 vip->lcontinue = 0;
504 /* Reset for the next line. */
505 line += len;
506 llen -= len;
507 if (p != NULL) {
508 ++line;
509 --llen;
513 /* Set up next continuation line. */
514 if (p == NULL)
515 gp->scr_cursor(sp, &notused, &vip->lcontinue);
519 * vs_ex_resolve --
520 * Deal with ex message output.
522 * This routine is called when exiting a colon command to resolve any ex
523 * output that may have occurred.
525 * PUBLIC: int vs_ex_resolve __P((SCR *, int *));
528 vs_ex_resolve(sp, continuep)
529 SCR *sp;
530 int *continuep;
532 EVENT ev;
533 GS *gp;
534 VI_PRIVATE *vip;
535 sw_t wtype;
537 gp = sp->gp;
538 vip = VIP(sp);
539 *continuep = 0;
541 /* If we ran any ex command, we can't trust the cursor position. */
542 F_SET(vip, VIP_CUR_INVALID);
544 /* Terminate any partially written message. */
545 if (vip->lcontinue != 0) {
546 vs_output(sp, vip->mtype, ".", 1);
547 vip->lcontinue = 0;
549 vip->mtype = M_NONE;
553 * If we switched out of the vi screen into ex, switch back while we
554 * figure out what to do with the screen and potentially get another
555 * command to execute.
557 * If we didn't switch into ex, we're not required to wait, and less
558 * than 2 lines of output, we can continue without waiting for the
559 * wait.
561 * Note, all other code paths require waiting, so we leave the report
562 * of modified lines until later, so that we won't wait for no other
563 * reason than a threshold number of lines were modified. This means
564 * we display cumulative line modification reports for groups of ex
565 * commands. That seems right to me (well, at least not wrong).
567 if (F_ISSET(sp, SC_SCR_EXWROTE)) {
568 if (sp->gp->scr_screen(sp, SC_VI))
569 return (1);
570 } else
571 if (!F_ISSET(sp, SC_EX_WAIT_YES) && vip->totalcount < 2) {
572 F_CLR(sp, SC_EX_WAIT_NO);
573 return (0);
576 /* Clear the required wait flag, it's no longer needed. */
577 F_CLR(sp, SC_EX_WAIT_YES);
580 * Wait, unless explicitly told not to wait or the user interrupted
581 * the command. If the user is leaving the screen, for any reason,
582 * they can't continue with further ex commands.
584 if (!F_ISSET(sp, SC_EX_WAIT_NO) && !INTERRUPTED(sp)) {
585 wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |
586 SC_FSWITCH | SC_SSWITCH) ? SCROLL_W : SCROLL_W_EX;
587 if (F_ISSET(sp, SC_SCR_EXWROTE))
588 vs_wait(sp, continuep, wtype);
589 else
590 vs_scroll(sp, continuep, wtype);
591 if (*continuep)
592 return (0);
595 /* If ex wrote on the screen, refresh the screen image. */
596 if (F_ISSET(sp, SC_SCR_EXWROTE))
597 F_SET(vip, VIP_N_EX_PAINT);
600 * If we're not the bottom of the split screen stack, the screen
601 * image itself is wrong, so redraw everything.
603 if (sp->q.cqe_next != (void *)&sp->wp->scrq)
604 F_SET(sp, SC_SCR_REDRAW);
606 /* If ex changed the underlying file, the map itself is wrong. */
607 if (F_ISSET(vip, VIP_N_EX_REDRAW))
608 F_SET(sp, SC_SCR_REFORMAT);
610 /* Ex may have switched out of the alternate screen, return. */
611 (void)gp->scr_attr(sp, SA_ALTERNATE, 1);
614 * Whew. We're finally back home, after what feels like years.
615 * Kiss the ground.
617 F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO);
620 * We may need to repaint some of the screen, e.g.:
622 * :set
623 * :!ls
625 * gives us a combination of some lines that are "wrong", and a need
626 * for a full refresh.
628 if (vip->totalcount > 1) {
629 /* Set up the redraw of the overwritten lines. */
630 ev.e_event = E_REPAINT;
631 ev.e_flno = vip->totalcount >=
632 sp->rows ? 1 : sp->rows - vip->totalcount;
633 ev.e_tlno = sp->rows;
635 /* Reset the count of overwriting lines. */
636 vip->linecount = vip->lcontinue = vip->totalcount = 0;
638 /* Redraw. */
639 (void)v_erepaint(sp, &ev);
640 } else
641 /* Reset the count of overwriting lines. */
642 vip->linecount = vip->lcontinue = vip->totalcount = 0;
644 return (0);
648 * vs_resolve --
649 * Deal with message output.
651 * PUBLIC: int vs_resolve __P((SCR *, SCR *, int));
654 vs_resolve(sp, csp, forcewait)
655 SCR *sp, *csp;
656 int forcewait;
658 EVENT ev;
659 GS *gp;
660 MSGS *mp;
661 VI_PRIVATE *vip;
662 size_t oldy, oldx;
663 int redraw;
666 * Vs_resolve is called from the main vi loop and the refresh function
667 * to periodically ensure that the user has seen any messages that have
668 * been displayed and that any status lines are correct. The sp screen
669 * is the screen we're checking, usually the current screen. When it's
670 * not, csp is the current screen, used for final cursor positioning.
672 gp = sp->gp;
673 vip = VIP(sp);
674 if (csp == NULL)
675 csp = sp;
677 /* Save the cursor position. */
678 (void)gp->scr_cursor(csp, &oldy, &oldx);
680 /* Ring the bell if it's scheduled. */
681 if (F_ISSET(gp, G_BELLSCHED)) {
682 F_CLR(gp, G_BELLSCHED);
683 (void)gp->scr_bell(sp);
686 /* Display new file status line. */
687 if (F_ISSET(sp, SC_STATUS)) {
688 F_CLR(sp, SC_STATUS);
689 msgq_status(sp, sp->lno, MSTAT_TRUNCATE);
692 /* Report on line modifications. */
693 mod_rpt(sp);
696 * Flush any saved messages. If the screen isn't ready, refresh
697 * it. (A side-effect of screen refresh is that we can display
698 * messages.) Once this is done, don't trust the cursor. That
699 * extra refresh screwed the pooch.
701 if (gp->msgq.lh_first != NULL) {
702 if (!F_ISSET(sp, SC_SCR_VI) && vs_refresh(sp, 1))
703 return (1);
704 while ((mp = gp->msgq.lh_first) != NULL) {
705 gp->scr_msg(sp, mp->mtype, mp->buf, mp->len);
706 LIST_REMOVE(mp, q);
707 free(mp->buf);
708 free(mp);
710 F_SET(vip, VIP_CUR_INVALID);
713 switch (vip->totalcount) {
714 case 0:
715 redraw = 0;
716 break;
717 case 1:
719 * If we're switching screens, we have to wait for messages,
720 * regardless. If we don't wait, skip updating the modeline.
722 if (forcewait)
723 vs_scroll(sp, NULL, SCROLL_W);
724 else
725 F_SET(vip, VIP_S_MODELINE);
727 redraw = 0;
728 break;
729 default:
731 * If >1 message line in use, prompt the user to continue and
732 * repaint overwritten lines.
734 vs_scroll(sp, NULL, SCROLL_W);
736 ev.e_event = E_REPAINT;
737 ev.e_flno = vip->totalcount >=
738 sp->rows ? 1 : sp->rows - vip->totalcount;
739 ev.e_tlno = sp->rows;
741 redraw = 1;
742 break;
745 /* Reset the count of overwriting lines. */
746 vip->linecount = vip->lcontinue = vip->totalcount = 0;
748 /* Redraw. */
749 if (redraw)
750 (void)v_erepaint(sp, &ev);
752 /* Restore the cursor position. */
753 (void)gp->scr_move(csp, oldy, oldx);
755 return (0);
759 * vs_scroll --
760 * Scroll the screen for output.
762 static void
763 vs_scroll(sp, continuep, wtype)
764 SCR *sp;
765 int *continuep;
766 sw_t wtype;
768 GS *gp;
769 VI_PRIVATE *vip;
771 gp = sp->gp;
772 vip = VIP(sp);
773 if (!IS_ONELINE(sp)) {
775 * Scroll the screen. Instead of scrolling the entire screen,
776 * delete the line above the first line output so preserve the
777 * maximum amount of the screen.
779 (void)gp->scr_move(sp, vip->totalcount <
780 sp->rows ? LASTLINE(sp) - vip->totalcount : 0, 0);
781 (void)gp->scr_deleteln(sp);
783 /* If there are screens below us, push them back into place. */
784 if (sp->q.cqe_next != (void *)&sp->wp->scrq) {
785 (void)gp->scr_move(sp, LASTLINE(sp), 0);
786 (void)gp->scr_insertln(sp);
789 if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows)
790 return;
791 vs_wait(sp, continuep, wtype);
795 * vs_wait --
796 * Prompt the user to continue.
798 static void
799 vs_wait(sp, continuep, wtype)
800 SCR *sp;
801 int *continuep;
802 sw_t wtype;
804 EVENT ev;
805 VI_PRIVATE *vip;
806 const char *p;
807 GS *gp;
808 size_t len;
810 gp = sp->gp;
811 vip = VIP(sp);
813 (void)gp->scr_move(sp, LASTLINE(sp), 0);
814 if (IS_ONELINE(sp))
815 p = msg_cmsg(sp, CMSG_CONT_S, &len);
816 else
817 switch (wtype) {
818 case SCROLL_W_QUIT:
819 p = msg_cmsg(sp, CMSG_CONT_Q, &len);
820 break;
821 case SCROLL_W_EX:
822 p = msg_cmsg(sp, CMSG_CONT_EX, &len);
823 break;
824 case SCROLL_W:
825 p = msg_cmsg(sp, CMSG_CONT, &len);
826 break;
827 default:
828 abort();
829 /* NOTREACHED */
831 (void)gp->scr_addstr(sp, p, len);
833 ++vip->totalcount;
834 vip->linecount = 0;
836 (void)gp->scr_clrtoeol(sp);
837 (void)gp->scr_refresh(sp, 0);
839 /* Get a single character from the terminal. */
840 if (continuep != NULL)
841 *continuep = 0;
842 for (;;) {
843 if (v_event_get(sp, &ev, 0, 0))
844 return;
845 if (ev.e_event == E_CHARACTER)
846 break;
847 if (ev.e_event == E_INTERRUPT) {
848 ev.e_c = CH_QUIT;
849 F_SET(gp, G_INTERRUPTED);
850 break;
852 (void)gp->scr_bell(sp);
854 switch (wtype) {
855 case SCROLL_W_QUIT:
856 if (ev.e_c == CH_QUIT)
857 F_SET(gp, G_INTERRUPTED);
858 break;
859 case SCROLL_W_EX:
860 if (ev.e_c == ':' && continuep != NULL)
861 *continuep = 1;
862 break;
863 case SCROLL_W:
864 break;
869 * vs_divider --
870 * Draw a dividing line between the screen and the output.
872 static void
873 vs_divider(sp)
874 SCR *sp;
876 GS *gp;
877 size_t len;
879 #define DIVIDESTR "+=+=+=+=+=+=+=+"
880 len =
881 sizeof(DIVIDESTR) - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR) - 1;
882 gp = sp->gp;
883 (void)gp->scr_attr(sp, SA_INVERSE, 1);
884 (void)gp->scr_addstr(sp, DIVIDESTR, len);
885 (void)gp->scr_attr(sp, SA_INVERSE, 0);
889 * vs_msgsave --
890 * Save a message for later display.
892 static void
893 vs_msgsave(sp, mt, p, len)
894 SCR *sp;
895 mtype_t mt;
896 char *p;
897 size_t len;
899 GS *gp;
900 MSGS *mp_c, *mp_n;
903 * We have to handle messages before we have any place to put them.
904 * If there's no screen support yet, allocate a msg structure, copy
905 * in the message, and queue it on the global structure. If we can't
906 * allocate memory here, we're genuinely screwed, dump the message
907 * to stderr in the (probably) vain hope that someone will see it.
909 CALLOC_GOTO(sp, mp_n, MSGS *, 1, sizeof(MSGS));
910 MALLOC_GOTO(sp, mp_n->buf, char *, len);
912 memmove(mp_n->buf, p, len);
913 mp_n->len = len;
914 mp_n->mtype = mt;
916 gp = sp->gp;
917 if ((mp_c = gp->msgq.lh_first) == NULL) {
918 LIST_INSERT_HEAD(&gp->msgq, mp_n, q);
919 } else {
920 for (; mp_c->q.le_next != NULL; mp_c = mp_c->q.le_next);
921 LIST_INSERT_AFTER(mp_c, mp_n, q);
923 return;
925 alloc_err:
926 if (mp_n != NULL)
927 free(mp_n);
928 (void)fprintf(stderr, "%.*s\n", (int)len, p);