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