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