|
|
1.1 root 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
8: static char *sccsid = "@(#)ex_vwind.c 7.4 (Berkeley) 3/9/87";
9: #endif not lint
10:
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: */
27: vmoveto(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: */
42: vjumpto(addr, curs, context)
43: register line *addr;
44: char *curs;
45: char context;
46: {
47:
48: ignore(noteit(0));
49: if (context != 0)
50: vcontext(addr, context);
51: else
52: vshow(addr, NOLINE);
53: ignore(noteit(1));
54: vnline(curs);
55: }
56:
57: /*
58: * Go up or down cnt (negative is up) to new position curs.
59: */
60: vupdown(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: */
81: vup(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 - ex_ZERO && vfit(dot - cnt, cnt) <= WTOP - ex_ZERO)
108: goto okr;
109: tot = WECHO - ex_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;
113: contxt:
114: vcontext(dot + ind - cnt, '.');
115: return;
116: }
117: okr:
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: */
130: vdown(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 - ex_ZERO;
158: if (state != VISUAL || cnt - tot > 0 || vfit(dot, cnt) > tot / 3 + 1) {
159: dcontxt:
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: */
179: vcontext(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: */
223: vclean()
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: */
240: vshow(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: */
293: vreset(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: */
308: line *
309: vback(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: */
329: vfit(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: */
349: vroll(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 && Peek_key != 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: */
390: vrollR(cnt)
391: register int cnt;
392: {
393: short oldhold = hold;
394:
395: #ifdef ADEBUG
396: if (trace)
397: tfixnl(), fprintf(trace, "vrollR(%d), dot=%d\n", cnt, lineDOT());
398: #endif
399: #ifndef CBREAK
400: if (vcookit(cnt))
401: fried++, vcook();
402: #endif
403: if (WBOT == WECHO)
404: vcnt = 0;
405: heldech = 0;
406: hold |= HOLDAT|HOLDECH;
407: for (; cnt > 0 && Peek_key != ATTN; cnt--) {
408: dot--;
409: vopen(dot, WTOP);
410: vscrap();
411: }
412: hold = oldhold;
413: if (heldech)
414: vclrech(0);
415: vsync(LINE(vcnt-1));
416: #ifndef CBREAK
417: if (fried)
418: flusho(), vraw();
419: #endif
420: }
421:
422: /*
423: * Go into cooked mode (allow interrupts) during
424: * a scroll if we are at less than 1200 baud and not
425: * a 'vi' command, of if we are in a 'vi' command and the
426: * scroll is more than 2 full screens.
427: *
428: * BUG: An interrupt during a scroll in this way
429: * dumps to command mode.
430: */
431: vcookit(cnt)
432: register int cnt;
433: {
434:
435: return (cnt > 1 && (ospeed < B1200 && !initev || cnt > LINES * 2));
436: }
437:
438: /*
439: * Determine displayed depth of current line.
440: */
441: vdepth()
442: {
443: register int d;
444:
445: d = (column(NOSTR) + WCOLS - 1 + (Put_char == listchar) + IN) / WCOLS;
446: #ifdef ADEBUG
447: if (trace)
448: tfixnl(), fprintf(trace, "vdepth returns %d\n", d == 0 ? 1 : d);
449: #endif
450: return (d == 0 ? 1 : d);
451: }
452:
453: /*
454: * Move onto a new line, with cursor at position curs.
455: */
456: vnline(curs)
457: char *curs;
458: {
459:
460: if (curs)
461: wcursor = curs;
462: else if (vmoving)
463: wcursor = vfindcol(vmovcol);
464: else
465: wcursor = vskipwh(linebuf);
466: cursor = linebuf;
467: vmove();
468: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.