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