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