154229Sbostic /*- 254229Sbostic * Copyright (c) 1992 The Regents of the University of California. 354229Sbostic * 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 11*54624Schristos #if !defined(lint) && !defined(SCCSID) 12*54624Schristos static char sccsid[] = "@(#)refresh.c 5.2 (Berkeley) 07/03/92"; 13*54624Schristos #endif /* not lint && not SCCSID */ 1454229Sbostic 1554229Sbostic /* 16*54624Schristos * 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 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 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 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 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 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*/ 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*/ 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 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 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 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 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 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 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 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 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