1 /* Copyright (c) 1981 Regents of the University of California */ 2 static char *sccsid = "@(#)ex_vwind.c 7.1 07/08/81"; 3 #include "ex.h" 4 #include "ex_tty.h" 5 #include "ex_vis.h" 6 7 /* 8 * Routines to adjust the window, showing specified lines 9 * in certain positions on the screen, and scrolling in both 10 * directions. Code here is very dependent on mode (open versus visual). 11 */ 12 13 /* 14 * Move in a nonlocal way to line addr. 15 * If it isn't on screen put it in specified context. 16 * New position for cursor is curs. 17 * Like most routines here, we vsave(). 18 */ 19 vmoveto(addr, curs, context) 20 register line *addr; 21 char *curs; 22 char context; 23 { 24 25 markit(addr); 26 vsave(); 27 vjumpto(addr, curs, context); 28 } 29 30 /* 31 * Vjumpto is like vmoveto, but doesn't mark previous 32 * context or save linebuf as current line. 33 */ 34 vjumpto(addr, curs, context) 35 register line *addr; 36 char *curs; 37 char context; 38 { 39 40 noteit(0); 41 if (context != 0) 42 vcontext(addr, context); 43 else 44 vshow(addr, NOLINE); 45 noteit(1); 46 vnline(curs); 47 } 48 49 /* 50 * Go up or down cnt (negative is up) to new position curs. 51 */ 52 vupdown(cnt, curs) 53 register int cnt; 54 char *curs; 55 { 56 57 if (cnt > 0) 58 vdown(cnt, 0, 0); 59 else if (cnt < 0) 60 vup(-cnt, 0, 0); 61 if (vcnt == 0) 62 vrepaint(curs); 63 else 64 vnline(curs); 65 } 66 67 /* 68 * Go up cnt lines, afterwards preferring to be ind 69 * logical lines from the top of the screen. 70 * If scroll, then we MUST use a scroll. 71 * Otherwise clear and redraw if motion is far. 72 */ 73 vup(cnt, ind, scroll) 74 register int cnt, ind; 75 bool scroll; 76 { 77 register int i, tot; 78 79 if (dot == one) { 80 beep(); 81 return; 82 } 83 vsave(); 84 i = lineDOT() - 1; 85 if (cnt > i) { 86 ind -= cnt - i; 87 if (ind < 0) 88 ind = 0; 89 cnt = i; 90 } 91 if (!scroll && cnt <= vcline) { 92 vshow(dot - cnt, NOLINE); 93 return; 94 } 95 cnt -= vcline, dot -= vcline, vcline = 0; 96 if (hold & HOLDWIG) 97 goto contxt; 98 if (state == VISUAL && !AL && !SR && 99 cnt <= WTOP - ZERO && vfit(dot - cnt, cnt) <= WTOP - ZERO) 100 goto okr; 101 tot = WECHO - ZERO; 102 if (state != VISUAL || (!AL && !SR) || (!scroll && (cnt > tot || vfit(dot - cnt, cnt) > tot / 3 + 1))) { 103 if (ind > basWLINES / 2) 104 ind = basWLINES / 3; 105 contxt: 106 vcontext(dot + ind - cnt, '.'); 107 return; 108 } 109 okr: 110 vrollR(cnt); 111 if (scroll) { 112 vcline += ind, dot += ind; 113 if (vcline >= vcnt) 114 dot -= vcline - vcnt + 1, vcline = vcnt - 1; 115 getDOT(); 116 } 117 } 118 119 /* 120 * Like vup, but scrolling down. 121 */ 122 vdown(cnt, ind, scroll) 123 register int cnt, ind; 124 bool scroll; 125 { 126 register int i, tot; 127 128 if (dot == dol) { 129 beep(); 130 return; 131 } 132 vsave(); 133 i = dol - dot; 134 if (cnt > i) { 135 ind -= cnt - i; 136 if (ind < 0) 137 ind = 0; 138 cnt = i; 139 } 140 i = vcnt - vcline - 1; 141 if (!scroll && cnt <= i) { 142 vshow(dot + cnt, NOLINE); 143 return; 144 } 145 cnt -= i, dot += i, vcline += i; 146 if (hold & HOLDWIG) 147 goto dcontxt; 148 if (!scroll) { 149 tot = WECHO - ZERO; 150 if (state != VISUAL || cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) { 151 dcontxt: 152 vcontext(dot + cnt, '.'); 153 return; 154 } 155 } 156 if (cnt > 0) 157 vroll(cnt); 158 if (state == VISUAL && scroll) { 159 vcline -= ind, dot -= ind; 160 if (vcline < 0) 161 dot -= vcline, vcline = 0; 162 getDOT(); 163 } 164 } 165 166 /* 167 * Show line addr in context where on the screen. 168 * Work here is in determining new top line implied by 169 * this placement of line addr, since we always draw from the top. 170 */ 171 vcontext(addr, where) 172 register line *addr; 173 char where; 174 { 175 register line *top; 176 177 getline(*addr); 178 if (state != VISUAL) 179 top = addr; 180 else switch (where) { 181 182 case '^': 183 addr = vback(addr, basWLINES - vdepth()); 184 getline(*addr); 185 /* fall into ... */ 186 187 case '-': 188 top = vback(addr, basWLINES - vdepth()); 189 getline(*addr); 190 break; 191 192 case '.': 193 top = vback(addr, basWLINES / 2 - vdepth()); 194 getline(*addr); 195 break; 196 197 default: 198 top = addr; 199 break; 200 } 201 if (state == ONEOPEN && LINE(0) == WBOT) 202 vup1(); 203 vcnt = vcline = 0; 204 vclean(); 205 if (state == CRTOPEN) 206 vup1(); 207 vshow(addr, top); 208 } 209 210 /* 211 * Get a clean line. If we are in a hard open 212 * we may be able to reuse the line we are on 213 * if it is blank. This is a real win. 214 */ 215 vclean() 216 { 217 218 if (state != VISUAL && state != CRTOPEN) { 219 destcol = 0; 220 if (!ateopr()) 221 vup1(); 222 vcnt = 0; 223 } 224 } 225 226 /* 227 * Show line addr with the specified top line on the screen. 228 * Top may be 0; in this case have vcontext compute the top 229 * (and call us recursively). Eventually, we clear the screen 230 * (or its open mode equivalent) and redraw. 231 */ 232 vshow(addr, top) 233 line *addr, *top; 234 { 235 #ifndef CBREAK 236 register bool fried = 0; 237 #endif 238 register int cnt = addr - dot; 239 register int i = vcline + cnt; 240 short oldhold = hold; 241 242 if (state != HARDOPEN && state != ONEOPEN && i >= 0 && i < vcnt) { 243 dot = addr; 244 getDOT(); 245 vcline = i; 246 return; 247 } 248 if (state != VISUAL) { 249 dot = addr; 250 vopen(dot, WBOT); 251 return; 252 } 253 if (top == 0) { 254 vcontext(addr, '.'); 255 return; 256 } 257 dot = top; 258 #ifndef CBREAK 259 if (vcookit(2)) 260 fried++, vcook(); 261 #endif 262 oldhold = hold; 263 hold |= HOLDAT; 264 vclear(); 265 vreset(0); 266 vredraw(WTOP); 267 /* error if vcline >= vcnt ! */ 268 vcline = addr - top; 269 dot = addr; 270 getDOT(); 271 hold = oldhold; 272 vsync(LASTLINE); 273 #ifndef CBREAK 274 if (fried) 275 flusho(), vraw(); 276 #endif 277 } 278 279 /* 280 * reset the state. 281 * If inecho then leave us at the beginning of the echo 282 * area; we are called this way in the middle of a :e escape 283 * from visual, e.g. 284 */ 285 vreset(inecho) 286 bool inecho; 287 { 288 289 vcnt = vcline = 0; 290 WTOP = basWTOP; 291 WLINES = basWLINES; 292 if (inecho) 293 splitw = 1, vgoto(WECHO, 0); 294 } 295 296 /* 297 * Starting from which line preceding tp uses almost (but not more 298 * than) cnt physical lines? 299 */ 300 line * 301 vback(tp, cnt) 302 register int cnt; 303 register line *tp; 304 { 305 register int d; 306 307 if (cnt > 0) 308 for (; tp > one; tp--) { 309 getline(tp[-1]); 310 d = vdepth(); 311 if (d > cnt) 312 break; 313 cnt -= d; 314 } 315 return (tp); 316 } 317 318 /* 319 * How much scrolling will it take to roll cnt lines starting at tp? 320 */ 321 vfit(tp, cnt) 322 register line *tp; 323 int cnt; 324 { 325 register int j; 326 327 j = 0; 328 while (cnt > 0) { 329 cnt--; 330 getline(tp[cnt]); 331 j += vdepth(); 332 } 333 if (tp > dot) 334 j -= WBOT - LASTLINE; 335 return (j); 336 } 337 338 /* 339 * Roll cnt lines onto the screen. 340 */ 341 vroll(cnt) 342 register int cnt; 343 { 344 #ifndef CBREAK 345 register bool fried = 0; 346 #endif 347 short oldhold = hold; 348 349 #ifdef ADEBUG 350 if (trace) 351 tfixnl(), fprintf(trace, "vroll(%d)\n", cnt); 352 #endif 353 if (state != VISUAL) 354 hold |= HOLDAT|HOLDROL; 355 if (WBOT == WECHO) { 356 vcnt = 0; 357 if (state == ONEOPEN) 358 vup1(); 359 } 360 #ifndef CBREAK 361 if (vcookit(cnt)) 362 fried++, vcook(); 363 #endif 364 for (; cnt > 0 && Peekkey != ATTN; cnt--) { 365 dot++, vcline++; 366 vopen(dot, LASTLINE); 367 vscrap(); 368 } 369 hold = oldhold; 370 if (state == HARDOPEN) 371 sethard(); 372 vsyncCL(); 373 #ifndef CBREAK 374 if (fried) 375 flusho(), vraw(); 376 #endif 377 } 378 379 /* 380 * Roll backwards (scroll up). 381 */ 382 vrollR(cnt) 383 register int cnt; 384 { 385 register bool fried = 0; 386 short oldhold = hold; 387 388 #ifdef ADEBUG 389 if (trace) 390 tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT()); 391 #endif 392 #ifndef CBREAK 393 if (vcookit(cnt)) 394 fried++, vcook(); 395 #endif 396 if (WBOT == WECHO) 397 vcnt = 0; 398 heldech = 0; 399 hold |= HOLDAT|HOLDECH; 400 for (; cnt > 0 && Peekkey != ATTN; cnt--) { 401 dot--; 402 vopen(dot, WTOP); 403 vscrap(); 404 } 405 hold = oldhold; 406 if (heldech) 407 vclrech(0); 408 vsync(LINE(vcnt-1)); 409 #ifndef CBREAK 410 if (fried) 411 flusho(), vraw(); 412 #endif 413 } 414 415 /* 416 * Go into cooked mode (allow interrupts) during 417 * a scroll if we are at less than 1200 baud and not 418 * a 'vi' command, of if we are in a 'vi' command and the 419 * scroll is more than 2 full screens. 420 * 421 * BUG: An interrupt during a scroll in this way 422 * dumps to command mode. 423 */ 424 vcookit(cnt) 425 register int cnt; 426 { 427 428 return (cnt > 1 && (ospeed < B1200 && !initev || cnt > LINES * 2)); 429 } 430 431 /* 432 * Determine displayed depth of current line. 433 */ 434 vdepth() 435 { 436 register int d; 437 438 d = (column(NOSTR) + WCOLS - 1 + (Putchar == listchar) + IN) / WCOLS; 439 #ifdef ADEBUG 440 if (trace) 441 tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d); 442 #endif 443 return (d == 0 ? 1 : d); 444 } 445 446 /* 447 * Move onto a new line, with cursor at position curs. 448 */ 449 vnline(curs) 450 char *curs; 451 { 452 453 if (curs) 454 wcursor = curs; 455 else if (vmoving) 456 wcursor = vfindcol(vmovcol); 457 else 458 wcursor = vskipwh(linebuf); 459 cursor = linebuf; 460 vmove(); 461 } 462