/************************************************************************ * This program is Copyright (C) 1986 by Jonathan Payne. JOVE is * * provided to you without charge, and with no warranty. You may give * * away copies of JOVE, including sources, provided that this notice is * * included in all the files. * ************************************************************************/ /* * Modified: 1988-1990 by T.R.Hageman * some efficiency improvements; * re-worked ModeLine; * added horizontal window shift to DrawMesg if Asking; * explicitly erase Standout Mode lines instead of usurping 8th bit of * character as standout flag (see also screen.c and term.c) * move ID_CHAR stuff to screen.c */ #define NO_PROCDECL /* kludge for teensy pdp11 compiler */ #include "jove.h" RCS("$Id: disp.c,v 14.32.0.10 1994/04/29 11:59:22 tom Exp tom $") #include "ctype.h" #include "io.h" #include "process.h" /* for {HOLD,RELSE}_ALARM */ #include "screen.h" #ifndef NO_PROCDECL # include "termcap.h" #else extern const char *XS, *SO; extern int SG; #endif #ifdef TINY # undef putch #endif private void AddLines __(( int _(num), int _(top), int _(bot) )), DelLines __(( int _(num), int _(top), int _(bot) )), DoIDline __(( int _(start) )), UpdLine __(( int _(linenum) )); private int ModeLine __(( Window *_(w) )); DEF_INT( "mode-line-should-standout", BriteMode, V_BOOL|V_MODELINE ) = YES; _IF(def PRIVATE) DEF_INT( "visible-bell", VisBell, V_BOOL ) ZERO; int RingBell ZERO; /* So if we have a lot of errors ... ring the bell only ONCE */ void rbell() { if (False(Quiet)) RingBell++; } /* Kludge windows gets called by the routines that delete lines from the buffer. If the w->w_line or w->w_top are deleted and this procedure is not called, the redisplay routine will barf. */ void ChkWindows(line1, line2) Line *line1; register Line *line2; { register Window *w = fwind; register Line *lp; line2 = line2->l_next; do { for (lp = line1; (lp = lp->l_next) != line2; ) { if (lp == w->w_top) w->w_flags |= W_TOPGONE; if (lp == w->w_line) w->w_flags |= W_CURGONE; } w = w->w_next; } while (w != fwind); } void redisplay() { if (!Asking) { /* ...to allow scrolling while in ask */ register Window *w = curwind; /* make curwind consistent */ register Buffer *b = w->w_bufp; w->w_line = b->b_dot; w->w_char = b->b_char; } if (InputPending = charp()) return; HOLD_ALARM; if (RingBell) { /* ring the bell */ dobell(1); RingBell = 0; } if (UpdMesg) /* update message line */ DrawMesg(YES); { /* update windows */ register int lineno = 0; register Window *w = fwind; do { UpdWindow(w, lineno); lineno += w->w_height; w = w->w_next; } while (lineno < ILI); } scursoff(); { /* update changed lines */ register struct scrimage *des_p = DesiredScreen; register struct scrimage *phys_p = PhysScreen; register int i = 0, done_ID = NO; do { if (!done_ID && (des_p->s_id != phys_p->s_id)) { DoIDline(i); done_ID++; } if ((des_p->s_flags != phys_p->s_flags) || (des_p->s_id != phys_p->s_id) || (des_p->s_vln != phys_p->s_vln) || #ifdef COLOR (des_p->s_color != phys_p->s_color) || #endif (des_p->s_offset != phys_p->s_offset)) { UpdLine(i); if (InputPending) goto ret; } des_p++, phys_p++; } while (++i < ILI); } { register int line, col; if (Asking) { /* position cursor */ line = ILI; col = calc_pos(mesgbuf, Asking); /* nice kludge... */ } else { register Window *w = curwind; #ifdef WINDOWS if (w->w_control) SetScrollBar(w->w_control); #endif line = w->w_dotline; col = w->w_dotcol - PhysScreen[line].s_offset; } Placur(line, col); set_color(PhysScreen[line].s_color); } curson(); UpdModLine = 0; ret: RELSE_ALARM; #ifdef WINDOWS if (Windchange) docontrols(); #endif } DEF_CMD( "update-screen", UpdScreen, NO ) { inIOread++; /* to force redisplay to complete. */ redisplay(); inIOread--; } /* calc_pos() returns the position on the line, that c_char represents in line. */ int calc_pos(cp, c_char) register const char *cp; int c_char; { register int pos = 0; register int c; while ((--c_char >= 0) && (c = *cp++)) { UpdVisPos(pos, c); } return pos; } int UpdModLine ZERO, UpdMesg ZERO, CanScroll ZERO; /* * [TRH] Add scroll limit variable. If the fraction of lines to be * added or deleted compared to the affected region is larger than * this limit, the affected region is repainted instead of being * scrolled. The variable ScrollLimit can be changed by the user. * It is given as a percentage. A suitable default value for * ScollLimit is chosen by IDline_setup. */ DEF_INT( "repaint-threshold", ScrollLimit, V_BASE10|MAX(100) ) ZERO; #define ShouldScroll(n,reg) (((n)*100)/(reg) < ScrollLimit) private void DoIDline(start) { register struct scrimage *des_p, *phys_p; register int i, top, num, bottom; register void (*doit)__(( int _(num), int _(top), int _(bottom) )); /* Some changes have been made. Try for insert or delete lines. If either case has happened, Addlines and/or DelLines will do necessary scrolling, also CONVERTING PhysScreen to account for the physical changes. The comparison continues from where the insertion/deletion takes place; this doesn't happen very often, usually it happens with more than one window with the same buffer. */ if (!CanScroll) return; /* We should never have been called!! */ i = start; do { for (des_p = &DesiredScreen[i], phys_p = &PhysScreen[i]; des_p->s_id == phys_p->s_id; des_p++, phys_p++) if (++i >= ILI) return; /* found a "dirty" region; scan it for scrolled lines */ bottom = ILI; top = i; for (;;) { if (++i < bottom) { des_p++; phys_p++; } else { /* * We hit the end of the dirty region. * Advance top of region, reset scan pointers; * bail out when only a single line left. */ ++top; if ((i = top + 1) >= bottom) return; des_p = &DesiredScreen[i]; phys_p = &PhysScreen[i]; } if (des_p->s_id == phys_p->s_id) { /* the "real" end of dirty region */ bottom = i; continue; } if (des_p->s_id == PhysScreen[top].s_id) { phys_p = &PhysScreen[top]; doit = AddLines; break; } if (phys_p->s_id == DesiredScreen[top].s_id) { des_p = &DesiredScreen[top]; doit = DelLines; break; } } /* we only get here when we found a scrollable region */ num = i - top; /* * scan for end of scrolled region. * At this point we made sure that des_p and phys_p point to * equal lines, so advance pointers first. */ while ((++des_p)->s_id == (++phys_p)->s_id && des_p->s_id) if (++i >= ILI) break; /* scroll it */ if (ShouldScroll(num, i - top)) { set_color(phys_p[-1].s_color); cursoff(); (*doit)(num, top, i); } /* continue the scan */ } while (++i < ILI); } /* Calls the routine to do the physical changes, and changes PhysScreen to reflect those changes. */ /* PRE: ((num > 0) && (top + num < bot)) */ private void AddLines(num, top, bot) { register struct scrimage *dest = &PhysScreen[bot], *src = &dest[-num], *end = &PhysScreen[top]; v_ins_line(num, top, bot); /* Now change PhysScreen to account for the physical change. */ do { *dest = *src; } while (--dest, --src >= end); do { dest->s_id = 0; dest->s_flags = 0; /* for standout */ #ifdef COLOR if (XS) dest->s_color = 0; #endif } while (--dest >= end); } private void DelLines(num, top, bot) { register struct scrimage *dest = &PhysScreen[top], *src = &dest[num], *end = &PhysScreen[bot]; v_del_line(num, top, bot); /* Now change PhysScreen to account for the physical change. */ do { *dest = *src; } while (++dest, ++src <= end); do { dest->s_id = 0; dest->s_flags = 0; /* for standout */ #ifdef COLOR if (XS) dest->s_color = 0; #endif } while (++dest <= end); } DEF_INT( "scroll-all-lines", ScrollAll, V_BOOL ) ZERO; _IF(def PRIVATE) DEF_INT( "auto-scroll-margin", AutoScroll, V_BASE10|MAX(50) ) ZERO; _IF(def AUTOSCROLL)_IF(def PRIVATE) #if (HIGHLIGHT) DEF_INT( "highlight", HighLight, V_BOOL ) = YES; _IF( HIGHLIGHT) #endif /* * Make DesiredScreen reflect what the screen should look like when we are * done with the redisplay. This deals with horizontal scrolling. Also * makes sure the current line of the Window is in the window. */ void UpdWindow(w, start) register Window *w; { register Line *lp; int dot_offset, /* start column of dot line */ num_offset = 0; /* set if lines are numbered */ #ifdef COLOR char color = w->w_bufp->b_color; #endif #if (W_TOPNUM) int old_dotline = w->w_dotline; #endif if (w->w_flags & W_NUMLINES) num_offset = 8; if (w->w_flags & W_CURGONE) { register Buffer *b = w->w_bufp; w->w_line = b->b_dot; w->w_char = b->b_char; } if (w->w_flags & W_TOPGONE) CentWind(w); /* Reset topline of screen */ w->w_flags &= ~(W_CURGONE|W_TOPGONE); /* First, make sure that current line is visible in the window... */ { register int i, end = start + SIZE(w); /* Bottom of window */ { register int ntries = 0; /* # of tries at updating window. */ i = start; lp = w->w_top; while (lp != w->w_line) { if (lp && ++i < end) { lp = lp->l_next; continue; } /* if we get here, we didn't find dotline in the window */ if (ntries == 0) CalcWind(w); #ifndef TINY else if (ntries == 1) { /* this shouldn't happen. */ w->w_top = w->w_line = w->w_bufp->b_first; dobell(2); f_mess("?redisplay?"); } #endif else /* this REALLY shouldn't happen! */ finish(1); ntries++; i = start; lp = w->w_top; } } /* Now, do some calculations for the current line. If the new dotcol is out of range, reselect a horizontal window. Allow cursor at rightmost column, i.e., don't scroll horizontally if we are at end of line. */ { #ifndef TINY char *base = lcontents(lp); # define NUM_OFFSET (base[w->w_char] ? num_offset : num_offset - 1) #else # define base lcontents(lp) # define NUM_OFFSET num_offset #endif w->w_dotcol = calc_pos(base, w->w_char); if (True(ScrollAll) || (dot_offset = PhysScreen[i].s_offset) == 0) dot_offset = w->w_offset; dot_offset = HorWindow(w->w_dotcol, dot_offset, NUM_OFFSET); /* compensate for displayed line numbers */ w->w_dotcol += num_offset; /* update window's offset if we're scrolling rigidly with point */ if (True(ScrollAll) && (w->w_offset != dot_offset)) { updmodline(); w->w_offset = dot_offset; } lp = w->w_top; #undef base #undef NUM_OFFSET } #ifdef AUTOSCROLL /* Now, do the EDT-style auto-scrolling, IF not inhibited, AND auto-scrolling is enabled, AND we are current window, AND we have a transition INTO the `forbidden' region. */ { register int scrollmargin; if (w->w_flags & W_NOAUTOSCROLL) w->w_flags &= ~W_NOAUTOSCROLL; else if ((scrollmargin = AutoScroll) && (w == curwind) && (scrollmargin = scrollmargin * SIZE(w) / 100)) { start += scrollmargin; if (i < start) { if (start <= w->w_dotline) { /* try to scroll down (by moving topline up) so that dotline ends up at auto-scroll margin. This may not go all the way if we are near the beginning of the buffer. */ w->w_topnum -= (start - i); do { if (lp->l_prev) lp = lp->l_prev; else { w->w_topnum += (start - i); break; } } while (++i < start); } } else { /* border case. sigh... */ if ((end -= scrollmargin) == start) end += 1; if ((i >= end) && (w->w_dotline < end)) { /* scroll up (by moving topline down) so that dotline ends up at auto-scroll margin. This cannot fail. */ w->w_topnum += (i - end + 1); do { lp = lp->l_next; } while (--i >= end); } } start -= scrollmargin; w->w_top = lp; } } #endif /* AUTOSCROLL */ w->w_dotline = i; } { register struct scrimage *des_p = &DesiredScreen[start], *end_p = &des_p[SIZE(w)]; register int lnum = (num_offset) ? w->w_topnum : 0; do { if (lp == NULL) { /* no buffer line associated with this screen line */ static struct scrimage clean_plate ZERO; *des_p = clean_plate; #ifdef COLOR des_p->s_color = color; #endif continue; } des_p->s_window = w; des_p->s_lp = lp; des_p->s_id = lp->l_dline & ~DIRTY; des_p->s_flags = (int)(lp->l_dline) & DIRTY; if (des_p->s_vln = lnum) lnum++; des_p->s_offset = (lp == w->w_line) ? dot_offset : w->w_offset; #if (HIGHLIGHT) if (lp == w->w_highlighted_line && True(HighLight)) des_p->s_flags |= HIGHLIGHT; #endif lp = lp->l_next; #ifdef COLOR des_p->s_color = color; #endif } while (++des_p < end_p); /* mode line */ des_p->s_window = w; des_p->s_flags = (UpdModLine #if (W_TOPNUM) || (w->w_flags & W_TOPNUM && w->w_line != PhysScreen[old_dotline].s_lp) #endif ) ? MODELINE|DIRTY : MODELINE; des_p->s_id = (disk_line) w->w_bufp; #ifdef COLOR des_p->s_color = color; #endif if (False(BriteMode)) return; if (!SO) { BriteMode = NO; return; } des_p->s_flags |= STANDOUT; #ifdef COLOR /* * (we only get here when mode lines stand out.) * Black-and-white mode line looks better; try to make it stand out * against the rest of the window. Also make sure the mode line of * the PREVIOUS window stands out against the body of both current * and previous window. In the case of adjacent black- and white- * background windows we resort to a white-on-blue mode line. * Do the same check against the message line for the last window. */ if (color == 0) color = DefColor; des_p->s_color = (BG_COLOR(color) == FG_COLOR(DEF_COLOR)) ? MK_COLOR(BG_COLOR(DEF_COLOR), FG_COLOR(DEF_COLOR)) : DEF_COLOR; if (w->w_next == fwind) { /* last window; check against mesgline */ register char mcolor = mesg_color; if (mcolor == 0) mcolor = DefColor; if (BG_COLOR(mcolor) == FG_COLOR(des_p->s_color)) { if (BG_COLOR(color) != BG_COLOR(des_p->s_color)) des_p->s_color ^= MK_COLOR(WHITE, WHITE); else des_p->s_color = MK_COLOR(BLUE, WHITE); } } if (start == 0) /* first window */ return; des_p = &DesiredScreen[start - 1]; if (BG_COLOR(color) == FG_COLOR(des_p->s_color)) { color = des_p[-1].s_color; if (color == 0) color = DefColor; if (BG_COLOR(color) != BG_COLOR(des_p->s_color)) des_p->s_color ^= MK_COLOR(WHITE, WHITE); else des_p->s_color = MK_COLOR(BLUE, WHITE); } #endif } } /* Write whatever is in mesgbuf (maybe we are Asking, or just printed * a message). Turns off the UpdMesg line flag. */ void DrawMesg(abortable) { if (abortable && charp()) return; i_set(ILI, 0); req_color(mesg_color); if (swrite(mesgbuf, abortable)) { cl_eol(); #ifdef COLOR PhysScreen[ILI].s_color = mesg_color; #endif UpdMesg = 0; } flusho(); } /* Reselect a new horizontal window */ int HorWindow(goal, offset, adjust) register int goal; register int offset; int adjust; { register int length = CO - adjust; if (goal <= offset) offset = 0; if (goal >= offset + length - 1) offset = goal - (length >> 1); return offset; } /* Update line linenum in window w. Only set PhysScreen to DesiredScreen if the swrite or cl_eol works, that is nothing is interupted by characters typed. */ private void UpdLine(linenum) int linenum; { register int vis_attrib = linenum; # define linenum vis_attrib /* alias! */ register struct scrimage *phys_p = &PhysScreen[linenum]; register struct scrimage *des_p = &DesiredScreen[linenum]; i_set(linenum, 0); # undef linenum des_p->s_flags &= ~DIRTY; req_color(des_p->s_color); if (phys_p->s_flags & ~des_p->s_flags & VIS_ATTRIB) cl_standout(); if (vis_attrib = des_p->s_flags & VIS_ATTRIB) standout(vis_attrib); if (des_p->s_flags & MODELINE) { if (!ModeLine(des_p->s_window)) goto ret; } else if (des_p->s_id == 0) { if (phys_p->s_id == 0) /* Not the same ... make sure */ goto ret; } else { des_p->s_lp->l_dline &= ~DIRTY; #ifdef ID_CHAR if (True(UseIC)) { char outbuf[MAXCOLS+1]; int fromcol = 0; if (des_p->s_vln) { fromcol = sprintf(outbuf, "%6d ", des_p->s_vln); } DeTab(des_p->s_offset, lcontents(des_p->s_lp), (outbuf + fromcol), (CO - fromcol), (des_p->s_window->w_flags & W_VISSPACE)); if (IDchar(outbuf, linenum, 0)) { *phys_p = *des_p; goto ret; } i_set(linenum, 0); if (!swrite(outbuf, YES)) { phys_p->s_id = -1; goto ret; } } else /* the following `if' */ #endif /* ID_CHAR */ if ((des_p->s_vln && !swrite(sprint("%6d ", des_p->s_vln), YES)) || !BufSwrite(des_p)) { phys_p->s_id = -1; goto ret; } } *phys_p = *des_p; cl_eol(); ret: if (vis_attrib) standout(0); } /* Print the mode line. */ private char *mend_p; private char *mode_app __(( char *_(mp), const char *_(str) )); private char * mode_app(mp, str) register char *mp; register const char *str; { while (mp <= mend_p) if (!(*mp++ = *str++)) { --mp; /* back over the null */ break; } return mp; } DEF_STR( "mode-line", ModeFmt, 120, V_STRING|V_MODELINE ) _IF(def PRIVATE) = #ifndef TINY "%3c %w %[%sJOVE (%M) Buffer: %b \"%f\" %P %]%s%m*- %p%s%((%t)%s%)%e"; #else "%3c %w %[%sJOVE (%M) Buffer: %b \"%f\" %]%s%m*- %e"; #endif private int ModeLine(w) Window *w; { extern int i_line; char line[MAXCOLS+2], fillc = True(BriteMode) ? ' ' : '-'; const char *app_p; register char *mode_p = line; register char *fmt = ModeFmt; register int n, ign_some = NO, glue = 0; register Buffer *thisbuf = w->w_bufp; mend_p = &mode_p[CO - SG - SG]; /* one too far so too long mode lines will be `!'ed */ while ((*mode_p = *fmt++) && mode_p <= mend_p) { if (*mode_p != '%') { #if NO if (*mode_p == '\\') if ((*mode_p = *fmt++) == '\0') { --fmt; break; } #endif if (!ign_some) mode_p++; continue; } n = 0; while (isdigit(*fmt)) n = n * 10 + *fmt++ - '0'; if (*fmt == '\0') /* char after the '%' */ break; if (ign_some) { /* %( %) may be nested. */ if (*fmt == '(') ign_some++; if (*fmt++ == ')') ign_some--; continue; } switch (*fmt++) { case '%': mode_p++; continue; case '(': /* conditionally ignore */ if (n == 0) { if (w->w_next == fwind) /* bottom window. */ continue; #ifndef TINY } else if (n < 20) { /* special cases: */ if (n >= 10) { /* negate condition */ n -= 10; ign_some++; } switch (n) { case 7: /* "~F" filename is undefined. */ if (thisbuf->b_fname) continue; break; case 8: /* "B=F" bufname equals filename. */ if (thisbuf->b_fname == NULL || strcmp(basename(thisbuf->b_fname), thisbuf->b_name) != 0) continue; break; default: /* matches buffer type. */ if (thisbuf->b_type == n) continue; break; } #endif } else { if (CO >= n) /* screen wide enough. */ continue; } #ifdef TINY ign_some++; #else ign_some ^= 1; #endif continue; case '[': /* edit-recursion depth */ case ']': for (n = RecDepth; --n >= 0 && mode_p < mend_p; ) *mode_p++ = fmt[-1]; continue; case 'b': /* buffer name */ app_p = thisbuf->b_name; break; case 'C': #ifdef MAIL if (chkmail(NO)) { # if !vms app_p = "[New mail]"; # else app_p = "[Message]"; # endif break; } #else # if !unix /* (ab)use it as CapsLock indicator */ { extern int CapsLock; if (CapsLock) { app_p = "[Caps]"; break; } } # endif #endif continue; case 'c': /* fill character(s) */ do { *mode_p++ = fillc; } while (mode_p < mend_p && --n > 0); continue; #ifdef CHDIR case 'd': /* print working directory */ app_p = pr_name(pwd()); break; #endif case 'e': /* stretchable glue */ do { glue++; *mode_p++ = '\0'; /* glue marker */ } while (mode_p < mend_p && --n > 0); continue; case 'F': /* short file name */ if (thisbuf->b_fname) { app_p = basename(thisbuf->b_fname); break; } /* else fall into... */ case 'f': /* full file name */ app_p = filename(thisbuf); break; #ifdef LOAD_AV case 'l': /* load-average */ { int theavg = get_la(); app_p = sprint("%d.%02d", theavg / 100, theavg % 100); } break; #endif case 'M': /* Major + Minor modes */ { extern const char * const MajorName[], * const MinorName[]; register const char * const *minor_p = MinorName; mode_p = mode_app(mode_p, MajorName[thisbuf->b_major]); n = thisbuf->b_minor; do { if (n & 1) mode_p = mode_app(mode_p, *minor_p); *minor_p++; } while (n >>= 1); if (Defining) mode_p = mode_app(mode_p, "Def "); mode_p--; /* Back over the extra space. */ continue; } case 'm': /* buffer modified flag */ *mode_p++ = (IsModified(thisbuf)) ? *fmt++ : *++fmt; fmt++; /* skip the other character */ continue; case 'n': /* buffer number */ app_p = itos(bufno(thisbuf)); break; #ifdef IPROCS case 'p': if (thisbuf->b_type != B_IPROCESS) continue; app_p = sprint("(%s)", pstate(thisbuf->b_process)); break; #endif /* IPROCS */ #if (W_TOPNUM) case 'P': /* estimated position in buffer */ { register Line *lp; /* Get the last line in the window. This assumes that `i_line' is set up to the on_screen line number of this mode line. */ if ((lp = DesiredScreen[i_line - 1].s_lp) == NULL || lastp(thisbuf, lp)) { app_p = (firstp(thisbuf, w->w_top)) ? "All" : "End"; break; } if (firstp(thisbuf, w->w_top)) { app_p = "Top"; break; } /* fall through */ } case 'L': /* Line number */ /* make sure topnum is accurate */ if (!(w->w_flags & (W_TOPNUM|W_NUMLINES))) w->w_topnum = lineno(w->w_top); # define W_NEEDTOP 0x8000 /* temp. flag to indicate that %P/%L was seen; it will be turned off and #undef'ed later in this routine. */ w->w_flags |= W_TOPNUM | W_NEEDTOP; /* calculate line number of current line from what we already know: (topnum + (dotline - FLine(w)) */ n = w->w_topnum + w->w_dotline + SIZE(w) - i_line; if (fmt[-1] == 'L') app_p = itos(n); else app_p = sprint("%2ld%%", (long) n * 100 / lineno(thisbuf->b_last)); break; #endif /* W_TOPNUM */ case 's': /* conditonal fill character(s) */ if (mode_p[-1] != '\0' && mode_p[-1] != ' ') do { *mode_p++ = ' '; } while (mode_p < mend_p && --n > 0); continue; case 't': /* time HH:MM */ { extern const char *hh_mm __(( void )); app_p = hh_mm(); break; } case 'V': app_p = version; break; case 'w': if (w->w_offset > 0) *mode_p++ = '>'; continue; default: /* just ignore unknown formats */ continue; } /* append only if we get here */ mode_p = mode_app(mode_p, app_p); } #if (W_TOPNUM) /* some administration: we don't need to calculate topnum if %P or %L are not present in the mode line, so turn off the request flag; otherwise just turn off the `%P or %L seen' flag. */ w->w_flags &= (w->w_flags & W_NEEDTOP) ? ~W_NEEDTOP : ~W_TOPNUM; # undef W_NEEDTOP #endif *mode_p = '\0'; /* Glue (Knuth's term) is a field that expands to fill any leftover space. Multiple glue fields compete on an equal basis. This is a generalization of a mechanism to allow centring and right-justification. The original meaning of %e (fill the rest of the line) has also been generalized. %e can now meaningfully be used 0 or more times. [TRH] And it obsoletes my %< and %>. */ if (glue) { # define d fmt /* alias! */ # define s mode_p d = mend_p; *d = '\0'; /* if mode line is too long, we still have to scan to replace glue markers with something visible. */ if (s > d) s = d; do { while (*--d = *--s) ; /* shift tail upto marker */ n = (d - s) / glue; ++d; /* 1 extra to replace marker */ do { *--d = fillc; } while (--n >= 0); } while (--glue); mode_p = mend_p; # undef s # undef d } return swrite(line, YES); } DEF_CMD( "clear-and-redraw", ClAndRedraw, NO ) { cl_scr(YES); } void ClrWindow(w) register Window *w; { register int line = FLine(w), i = w->w_height; set_color(w->w_bufp->b_color); do { i_set(line++, 0); v_inval(); } while (--i > 0); /* including modeline! */ } DEF_CMD( "redraw-display", RedrawDisplay, NO ) { register Window *w = curwind; register int n; register Line *newtop; if (exp_p == NO) n = HALF(w); /* default: center */ else if ((n = exp) < 0) /* >= 0: from top of window */ n += SIZE(w); /* < 0: from bottom of window */ newtop = prev_line((w->w_line = w->w_bufp->b_dot), n); if (newtop == w->w_top) ClrWindow(w); else SetTop(w, newtop); #ifdef AUTOSCROLL w->w_flags |= W_NOAUTOSCROLL; #endif } /* [TRH] a little bit of reorganisation here... * in my opinion, leaving out the Asking check has no ill effects * while it allows to scroll completion windows and the like. * [May 89] Add programmable scroll step rate. */ private int PageStep; DEF_CMD( "previous-page", NextPage, NEGATE ); DEF_CMD( "next-page", NextPage, NO ) { DefExp(&PageStep); DoScroll(exp, (exp_p - YES)); /* exp_p != YES */ } DEF_CMD( "scroll-down", UpScroll, NEGATE ); DEF_CMD( "scroll-up", UpScroll, NO ) { DoScroll(exp, NO); } DEF_INT( "page-overlap", PageOverlap, V_BASE10 ) = 2; _IF(def PRIVATE) void DoScroll(numlines, page) register int numlines; int page; { register Window *w = curwind; if (page) { register int pagestep; /* [TRH Jul-90] refuse to page down if the end of the buffer is already visible in the window. */ if (numlines > 0 && in_window(w, w->w_bufp->b_last) >= 0) return; if ((pagestep = SIZE(w) - PageOverlap) > 0) numlines *= pagestep; } { register Line *newtop; /* next_line handles negative line count itself */ newtop = next_line(w->w_top, numlines); SetTop(w, newtop); if (page || in_window(w, w->w_bufp->b_dot) < 0) { w->w_line = newtop; if (w->w_bufp == curbuf) SetLine(newtop); } } } /* Message prints the null terminated string onto the bottom line of the terminal. */ void message(str) const char *str; { if (InJoverc) return; updmesg(); errormsg = 0; if (str != mesgbuf) null_ncpy(mesgbuf, str, (sizeof mesgbuf) - 1); } /* move dot to Beginning (or end, if EXP < 0) of Window */ DEF_CMD( "end-of-window", Bow, NEGATE ); DEF_CMD( "beginning-of-window", Bow, NO ) { register Window *w = curwind; register int num, wheight = w->w_height; if (Asking) return; if ((num = exp) < 0) num += wheight; /* Eow() */ if (--num < 0) num = 0; else if (num > (wheight -= 2)) num = wheight; SetLine(next_line(w->w_top, num)); if (exp < 0 && exp_p == NO) Eol(); #ifdef AUTOSCROLL w->w_flags |= W_NOAUTOSCROLL; #endif } private int LineNo, last_col, DoAutoNL; private Window *old_wind; /* save the window we were in BEFORE before we were called, if UseBuffers is False */ DEF_INT( "send-typeout-to-buffer", UseBuffers, V_BOOL ) ZERO; int TOabort ZERO; /* This initializes the typeout. If send-typeout-to-buffers is set the buffer NAME is created (emptied if it already exists) and output goes to the buffer. Otherwise output is drawn on the screen and erased by TOstop() */ void TOstart(name, auto_newline) const char *name; { if (True(UseBuffers)) { old_wind = curwind; pop_wind(name, YES, B_SCRATCH); } TOabort = LineNo = last_col = 0; DoAutoNL = auto_newline; } /* VARARGS1 */ void DEFVARG(Typeout, (const char *fmt, ...), (fmt, va_alist) const char *fmt;) { register const char *f; if (False(UseBuffers)) { if (TOabort) return; if (LineNo == ILI - 1) { register int c; f_mess("--more--"); c = getchar(); f_mess(NullStr); if (c == ' ') { LineNo = 0; } else if (c == CR) { /* really like "more(1)" */ LineNo--; set_color(Gcolor[B_SCRATCH]); v_del_line(1, 0, LineNo); if (!CanScroll) { /* the brute way */ i_set(ILI - 1, 0); Overtype(NullStr); /* invalidate mode line */ cl_eol(); curstoLL(); putch('\n'); } } else { TOabort++; if (c != AbortChar && c != RUBOUT) add_stroke(c), Ungetc(c); return; } last_col = 0; } i_set(LineNo, last_col); cl_standout(); req_color(Gcolor[B_SCRATCH]); } if (f = fmt) { char string[LBSIZE]; va_register va_list ap; va_begin(ap, fmt); format(string, sizeof string, f, ap); va_end(ap); if (True(UseBuffers)) ins_str(string, NO); else last_col = Overtype(string); } if (!f || DoAutoNL) { if (True(UseBuffers)) ins_str("\n", NO); else { Overtype(NullStr); cl_eol(); flusho(); LineNo++; last_col = 0; } } } void TOstop() { if (True(UseBuffers)) { ToFirst(); /* do this by hand since SetWind won't if Asking */ tiewind(curwind, curbuf); SetWind(old_wind); } else if (!TOabort) { static char Dash[] = "----------"; register int c; if (last_col) Typeout(NULL); if (LineNo == ILI - 1) { f_mess(Dash); } else { #ifdef COLOR /* so the rest of the line will keep its original color, which looks nicer. */ c = PhysScreen[LineNo].s_color; DoAutoNL = NO; #endif Typeout(Dash); req_color(c); cl_eol(); Placur(LineNo - DoAutoNL, sizeof Dash - 1); curson(); } c = getchar(); s_mess(NullStr); if (c != ' ' && c != CR) add_stroke(c), Ungetc(c); } } /*====================================================================== * $Log: disp.c,v $ * Revision 14.32.0.10 1994/04/29 11:59:22 tom * (redisplay): transpose cursor placement and set_color; * (UpdLine): transpose *phys_p assignment and cl_eol(); * (Typeout): use `va_register va_list'. * * Revision 14.32.0.2 1993/07/14 13:47:20 tom * (TOstop): fix COLOR bug that surfaced due to changes in req_color in 14.32. * * Revision 14.32 1993/04/09 00:46:25 tom * (ModeLine): make %P display "All" if complete buffer is visible. * * Revision 14.31 1993/02/15 02:27:35 tom * ModeLine: enable %t option for TINY joves. * * Revision 14.30 1993/01/27 01:33:20 tom * cleanup whitespace; parenthize && || expr to avoid compiler warning. * * Revision 14.28 1992/10/02 15:38:58 tom * support user-variable "default-color". * * Revision 14.26 1992/08/26 23:56:51 tom * PRIVATE-ized some Variable defs; add RCS directives. * */