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