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