1 /*
2 * This code contains changes by
3 * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4 *
5 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6 * to these changes.
7 *
8 *
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *
41 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * Redistributions of source code and documentation must retain the
47 * above copyright notice, this list of conditions and the following
48 * disclaimer.
49 * Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed or owned by Caldera
55 * International, Inc.
56 * Neither the name of Caldera International, Inc. nor the names of
57 * other contributors may be used to endorse or promote products
58 * derived from this software without specific prior written permission.
59 *
60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73
74 #ifndef lint
75 #ifdef DOSCCS
76 static char sccsid[] = "@(#)ex_vwind.c 1.9 (gritter) 11/23/04";
77 #endif
78 #endif
79
80 /* from ex_vwind.c 7.3 (Berkeley) 6/7/85 */
81
82 #include "ex.h"
83 #include "ex_tty.h"
84 #include "ex_vis.h"
85
86 /*
87 * Routines to adjust the window, showing specified lines
88 * in certain positions on the screen, and scrolling in both
89 * directions. Code here is very dependent on mode (open versus visual).
90 */
91
92 /*
93 * Move in a nonlocal way to line addr.
94 * If it isn't on screen put it in specified context.
95 * New position for cursor is curs.
96 * Like most routines here, we vsave().
97 */
98 void
vmoveto(register line * addr,char * curs,int context)99 vmoveto(register line *addr, char *curs, int context)
100 {
101
102 markit(addr);
103 vsave();
104 vjumpto(addr, curs, context);
105 }
106
107 /*
108 * Vjumpto is like vmoveto, but doesn't mark previous
109 * context or save linebuf as current line.
110 */
111 void
vjumpto(register line * addr,char * curs,int context)112 vjumpto(register line *addr, char *curs, int context)
113 {
114
115 noteit(0);
116 if (context != 0)
117 vcontext(addr, context);
118 else
119 vshow(addr, NOLINE);
120 noteit(1);
121 vnline(curs);
122 }
123
124 /*
125 * Go up or down cnt (negative is up) to new position curs.
126 */
127 void
vupdown(register int cnt,char * curs)128 vupdown(register int cnt, char *curs)
129 {
130
131 if (cnt > 0)
132 vdown(cnt, 0, 0);
133 else if (cnt < 0)
134 vup(-cnt, 0, 0);
135 if (vcnt == 0)
136 vrepaint(curs);
137 else
138 vnline(curs);
139 }
140
141 /*
142 * Go up cnt lines, afterwards preferring to be ind
143 * logical lines from the top of the screen.
144 * If scroll, then we MUST use a scroll.
145 * Otherwise clear and redraw if motion is far.
146 */
147 void
vup(register int cnt,register int ind,int scroll)148 vup(register int cnt, register int ind, int scroll)
149 {
150 register int i, tot;
151
152 if (dot == one) {
153 beep();
154 return;
155 }
156 vsave();
157 i = lineDOT() - 1;
158 if (cnt > i) {
159 ind -= cnt - i;
160 if (ind < 0)
161 ind = 0;
162 cnt = i;
163 }
164 if (!scroll && cnt <= vcline) {
165 vshow(dot - cnt, NOLINE);
166 return;
167 }
168 cnt -= vcline, dot -= vcline, vcline = 0;
169 if (hold & HOLDWIG)
170 goto contxt;
171 if (state == VISUAL && !AL && !SR &&
172 cnt <= WTOP - ZERO && vfit(dot - cnt, cnt) <= WTOP - ZERO)
173 goto okr;
174 tot = WECHO - ZERO;
175 if (state != VISUAL || (!AL && !SR) || (!scroll && (cnt > tot || vfit(dot - cnt, cnt) > tot / 3 + 1))) {
176 if (ind > basWLINES / 2)
177 ind = basWLINES / 3;
178 contxt:
179 vcontext(dot + ind - cnt, '.');
180 return;
181 }
182 okr:
183 vrollR(cnt);
184 if (scroll) {
185 vcline += ind, dot += ind;
186 if (vcline >= vcnt)
187 dot -= vcline - vcnt + 1, vcline = vcnt - 1;
188 getDOT();
189 }
190 }
191
192 /*
193 * Like vup, but scrolling down.
194 */
195 void
vdown(register int cnt,register int ind,int scroll)196 vdown(register int cnt, register int ind, int scroll)
197 {
198 register int i, tot;
199
200 if (dot == dol) {
201 beep();
202 return;
203 }
204 vsave();
205 i = dol - dot;
206 if (cnt > i) {
207 ind -= cnt - i;
208 if (ind < 0)
209 ind = 0;
210 cnt = i;
211 }
212 i = vcnt - vcline - 1;
213 if (!scroll && cnt <= i) {
214 vshow(dot + cnt, NOLINE);
215 return;
216 }
217 cnt -= i, dot += i, vcline += i;
218 if (hold & HOLDWIG)
219 goto dcontxt;
220 if (!scroll) {
221 tot = WECHO - ZERO;
222 if (state != VISUAL || cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) {
223 dcontxt:
224 vcontext(dot + cnt, '.');
225 return;
226 }
227 }
228 if (cnt > 0)
229 vroll(cnt);
230 if (state == VISUAL && scroll) {
231 vcline -= ind, dot -= ind;
232 if (vcline < 0)
233 dot -= vcline, vcline = 0;
234 getDOT();
235 }
236 }
237
238 /*
239 * Show line addr in context where on the screen.
240 * Work here is in determining new top line implied by
241 * this placement of line addr, since we always draw from the top.
242 */
243 void
vcontext(register line * addr,int where)244 vcontext(register line *addr, int where)
245 {
246 register line *top;
247
248 getline(*addr);
249 if (state != VISUAL)
250 top = addr;
251 else switch (where) {
252
253 case '^':
254 addr = vback(addr, basWLINES - vdepth());
255 getline(*addr);
256 /* fall into ... */
257
258 case '-':
259 top = vback(addr, basWLINES - vdepth());
260 getline(*addr);
261 break;
262
263 case '.':
264 top = vback(addr, basWLINES / 2 - vdepth());
265 getline(*addr);
266 break;
267
268 default:
269 top = addr;
270 break;
271 }
272 if (state == ONEOPEN && LINE(0) == WBOT)
273 vup1();
274 vcnt = vcline = 0;
275 vclean();
276 if (state == CRTOPEN)
277 vup1();
278 vshow(addr, top);
279 }
280
281 /*
282 * Get a clean line. If we are in a hard open
283 * we may be able to reuse the line we are on
284 * if it is blank. This is a real win.
285 */
286 void
vclean(void)287 vclean(void)
288 {
289
290 if (state != VISUAL && state != CRTOPEN) {
291 destcol = 0;
292 if (!ateopr())
293 vup1();
294 vcnt = 0;
295 }
296 }
297
298 /*
299 * Show line addr with the specified top line on the screen.
300 * Top may be 0; in this case have vcontext compute the top
301 * (and call us recursively). Eventually, we clear the screen
302 * (or its open mode equivalent) and redraw.
303 */
304 void
vshow(line * addr,line * top)305 vshow(line *addr, line *top)
306 {
307 register int cnt = addr - dot;
308 register int i = vcline + cnt;
309 short oldhold = hold;
310
311 if (state != HARDOPEN && state != ONEOPEN && i >= 0 && i < vcnt) {
312 dot = addr;
313 getDOT();
314 vcline = i;
315 return;
316 }
317 if (state != VISUAL) {
318 dot = addr;
319 vopen(dot, WBOT);
320 return;
321 }
322 if (top == 0) {
323 vcontext(addr, '.');
324 return;
325 }
326 dot = top;
327 oldhold = hold;
328 hold |= HOLDAT;
329 vclear();
330 vreset(0);
331 vredraw(WTOP);
332 /* error if vcline >= vcnt ! */
333 vcline = addr - top;
334 dot = addr;
335 getDOT();
336 hold = oldhold;
337 vsync(LASTLINE);
338 }
339
340 /*
341 * reset the state.
342 * If inecho then leave us at the beginning of the echo
343 * area; we are called this way in the middle of a :e escape
344 * from visual, e.g.
345 */
346 void
vreset(int inecho)347 vreset(int inecho)
348 {
349
350 vcnt = vcline = 0;
351 WTOP = basWTOP;
352 WLINES = basWLINES;
353 if (inecho)
354 splitw = 1, vgoto(WECHO, 0);
355 }
356
357 /*
358 * Starting from which line preceding tp uses almost (but not more
359 * than) cnt physical lines?
360 */
361 line *
vback(register line * tp,register int cnt)362 vback(register line *tp, register int cnt)
363 {
364 register int d;
365
366 if (cnt > 0)
367 for (; tp > one; tp--) {
368 getline(tp[-1]);
369 d = vdepth();
370 if (d > cnt)
371 break;
372 cnt -= d;
373 }
374 return (tp);
375 }
376
377 /*
378 * How much scrolling will it take to roll cnt lines starting at tp?
379 */
380 int
vfit(register line * tp,int cnt)381 vfit(register line *tp, int cnt)
382 {
383 register int j;
384
385 j = 0;
386 while (cnt > 0) {
387 cnt--;
388 getline(tp[cnt]);
389 j += vdepth();
390 }
391 if (tp > dot)
392 j -= WBOT - LASTLINE;
393 return (j);
394 }
395
396 /*
397 * Roll cnt lines onto the screen.
398 */
399 void
vroll(register int cnt)400 vroll(register int cnt)
401 {
402 short oldhold = hold;
403
404 #ifdef ADEBUG
405 if (trace)
406 tfixnl(), fprintf(trace, "vroll(%d)\n", cnt);
407 #endif
408 if (state != VISUAL)
409 hold |= HOLDAT|HOLDROL;
410 if (WBOT == WECHO) {
411 vcnt = 0;
412 if (state == ONEOPEN)
413 vup1();
414 }
415 for (; cnt > 0 && Peekkey != ATTN; cnt--) {
416 dot++, vcline++;
417 vopen(dot, LASTLINE);
418 vscrap();
419 }
420 hold = oldhold;
421 if (state == HARDOPEN)
422 sethard();
423 vsyncCL();
424 }
425
426 /*
427 * Roll backwards (scroll up).
428 */
429 void
vrollR(register int cnt)430 vrollR(register int cnt)
431 {
432 short oldhold = hold;
433
434 #ifdef ADEBUG
435 if (trace)
436 tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT());
437 #endif
438 if (WBOT == WECHO)
439 vcnt = 0;
440 heldech = 0;
441 hold |= HOLDAT|HOLDECH;
442 for (; cnt > 0 && Peekkey != ATTN; cnt--) {
443 dot--;
444 vopen(dot, WTOP);
445 vscrap();
446 }
447 hold = oldhold;
448 if (heldech)
449 vclrech(0);
450 vsync(LINE(vcnt-1));
451 }
452
453 /*
454 * Go into cooked mode (allow interrupts) during
455 * a scroll if we are at less than 1200 baud and not
456 * a 'vi' command, of if we are in a 'vi' command and the
457 * scroll is more than 2 full screens.
458 *
459 * BUG: An interrupt during a scroll in this way
460 * dumps to command mode.
461 */
462 int
vcookit(register int cnt)463 vcookit(register int cnt)
464 {
465
466 return (cnt > 1 && (ospeed < B1200 && !initev || cnt > TLINES * 2));
467 }
468
469 /*
470 * Determine displayed depth of current line.
471 */
472 int
vdepth(void)473 vdepth(void)
474 {
475 register int d;
476
477 d = (column(NOSTR) + WCOLS - 1 + (Putchar == listchar) + IN) / WCOLS;
478 #ifdef ADEBUG
479 if (trace)
480 tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d);
481 #endif
482 return (d == 0 ? 1 : d);
483 }
484
485 /*
486 * Move onto a new line, with cursor at position curs.
487 */
488 void
vnline(char * curs)489 vnline(char *curs)
490 {
491
492 if (curs)
493 wcursor = curs;
494 else if (vmoving)
495 wcursor = vfindcol(vmovcol);
496 else
497 wcursor = vskipwh(linebuf);
498 cursor = linebuf;
499 vmove(0);
500 }
501