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. 16148834Sstefanf * 3. Neither the name of the University nor the names of its contributors 171573Srgrimes * may be used to endorse or promote products derived from this software 181573Srgrimes * without specific prior written permission. 191573Srgrimes * 201573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301573Srgrimes * SUCH DAMAGE. 3184260Sobrien * 32237448Spfg * $NetBSD: refresh.c,v 1.34 2009/12/28 22:15:36 christos Exp $ 331573Srgrimes */ 341573Srgrimes 351573Srgrimes#if !defined(lint) && !defined(SCCSID) 361573Srgrimesstatic char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; 371573Srgrimes#endif /* not lint && not SCCSID */ 3884260Sobrien#include <sys/cdefs.h> 3984260Sobrien__FBSDID("$FreeBSD$"); 401573Srgrimes 411573Srgrimes/* 421573Srgrimes * refresh.c: Lower level screen refreshing functions 431573Srgrimes */ 441573Srgrimes#include "sys.h" 451573Srgrimes#include <stdio.h> 46148834Sstefanf#include <ctype.h> 471573Srgrimes#include <unistd.h> 481573Srgrimes#include <string.h> 491573Srgrimes 501573Srgrimes#include "el.h" 511573Srgrimes 52237448Spfgprivate void re_nextline(EditLine *); 5384260Sobrienprivate void re_addc(EditLine *, int); 5484260Sobrienprivate void re_update_line(EditLine *, char *, char *, int); 5584260Sobrienprivate void re_insert (EditLine *, char *, int, int, char *, int); 5684260Sobrienprivate void re_delete(EditLine *, char *, int, int, int); 5784260Sobrienprivate void re_fastputc(EditLine *, int); 58153079Sstefanfprivate void re_clear_eol(EditLine *, int, int, int); 5984260Sobrienprivate void re__strncopy(char *, char *, size_t); 60148834Sstefanfprivate void re__copy_and_pad(char *, const char *, size_t); 611573Srgrimes 621573Srgrimes#ifdef DEBUG_REFRESH 63148834Sstefanfprivate void re_printstr(EditLine *, const char *, char *, char *); 6484260Sobrien#define __F el->el_errfile 6584260Sobrien#define ELRE_ASSERT(a, b, c) do \ 66148834Sstefanf if (/*CONSTCOND*/ a) { \ 671573Srgrimes (void) fprintf b; \ 681573Srgrimes c; \ 691573Srgrimes } \ 70148834Sstefanf while (/*CONSTCOND*/0) 7184260Sobrien#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) 7284260Sobrien 731573Srgrimes/* re_printstr(): 741573Srgrimes * Print a string on the debugging pty 751573Srgrimes */ 761573Srgrimesprivate void 77148834Sstefanfre_printstr(EditLine *el, const char *str, char *f, char *t) 781573Srgrimes{ 7984260Sobrien 8084260Sobrien ELRE_DEBUG(1, (__F, "%s:\"", str)); 8184260Sobrien while (f < t) 8284260Sobrien ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); 8384260Sobrien ELRE_DEBUG(1, (__F, "\"\r\n")); 848870Srgrimes} 851573Srgrimes#else 8684260Sobrien#define ELRE_ASSERT(a, b, c) 8784260Sobrien#define ELRE_DEBUG(a, b) 881573Srgrimes#endif 891573Srgrimes 90237448Spfg/* re_nextline(): 91237448Spfg * Move to the next line or scroll 92237448Spfg */ 93237448Spfgprivate void 94237448Spfgre_nextline(EditLine *el) 95237448Spfg{ 96237448Spfg el->el_refresh.r_cursor.h = 0; /* reset it. */ 971573Srgrimes 98237448Spfg /* 99237448Spfg * If we would overflow (input is longer than terminal size), 100237448Spfg * emulate scroll by dropping first line and shuffling the rest. 101237448Spfg * We do this via pointer shuffling - it's safe in this case 102237448Spfg * and we avoid memcpy(). 103237448Spfg */ 104237448Spfg if (el->el_refresh.r_cursor.v + 1 >= el->el_term.t_size.v) { 105237448Spfg int i, lins = el->el_term.t_size.v; 106237448Spfg char *firstline = el->el_vdisplay[0]; 107237448Spfg 108237448Spfg for(i = 1; i < lins; i++) 109237448Spfg el->el_vdisplay[i - 1] = el->el_vdisplay[i]; 110237448Spfg 111237448Spfg firstline[0] = '\0'; /* empty the string */ 112237448Spfg el->el_vdisplay[i - 1] = firstline; 113237448Spfg } else 114237448Spfg el->el_refresh.r_cursor.v++; 115237448Spfg 116237448Spfg ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_term.t_size.v, 117237448Spfg (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", 118237448Spfg el->el_refresh.r_cursor.v, el->el_term.t_size.v), 119237448Spfg abort()); 120237448Spfg} 121237448Spfg 1221573Srgrimes/* re_addc(): 1231573Srgrimes * Draw c, expanding tabs, control chars etc. 1241573Srgrimes */ 1251573Srgrimesprivate void 12684260Sobrienre_addc(EditLine *el, int c) 1271573Srgrimes{ 12817524Sache 12984260Sobrien if (isprint(c)) { 13084260Sobrien re_putc(el, c, 1); 13184260Sobrien return; 1321573Srgrimes } 13384260Sobrien if (c == '\n') { /* expand the newline */ 13484260Sobrien int oldv = el->el_refresh.r_cursor.v; 13584260Sobrien re_putc(el, '\0', 0); /* assure end of line */ 136237448Spfg if (oldv == el->el_refresh.r_cursor.v) /* XXX */ 137237448Spfg re_nextline(el); 13884260Sobrien return; 13984260Sobrien } 14084260Sobrien if (c == '\t') { /* expand the tab */ 14184260Sobrien for (;;) { 14284260Sobrien re_putc(el, ' ', 1); 14384260Sobrien if ((el->el_refresh.r_cursor.h & 07) == 0) 14484260Sobrien break; /* go until tab stop */ 14584260Sobrien } 14684260Sobrien } else if (iscntrl(c)) { 14784260Sobrien re_putc(el, '^', 1); 14884260Sobrien if (c == 0177) 14984260Sobrien re_putc(el, '?', 1); 15084260Sobrien else 15184260Sobrien /* uncontrolify it; works only for iso8859-1 like sets */ 15284260Sobrien re_putc(el, (toascii(c) | 0100), 1); 15384260Sobrien } else { 15484260Sobrien re_putc(el, '\\', 1); 15584260Sobrien re_putc(el, (int) ((((unsigned int) c >> 6) & 07) + '0'), 1); 15684260Sobrien re_putc(el, (int) ((((unsigned int) c >> 3) & 07) + '0'), 1); 15784260Sobrien re_putc(el, (c & 07) + '0', 1); 15884260Sobrien } 15984260Sobrien} 1601573Srgrimes 1611573Srgrimes 1621573Srgrimes/* re_putc(): 1631573Srgrimes * Draw the character given 1641573Srgrimes */ 1651573Srgrimesprotected void 16684260Sobrienre_putc(EditLine *el, int c, int shift) 1671573Srgrimes{ 1681573Srgrimes 16984260Sobrien ELRE_DEBUG(1, (__F, "printing %3.3o '%c'\r\n", c, c)); 1701573Srgrimes 17184260Sobrien el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_refresh.r_cursor.h] = c; 17284260Sobrien if (!shift) 17384260Sobrien return; 1741573Srgrimes 17584260Sobrien el->el_refresh.r_cursor.h++; /* advance to next place */ 17684260Sobrien if (el->el_refresh.r_cursor.h >= el->el_term.t_size.h) { 17784260Sobrien /* assure end of line */ 178237448Spfg el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_term.t_size.h] 179237448Spfg = '\0'; 180237448Spfg re_nextline(el); 181237448Spfg } 18284260Sobrien 18384260Sobrien} 18484260Sobrien 18584260Sobrien 1861573Srgrimes/* re_refresh(): 1871573Srgrimes * draws the new virtual screen image from the current input 1881573Srgrimes * line, then goes line-by-line changing the real image to the new 1891573Srgrimes * virtual image. The routine to re-draw a line can be replaced 1901573Srgrimes * easily in hopes of a smarter one being placed there. 1911573Srgrimes */ 1921573Srgrimesprotected void 19384260Sobrienre_refresh(EditLine *el) 1941573Srgrimes{ 19584260Sobrien int i, rhdiff; 19684260Sobrien char *cp, *st; 19784260Sobrien coord_t cur; 19884260Sobrien#ifdef notyet 19984260Sobrien size_t termsz; 20084260Sobrien#endif 2011573Srgrimes 20284260Sobrien ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%s:\r\n", 20384260Sobrien el->el_line.buffer)); 2041573Srgrimes 20584260Sobrien /* reset the Drawing cursor */ 20684260Sobrien el->el_refresh.r_cursor.h = 0; 20784260Sobrien el->el_refresh.r_cursor.v = 0; 2081573Srgrimes 20984260Sobrien /* temporarily draw rprompt to calculate its size */ 21084260Sobrien prompt_print(el, EL_RPROMPT); 2111573Srgrimes 21284260Sobrien /* reset the Drawing cursor */ 21384260Sobrien el->el_refresh.r_cursor.h = 0; 21484260Sobrien el->el_refresh.r_cursor.v = 0; 2151573Srgrimes 216148834Sstefanf if (el->el_line.cursor >= el->el_line.lastchar) { 217148834Sstefanf if (el->el_map.current == el->el_map.alt 218148834Sstefanf && el->el_line.lastchar != el->el_line.buffer) 219148834Sstefanf el->el_line.cursor = el->el_line.lastchar - 1; 220148834Sstefanf else 221148834Sstefanf el->el_line.cursor = el->el_line.lastchar; 222148834Sstefanf } 223148834Sstefanf 22484260Sobrien cur.h = -1; /* set flag in case I'm not set */ 22584260Sobrien cur.v = 0; 22684260Sobrien 22784260Sobrien prompt_print(el, EL_PROMPT); 22884260Sobrien 22984260Sobrien /* draw the current input buffer */ 23084260Sobrien#if notyet 23184260Sobrien termsz = el->el_term.t_size.h * el->el_term.t_size.v; 23284260Sobrien if (el->el_line.lastchar - el->el_line.buffer > termsz) { 23384260Sobrien /* 23484260Sobrien * If line is longer than terminal, process only part 23584260Sobrien * of line which would influence display. 23684260Sobrien */ 23784260Sobrien size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; 23884260Sobrien 23984260Sobrien st = el->el_line.lastchar - rem 24084260Sobrien - (termsz - (((rem / el->el_term.t_size.v) - 1) 24184260Sobrien * el->el_term.t_size.v)); 24284260Sobrien } else 24384260Sobrien#endif 24484260Sobrien st = el->el_line.buffer; 24584260Sobrien 24684260Sobrien for (cp = st; cp < el->el_line.lastchar; cp++) { 24784260Sobrien if (cp == el->el_line.cursor) { 24884260Sobrien /* save for later */ 24984260Sobrien cur.h = el->el_refresh.r_cursor.h; 25084260Sobrien cur.v = el->el_refresh.r_cursor.v; 25184260Sobrien } 25284260Sobrien re_addc(el, (unsigned char) *cp); 2531573Srgrimes } 2541573Srgrimes 25584260Sobrien if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */ 25684260Sobrien cur.h = el->el_refresh.r_cursor.h; 25784260Sobrien cur.v = el->el_refresh.r_cursor.v; 25884260Sobrien } 25984260Sobrien rhdiff = el->el_term.t_size.h - el->el_refresh.r_cursor.h - 26084260Sobrien el->el_rprompt.p_pos.h; 26184260Sobrien if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && 26284260Sobrien !el->el_refresh.r_cursor.v && rhdiff > 1) { 26384260Sobrien /* 26484260Sobrien * have a right-hand side prompt that will fit 26584260Sobrien * on the end of the first line with at least 26684260Sobrien * one character gap to the input buffer. 26784260Sobrien */ 26884260Sobrien while (--rhdiff > 0) /* pad out with spaces */ 26984260Sobrien re_putc(el, ' ', 1); 27084260Sobrien prompt_print(el, EL_RPROMPT); 27184260Sobrien } else { 27284260Sobrien el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */ 27384260Sobrien el->el_rprompt.p_pos.v = 0; 27484260Sobrien } 2751573Srgrimes 27684260Sobrien re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */ 2771573Srgrimes 27884260Sobrien el->el_refresh.r_newcv = el->el_refresh.r_cursor.v; 2791573Srgrimes 28084260Sobrien ELRE_DEBUG(1, (__F, 28184260Sobrien "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", 28284260Sobrien el->el_term.t_size.h, el->el_refresh.r_cursor.h, 28384260Sobrien el->el_refresh.r_cursor.v, el->el_vdisplay[0])); 2841573Srgrimes 28584260Sobrien ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv)); 28684260Sobrien for (i = 0; i <= el->el_refresh.r_newcv; i++) { 28784260Sobrien /* NOTE THAT re_update_line MAY CHANGE el_display[i] */ 28884260Sobrien re_update_line(el, el->el_display[i], el->el_vdisplay[i], i); 28984260Sobrien 29084260Sobrien /* 29184260Sobrien * Copy the new line to be the current one, and pad out with 29284260Sobrien * spaces to the full width of the terminal so that if we try 29384260Sobrien * moving the cursor by writing the character that is at the 29484260Sobrien * end of the screen line, it won't be a NUL or some old 29584260Sobrien * leftover stuff. 29684260Sobrien */ 29784260Sobrien re__copy_and_pad(el->el_display[i], el->el_vdisplay[i], 29884260Sobrien (size_t) el->el_term.t_size.h); 29984260Sobrien } 30084260Sobrien ELRE_DEBUG(1, (__F, 30184260Sobrien "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", 30284260Sobrien el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i)); 30384260Sobrien 30484260Sobrien if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) 30584260Sobrien for (; i <= el->el_refresh.r_oldcv; i++) { 30684260Sobrien term_move_to_line(el, i); 30784260Sobrien term_move_to_char(el, 0); 30884260Sobrien term_clear_EOL(el, (int) strlen(el->el_display[i])); 3091573Srgrimes#ifdef DEBUG_REFRESH 310237448Spfg term_overwrite(el, "C\b", (size_t)2); 3111573Srgrimes#endif /* DEBUG_REFRESH */ 31284260Sobrien el->el_display[i][0] = '\0'; 31384260Sobrien } 3148870Srgrimes 31584260Sobrien el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ 31684260Sobrien ELRE_DEBUG(1, (__F, 31784260Sobrien "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", 31884260Sobrien el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, 31984260Sobrien cur.h, cur.v)); 32084260Sobrien term_move_to_line(el, cur.v); /* go to where the cursor is */ 32184260Sobrien term_move_to_char(el, cur.h); 32284260Sobrien} 3231573Srgrimes 3241573Srgrimes 3251573Srgrimes/* re_goto_bottom(): 3268870Srgrimes * used to go to last used screen line 3271573Srgrimes */ 3281573Srgrimesprotected void 32984260Sobrienre_goto_bottom(EditLine *el) 3301573Srgrimes{ 3311573Srgrimes 33284260Sobrien term_move_to_line(el, el->el_refresh.r_oldcv); 333237448Spfg term__putc(el, '\n'); 33484260Sobrien re_clear_display(el); 335237448Spfg term__flush(el); 33684260Sobrien} 3371573Srgrimes 33884260Sobrien 3391573Srgrimes/* re_insert(): 3401573Srgrimes * insert num characters of s into d (in front of the character) 3418870Srgrimes * at dat, maximum length of d is dlen 3421573Srgrimes */ 3431573Srgrimesprivate void 3441573Srgrimes/*ARGSUSED*/ 345148834Sstefanfre_insert(EditLine *el __unused, 346148834Sstefanf char *d, int dat, int dlen, char *s, int num) 3471573Srgrimes{ 34884260Sobrien char *a, *b; 3491573Srgrimes 35084260Sobrien if (num <= 0) 35184260Sobrien return; 35284260Sobrien if (num > dlen - dat) 35384260Sobrien num = dlen - dat; 3541573Srgrimes 35584260Sobrien ELRE_DEBUG(1, 35684260Sobrien (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", 35784260Sobrien num, dat, dlen, d)); 358153079Sstefanf ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); 3591573Srgrimes 36084260Sobrien /* open up the space for num chars */ 36184260Sobrien if (num > 0) { 36284260Sobrien b = d + dlen - 1; 36384260Sobrien a = b - num; 36484260Sobrien while (a >= &d[dat]) 36584260Sobrien *b-- = *a--; 36684260Sobrien d[dlen] = '\0'; /* just in case */ 36784260Sobrien } 36884260Sobrien ELRE_DEBUG(1, (__F, 3691573Srgrimes "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", 37084260Sobrien num, dat, dlen, d)); 371153079Sstefanf ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); 3721573Srgrimes 37384260Sobrien /* copy the characters */ 37484260Sobrien for (a = d + dat; (a < d + dlen) && (num > 0); num--) 37584260Sobrien *a++ = *s++; 3761573Srgrimes 37784260Sobrien ELRE_DEBUG(1, 37884260Sobrien (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", 37984260Sobrien num, dat, dlen, d, s)); 380153079Sstefanf ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); 38184260Sobrien} 3821573Srgrimes 3831573Srgrimes 3841573Srgrimes/* re_delete(): 3858870Srgrimes * delete num characters d at dat, maximum length of d is dlen 3861573Srgrimes */ 3871573Srgrimesprivate void 3881573Srgrimes/*ARGSUSED*/ 389148834Sstefanfre_delete(EditLine *el __unused, 390148834Sstefanf char *d, int dat, int dlen, int num) 3911573Srgrimes{ 39284260Sobrien char *a, *b; 3931573Srgrimes 39484260Sobrien if (num <= 0) 39584260Sobrien return; 39684260Sobrien if (dat + num >= dlen) { 39784260Sobrien d[dat] = '\0'; 39884260Sobrien return; 39984260Sobrien } 40084260Sobrien ELRE_DEBUG(1, 40184260Sobrien (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", 40284260Sobrien num, dat, dlen, d)); 4031573Srgrimes 40484260Sobrien /* open up the space for num chars */ 40584260Sobrien if (num > 0) { 40684260Sobrien b = d + dat; 40784260Sobrien a = b + num; 40884260Sobrien while (a < &d[dlen]) 40984260Sobrien *b++ = *a++; 41084260Sobrien d[dlen] = '\0'; /* just in case */ 41184260Sobrien } 41284260Sobrien ELRE_DEBUG(1, 41384260Sobrien (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", 41484260Sobrien num, dat, dlen, d)); 41584260Sobrien} 4161573Srgrimes 4171573Srgrimes 4181573Srgrimes/* re__strncopy(): 4191573Srgrimes * Like strncpy without padding. 4201573Srgrimes */ 4211573Srgrimesprivate void 42284260Sobrienre__strncopy(char *a, char *b, size_t n) 4231573Srgrimes{ 4241573Srgrimes 42584260Sobrien while (n-- && *b) 42684260Sobrien *a++ = *b++; 42784260Sobrien} 4281573Srgrimes 429153079Sstefanf/* re_clear_eol(): 430153079Sstefanf * Find the number of characters we need to clear till the end of line 431153079Sstefanf * in order to make sure that we have cleared the previous contents of 432153079Sstefanf * the line. fx and sx is the number of characters inserted or deleted 433153079Sstefanf * int the first or second diff, diff is the difference between the 434153079Sstefanf * number of characters between the new and old line. 435153079Sstefanf */ 436153079Sstefanfprivate void 437153079Sstefanfre_clear_eol(EditLine *el, int fx, int sx, int diff) 438153079Sstefanf{ 43984260Sobrien 440153079Sstefanf ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n", 441153079Sstefanf sx, fx, diff)); 442153079Sstefanf 443153079Sstefanf if (fx < 0) 444153079Sstefanf fx = -fx; 445153079Sstefanf if (sx < 0) 446153079Sstefanf sx = -sx; 447153079Sstefanf if (fx > diff) 448153079Sstefanf diff = fx; 449153079Sstefanf if (sx > diff) 450153079Sstefanf diff = sx; 451153079Sstefanf 452153079Sstefanf ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff)); 453153079Sstefanf term_clear_EOL(el, diff); 454153079Sstefanf} 455153079Sstefanf 45684260Sobrien/***************************************************************** 4571573Srgrimes re_update_line() is based on finding the middle difference of each line 4581573Srgrimes on the screen; vis: 4591573Srgrimes 4601573Srgrimes /old first difference 4611573Srgrimes /beginning of line | /old last same /old EOL 4621573Srgrimes v v v v 4631573Srgrimesold: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 4641573Srgrimesnew: eddie> Oh, my little buggy says to me, as lurgid as 4651573Srgrimes ^ ^ ^ ^ 4661573Srgrimes \beginning of line | \new last same \new end of line 4671573Srgrimes \new first difference 4681573Srgrimes 4691573Srgrimes all are character pointers for the sake of speed. Special cases for 4701573Srgrimes no differences, as well as for end of line additions must be handled. 4711573Srgrimes**************************************************************** */ 4721573Srgrimes 4731573Srgrimes/* Minimum at which doing an insert it "worth it". This should be about 4741573Srgrimes * half the "cost" of going into insert mode, inserting a character, and 4751573Srgrimes * going back out. This should really be calculated from the termcap 4761573Srgrimes * data... For the moment, a good number for ANSI terminals. 4771573Srgrimes */ 47884260Sobrien#define MIN_END_KEEP 4 4791573Srgrimes 4801573Srgrimesprivate void 48184260Sobrienre_update_line(EditLine *el, char *old, char *new, int i) 4821573Srgrimes{ 48384260Sobrien char *o, *n, *p, c; 48484260Sobrien char *ofd, *ols, *oe, *nfd, *nls, *ne; 48584260Sobrien char *osb, *ose, *nsb, *nse; 48684260Sobrien int fx, sx; 487237448Spfg size_t len; 4881573Srgrimes 48984260Sobrien /* 49084260Sobrien * find first diff 49184260Sobrien */ 49284260Sobrien for (o = old, n = new; *o && (*o == *n); o++, n++) 49384260Sobrien continue; 49484260Sobrien ofd = o; 49584260Sobrien nfd = n; 4961573Srgrimes 49784260Sobrien /* 49884260Sobrien * Find the end of both old and new 49984260Sobrien */ 50084260Sobrien while (*o) 50184260Sobrien o++; 50284260Sobrien /* 50384260Sobrien * Remove any trailing blanks off of the end, being careful not to 50484260Sobrien * back up past the beginning. 50584260Sobrien */ 50684260Sobrien while (ofd < o) { 50784260Sobrien if (o[-1] != ' ') 50884260Sobrien break; 50984260Sobrien o--; 51084260Sobrien } 51184260Sobrien oe = o; 51284260Sobrien *oe = '\0'; 5138870Srgrimes 51484260Sobrien while (*n) 51584260Sobrien n++; 5161573Srgrimes 51784260Sobrien /* remove blanks from end of new */ 51884260Sobrien while (nfd < n) { 51984260Sobrien if (n[-1] != ' ') 52084260Sobrien break; 52184260Sobrien n--; 5221573Srgrimes } 52384260Sobrien ne = n; 52484260Sobrien *ne = '\0'; 5251573Srgrimes 52684260Sobrien /* 52784260Sobrien * if no diff, continue to next line of redraw 52884260Sobrien */ 52984260Sobrien if (*ofd == '\0' && *nfd == '\0') { 53084260Sobrien ELRE_DEBUG(1, (__F, "no difference.\r\n")); 53184260Sobrien return; 5321573Srgrimes } 53384260Sobrien /* 53484260Sobrien * find last same pointer 53584260Sobrien */ 53684260Sobrien while ((o > ofd) && (n > nfd) && (*--o == *--n)) 53784260Sobrien continue; 53884260Sobrien ols = ++o; 53984260Sobrien nls = ++n; 5401573Srgrimes 54184260Sobrien /* 54284260Sobrien * find same begining and same end 54384260Sobrien */ 5441573Srgrimes osb = ols; 54584260Sobrien nsb = nls; 5461573Srgrimes ose = ols; 5471573Srgrimes nse = nls; 5481573Srgrimes 5491573Srgrimes /* 55084260Sobrien * case 1: insert: scan from nfd to nls looking for *ofd 55184260Sobrien */ 55284260Sobrien if (*ofd) { 55384260Sobrien for (c = *ofd, n = nfd; n < nls; n++) { 55484260Sobrien if (c == *n) { 55584260Sobrien for (o = ofd, p = n; 55684260Sobrien p < nls && o < ols && *o == *p; 55784260Sobrien o++, p++) 55884260Sobrien continue; 55984260Sobrien /* 56084260Sobrien * if the new match is longer and it's worth 56184260Sobrien * keeping, then we take it 56284260Sobrien */ 56384260Sobrien if (((nse - nsb) < (p - n)) && 56484260Sobrien (2 * (p - n) > n - nfd)) { 56584260Sobrien nsb = n; 56684260Sobrien nse = p; 56784260Sobrien osb = ofd; 56884260Sobrien ose = o; 56984260Sobrien } 57084260Sobrien } 57184260Sobrien } 57284260Sobrien } 5731573Srgrimes /* 57484260Sobrien * case 2: delete: scan from ofd to ols looking for *nfd 57584260Sobrien */ 57684260Sobrien if (*nfd) { 57784260Sobrien for (c = *nfd, o = ofd; o < ols; o++) { 57884260Sobrien if (c == *o) { 57984260Sobrien for (n = nfd, p = o; 58084260Sobrien p < ols && n < nls && *p == *n; 58184260Sobrien p++, n++) 58284260Sobrien continue; 58384260Sobrien /* 58484260Sobrien * if the new match is longer and it's worth 58584260Sobrien * keeping, then we take it 58684260Sobrien */ 58784260Sobrien if (((ose - osb) < (p - o)) && 58884260Sobrien (2 * (p - o) > o - ofd)) { 58984260Sobrien nsb = nfd; 59084260Sobrien nse = n; 59184260Sobrien osb = o; 59284260Sobrien ose = p; 59384260Sobrien } 59484260Sobrien } 59584260Sobrien } 5961573Srgrimes } 59784260Sobrien /* 59884260Sobrien * Pragmatics I: If old trailing whitespace or not enough characters to 59984260Sobrien * save to be worth it, then don't save the last same info. 60084260Sobrien */ 60184260Sobrien if ((oe - ols) < MIN_END_KEEP) { 60284260Sobrien ols = oe; 60384260Sobrien nls = ne; 6041573Srgrimes } 6051573Srgrimes /* 60684260Sobrien * Pragmatics II: if the terminal isn't smart enough, make the data 60784260Sobrien * dumber so the smart update doesn't try anything fancy 60884260Sobrien */ 60984260Sobrien 6101573Srgrimes /* 61184260Sobrien * fx is the number of characters we need to insert/delete: in the 61284260Sobrien * beginning to bring the two same begins together 61384260Sobrien */ 614237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 61584260Sobrien /* 61684260Sobrien * sx is the number of characters we need to insert/delete: in the 61784260Sobrien * end to bring the two same last parts together 61884260Sobrien */ 619237448Spfg sx = (int)((nls - nse) - (ols - ose)); 6201573Srgrimes 62184260Sobrien if (!EL_CAN_INSERT) { 62284260Sobrien if (fx > 0) { 62384260Sobrien osb = ols; 62484260Sobrien ose = ols; 62584260Sobrien nsb = nls; 62684260Sobrien nse = nls; 62784260Sobrien } 62884260Sobrien if (sx > 0) { 62984260Sobrien ols = oe; 63084260Sobrien nls = ne; 63184260Sobrien } 63284260Sobrien if ((ols - ofd) < (nls - nfd)) { 63384260Sobrien ols = oe; 63484260Sobrien nls = ne; 63584260Sobrien } 6361573Srgrimes } 63784260Sobrien if (!EL_CAN_DELETE) { 63884260Sobrien if (fx < 0) { 63984260Sobrien osb = ols; 64084260Sobrien ose = ols; 64184260Sobrien nsb = nls; 64284260Sobrien nse = nls; 64384260Sobrien } 64484260Sobrien if (sx < 0) { 64584260Sobrien ols = oe; 64684260Sobrien nls = ne; 64784260Sobrien } 64884260Sobrien if ((ols - ofd) > (nls - nfd)) { 64984260Sobrien ols = oe; 65084260Sobrien nls = ne; 65184260Sobrien } 6521573Srgrimes } 6531573Srgrimes /* 65484260Sobrien * Pragmatics III: make sure the middle shifted pointers are correct if 65584260Sobrien * they don't point to anything (we may have moved ols or nls). 65684260Sobrien */ 65784260Sobrien /* if the change isn't worth it, don't bother */ 65884260Sobrien /* was: if (osb == ose) */ 65984260Sobrien if ((ose - osb) < MIN_END_KEEP) { 66084260Sobrien osb = ols; 66184260Sobrien ose = ols; 66284260Sobrien nsb = nls; 66384260Sobrien nse = nls; 66484260Sobrien } 6651573Srgrimes /* 66684260Sobrien * Now that we are done with pragmatics we recompute fx, sx 66784260Sobrien */ 668237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 669237448Spfg sx = (int)((nls - nse) - (ols - ose)); 6701573Srgrimes 671153079Sstefanf ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx)); 67284260Sobrien ELRE_DEBUG(1, (__F, "ofd %d, osb %d, ose %d, ols %d, oe %d\n", 67384260Sobrien ofd - old, osb - old, ose - old, ols - old, oe - old)); 67484260Sobrien ELRE_DEBUG(1, (__F, "nfd %d, nsb %d, nse %d, nls %d, ne %d\n", 67584260Sobrien nfd - new, nsb - new, nse - new, nls - new, ne - new)); 67684260Sobrien ELRE_DEBUG(1, (__F, 67784260Sobrien "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n")); 67884260Sobrien ELRE_DEBUG(1, (__F, 67984260Sobrien "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n")); 68084260Sobrien#ifdef DEBUG_REFRESH 68184260Sobrien re_printstr(el, "old- oe", old, oe); 68284260Sobrien re_printstr(el, "new- ne", new, ne); 68384260Sobrien re_printstr(el, "old-ofd", old, ofd); 68484260Sobrien re_printstr(el, "new-nfd", new, nfd); 68584260Sobrien re_printstr(el, "ofd-osb", ofd, osb); 68684260Sobrien re_printstr(el, "nfd-nsb", nfd, nsb); 68784260Sobrien re_printstr(el, "osb-ose", osb, ose); 68884260Sobrien re_printstr(el, "nsb-nse", nsb, nse); 68984260Sobrien re_printstr(el, "ose-ols", ose, ols); 69084260Sobrien re_printstr(el, "nse-nls", nse, nls); 69184260Sobrien re_printstr(el, "ols- oe", ols, oe); 69284260Sobrien re_printstr(el, "nls- ne", nls, ne); 69384260Sobrien#endif /* DEBUG_REFRESH */ 69484260Sobrien 6951573Srgrimes /* 69684260Sobrien * el_cursor.v to this line i MUST be in this routine so that if we 69784260Sobrien * don't have to change the line, we don't move to it. el_cursor.h to 69884260Sobrien * first diff char 69984260Sobrien */ 70084260Sobrien term_move_to_line(el, i); 7011573Srgrimes 70284260Sobrien /* 70384260Sobrien * at this point we have something like this: 70484260Sobrien * 70584260Sobrien * /old /ofd /osb /ose /ols /oe 70684260Sobrien * v.....................v v..................v v........v 70784260Sobrien * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 70884260Sobrien * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 70984260Sobrien * ^.....................^ ^..................^ ^........^ 71084260Sobrien * \new \nfd \nsb \nse \nls \ne 71184260Sobrien * 71284260Sobrien * fx is the difference in length between the chars between nfd and 71384260Sobrien * nsb, and the chars between ofd and osb, and is thus the number of 71484260Sobrien * characters to delete if < 0 (new is shorter than old, as above), 71584260Sobrien * or insert (new is longer than short). 71684260Sobrien * 71784260Sobrien * sx is the same for the second differences. 71884260Sobrien */ 7191573Srgrimes 72084260Sobrien /* 72184260Sobrien * if we have a net insert on the first difference, AND inserting the 72284260Sobrien * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful 72384260Sobrien * character (which is ne if nls != ne, otherwise is nse) off the edge 72484260Sobrien * of the screen (el->el_term.t_size.h) else we do the deletes first 72584260Sobrien * so that we keep everything we need to. 72684260Sobrien */ 7271573Srgrimes 7281573Srgrimes /* 72984260Sobrien * if the last same is the same like the end, there is no last same 73084260Sobrien * part, otherwise we want to keep the last same part set p to the 73184260Sobrien * last useful old character 73284260Sobrien */ 73384260Sobrien p = (ols != oe) ? oe : ose; 73484260Sobrien 73584260Sobrien /* 73684260Sobrien * if (There is a diffence in the beginning) && (we need to insert 73784260Sobrien * characters) && (the number of characters to insert is less than 73884260Sobrien * the term width) 73984260Sobrien * We need to do an insert! 74084260Sobrien * else if (we need to delete characters) 74184260Sobrien * We need to delete characters! 74284260Sobrien * else 74384260Sobrien * No insert or delete 74484260Sobrien */ 74584260Sobrien if ((nsb != nfd) && fx > 0 && 74684260Sobrien ((p - old) + fx <= el->el_term.t_size.h)) { 74784260Sobrien ELRE_DEBUG(1, 74884260Sobrien (__F, "first diff insert at %d...\r\n", nfd - new)); 7491573Srgrimes /* 75084260Sobrien * Move to the first char to insert, where the first diff is. 7511573Srgrimes */ 752237448Spfg term_move_to_char(el, (int)(nfd - new)); 75384260Sobrien /* 75484260Sobrien * Check if we have stuff to keep at end 75584260Sobrien */ 75684260Sobrien if (nsb != ne) { 75784260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 75884260Sobrien /* 75984260Sobrien * insert fx chars of new starting at nfd 76084260Sobrien */ 76184260Sobrien if (fx > 0) { 76284260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 76384260Sobrien "ERROR: cannot insert in early first diff\n")); 76484260Sobrien term_insertwrite(el, nfd, fx); 765237448Spfg re_insert(el, old, (int)(ofd - old), 76684260Sobrien el->el_term.t_size.h, nfd, fx); 76784260Sobrien } 76884260Sobrien /* 76984260Sobrien * write (nsb-nfd) - fx chars of new starting at 77084260Sobrien * (nfd + fx) 77184260Sobrien */ 772237448Spfg len = (size_t) ((nsb - nfd) - fx); 773237448Spfg term_overwrite(el, (nfd + fx), len); 774237448Spfg re__strncopy(ofd + fx, nfd + fx, len); 77584260Sobrien } else { 77684260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 777237448Spfg len = (size_t)(nsb - nfd); 778237448Spfg term_overwrite(el, nfd, len); 779237448Spfg re__strncopy(ofd, nfd, len); 78084260Sobrien /* 78184260Sobrien * Done 78284260Sobrien */ 78384260Sobrien return; 78484260Sobrien } 78584260Sobrien } else if (fx < 0) { 78684260Sobrien ELRE_DEBUG(1, 78784260Sobrien (__F, "first diff delete at %d...\r\n", ofd - old)); 78884260Sobrien /* 78984260Sobrien * move to the first char to delete where the first diff is 79084260Sobrien */ 791237448Spfg term_move_to_char(el, (int)(ofd - old)); 79284260Sobrien /* 79384260Sobrien * Check if we have stuff to save 79484260Sobrien */ 79584260Sobrien if (osb != oe) { 79684260Sobrien ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); 79784260Sobrien /* 79884260Sobrien * fx is less than zero *always* here but we check 79984260Sobrien * for code symmetry 80084260Sobrien */ 80184260Sobrien if (fx < 0) { 80284260Sobrien ELRE_DEBUG(!EL_CAN_DELETE, (__F, 80384260Sobrien "ERROR: cannot delete in first diff\n")); 80484260Sobrien term_deletechars(el, -fx); 805237448Spfg re_delete(el, old, (int)(ofd - old), 80684260Sobrien el->el_term.t_size.h, -fx); 80784260Sobrien } 80884260Sobrien /* 80984260Sobrien * write (nsb-nfd) chars of new starting at nfd 81084260Sobrien */ 811237448Spfg len = (size_t) (nsb - nfd); 812237448Spfg term_overwrite(el, nfd, len); 813237448Spfg re__strncopy(ofd, nfd, len); 8141573Srgrimes 81584260Sobrien } else { 81684260Sobrien ELRE_DEBUG(1, (__F, 81784260Sobrien "but with nothing left to save\r\n")); 81884260Sobrien /* 81984260Sobrien * write (nsb-nfd) chars of new starting at nfd 82084260Sobrien */ 821237448Spfg term_overwrite(el, nfd, (size_t)(nsb - nfd)); 822237448Spfg re_clear_eol(el, fx, sx, 823237448Spfg (int)((oe - old) - (ne - new))); 82484260Sobrien /* 82584260Sobrien * Done 82684260Sobrien */ 82784260Sobrien return; 82884260Sobrien } 82984260Sobrien } else 83084260Sobrien fx = 0; 8311573Srgrimes 83284260Sobrien if (sx < 0 && (ose - old) + fx < el->el_term.t_size.h) { 83384260Sobrien ELRE_DEBUG(1, (__F, 83484260Sobrien "second diff delete at %d...\r\n", (ose - old) + fx)); 83584260Sobrien /* 83684260Sobrien * Check if we have stuff to delete 83784260Sobrien */ 83884260Sobrien /* 83984260Sobrien * fx is the number of characters inserted (+) or deleted (-) 84084260Sobrien */ 8411573Srgrimes 842237448Spfg term_move_to_char(el, (int)((ose - old) + fx)); 84384260Sobrien /* 84484260Sobrien * Check if we have stuff to save 84584260Sobrien */ 84684260Sobrien if (ols != oe) { 84784260Sobrien ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); 84884260Sobrien /* 84984260Sobrien * Again a duplicate test. 85084260Sobrien */ 85184260Sobrien if (sx < 0) { 85284260Sobrien ELRE_DEBUG(!EL_CAN_DELETE, (__F, 85384260Sobrien "ERROR: cannot delete in second diff\n")); 85484260Sobrien term_deletechars(el, -sx); 85584260Sobrien } 85684260Sobrien /* 85784260Sobrien * write (nls-nse) chars of new starting at nse 85884260Sobrien */ 859237448Spfg term_overwrite(el, nse, (size_t)(nls - nse)); 86084260Sobrien } else { 86184260Sobrien ELRE_DEBUG(1, (__F, 86284260Sobrien "but with nothing left to save\r\n")); 863237448Spfg term_overwrite(el, nse, (size_t)(nls - nse)); 864237448Spfg re_clear_eol(el, fx, sx, 865237448Spfg (int)((oe - old) - (ne - new))); 86684260Sobrien } 8671573Srgrimes } 86884260Sobrien /* 86984260Sobrien * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 87084260Sobrien */ 87184260Sobrien if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 87284260Sobrien ELRE_DEBUG(1, (__F, "late first diff insert at %d...\r\n", 87384260Sobrien nfd - new)); 8741573Srgrimes 875237448Spfg term_move_to_char(el, (int)(nfd - new)); 87684260Sobrien /* 87784260Sobrien * Check if we have stuff to keep at the end 87884260Sobrien */ 87984260Sobrien if (nsb != ne) { 88084260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 88184260Sobrien /* 88284260Sobrien * We have to recalculate fx here because we set it 88384260Sobrien * to zero above as a flag saying that we hadn't done 88484260Sobrien * an early first insert. 88584260Sobrien */ 886237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 88784260Sobrien if (fx > 0) { 88884260Sobrien /* 88984260Sobrien * insert fx chars of new starting at nfd 89084260Sobrien */ 89184260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 89284260Sobrien "ERROR: cannot insert in late first diff\n")); 89384260Sobrien term_insertwrite(el, nfd, fx); 894237448Spfg re_insert(el, old, (int)(ofd - old), 89584260Sobrien el->el_term.t_size.h, nfd, fx); 89684260Sobrien } 89784260Sobrien /* 89884260Sobrien * write (nsb-nfd) - fx chars of new starting at 89984260Sobrien * (nfd + fx) 90084260Sobrien */ 901237448Spfg len = (size_t) ((nsb - nfd) - fx); 902237448Spfg term_overwrite(el, (nfd + fx), len); 903237448Spfg re__strncopy(ofd + fx, nfd + fx, len); 90484260Sobrien } else { 90584260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 906237448Spfg len = (size_t) (nsb - nfd); 907237448Spfg term_overwrite(el, nfd, len); 908237448Spfg re__strncopy(ofd, nfd, len); 90984260Sobrien } 9101573Srgrimes } 91184260Sobrien /* 91284260Sobrien * line is now NEW up to nse 91384260Sobrien */ 91484260Sobrien if (sx >= 0) { 91584260Sobrien ELRE_DEBUG(1, (__F, 916237448Spfg "second diff insert at %d...\r\n", (int)(nse - new))); 917237448Spfg term_move_to_char(el, (int)(nse - new)); 91884260Sobrien if (ols != oe) { 91984260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 92084260Sobrien if (sx > 0) { 92184260Sobrien /* insert sx chars of new starting at nse */ 92284260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 92384260Sobrien "ERROR: cannot insert in second diff\n")); 92484260Sobrien term_insertwrite(el, nse, sx); 92584260Sobrien } 92684260Sobrien /* 92784260Sobrien * write (nls-nse) - sx chars of new starting at 92884260Sobrien * (nse + sx) 92984260Sobrien */ 930237448Spfg term_overwrite(el, (nse + sx), 931237448Spfg (size_t)((nls - nse) - sx)); 93284260Sobrien } else { 93384260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 934237448Spfg term_overwrite(el, nse, (size_t)(nls - nse)); 9351573Srgrimes 93684260Sobrien /* 93784260Sobrien * No need to do a clear-to-end here because we were 93884260Sobrien * doing a second insert, so we will have over 93984260Sobrien * written all of the old string. 94084260Sobrien */ 94184260Sobrien } 94284260Sobrien } 94384260Sobrien ELRE_DEBUG(1, (__F, "done.\r\n")); 94484260Sobrien} 9451573Srgrimes 94684260Sobrien 9471573Srgrimes/* re__copy_and_pad(): 9481573Srgrimes * Copy string and pad with spaces 9491573Srgrimes */ 9501573Srgrimesprivate void 951148834Sstefanfre__copy_and_pad(char *dst, const char *src, size_t width) 9521573Srgrimes{ 953148834Sstefanf size_t i; 9541573Srgrimes 95584260Sobrien for (i = 0; i < width; i++) { 95684260Sobrien if (*src == '\0') 95784260Sobrien break; 95884260Sobrien *dst++ = *src++; 95984260Sobrien } 9601573Srgrimes 96184260Sobrien for (; i < width; i++) 96284260Sobrien *dst++ = ' '; 9631573Srgrimes 96484260Sobrien *dst = '\0'; 96584260Sobrien} 9661573Srgrimes 96784260Sobrien 9681573Srgrimes/* re_refresh_cursor(): 9691573Srgrimes * Move to the new cursor position 9701573Srgrimes */ 9711573Srgrimesprotected void 97284260Sobrienre_refresh_cursor(EditLine *el) 9731573Srgrimes{ 97484260Sobrien char *cp, c; 97584260Sobrien int h, v, th; 9761573Srgrimes 977148834Sstefanf if (el->el_line.cursor >= el->el_line.lastchar) { 978148834Sstefanf if (el->el_map.current == el->el_map.alt 979148834Sstefanf && el->el_line.lastchar != el->el_line.buffer) 980148834Sstefanf el->el_line.cursor = el->el_line.lastchar - 1; 981148834Sstefanf else 982148834Sstefanf el->el_line.cursor = el->el_line.lastchar; 983148834Sstefanf } 984148834Sstefanf 98584260Sobrien /* first we must find where the cursor is... */ 98684260Sobrien h = el->el_prompt.p_pos.h; 98784260Sobrien v = el->el_prompt.p_pos.v; 98884260Sobrien th = el->el_term.t_size.h; /* optimize for speed */ 9891573Srgrimes 99084260Sobrien /* do input buffer to el->el_line.cursor */ 99184260Sobrien for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) { 992148834Sstefanf c = *cp; 9931573Srgrimes 994237448Spfg switch (c) { 995237448Spfg case '\n': /* handle newline in data part too */ 99684260Sobrien h = 0; 99784260Sobrien v++; 998237448Spfg break; 999237448Spfg case '\t': /* if a tab, to next tab stop */ 1000237448Spfg while (++h & 07) 1001237448Spfg continue; 1002237448Spfg break; 1003237448Spfg default: 1004237448Spfg if (iscntrl((unsigned char) c)) 1005237448Spfg h += 2; /* ^x */ 1006237448Spfg else if (!isprint((unsigned char) c)) 1007237448Spfg h += 4; /* octal \xxx */ 1008237448Spfg else 100984260Sobrien h++; 1010237448Spfg break; 10111573Srgrimes } 101284260Sobrien 101384260Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1014237448Spfg h -= th; 101584260Sobrien v++; 10161573Srgrimes } 10171573Srgrimes } 10181573Srgrimes 101984260Sobrien /* now go there */ 102084260Sobrien term_move_to_line(el, v); 102184260Sobrien term_move_to_char(el, h); 1022237448Spfg term__flush(el); 102384260Sobrien} 10241573Srgrimes 10251573Srgrimes 10261573Srgrimes/* re_fastputc(): 10271573Srgrimes * Add a character fast. 10281573Srgrimes */ 10291573Srgrimesprivate void 103084260Sobrienre_fastputc(EditLine *el, int c) 10311573Srgrimes{ 10321573Srgrimes 1033237448Spfg term__putc(el, c); 103484260Sobrien el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; 103584260Sobrien if (el->el_cursor.h >= el->el_term.t_size.h) { 103684260Sobrien /* if we must overflow */ 103784260Sobrien el->el_cursor.h = 0; 10381573Srgrimes 103984260Sobrien /* 104084260Sobrien * If we would overflow (input is longer than terminal size), 104184260Sobrien * emulate scroll by dropping first line and shuffling the rest. 104284260Sobrien * We do this via pointer shuffling - it's safe in this case 104384260Sobrien * and we avoid memcpy(). 104484260Sobrien */ 104584260Sobrien if (el->el_cursor.v + 1 >= el->el_term.t_size.v) { 104684260Sobrien int i, lins = el->el_term.t_size.v; 104784260Sobrien char *firstline = el->el_display[0]; 104884260Sobrien 1049237448Spfg for(i = 1; i < lins; i++) 1050237448Spfg el->el_display[i - 1] = el->el_display[i]; 105184260Sobrien 105284260Sobrien re__copy_and_pad(firstline, "", 0); 1053237448Spfg el->el_display[i - 1] = firstline; 105484260Sobrien } else { 105584260Sobrien el->el_cursor.v++; 105684260Sobrien el->el_refresh.r_oldcv++; 105784260Sobrien } 105884260Sobrien if (EL_HAS_AUTO_MARGINS) { 105984260Sobrien if (EL_HAS_MAGIC_MARGINS) { 1060237448Spfg term__putc(el, ' '); 1061237448Spfg term__putc(el, '\b'); 106284260Sobrien } 106384260Sobrien } else { 1064237448Spfg term__putc(el, '\r'); 1065237448Spfg term__putc(el, '\n'); 106684260Sobrien } 106784260Sobrien } 106884260Sobrien} 106984260Sobrien 107084260Sobrien 10711573Srgrimes/* re_fastaddc(): 10721573Srgrimes * we added just one char, handle it fast. 10738870Srgrimes * Assumes that screen cursor == real cursor 10741573Srgrimes */ 10751573Srgrimesprotected void 107684260Sobrienre_fastaddc(EditLine *el) 10771573Srgrimes{ 107884260Sobrien char c; 107984260Sobrien int rhdiff; 10801573Srgrimes 108184260Sobrien c = (unsigned char)el->el_line.cursor[-1]; 10821573Srgrimes 108384260Sobrien if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { 108484260Sobrien re_refresh(el); /* too hard to handle */ 108584260Sobrien return; 108684260Sobrien } 108784260Sobrien rhdiff = el->el_term.t_size.h - el->el_cursor.h - 108884260Sobrien el->el_rprompt.p_pos.h; 108984260Sobrien if (el->el_rprompt.p_pos.h && rhdiff < 3) { 109084260Sobrien re_refresh(el); /* clear out rprompt if less than 1 char gap */ 109184260Sobrien return; 109284260Sobrien } /* else (only do at end of line, no TAB) */ 109384260Sobrien if (iscntrl((unsigned char) c)) { /* if control char, do caret */ 109484260Sobrien char mc = (c == 0177) ? '?' : (toascii(c) | 0100); 109584260Sobrien re_fastputc(el, '^'); 109684260Sobrien re_fastputc(el, mc); 109784260Sobrien } else if (isprint((unsigned char) c)) { /* normal char */ 109884260Sobrien re_fastputc(el, c); 109984260Sobrien } else { 110084260Sobrien re_fastputc(el, '\\'); 1101148834Sstefanf re_fastputc(el, (int)(((((unsigned int)c) >> 6) & 3) + '0')); 1102148834Sstefanf re_fastputc(el, (int)(((((unsigned int)c) >> 3) & 7) + '0')); 110384260Sobrien re_fastputc(el, (c & 7) + '0'); 110484260Sobrien } 1105237448Spfg term__flush(el); 110684260Sobrien} 11071573Srgrimes 11081573Srgrimes 11091573Srgrimes/* re_clear_display(): 11108870Srgrimes * clear the screen buffers so that new new prompt starts fresh. 11111573Srgrimes */ 11121573Srgrimesprotected void 111384260Sobrienre_clear_display(EditLine *el) 11141573Srgrimes{ 111584260Sobrien int i; 11161573Srgrimes 111784260Sobrien el->el_cursor.v = 0; 111884260Sobrien el->el_cursor.h = 0; 111984260Sobrien for (i = 0; i < el->el_term.t_size.v; i++) 112084260Sobrien el->el_display[i][0] = '\0'; 112184260Sobrien el->el_refresh.r_oldcv = 0; 112284260Sobrien} 11231573Srgrimes 11241573Srgrimes 11251573Srgrimes/* re_clear_lines(): 11268870Srgrimes * Make sure all lines are *really* blank 11271573Srgrimes */ 11281573Srgrimesprotected void 112984260Sobrienre_clear_lines(EditLine *el) 11301573Srgrimes{ 113184260Sobrien 113284260Sobrien if (EL_CAN_CEOL) { 113384260Sobrien int i; 1134237448Spfg for (i = el->el_refresh.r_oldcv; i >= 0; i--) { 113584260Sobrien /* for each line on the screen */ 113684260Sobrien term_move_to_line(el, i); 1137237448Spfg term_move_to_char(el, 0); 113884260Sobrien term_clear_EOL(el, el->el_term.t_size.h); 113984260Sobrien } 114084260Sobrien } else { 114184260Sobrien term_move_to_line(el, el->el_refresh.r_oldcv); 114284260Sobrien /* go to last line */ 1143237448Spfg term__putc(el, '\r'); /* go to BOL */ 1144237448Spfg term__putc(el, '\n'); /* go to new line */ 11451573Srgrimes } 114684260Sobrien} 1147