1 /* Copyright (c) 1980 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_v.c 6.1 10/19/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 } 383