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