| 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.9 (Berkeley) %G%"; |
| 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 | |
| 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 | vintr() |
| 396 | { |
| 397 | extern jmp_buf readbuf; |
| 398 | extern int doingread; |
| 399 | |
| 400 | signal(SIGINT, vintr); |
| 401 | if (vcatch) |
| 402 | onintr(); |
| 403 | ungetkey(ATTN); |
| 404 | draino(); |
| 405 | if (doingread) { |
| 406 | doingread = 0; |
| 407 | longjmp(readbuf, 1); |
| 408 | } |
| 409 | } |
| 410 | #endif |
| 411 | |
| 412 | /* |
| 413 | * Set the size of the screen to size lines, to take effect the |
| 414 | * next time the screen is redrawn. |
| 415 | */ |
| 416 | vsetsiz(size) |
| 417 | int size; |
| 418 | { |
| 419 | register int b; |
| 420 | |
| 421 | if (bastate != VISUAL) |
| 422 | return; |
| 423 | b = LINES - 1 - size; |
| 424 | if (b >= LINES - 1) |
| 425 | b = LINES - 2; |
| 426 | if (b < 0) |
| 427 | b = 0; |
| 428 | basWTOP = b; |
| 429 | basWLINES = WBOT - b + 1; |
| 430 | } |
| 431 | |
| 432 | #ifdef SIGWINCH |
| 433 | winch() |
| 434 | { |
| 435 | vsave(); |
| 436 | ignore(setty(normf)); |
| 437 | longjmp(venv, 1); |
| 438 | } |
| 439 | #endif |