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