1: /* Copyright (c) 1979 Regents of the University of California */ 2: #include "ex.h" 3: #include "ex_tty.h" 4: #include "ex_vis.h" 5: 6: /* 7: * Routines to adjust the window, showing specified lines 8: * in certain positions on the screen, and scrolling in both 9: * directions. Code here is very dependent on mode (open versus visual). 10: */ 11: 12: /* 13: * Move in a nonlocal way to line addr. 14: * If it isn't on screen put it in specified context. 15: * New position for cursor is curs. 16: * Like most routines here, we vsave(). 17: */ 18: vmoveto(addr, curs, context) 19: register line *addr; 20: char *curs; 21: char context; 22: { 23: 24: markit(addr); 25: vsave(); 26: vjumpto(addr, curs, context); 27: } 28: 29: /* 30: * Vjumpto is like vmoveto, but doesn't mark previous 31: * context or save linebuf as current line. 32: */ 33: vjumpto(addr, curs, context) 34: register line *addr; 35: char *curs; 36: char context; 37: { 38: 39: noteit(0); 40: if (context != 0) 41: vcontext(addr, context); 42: else 43: vshow(addr, NOLINE); 44: noteit(1); 45: vnline(curs); 46: } 47: 48: /* 49: * Go up or down cnt (negative is up) to new position curs. 50: */ 51: vupdown(cnt, curs) 52: register int cnt; 53: char *curs; 54: { 55: 56: if (cnt > 0) 57: vdown(cnt, 0, 0); 58: else if (cnt < 0) 59: vup(-cnt, 0, 0); 60: if (vcnt == 0) 61: vrepaint(curs); 62: else 63: vnline(curs); 64: } 65: 66: /* 67: * Go up cnt lines, afterwards preferring to be ind 68: * logical lines from the top of the screen. 69: * If scroll, then we MUST use a scroll. 70: * Otherwise clear and redraw if motion is far. 71: */ 72: vup(cnt, ind, scroll) 73: register int cnt, ind; 74: bool scroll; 75: { 76: register int i, tot; 77: 78: if (dot == one) { 79: beep(); 80: return; 81: } 82: vsave(); 83: i = lineDOT() - 1; 84: if (cnt > i) { 85: ind -= cnt - i; 86: if (ind < 0) 87: ind = 0; 88: cnt = i; 89: } 90: if (!scroll && cnt <= vcline) { 91: vshow(dot - cnt, NOLINE); 92: return; 93: } 94: cnt -= vcline, dot -= vcline, vcline = 0; 95: if (hold & HOLDWIG) 96: goto contxt; 97: if ( 98: #ifdef OPENCODE 99: state == VISUAL && 100: #endif 101: !AL && !SR && 102: cnt <= WTOP - ZERO && vfit(dot - cnt, cnt) <= WTOP - ZERO) 103: goto okr; 104: tot = WECHO - ZERO; 105: if ( 106: #ifdef OPENCODE 107: state != VISUAL || 108: #endif 109: (!AL && !SR) || (!scroll && (cnt > tot || vfit(dot - cnt, cnt) > tot / 3 + 1))) { 110: if (ind > basWLINES / 2) 111: ind = basWLINES / 3; 112: contxt: 113: vcontext(dot + ind - cnt, '.'); 114: return; 115: } 116: okr: 117: vrollR(cnt); 118: if (scroll) { 119: vcline += ind, dot += ind; 120: if (vcline >= vcnt) 121: dot -= vcline - vcnt + 1, vcline = vcnt - 1; 122: getDOT(); 123: } 124: } 125: 126: /* 127: * Like vup, but scrolling down. 128: */ 129: vdown(cnt, ind, scroll) 130: register int cnt, ind; 131: bool scroll; 132: { 133: register int i, tot; 134: 135: if (dot == dol) { 136: beep(); 137: return; 138: } 139: vsave(); 140: i = dol - dot; 141: if (cnt > i) { 142: ind -= cnt - i; 143: if (ind < 0) 144: ind = 0; 145: cnt = i; 146: } 147: i = vcnt - vcline - 1; 148: if (!scroll && cnt <= i) { 149: vshow(dot + cnt, NOLINE); 150: return; 151: } 152: cnt -= i, dot += i, vcline += i; 153: if (hold & HOLDWIG) 154: goto dcontxt; 155: if (!scroll) { 156: tot = WECHO - ZERO; 157: if ( 158: #ifdef OPENCODE 159: state != VISUAL || 160: #endif 161: cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) { 162: dcontxt: 163: vcontext(dot + cnt, '.'); 164: return; 165: } 166: } 167: if (cnt > 0) 168: vroll(cnt); 169: if ( 170: #ifdef OPENCODE 171: state == VISUAL && 172: #endif 173: scroll) { 174: vcline -= ind, dot -= ind; 175: if (vcline < 0) 176: dot -= vcline, vcline = 0; 177: getDOT(); 178: } 179: } 180: 181: /* 182: * Show line addr in context where on the screen. 183: * Work here is in determining new top line implied by 184: * this placement of line addr, since we always draw from the top. 185: */ 186: vcontext(addr, where) 187: register line *addr; 188: char where; 189: { 190: register line *top; 191: 192: getline(*addr); 193: #ifdef OPENCODE 194: if (state != VISUAL) 195: top = addr; 196: else 197: #endif 198: switch (where) { 199: 200: case '^': 201: addr = vback(addr, basWLINES - vdepth()); 202: getline(*addr); 203: /* fall into ... */ 204: 205: case '-': 206: top = vback(addr, basWLINES - vdepth()); 207: getline(*addr); 208: break; 209: 210: case '.': 211: top = vback(addr, basWLINES / 2 - vdepth()); 212: getline(*addr); 213: break; 214: 215: default: 216: top = addr; 217: break; 218: } 219: #ifdef OPENCODE 220: if (state == ONEOPEN && LINE(0) == WBOT) 221: vup1(); 222: #endif 223: vcnt = vcline = 0; 224: vclean(); 225: #ifdef OPENCODE 226: if (state == CRTOPEN) 227: vup1(); 228: #endif 229: vshow(addr, top); 230: } 231: 232: /* 233: * Get a clean line. If we are in a hard open 234: * we may be able to reuse the line we are on 235: * if it is blank. This is a real win. 236: */ 237: vclean() 238: { 239: 240: #ifdef OPENCODE 241: if (state != VISUAL && state != CRTOPEN) { 242: destcol = 0; 243: if (!ateopr()) 244: vup1(); 245: vcnt = 0; 246: } 247: #endif 248: } 249: 250: /* 251: * Show line addr with the specified top line on the screen. 252: * Top may be 0; in this case have vcontext compute the top 253: * (and call us recursively). Eventually, we clear the screen 254: * (or its open mode equivalent) and redraw. 255: */ 256: vshow(addr, top) 257: line *addr, *top; 258: { 259: #ifndef CBREAK 260: register bool fried = 0; 261: #endif 262: register int cnt = addr - dot; 263: register int i = vcline + cnt; 264: short oldhold = hold; 265: 266: if ( 267: #ifdef OPENCODE 268: state != HARDOPEN && state != ONEOPEN && 269: #endif 270: i >= 0 && i < vcnt) { 271: dot = addr; 272: getDOT(); 273: vcline = i; 274: return; 275: } 276: #ifdef OPENCODE 277: if (state != VISUAL) { 278: dot = addr; 279: vopen(dot, WBOT); 280: return; 281: } 282: #endif 283: if (top == 0) { 284: vcontext(addr, '.'); 285: return; 286: } 287: dot = top; 288: #ifndef CBREAK 289: if (vcookit(2)) 290: fried++, vcook(); 291: #endif 292: oldhold = hold; 293: hold |= HOLDAT; 294: vclear(); 295: vreset(0); 296: vredraw(WTOP); 297: /* error if vcline >= vcnt ! */ 298: vcline = addr - top; 299: dot = addr; 300: getDOT(); 301: hold = oldhold; 302: vsync(LASTLINE); 303: #ifndef CBREAK 304: if (fried) 305: flusho(), vraw(); 306: #endif 307: } 308: 309: /* 310: * reset the state. 311: * If inecho then leave us at the beginning of the echo 312: * area; we are called this way in the middle of a :e escape 313: * from visual, e.g. 314: */ 315: vreset(inecho) 316: bool inecho; 317: { 318: 319: vcnt = vcline = 0; 320: WTOP = basWTOP; 321: WLINES = basWLINES; 322: if (inecho) 323: splitw = 1, vgoto(WECHO, 0); 324: } 325: 326: /* 327: * Starting from which line preceding tp uses almost (but not more 328: * than) cnt physical lines? 329: */ 330: line * 331: vback(tp, cnt) 332: register int cnt; 333: register line *tp; 334: { 335: register int d; 336: 337: if (cnt > 0) 338: for (; tp > one; tp--) { 339: getline(tp[-1]); 340: d = vdepth(); 341: if (d > cnt) 342: break; 343: cnt -= d; 344: } 345: return (tp); 346: } 347: 348: /* 349: * How much scrolling will it take to roll cnt lines starting at tp? 350: */ 351: vfit(tp, cnt) 352: register line *tp; 353: int cnt; 354: { 355: register int j; 356: 357: j = 0; 358: while (cnt > 0) { 359: cnt--; 360: getline(tp[cnt]); 361: j += vdepth(); 362: } 363: if (tp > dot) 364: j -= WBOT - LASTLINE; 365: return (j); 366: } 367: 368: /* 369: * Roll cnt lines onto the screen. 370: */ 371: vroll(cnt) 372: register int cnt; 373: { 374: #ifndef CBREAK 375: register bool fried = 0; 376: #endif 377: short oldhold = hold; 378: 379: #ifdef ADEBUG 380: if (trace) 381: tfixnl(), fprintf(trace, "vroll(%d)\n", cnt); 382: #endif 383: #ifdef OPENCODE 384: if (state != VISUAL) 385: hold |= HOLDAT|HOLDROL; 386: #endif 387: if (WBOT == WECHO) { 388: vcnt = 0; 389: #ifdef OPENCODE 390: if (state == ONEOPEN) 391: vup1(); 392: #endif 393: } 394: #ifndef CBREAK 395: if (vcookit(cnt)) 396: fried++, vcook(); 397: #endif 398: for (; cnt > 0 && Peekkey != ATTN; cnt--) { 399: dot++, vcline++; 400: vopen(dot, LASTLINE); 401: vscrap(); 402: } 403: hold = oldhold; 404: #ifdef OPENCODE 405: if (state == HARDOPEN) 406: sethard(); 407: #endif 408: vsyncCL(); 409: #ifndef CBREAK 410: if (fried) 411: flusho(), vraw(); 412: #endif 413: } 414: 415: /* 416: * Roll backwards (scroll up). 417: */ 418: vrollR(cnt) 419: register int cnt; 420: { 421: register bool fried = 0; 422: short oldhold = hold; 423: 424: #ifdef ADEBUG 425: if (trace) 426: tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT()); 427: #endif 428: #ifndef CBREAK 429: if (vcookit(cnt)) 430: fried++, vcook(); 431: #endif 432: if (WBOT == WECHO) 433: vcnt = 0; 434: heldech = 0; 435: hold |= HOLDAT|HOLDECH; 436: for (; cnt > 0 && Peekkey != ATTN; cnt--) { 437: dot--; 438: vopen(dot, WTOP); 439: vscrap(); 440: } 441: hold = oldhold; 442: if (heldech) 443: vclrech(0); 444: vsync(LINE(vcnt-1)); 445: #ifndef CBREAK 446: if (fried) 447: flusho(), vraw(); 448: #endif 449: } 450: 451: /* 452: * Go into cooked mode (allow interrupts) during 453: * a scroll if we are at less than 1200 baud and not 454: * a 'vi' command, of if we are in a 'vi' command and the 455: * scroll is more than 2 full screens. 456: * 457: * BUG: An interrupt during a scroll in this way 458: * dumps to command mode. 459: */ 460: vcookit(cnt) 461: register int cnt; 462: { 463: 464: return (cnt > 1 && (ospeed < B1200 && !initev || cnt > LINES * 2)); 465: } 466: 467: /* 468: * Determine displayed depth of current line. 469: */ 470: vdepth() 471: { 472: register int d; 473: 474: d = (column(NOSTR) + WCOLS - 1 + (Putchar == listchar) + IN) / WCOLS; 475: #ifdef ADEBUG 476: if (trace) 477: tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d); 478: #endif 479: return (d == 0 ? 1 : d); 480: } 481: 482: /* 483: * Move onto a new line, with cursor at position curs. 484: */ 485: vnline(curs) 486: char *curs; 487: { 488: 489: if (curs) 490: wcursor = curs; 491: else if (vmoving) 492: wcursor = vfindcol(vmovcol); 493: else 494: wcursor = vskipwh(linebuf); 495: cursor = linebuf; 496: vmove(); 497: }