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