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