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