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: #ifndef lint 8: static char *sccsid = "@(#)ex_v.c 7.8 (Berkeley) 6/7/85"; 9: #endif not lint 10: 11: #include "ex.h" 12: #include "ex_re.h" 13: #include "ex_tty.h" 14: #include "ex_vis.h" 15: 16: /* 17: * Entry points to open and visual from command mode processor. 18: * The open/visual code breaks down roughly as follows: 19: * 20: * ex_v.c entry points, checking of terminal characteristics 21: * 22: * ex_vadj.c logical screen control, use of intelligent operations 23: * insert/delete line and coordination with screen image; 24: * updating of screen after changes. 25: * 26: * ex_vget.c input of single keys and reading of input lines 27: * from the echo area, handling of \ escapes on input for 28: * uppercase only terminals, handling of memory for repeated 29: * commands and small saved texts from inserts and partline 30: * deletes, notification of multi line changes in the echo 31: * area. 32: * 33: * ex_vmain.c main command decoding, some command processing. 34: * 35: * ex_voperate.c decoding of operator/operand sequences and 36: * contextual scans, implementation of word motions. 37: * 38: * ex_vops.c major operator interfaces, undos, motions, deletes, 39: * changes, opening new lines, shifts, replacements and yanks 40: * coordinating logical and physical changes. 41: * 42: * ex_vops2.c subroutines for operator interfaces in ex_vops.c, 43: * insert mode, read input line processing at lowest level. 44: * 45: * ex_vops3.c structured motion definitions of ( ) { } and [ ] operators, 46: * indent for lisp routines, () and {} balancing. 47: * 48: * ex_vput.c output routines, clearing, physical mapping of logical cursor 49: * positioning, cursor motions, handling of insert character 50: * and delete character functions of intelligent and unintelligent 51: * terminals, visual mode tracing routines (for debugging), 52: * control of screen image and its updating. 53: * 54: * ex_vwind.c window level control of display, forward and backward rolls, 55: * absolute motions, contextual displays, line depth determination 56: */ 57: 58: jmp_buf venv; 59: int winch(); 60: 61: /* 62: * Enter open mode 63: */ 64: #ifdef u370 65: char atube[TUBESIZE+LBSIZE]; 66: #endif 67: oop() 68: { 69: register char *ic; 70: #ifndef u370 71: char atube[TUBESIZE + LBSIZE]; 72: #endif 73: ttymode f; /* mjm: was register */ 74: int resize; 75: 76: if (resize = setjmp(venv)) { 77: setsize(); 78: initev = (char *)0; 79: inopen = 0; 80: addr1 = addr2 = dot; 81: } 82: (void)signal(SIGWINCH, winch); 83: ovbeg(); 84: if (peekchar() == '/') { 85: ignore(compile(getchar(), 1)); 86: savere(scanre); 87: if (execute(0, dot) == 0) 88: error("Fail|Pattern not found on addressed line"); 89: ic = loc1; 90: if (ic > linebuf && *ic == 0) 91: ic--; 92: } else { 93: getDOT(); 94: ic = vskipwh(linebuf); 95: } 96: newline(); 97: 98: /* 99: * If overstrike then have to HARDOPEN 100: * else if can move cursor up off current line can use CRTOPEN (~~vi1) 101: * otherwise (ugh) have to use ONEOPEN (like adm3) 102: */ 103: if (OS && !EO) 104: bastate = HARDOPEN; 105: else if (CA || UP) 106: bastate = CRTOPEN; 107: else 108: bastate = ONEOPEN; 109: setwind(); 110: 111: /* 112: * To avoid bombing on glass-crt's when the line is too long 113: * pretend that such terminals are 160 columns wide. 114: * If a line is too wide for display, we will dynamically 115: * switch to hardcopy open mode. 116: */ 117: if (state != CRTOPEN) 118: WCOLS = TUBECOLS; 119: if (!inglobal) 120: savevis(); 121: vok(atube); 122: if (state != CRTOPEN) 123: COLUMNS = WCOLS; 124: Outchar = vputchar; 125: f = ostart(); 126: if (state == CRTOPEN) { 127: if (outcol == UKCOL) 128: outcol = 0; 129: vmoveitup(1, 1); 130: } else 131: outline = destline = WBOT; 132: vshow(dot, NOLINE); 133: vnline(ic); 134: vmain(); 135: if (state != CRTOPEN) 136: vclean(); 137: Command = "open"; 138: ovend(f); 139: (void)signal(SIGWINCH, SIG_DFL); 140: } 141: 142: ovbeg() 143: { 144: 145: if (!value(OPEN)) 146: error("Can't use open/visual unless open option is set"); 147: if (inopen) 148: error("Recursive open/visual not allowed"); 149: Vlines = lineDOL(); 150: fixzero(); 151: setdot(); 152: pastwh(); 153: dot = addr2; 154: } 155: 156: ovend(f) 157: ttymode f; 158: { 159: 160: splitw++; 161: vgoto(WECHO, 0); 162: vclreol(); 163: vgoto(WECHO, 0); 164: holdcm = 0; 165: splitw = 0; 166: ostop(f); 167: setoutt(); 168: undvis(); 169: COLUMNS = OCOLUMNS; 170: inopen = 0; 171: flusho(); 172: netchHAD(Vlines); 173: } 174: 175: /* 176: * Enter visual mode 177: */ 178: vop() 179: { 180: register int c; 181: #ifndef u370 182: char atube[TUBESIZE + LBSIZE]; 183: #endif 184: ttymode f; /* mjm: was register */ 185: int resize; 186: 187: if (!CA && UP == NOSTR) { 188: if (initev) { 189: toopen: 190: merror("[Using open mode]"); 191: putNFL(); 192: oop(); 193: return; 194: } 195: error("Visual needs addressible cursor or upline capability"); 196: } 197: if (OS && !EO) { 198: if (initev) 199: goto toopen; 200: error("Can't use visual on a terminal which overstrikes"); 201: } 202: if (!CL) { 203: if (initev) 204: goto toopen; 205: error("Visual requires clear screen capability"); 206: } 207: if (NS && !SF) { 208: if (initev) 209: goto toopen; 210: error("Visual requires scrolling"); 211: } 212: if (resize = setjmp(venv)) { 213: setsize(); 214: initev = (char *)0; 215: inopen = 0; 216: addr1 = addr2 = dot; 217: } 218: (void)signal(SIGWINCH, winch); 219: ovbeg(); 220: bastate = VISUAL; 221: c = 0; 222: if (any(peekchar(), "+-^.")) 223: c = getchar(); 224: pastwh(); 225: vsetsiz(isdigit(peekchar()) ? getnum() : value(WINDOW)); 226: setwind(); 227: newline(); 228: vok(atube); 229: if (!inglobal) 230: savevis(); 231: Outchar = vputchar; 232: vmoving = 0; 233: f = ostart(); 234: if (initev == 0) { 235: vcontext(dot, c); 236: vnline(NOSTR); 237: } 238: vmain(); 239: Command = "visual"; 240: ovend(f); 241: (void)signal(SIGWINCH, SIG_DFL); 242: } 243: 244: /* 245: * Hack to allow entry to visual with 246: * empty buffer since routines internally 247: * demand at least one line. 248: */ 249: fixzero() 250: { 251: 252: if (dol == zero) { 253: register bool ochng = chng; 254: 255: vdoappend(""); 256: if (!ochng) 257: sync(); 258: addr1 = addr2 = one; 259: } else if (addr2 == zero) 260: addr2 = one; 261: } 262: 263: /* 264: * Save lines before visual between unddol and truedol. 265: * Accomplish this by throwing away current [unddol,truedol] 266: * and then saving all the lines in the buffer and moving 267: * unddol back to dol. Don't do this if in a global. 268: * 269: * If you do 270: * g/xxx/vi. 271: * and then do a 272: * :e xxxx 273: * at some point, and then quit from the visual and undo 274: * you get the old file back. Somewhat weird. 275: */ 276: savevis() 277: { 278: 279: if (inglobal) 280: return; 281: truedol = unddol; 282: saveall(); 283: unddol = dol; 284: undkind = UNDNONE; 285: } 286: 287: /* 288: * Restore a sensible state after a visual/open, moving the saved 289: * stuff back to [unddol,dol], and killing the partial line kill indicators. 290: */ 291: undvis() 292: { 293: 294: if (ruptible) 295: signal(SIGINT, onintr); 296: squish(); 297: pkill[0] = pkill[1] = 0; 298: unddol = truedol; 299: unddel = zero; 300: undap1 = one; 301: undap2 = dol + 1; 302: undkind = UNDALL; 303: if (undadot <= zero || undadot > dol) 304: undadot = zero+1; 305: } 306: 307: /* 308: * Set the window parameters based on the base state bastate 309: * and the available buffer space. 310: */ 311: setwind() 312: { 313: 314: WCOLS = COLUMNS; 315: switch (bastate) { 316: 317: case ONEOPEN: 318: if (AM) 319: WCOLS--; 320: /* fall into ... */ 321: 322: case HARDOPEN: 323: basWTOP = WTOP = WBOT = WECHO = 0; 324: ZERO = 0; 325: holdcm++; 326: break; 327: 328: case CRTOPEN: 329: basWTOP = LINES - 2; 330: /* fall into */ 331: 332: case VISUAL: 333: ZERO = LINES - TUBESIZE / WCOLS; 334: if (ZERO < 0) 335: ZERO = 0; 336: if (ZERO > basWTOP) 337: error("Screen too large for internal buffer"); 338: WTOP = basWTOP; WBOT = LINES - 2; WECHO = LINES - 1; 339: break; 340: } 341: state = bastate; 342: basWLINES = WLINES = WBOT - WTOP + 1; 343: } 344: 345: /* 346: * Can we hack an open/visual on this terminal? 347: * If so, then divide the screen buffer up into lines, 348: * and initialize a bunch of state variables before we start. 349: */ 350: vok(atube) 351: register char *atube; 352: { 353: register int i; 354: 355: if (WCOLS == 1000) 356: serror("Don't know enough about your terminal to use %s", Command); 357: if (WCOLS > TUBECOLS) 358: error("Terminal too wide"); 359: if (WLINES >= TUBELINES || WCOLS * (WECHO - ZERO + 1) > TUBESIZE) 360: error("Screen too large"); 361: 362: vtube0 = atube; 363: vclrbyte(atube, WCOLS * (WECHO - ZERO + 1)); 364: for (i = 0; i < ZERO; i++) 365: vtube[i] = (char *) 0; 366: for (; i <= WECHO; i++) 367: vtube[i] = atube, atube += WCOLS; 368: for (; i < TUBELINES; i++) 369: vtube[i] = (char *) 0; 370: vutmp = atube; 371: vundkind = VNONE; 372: vUNDdot = 0; 373: OCOLUMNS = COLUMNS; 374: inopen = 1; 375: #ifdef CBREAK 376: signal(SIGINT, vintr); 377: #endif 378: vmoving = 0; 379: splitw = 0; 380: doomed = 0; 381: holdupd = 0; 382: Peekkey = 0; 383: vcnt = vcline = 0; 384: if (vSCROLL == 0) 385: vSCROLL = (value(WINDOW)+1)/2; /* round up so dft=6,11 */ 386: } 387: 388: #ifdef CBREAK 389: vintr() 390: { 391: extern jmp_buf readbuf; 392: extern int doingread; 393: 394: signal(SIGINT, vintr); 395: if (vcatch) 396: onintr(); 397: ungetkey(ATTN); 398: draino(); 399: if (doingread) { 400: doingread = 0; 401: longjmp(readbuf, 1); 402: } 403: } 404: #endif 405: 406: /* 407: * Set the size of the screen to size lines, to take effect the 408: * next time the screen is redrawn. 409: */ 410: vsetsiz(size) 411: int size; 412: { 413: register int b; 414: 415: if (bastate != VISUAL) 416: return; 417: b = LINES - 1 - size; 418: if (b >= LINES - 1) 419: b = LINES - 2; 420: if (b < 0) 421: b = 0; 422: basWTOP = b; 423: basWLINES = WBOT - b + 1; 424: } 425: 426: winch() 427: { 428: vsave(); 429: setty(normf); 430: longjmp(venv, 1); 431: }