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