1: /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */ 2: static char rcsid[] = "$Header: scrn.c,v 2.5 85/08/22 16:07:10 timo Exp $"; 3: 4: /* 5: * B editor -- Screen management package, higher level routines. 6: */ 7: 8: #include "b.h" 9: #include "erro.h" 10: #include "bobj.h" 11: #include "node.h" 12: #include "supr.h" 13: #include "gram.h" 14: #include "cell.h" 15: 16: 17: extern bool dflag; 18: 19: cell *gettop(); 20: extern int focy; 21: extern int focx; 22: 23: Visible int winstart; 24: 25: Visible int winheight; 26: Visible int indent; 27: Visible int llength; 28: 29: Visible bool noscroll; 30: Visible bool nosense; 31: 32: Hidden cell *tops; 33: 34: 35: /* 36: * Actual screen update. 37: */ 38: 39: Visible Procedure 40: actupdate(copybuffer, recording, lasttime) 41: value copybuffer; 42: bool recording; 43: bool lasttime; /* Yes if called from final screen update */ 44: { 45: register cell *p; 46: cell *top = tops; 47: register int diff; 48: register int curlno; 49: register int delcnt = 0; /* Lines deleted during the process. */ 50: /* Used as offset for lines that are on the screen. */ 51: int totlines = 0; 52: int topline = 0; 53: int scrlines = 0; 54: 55: if (winstart > 0) 56: growwin(); 57: if (winstart <= 0) { 58: top = gettop(tops); 59: for (p = tops; p && p != top; p = p->c_link) 60: ++topline; 61: totlines = topline; 62: } 63: startactupdate(lasttime); 64: focy = Nowhere; 65: for (p = top, curlno = winstart; p && curlno < winheight; 66: curlno += Space(p), p = p->c_link) { 67: ++scrlines; 68: if (lasttime) { 69: p->c_newfocus = No; 70: p->c_newvhole = 0; 71: } 72: if (p->c_onscreen != Nowhere && Space(p) == Oldspace(p)) { 73: /* Old comrade */ 74: diff = p->c_onscreen - (curlno+delcnt); 75: /* diff can't be negative due to 'makeroom' below! */ 76: if (diff > 0) { /* Get him here */ 77: trmscrollup(curlno, winheight, diff); 78: delcnt += diff; 79: } 80: if (p->c_oldfocus || p->c_newfocus 81: || p->c_oldindent != p->c_newindent 82: || p->c_onscreen + Space(p) >= winheight) { 83: delcnt = make2room(p, curlno, delcnt); 84: outline(p, curlno); 85: } 86: } 87: else { /* New guy, make him toe the line */ 88: delcnt = makeroom(p, curlno, delcnt); 89: delcnt = make2room(p, curlno, delcnt); 90: outline(p, curlno); 91: } 92: p->c_onscreen = curlno; 93: p->c_oldindent = p->c_newindent; 94: p->c_oldvhole = p->c_newvhole; 95: p->c_oldfocus = p->c_newfocus; 96: } 97: totlines += scrlines; 98: for (; p; p = p->c_link) { /* Count rest and remove old memories */ 99: ++totlines; 100: /* This code should never find any garbage?! */ 101: #ifndef NDEBUG 102: if (p->c_onscreen != Nowhere) 103: debug("[Garbage removed from screen list]"); 104: #endif NDEBUG 105: p->c_onscreen = Nowhere; 106: } 107: trmscrollup(curlno, winheight, -delcnt); 108: curlno += delcnt; 109: if (curlno < winheight) { /* Clear lines beyond end of unit */ 110: trmputdata(curlno, winheight-1, 0, ""); 111: scrlines += winheight-curlno; 112: } 113: if (!lasttime) { 114: stsline(totlines, topline, scrlines, copybuffer, recording); 115: if (focy != Nowhere) 116: trmsync(focy, focx); 117: else 118: trmsync(winheight, 0); 119: } 120: endactupdate(); 121: } 122: 123: 124: /* 125: * Grow the window if not maximum size. 126: */ 127: 128: Hidden Procedure 129: growwin() 130: { 131: register int winsize; 132: register int growth; 133: register cell *p; 134: 135: winsize = 0; 136: for (p = tops; p; p = p->c_link) 137: winsize += Space(p); 138: if (winsize <= winheight - winstart) 139: return; /* No need to grow */ 140: if (winsize > winheight) 141: winsize = winheight; /* Limit size to maximum available */ 142: 143: growth = winsize - (winheight - winstart); 144: trmscrollup(0, winheight - (winstart!=winheight), growth); 145: winstart -= growth; 146: for (p = tops; p; p = p->c_link) { 147: if (p->c_onscreen != Nowhere) 148: p->c_onscreen -= growth; 149: } 150: } 151: 152: 153: /* 154: * Make room for possible insertions. 155: * (If a line is inserted, it may be necessary to delete lines 156: * further on the screen.) 157: */ 158: 159: Hidden Procedure 160: makeroom(p, curlno, delcnt) 161: register cell *p; 162: register int curlno; 163: register int delcnt; 164: { 165: register int here = 0; 166: register int need = Space(p); 167: register int amiss; 168: int avail; 169: int diff; 170: 171: Assert(p); 172: do { 173: p = p->c_link; 174: if (!p) 175: return delcnt; 176: } while (p->c_onscreen == Nowhere); 177: here = p->c_onscreen - delcnt; 178: avail = here - curlno; 179: amiss = need - avail; 180: #ifndef NDEBUG 181: if (dflag) 182: debug("[makeroom: curlno=%d, delcnt=%d, here=%d, avail=%d, amiss=%d]", 183: curlno, delcnt, here, avail, amiss); 184: #endif NDEBUG 185: if (amiss <= 0) 186: return delcnt; 187: if (amiss > delcnt) { 188: for (; p; p = p->c_link) { 189: if (p->c_onscreen != Nowhere) { 190: diff = amiss-delcnt; 191: if (p->c_onscreen - delcnt - here < diff) 192: diff = p->c_onscreen - delcnt - here; 193: if (diff > 0) { 194: trmscrollup(here, winheight, diff); 195: delcnt += diff; 196: } 197: p->c_onscreen += -delcnt + amiss; 198: here = p->c_onscreen - amiss; 199: if (p->c_onscreen >= winheight) 200: p->c_onscreen = Nowhere; 201: } 202: here += Space(p); 203: } 204: /* Now for all p encountered whose p->c_onscreen != Nowhere, 205: /* p->c_onscreen - amiss is its actual position. */ 206: if (amiss > delcnt) { 207: trmscrollup(winheight - amiss, winheight, amiss-delcnt); 208: delcnt = amiss; 209: } 210: } 211: /* Now amiss <= delcnt */ 212: trmscrollup(curlno + avail, winheight, -amiss); 213: return delcnt - amiss; 214: } 215: 216: 217: /* 218: * Addition to makeroom - make sure the status line is not overwritten. 219: * Returns new delcnt, like makeroom does. 220: */ 221: 222: Hidden int 223: make2room(p, curlno, delcnt) 224: cell *p; 225: int curlno; 226: int delcnt; 227: { 228: int nextline = curlno + Space(p); 229: int sline = winheight - delcnt; 230: int diff; 231: 232: if (sline < curlno) { 233: #ifndef NDEBUG 234: debug("[Status line overwritten]"); 235: #endif NDEBUG 236: return delcnt; 237: } 238: if (nextline > winheight) 239: nextline = winheight; 240: diff = nextline - sline; 241: if (diff > 0) { 242: trmscrollup(sline, winheight, -diff); 243: delcnt -= diff; 244: } 245: return delcnt; 246: 247: } 248: 249: 250: /* 251: * Routine called for every change in the screen. 252: */ 253: 254: Visible Procedure 255: virtupdate(oldep, newep, highest) 256: environ *oldep; 257: environ *newep; 258: int highest; 259: { 260: environ old; 261: environ new; 262: register int oldlno; 263: register int newlno; 264: register int oldlcnt; 265: register int newlcnt; 266: register int i; 267: 268: if (!oldep) { 269: highest = 1; 270: trmputdata(winstart, winheight, indent, ""); 271: discard(tops); 272: tops = Cnil; 273: Ecopy(*newep, old); 274: } 275: else { 276: Ecopy(*oldep, old); 277: } 278: Ecopy(*newep, new); 279: 280: savefocus(&new); 281: 282: oldlcnt = fixlevels(&old, &new, highest); 283: newlcnt = -width(tree(new.focus)); 284: if (newlcnt < 0) 285: newlcnt = 0; 286: i = -width(tree(old.focus)); 287: if (i < 0) 288: i = 0; 289: newlcnt -= i - oldlcnt; 290: /* Offset newlcnt as much as oldcnt is offset */ 291: 292: oldlno = Ycoord(old.focus); 293: newlno = Ycoord(new.focus); 294: if (!atlinestart(&old)) 295: ++oldlcnt; 296: else 297: ++oldlno; 298: if (!atlinestart(&new)) 299: ++newlcnt; 300: else 301: ++newlno; 302: Assert(oldlno == newlno); 303: 304: tops = replist(tops, build(new.focus, newlcnt), oldlno, oldlcnt); 305: 306: setfocus(tops); /* Incorporate the information saved by savefocus */ 307: 308: Erelease(old); 309: Erelease(new); 310: } 311: 312: 313: Hidden bool 314: atlinestart(ep) 315: environ *ep; 316: { 317: register string repr = noderepr(tree(ep->focus))[0]; 318: 319: return Fw_negative(repr); 320: } 321: 322: 323: /* 324: * Make the two levels the same, and make sure they both are line starters 325: * if at all possible. Return the OLD number of lines to be replaced. 326: * (0 if the whole unit has no linefeeds.) 327: */ 328: 329: Hidden int 330: fixlevels(oldep, newep, highest) 331: register environ *oldep; 332: register environ *newep; 333: register int highest; 334: { 335: register int oldpl = pathlength(oldep->focus); 336: register int newpl = pathlength(newep->focus); 337: register bool intraline = No; 338: register int w; 339: 340: if (oldpl < highest) 341: highest = oldpl; 342: if (newpl < highest) 343: highest = newpl; 344: while (oldpl > highest) { 345: up(&oldep->focus) || Abort(); 346: --oldpl; 347: } 348: while (newpl > highest) { 349: up(&newep->focus) || Abort(); 350: --newpl; 351: } 352: if (Ycoord(newep->focus) != Ycoord(oldep->focus) || 353: Level(newep->focus) != Level(newep->focus)) { 354: /* Inconsistency found. */ 355: Assert(highest > 1); /* Inconsistency at top level. Stop. */ 356: return fixlevels(oldep, newep, 1); /* Try to recover. */ 357: } 358: intraline = width(tree(oldep->focus)) >= 0 359: && width(tree(newep->focus)) >= 0; 360: while (!atlinestart(oldep) || !atlinestart(newep)) { 361: /* Find beginning of lines for both */ 362: if (!up(&newep->focus)) { 363: Assert(!up(&newep->focus)); 364: break; 365: } 366: --oldpl; 367: up(&oldep->focus) || Abort(); 368: --newpl; 369: } 370: if (intraline) 371: return atlinestart(oldep); 372: w = width(tree(oldep->focus)); 373: return w < 0 ? -w : 0; 374: } 375: 376: 377: /* 378: * Initialization code. 379: */ 380: 381: Visible Procedure 382: initshow() 383: { 384: int flags = 0; 385: #ifndef NDEBUG 386: if (dflag) 387: fprintf(stderr, "*** initshow();\n\r"); 388: #endif NDEBUG 389: if (!trmstart(&winheight, &llength, &flags)) { 390: endunix(); 391: exit(2); 392: } 393: noscroll = (flags&2) == 0; 394: nosense = (flags&8) == 0; 395: winstart = --winheight; 396: } 397: 398: 399: /* 400: * Routine to move the cursor to the first line after the just edited 401: * document. (Called after each editing action.) 402: */ 403: 404: Visible Procedure 405: endshow() 406: { 407: register cell *p; 408: register int last = winheight; 409: 410: for (p = tops; p; p = p->c_link) { 411: if (p->c_onscreen != Nowhere) 412: last = p->c_onscreen + Oldspace(p); 413: } 414: if (last > winheight) 415: last = winheight; 416: discard(tops); 417: tops = Cnil; 418: trmputdata(last, winheight, 0, ""); 419: trmsync(last, 0); 420: trmend(); 421: } 422: 423: 424: /* 425: * Translate a cursor position in tree coordinates. 426: * 427: * ***** DOESN'T WORK IF SCREEN INDENT DIFFERS FROM TREE INDENT! ***** 428: * (I.e. for lines with >= 80 spaces indentation) 429: */ 430: 431: Visible bool 432: backtranslate(py, px) 433: int *py; 434: int *px; 435: { 436: cell *p; 437: int y = *py; 438: int x = *px; 439: int i; 440: 441: for (i = 0, p = tops; p; ++i, p = p->c_link) { 442: if (p->c_onscreen != Nowhere 443: && y >= p->c_onscreen && y < p->c_onscreen + Space(p)) { 444: *px += (y - p->c_onscreen) * llength - indent; 445: if (*px < 0) 446: *px = 0; 447: *py = i; 448: if (p->c_oldvhole && (y > focy || y == focy && x > focx)) 449: --*px; /* Correction if beyond Vhole on same logical line */ 450: return Yes; 451: } 452: } 453: error(GOTO_OUT); 454: return No; 455: } 456: 457: 458: /* 459: * Set the indent level and window start line. 460: */ 461: 462: Visible Procedure 463: setindent(x) 464: int x; 465: { 466: winstart= winheight; 467: indent= x; 468: } 469: 470: 471: /* 472: * Show the command prompt. 473: */ 474: 475: Visible Procedure cmdprompt(prompt) 476: string prompt; 477: { 478: setindent(strlen(prompt)); 479: trmputdata(winstart, winstart, 0, prompt); 480: }