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