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