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