📄 redraw.c
字号:
/* redraw.c *//* Author: * Steve Kirkendall * 14407 SW Teal Blvd. #C * Beaverton, OR 97005 * kirkenda@cs.pdx.edu *//* This file contains functions that draw text on the screen. The major entry * points are: * redrawrange() - called from modify.c to give hints about what parts * of the screen need to be redrawn. * redraw() - redraws the screen (or part of it) and positions * the cursor where it belongs. * idx2col() - converts a markidx() value to a logical column number. */#include "config.h"#include "vi.h"/* This variable contains the line number that smartdrawtext() knows best */static long smartlno;/* This function remembers where changes were made, so that the screen can be * redraw in a more efficient manner. */static long redrawafter; /* line# of first line that must be redrawn */static long preredraw; /* line# of last line changed, before change */static long postredraw; /* line# of last line changed, after change */static int mustredraw; /* boolean: anything forcing a screen update? */void redrawrange(after, pre, post) long after; /* lower bound of redrawafter */ long pre; /* upper bound of preredraw */ long post; /* upper bound of postredraw */{ if (after == redrawafter) { /* multiple insertions/deletions at the same place -- combine * them */ preredraw -= (post - pre); if (postredraw < post) { preredraw += (post - postredraw); postredraw = post; } if (redrawafter > preredraw) { redrawafter = preredraw; } if (redrawafter < 1L) { redrawafter = 0L; preredraw = postredraw = INFINITY; } } else if (postredraw > 0L) { /* multiple changes in different places -- redraw everything * after "after". */ postredraw = preredraw = INFINITY; if (after < redrawafter) redrawafter = after; } else { /* first change */ redrawafter = after; preredraw = pre; postredraw = post; } mustredraw = TRUE;}#ifndef NO_CHARATTR/* see if a given line uses character attribute strings */static int hasattr(lno, text) long lno; /* the line# of the cursor */ REG char *text; /* the text of the line, from fetchline */{ static long plno; /* previous line number */ static long chgs; /* previous value of changes counter */ static int panswer;/* previous answer */ char *scan; /* if charattr is off, then the answer is "no, it doesn't" */ if (!*o_charattr) { chgs = 0; /* <- forces us to check if charattr is later set */ return FALSE; } /* if we already know the answer, return it... */ if (lno == plno && chgs == changes) { return panswer; } /* get the line & look for "\fX" */ if (!text[0] || !text[1] || !text[2]) { panswer = FALSE; } else { for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++) { } panswer = (scan[2] != '\0'); } /* save the results */ plno = lno; chgs = changes; /* return the results */ return panswer;}#endif#ifndef NO_VISIBLE/* This function checks to make sure that the correct lines are shown in * reverse-video. This is used to handle the "v" and "V" commands. */static long vizlow, vizhigh; /* the starting and ending lines */static int vizleft, vizright; /* starting & ending indicies */static int vizchange; /* boolean: must use stupid drawtext? */static void setviz(curs) MARK curs;{ long newlow, newhigh; long extra = 0L; /* for now, assume the worst... */ vizchange = TRUE; /* set newlow & newhigh according to V_from and cursor */ if (!V_from) { /* no lines should have reverse-video */ if (vizlow) { redrawrange(vizlow, vizhigh + 1L, vizhigh + 1L); vizlow = vizhigh = 0L; } else { vizchange = FALSE; } return; } /* figure out which lines *SHOULD* have hilites */ if (V_from < curs) { newlow = markline(V_from); newhigh = markline(curs); vizleft = markidx(V_from); vizright = markidx(curs) + 1; } else { newlow = markline(curs); newhigh = markline(V_from); vizleft = markidx(curs); vizright = markidx(V_from) + 1; } /* adjust for line-mode hiliting */ if (V_linemd) { vizleft = 0; vizright = BLKSIZE - 1; } else { extra = 1L; } /* arrange for the necessary lines to be redrawn */ if (vizlow == 0L) { /* just starting to redraw */ redrawrange(newlow, newhigh, newhigh); } else { /* Were new lines added/removed at the front? */ if (newlow != vizlow) { if (newlow < vizlow) redrawrange(newlow, vizlow + extra, vizlow + extra); else redrawrange(vizlow, newlow + extra, newlow + extra); } /* Were new lines added/removed at the back? */ if (newhigh != vizhigh) { if (newhigh < vizhigh) redrawrange(newhigh + 1L - extra, vizhigh + 1L, vizhigh + 1L); else redrawrange(vizhigh + 1L - extra, newhigh, newhigh); } } /* remember which lines will contain hilighted text now */ vizlow = newlow; vizhigh = newhigh;}#endif /* !NO_VISIBLE *//* This function converts a MARK to a column number. It doesn't automatically * adjust for leftcol; that must be done by the calling function */int idx2col(curs, text, inputting) MARK curs; /* the line# & index# of the cursor */ REG char *text; /* the text of the line, from fetchline */ int inputting; /* boolean: called from input() ? */{ static MARK pcursor;/* previous cursor, for possible shortcut */ static MARK pcol; /* column number for pcol */ static long chgs; /* previous value of changes counter */ REG int col; /* used to count column numbers */ REG int idx; /* used to count down the index */ REG int i; /* for now, assume we have to start counting at the left edge */ col = 0; idx = markidx(curs); /* if the file hasn't changed & line number is the same & it has no * embedded character attribute strings, can we do shortcuts? */ if (chgs == changes && !((curs ^ pcursor) & ~(BLKSIZE - 1))#ifndef NO_CHARATTR && !hasattr(markline(curs), text)#endif ) { /* no movement? */ if (curs == pcursor) { /* return the column of the char; for tabs, return its last column */ if (text[idx] == '\t' && !inputting && !*o_list) { return pcol + *o_tabstop - (pcol % *o_tabstop) - 1; } else { return pcol; } } /* movement to right? */ if (curs > pcursor) { /* start counting from previous place */ col = pcol; idx = markidx(curs) - markidx(pcursor); text += markidx(pcursor); } } /* count over to the char after the idx position */ while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */ { if (i == '\t' && !*o_list) { col += *o_tabstop; col -= col % *o_tabstop; } else if (i >= '\0' && i < ' ' || i == '\177') { col += 2; }#ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more at bottom of loop */ idx -= 2; } #endif else { col++; } text++; idx--; } /* save stuff to speed next call */ pcursor = curs; pcol = col; chgs = changes; /* return the column of the char; for tabs, return its last column */ if (*text == '\t' && !inputting && !*o_list) { return col + *o_tabstop - (col % *o_tabstop) - 1; } else { return col; }}/* This function is similar to idx2col except that it takes care of sideways * scrolling - for the given line, at least. */int mark2phys(m, text, inputting) MARK m; /* a mark to convert */ char *text; /* the line that m refers to */ int inputting; /* boolean: caled from input() ? */{ int i; i = idx2col(m, text, inputting); while (i < leftcol) { leftcol -= *o_sidescroll; mustredraw = TRUE; redrawrange(1L, INFINITY, INFINITY); } while (i > rightcol) { leftcol += *o_sidescroll; mustredraw = TRUE; redrawrange(1L, INFINITY, INFINITY); } physrow = markline(m) - topline; physcol = i - leftcol; if (*o_number) physcol += 8; return physcol;}/* This function draws a single line of text on the screen. The screen's * cursor is assumed to be located at the leftmost column of the appropriate * row. */static void drawtext(text, lno, clr) REG char *text; /* the text to draw */ long lno; /* the number of the line to draw */ int clr; /* boolean: do a clrtoeol? */{ REG int col; /* column number */ REG int i; REG int tabstop; /* *o_tabstop */ REG int limitcol; /* leftcol or leftcol + COLS */ int abnormal; /* boolean: charattr != A_NORMAL? */#ifndef NO_VISIBLE int rev; /* boolean: standout mode, too? */ int idx = 0;#endif char numstr[9]; /* show the line number, if necessary */ if (*o_number) { sprintf(numstr, "%6ld |", lno); qaddstr(numstr); }#ifndef NO_SENTENCE /* if we're hiding format lines, and this is one of them, then hide it */ if (*o_hideformat && *text == '.') { clrtoeol();#if OSK qaddch('\l');#else qaddch('\n');#endif return; }#endif /* move some things into registers... */ limitcol = leftcol; tabstop = *o_tabstop; abnormal = FALSE;#ifndef CRUNCH if (clr) clrtoeol();#endif /* skip stuff that was scrolled off left edge */ for (col = 0; (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */ text++) {#ifndef NO_VISIBLE idx++;#endif if (i == '\t' && !*o_list) { col = col + tabstop - (col % tabstop); } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; }#ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of "for" loop */ /* since this attribute might carry over, we need it */ switch (*text) { case 'R': case 'P': attrset(A_NORMAL); abnormal = FALSE; break; case 'B': attrset(A_BOLD); abnormal = TRUE; break; case 'U': attrset(A_UNDERLINE); abnormal = TRUE; break; case 'I': attrset(A_ALTCHARSET); abnormal = TRUE; break; } }#endif else { col++; } }#ifndef NO_VISIBLE /* Should we start hiliting at the first char of this line? */ if ((lno > vizlow && lno <= vizhigh || lno == vizlow && vizleft < idx) && !(lno == vizhigh && vizright < idx)) { do_VISIBLE(); rev = TRUE; }#endif /* adjust for control char that was partially visible */ while (col > limitcol) { qaddch(' '); limitcol++; } /* now for the visible characters */ limitcol = leftcol + COLS; if (*o_number) limitcol -= 8; for (; (i = *text) && col < limitcol; text++) {#ifndef NO_VISIBLE /* maybe turn hilite on/off in the middle of the line */ if (lno == vizlow && vizleft == idx) { do_VISIBLE(); rev = TRUE; } if (lno == vizhigh && vizright == idx) { do_SE(); rev = FALSE; } idx++; /* if hiliting, never emit physical tabs */ if (rev && i == '\t' && !*o_list) { i = col + tabstop - (col % tabstop); do { qaddch(' '); col++; } while (col < i); } else#endif /* !NO_VISIBLE */ if (i == '\t' && !*o_list) { i = col + tabstop - (col % tabstop); if (i < limitcol) {#ifdef CRUNCH if (!clr && has_PT && !((i - leftcol) & 7))#else if (has_PT && !((i - leftcol) & 7))#endif { do { qaddch('\t'); col += 8; /* not exact! */ } while (col < i); col = i; /* NOW it is exact */ } else { do { qaddch(' '); col++; } while (col < i); } } else /* tab ending after screen? next line! */ { col = limitcol; if (has_AM) { addch('\n'); /* GB */ } } } else if (i >= 0 && i < ' ' || i == '\177') { col += 2; qaddch('^'); if (col <= limitcol) { qaddch(i ^ '@'); } }#ifndef NO_CHARATTR else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) { text += 2; /* plus one more as part of "for" loop */ switch (*text) { case 'R': case 'P': attrset(A_NORMAL); abnormal = FALSE; break; case 'B': attrset(A_BOLD); abnormal = TRUE; break; case 'U': attrset(A_UNDERLINE); abnormal = TRUE; break; case 'I': attrset(A_ALTCHARSET); abnormal = TRUE; break; } }#endif else { col++; qaddch(i); } } /* get ready for the next line */#ifndef NO_CHARATTR if (abnormal) { attrset(A_NORMAL); }#endif if (*o_list && col < limitcol) { qaddch('$'); col++; }#ifndef NO_VISIBLE /* did we hilite this whole line? If so, STOP! */ if (rev) { do_SE(); }#endif#ifdef CRUNCH if (clr && col < limitcol) { clrtoeol(); }#endif if (!has_AM || col < limitcol) { addch('\n'); } wqrefresh();}#ifndef CRUNCHstatic void nudgecursor(same, scan, new, lno) int same; /* number of chars to be skipped over */ char *scan; /* where the same chars end */ char *new; /* where the visible part of the line starts */ long lno; /* line number of this line */{ int col; if (same > 0) { if (same < 5) { /* move the cursor by overwriting */ while (same > 0) { qaddch(scan[-same]); same--; } } else { /* move the cursor by calling move() */ col = (int)(scan - new); if (*o_number) col += 8; move((int)(lno - topline), col); } }}#endif /* not CRUNCH */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -