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