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