xref: /dragonfly/contrib/libedit/src/refresh.c (revision 37de577a)
1 /*	$NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $	*/
2 
3 /*-
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93";
39 #else
40 __RCSID("$NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 
44 /*
45  * refresh.c: Lower level screen refreshing functions
46  */
47 #include <stdio.h>
48 #include <string.h>
49 #include <unistd.h>
50 
51 #include "el.h"
52 
53 static void	re_nextline(EditLine *);
54 static void	re_addc(EditLine *, wint_t);
55 static void	re_update_line(EditLine *, wchar_t *, wchar_t *, int);
56 static void	re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int);
57 static void	re_delete(EditLine *, wchar_t *, int, int, int);
58 static void	re_fastputc(EditLine *, wint_t);
59 static void	re_clear_eol(EditLine *, int, int, int);
60 static void	re__strncopy(wchar_t *, wchar_t *, size_t);
61 static void	re__copy_and_pad(wchar_t *, const wchar_t *, size_t);
62 
63 #ifdef DEBUG_REFRESH
64 static void	re_printstr(EditLine *, const char *, wchar_t *, wchar_t *);
65 #define	__F el->el_errfile
66 #define	ELRE_ASSERT(a, b, c)	do				\
67 				    if (/*CONSTCOND*/ a) {	\
68 					(void) fprintf b;	\
69 					c;			\
70 				    }				\
71 				while (/*CONSTCOND*/0)
72 #define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
73 
74 /* re_printstr():
75  *	Print a string on the debugging pty
76  */
77 static void
78 re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t)
79 {
80 
81 	ELRE_DEBUG(1, (__F, "%s:\"", str));
82 	while (f < t)
83 		ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
84 	ELRE_DEBUG(1, (__F, "\"\r\n"));
85 }
86 #else
87 #define	ELRE_ASSERT(a, b, c)
88 #define	ELRE_DEBUG(a, b)
89 #endif
90 
91 /* re_nextline():
92  *	Move to the next line or scroll
93  */
94 static void
95 re_nextline(EditLine *el)
96 {
97 	el->el_refresh.r_cursor.h = 0;	/* reset it. */
98 
99 	/*
100 	 * If we would overflow (input is longer than terminal size),
101 	 * emulate scroll by dropping first line and shuffling the rest.
102 	 * We do this via pointer shuffling - it's safe in this case
103 	 * and we avoid memcpy().
104 	 */
105 	if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) {
106 		int i, lins = el->el_terminal.t_size.v;
107 		wchar_t *firstline = el->el_vdisplay[0];
108 
109 		for(i = 1; i < lins; i++)
110 			el->el_vdisplay[i - 1] = el->el_vdisplay[i];
111 
112 		firstline[0] = '\0';		/* empty the string */
113 		el->el_vdisplay[i - 1] = firstline;
114 	} else
115 		el->el_refresh.r_cursor.v++;
116 
117 	ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v,
118 	    (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
119 	    el->el_refresh.r_cursor.v, el->el_terminal.t_size.v),
120 	    abort());
121 }
122 
123 /* re_addc():
124  *	Draw c, expanding tabs, control chars etc.
125  */
126 static void
127 re_addc(EditLine *el, wint_t c)
128 {
129 	switch (ct_chr_class(c)) {
130 	case CHTYPE_TAB:        /* expand the tab */
131 		for (;;) {
132 			re_putc(el, ' ', 1);
133 			if ((el->el_refresh.r_cursor.h & 07) == 0)
134 				break;			/* go until tab stop */
135 		}
136 		break;
137 	case CHTYPE_NL: {
138 		int oldv = el->el_refresh.r_cursor.v;
139 		re_putc(el, '\0', 0);			/* assure end of line */
140 		if (oldv == el->el_refresh.r_cursor.v)	/* XXX */
141 			re_nextline(el);
142 		break;
143 	}
144 	case CHTYPE_PRINT:
145 		re_putc(el, c, 1);
146 		break;
147 	default: {
148 		wchar_t visbuf[VISUAL_WIDTH_MAX];
149 		ssize_t i, n =
150 		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
151 		for (i = 0; n-- > 0; ++i)
152 		    re_putc(el, visbuf[i], 1);
153 		break;
154 	}
155 	}
156 }
157 
158 /* re_putliteral():
159  *	Place the literal string given
160  */
161 libedit_private void
162 re_putliteral(EditLine *el, const wchar_t *begin, const wchar_t *end)
163 {
164 	coord_t *cur = &el->el_refresh.r_cursor;
165 	wint_t c;
166 	int sizeh = el->el_terminal.t_size.h;
167 	int i, w;
168 
169 	c = literal_add(el, begin, end, &w);
170 	if (c == 0 || w <= 0)
171 		return;
172 	el->el_vdisplay[cur->v][cur->h] = c;
173 
174 	i = w;
175 	if (i > sizeh - cur->h)		/* avoid overflow */
176 		i = sizeh - cur->h;
177 	while (--i > 0)
178 		el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
179 
180 	cur->h += w;
181 	if (cur->h >= sizeh) {
182 		/* assure end of line */
183 		el->el_vdisplay[cur->v][sizeh] = '\0';
184 		re_nextline(el);
185 	}
186 }
187 
188 /* re_putc():
189  *	Draw the character given
190  */
191 libedit_private void
192 re_putc(EditLine *el, wint_t c, int shift)
193 {
194 	coord_t *cur = &el->el_refresh.r_cursor;
195 	int i, w = wcwidth(c);
196 	int sizeh = el->el_terminal.t_size.h;
197 
198 	ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c));
199 	if (w == -1)
200 		w = 0;
201 
202 	while (shift && (cur->h + w > sizeh))
203 	    re_putc(el, ' ', 1);
204 
205 	el->el_vdisplay[cur->v][cur->h] = c;
206 	/* assumes !shift is only used for single-column chars */
207 	i = w;
208 	while (--i > 0)
209 		el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR;
210 
211 	if (!shift)
212 		return;
213 
214 	cur->h += w;	/* advance to next place */
215 	if (cur->h >= sizeh) {
216 		/* assure end of line */
217 		el->el_vdisplay[cur->v][sizeh] = '\0';
218 		re_nextline(el);
219 	}
220 }
221 
222 
223 /* re_refresh():
224  *	draws the new virtual screen image from the current input
225  *	line, then goes line-by-line changing the real image to the new
226  *	virtual image. The routine to re-draw a line can be replaced
227  *	easily in hopes of a smarter one being placed there.
228  */
229 libedit_private void
230 re_refresh(EditLine *el)
231 {
232 	int i, rhdiff;
233 	wchar_t *cp, *st;
234 	coord_t cur;
235 #ifdef notyet
236 	size_t termsz;
237 #endif
238 
239 	ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n",
240 	    el->el_line.buffer));
241 
242 	literal_clear(el);
243 	/* reset the Drawing cursor */
244 	el->el_refresh.r_cursor.h = 0;
245 	el->el_refresh.r_cursor.v = 0;
246 
247 	terminal_move_to_char(el, 0);
248 
249 	/* temporarily draw rprompt to calculate its size */
250 	prompt_print(el, EL_RPROMPT);
251 
252 	/* reset the Drawing cursor */
253 	el->el_refresh.r_cursor.h = 0;
254 	el->el_refresh.r_cursor.v = 0;
255 
256 	if (el->el_line.cursor >= el->el_line.lastchar) {
257 		if (el->el_map.current == el->el_map.alt
258 		    && el->el_line.lastchar != el->el_line.buffer)
259 			el->el_line.cursor = el->el_line.lastchar - 1;
260 		else
261 			el->el_line.cursor = el->el_line.lastchar;
262 	}
263 
264 	cur.h = -1;		/* set flag in case I'm not set */
265 	cur.v = 0;
266 
267 	prompt_print(el, EL_PROMPT);
268 
269 	/* draw the current input buffer */
270 #if notyet
271 	termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v;
272 	if (el->el_line.lastchar - el->el_line.buffer > termsz) {
273 		/*
274 		 * If line is longer than terminal, process only part
275 		 * of line which would influence display.
276 		 */
277 		size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
278 
279 		st = el->el_line.lastchar - rem
280 			- (termsz - (((rem / el->el_terminal.t_size.v) - 1)
281 					* el->el_terminal.t_size.v));
282 	} else
283 #endif
284 		st = el->el_line.buffer;
285 
286 	for (cp = st; cp < el->el_line.lastchar; cp++) {
287 		if (cp == el->el_line.cursor) {
288                         int w = wcwidth(*cp);
289 			/* save for later */
290 			cur.h = el->el_refresh.r_cursor.h;
291 			cur.v = el->el_refresh.r_cursor.v;
292                         /* handle being at a linebroken doublewidth char */
293                         if (w > 1 && el->el_refresh.r_cursor.h + w >
294 			    el->el_terminal.t_size.h) {
295 				cur.h = 0;
296 				cur.v++;
297                         }
298 		}
299 		re_addc(el, *cp);
300 	}
301 
302 	if (cur.h == -1) {	/* if I haven't been set yet, I'm at the end */
303 		cur.h = el->el_refresh.r_cursor.h;
304 		cur.v = el->el_refresh.r_cursor.v;
305 	}
306 	rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h -
307 	    el->el_rprompt.p_pos.h;
308 	if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
309 	    !el->el_refresh.r_cursor.v && rhdiff > 1) {
310 		/*
311 		 * have a right-hand side prompt that will fit
312 		 * on the end of the first line with at least
313 		 * one character gap to the input buffer.
314 		 */
315 		while (--rhdiff > 0)	/* pad out with spaces */
316 			re_putc(el, ' ', 1);
317 		prompt_print(el, EL_RPROMPT);
318 	} else {
319 		el->el_rprompt.p_pos.h = 0;	/* flag "not using rprompt" */
320 		el->el_rprompt.p_pos.v = 0;
321 	}
322 
323 	re_putc(el, '\0', 0);	/* make line ended with NUL, no cursor shift */
324 
325 	el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
326 
327 	ELRE_DEBUG(1, (__F,
328 		"term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
329 		el->el_terminal.t_size.h, el->el_refresh.r_cursor.h,
330 		el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0],
331 		&el->el_scratch)));
332 
333 	ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
334 	for (i = 0; i <= el->el_refresh.r_newcv; i++) {
335 		/* NOTE THAT re_update_line MAY CHANGE el_display[i] */
336 		re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
337 
338 		/*
339 		 * Copy the new line to be the current one, and pad out with
340 		 * spaces to the full width of the terminal so that if we try
341 		 * moving the cursor by writing the character that is at the
342 		 * end of the screen line, it won't be a NUL or some old
343 		 * leftover stuff.
344 		 */
345 		re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
346 		    (size_t) el->el_terminal.t_size.h);
347 	}
348 	ELRE_DEBUG(1, (__F,
349 	"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
350 	    el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
351 
352 	if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
353 		for (; i <= el->el_refresh.r_oldcv; i++) {
354 			terminal_move_to_line(el, i);
355 			terminal_move_to_char(el, 0);
356                         /* This wcslen should be safe even with MB_FILL_CHARs */
357 			terminal_clear_EOL(el, (int) wcslen(el->el_display[i]));
358 #ifdef DEBUG_REFRESH
359 			terminal_overwrite(el, L"C\b", 2);
360 #endif /* DEBUG_REFRESH */
361 			el->el_display[i][0] = '\0';
362 		}
363 
364 	el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
365 	ELRE_DEBUG(1, (__F,
366 	    "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
367 	    el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
368 	    cur.h, cur.v));
369 	terminal_move_to_line(el, cur.v);	/* go to where the cursor is */
370 	terminal_move_to_char(el, cur.h);
371 }
372 
373 
374 /* re_goto_bottom():
375  *	 used to go to last used screen line
376  */
377 libedit_private void
378 re_goto_bottom(EditLine *el)
379 {
380 
381 	terminal_move_to_line(el, el->el_refresh.r_oldcv);
382 	terminal__putc(el, '\n');
383 	re_clear_display(el);
384 	terminal__flush(el);
385 }
386 
387 
388 /* re_insert():
389  *	insert num characters of s into d (in front of the character)
390  *	at dat, maximum length of d is dlen
391  */
392 static void
393 /*ARGSUSED*/
394 re_insert(EditLine *el __attribute__((__unused__)),
395     wchar_t *d, int dat, int dlen, wchar_t *s, int num)
396 {
397 	wchar_t *a, *b;
398 
399 	if (num <= 0)
400 		return;
401 	if (num > dlen - dat)
402 		num = dlen - dat;
403 
404 	ELRE_DEBUG(1,
405 	    (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
406 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
407 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
408 	    &el->el_scratch)));
409 
410 	/* open up the space for num chars */
411 	if (num > 0) {
412 		b = d + dlen - 1;
413 		a = b - num;
414 		while (a >= &d[dat])
415 			*b-- = *a--;
416 		d[dlen] = '\0';	/* just in case */
417 	}
418 
419 	ELRE_DEBUG(1, (__F,
420 		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
421 		num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
422 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s,
423 		&el->el_scratch)));
424 
425 	/* copy the characters */
426 	for (a = d + dat; (a < d + dlen) && (num > 0); num--)
427 		*a++ = *s++;
428 
429 #ifdef notyet
430         /* ct_encode_string() uses a static buffer, so we can't conveniently
431          * encode both d & s here */
432 	ELRE_DEBUG(1,
433 	    (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
434 	    num, dat, dlen, d, s));
435 	ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s));
436 #endif
437 }
438 
439 
440 /* re_delete():
441  *	delete num characters d at dat, maximum length of d is dlen
442  */
443 static void
444 /*ARGSUSED*/
445 re_delete(EditLine *el __attribute__((__unused__)),
446     wchar_t *d, int dat, int dlen, int num)
447 {
448 	wchar_t *a, *b;
449 
450 	if (num <= 0)
451 		return;
452 	if (dat + num >= dlen) {
453 		d[dat] = '\0';
454 		return;
455 	}
456 	ELRE_DEBUG(1,
457 	    (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
458 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
459 
460 	/* open up the space for num chars */
461 	if (num > 0) {
462 		b = d + dat;
463 		a = b + num;
464 		while (a < &d[dlen])
465 			*b++ = *a++;
466 		d[dlen] = '\0';	/* just in case */
467 	}
468 	ELRE_DEBUG(1,
469 	    (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
470 	    num, dat, dlen, ct_encode_string(d, &el->el_scratch)));
471 }
472 
473 
474 /* re__strncopy():
475  *	Like strncpy without padding.
476  */
477 static void
478 re__strncopy(wchar_t *a, wchar_t *b, size_t n)
479 {
480 
481 	while (n-- && *b)
482 		*a++ = *b++;
483 }
484 
485 /* re_clear_eol():
486  *	Find the number of characters we need to clear till the end of line
487  *	in order to make sure that we have cleared the previous contents of
488  *	the line. fx and sx is the number of characters inserted or deleted
489  *	in the first or second diff, diff is the difference between the
490  *	number of characters between the new and old line.
491  */
492 static void
493 re_clear_eol(EditLine *el, int fx, int sx, int diff)
494 {
495 
496 	ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n",
497 	    sx, fx, diff));
498 
499 	if (fx < 0)
500 		fx = -fx;
501 	if (sx < 0)
502 		sx = -sx;
503 	if (fx > diff)
504 		diff = fx;
505 	if (sx > diff)
506 		diff = sx;
507 
508 	ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff));
509 	terminal_clear_EOL(el, diff);
510 }
511 
512 /*****************************************************************
513     re_update_line() is based on finding the middle difference of each line
514     on the screen; vis:
515 
516 			     /old first difference
517 	/beginning of line   |              /old last same       /old EOL
518 	v		     v              v                    v
519 old:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
520 new:	eddie> Oh, my little buggy says to me, as lurgid as
521 	^		     ^        ^			   ^
522 	\beginning of line   |        \new last same	   \new end of line
523 			     \new first difference
524 
525     all are character pointers for the sake of speed.  Special cases for
526     no differences, as well as for end of line additions must be handled.
527 **************************************************************** */
528 
529 /* Minimum at which doing an insert it "worth it".  This should be about
530  * half the "cost" of going into insert mode, inserting a character, and
531  * going back out.  This should really be calculated from the termcap
532  * data...  For the moment, a good number for ANSI terminals.
533  */
534 #define	MIN_END_KEEP	4
535 
536 static void
537 re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i)
538 {
539 	wchar_t *o, *n, *p, c;
540 	wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne;
541 	wchar_t *osb, *ose, *nsb, *nse;
542 	int fx, sx;
543 	size_t len;
544 
545 	/*
546          * find first diff
547          */
548 	for (o = old, n = new; *o && (*o == *n); o++, n++)
549 		continue;
550 	ofd = o;
551 	nfd = n;
552 
553 	/*
554          * Find the end of both old and new
555          */
556 	while (*o)
557 		o++;
558 	/*
559          * Remove any trailing blanks off of the end, being careful not to
560          * back up past the beginning.
561          */
562 	while (ofd < o) {
563 		if (o[-1] != ' ')
564 			break;
565 		o--;
566 	}
567 	oe = o;
568 	*oe = '\0';
569 
570 	while (*n)
571 		n++;
572 
573 	/* remove blanks from end of new */
574 	while (nfd < n) {
575 		if (n[-1] != ' ')
576 			break;
577 		n--;
578 	}
579 	ne = n;
580 	*ne = '\0';
581 
582 	/*
583          * if no diff, continue to next line of redraw
584          */
585 	if (*ofd == '\0' && *nfd == '\0') {
586 		ELRE_DEBUG(1, (__F, "no difference.\r\n"));
587 		return;
588 	}
589 	/*
590          * find last same pointer
591          */
592 	while ((o > ofd) && (n > nfd) && (*--o == *--n))
593 		continue;
594 	ols = ++o;
595 	nls = ++n;
596 
597 	/*
598          * find same beginning and same end
599          */
600 	osb = ols;
601 	nsb = nls;
602 	ose = ols;
603 	nse = nls;
604 
605 	/*
606          * case 1: insert: scan from nfd to nls looking for *ofd
607          */
608 	if (*ofd) {
609 		for (c = *ofd, n = nfd; n < nls; n++) {
610 			if (c == *n) {
611 				for (o = ofd, p = n;
612 				    p < nls && o < ols && *o == *p;
613 				    o++, p++)
614 					continue;
615 				/*
616 				 * if the new match is longer and it's worth
617 				 * keeping, then we take it
618 				 */
619 				if (((nse - nsb) < (p - n)) &&
620 				    (2 * (p - n) > n - nfd)) {
621 					nsb = n;
622 					nse = p;
623 					osb = ofd;
624 					ose = o;
625 				}
626 			}
627 		}
628 	}
629 	/*
630          * case 2: delete: scan from ofd to ols looking for *nfd
631          */
632 	if (*nfd) {
633 		for (c = *nfd, o = ofd; o < ols; o++) {
634 			if (c == *o) {
635 				for (n = nfd, p = o;
636 				    p < ols && n < nls && *p == *n;
637 				    p++, n++)
638 					continue;
639 				/*
640 				 * if the new match is longer and it's worth
641 				 * keeping, then we take it
642 				 */
643 				if (((ose - osb) < (p - o)) &&
644 				    (2 * (p - o) > o - ofd)) {
645 					nsb = nfd;
646 					nse = n;
647 					osb = o;
648 					ose = p;
649 				}
650 			}
651 		}
652 	}
653 	/*
654          * Pragmatics I: If old trailing whitespace or not enough characters to
655          * save to be worth it, then don't save the last same info.
656          */
657 	if ((oe - ols) < MIN_END_KEEP) {
658 		ols = oe;
659 		nls = ne;
660 	}
661 	/*
662          * Pragmatics II: if the terminal isn't smart enough, make the data
663          * dumber so the smart update doesn't try anything fancy
664          */
665 
666 	/*
667          * fx is the number of characters we need to insert/delete: in the
668          * beginning to bring the two same begins together
669          */
670 	fx = (int)((nsb - nfd) - (osb - ofd));
671 	/*
672          * sx is the number of characters we need to insert/delete: in the
673          * end to bring the two same last parts together
674          */
675 	sx = (int)((nls - nse) - (ols - ose));
676 
677 	if (!EL_CAN_INSERT) {
678 		if (fx > 0) {
679 			osb = ols;
680 			ose = ols;
681 			nsb = nls;
682 			nse = nls;
683 		}
684 		if (sx > 0) {
685 			ols = oe;
686 			nls = ne;
687 		}
688 		if ((ols - ofd) < (nls - nfd)) {
689 			ols = oe;
690 			nls = ne;
691 		}
692 	}
693 	if (!EL_CAN_DELETE) {
694 		if (fx < 0) {
695 			osb = ols;
696 			ose = ols;
697 			nsb = nls;
698 			nse = nls;
699 		}
700 		if (sx < 0) {
701 			ols = oe;
702 			nls = ne;
703 		}
704 		if ((ols - ofd) > (nls - nfd)) {
705 			ols = oe;
706 			nls = ne;
707 		}
708 	}
709 	/*
710          * Pragmatics III: make sure the middle shifted pointers are correct if
711          * they don't point to anything (we may have moved ols or nls).
712          */
713 	/* if the change isn't worth it, don't bother */
714 	/* was: if (osb == ose) */
715 	if ((ose - osb) < MIN_END_KEEP) {
716 		osb = ols;
717 		ose = ols;
718 		nsb = nls;
719 		nse = nls;
720 	}
721 	/*
722          * Now that we are done with pragmatics we recompute fx, sx
723          */
724 	fx = (int)((nsb - nfd) - (osb - ofd));
725 	sx = (int)((nls - nse) - (ols - ose));
726 
727 	ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx));
728 	ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n",
729 		ofd - old, osb - old, ose - old, ols - old, oe - old));
730 	ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n",
731 		nfd - new, nsb - new, nse - new, nls - new, ne - new));
732 	ELRE_DEBUG(1, (__F,
733 		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
734 	ELRE_DEBUG(1, (__F,
735 		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
736 #ifdef DEBUG_REFRESH
737 	re_printstr(el, "old- oe", old, oe);
738 	re_printstr(el, "new- ne", new, ne);
739 	re_printstr(el, "old-ofd", old, ofd);
740 	re_printstr(el, "new-nfd", new, nfd);
741 	re_printstr(el, "ofd-osb", ofd, osb);
742 	re_printstr(el, "nfd-nsb", nfd, nsb);
743 	re_printstr(el, "osb-ose", osb, ose);
744 	re_printstr(el, "nsb-nse", nsb, nse);
745 	re_printstr(el, "ose-ols", ose, ols);
746 	re_printstr(el, "nse-nls", nse, nls);
747 	re_printstr(el, "ols- oe", ols, oe);
748 	re_printstr(el, "nls- ne", nls, ne);
749 #endif /* DEBUG_REFRESH */
750 
751 	/*
752          * el_cursor.v to this line i MUST be in this routine so that if we
753          * don't have to change the line, we don't move to it. el_cursor.h to
754          * first diff char
755          */
756 	terminal_move_to_line(el, i);
757 
758 	/*
759          * at this point we have something like this:
760          *
761          * /old                  /ofd    /osb               /ose    /ols     /oe
762          * v.....................v       v..................v       v........v
763          * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
764          * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
765          * ^.....................^     ^..................^       ^........^
766          * \new                  \nfd  \nsb               \nse     \nls    \ne
767          *
768          * fx is the difference in length between the chars between nfd and
769          * nsb, and the chars between ofd and osb, and is thus the number of
770          * characters to delete if < 0 (new is shorter than old, as above),
771          * or insert (new is longer than short).
772          *
773          * sx is the same for the second differences.
774          */
775 
776 	/*
777          * if we have a net insert on the first difference, AND inserting the
778          * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
779          * character (which is ne if nls != ne, otherwise is nse) off the edge
780 	 * of the screen (el->el_terminal.t_size.h) else we do the deletes first
781 	 * so that we keep everything we need to.
782          */
783 
784 	/*
785          * if the last same is the same like the end, there is no last same
786          * part, otherwise we want to keep the last same part set p to the
787          * last useful old character
788          */
789 	p = (ols != oe) ? oe : ose;
790 
791 	/*
792          * if (There is a diffence in the beginning) && (we need to insert
793          *   characters) && (the number of characters to insert is less than
794          *   the term width)
795 	 *	We need to do an insert!
796 	 * else if (we need to delete characters)
797 	 *	We need to delete characters!
798 	 * else
799 	 *	No insert or delete
800          */
801 	if ((nsb != nfd) && fx > 0 &&
802 	    ((p - old) + fx <= el->el_terminal.t_size.h)) {
803 		ELRE_DEBUG(1,
804 		    (__F, "first diff insert at %td...\r\n", nfd - new));
805 		/*
806 		 * Move to the first char to insert, where the first diff is.
807 		 */
808 		terminal_move_to_char(el, (int)(nfd - new));
809 		/*
810 		 * Check if we have stuff to keep at end
811 		 */
812 		if (nsb != ne) {
813 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
814 			/*
815 		         * insert fx chars of new starting at nfd
816 		         */
817 			if (fx > 0) {
818 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
819 				"ERROR: cannot insert in early first diff\n"));
820 				terminal_insertwrite(el, nfd, fx);
821 				re_insert(el, old, (int)(ofd - old),
822 				    el->el_terminal.t_size.h, nfd, fx);
823 			}
824 			/*
825 		         * write (nsb-nfd) - fx chars of new starting at
826 		         * (nfd + fx)
827 			 */
828 			len = (size_t) ((nsb - nfd) - fx);
829 			terminal_overwrite(el, (nfd + fx), len);
830 			re__strncopy(ofd + fx, nfd + fx, len);
831 		} else {
832 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
833 			len = (size_t)(nsb - nfd);
834 			terminal_overwrite(el, nfd, len);
835 			re__strncopy(ofd, nfd, len);
836 			/*
837 		         * Done
838 		         */
839 			return;
840 		}
841 	} else if (fx < 0) {
842 		ELRE_DEBUG(1,
843 		    (__F, "first diff delete at %td...\r\n", ofd - old));
844 		/*
845 		 * move to the first char to delete where the first diff is
846 		 */
847 		terminal_move_to_char(el, (int)(ofd - old));
848 		/*
849 		 * Check if we have stuff to save
850 		 */
851 		if (osb != oe) {
852 			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
853 			/*
854 		         * fx is less than zero *always* here but we check
855 		         * for code symmetry
856 		         */
857 			if (fx < 0) {
858 				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
859 				    "ERROR: cannot delete in first diff\n"));
860 				terminal_deletechars(el, -fx);
861 				re_delete(el, old, (int)(ofd - old),
862 				    el->el_terminal.t_size.h, -fx);
863 			}
864 			/*
865 		         * write (nsb-nfd) chars of new starting at nfd
866 		         */
867 			len = (size_t) (nsb - nfd);
868 			terminal_overwrite(el, nfd, len);
869 			re__strncopy(ofd, nfd, len);
870 
871 		} else {
872 			ELRE_DEBUG(1, (__F,
873 			    "but with nothing left to save\r\n"));
874 			/*
875 		         * write (nsb-nfd) chars of new starting at nfd
876 		         */
877 			terminal_overwrite(el, nfd, (size_t)(nsb - nfd));
878 			re_clear_eol(el, fx, sx,
879 			    (int)((oe - old) - (ne - new)));
880 			/*
881 		         * Done
882 		         */
883 			return;
884 		}
885 	} else
886 		fx = 0;
887 
888 	if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) {
889 		ELRE_DEBUG(1, (__F,
890 		    "second diff delete at %td...\r\n", (ose - old) + fx));
891 		/*
892 		 * Check if we have stuff to delete
893 		 */
894 		/*
895 		 * fx is the number of characters inserted (+) or deleted (-)
896 		 */
897 
898 		terminal_move_to_char(el, (int)((ose - old) + fx));
899 		/*
900 		 * Check if we have stuff to save
901 		 */
902 		if (ols != oe) {
903 			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
904 			/*
905 		         * Again a duplicate test.
906 		         */
907 			if (sx < 0) {
908 				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
909 				    "ERROR: cannot delete in second diff\n"));
910 				terminal_deletechars(el, -sx);
911 			}
912 			/*
913 		         * write (nls-nse) chars of new starting at nse
914 		         */
915 			terminal_overwrite(el, nse, (size_t)(nls - nse));
916 		} else {
917 			ELRE_DEBUG(1, (__F,
918 			    "but with nothing left to save\r\n"));
919 			terminal_overwrite(el, nse, (size_t)(nls - nse));
920 			re_clear_eol(el, fx, sx,
921 			    (int)((oe - old) - (ne - new)));
922 		}
923 	}
924 	/*
925          * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
926          */
927 	if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
928 		ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n",
929 		    nfd - new));
930 
931 		terminal_move_to_char(el, (int)(nfd - new));
932 		/*
933 		 * Check if we have stuff to keep at the end
934 		 */
935 		if (nsb != ne) {
936 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
937 			/*
938 		         * We have to recalculate fx here because we set it
939 		         * to zero above as a flag saying that we hadn't done
940 		         * an early first insert.
941 		         */
942 			fx = (int)((nsb - nfd) - (osb - ofd));
943 			if (fx > 0) {
944 				/*
945 				 * insert fx chars of new starting at nfd
946 				 */
947 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
948 				 "ERROR: cannot insert in late first diff\n"));
949 				terminal_insertwrite(el, nfd, fx);
950 				re_insert(el, old, (int)(ofd - old),
951 				    el->el_terminal.t_size.h, nfd, fx);
952 			}
953 			/*
954 		         * write (nsb-nfd) - fx chars of new starting at
955 		         * (nfd + fx)
956 			 */
957 			len = (size_t) ((nsb - nfd) - fx);
958 			terminal_overwrite(el, (nfd + fx), len);
959 			re__strncopy(ofd + fx, nfd + fx, len);
960 		} else {
961 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
962 			len = (size_t) (nsb - nfd);
963 			terminal_overwrite(el, nfd, len);
964 			re__strncopy(ofd, nfd, len);
965 		}
966 	}
967 	/*
968          * line is now NEW up to nse
969          */
970 	if (sx >= 0) {
971 		ELRE_DEBUG(1, (__F,
972 		    "second diff insert at %d...\r\n", (int)(nse - new)));
973 		terminal_move_to_char(el, (int)(nse - new));
974 		if (ols != oe) {
975 			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
976 			if (sx > 0) {
977 				/* insert sx chars of new starting at nse */
978 				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
979 				    "ERROR: cannot insert in second diff\n"));
980 				terminal_insertwrite(el, nse, sx);
981 			}
982 			/*
983 		         * write (nls-nse) - sx chars of new starting at
984 			 * (nse + sx)
985 		         */
986 			terminal_overwrite(el, (nse + sx),
987 			    (size_t)((nls - nse) - sx));
988 		} else {
989 			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
990 			terminal_overwrite(el, nse, (size_t)(nls - nse));
991 
992 			/*
993 	                 * No need to do a clear-to-end here because we were
994 	                 * doing a second insert, so we will have over
995 	                 * written all of the old string.
996 		         */
997 		}
998 	}
999 	ELRE_DEBUG(1, (__F, "done.\r\n"));
1000 }
1001 
1002 
1003 /* re__copy_and_pad():
1004  *	Copy string and pad with spaces
1005  */
1006 static void
1007 re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width)
1008 {
1009 	size_t i;
1010 
1011 	for (i = 0; i < width; i++) {
1012 		if (*src == '\0')
1013 			break;
1014 		*dst++ = *src++;
1015 	}
1016 
1017 	for (; i < width; i++)
1018 		*dst++ = ' ';
1019 
1020 	*dst = '\0';
1021 }
1022 
1023 
1024 /* re_refresh_cursor():
1025  *	Move to the new cursor position
1026  */
1027 libedit_private void
1028 re_refresh_cursor(EditLine *el)
1029 {
1030 	wchar_t *cp;
1031 	int h, v, th, w;
1032 
1033 	if (el->el_line.cursor >= el->el_line.lastchar) {
1034 		if (el->el_map.current == el->el_map.alt
1035 		    && el->el_line.lastchar != el->el_line.buffer)
1036 			el->el_line.cursor = el->el_line.lastchar - 1;
1037 		else
1038 			el->el_line.cursor = el->el_line.lastchar;
1039 	}
1040 
1041 	/* first we must find where the cursor is... */
1042 	h = el->el_prompt.p_pos.h;
1043 	v = el->el_prompt.p_pos.v;
1044 	th = el->el_terminal.t_size.h;	/* optimize for speed */
1045 
1046 	/* do input buffer to el->el_line.cursor */
1047 	for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
1048                 switch (ct_chr_class(*cp)) {
1049 		case CHTYPE_NL:  /* handle newline in data part too */
1050 			h = 0;
1051 			v++;
1052 			break;
1053 		case CHTYPE_TAB: /* if a tab, to next tab stop */
1054 			while (++h & 07)
1055 				continue;
1056 			break;
1057 		default:
1058 			w = wcwidth(*cp);
1059 			if (w > 1 && h + w > th) { /* won't fit on line */
1060 				h = 0;
1061 				v++;
1062 			}
1063 			h += ct_visual_width(*cp);
1064 			break;
1065                 }
1066 
1067 		if (h >= th) {	/* check, extra long tabs picked up here also */
1068 			h -= th;
1069 			v++;
1070 		}
1071 	}
1072         /* if we have a next character, and it's a doublewidth one, we need to
1073          * check whether we need to linebreak for it to fit */
1074         if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1)
1075                 if (h + w > th) {
1076                     h = 0;
1077                     v++;
1078                 }
1079 
1080 	/* now go there */
1081 	terminal_move_to_line(el, v);
1082 	terminal_move_to_char(el, h);
1083 	terminal__flush(el);
1084 }
1085 
1086 
1087 /* re_fastputc():
1088  *	Add a character fast.
1089  */
1090 static void
1091 re_fastputc(EditLine *el, wint_t c)
1092 {
1093 	wchar_t *lastline;
1094 	int w;
1095 
1096 	w = wcwidth(c);
1097 	while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h)
1098 	    re_fastputc(el, ' ');
1099 
1100 	terminal__putc(el, c);
1101 	el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
1102 	while (--w > 0)
1103 		el->el_display[el->el_cursor.v][el->el_cursor.h++]
1104 			= MB_FILL_CHAR;
1105 
1106 	if (el->el_cursor.h >= el->el_terminal.t_size.h) {
1107 		/* if we must overflow */
1108 		el->el_cursor.h = 0;
1109 
1110 		/*
1111 		 * If we would overflow (input is longer than terminal size),
1112 		 * emulate scroll by dropping first line and shuffling the rest.
1113 		 * We do this via pointer shuffling - it's safe in this case
1114 		 * and we avoid memcpy().
1115 		 */
1116 		if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) {
1117 			int i, lins = el->el_terminal.t_size.v;
1118 
1119 			lastline = el->el_display[0];
1120 			for(i = 1; i < lins; i++)
1121 				el->el_display[i - 1] = el->el_display[i];
1122 
1123 			el->el_display[i - 1] = lastline;
1124 		} else {
1125 			el->el_cursor.v++;
1126 			lastline = el->el_display[++el->el_refresh.r_oldcv];
1127 		}
1128 		re__copy_and_pad(lastline, L"", (size_t)el->el_terminal.t_size.h);
1129 
1130 		if (EL_HAS_AUTO_MARGINS) {
1131 			if (EL_HAS_MAGIC_MARGINS) {
1132 				terminal__putc(el, ' ');
1133 				terminal__putc(el, '\b');
1134 			}
1135 		} else {
1136 			terminal__putc(el, '\r');
1137 			terminal__putc(el, '\n');
1138 		}
1139 	}
1140 }
1141 
1142 
1143 /* re_fastaddc():
1144  *	we added just one char, handle it fast.
1145  *	Assumes that screen cursor == real cursor
1146  */
1147 libedit_private void
1148 re_fastaddc(EditLine *el)
1149 {
1150 	wchar_t c;
1151 	int rhdiff;
1152 
1153 	c = el->el_line.cursor[-1];
1154 
1155 	if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
1156 		re_refresh(el);	/* too hard to handle */
1157 		return;
1158 	}
1159 	rhdiff = el->el_terminal.t_size.h - el->el_cursor.h -
1160 	    el->el_rprompt.p_pos.h;
1161 	if (el->el_rprompt.p_pos.h && rhdiff < 3) {
1162 		re_refresh(el);	/* clear out rprompt if less than 1 char gap */
1163 		return;
1164 	}			/* else (only do at end of line, no TAB) */
1165 	switch (ct_chr_class(c)) {
1166 	case CHTYPE_TAB: /* already handled, should never happen here */
1167 		break;
1168 	case CHTYPE_NL:
1169 	case CHTYPE_PRINT:
1170 		re_fastputc(el, c);
1171 		break;
1172 	case CHTYPE_ASCIICTL:
1173 	case CHTYPE_NONPRINT: {
1174 		wchar_t visbuf[VISUAL_WIDTH_MAX];
1175 		ssize_t i, n =
1176 		    ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c);
1177 		for (i = 0; n-- > 0; ++i)
1178 			re_fastputc(el, visbuf[i]);
1179 		break;
1180 	}
1181 	}
1182 	terminal__flush(el);
1183 }
1184 
1185 
1186 /* re_clear_display():
1187  *	clear the screen buffers so that new new prompt starts fresh.
1188  */
1189 libedit_private void
1190 re_clear_display(EditLine *el)
1191 {
1192 	int i;
1193 
1194 	el->el_cursor.v = 0;
1195 	el->el_cursor.h = 0;
1196 	for (i = 0; i < el->el_terminal.t_size.v; i++)
1197 		el->el_display[i][0] = '\0';
1198 	el->el_refresh.r_oldcv = 0;
1199 }
1200 
1201 
1202 /* re_clear_lines():
1203  *	Make sure all lines are *really* blank
1204  */
1205 libedit_private void
1206 re_clear_lines(EditLine *el)
1207 {
1208 
1209 	if (EL_CAN_CEOL) {
1210 		int i;
1211 		for (i = el->el_refresh.r_oldcv; i >= 0; i--) {
1212 			/* for each line on the screen */
1213 			terminal_move_to_line(el, i);
1214 			terminal_move_to_char(el, 0);
1215 			terminal_clear_EOL(el, el->el_terminal.t_size.h);
1216 		}
1217 	} else {
1218 		terminal_move_to_line(el, el->el_refresh.r_oldcv);
1219 					/* go to last line */
1220 		terminal__putc(el, '\r');	/* go to BOL */
1221 		terminal__putc(el, '\n');	/* go to new line */
1222 	}
1223 }
1224