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