refresh.c revision 84260
11573Srgrimes/*-
21573Srgrimes * Copyright (c) 1992, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * This code is derived from software contributed to Berkeley by
61573Srgrimes * Christos Zoulas of Cornell University.
71573Srgrimes *
81573Srgrimes * Redistribution and use in source and binary forms, with or without
91573Srgrimes * modification, are permitted provided that the following conditions
101573Srgrimes * are met:
111573Srgrimes * 1. Redistributions of source code must retain the above copyright
121573Srgrimes *    notice, this list of conditions and the following disclaimer.
131573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141573Srgrimes *    notice, this list of conditions and the following disclaimer in the
151573Srgrimes *    documentation and/or other materials provided with the distribution.
161573Srgrimes * 3. All advertising materials mentioning features or use of this software
171573Srgrimes *    must display the following acknowledgement:
181573Srgrimes *	This product includes software developed by the University of
191573Srgrimes *	California, Berkeley and its contributors.
201573Srgrimes * 4. Neither the name of the University nor the names of its contributors
211573Srgrimes *    may be used to endorse or promote products derived from this software
221573Srgrimes *    without specific prior written permission.
231573Srgrimes *
241573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341573Srgrimes * SUCH DAMAGE.
3584260Sobrien *
3684260Sobrien *	$NetBSD: refresh.c,v 1.16 2001/01/10 07:45:42 jdolecek Exp $
371573Srgrimes */
381573Srgrimes
3984201Sdillon#include <sys/cdefs.h>
4084201Sdillon__FBSDID("$FreeBSD: head/lib/libedit/refresh.c 84260 2001-10-01 08:41:27Z obrien $");
411573Srgrimes#if !defined(lint) && !defined(SCCSID)
421573Srgrimesstatic char sccsid[] = "@(#)refresh.c	8.1 (Berkeley) 6/4/93";
431573Srgrimes#endif /* not lint && not SCCSID */
4484260Sobrien#include <sys/cdefs.h>
4584260Sobrien__FBSDID("$FreeBSD: head/lib/libedit/refresh.c 84260 2001-10-01 08:41:27Z obrien $");
461573Srgrimes
471573Srgrimes/*
481573Srgrimes * refresh.c: Lower level screen refreshing functions
491573Srgrimes */
501573Srgrimes#include "sys.h"
511573Srgrimes#include <stdio.h>
521573Srgrimes#include <unistd.h>
531573Srgrimes#include <string.h>
541573Srgrimes
551573Srgrimes#include "el.h"
561573Srgrimes
5784260Sobrienprivate void	re_addc(EditLine *, int);
5884260Sobrienprivate void	re_update_line(EditLine *, char *, char *, int);
5984260Sobrienprivate void	re_insert (EditLine *, char *, int, int, char *, int);
6084260Sobrienprivate void	re_delete(EditLine *, char *, int, int, int);
6184260Sobrienprivate void	re_fastputc(EditLine *, int);
6284260Sobrienprivate void	re__strncopy(char *, char *, size_t);
6384260Sobrienprivate void	re__copy_and_pad(char *, char *, size_t);
641573Srgrimes
651573Srgrimes#ifdef DEBUG_REFRESH
6684260Sobrienprivate void	re_printstr(EditLine *, char *, char *, char *);
6784260Sobrien#define	__F el->el_errfile
6884260Sobrien#define	ELRE_ASSERT(a, b, c)	do 				\
691573Srgrimes				    if (a) {			\
701573Srgrimes					(void) fprintf b;	\
711573Srgrimes					c;			\
721573Srgrimes				    }				\
731573Srgrimes				while (0)
7484260Sobrien#define	ELRE_DEBUG(a, b)	ELRE_ASSERT(a,b,;)
7584260Sobrien
761573Srgrimes/* re_printstr():
771573Srgrimes *	Print a string on the debugging pty
781573Srgrimes */
791573Srgrimesprivate void
8084260Sobrienre_printstr(EditLine *el, char *str, char *f, char *t)
811573Srgrimes{
8284260Sobrien
8384260Sobrien	ELRE_DEBUG(1, (__F, "%s:\"", str));
8484260Sobrien	while (f < t)
8584260Sobrien		ELRE_DEBUG(1, (__F, "%c", *f++ & 0177));
8684260Sobrien	ELRE_DEBUG(1, (__F, "\"\r\n"));
878870Srgrimes}
881573Srgrimes#else
8984260Sobrien#define	ELRE_ASSERT(a, b, c)
9084260Sobrien#define	ELRE_DEBUG(a, b)
911573Srgrimes#endif
921573Srgrimes
931573Srgrimes
941573Srgrimes/* re_addc():
951573Srgrimes *	Draw c, expanding tabs, control chars etc.
961573Srgrimes */
971573Srgrimesprivate void
9884260Sobrienre_addc(EditLine *el, int c)
991573Srgrimes{
10017524Sache
10184260Sobrien	c = (unsigned char)c;
10284260Sobrien
10384260Sobrien	if (isprint(c)) {
10484260Sobrien		re_putc(el, c, 1);
10584260Sobrien		return;
1061573Srgrimes	}
10784260Sobrien	if (c == '\n') {				/* expand the newline */
10884260Sobrien		int oldv = el->el_refresh.r_cursor.v;
10984260Sobrien		re_putc(el, '\0', 0);			/* assure end of line */
11084260Sobrien		if (oldv == el->el_refresh.r_cursor.v) { /* XXX */
11184260Sobrien			el->el_refresh.r_cursor.h = 0;	/* reset cursor pos */
11284260Sobrien			el->el_refresh.r_cursor.v++;
11384260Sobrien		}
11484260Sobrien		return;
11584260Sobrien	}
11684260Sobrien	if (c == '\t') {				/* expand the tab */
11784260Sobrien		for (;;) {
11884260Sobrien			re_putc(el, ' ', 1);
11984260Sobrien			if ((el->el_refresh.r_cursor.h & 07) == 0)
12084260Sobrien				break;			/* go until tab stop */
12184260Sobrien		}
12284260Sobrien	} else if (iscntrl(c)) {
12384260Sobrien		re_putc(el, '^', 1);
12484260Sobrien		if (c == 0177)
12584260Sobrien			re_putc(el, '?', 1);
12684260Sobrien		else
12784260Sobrien		    /* uncontrolify it; works only for iso8859-1 like sets */
12884260Sobrien			re_putc(el, (toascii(c) | 0100), 1);
12984260Sobrien	} else {
13084260Sobrien		re_putc(el, '\\', 1);
13184260Sobrien		re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1);
13284260Sobrien		re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1);
13384260Sobrien		re_putc(el, (c & 07) + '0', 1);
13484260Sobrien	}
13584260Sobrien}
1361573Srgrimes
1371573Srgrimes
1381573Srgrimes/* re_putc():
1391573Srgrimes *	Draw the character given
1401573Srgrimes */
1411573Srgrimesprotected void
14284260Sobrienre_putc(EditLine *el, int c, int shift)
1431573Srgrimes{
1441573Srgrimes
14584260Sobrien	ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c));
1461573Srgrimes
14784260Sobrien	el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
14884260Sobrien	if (!shift)
14984260Sobrien		return;
1501573Srgrimes
15184260Sobrien	el->el_refresh.r_cursor.h++;	/* advance to next place */
15284260Sobrien	if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
15384260Sobrien		el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
15484260Sobrien		/* assure end of line */
15584260Sobrien		el->el_refresh.r_cursor.h = 0;	/* reset it. */
15684260Sobrien
15784260Sobrien		/*
15884260Sobrien		 * If we would overflow (input is longer than terminal size),
15984260Sobrien		 * emulate scroll by dropping first line and shuffling the rest.
16084260Sobrien		 * We do this via pointer shuffling - it's safe in this case
16184260Sobrien		 * and we avoid memcpy().
16284260Sobrien		 */
16384260Sobrien		if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) {
16484260Sobrien			int i, lins = el->el_term.t_size.v;
16584260Sobrien			char *firstline = el->el_vdisplay[0];
16684260Sobrien
16784260Sobrien			for(i=1; i < lins; i++)
16884260Sobrien				el->el_vdisplay[i-1] = el->el_vdisplay[i];
16984260Sobrien
17084260Sobrien			firstline[0] = '\0';		/* empty the string */
17184260Sobrien			el->el_vdisplay[i-1] = firstline;
17284260Sobrien		} else
17384260Sobrien			el->el_refresh.r_cursor.v++;
17484260Sobrien
17584260Sobrien		ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
17684260Sobrien		    (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
17784260Sobrien		    el->el_refresh.r_cursor.v, el->el_term.t_size.v),
17884260Sobrien		    abort());
17984260Sobrien	}
18084260Sobrien}
18184260Sobrien
18284260Sobrien
1831573Srgrimes/* re_refresh():
1841573Srgrimes *	draws the new virtual screen image from the current input
1851573Srgrimes *  	line, then goes line-by-line changing the real image to the new
1861573Srgrimes *	virtual image. The routine to re-draw a line can be replaced
1871573Srgrimes *	easily in hopes of a smarter one being placed there.
1881573Srgrimes */
1891573Srgrimesprotected void
19084260Sobrienre_refresh(EditLine *el)
1911573Srgrimes{
19284260Sobrien	int i, rhdiff;
19384260Sobrien	char *cp, *st;
19484260Sobrien	coord_t cur;
19584260Sobrien#ifdef notyet
19684260Sobrien	size_t termsz;
19784260Sobrien#endif
1981573Srgrimes
19984260Sobrien	ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n",
20084260Sobrien	    el->el_line.buffer));
2011573Srgrimes
20284260Sobrien	/* reset the Drawing cursor */
20384260Sobrien	el->el_refresh.r_cursor.h = 0;
20484260Sobrien	el->el_refresh.r_cursor.v = 0;
2051573Srgrimes
20684260Sobrien	/* temporarily draw rprompt to calculate its size */
20784260Sobrien	prompt_print(el, EL_RPROMPT);
2081573Srgrimes
20984260Sobrien	/* reset the Drawing cursor */
21084260Sobrien	el->el_refresh.r_cursor.h = 0;
21184260Sobrien	el->el_refresh.r_cursor.v = 0;
2121573Srgrimes
21384260Sobrien	cur.h = -1;		/* set flag in case I'm not set */
21484260Sobrien	cur.v = 0;
21584260Sobrien
21684260Sobrien	prompt_print(el, EL_PROMPT);
21784260Sobrien
21884260Sobrien	/* draw the current input buffer */
21984260Sobrien#if notyet
22084260Sobrien	termsz = el->el_term.t_size.h * el->el_term.t_size.v;
22184260Sobrien	if (el->el_line.lastchar - el->el_line.buffer > termsz) {
22284260Sobrien		/*
22384260Sobrien		 * If line is longer than terminal, process only part
22484260Sobrien		 * of line which would influence display.
22584260Sobrien		 */
22684260Sobrien		size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz;
22784260Sobrien
22884260Sobrien		st = el->el_line.lastchar - rem
22984260Sobrien			- (termsz - (((rem / el->el_term.t_size.v) - 1)
23084260Sobrien					* el->el_term.t_size.v));
23184260Sobrien	} else
23284260Sobrien#endif
23384260Sobrien		st = el->el_line.buffer;
23484260Sobrien
23584260Sobrien	for (cp = st; cp < el->el_line.lastchar; cp++) {
23684260Sobrien		if (cp == el->el_line.cursor) {
23784260Sobrien			/* save for later */
23884260Sobrien			cur.h = el->el_refresh.r_cursor.h;
23984260Sobrien			cur.v = el->el_refresh.r_cursor.v;
24084260Sobrien		}
24184260Sobrien		re_addc(el, (unsigned char) *cp);
2421573Srgrimes	}
2431573Srgrimes
24484260Sobrien	if (cur.h == -1) {	/* if I haven't been set yet, I'm at the end */
24584260Sobrien		cur.h = el->el_refresh.r_cursor.h;
24684260Sobrien		cur.v = el->el_refresh.r_cursor.v;
24784260Sobrien	}
24884260Sobrien	rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h -
24984260Sobrien	    el->el_rprompt.p_pos.h;
25084260Sobrien	if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v &&
25184260Sobrien	    !el->el_refresh.r_cursor.v && rhdiff > 1) {
25284260Sobrien		/*
25384260Sobrien		 * have a right-hand side prompt that will fit
25484260Sobrien		 * on the end of the first line with at least
25584260Sobrien		 * one character gap to the input buffer.
25684260Sobrien		 */
25784260Sobrien		while (--rhdiff > 0)	/* pad out with spaces */
25884260Sobrien			re_putc(el, ' ', 1);
25984260Sobrien		prompt_print(el, EL_RPROMPT);
26084260Sobrien	} else {
26184260Sobrien		el->el_rprompt.p_pos.h = 0;	/* flag "not using rprompt" */
26284260Sobrien		el->el_rprompt.p_pos.v = 0;
26384260Sobrien	}
2641573Srgrimes
26584260Sobrien	re_putc(el, '\0', 0);	/* make line ended with NUL, no cursor shift */
2661573Srgrimes
26784260Sobrien	el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
2681573Srgrimes
26984260Sobrien	ELRE_DEBUG(1, (__F,
27084260Sobrien		"term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
27184260Sobrien		el->el_term.t_size.h, el->el_refresh.r_cursor.h,
27284260Sobrien		el->el_refresh.r_cursor.v, el->el_vdisplay[0]));
2731573Srgrimes
27484260Sobrien	ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv));
27584260Sobrien	for (i = 0; i <= el->el_refresh.r_newcv; i++) {
27684260Sobrien		/* NOTE THAT re_update_line MAY CHANGE el_display[i] */
27784260Sobrien		re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
27884260Sobrien
27984260Sobrien		/*
28084260Sobrien		 * Copy the new line to be the current one, and pad out with
28184260Sobrien		 * spaces to the full width of the terminal so that if we try
28284260Sobrien		 * moving the cursor by writing the character that is at the
28384260Sobrien		 * end of the screen line, it won't be a NUL or some old
28484260Sobrien		 * leftover stuff.
28584260Sobrien		 */
28684260Sobrien		re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
28784260Sobrien		    (size_t) el->el_term.t_size.h);
28884260Sobrien	}
28984260Sobrien	ELRE_DEBUG(1, (__F,
29084260Sobrien	"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
29184260Sobrien	    el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i));
29284260Sobrien
29384260Sobrien	if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
29484260Sobrien		for (; i <= el->el_refresh.r_oldcv; i++) {
29584260Sobrien			term_move_to_line(el, i);
29684260Sobrien			term_move_to_char(el, 0);
29784260Sobrien			term_clear_EOL(el, (int) strlen(el->el_display[i]));
2981573Srgrimes#ifdef DEBUG_REFRESH
29984260Sobrien			term_overwrite(el, "C\b", 2);
3001573Srgrimes#endif /* DEBUG_REFRESH */
30184260Sobrien			el->el_display[i][0] = '\0';
30284260Sobrien		}
3038870Srgrimes
30484260Sobrien	el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
30584260Sobrien	ELRE_DEBUG(1, (__F,
30684260Sobrien	    "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
30784260Sobrien	    el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
30884260Sobrien	    cur.h, cur.v));
30984260Sobrien	term_move_to_line(el, cur.v);	/* go to where the cursor is */
31084260Sobrien	term_move_to_char(el, cur.h);
31184260Sobrien}
3121573Srgrimes
3131573Srgrimes
3141573Srgrimes/* re_goto_bottom():
3158870Srgrimes *	 used to go to last used screen line
3161573Srgrimes */
3171573Srgrimesprotected void
31884260Sobrienre_goto_bottom(EditLine *el)
3191573Srgrimes{
3201573Srgrimes
32184260Sobrien	term_move_to_line(el, el->el_refresh.r_oldcv);
32284260Sobrien	term__putc('\r');
32384260Sobrien	term__putc('\n');
32484260Sobrien	re_clear_display(el);
32584260Sobrien	term__flush();
32684260Sobrien}
3271573Srgrimes
32884260Sobrien
3291573Srgrimes/* re_insert():
3301573Srgrimes *	insert num characters of s into d (in front of the character)
3318870Srgrimes *	at dat, maximum length of d is dlen
3321573Srgrimes */
3331573Srgrimesprivate void
3341573Srgrimes/*ARGSUSED*/
33584260Sobrienre_insert(EditLine *el, char *d, int dat, int dlen, char *s, int num)
3361573Srgrimes{
33784260Sobrien	char *a, *b;
3381573Srgrimes
33984260Sobrien	if (num <= 0)
34084260Sobrien		return;
34184260Sobrien	if (num > dlen - dat)
34284260Sobrien		num = dlen - dat;
3431573Srgrimes
34484260Sobrien	ELRE_DEBUG(1,
34584260Sobrien	    (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
34684260Sobrien	    num, dat, dlen, d));
34784260Sobrien	ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
3481573Srgrimes
34984260Sobrien	/* open up the space for num chars */
35084260Sobrien	if (num > 0) {
35184260Sobrien		b = d + dlen - 1;
35284260Sobrien		a = b - num;
35384260Sobrien		while (a >= &d[dat])
35484260Sobrien			*b-- = *a--;
35584260Sobrien		d[dlen] = '\0';	/* just in case */
35684260Sobrien	}
35784260Sobrien	ELRE_DEBUG(1, (__F,
3581573Srgrimes		"re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
35984260Sobrien		num, dat, dlen, d));
36084260Sobrien	ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
3611573Srgrimes
36284260Sobrien	/* copy the characters */
36384260Sobrien	for (a = d + dat; (a < d + dlen) && (num > 0); num--)
36484260Sobrien		*a++ = *s++;
3651573Srgrimes
36684260Sobrien	ELRE_DEBUG(1,
36784260Sobrien	    (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
36884260Sobrien	    num, dat, dlen, d, s));
36984260Sobrien	ELRE_DEBUG(1, (__F, "s == \"%s\"n", s));
37084260Sobrien}
3711573Srgrimes
3721573Srgrimes
3731573Srgrimes/* re_delete():
3748870Srgrimes *	delete num characters d at dat, maximum length of d is dlen
3751573Srgrimes */
3761573Srgrimesprivate void
3771573Srgrimes/*ARGSUSED*/
37884260Sobrienre_delete(EditLine *el, char *d, int dat, int dlen, int num)
3791573Srgrimes{
38084260Sobrien	char *a, *b;
3811573Srgrimes
38284260Sobrien	if (num <= 0)
38384260Sobrien		return;
38484260Sobrien	if (dat + num >= dlen) {
38584260Sobrien		d[dat] = '\0';
38684260Sobrien		return;
38784260Sobrien	}
38884260Sobrien	ELRE_DEBUG(1,
38984260Sobrien	    (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
39084260Sobrien	    num, dat, dlen, d));
3911573Srgrimes
39284260Sobrien	/* open up the space for num chars */
39384260Sobrien	if (num > 0) {
39484260Sobrien		b = d + dat;
39584260Sobrien		a = b + num;
39684260Sobrien		while (a < &d[dlen])
39784260Sobrien			*b++ = *a++;
39884260Sobrien		d[dlen] = '\0';	/* just in case */
39984260Sobrien	}
40084260Sobrien	ELRE_DEBUG(1,
40184260Sobrien	    (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
40284260Sobrien	    num, dat, dlen, d));
40384260Sobrien}
4041573Srgrimes
4051573Srgrimes
4061573Srgrimes/* re__strncopy():
4071573Srgrimes *	Like strncpy without padding.
4081573Srgrimes */
4091573Srgrimesprivate void
41084260Sobrienre__strncopy(char *a, char *b, size_t n)
4111573Srgrimes{
4121573Srgrimes
41384260Sobrien	while (n-- && *b)
41484260Sobrien		*a++ = *b++;
41584260Sobrien}
4161573Srgrimes
41784260Sobrien
41884260Sobrien/*****************************************************************
4191573Srgrimes    re_update_line() is based on finding the middle difference of each line
4201573Srgrimes    on the screen; vis:
4211573Srgrimes
4221573Srgrimes			     /old first difference
4231573Srgrimes	/beginning of line   |              /old last same       /old EOL
4241573Srgrimes	v		     v              v                    v
4251573Srgrimesold:	eddie> Oh, my little gruntle-buggy is to me, as lurgid as
4261573Srgrimesnew:	eddie> Oh, my little buggy says to me, as lurgid as
4271573Srgrimes	^		     ^        ^			   ^
4281573Srgrimes	\beginning of line   |        \new last same	   \new end of line
4291573Srgrimes			     \new first difference
4301573Srgrimes
4311573Srgrimes    all are character pointers for the sake of speed.  Special cases for
4321573Srgrimes    no differences, as well as for end of line additions must be handled.
4331573Srgrimes**************************************************************** */
4341573Srgrimes
4351573Srgrimes/* Minimum at which doing an insert it "worth it".  This should be about
4361573Srgrimes * half the "cost" of going into insert mode, inserting a character, and
4371573Srgrimes * going back out.  This should really be calculated from the termcap
4381573Srgrimes * data...  For the moment, a good number for ANSI terminals.
4391573Srgrimes */
44084260Sobrien#define	MIN_END_KEEP	4
4411573Srgrimes
4421573Srgrimesprivate void
44384260Sobrienre_update_line(EditLine *el, char *old, char *new, int i)
4441573Srgrimes{
44584260Sobrien	char *o, *n, *p, c;
44684260Sobrien	char *ofd, *ols, *oe, *nfd, *nls, *ne;
44784260Sobrien	char *osb, *ose, *nsb, *nse;
44884260Sobrien	int fx, sx;
4491573Srgrimes
45084260Sobrien	/*
45184260Sobrien         * find first diff
45284260Sobrien         */
45384260Sobrien	for (o = old, n = new; *o && (*o == *n); o++, n++)
45484260Sobrien		continue;
45584260Sobrien	ofd = o;
45684260Sobrien	nfd = n;
4571573Srgrimes
45884260Sobrien	/*
45984260Sobrien         * Find the end of both old and new
46084260Sobrien         */
46184260Sobrien	while (*o)
46284260Sobrien		o++;
46384260Sobrien	/*
46484260Sobrien         * Remove any trailing blanks off of the end, being careful not to
46584260Sobrien         * back up past the beginning.
46684260Sobrien         */
46784260Sobrien	while (ofd < o) {
46884260Sobrien		if (o[-1] != ' ')
46984260Sobrien			break;
47084260Sobrien		o--;
47184260Sobrien	}
47284260Sobrien	oe = o;
47384260Sobrien	*oe = '\0';
4748870Srgrimes
47584260Sobrien	while (*n)
47684260Sobrien		n++;
4771573Srgrimes
47884260Sobrien	/* remove blanks from end of new */
47984260Sobrien	while (nfd < n) {
48084260Sobrien		if (n[-1] != ' ')
48184260Sobrien			break;
48284260Sobrien		n--;
4831573Srgrimes	}
48484260Sobrien	ne = n;
48584260Sobrien	*ne = '\0';
4861573Srgrimes
48784260Sobrien	/*
48884260Sobrien         * if no diff, continue to next line of redraw
48984260Sobrien         */
49084260Sobrien	if (*ofd == '\0' && *nfd == '\0') {
49184260Sobrien		ELRE_DEBUG(1, (__F, "no difference.\r\n"));
49284260Sobrien		return;
4931573Srgrimes	}
49484260Sobrien	/*
49584260Sobrien         * find last same pointer
49684260Sobrien         */
49784260Sobrien	while ((o > ofd) && (n > nfd) && (*--o == *--n))
49884260Sobrien		continue;
49984260Sobrien	ols = ++o;
50084260Sobrien	nls = ++n;
5011573Srgrimes
50284260Sobrien	/*
50384260Sobrien         * find same begining and same end
50484260Sobrien         */
5051573Srgrimes	osb = ols;
50684260Sobrien	nsb = nls;
5071573Srgrimes	ose = ols;
5081573Srgrimes	nse = nls;
5091573Srgrimes
5101573Srgrimes	/*
51184260Sobrien         * case 1: insert: scan from nfd to nls looking for *ofd
51284260Sobrien         */
51384260Sobrien	if (*ofd) {
51484260Sobrien		for (c = *ofd, n = nfd; n < nls; n++) {
51584260Sobrien			if (c == *n) {
51684260Sobrien				for (o = ofd, p = n;
51784260Sobrien				    p < nls && o < ols && *o == *p;
51884260Sobrien				    o++, p++)
51984260Sobrien					continue;
52084260Sobrien				/*
52184260Sobrien				 * if the new match is longer and it's worth
52284260Sobrien				 * keeping, then we take it
52384260Sobrien				 */
52484260Sobrien				if (((nse - nsb) < (p - n)) &&
52584260Sobrien				    (2 * (p - n) > n - nfd)) {
52684260Sobrien					nsb = n;
52784260Sobrien					nse = p;
52884260Sobrien					osb = ofd;
52984260Sobrien					ose = o;
53084260Sobrien				}
53184260Sobrien			}
53284260Sobrien		}
53384260Sobrien	}
5341573Srgrimes	/*
53584260Sobrien         * case 2: delete: scan from ofd to ols looking for *nfd
53684260Sobrien         */
53784260Sobrien	if (*nfd) {
53884260Sobrien		for (c = *nfd, o = ofd; o < ols; o++) {
53984260Sobrien			if (c == *o) {
54084260Sobrien				for (n = nfd, p = o;
54184260Sobrien				    p < ols && n < nls && *p == *n;
54284260Sobrien				    p++, n++)
54384260Sobrien					continue;
54484260Sobrien				/*
54584260Sobrien				 * if the new match is longer and it's worth
54684260Sobrien				 * keeping, then we take it
54784260Sobrien				 */
54884260Sobrien				if (((ose - osb) < (p - o)) &&
54984260Sobrien				    (2 * (p - o) > o - ofd)) {
55084260Sobrien					nsb = nfd;
55184260Sobrien					nse = n;
55284260Sobrien					osb = o;
55384260Sobrien					ose = p;
55484260Sobrien				}
55584260Sobrien			}
55684260Sobrien		}
5571573Srgrimes	}
55884260Sobrien	/*
55984260Sobrien         * Pragmatics I: If old trailing whitespace or not enough characters to
56084260Sobrien         * save to be worth it, then don't save the last same info.
56184260Sobrien         */
56284260Sobrien	if ((oe - ols) < MIN_END_KEEP) {
56384260Sobrien		ols = oe;
56484260Sobrien		nls = ne;
5651573Srgrimes	}
5661573Srgrimes	/*
56784260Sobrien         * Pragmatics II: if the terminal isn't smart enough, make the data
56884260Sobrien         * dumber so the smart update doesn't try anything fancy
56984260Sobrien         */
57084260Sobrien
5711573Srgrimes	/*
57284260Sobrien         * fx is the number of characters we need to insert/delete: in the
57384260Sobrien         * beginning to bring the two same begins together
57484260Sobrien         */
57584260Sobrien	fx = (nsb - nfd) - (osb - ofd);
57684260Sobrien	/*
57784260Sobrien         * sx is the number of characters we need to insert/delete: in the
57884260Sobrien         * end to bring the two same last parts together
57984260Sobrien         */
58084260Sobrien	sx = (nls - nse) - (ols - ose);
5811573Srgrimes
58284260Sobrien	if (!EL_CAN_INSERT) {
58384260Sobrien		if (fx > 0) {
58484260Sobrien			osb = ols;
58584260Sobrien			ose = ols;
58684260Sobrien			nsb = nls;
58784260Sobrien			nse = nls;
58884260Sobrien		}
58984260Sobrien		if (sx > 0) {
59084260Sobrien			ols = oe;
59184260Sobrien			nls = ne;
59284260Sobrien		}
59384260Sobrien		if ((ols - ofd) < (nls - nfd)) {
59484260Sobrien			ols = oe;
59584260Sobrien			nls = ne;
59684260Sobrien		}
5971573Srgrimes	}
59884260Sobrien	if (!EL_CAN_DELETE) {
59984260Sobrien		if (fx < 0) {
60084260Sobrien			osb = ols;
60184260Sobrien			ose = ols;
60284260Sobrien			nsb = nls;
60384260Sobrien			nse = nls;
60484260Sobrien		}
60584260Sobrien		if (sx < 0) {
60684260Sobrien			ols = oe;
60784260Sobrien			nls = ne;
60884260Sobrien		}
60984260Sobrien		if ((ols - ofd) > (nls - nfd)) {
61084260Sobrien			ols = oe;
61184260Sobrien			nls = ne;
61284260Sobrien		}
6131573Srgrimes	}
6141573Srgrimes	/*
61584260Sobrien         * Pragmatics III: make sure the middle shifted pointers are correct if
61684260Sobrien         * they don't point to anything (we may have moved ols or nls).
61784260Sobrien         */
61884260Sobrien	/* if the change isn't worth it, don't bother */
61984260Sobrien	/* was: if (osb == ose) */
62084260Sobrien	if ((ose - osb) < MIN_END_KEEP) {
62184260Sobrien		osb = ols;
62284260Sobrien		ose = ols;
62384260Sobrien		nsb = nls;
62484260Sobrien		nse = nls;
62584260Sobrien	}
6261573Srgrimes	/*
62784260Sobrien         * Now that we are done with pragmatics we recompute fx, sx
62884260Sobrien         */
62984260Sobrien	fx = (nsb - nfd) - (osb - ofd);
63084260Sobrien	sx = (nls - nse) - (ols - ose);
6311573Srgrimes
63284260Sobrien	ELRE_DEBUG(1, (__F, "\n"));
63384260Sobrien	ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
63484260Sobrien		ofd - old, osb - old, ose - old, ols - old, oe - old));
63584260Sobrien	ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
63684260Sobrien		nfd - new, nsb - new, nse - new, nls - new, ne - new));
63784260Sobrien	ELRE_DEBUG(1, (__F,
63884260Sobrien		"xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"));
63984260Sobrien	ELRE_DEBUG(1, (__F,
64084260Sobrien		"xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"));
64184260Sobrien#ifdef DEBUG_REFRESH
64284260Sobrien	re_printstr(el, "old- oe", old, oe);
64384260Sobrien	re_printstr(el, "new- ne", new, ne);
64484260Sobrien	re_printstr(el, "old-ofd", old, ofd);
64584260Sobrien	re_printstr(el, "new-nfd", new, nfd);
64684260Sobrien	re_printstr(el, "ofd-osb", ofd, osb);
64784260Sobrien	re_printstr(el, "nfd-nsb", nfd, nsb);
64884260Sobrien	re_printstr(el, "osb-ose", osb, ose);
64984260Sobrien	re_printstr(el, "nsb-nse", nsb, nse);
65084260Sobrien	re_printstr(el, "ose-ols", ose, ols);
65184260Sobrien	re_printstr(el, "nse-nls", nse, nls);
65284260Sobrien	re_printstr(el, "ols- oe", ols, oe);
65384260Sobrien	re_printstr(el, "nls- ne", nls, ne);
65484260Sobrien#endif /* DEBUG_REFRESH */
65584260Sobrien
6561573Srgrimes	/*
65784260Sobrien         * el_cursor.v to this line i MUST be in this routine so that if we
65884260Sobrien         * don't have to change the line, we don't move to it. el_cursor.h to
65984260Sobrien         * first diff char
66084260Sobrien         */
66184260Sobrien	term_move_to_line(el, i);
6621573Srgrimes
66384260Sobrien	/*
66484260Sobrien         * at this point we have something like this:
66584260Sobrien         *
66684260Sobrien         * /old                  /ofd    /osb               /ose    /ols     /oe
66784260Sobrien         * v.....................v       v..................v       v........v
66884260Sobrien         * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
66984260Sobrien         * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
67084260Sobrien         * ^.....................^     ^..................^       ^........^
67184260Sobrien         * \new                  \nfd  \nsb               \nse     \nls    \ne
67284260Sobrien         *
67384260Sobrien         * fx is the difference in length between the chars between nfd and
67484260Sobrien         * nsb, and the chars between ofd and osb, and is thus the number of
67584260Sobrien         * characters to delete if < 0 (new is shorter than old, as above),
67684260Sobrien         * or insert (new is longer than short).
67784260Sobrien         *
67884260Sobrien         * sx is the same for the second differences.
67984260Sobrien         */
6801573Srgrimes
68184260Sobrien	/*
68284260Sobrien         * if we have a net insert on the first difference, AND inserting the
68384260Sobrien         * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful
68484260Sobrien         * character (which is ne if nls != ne, otherwise is nse) off the edge
68584260Sobrien	 * of the screen (el->el_term.t_size.h) else we do the deletes first
68684260Sobrien	 * so that we keep everything we need to.
68784260Sobrien         */
6881573Srgrimes
6891573Srgrimes	/*
69084260Sobrien         * if the last same is the same like the end, there is no last same
69184260Sobrien         * part, otherwise we want to keep the last same part set p to the
69284260Sobrien         * last useful old character
69384260Sobrien         */
69484260Sobrien	p = (ols != oe) ? oe : ose;
69584260Sobrien
69684260Sobrien	/*
69784260Sobrien         * if (There is a diffence in the beginning) && (we need to insert
69884260Sobrien         *   characters) && (the number of characters to insert is less than
69984260Sobrien         *   the term width)
70084260Sobrien	 *	We need to do an insert!
70184260Sobrien	 * else if (we need to delete characters)
70284260Sobrien	 *	We need to delete characters!
70384260Sobrien	 * else
70484260Sobrien	 *	No insert or delete
70584260Sobrien         */
70684260Sobrien	if ((nsb != nfd) && fx > 0 &&
70784260Sobrien	    ((p - old) + fx <= el->el_term.t_size.h)) {
70884260Sobrien		ELRE_DEBUG(1,
70984260Sobrien		    (__F, "first diff insert at %d...\r\n", nfd - new));
7101573Srgrimes		/*
71184260Sobrien		 * Move to the first char to insert, where the first diff is.
7121573Srgrimes		 */
71384260Sobrien		term_move_to_char(el, nfd - new);
71484260Sobrien		/*
71584260Sobrien		 * Check if we have stuff to keep at end
71684260Sobrien		 */
71784260Sobrien		if (nsb != ne) {
71884260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
71984260Sobrien			/*
72084260Sobrien		         * insert fx chars of new starting at nfd
72184260Sobrien		         */
72284260Sobrien			if (fx > 0) {
72384260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
72484260Sobrien				"ERROR: cannot insert in early first diff\n"));
72584260Sobrien				term_insertwrite(el, nfd, fx);
72684260Sobrien				re_insert(el, old, ofd - old,
72784260Sobrien				    el->el_term.t_size.h, nfd, fx);
72884260Sobrien			}
72984260Sobrien			/*
73084260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
73184260Sobrien		         * (nfd + fx)
73284260Sobrien			 */
73384260Sobrien			term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
73484260Sobrien			re__strncopy(ofd + fx, nfd + fx,
73584260Sobrien			    (size_t) ((nsb - nfd) - fx));
73684260Sobrien		} else {
73784260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
73884260Sobrien			term_overwrite(el, nfd, (nsb - nfd));
73984260Sobrien			re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
74084260Sobrien			/*
74184260Sobrien		         * Done
74284260Sobrien		         */
74384260Sobrien			return;
74484260Sobrien		}
74584260Sobrien	} else if (fx < 0) {
74684260Sobrien		ELRE_DEBUG(1,
74784260Sobrien		    (__F, "first diff delete at %d...\r\n", ofd - old));
74884260Sobrien		/*
74984260Sobrien		 * move to the first char to delete where the first diff is
75084260Sobrien		 */
75184260Sobrien		term_move_to_char(el, ofd - old);
75284260Sobrien		/*
75384260Sobrien		 * Check if we have stuff to save
75484260Sobrien		 */
75584260Sobrien		if (osb != oe) {
75684260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
75784260Sobrien			/*
75884260Sobrien		         * fx is less than zero *always* here but we check
75984260Sobrien		         * for code symmetry
76084260Sobrien		         */
76184260Sobrien			if (fx < 0) {
76284260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
76384260Sobrien				    "ERROR: cannot delete in first diff\n"));
76484260Sobrien				term_deletechars(el, -fx);
76584260Sobrien				re_delete(el, old, ofd - old,
76684260Sobrien				    el->el_term.t_size.h, -fx);
76784260Sobrien			}
76884260Sobrien			/*
76984260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
77084260Sobrien		         */
77184260Sobrien			term_overwrite(el, nfd, (nsb - nfd));
77284260Sobrien			re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
7731573Srgrimes
77484260Sobrien		} else {
77584260Sobrien			ELRE_DEBUG(1, (__F,
77684260Sobrien			    "but with nothing left to save\r\n"));
77784260Sobrien			/*
77884260Sobrien		         * write (nsb-nfd) chars of new starting at nfd
77984260Sobrien		         */
78084260Sobrien			term_overwrite(el, nfd, (nsb - nfd));
78184260Sobrien			ELRE_DEBUG(1, (__F,
78284260Sobrien			    "cleareol %d\n", (oe - old) - (ne - new)));
78384260Sobrien			term_clear_EOL(el, (oe - old) - (ne - new));
78484260Sobrien			/*
78584260Sobrien		         * Done
78684260Sobrien		         */
78784260Sobrien			return;
78884260Sobrien		}
78984260Sobrien	} else
79084260Sobrien		fx = 0;
7911573Srgrimes
79284260Sobrien	if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) {
79384260Sobrien		ELRE_DEBUG(1, (__F,
79484260Sobrien		    "second diff delete at %d...\r\n", (ose - old) + fx));
79584260Sobrien		/*
79684260Sobrien		 * Check if we have stuff to delete
79784260Sobrien		 */
79884260Sobrien		/*
79984260Sobrien		 * fx is the number of characters inserted (+) or deleted (-)
80084260Sobrien		 */
8011573Srgrimes
80284260Sobrien		term_move_to_char(el, (ose - old) + fx);
80384260Sobrien		/*
80484260Sobrien		 * Check if we have stuff to save
80584260Sobrien		 */
80684260Sobrien		if (ols != oe) {
80784260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n"));
80884260Sobrien			/*
80984260Sobrien		         * Again a duplicate test.
81084260Sobrien		         */
81184260Sobrien			if (sx < 0) {
81284260Sobrien				ELRE_DEBUG(!EL_CAN_DELETE, (__F,
81384260Sobrien				    "ERROR: cannot delete in second diff\n"));
81484260Sobrien				term_deletechars(el, -sx);
81584260Sobrien			}
81684260Sobrien			/*
81784260Sobrien		         * write (nls-nse) chars of new starting at nse
81884260Sobrien		         */
81984260Sobrien			term_overwrite(el, nse, (nls - nse));
82084260Sobrien		} else {
82184260Sobrien			ELRE_DEBUG(1, (__F,
82284260Sobrien			    "but with nothing left to save\r\n"));
82384260Sobrien			term_overwrite(el, nse, (nls - nse));
82484260Sobrien			ELRE_DEBUG(1, (__F,
82584260Sobrien			    "cleareol %d\n", (oe - old) - (ne - new)));
82684260Sobrien			if ((oe - old) - (ne - new) != 0)
82784260Sobrien				term_clear_EOL(el, (oe - old) - (ne - new));
82884260Sobrien		}
8291573Srgrimes	}
83084260Sobrien	/*
83184260Sobrien         * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
83284260Sobrien         */
83384260Sobrien	if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
83484260Sobrien		ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n",
83584260Sobrien		    nfd - new));
8361573Srgrimes
83784260Sobrien		term_move_to_char(el, nfd - new);
83884260Sobrien		/*
83984260Sobrien		 * Check if we have stuff to keep at the end
84084260Sobrien		 */
84184260Sobrien		if (nsb != ne) {
84284260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
84384260Sobrien			/*
84484260Sobrien		         * We have to recalculate fx here because we set it
84584260Sobrien		         * to zero above as a flag saying that we hadn't done
84684260Sobrien		         * an early first insert.
84784260Sobrien		         */
84884260Sobrien			fx = (nsb - nfd) - (osb - ofd);
84984260Sobrien			if (fx > 0) {
85084260Sobrien				/*
85184260Sobrien				 * insert fx chars of new starting at nfd
85284260Sobrien				 */
85384260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
85484260Sobrien				 "ERROR: cannot insert in late first diff\n"));
85584260Sobrien				term_insertwrite(el, nfd, fx);
85684260Sobrien				re_insert(el, old, ofd - old,
85784260Sobrien				    el->el_term.t_size.h, nfd, fx);
85884260Sobrien			}
85984260Sobrien			/*
86084260Sobrien		         * write (nsb-nfd) - fx chars of new starting at
86184260Sobrien		         * (nfd + fx)
86284260Sobrien			 */
86384260Sobrien			term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
86484260Sobrien			re__strncopy(ofd + fx, nfd + fx,
86584260Sobrien			    (size_t) ((nsb - nfd) - fx));
86684260Sobrien		} else {
86784260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
86884260Sobrien			term_overwrite(el, nfd, (nsb - nfd));
86984260Sobrien			re__strncopy(ofd, nfd, (size_t) (nsb - nfd));
87084260Sobrien		}
8711573Srgrimes	}
87284260Sobrien	/*
87384260Sobrien         * line is now NEW up to nse
87484260Sobrien         */
87584260Sobrien	if (sx >= 0) {
87684260Sobrien		ELRE_DEBUG(1, (__F,
87784260Sobrien		    "second diff insert at %d...\r\n", nse - new));
87884260Sobrien		term_move_to_char(el, nse - new);
87984260Sobrien		if (ols != oe) {
88084260Sobrien			ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n"));
88184260Sobrien			if (sx > 0) {
88284260Sobrien				/* insert sx chars of new starting at nse */
88384260Sobrien				ELRE_DEBUG(!EL_CAN_INSERT, (__F,
88484260Sobrien				    "ERROR: cannot insert in second diff\n"));
88584260Sobrien				term_insertwrite(el, nse, sx);
88684260Sobrien			}
88784260Sobrien			/*
88884260Sobrien		         * write (nls-nse) - sx chars of new starting at
88984260Sobrien			 * (nse + sx)
89084260Sobrien		         */
89184260Sobrien			term_overwrite(el, nse + sx, (nls - nse) - sx);
89284260Sobrien		} else {
89384260Sobrien			ELRE_DEBUG(1, (__F, "without anything to save\r\n"));
89484260Sobrien			term_overwrite(el, nse, (nls - nse));
8951573Srgrimes
89684260Sobrien			/*
89784260Sobrien	                 * No need to do a clear-to-end here because we were
89884260Sobrien	                 * doing a second insert, so we will have over
89984260Sobrien	                 * written all of the old string.
90084260Sobrien		         */
90184260Sobrien		}
90284260Sobrien	}
90384260Sobrien	ELRE_DEBUG(1, (__F, "done.\r\n"));
90484260Sobrien}
9051573Srgrimes
90684260Sobrien
9071573Srgrimes/* re__copy_and_pad():
9081573Srgrimes *	Copy string and pad with spaces
9091573Srgrimes */
9101573Srgrimesprivate void
91184260Sobrienre__copy_and_pad(char *dst, char *src, size_t width)
9121573Srgrimes{
91384260Sobrien	int i;
9141573Srgrimes
91584260Sobrien	for (i = 0; i < width; i++) {
91684260Sobrien		if (*src == '\0')
91784260Sobrien			break;
91884260Sobrien		*dst++ = *src++;
91984260Sobrien	}
9201573Srgrimes
92184260Sobrien	for (; i < width; i++)
92284260Sobrien		*dst++ = ' ';
9231573Srgrimes
92484260Sobrien	*dst = '\0';
92584260Sobrien}
9261573Srgrimes
92784260Sobrien
9281573Srgrimes/* re_refresh_cursor():
9291573Srgrimes *	Move to the new cursor position
9301573Srgrimes */
9311573Srgrimesprotected void
93284260Sobrienre_refresh_cursor(EditLine *el)
9331573Srgrimes{
93484260Sobrien	char *cp, c;
93584260Sobrien	int h, v, th;
9361573Srgrimes
93784260Sobrien	/* first we must find where the cursor is... */
93884260Sobrien	h = el->el_prompt.p_pos.h;
93984260Sobrien	v = el->el_prompt.p_pos.v;
94084260Sobrien	th = el->el_term.t_size.h;	/* optimize for speed */
9411573Srgrimes
94284260Sobrien	/* do input buffer to el->el_line.cursor */
94384260Sobrien	for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
94484260Sobrien		c = (unsigned char)*cp;
94584260Sobrien		h++;		/* all chars at least this long */
9461573Srgrimes
94784260Sobrien		if (c == '\n') {/* handle newline in data part too */
94884260Sobrien			h = 0;
94984260Sobrien			v++;
95084260Sobrien		} else {
95184260Sobrien			if (c == '\t') {	/* if a tab, to next tab stop */
95284260Sobrien				while (h & 07) {
95384260Sobrien					h++;
95484260Sobrien				}
95584260Sobrien			} else if (iscntrl((unsigned char) c)) {
95684260Sobrien						/* if control char */
95784260Sobrien				h++;
95884260Sobrien				if (h > th) {	/* if overflow, compensate */
95984260Sobrien					h = 1;
96084260Sobrien					v++;
96184260Sobrien				}
96284260Sobrien			} else if (!isprint((unsigned char) c)) {
96384260Sobrien				h += 3;
96484260Sobrien				if (h > th) {	/* if overflow, compensate */
96584260Sobrien					h = h - th;
96684260Sobrien					v++;
96784260Sobrien				}
96884260Sobrien			}
9691573Srgrimes		}
97084260Sobrien
97184260Sobrien		if (h >= th) {	/* check, extra long tabs picked up here also */
97284260Sobrien			h = 0;
97384260Sobrien			v++;
9741573Srgrimes		}
9751573Srgrimes	}
9761573Srgrimes
97784260Sobrien	/* now go there */
97884260Sobrien	term_move_to_line(el, v);
97984260Sobrien	term_move_to_char(el, h);
98084260Sobrien	term__flush();
98184260Sobrien}
9821573Srgrimes
9831573Srgrimes
9841573Srgrimes/* re_fastputc():
9851573Srgrimes *	Add a character fast.
9861573Srgrimes */
9871573Srgrimesprivate void
98884260Sobrienre_fastputc(EditLine *el, int c)
9891573Srgrimes{
9901573Srgrimes
99184260Sobrien	term__putc(c);
99284260Sobrien	el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
99384260Sobrien	if (el->el_cursor.h >= el->el_term.t_size.h) {
99484260Sobrien		/* if we must overflow */
99584260Sobrien		el->el_cursor.h = 0;
9961573Srgrimes
99784260Sobrien		/*
99884260Sobrien		 * If we would overflow (input is longer than terminal size),
99984260Sobrien		 * emulate scroll by dropping first line and shuffling the rest.
100084260Sobrien		 * We do this via pointer shuffling - it's safe in this case
100184260Sobrien		 * and we avoid memcpy().
100284260Sobrien		 */
100384260Sobrien		if (el->el_cursor.v + 1 >= el->el_term.t_size.v) {
100484260Sobrien			int i, lins = el->el_term.t_size.v;
100584260Sobrien			char *firstline = el->el_display[0];
100684260Sobrien
100784260Sobrien			for(i=1; i < lins; i++)
100884260Sobrien				el->el_display[i-1] = el->el_display[i];
100984260Sobrien
101084260Sobrien			re__copy_and_pad(firstline, "", 0);
101184260Sobrien			el->el_display[i-1] = firstline;
101284260Sobrien		} else {
101384260Sobrien			el->el_cursor.v++;
101484260Sobrien			el->el_refresh.r_oldcv++;
101584260Sobrien		}
101684260Sobrien		if (EL_HAS_AUTO_MARGINS) {
101784260Sobrien			if (EL_HAS_MAGIC_MARGINS) {
101884260Sobrien				term__putc(' ');
101984260Sobrien				term__putc('\b');
102084260Sobrien			}
102184260Sobrien		} else {
102284260Sobrien			term__putc('\r');
102384260Sobrien			term__putc('\n');
102484260Sobrien		}
102584260Sobrien	}
102684260Sobrien}
102784260Sobrien
102884260Sobrien
10291573Srgrimes/* re_fastaddc():
10301573Srgrimes *	we added just one char, handle it fast.
10318870Srgrimes *	Assumes that screen cursor == real cursor
10321573Srgrimes */
10331573Srgrimesprotected void
103484260Sobrienre_fastaddc(EditLine *el)
10351573Srgrimes{
103684260Sobrien	char c;
103784260Sobrien	int rhdiff;
10381573Srgrimes
103984260Sobrien	c = (unsigned char)el->el_line.cursor[-1];
10401573Srgrimes
104184260Sobrien	if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
104284260Sobrien		re_refresh(el);	/* too hard to handle */
104384260Sobrien		return;
104484260Sobrien	}
104584260Sobrien	rhdiff = el->el_term.t_size.h - el->el_cursor.h -
104684260Sobrien	    el->el_rprompt.p_pos.h;
104784260Sobrien	if (el->el_rprompt.p_pos.h && rhdiff < 3) {
104884260Sobrien		re_refresh(el);	/* clear out rprompt if less than 1 char gap */
104984260Sobrien		return;
105084260Sobrien	}			/* else (only do at end of line, no TAB) */
105184260Sobrien	if (iscntrl((unsigned char) c)) {	/* if control char, do caret */
105284260Sobrien		char mc = (c == 0177) ? '?' : (toascii(c) | 0100);
105384260Sobrien		re_fastputc(el, '^');
105484260Sobrien		re_fastputc(el, mc);
105584260Sobrien	} else if (isprint((unsigned char) c)) {	/* normal char */
105684260Sobrien		re_fastputc(el, c);
105784260Sobrien	} else {
105884260Sobrien		re_fastputc(el, '\\');
105984260Sobrien		re_fastputc(el, (int) ((((unsigned int) c >> 6) & 7) + '0'));
106084260Sobrien		re_fastputc(el, (int) ((((unsigned int) c >> 3) & 7) + '0'));
106184260Sobrien		re_fastputc(el, (c & 7) + '0');
106284260Sobrien	}
106384260Sobrien	term__flush();
106484260Sobrien}
10651573Srgrimes
10661573Srgrimes
10671573Srgrimes/* re_clear_display():
10688870Srgrimes *	clear the screen buffers so that new new prompt starts fresh.
10691573Srgrimes */
10701573Srgrimesprotected void
107184260Sobrienre_clear_display(EditLine *el)
10721573Srgrimes{
107384260Sobrien	int i;
10741573Srgrimes
107584260Sobrien	el->el_cursor.v = 0;
107684260Sobrien	el->el_cursor.h = 0;
107784260Sobrien	for (i = 0; i < el->el_term.t_size.v; i++)
107884260Sobrien		el->el_display[i][0] = '\0';
107984260Sobrien	el->el_refresh.r_oldcv = 0;
108084260Sobrien}
10811573Srgrimes
10821573Srgrimes
10831573Srgrimes/* re_clear_lines():
10848870Srgrimes *	Make sure all lines are *really* blank
10851573Srgrimes */
10861573Srgrimesprotected void
108784260Sobrienre_clear_lines(EditLine *el)
10881573Srgrimes{
108984260Sobrien
109084260Sobrien	if (EL_CAN_CEOL) {
109184260Sobrien		int i;
109284260Sobrien		term_move_to_char(el, 0);
109384260Sobrien		for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
109484260Sobrien			/* for each line on the screen */
109584260Sobrien			term_move_to_line(el, i);
109684260Sobrien			term_clear_EOL(el, el->el_term.t_size.h);
109784260Sobrien		}
109884260Sobrien		term_move_to_line(el, 0);
109984260Sobrien	} else {
110084260Sobrien		term_move_to_line(el, el->el_refresh.r_oldcv);
110184260Sobrien					/* go to last line */
110284260Sobrien		term__putc('\r');	/* go to BOL */
110384260Sobrien		term__putc('\n');	/* go to new line */
11041573Srgrimes	}
110584260Sobrien}
1106