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