154229Sbostic /*-
2*61275Sbostic * Copyright (c) 1992, 1993
3*61275Sbostic * The Regents of the University of California. All rights reserved.
454229Sbostic *
554229Sbostic * This code is derived from software contributed to Berkeley by
654229Sbostic * Christos Zoulas of Cornell University.
754229Sbostic *
854229Sbostic * %sccs.include.redist.c%
954229Sbostic */
1054229Sbostic
1154624Schristos #if !defined(lint) && !defined(SCCSID)
12*61275Sbostic static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 06/04/93";
1354624Schristos #endif /* not lint && not SCCSID */
1454229Sbostic
1554229Sbostic /*
1654624Schristos * refresh.c: Lower level screen refreshing functions
1754229Sbostic */
1854229Sbostic #include "sys.h"
1954229Sbostic #include <stdio.h>
2054229Sbostic #include <ctype.h>
2154229Sbostic #include <unistd.h>
2254229Sbostic #include <string.h>
2354229Sbostic
2454229Sbostic #include "el.h"
2554229Sbostic
2654229Sbostic private void re_addc __P((EditLine *, int));
2754229Sbostic private void re_update_line __P((EditLine *, char *, char *, int));
2854229Sbostic private void re_insert __P((EditLine *, char *, int, int,
2954229Sbostic char *, int));
3054229Sbostic private void re_delete __P((EditLine *, char *, int, int,
3154229Sbostic int));
3254229Sbostic private void re_fastputc __P((EditLine *, int));
3354229Sbostic
3454229Sbostic private void re__strncopy __P((char *, char *, size_t));
3554229Sbostic private void re__copy_and_pad __P((char *, char *, size_t));
3654229Sbostic
3754229Sbostic #ifdef DEBUG_REFRESH
3854229Sbostic private void re_printstr __P((EditLine *, char *, char *,
3954229Sbostic char *));
4054229Sbostic # define __F el->el_errfile
4154229Sbostic # define RE_DEBUG(a, b, c) do \
4254229Sbostic if (a) { \
4354229Sbostic (void) fprintf b; \
4454229Sbostic c; \
4554229Sbostic } \
4654229Sbostic while (0)
4754229Sbostic /* re_printstr():
4854229Sbostic * Print a string on the debugging pty
4954229Sbostic */
5054229Sbostic private void
re_printstr(el,str,f,t)5154229Sbostic re_printstr(el, str, f, t)
5254229Sbostic EditLine *el;
5354229Sbostic char *str;
5454229Sbostic char *f, *t;
5554229Sbostic {
5654229Sbostic RE_DEBUG(1,(__F, "%s:\"", str),);
5754229Sbostic while (f < t)
5854229Sbostic RE_DEBUG(1,(__F, "%c", *f++ & 0177),);
5954229Sbostic RE_DEBUG(1,(__F, "\"\r\n"),);
6054229Sbostic }
6154229Sbostic #else
6254229Sbostic # define RE_DEBUG(a, b, c)
6354229Sbostic #endif
6454229Sbostic
6554229Sbostic
6654229Sbostic /* re_addc():
6754229Sbostic * Draw c, expanding tabs, control chars etc.
6854229Sbostic */
6954229Sbostic private void
re_addc(el,c)7054229Sbostic re_addc(el, c)
7154229Sbostic EditLine *el;
7254229Sbostic int c;
7354229Sbostic {
7454229Sbostic if (isprint(c)) {
7554229Sbostic re_putc(el, c);
7654229Sbostic return;
7754229Sbostic }
7854229Sbostic if (c == '\n') { /* expand the newline */
7954229Sbostic re_putc(el, '\0'); /* assure end of line */
8054229Sbostic el->el_refresh.r_cursor.h = 0; /* reset cursor pos */
8154229Sbostic el->el_refresh.r_cursor.v++;
8254229Sbostic return;
8354229Sbostic }
8454229Sbostic if (c == '\t') { /* expand the tab */
8554229Sbostic for (;;) {
8654229Sbostic re_putc(el, ' ');
8754229Sbostic if ((el->el_refresh.r_cursor.h & 07) == 0)
8854229Sbostic break; /* go until tab stop */
8954229Sbostic }
9054229Sbostic }
9154229Sbostic else if (iscntrl(c)) {
9254229Sbostic re_putc(el, '^');
9354229Sbostic if (c == '\177')
9454229Sbostic re_putc(el, '?');
9554229Sbostic else
9654229Sbostic /* uncontrolify it; works only for iso8859-1 like sets */
9754229Sbostic re_putc(el, (c | 0100));
9854229Sbostic }
9954229Sbostic else {
10054229Sbostic re_putc(el, '\\');
10154229Sbostic re_putc(el, ((c >> 6) & 07) + '0');
10254229Sbostic re_putc(el, ((c >> 3) & 07) + '0');
10354229Sbostic re_putc(el, (c & 07) + '0');
10454229Sbostic }
10554229Sbostic } /* end re_addc */
10654229Sbostic
10754229Sbostic
10854229Sbostic /* re_putc():
10954229Sbostic * Draw the character given
11054229Sbostic */
11154229Sbostic protected void
re_putc(el,c)11254229Sbostic re_putc(el, c)
11354229Sbostic EditLine *el;
11454229Sbostic int c;
11554229Sbostic {
11654229Sbostic RE_DEBUG(1,(__F, "printing %3.3o '%c'\r\n", c, c),);
11754229Sbostic
11854229Sbostic el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c;
11954229Sbostic el->el_refresh.r_cursor.h++; /* advance to next place */
12054229Sbostic if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) {
12154229Sbostic el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] = '\0';
12254229Sbostic /* assure end of line */
12354229Sbostic el->el_refresh.r_cursor.h = 0; /* reset it. */
12454229Sbostic el->el_refresh.r_cursor.v++;
12554229Sbostic RE_DEBUG(el->el_refresh.r_cursor.v >= el->el_term.t_size.v,
12654229Sbostic (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n",
12754229Sbostic el->el_refresh.r_cursor.v, el->el_term.t_size.v), abort());
12854229Sbostic }
12954229Sbostic } /* end re_putc */
13054229Sbostic
13154229Sbostic
13254229Sbostic /* re_refresh():
13354229Sbostic * draws the new virtual screen image from the current input
13454229Sbostic * line, then goes line-by-line changing the real image to the new
13554229Sbostic * virtual image. The routine to re-draw a line can be replaced
13654229Sbostic * easily in hopes of a smarter one being placed there.
13754229Sbostic */
13854229Sbostic protected void
re_refresh(el)13954229Sbostic re_refresh(el)
14054229Sbostic EditLine *el;
14154229Sbostic {
14254229Sbostic int i;
14354229Sbostic char *cp;
14454229Sbostic coord_t cur;
14554229Sbostic
14654229Sbostic RE_DEBUG(1,(__F, "el->el_line.buffer = :%s:\r\n", el->el_line.buffer),);
14754229Sbostic
14854229Sbostic /* reset the Drawing cursor */
14954229Sbostic el->el_refresh.r_cursor.h = 0;
15054229Sbostic el->el_refresh.r_cursor.v = 0;
15154229Sbostic
15254229Sbostic cur.h = -1; /* set flag in case I'm not set */
15354229Sbostic cur.v = 0;
15454229Sbostic
15554229Sbostic prompt_print(el);
15654229Sbostic
15754229Sbostic /* draw the current input buffer */
15854229Sbostic for (cp = el->el_line.buffer; cp < el->el_line.lastchar; cp++) {
15954229Sbostic if (cp == el->el_line.cursor) {
16054229Sbostic cur.h = el->el_refresh.r_cursor.h; /* save for later */
16154229Sbostic cur.v = el->el_refresh.r_cursor.v;
16254229Sbostic }
16354229Sbostic re_addc(el, *cp);
16454229Sbostic }
16554229Sbostic
16654229Sbostic if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */
16754229Sbostic cur.h = el->el_refresh.r_cursor.h;
16854229Sbostic cur.v = el->el_refresh.r_cursor.v;
16954229Sbostic }
17054229Sbostic /* must be done BEFORE the NUL is written */
17154229Sbostic el->el_refresh.r_newcv = el->el_refresh.r_cursor.v;
17254229Sbostic re_putc(el, '\0'); /* put NUL on end */
17354229Sbostic
17454229Sbostic RE_DEBUG(1,(__F,
17554229Sbostic "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n",
17654229Sbostic el->el_term.t_size.h, el->el_refresh.r_cursor.h,
17754229Sbostic el->el_refresh.r_cursor.v, el->el_vdisplay[0]),);
17854229Sbostic
17954229Sbostic RE_DEBUG(1,(__F, "updating %d lines.\r\n", el->el_refresh.r_newcv),);
18054229Sbostic for (i = 0; i <= el->el_refresh.r_newcv; i++) {
18154229Sbostic /* NOTE THAT re_update_line MAY CHANGE el_display[i] */
18254229Sbostic re_update_line(el, el->el_display[i], el->el_vdisplay[i], i);
18354229Sbostic
18454229Sbostic /*
18554229Sbostic * Copy the new line to be the current one, and pad out with spaces
18654229Sbostic * to the full width of the terminal so that if we try moving the
18754229Sbostic * cursor by writing the character that is at the end of the
18854229Sbostic * screen line, it won't be a NUL or some old leftover stuff.
18954229Sbostic */
19054229Sbostic re__copy_and_pad(el->el_display[i], el->el_vdisplay[i],
19154229Sbostic el->el_term.t_size.h);
19254229Sbostic }
19354229Sbostic RE_DEBUG(1,(__F,
19454229Sbostic "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n",
19554229Sbostic el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i),);
19654229Sbostic
19754229Sbostic if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv)
19854229Sbostic for (; i <= el->el_refresh.r_oldcv; i++) {
19954229Sbostic term_move_to_line(el, i);
20054229Sbostic term_move_to_char(el, 0);
20154229Sbostic term_clear_EOL(el, strlen(el->el_display[i]));
20254229Sbostic #ifdef DEBUG_REFRESH
20354229Sbostic term_overwrite(el, "C\b", 2);
20454229Sbostic #endif /* DEBUG_REFRESH */
20554229Sbostic *el->el_display[i] = '\0';
20654229Sbostic }
20754229Sbostic
20854229Sbostic el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */
20954229Sbostic RE_DEBUG(1,(__F,
21054229Sbostic "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n",
21154229Sbostic el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v,
21254229Sbostic cur.h, cur.v),);
21354229Sbostic term_move_to_line(el, cur.v); /* go to where the cursor is */
21454229Sbostic term_move_to_char(el, cur.h);
21554229Sbostic } /* end re_refresh */
21654229Sbostic
21754229Sbostic
21854229Sbostic /* re_goto_bottom():
21954229Sbostic * used to go to last used screen line
22054229Sbostic */
22154229Sbostic protected void
re_goto_bottom(el)22254229Sbostic re_goto_bottom(el)
22354229Sbostic EditLine *el;
22454229Sbostic {
22554229Sbostic term_move_to_line(el, el->el_refresh.r_oldcv);
22654229Sbostic term__putc('\r');
22754229Sbostic term__putc('\n');
22854229Sbostic re_clear_display(el);
22954229Sbostic term__flush();
23054229Sbostic } /* end re_goto_bottom */
23154229Sbostic
23254229Sbostic
23354229Sbostic /* re_insert():
23454229Sbostic * insert num characters of s into d (in front of the character)
23554229Sbostic * at dat, maximum length of d is dlen
23654229Sbostic */
23754229Sbostic private void
23854229Sbostic /*ARGSUSED*/
re_insert(el,d,dat,dlen,s,num)23954229Sbostic re_insert(el, d, dat, dlen, s, num)
24054229Sbostic EditLine *el;
24154229Sbostic char *d;
24254229Sbostic int dat, dlen;
24354229Sbostic char *s;
24454229Sbostic int num;
24554229Sbostic {
24654229Sbostic char *a, *b;
24754229Sbostic
24854229Sbostic if (num <= 0)
24954229Sbostic return;
25054229Sbostic if (num > dlen - dat)
25154229Sbostic num = dlen - dat;
25254229Sbostic
25354229Sbostic RE_DEBUG(1,(__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n",
25454229Sbostic num, dat, dlen, d),);
25554229Sbostic RE_DEBUG(1,(__F, "s == \"%s\"n", s),);
25654229Sbostic
25754229Sbostic /* open up the space for num chars */
25854229Sbostic if (num > 0) {
25954229Sbostic b = d + dlen - 1;
26054229Sbostic a = b - num;
26154229Sbostic while (a >= &d[dat])
26254229Sbostic *b-- = *a--;
26354229Sbostic d[dlen] = '\0'; /* just in case */
26454229Sbostic }
26554229Sbostic RE_DEBUG(1,(__F,
26654229Sbostic "re_insert() after insert: %d at %d max %d, d == \"%s\"\n",
26754229Sbostic num, dat, dlen, d),);
26854229Sbostic RE_DEBUG(1,(__F, "s == \"%s\"n", s),);
26954229Sbostic
27054229Sbostic /* copy the characters */
27154229Sbostic for (a = d + dat; (a < d + dlen) && (num > 0); num--)
27254229Sbostic *a++ = *s++;
27354229Sbostic
27454229Sbostic RE_DEBUG(1,(__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n",
27554229Sbostic num, dat, dlen, d, s),);
27654229Sbostic RE_DEBUG(1,(__F, "s == \"%s\"n", s),);
27754229Sbostic } /* end re_insert */
27854229Sbostic
27954229Sbostic
28054229Sbostic /* re_delete():
28154229Sbostic * delete num characters d at dat, maximum length of d is dlen
28254229Sbostic */
28354229Sbostic private void
28454229Sbostic /*ARGSUSED*/
re_delete(el,d,dat,dlen,num)28554229Sbostic re_delete(el, d, dat, dlen, num)
28654229Sbostic EditLine *el;
28754229Sbostic char *d;
28854229Sbostic int dat, dlen, num;
28954229Sbostic {
29054229Sbostic char *a, *b;
29154229Sbostic
29254229Sbostic if (num <= 0)
29354229Sbostic return;
29454229Sbostic if (dat + num >= dlen) {
29554229Sbostic d[dat] = '\0';
29654229Sbostic return;
29754229Sbostic }
29854229Sbostic
29954229Sbostic RE_DEBUG(1,(__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n",
30054229Sbostic num, dat, dlen, d),);
30154229Sbostic
30254229Sbostic /* open up the space for num chars */
30354229Sbostic if (num > 0) {
30454229Sbostic b = d + dat;
30554229Sbostic a = b + num;
30654229Sbostic while (a < &d[dlen])
30754229Sbostic *b++ = *a++;
30854229Sbostic d[dlen] = '\0'; /* just in case */
30954229Sbostic }
31054229Sbostic RE_DEBUG(1,(__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n",
31154229Sbostic num, dat, dlen, d),);
31254229Sbostic } /* end re_delete */
31354229Sbostic
31454229Sbostic
31554229Sbostic /* re__strncopy():
31654229Sbostic * Like strncpy without padding.
31754229Sbostic */
31854229Sbostic private void
re__strncopy(a,b,n)31954229Sbostic re__strncopy(a, b, n)
32054229Sbostic char *a, *b;
32154229Sbostic size_t n;
32254229Sbostic {
32354229Sbostic while (n-- && *b)
32454229Sbostic *a++ = *b++;
32554229Sbostic } /* end re__strncopy */
32654229Sbostic
32754229Sbostic
32854229Sbostic /* ****************************************************************
32954229Sbostic re_update_line() is based on finding the middle difference of each line
33054229Sbostic on the screen; vis:
33154229Sbostic
33254229Sbostic /old first difference
33354229Sbostic /beginning of line | /old last same /old EOL
33454229Sbostic v v v v
33554229Sbostic old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as
33654229Sbostic new: eddie> Oh, my little buggy says to me, as lurgid as
33754229Sbostic ^ ^ ^ ^
33854229Sbostic \beginning of line | \new last same \new end of line
33954229Sbostic \new first difference
34054229Sbostic
34154229Sbostic all are character pointers for the sake of speed. Special cases for
34254229Sbostic no differences, as well as for end of line additions must be handled.
34354229Sbostic **************************************************************** */
34454229Sbostic
34554229Sbostic /* Minimum at which doing an insert it "worth it". This should be about
34654229Sbostic * half the "cost" of going into insert mode, inserting a character, and
34754229Sbostic * going back out. This should really be calculated from the termcap
34854229Sbostic * data... For the moment, a good number for ANSI terminals.
34954229Sbostic */
35054229Sbostic #define MIN_END_KEEP 4
35154229Sbostic
35254229Sbostic private void
re_update_line(el,old,new,i)35354229Sbostic re_update_line(el, old, new, i)
35454229Sbostic EditLine *el;
35554229Sbostic char *old, *new;
35654229Sbostic int i;
35754229Sbostic {
35854229Sbostic char *o, *n, *p, c;
35954229Sbostic char *ofd, *ols, *oe, *nfd, *nls, *ne;
36054229Sbostic char *osb, *ose, *nsb, *nse;
36154229Sbostic int fx, sx;
36254229Sbostic
36354229Sbostic /*
36454229Sbostic * find first diff
36554229Sbostic */
36654229Sbostic for (o = old, n = new; *o && (*o == *n); o++, n++)
36754229Sbostic continue;
36854229Sbostic ofd = o;
36954229Sbostic nfd = n;
37054229Sbostic
37154229Sbostic /*
37254229Sbostic * Find the end of both old and new
37354229Sbostic */
37454229Sbostic while (*o)
37554229Sbostic o++;
37654229Sbostic /*
37754229Sbostic * Remove any trailing blanks off of the end, being careful not to
37854229Sbostic * back up past the beginning.
37954229Sbostic */
38054229Sbostic while (ofd < o) {
38154229Sbostic if (o[-1] != ' ')
38254229Sbostic break;
38354229Sbostic o--;
38454229Sbostic }
38554229Sbostic oe = o;
38654229Sbostic *oe = '\0';
38754229Sbostic
38854229Sbostic while (*n)
38954229Sbostic n++;
39054229Sbostic
39154229Sbostic /* remove blanks from end of new */
39254229Sbostic while (nfd < n) {
39354229Sbostic if (n[-1] != ' ')
39454229Sbostic break;
39554229Sbostic n--;
39654229Sbostic }
39754229Sbostic ne = n;
39854229Sbostic *ne = '\0';
39954229Sbostic
40054229Sbostic /*
40154229Sbostic * if no diff, continue to next line of redraw
40254229Sbostic */
40354229Sbostic if (*ofd == '\0' && *nfd == '\0') {
40454229Sbostic RE_DEBUG(1,(__F, "no difference.\r\n"),);
40554229Sbostic return;
40654229Sbostic }
40754229Sbostic
40854229Sbostic /*
40954229Sbostic * find last same pointer
41054229Sbostic */
41154229Sbostic while ((o > ofd) && (n > nfd) && (*--o == *--n))
41254229Sbostic continue;
41354229Sbostic ols = ++o;
41454229Sbostic nls = ++n;
41554229Sbostic
41654229Sbostic /*
41754229Sbostic * find same begining and same end
41854229Sbostic */
41954229Sbostic osb = ols;
42054229Sbostic nsb = nls;
42154229Sbostic ose = ols;
42254229Sbostic nse = nls;
42354229Sbostic
42454229Sbostic /*
42554229Sbostic * case 1: insert: scan from nfd to nls looking for *ofd
42654229Sbostic */
42754229Sbostic if (*ofd) {
42854229Sbostic for (c = *ofd, n = nfd; n < nls; n++) {
42954229Sbostic if (c == *n) {
43054229Sbostic for (o = ofd, p = n; p < nls && o < ols && *o == *p; o++, p++)
43154229Sbostic continue;
43254229Sbostic /*
43354229Sbostic * if the new match is longer and it's worth keeping, then we
43454229Sbostic * take it
43554229Sbostic */
43654229Sbostic if (((nse - nsb) < (p - n)) && (2 * (p - n) > n - nfd)) {
43754229Sbostic nsb = n;
43854229Sbostic nse = p;
43954229Sbostic osb = ofd;
44054229Sbostic ose = o;
44154229Sbostic }
44254229Sbostic }
44354229Sbostic }
44454229Sbostic }
44554229Sbostic
44654229Sbostic /*
44754229Sbostic * case 2: delete: scan from ofd to ols looking for *nfd
44854229Sbostic */
44954229Sbostic if (*nfd) {
45054229Sbostic for (c = *nfd, o = ofd; o < ols; o++) {
45154229Sbostic if (c == *o) {
45254229Sbostic for (n = nfd, p = o; p < ols && n < nls && *p == *n; p++, n++)
45354229Sbostic continue;
45454229Sbostic /*
45554229Sbostic * if the new match is longer and it's worth keeping, then we
45654229Sbostic * take it
45754229Sbostic */
45854229Sbostic if (((ose - osb) < (p - o)) && (2 * (p - o) > o - ofd)) {
45954229Sbostic nsb = nfd;
46054229Sbostic nse = n;
46154229Sbostic osb = o;
46254229Sbostic ose = p;
46354229Sbostic }
46454229Sbostic }
46554229Sbostic }
46654229Sbostic }
46754229Sbostic
46854229Sbostic /*
46954229Sbostic * Pragmatics I: If old trailing whitespace or not enough characters to
47054229Sbostic * save to be worth it, then don't save the last same info.
47154229Sbostic */
47254229Sbostic if ((oe - ols) < MIN_END_KEEP) {
47354229Sbostic ols = oe;
47454229Sbostic nls = ne;
47554229Sbostic }
47654229Sbostic
47754229Sbostic /*
47854229Sbostic * Pragmatics II: if the terminal isn't smart enough, make the data dumber
47954229Sbostic * so the smart update doesn't try anything fancy
48054229Sbostic */
48154229Sbostic
48254229Sbostic /*
48354229Sbostic * fx is the number of characters we need to insert/delete: in the
48454229Sbostic * beginning to bring the two same begins together
48554229Sbostic */
48654229Sbostic fx = (nsb - nfd) - (osb - ofd);
48754229Sbostic /*
48854229Sbostic * sx is the number of characters we need to insert/delete: in the end to
48954229Sbostic * bring the two same last parts together
49054229Sbostic */
49154229Sbostic sx = (nls - nse) - (ols - ose);
49254229Sbostic
49354229Sbostic if (!EL_CAN_INSERT) {
49454229Sbostic if (fx > 0) {
49554229Sbostic osb = ols;
49654229Sbostic ose = ols;
49754229Sbostic nsb = nls;
49854229Sbostic nse = nls;
49954229Sbostic }
50054229Sbostic if (sx > 0) {
50154229Sbostic ols = oe;
50254229Sbostic nls = ne;
50354229Sbostic }
50454229Sbostic if ((ols - ofd) < (nls - nfd)) {
50554229Sbostic ols = oe;
50654229Sbostic nls = ne;
50754229Sbostic }
50854229Sbostic }
50954229Sbostic if (!EL_CAN_DELETE) {
51054229Sbostic if (fx < 0) {
51154229Sbostic osb = ols;
51254229Sbostic ose = ols;
51354229Sbostic nsb = nls;
51454229Sbostic nse = nls;
51554229Sbostic }
51654229Sbostic if (sx < 0) {
51754229Sbostic ols = oe;
51854229Sbostic nls = ne;
51954229Sbostic }
52054229Sbostic if ((ols - ofd) > (nls - nfd)) {
52154229Sbostic ols = oe;
52254229Sbostic nls = ne;
52354229Sbostic }
52454229Sbostic }
52554229Sbostic
52654229Sbostic /*
52754229Sbostic * Pragmatics III: make sure the middle shifted pointers are correct if
52854229Sbostic * they don't point to anything (we may have moved ols or nls).
52954229Sbostic */
53054229Sbostic /* if the change isn't worth it, don't bother */
53154229Sbostic /* was: if (osb == ose) */
53254229Sbostic if ((ose - osb) < MIN_END_KEEP) {
53354229Sbostic osb = ols;
53454229Sbostic ose = ols;
53554229Sbostic nsb = nls;
53654229Sbostic nse = nls;
53754229Sbostic }
53854229Sbostic
53954229Sbostic /*
54054229Sbostic * Now that we are done with pragmatics we recompute fx, sx
54154229Sbostic */
54254229Sbostic fx = (nsb - nfd) - (osb - ofd);
54354229Sbostic sx = (nls - nse) - (ols - ose);
54454229Sbostic
54554229Sbostic RE_DEBUG(1,(__F, "\n"),);
54654229Sbostic RE_DEBUG(1,(__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n",
54754229Sbostic ofd - old, osb - old, ose - old, ols - old, oe - old),);
54854229Sbostic RE_DEBUG(1,(__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n",
54954229Sbostic nfd - new, nsb - new, nse - new, nls - new, ne - new),);
55054229Sbostic RE_DEBUG(1,(__F,
55154229Sbostic "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n"),);
55254229Sbostic RE_DEBUG(1,(__F,
55354229Sbostic "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n"),);
55454229Sbostic #ifdef DEBUG_REFRESH
55554229Sbostic re_printstr(el, "old- oe", old, oe);
55654229Sbostic re_printstr(el, "new- ne", new, ne);
55754229Sbostic re_printstr(el, "old-ofd", old, ofd);
55854229Sbostic re_printstr(el, "new-nfd", new, nfd);
55954229Sbostic re_printstr(el, "ofd-osb", ofd, osb);
56054229Sbostic re_printstr(el, "nfd-nsb", nfd, nsb);
56154229Sbostic re_printstr(el, "osb-ose", osb, ose);
56254229Sbostic re_printstr(el, "nsb-nse", nsb, nse);
56354229Sbostic re_printstr(el, "ose-ols", ose, ols);
56454229Sbostic re_printstr(el, "nse-nls", nse, nls);
56554229Sbostic re_printstr(el, "ols- oe", ols, oe);
56654229Sbostic re_printstr(el, "nls- ne", nls, ne);
56754229Sbostic #endif /* DEBUG_REFRESH */
56854229Sbostic
56954229Sbostic /*
57054229Sbostic * el_cursor.v to this line i MUST be in this routine so that if we
57154229Sbostic * don't have to change the line, we don't move to it. el_cursor.h to first
57254229Sbostic * diff char
57354229Sbostic */
57454229Sbostic term_move_to_line(el, i);
57554229Sbostic
57654229Sbostic /*
57754229Sbostic * at this point we have something like this:
57854229Sbostic *
57954229Sbostic * /old /ofd /osb /ose /ols /oe
58054229Sbostic * v.....................v v..................v v........v
58154229Sbostic * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as
58254229Sbostic * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as
58354229Sbostic * ^.....................^ ^..................^ ^........^
58454229Sbostic * \new \nfd \nsb \nse \nls \ne
58554229Sbostic *
58654229Sbostic * fx is the difference in length between the the chars between nfd and
58754229Sbostic * nsb, and the chars between ofd and osb, and is thus the number of
58854229Sbostic * characters to delete if < 0 (new is shorter than old, as above),
58954229Sbostic * or insert (new is longer than short).
59054229Sbostic *
59154229Sbostic * sx is the same for the second differences.
59254229Sbostic */
59354229Sbostic
59454229Sbostic /*
59554229Sbostic * if we have a net insert on the first difference, AND inserting the net
59654229Sbostic * amount ((nsb-nfd) - (osb-ofd)) won't push the last useful character
59754229Sbostic * (which is ne if nls != ne, otherwise is nse) off the edge of the screen
59854229Sbostic * (el->el_term.t_size.h) else we do the deletes first so that we keep everything we need
59954229Sbostic * to.
60054229Sbostic */
60154229Sbostic
60254229Sbostic /*
60354229Sbostic * if the last same is the same like the end, there is no last same part,
60454229Sbostic * otherwise we want to keep the last same part set p to the last useful
60554229Sbostic * old character
60654229Sbostic */
60754229Sbostic p = (ols != oe) ? oe : ose;
60854229Sbostic
60954229Sbostic /*
61054229Sbostic * if (There is a diffence in the beginning) && (we need to insert
61154229Sbostic * characters) && (the number of characters to insert is less than the term
61254229Sbostic * width) We need to do an insert! else if (we need to delete characters)
61354229Sbostic * We need to delete characters! else No insert or delete
61454229Sbostic */
61554229Sbostic if ((nsb != nfd) && fx > 0 && ((p - old) + fx <= el->el_term.t_size.h)) {
61654229Sbostic RE_DEBUG(1,(__F, "first diff insert at %d...\r\n", nfd - new),);
61754229Sbostic /*
61854229Sbostic * Move to the first char to insert, where the first diff is.
61954229Sbostic */
62054229Sbostic term_move_to_char(el, nfd - new);
62154229Sbostic /*
62254229Sbostic * Check if we have stuff to keep at end
62354229Sbostic */
62454229Sbostic if (nsb != ne) {
62554229Sbostic RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),);
62654229Sbostic /*
62754229Sbostic * insert fx chars of new starting at nfd
62854229Sbostic */
62954229Sbostic if (fx > 0) {
63054229Sbostic RE_DEBUG(!EL_CAN_INSERT,
63154229Sbostic (__F, "ERROR: cannot insert in early first diff\n"),);
63254229Sbostic term_insertwrite(el, nfd, fx);
63354229Sbostic re_insert(el, old, ofd - old, el->el_term.t_size.h, nfd, fx);
63454229Sbostic }
63554229Sbostic /*
63654229Sbostic * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
63754229Sbostic */
63854229Sbostic term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
63954229Sbostic re__strncopy(ofd + fx, nfd + fx, (nsb - nfd) - fx);
64054229Sbostic }
64154229Sbostic else {
64254229Sbostic RE_DEBUG(1,(__F, "without anything to save\r\n"),);
64354229Sbostic term_overwrite(el, nfd, (nsb - nfd));
64454229Sbostic re__strncopy(ofd, nfd, (nsb - nfd));
64554229Sbostic /*
64654229Sbostic * Done
64754229Sbostic */
64854229Sbostic return;
64954229Sbostic }
65054229Sbostic }
65154229Sbostic else if (fx < 0) {
65254229Sbostic RE_DEBUG(1,(__F, "first diff delete at %d...\r\n", ofd - old),);
65354229Sbostic /*
65454229Sbostic * move to the first char to delete where the first diff is
65554229Sbostic */
65654229Sbostic term_move_to_char(el, ofd - old);
65754229Sbostic /*
65854229Sbostic * Check if we have stuff to save
65954229Sbostic */
66054229Sbostic if (osb != oe) {
66154229Sbostic RE_DEBUG(1,(__F, "with stuff to save at end\r\n"),);
66254229Sbostic /*
66354229Sbostic * fx is less than zero *always* here but we check for code
66454229Sbostic * symmetry
66554229Sbostic */
66654229Sbostic if (fx < 0) {
66754229Sbostic RE_DEBUG(!EL_CAN_DELETE,
66854229Sbostic (__F, "ERROR: cannot delete in first diff\n"),);
66954229Sbostic term_deletechars(el, -fx);
67054229Sbostic re_delete(el, old, ofd - old, el->el_term.t_size.h, -fx);
67154229Sbostic }
67254229Sbostic /*
67354229Sbostic * write (nsb-nfd) chars of new starting at nfd
67454229Sbostic */
67554229Sbostic term_overwrite(el, nfd, (nsb - nfd));
67654229Sbostic re__strncopy(ofd, nfd, (nsb - nfd));
67754229Sbostic
67854229Sbostic }
67954229Sbostic else {
68054229Sbostic RE_DEBUG(1,(__F, "but with nothing left to save\r\n"),);
68154229Sbostic /*
68254229Sbostic * write (nsb-nfd) chars of new starting at nfd
68354229Sbostic */
68454229Sbostic term_overwrite(el, nfd, (nsb - nfd));
68554229Sbostic RE_DEBUG(1,(__F, "cleareol %d\n", (oe - old) - (ne - new)),);
68654229Sbostic term_clear_EOL(el, (oe - old) - (ne - new));
68754229Sbostic /*
68854229Sbostic * Done
68954229Sbostic */
69054229Sbostic return;
69154229Sbostic }
69254229Sbostic }
69354229Sbostic else
69454229Sbostic fx = 0;
69554229Sbostic
69654229Sbostic if (sx < 0) {
69754229Sbostic RE_DEBUG(1,(__F, "second diff delete at %d...\r\n", (ose - old) + fx),);
69854229Sbostic /*
69954229Sbostic * Check if we have stuff to delete
70054229Sbostic */
70154229Sbostic /*
70254229Sbostic * fx is the number of characters inserted (+) or deleted (-)
70354229Sbostic */
70454229Sbostic
70554229Sbostic term_move_to_char(el, (ose - old) + fx);
70654229Sbostic /*
70754229Sbostic * Check if we have stuff to save
70854229Sbostic */
70954229Sbostic if (ols != oe) {
71054229Sbostic RE_DEBUG(1,(__F, "with stuff to save at end\r\n"),);
71154229Sbostic /*
71254229Sbostic * Again a duplicate test.
71354229Sbostic */
71454229Sbostic if (sx < 0) {
71554229Sbostic RE_DEBUG(!EL_CAN_DELETE,
71654229Sbostic (__F, "ERROR: cannot delete in second diff\n"),);
71754229Sbostic term_deletechars(el, -sx);
71854229Sbostic }
71954229Sbostic
72054229Sbostic /*
72154229Sbostic * write (nls-nse) chars of new starting at nse
72254229Sbostic */
72354229Sbostic term_overwrite(el, nse, (nls - nse));
72454229Sbostic }
72554229Sbostic else {
72654229Sbostic RE_DEBUG(1,(__F, "but with nothing left to save\r\n"),);
72754229Sbostic term_overwrite(el, nse, (nls - nse));
72854229Sbostic RE_DEBUG(1,(__F, "cleareol %d\n", (oe - old) - (ne - new)),);
72954229Sbostic term_clear_EOL(el, (oe - old) - (ne - new));
73054229Sbostic }
73154229Sbostic }
73254229Sbostic
73354229Sbostic /*
73454229Sbostic * if we have a first insert AND WE HAVEN'T ALREADY DONE IT...
73554229Sbostic */
73654229Sbostic if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) {
73754229Sbostic RE_DEBUG(1,(__F, "late first diff insert at %d...\r\n", nfd - new),);
73854229Sbostic
73954229Sbostic term_move_to_char(el, nfd - new);
74054229Sbostic /*
74154229Sbostic * Check if we have stuff to keep at the end
74254229Sbostic */
74354229Sbostic if (nsb != ne) {
74454229Sbostic RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),);
74554229Sbostic /*
74654229Sbostic * We have to recalculate fx here because we set it
74754229Sbostic * to zero above as a flag saying that we hadn't done
74854229Sbostic * an early first insert.
74954229Sbostic */
75054229Sbostic fx = (nsb - nfd) - (osb - ofd);
75154229Sbostic if (fx > 0) {
75254229Sbostic /*
75354229Sbostic * insert fx chars of new starting at nfd
75454229Sbostic */
75554229Sbostic RE_DEBUG(!EL_CAN_INSERT,
75654229Sbostic (__F, "ERROR: cannot insert in late first diff\n"),);
75754229Sbostic term_insertwrite(el, nfd, fx);
75854229Sbostic re_insert(el, old, ofd - old, el->el_term.t_size.h, nfd, fx);
75954229Sbostic }
76054229Sbostic
76154229Sbostic /*
76254229Sbostic * write (nsb-nfd) - fx chars of new starting at (nfd + fx)
76354229Sbostic */
76454229Sbostic term_overwrite(el, nfd + fx, (nsb - nfd) - fx);
76554229Sbostic re__strncopy(ofd + fx, nfd + fx, (nsb - nfd) - fx);
76654229Sbostic }
76754229Sbostic else {
76854229Sbostic RE_DEBUG(1,(__F, "without anything to save\r\n"),);
76954229Sbostic term_overwrite(el, nfd, (nsb - nfd));
77054229Sbostic re__strncopy(ofd, nfd, (nsb - nfd));
77154229Sbostic }
77254229Sbostic }
77354229Sbostic
77454229Sbostic /*
77554229Sbostic * line is now NEW up to nse
77654229Sbostic */
77754229Sbostic if (sx >= 0) {
77854229Sbostic RE_DEBUG(1,(__F, "second diff insert at %d...\r\n", nse - new),);
77954229Sbostic term_move_to_char(el, nse - new);
78054229Sbostic if (ols != oe) {
78154229Sbostic RE_DEBUG(1,(__F, "with stuff to keep at end\r\n"),);
78254229Sbostic if (sx > 0) {
78354229Sbostic /* insert sx chars of new starting at nse */
78454229Sbostic RE_DEBUG(!EL_CAN_INSERT,
78554229Sbostic (__F, "ERROR: cannot insert in second diff\n"),);
78654229Sbostic term_insertwrite(el, nse, sx);
78754229Sbostic }
78854229Sbostic
78954229Sbostic /*
79054229Sbostic * write (nls-nse) - sx chars of new starting at (nse + sx)
79154229Sbostic */
79254229Sbostic term_overwrite(el, nse + sx, (nls - nse) - sx);
79354229Sbostic }
79454229Sbostic else {
79554229Sbostic RE_DEBUG(1,(__F, "without anything to save\r\n"),);
79654229Sbostic term_overwrite(el, nse, (nls - nse));
79754229Sbostic
79854229Sbostic /*
79954229Sbostic * No need to do a clear-to-end here because we were doing
80054229Sbostic * a second insert, so we will have over written all of the
80154229Sbostic * old string.
80254229Sbostic */
80354229Sbostic }
80454229Sbostic }
80554229Sbostic RE_DEBUG(1,(__F, "done.\r\n"),);
80654229Sbostic } /* re_update_line */
80754229Sbostic
80854229Sbostic
80954229Sbostic /* re__copy_and_pad():
81054229Sbostic * Copy string and pad with spaces
81154229Sbostic */
81254229Sbostic private void
re__copy_and_pad(dst,src,width)81354229Sbostic re__copy_and_pad(dst, src, width)
81454229Sbostic char *dst, *src;
81554229Sbostic size_t width;
81654229Sbostic {
81754229Sbostic int i;
81854229Sbostic
81954229Sbostic for (i = 0; i < width; i++) {
82054229Sbostic if (*src == '\0')
82154229Sbostic break;
82254229Sbostic *dst++ = *src++;
82354229Sbostic }
82454229Sbostic
82554229Sbostic while (i < width) {
82654229Sbostic *dst++ = ' ';
82754229Sbostic i++;
82854229Sbostic }
82954229Sbostic *dst = '\0';
83054229Sbostic } /* end re__copy_and_pad */
83154229Sbostic
83254229Sbostic
83354229Sbostic /* re_refresh_cursor():
83454229Sbostic * Move to the new cursor position
83554229Sbostic */
83654229Sbostic protected void
re_refresh_cursor(el)83754229Sbostic re_refresh_cursor(el)
83854229Sbostic EditLine *el;
83954229Sbostic {
84054229Sbostic char *cp, c;
84154229Sbostic int h, v, th;
84254229Sbostic
84354229Sbostic /* first we must find where the cursor is... */
84454229Sbostic h = el->el_prompt.p_pos.h;
84554229Sbostic v = el->el_prompt.p_pos.v;
84654229Sbostic th = el->el_term.t_size.h; /* optimize for speed */
84754229Sbostic
84854229Sbostic /* do input buffer to el->el_line.cursor */
84954229Sbostic for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) {
85054229Sbostic c = *cp;
85154229Sbostic h++; /* all chars at least this long */
85254229Sbostic
85354229Sbostic if (c == '\n') { /* handle newline in data part too */
85454229Sbostic h = 0;
85554229Sbostic v++;
85654229Sbostic }
85754229Sbostic else {
85854229Sbostic if (c == '\t') { /* if a tab, to next tab stop */
85954229Sbostic while (h & 07) {
86054229Sbostic h++;
86154229Sbostic }
86254229Sbostic }
86354229Sbostic else if (iscntrl(c)) { /* if control char */
86454229Sbostic h++;
86554229Sbostic if (h > th) { /* if overflow, compensate */
86654229Sbostic h = 1;
86754229Sbostic v++;
86854229Sbostic }
86954229Sbostic }
87054229Sbostic else if (!isprint(c)) {
87154229Sbostic h += 3;
87254229Sbostic if (h > th) { /* if overflow, compensate */
87354229Sbostic h = h - th;
87454229Sbostic v++;
87554229Sbostic }
87654229Sbostic }
87754229Sbostic }
87854229Sbostic
87954229Sbostic if (h >= th) { /* check, extra long tabs picked up here also */
88054229Sbostic h = 0;
88154229Sbostic v++;
88254229Sbostic }
88354229Sbostic }
88454229Sbostic
88554229Sbostic /* now go there */
88654229Sbostic term_move_to_line(el, v);
88754229Sbostic term_move_to_char(el, h);
88854229Sbostic term__flush();
88954229Sbostic } /* re_refresh_cursor */
89054229Sbostic
89154229Sbostic
89254229Sbostic /* re_fastputc():
89354229Sbostic * Add a character fast.
89454229Sbostic */
89554229Sbostic private void
re_fastputc(el,c)89654229Sbostic re_fastputc(el, c)
89754229Sbostic EditLine *el;
89854229Sbostic int c;
89954229Sbostic {
90054229Sbostic term__putc(c);
90154229Sbostic el->el_display[el->el_cursor.v][el->el_cursor.h++] = c;
90254229Sbostic if (el->el_cursor.h >= el->el_term.t_size.h) {
90354229Sbostic /* if we must overflow */
90454229Sbostic el->el_cursor.h = 0;
90554229Sbostic el->el_cursor.v++;
90654229Sbostic el->el_refresh.r_oldcv++;
90754229Sbostic term__putc('\r');
90854229Sbostic term__putc('\n');
90954229Sbostic }
91054229Sbostic } /* end re_fastputc */
91154229Sbostic
91254229Sbostic
91354229Sbostic /* re_fastaddc():
91454229Sbostic * we added just one char, handle it fast.
91554229Sbostic * Assumes that screen cursor == real cursor
91654229Sbostic */
91754229Sbostic protected void
re_fastaddc(el)91854229Sbostic re_fastaddc(el)
91954229Sbostic EditLine *el;
92054229Sbostic {
92154229Sbostic char c;
92254229Sbostic
92354229Sbostic c = el->el_line.cursor[-1];
92454229Sbostic
92554229Sbostic if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) {
92654229Sbostic re_refresh(el); /* too hard to handle */
92754229Sbostic return;
92854229Sbostic } /* else (only do at end of line, no TAB) */
92954229Sbostic
93054229Sbostic if (iscntrl(c)) { /* if control char, do caret */
93154229Sbostic char mc = (c == '\177') ? '?' : (c | 0100);
93254229Sbostic re_fastputc(el, '^');
93354229Sbostic re_fastputc(el, mc);
93454229Sbostic }
93554229Sbostic else if (isprint(c)) { /* normal char */
93654229Sbostic re_fastputc(el, c);
93754229Sbostic }
93854229Sbostic else {
93954229Sbostic re_fastputc(el, '\\');
94054229Sbostic re_fastputc(el, ((c >> 6) & 7) + '0');
94154229Sbostic re_fastputc(el, ((c >> 3) & 7) + '0');
94254229Sbostic re_fastputc(el, (c & 7) + '0');
94354229Sbostic }
94454229Sbostic term__flush();
94554229Sbostic } /* end re_fastaddc */
94654229Sbostic
94754229Sbostic
94854229Sbostic /* re_clear_display():
94954229Sbostic * clear the screen buffers so that new new prompt starts fresh.
95054229Sbostic */
95154229Sbostic protected void
re_clear_display(el)95254229Sbostic re_clear_display(el)
95354229Sbostic EditLine *el;
95454229Sbostic {
95554229Sbostic int i;
95654229Sbostic
95754229Sbostic el->el_cursor.v = 0;
95854229Sbostic el->el_cursor.h = 0;
95954229Sbostic for (i = 0; i < el->el_term.t_size.v; i++)
96054229Sbostic el->el_display[i][0] = '\0';
96154229Sbostic el->el_refresh.r_oldcv = 0;
96254229Sbostic } /* end re_clear_display */
96354229Sbostic
96454229Sbostic
96554229Sbostic /* re_clear_lines():
96654229Sbostic * Make sure all lines are *really* blank
96754229Sbostic */
96854229Sbostic protected void
re_clear_lines(el)96954229Sbostic re_clear_lines(el)
97054229Sbostic EditLine *el;
97154229Sbostic {
97254229Sbostic if (EL_CAN_CEOL) {
97354229Sbostic int i;
97454229Sbostic term_move_to_char(el, 0);
97554229Sbostic for (i = 0; i <= el->el_refresh.r_oldcv; i++) {
97654229Sbostic /* for each line on the screen */
97754229Sbostic term_move_to_line(el, i);
97854229Sbostic term_clear_EOL(el, el->el_term.t_size.h);
97954229Sbostic }
98054229Sbostic term_move_to_line(el, 0);
98154229Sbostic }
98254229Sbostic else {
98354229Sbostic term_move_to_line(el, el->el_refresh.r_oldcv); /* go to last line */
98454229Sbostic term__putc('\r'); /* go to BOL */
98554229Sbostic term__putc('\n'); /* go to new line */
98654229Sbostic }
98754229Sbostic } /* end re_clear_lines */
988