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