|
|
1.1 ! root 1: /* redraw.c */ ! 2: ! 3: /* Author: ! 4: * Steve Kirkendall ! 5: * 14407 SW Teal Blvd. #C ! 6: * Beaverton, OR 97005 ! 7: * [email protected] ! 8: */ ! 9: ! 10: ! 11: /* This file contains functions that draw text on the screen. The major entry ! 12: * points are: ! 13: * redrawrange() - called from modify.c to give hints about what parts ! 14: * of the screen need to be redrawn. ! 15: * redraw() - redraws the screen (or part of it) and positions ! 16: * the cursor where it belongs. ! 17: * idx2col() - converts a markidx() value to a logical column number. ! 18: */ ! 19: ! 20: #include "config.h" ! 21: #include "vi.h" ! 22: #ifdef CRUNCH ! 23: # define NEAR LINES ! 24: #else ! 25: # define NEAR (*o_nearscroll&0xff) ! 26: #endif ! 27: ! 28: /* This variable contains the line number that smartdrawtext() knows best */ ! 29: static long smartlno; ! 30: ! 31: /* This function remembers where changes were made, so that the screen can be ! 32: * redraw in a more efficient manner. ! 33: */ ! 34: static long redrawafter; /* line# of first line that must be redrawn */ ! 35: static long preredraw; /* line# of last line changed, before change */ ! 36: static long postredraw; /* line# of last line changed, after change */ ! 37: static int mustredraw; /* boolean: anything forcing a screen update? */ ! 38: void redrawrange(after, pre, post) ! 39: long after; /* lower bound of redrawafter */ ! 40: long pre; /* upper bound of preredraw */ ! 41: long post; /* upper bound of postredraw */ ! 42: { ! 43: if (after == redrawafter) ! 44: { ! 45: /* multiple insertions/deletions at the same place -- combine ! 46: * them ! 47: */ ! 48: preredraw -= (post - pre); ! 49: if (postredraw < post) ! 50: { ! 51: preredraw += (post - postredraw); ! 52: postredraw = post; ! 53: } ! 54: if (redrawafter > preredraw) ! 55: { ! 56: redrawafter = preredraw; ! 57: } ! 58: if (redrawafter < 1L) ! 59: { ! 60: redrawafter = 0L; ! 61: preredraw = postredraw = INFINITY; ! 62: } ! 63: } ! 64: else if (postredraw > 0L) ! 65: { ! 66: /* multiple changes in different places -- redraw everything ! 67: * after "after". ! 68: */ ! 69: postredraw = preredraw = INFINITY; ! 70: if (after < redrawafter) ! 71: redrawafter = after; ! 72: } ! 73: else ! 74: { ! 75: /* first change */ ! 76: redrawafter = after; ! 77: preredraw = pre; ! 78: postredraw = post; ! 79: } ! 80: mustredraw = TRUE; ! 81: } ! 82: ! 83: ! 84: #ifndef NO_CHARATTR ! 85: /* see if a given line uses character attribute strings */ ! 86: static int hasattr(lno, text) ! 87: long lno; /* the line# of the cursor */ ! 88: REG char *text; /* the text of the line, from fetchline */ ! 89: { ! 90: static long plno; /* previous line number */ ! 91: static long chgs; /* previous value of changes counter */ ! 92: static int panswer;/* previous answer */ ! 93: char *scan; ! 94: ! 95: /* if charattr is off, then the answer is "no, it doesn't" */ ! 96: if (!*o_charattr) ! 97: { ! 98: chgs = 0; /* <- forces us to check if charattr is later set */ ! 99: return FALSE; ! 100: } ! 101: ! 102: /* if we already know the answer, return it... */ ! 103: if (lno == plno && chgs == changes) ! 104: { ! 105: return panswer; ! 106: } ! 107: ! 108: /* get the line & look for "\fX" */ ! 109: if (!text[0] || !text[1] || !text[2]) ! 110: { ! 111: panswer = FALSE; ! 112: } ! 113: else ! 114: { ! 115: for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++) ! 116: { ! 117: } ! 118: panswer = (scan[2] != '\0'); ! 119: } ! 120: ! 121: /* save the results */ ! 122: plno = lno; ! 123: chgs = changes; ! 124: ! 125: /* return the results */ ! 126: return panswer; ! 127: } ! 128: #endif ! 129: ! 130: ! 131: #ifndef NO_VISIBLE ! 132: /* This function checks to make sure that the correct lines are shown in ! 133: * reverse-video. This is used to handle the "v" and "V" commands. ! 134: */ ! 135: static long vizlow, vizhigh; /* the starting and ending lines */ ! 136: static int vizleft, vizright; /* starting & ending indicies */ ! 137: static int vizchange; /* boolean: must use stupid drawtext? */ ! 138: static void setviz(curs) ! 139: MARK curs; ! 140: { ! 141: long newlow, newhigh; ! 142: long extra = 0L; ! 143: ! 144: /* for now, assume the worst... */ ! 145: vizchange = TRUE; ! 146: ! 147: /* set newlow & newhigh according to V_from and cursor */ ! 148: if (!V_from) ! 149: { ! 150: /* no lines should have reverse-video */ ! 151: if (vizlow) ! 152: { ! 153: redrawrange(vizlow, vizhigh + 1L, vizhigh + 1L); ! 154: vizlow = vizhigh = 0L; ! 155: } ! 156: else ! 157: { ! 158: vizchange = FALSE; ! 159: } ! 160: return; ! 161: } ! 162: ! 163: /* figure out which lines *SHOULD* have hilites */ ! 164: if (V_from < curs) ! 165: { ! 166: newlow = markline(V_from); ! 167: newhigh = markline(curs); ! 168: vizleft = markidx(V_from); ! 169: vizright = markidx(curs) + 1; ! 170: } ! 171: else ! 172: { ! 173: newlow = markline(curs); ! 174: newhigh = markline(V_from); ! 175: vizleft = markidx(curs); ! 176: vizright = markidx(V_from) + 1; ! 177: } ! 178: ! 179: /* adjust for line-mode hiliting */ ! 180: if (V_linemd) ! 181: { ! 182: vizleft = 0; ! 183: vizright = BLKSIZE - 1; ! 184: } ! 185: else ! 186: { ! 187: extra = 1L; ! 188: } ! 189: ! 190: /* arrange for the necessary lines to be redrawn */ ! 191: if (vizlow == 0L) ! 192: { ! 193: /* just starting to redraw */ ! 194: redrawrange(newlow, newhigh, newhigh); ! 195: } ! 196: else ! 197: { ! 198: /* Were new lines added/removed at the front? */ ! 199: if (newlow != vizlow) ! 200: { ! 201: if (newlow < vizlow) ! 202: redrawrange(newlow, vizlow + extra, vizlow + extra); ! 203: else ! 204: redrawrange(vizlow, newlow + extra, newlow + extra); ! 205: } ! 206: ! 207: /* Were new lines added/removed at the back? */ ! 208: if (newhigh != vizhigh) ! 209: { ! 210: if (newhigh < vizhigh) ! 211: redrawrange(newhigh + 1L - extra, vizhigh + 1L, vizhigh + 1L); ! 212: else ! 213: redrawrange(vizhigh + 1L - extra, newhigh, newhigh); ! 214: } ! 215: } ! 216: ! 217: /* remember which lines will contain hilighted text now */ ! 218: vizlow = newlow; ! 219: vizhigh = newhigh; ! 220: } ! 221: #endif /* !NO_VISIBLE */ ! 222: ! 223: ! 224: /* This function converts a MARK to a column number. It doesn't automatically ! 225: * adjust for leftcol; that must be done by the calling function ! 226: */ ! 227: int idx2col(curs, text, inputting) ! 228: MARK curs; /* the line# & index# of the cursor */ ! 229: REG char *text; /* the text of the line, from fetchline */ ! 230: int inputting; /* boolean: called from input() ? */ ! 231: { ! 232: static MARK pcursor;/* previous cursor, for possible shortcut */ ! 233: static MARK pcol; /* column number for pcol */ ! 234: static long chgs; /* previous value of changes counter */ ! 235: REG int col; /* used to count column numbers */ ! 236: REG int idx; /* used to count down the index */ ! 237: REG int i; ! 238: ! 239: /* for now, assume we have to start counting at the left edge */ ! 240: col = 0; ! 241: idx = markidx(curs); ! 242: ! 243: /* if the file hasn't changed & line number is the same & it has no ! 244: * embedded character attribute strings, can we do shortcuts? ! 245: */ ! 246: if (chgs == changes ! 247: && !((curs ^ pcursor) & ~(BLKSIZE - 1)) ! 248: #ifndef NO_CHARATTR ! 249: && !hasattr(markline(curs), text) ! 250: #endif ! 251: ) ! 252: { ! 253: /* no movement? */ ! 254: if (curs == pcursor) ! 255: { ! 256: /* return the column of the char; for tabs, return its last column */ ! 257: if (text[idx] == '\t' && !inputting && !*o_list) ! 258: { ! 259: return pcol + *o_tabstop - (pcol % *o_tabstop) - 1; ! 260: } ! 261: else ! 262: { ! 263: return pcol; ! 264: } ! 265: } ! 266: ! 267: /* movement to right? */ ! 268: if (curs > pcursor) ! 269: { ! 270: /* start counting from previous place */ ! 271: col = pcol; ! 272: idx = markidx(curs) - markidx(pcursor); ! 273: text += markidx(pcursor); ! 274: } ! 275: } ! 276: ! 277: /* count over to the char after the idx position */ ! 278: while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */ ! 279: { ! 280: if (i == '\t' && !*o_list) ! 281: { ! 282: col += *o_tabstop; ! 283: col -= col % *o_tabstop; ! 284: } ! 285: else if (i >= '\0' && i < ' ' || i == '\177') ! 286: { ! 287: col += 2; ! 288: } ! 289: #ifndef NO_CHARATTR ! 290: else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) ! 291: { ! 292: text += 2; /* plus one more at bottom of loop */ ! 293: idx -= 2; ! 294: } ! 295: #endif ! 296: else ! 297: { ! 298: col++; ! 299: } ! 300: text++; ! 301: idx--; ! 302: } ! 303: ! 304: /* save stuff to speed next call */ ! 305: pcursor = curs; ! 306: pcol = col; ! 307: chgs = changes; ! 308: ! 309: /* return the column of the char; for tabs, return its last column */ ! 310: if (*text == '\t' && !inputting && !*o_list) ! 311: { ! 312: return col + *o_tabstop - (col % *o_tabstop) - 1; ! 313: } ! 314: else ! 315: { ! 316: return col; ! 317: } ! 318: } ! 319: ! 320: ! 321: /* This function is similar to idx2col except that it takes care of sideways ! 322: * scrolling - for the given line, at least. ! 323: */ ! 324: int mark2phys(m, text, inputting) ! 325: MARK m; /* a mark to convert */ ! 326: char *text; /* the line that m refers to */ ! 327: int inputting; /* boolean: caled from input() ? */ ! 328: { ! 329: int i; ! 330: ! 331: i = idx2col(m, text, inputting); ! 332: while (i < leftcol) ! 333: { ! 334: leftcol -= *o_sidescroll; ! 335: mustredraw = TRUE; ! 336: redrawrange(1L, INFINITY, INFINITY); ! 337: } ! 338: while (i > rightcol) ! 339: { ! 340: leftcol += *o_sidescroll; ! 341: mustredraw = TRUE; ! 342: redrawrange(1L, INFINITY, INFINITY); ! 343: } ! 344: physrow = markline(m) - topline; ! 345: physcol = i - leftcol; ! 346: if (*o_number) ! 347: physcol += 8; ! 348: ! 349: return physcol; ! 350: } ! 351: ! 352: /* This function draws a single line of text on the screen. The screen's ! 353: * cursor is assumed to be located at the leftmost column of the appropriate ! 354: * row. ! 355: */ ! 356: static void drawtext(text, lno, clr) ! 357: REG char *text; /* the text to draw */ ! 358: long lno; /* the number of the line to draw */ ! 359: int clr; /* boolean: do a clrtoeol? */ ! 360: { ! 361: REG int col; /* column number */ ! 362: REG int i; ! 363: REG int tabstop; /* *o_tabstop */ ! 364: REG int limitcol; /* leftcol or leftcol + COLS */ ! 365: int abnormal; /* boolean: charattr != A_NORMAL? */ ! 366: #ifndef NO_VISIBLE ! 367: int rev; /* boolean: standout mode, too? */ ! 368: int idx = 0; ! 369: #endif ! 370: char numstr[9]; ! 371: ! 372: /* show the line number, if necessary */ ! 373: if (*o_number) ! 374: { ! 375: sprintf(numstr, "%6ld ", lno); ! 376: qaddstr(numstr); ! 377: } ! 378: ! 379: #ifndef NO_SENTENCE ! 380: /* if we're hiding format lines, and this is one of them, then hide it */ ! 381: if (*o_hideformat && *text == '.') ! 382: { ! 383: clrtoeol(); ! 384: #if OSK ! 385: qaddch('\l'); ! 386: #else ! 387: qaddch('\n'); ! 388: #endif ! 389: return; ! 390: } ! 391: #endif ! 392: ! 393: /* move some things into registers... */ ! 394: limitcol = leftcol; ! 395: tabstop = *o_tabstop; ! 396: abnormal = FALSE; ! 397: ! 398: #ifndef CRUNCH ! 399: if (clr) ! 400: clrtoeol(); ! 401: #endif ! 402: ! 403: /* skip stuff that was scrolled off left edge */ ! 404: for (col = 0; ! 405: (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */ ! 406: text++) ! 407: { ! 408: #ifndef NO_VISIBLE ! 409: idx++; ! 410: #endif ! 411: if (i == '\t' && !*o_list) ! 412: { ! 413: col = col + tabstop - (col % tabstop); ! 414: } ! 415: else if (i >= 0 && i < ' ' || i == '\177') ! 416: { ! 417: col += 2; ! 418: } ! 419: #ifndef NO_CHARATTR ! 420: else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) ! 421: { ! 422: text += 2; /* plus one more as part of "for" loop */ ! 423: ! 424: /* since this attribute might carry over, we need it */ ! 425: switch (*text) ! 426: { ! 427: case 'R': ! 428: case 'P': ! 429: attrset(A_NORMAL); ! 430: abnormal = FALSE; ! 431: break; ! 432: ! 433: case 'B': ! 434: attrset(A_BOLD); ! 435: abnormal = TRUE; ! 436: break; ! 437: ! 438: case 'U': ! 439: attrset(A_UNDERLINE); ! 440: abnormal = TRUE; ! 441: break; ! 442: ! 443: case 'I': ! 444: attrset(A_ALTCHARSET); ! 445: abnormal = TRUE; ! 446: break; ! 447: } ! 448: } ! 449: #endif ! 450: else ! 451: { ! 452: col++; ! 453: } ! 454: } ! 455: ! 456: #ifndef NO_VISIBLE ! 457: /* Should we start hiliting at the first char of this line? */ ! 458: if ((lno > vizlow && lno <= vizhigh ! 459: || lno == vizlow && vizleft < idx) ! 460: && !(lno == vizhigh && vizright < idx)) ! 461: { ! 462: do_VISIBLE(); ! 463: rev = TRUE; ! 464: } ! 465: #endif ! 466: ! 467: /* adjust for control char that was partially visible */ ! 468: while (col > limitcol) ! 469: { ! 470: qaddch(' '); ! 471: limitcol++; ! 472: } ! 473: ! 474: /* now for the visible characters */ ! 475: limitcol = leftcol + COLS; ! 476: if (*o_number) ! 477: limitcol -= 8; ! 478: for (; (i = *text) && col < limitcol; text++) ! 479: { ! 480: #ifndef NO_VISIBLE ! 481: /* maybe turn hilite on/off in the middle of the line */ ! 482: if (lno == vizlow && vizleft == idx) ! 483: { ! 484: do_VISIBLE(); ! 485: rev = TRUE; ! 486: } ! 487: if (lno == vizhigh && vizright == idx) ! 488: { ! 489: do_SE(); ! 490: rev = FALSE; ! 491: } ! 492: idx++; ! 493: ! 494: /* if hiliting, never emit physical tabs */ ! 495: if (rev && i == '\t' && !*o_list) ! 496: { ! 497: i = col + tabstop - (col % tabstop); ! 498: do ! 499: { ! 500: qaddch(' '); ! 501: col++; ! 502: } while (col < i && col < limitcol); ! 503: } ! 504: else ! 505: #endif /* !NO_VISIBLE */ ! 506: if (i == '\t' && !*o_list) ! 507: { ! 508: i = col + tabstop - (col % tabstop); ! 509: if (i < limitcol) ! 510: { ! 511: #ifdef CRUNCH ! 512: if (!clr && has_PT && !((i - leftcol) & 7)) ! 513: #else ! 514: if (has_PT && !((i - leftcol) & 7)) ! 515: #endif ! 516: { ! 517: do ! 518: { ! 519: qaddch('\t'); ! 520: col += 8; /* not exact! */ ! 521: } while (col < i); ! 522: col = i; /* NOW it is exact */ ! 523: } ! 524: else ! 525: { ! 526: do ! 527: { ! 528: qaddch(' '); ! 529: col++; ! 530: } while (col < i && col < limitcol); ! 531: } ! 532: } ! 533: else /* tab ending after screen? next line! */ ! 534: { ! 535: col = limitcol; ! 536: if (has_AM) ! 537: { ! 538: addch('\n'); /* GB */ ! 539: } ! 540: } ! 541: } ! 542: else if (i >= 0 && i < ' ' || i == '\177') ! 543: { ! 544: col += 2; ! 545: qaddch('^'); ! 546: if (col <= limitcol) ! 547: { ! 548: qaddch(i ^ '@'); ! 549: } ! 550: } ! 551: #ifndef NO_CHARATTR ! 552: else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr) ! 553: { ! 554: text += 2; /* plus one more as part of "for" loop */ ! 555: switch (*text) ! 556: { ! 557: case 'R': ! 558: case 'P': ! 559: attrset(A_NORMAL); ! 560: abnormal = FALSE; ! 561: break; ! 562: ! 563: case 'B': ! 564: attrset(A_BOLD); ! 565: abnormal = TRUE; ! 566: break; ! 567: ! 568: case 'U': ! 569: attrset(A_UNDERLINE); ! 570: abnormal = TRUE; ! 571: break; ! 572: ! 573: case 'I': ! 574: attrset(A_ALTCHARSET); ! 575: abnormal = TRUE; ! 576: break; ! 577: } ! 578: } ! 579: #endif ! 580: else ! 581: { ! 582: col++; ! 583: qaddch(i); ! 584: } ! 585: } ! 586: ! 587: /* get ready for the next line */ ! 588: #ifndef NO_CHARATTR ! 589: if (abnormal) ! 590: { ! 591: attrset(A_NORMAL); ! 592: } ! 593: #endif ! 594: if (*o_list && col < limitcol) ! 595: { ! 596: qaddch('$'); ! 597: col++; ! 598: } ! 599: ! 600: #ifndef NO_VISIBLE ! 601: /* did we hilite this whole line? If so, STOP! */ ! 602: if (rev) ! 603: { ! 604: do_SE(); ! 605: } ! 606: #endif ! 607: ! 608: #ifdef CRUNCH ! 609: if (clr && col < limitcol) ! 610: { ! 611: clrtoeol(); ! 612: } ! 613: #endif ! 614: if (!has_AM || col < limitcol) ! 615: { ! 616: addch('\n'); ! 617: } ! 618: ! 619: wqrefresh(); ! 620: } ! 621: ! 622: ! 623: #ifndef CRUNCH ! 624: static void nudgecursor(same, scan, new, lno) ! 625: int same; /* number of chars to be skipped over */ ! 626: char *scan; /* where the same chars end */ ! 627: char *new; /* where the visible part of the line starts */ ! 628: long lno; /* line number of this line */ ! 629: { ! 630: int col; ! 631: ! 632: if (same > 0) ! 633: { ! 634: if (same < 5) ! 635: { ! 636: /* move the cursor by overwriting */ ! 637: while (same > 0) ! 638: { ! 639: qaddch(scan[-same]); ! 640: same--; ! 641: } ! 642: } ! 643: else ! 644: { ! 645: /* move the cursor by calling move() */ ! 646: col = (int)(scan - new); ! 647: if (*o_number) ! 648: col += 8; ! 649: move((int)(lno - topline), col); ! 650: } ! 651: } ! 652: } ! 653: #endif /* not CRUNCH */ ! 654: ! 655: /* This function draws a single line of text on the screen, possibly with ! 656: * some cursor optimization. The cursor is repositioned before drawing ! 657: * begins, so its position before doesn't really matter. ! 658: */ ! 659: static void smartdrawtext(text, lno, showit) ! 660: REG char *text; /* the text to draw */ ! 661: long lno; /* line number of the text */ ! 662: int showit; /* boolean: output line? (else just remember it) */ ! 663: { ! 664: #ifdef CRUNCH ! 665: move((int)(lno - topline), 0); ! 666: if (showit) ! 667: { ! 668: drawtext(text, lno, TRUE); ! 669: } ! 670: #else /* not CRUNCH */ ! 671: static char old[256]; /* how the line looked last time */ ! 672: char new[256]; /* how it looks now */ ! 673: char *build; /* used to put chars into new[] */ ! 674: char *scan; /* used for moving thru new[] or old[] */ ! 675: char *end; /* last non-blank changed char */ ! 676: char *shift; /* used to insert/delete chars */ ! 677: int same; /* length of a run of unchanged chars */ ! 678: int limitcol; ! 679: int col; ! 680: int i; ! 681: char numstr[9]; ! 682: ! 683: # ifndef NO_CHARATTR ! 684: /* if this line has attributes, do it the dumb way instead */ ! 685: if (hasattr(lno, text)) ! 686: { ! 687: move((int)(lno - topline), 0); ! 688: drawtext(text, lno, TRUE); ! 689: return; ! 690: } ! 691: # endif ! 692: # ifndef NO_SENTENCE ! 693: /* if this line is a format line, & we're hiding format lines, then ! 694: * let the dumb drawtext() function handle it ! 695: */ ! 696: if (*o_hideformat && *text == '.') ! 697: { ! 698: move((int)(lno - topline), 0); ! 699: drawtext(text, lno, TRUE); ! 700: return; ! 701: } ! 702: # endif ! 703: # ifndef NO_VISIBLE ! 704: if (vizchange) ! 705: { ! 706: move((int)(lno - topline), 0); ! 707: drawtext(text, lno, TRUE); ! 708: smartlno = 0L; ! 709: return; ! 710: } ! 711: # endif ! 712: ! 713: /* skip stuff that was scrolled off left edge */ ! 714: limitcol = leftcol; ! 715: for (col = 0; ! 716: (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */ ! 717: text++) ! 718: { ! 719: if (i == '\t' && !*o_list) ! 720: { ! 721: col = col + *o_tabstop - (col % *o_tabstop); ! 722: } ! 723: else if (i >= 0 && i < ' ' || i == '\177') ! 724: { ! 725: col += 2; ! 726: } ! 727: else ! 728: { ! 729: col++; ! 730: } ! 731: } ! 732: ! 733: /* adjust for control char that was partially visible */ ! 734: build = new; ! 735: while (col > limitcol) ! 736: { ! 737: *build++ = ' '; ! 738: limitcol++; ! 739: } ! 740: ! 741: /* now for the visible characters */ ! 742: limitcol = leftcol + COLS; ! 743: if (*o_number) ! 744: limitcol -= 8; ! 745: for (; (i = *text) && col < limitcol; text++) ! 746: { ! 747: if (i == '\t' && !*o_list) ! 748: { ! 749: i = col + *o_tabstop - (col % *o_tabstop); ! 750: while (col < i && col < limitcol) ! 751: { ! 752: *build++ = ' '; ! 753: col++; ! 754: } ! 755: } ! 756: else if (i >= 0 && i < ' ' || i == '\177') ! 757: { ! 758: col += 2; ! 759: *build++ = '^'; ! 760: if (col <= limitcol) ! 761: { ! 762: *build++ = (i ^ '@'); ! 763: } ! 764: } ! 765: else ! 766: { ! 767: col++; ! 768: *build++ = i; ! 769: } ! 770: } ! 771: if (col < limitcol && *o_list) ! 772: { ! 773: *build++ = '$'; ! 774: col++; ! 775: } ! 776: end = build; ! 777: while (col < limitcol) ! 778: { ! 779: *build++ = ' '; ! 780: col++; ! 781: } ! 782: ! 783: /* if we're just supposed to remember this line, then remember it */ ! 784: if (!showit) ! 785: { ! 786: smartlno = lno; ! 787: strncpy(old, new, COLS); ! 788: return; ! 789: } ! 790: ! 791: /* locate the last non-blank character */ ! 792: while (end > new && end[-1] == ' ') ! 793: { ! 794: end--; ! 795: } ! 796: ! 797: /* can we optimize the displaying of this line? */ ! 798: if (lno != smartlno) ! 799: { ! 800: /* nope, can't optimize - different line */ ! 801: move((int)(lno - topline), 0); ! 802: ! 803: /* show the line number, if necessary */ ! 804: if (*o_number) ! 805: { ! 806: sprintf(numstr, "%6ld ", lno); ! 807: qaddstr(numstr); ! 808: } ! 809: ! 810: /* show the new line */ ! 811: for (scan = new, build = old; scan < end; ) ! 812: { ! 813: qaddch(*scan); ! 814: *build++ = *scan++; ! 815: } ! 816: if (end < new + COLS - (*o_number ? 8 : 0)) ! 817: { ! 818: clrtoeol(); ! 819: while (build < old + COLS) ! 820: { ! 821: *build++ = ' '; ! 822: } ! 823: } ! 824: smartlno = lno; ! 825: return; ! 826: } ! 827: ! 828: /* skip any initial unchanged characters */ ! 829: for (scan = new, build = old; scan < end && *scan == *build; scan++, build++) ! 830: { ! 831: } ! 832: i = (scan - new); ! 833: if (*o_number) ! 834: i += 8; ! 835: move((int)(lno - topline), i); ! 836: ! 837: /* The in-between characters must be changed */ ! 838: same = 0; ! 839: while (scan < end) ! 840: { ! 841: /* is this character a match? */ ! 842: if (scan[0] == build[0]) ! 843: { ! 844: same++; ! 845: } ! 846: else /* do we want to insert? */ ! 847: if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM)) ! 848: { ! 849: nudgecursor(same, scan, new, lno); ! 850: same = 0; ! 851: ! 852: insch(*scan); ! 853: for (shift = old + COLS; --shift > build; ) ! 854: { ! 855: shift[0] = shift[-1]; ! 856: } ! 857: *build = *scan; ! 858: } ! 859: else /* do we want to delete? */ ! 860: if (build < old + COLS - 1 && scan[0] == build[1] && has_DC) ! 861: { ! 862: nudgecursor(same, scan, new, lno); ! 863: same = 0; ! 864: ! 865: delch(); ! 866: same++; ! 867: for (shift = build; shift < old + COLS - 1; shift++) ! 868: { ! 869: shift[0] = shift[1]; ! 870: } ! 871: if (*o_number) ! 872: shift -= 8; ! 873: *shift = ' '; ! 874: } ! 875: else /* we must overwrite */ ! 876: { ! 877: nudgecursor(same, scan, new, lno); ! 878: same = 0; ! 879: ! 880: addch(*scan); ! 881: *build = *scan; ! 882: } ! 883: ! 884: build++; ! 885: scan++; ! 886: } ! 887: ! 888: /* maybe clear to EOL */ ! 889: end = old + COLS - (*o_number ? 8 : 0); ! 890: while (build < end && *build == ' ') ! 891: { ! 892: build++; ! 893: } ! 894: if (build < end) ! 895: { ! 896: nudgecursor(same, scan, new, lno); ! 897: same = 0; ! 898: ! 899: clrtoeol(); ! 900: while (build < old + COLS) ! 901: { ! 902: *build++ = ' '; ! 903: } ! 904: } ! 905: #endif /* not CRUNCH */ ! 906: } ! 907: ! 908: ! 909: /* This function is used in visual mode for drawing the screen (or just parts ! 910: * of the screen, if that's all thats needed). It also takes care of ! 911: * scrolling. ! 912: */ ! 913: void redraw(curs, inputting) ! 914: MARK curs; /* where to leave the screen's cursor */ ! 915: int inputting; /* boolean: being called from input() ? */ ! 916: { ! 917: char *text; /* a line of text to display */ ! 918: static long chgs; /* previous changes level */ ! 919: long l; ! 920: int i; ! 921: #ifndef CRUNCH ! 922: static long showtop; /* top line in window */ ! 923: static long showbottom; /* bottom line in window */ ! 924: #endif ! 925: ! 926: /* if curs == MARK_UNSET, then we should reset internal vars */ ! 927: if (curs == MARK_UNSET) ! 928: { ! 929: if (topline < 1 || topline > nlines) ! 930: { ! 931: topline = 1L; ! 932: } ! 933: else ! 934: { ! 935: move(LINES - 1, 0); ! 936: clrtoeol(); ! 937: } ! 938: leftcol = 0; ! 939: mustredraw = TRUE; ! 940: redrawafter = INFINITY; ! 941: preredraw = 0L; ! 942: postredraw = 0L; ! 943: chgs = 0; ! 944: smartlno = 0L; ! 945: #ifndef NO_VISIBLE ! 946: vizlow = vizhigh = 0L; ! 947: vizchange = FALSE; ! 948: #endif ! 949: #ifndef CRUNCH ! 950: showtop = 0; ! 951: showbottom = INFINITY; ! 952: #endif ! 953: return; ! 954: } ! 955: ! 956: #ifndef NO_VISIBLE ! 957: /* adjustments to hilited area may force extra lines to be redrawn. */ ! 958: setviz(curs); ! 959: #endif ! 960: ! 961: /* figure out which column the cursor will be in */ ! 962: l = markline(curs); ! 963: text = fetchline(l); ! 964: mark2phys(curs, text, inputting); ! 965: ! 966: #ifndef NO_COLOR ! 967: fixcolor(); ! 968: #endif ! 969: ! 970: /* adjust topline, if necessary, to get the cursor on the screen */ ! 971: if (l >= topline && l <= botline) ! 972: { ! 973: /* it is on the screen already */ ! 974: ! 975: /* if the file was changed but !mustredraw, then redraw line */ ! 976: if (!mustredraw && (chgs != changes ! 977: #ifndef NO_VISIBLE ! 978: || V_from ! 979: #endif ! 980: #ifndef CRUNCH ! 981: || l < showtop || l > showbottom ! 982: #endif ! 983: )) ! 984: { ! 985: smartdrawtext(text, l, (chgs != changes)); ! 986: } ! 987: } ! 988: else if (l < topline && l >= topline - NEAR && (has_SR || has_AL)) ! 989: { ! 990: /* near top - scroll down */ ! 991: if (!mustredraw) ! 992: { ! 993: move(0,0); ! 994: while (l < topline) ! 995: { ! 996: topline--; ! 997: if (has_SR) ! 998: { ! 999: do_SR(); ! 1000: } ! 1001: else ! 1002: { ! 1003: insertln(); ! 1004: } ! 1005: text = fetchline(topline); ! 1006: drawtext(text, topline, FALSE); ! 1007: do_UP(); ! 1008: } ! 1009: ! 1010: /* blank out the last line */ ! 1011: move(LINES - 1, 0); ! 1012: clrtoeol(); ! 1013: } ! 1014: else ! 1015: { ! 1016: topline = l; ! 1017: redrawrange(0L, INFINITY, INFINITY); ! 1018: } ! 1019: } ! 1020: else if (l > topline && l <= botline + NEAR) ! 1021: { ! 1022: /* near bottom -- scroll up */ ! 1023: if (!mustredraw) ! 1024: { ! 1025: move(LINES - 1,0); ! 1026: clrtoeol(); ! 1027: while (l > botline) ! 1028: { ! 1029: topline++; /* <-- also adjusts botline */ ! 1030: text = fetchline(botline); ! 1031: drawtext(text, botline, FALSE); ! 1032: } ! 1033: #ifndef CRUNCH ! 1034: showbottom = l; ! 1035: #endif ! 1036: } ! 1037: else ! 1038: { ! 1039: topline = l - (LINES - 2); ! 1040: redrawrange(0L, INFINITY, INFINITY); ! 1041: } ! 1042: } ! 1043: else ! 1044: { ! 1045: /* distant line - center it & force a redraw */ ! 1046: topline = l - (LINES / 2) - 1; ! 1047: if (topline < 1) ! 1048: { ! 1049: topline = 1; ! 1050: } ! 1051: redrawrange(0L, INFINITY, INFINITY); ! 1052: smartlno = 0L; ! 1053: changes++; ! 1054: } ! 1055: ! 1056: #ifndef CRUNCH ! 1057: /* make sure the current line is included in the "window" */ ! 1058: if (l < showtop) ! 1059: { ! 1060: redrawrange(l, showtop, showtop); ! 1061: showtop = l; ! 1062: } ! 1063: if (l > showbottom) ! 1064: { ! 1065: redrawrange(showbottom, l, l); ! 1066: showbottom = l; ! 1067: } ! 1068: #endif ! 1069: ! 1070: ! 1071: /* Now... do we really have to redraw? */ ! 1072: if (mustredraw) ! 1073: { ! 1074: /* If redrawfter (and friends) aren't set, assume we should ! 1075: * redraw everything. ! 1076: */ ! 1077: if (redrawafter == INFINITY) ! 1078: { ! 1079: redrawafter = 0L; ! 1080: preredraw = postredraw = INFINITY; ! 1081: } ! 1082: ! 1083: #ifndef CRUNCH ! 1084: /* shrink the window, if possible */ ! 1085: if (showtop < topline) ! 1086: { ! 1087: showtop = topline; ! 1088: } ! 1089: if (showbottom > botline) ! 1090: { ! 1091: showbottom = botline; ! 1092: } ! 1093: if (postredraw == INFINITY) ! 1094: { ! 1095: /* these will be set to more reasonable values later */ ! 1096: showtop = INFINITY; ! 1097: showbottom = 0L; ! 1098: } ! 1099: #endif ! 1100: ! 1101: /* adjust smartlno to correspond with inserted/deleted lines */ ! 1102: if (smartlno >= redrawafter) ! 1103: { ! 1104: if (smartlno < preredraw && postredraw != preredraw) /*!!!*/ ! 1105: { ! 1106: smartlno = 0L; ! 1107: } ! 1108: else ! 1109: { ! 1110: smartlno += (postredraw - preredraw); ! 1111: } ! 1112: } ! 1113: ! 1114: /* should we insert some lines into the screen? */ ! 1115: if (preredraw < postredraw && preredraw <= botline) ! 1116: { ! 1117: /* lines were inserted into the file */ ! 1118: ! 1119: /* decide where insertion should start */ ! 1120: if (preredraw < topline) ! 1121: { ! 1122: l = topline; ! 1123: } ! 1124: else ! 1125: { ! 1126: l = preredraw; ! 1127: } ! 1128: ! 1129: /* insert the lines... maybe */ ! 1130: if (l + postredraw - preredraw > botline || !has_AL || *o_number) ! 1131: { ! 1132: /* Whoa! a whole screen full - just redraw */ ! 1133: preredraw = postredraw = INFINITY; ! 1134: } ! 1135: else ! 1136: { ! 1137: /* really insert 'em */ ! 1138: move((int)(l - topline), 0); ! 1139: for (i = postredraw - preredraw; i > 0; i--) ! 1140: { ! 1141: insertln(); ! 1142: } ! 1143: ! 1144: /* NOTE: the contents of those lines will be ! 1145: * drawn as part of the regular redraw loop. ! 1146: */ ! 1147: ! 1148: /* clear the last line */ ! 1149: move(LINES - 1, 0); ! 1150: clrtoeol(); ! 1151: } ! 1152: } ! 1153: ! 1154: /* do we want to delete some lines from the screen? */ ! 1155: if (preredraw > postredraw && postredraw <= botline) ! 1156: { ! 1157: if (preredraw > botline || !has_DL || *o_number) ! 1158: { ! 1159: postredraw = preredraw = INFINITY; ! 1160: } ! 1161: else /* we'd best delete some lines from the screen */ ! 1162: { ! 1163: /* clear the last line, so it doesn't look ! 1164: * ugly as it gets pulled up into the screen ! 1165: */ ! 1166: move(LINES - 1, 0); ! 1167: clrtoeol(); ! 1168: ! 1169: /* delete the lines */ ! 1170: move((int)(postredraw - topline), 0); ! 1171: for (l = postredraw; ! 1172: l < preredraw && l <= botline; ! 1173: l++) ! 1174: { ! 1175: deleteln(); ! 1176: } ! 1177: ! 1178: /* draw the lines that are now newly visible ! 1179: * at the bottom of the screen ! 1180: */ ! 1181: i = LINES - 1 + (postredraw - preredraw); ! 1182: move(i, 0); ! 1183: for (l = topline + i; l <= botline; l++) ! 1184: { ! 1185: /* clear this line */ ! 1186: clrtoeol(); ! 1187: ! 1188: /* draw the line, or ~ for non-lines */ ! 1189: if (l <= nlines) ! 1190: { ! 1191: text = fetchline(l); ! 1192: drawtext(text, l, FALSE); ! 1193: } ! 1194: else ! 1195: { ! 1196: addstr("~\n"); ! 1197: } ! 1198: } ! 1199: } ! 1200: } ! 1201: ! 1202: /* redraw the current line */ ! 1203: l = markline(curs); ! 1204: pfetch(l); ! 1205: smartdrawtext(ptext, l, TRUE); ! 1206: ! 1207: #ifndef CRUNCH ! 1208: /* decide which lines must be in the "window" around the cursor */ ! 1209: l = markline(curs); ! 1210: if ((*o_window & 0xff) + 1 == LINES) ! 1211: { ! 1212: showtop = 1; ! 1213: showbottom = INFINITY; ! 1214: } ! 1215: else if (l < showtop || l > showbottom) ! 1216: { ! 1217: l -= (*o_window & 0xff) / 2; ! 1218: if (l < topline) ! 1219: { ! 1220: l = topline; ! 1221: } ! 1222: if (l < showtop) ! 1223: { ! 1224: showtop = l; ! 1225: } ! 1226: l += (*o_window & 0xff) - 1; ! 1227: if (l > botline) ! 1228: { ! 1229: showtop = showtop - l + botline; ! 1230: l = botline; ! 1231: } ! 1232: if (l > showbottom) ! 1233: { ! 1234: showbottom = l; ! 1235: } ! 1236: } ! 1237: #endif ! 1238: ! 1239: /* decide where we should start redrawing from */ ! 1240: if (redrawafter < topline) ! 1241: { ! 1242: l = topline; ! 1243: } ! 1244: else ! 1245: { ! 1246: l = redrawafter; ! 1247: } ! 1248: if (l <= botline && l < postredraw && (l != smartlno || botline != smartlno)) ! 1249: { ! 1250: /* draw the other lines */ ! 1251: move((int)(l - topline), 0); ! 1252: for (; l <= botline && l < postredraw; l++) ! 1253: { ! 1254: /* we already drew the current line, so skip it now */ ! 1255: if (l == smartlno) ! 1256: { ! 1257: #if OSK ! 1258: qaddch('\l'); ! 1259: #else ! 1260: qaddch('\n'); ! 1261: #endif ! 1262: continue; ! 1263: } ! 1264: ! 1265: /* draw the line, or ~ for non-lines */ ! 1266: if (l > nlines) ! 1267: { ! 1268: qaddch('~'); ! 1269: clrtoeol(); ! 1270: addch('\n'); ! 1271: } ! 1272: #ifndef CRUNCH ! 1273: else if (l < showtop || l > showbottom) ! 1274: { ! 1275: qaddch('@'); ! 1276: clrtoeol(); ! 1277: addch('\n'); ! 1278: } ! 1279: #endif ! 1280: else ! 1281: { ! 1282: text = fetchline(l); ! 1283: drawtext(text, l, TRUE); ! 1284: } ! 1285: } ! 1286: } ! 1287: ! 1288: mustredraw = FALSE; ! 1289: } ! 1290: ! 1291: /* force total (non-partial) redraw next time if not set */ ! 1292: redrawafter = INFINITY; ! 1293: preredraw = 0L; ! 1294: postredraw = 0L; ! 1295: ! 1296: /* move the cursor to where it belongs */ ! 1297: move((int)(markline(curs) - topline), physcol); ! 1298: wqrefresh(); ! 1299: ! 1300: chgs = changes; ! 1301: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.