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