1313981Spfg/* $NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $ */ 2276881Sbapt 31573Srgrimes/*- 41573Srgrimes * Copyright (c) 1992, 1993 51573Srgrimes * The Regents of the University of California. All rights reserved. 61573Srgrimes * 71573Srgrimes * This code is derived from software contributed to Berkeley by 81573Srgrimes * Christos Zoulas of Cornell University. 91573Srgrimes * 101573Srgrimes * Redistribution and use in source and binary forms, with or without 111573Srgrimes * modification, are permitted provided that the following conditions 121573Srgrimes * are met: 131573Srgrimes * 1. Redistributions of source code must retain the above copyright 141573Srgrimes * notice, this list of conditions and the following disclaimer. 151573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161573Srgrimes * notice, this list of conditions and the following disclaimer in the 171573Srgrimes * documentation and/or other materials provided with the distribution. 18148834Sstefanf * 3. Neither the name of the University nor the names of its contributors 191573Srgrimes * may be used to endorse or promote products derived from this software 201573Srgrimes * without specific prior written permission. 211573Srgrimes * 221573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 231573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 241573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 251573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 261573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 271573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 281573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 291573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 301573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 311573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 321573Srgrimes * SUCH DAMAGE. 331573Srgrimes */ 341573Srgrimes 35276881Sbapt#include "config.h" 361573Srgrimes#if !defined(lint) && !defined(SCCSID) 37276881Sbapt#if 0 381573Srgrimesstatic char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; 39276881Sbapt#else 40313981Spfg__RCSID("$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $"); 41276881Sbapt#endif 421573Srgrimes#endif /* not lint && not SCCSID */ 4384260Sobrien#include <sys/cdefs.h> 4484260Sobrien__FBSDID("$FreeBSD: stable/11/lib/libedit/refresh.c 330446 2018-03-05 06:59:30Z eadler $"); 451573Srgrimes 461573Srgrimes/* 471573Srgrimes * refresh.c: Lower level screen refreshing functions 481573Srgrimes */ 491573Srgrimes#include <stdio.h> 50313981Spfg#include <string.h> 51296435Spfg#include <unistd.h> 521573Srgrimes 531573Srgrimes#include "el.h" 541573Srgrimes 55237448Spfgprivate void re_nextline(EditLine *); 56313981Spfgprivate void re_addc(EditLine *, wint_t); 57276881Sbaptprivate void re_update_line(EditLine *, Char *, Char *, int); 58276881Sbaptprivate void re_insert (EditLine *, Char *, int, int, Char *, int); 59276881Sbaptprivate void re_delete(EditLine *, Char *, int, int, int); 60313981Spfgprivate void re_fastputc(EditLine *, wint_t); 61153079Sstefanfprivate void re_clear_eol(EditLine *, int, int, int); 62276881Sbaptprivate void re__strncopy(Char *, Char *, size_t); 63276881Sbaptprivate void re__copy_and_pad(Char *, const Char *, size_t); 641573Srgrimes 651573Srgrimes#ifdef DEBUG_REFRESH 66313981Spfgprivate void re_printstr(EditLine *, const char *, Char *, Char *); 6784260Sobrien#define __F el->el_errfile 68313981Spfg#define ELRE_ASSERT(a, b, c) do \ 69148834Sstefanf if (/*CONSTCOND*/ a) { \ 701573Srgrimes (void) fprintf b; \ 711573Srgrimes c; \ 721573Srgrimes } \ 73148834Sstefanf while (/*CONSTCOND*/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 80313981Spfgre_printstr(EditLine *el, const 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 93237448Spfg/* re_nextline(): 94237448Spfg * Move to the next line or scroll 95237448Spfg */ 96237448Spfgprivate void 97237448Spfgre_nextline(EditLine *el) 98237448Spfg{ 99237448Spfg el->el_refresh.r_cursor.h = 0; /* reset it. */ 1001573Srgrimes 101237448Spfg /* 102237448Spfg * If we would overflow (input is longer than terminal size), 103237448Spfg * emulate scroll by dropping first line and shuffling the rest. 104237448Spfg * We do this via pointer shuffling - it's safe in this case 105237448Spfg * and we avoid memcpy(). 106237448Spfg */ 107276881Sbapt if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { 108276881Sbapt int i, lins = el->el_terminal.t_size.v; 109276881Sbapt Char *firstline = el->el_vdisplay[0]; 110237448Spfg 111237448Spfg for(i = 1; i < lins; i++) 112237448Spfg el->el_vdisplay[i - 1] = el->el_vdisplay[i]; 113237448Spfg 114313981Spfg firstline[0] = '\0'; /* empty the string */ 115237448Spfg el->el_vdisplay[i - 1] = firstline; 116237448Spfg } else 117237448Spfg el->el_refresh.r_cursor.v++; 118237448Spfg 119276881Sbapt ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v, 120237448Spfg (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", 121276881Sbapt el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), 122237448Spfg abort()); 123237448Spfg} 124237448Spfg 1251573Srgrimes/* re_addc(): 1261573Srgrimes * Draw c, expanding tabs, control chars etc. 1271573Srgrimes */ 1281573Srgrimesprivate void 129313981Spfgre_addc(EditLine *el, wint_t c) 1301573Srgrimes{ 131276881Sbapt switch (ct_chr_class((Char)c)) { 132276881Sbapt case CHTYPE_TAB: /* expand the tab */ 13384260Sobrien for (;;) { 13484260Sobrien re_putc(el, ' ', 1); 13584260Sobrien if ((el->el_refresh.r_cursor.h & 07) == 0) 13684260Sobrien break; /* go until tab stop */ 13784260Sobrien } 138276881Sbapt break; 139276881Sbapt case CHTYPE_NL: { 140276881Sbapt int oldv = el->el_refresh.r_cursor.v; 141276881Sbapt re_putc(el, '\0', 0); /* assure end of line */ 142276881Sbapt if (oldv == el->el_refresh.r_cursor.v) /* XXX */ 143276881Sbapt re_nextline(el); 144276881Sbapt break; 14584260Sobrien } 146276881Sbapt case CHTYPE_PRINT: 147276881Sbapt re_putc(el, c, 1); 148276881Sbapt break; 149276881Sbapt default: { 150276881Sbapt Char visbuf[VISUAL_WIDTH_MAX]; 151276881Sbapt ssize_t i, n = 152276881Sbapt ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); 153276881Sbapt for (i = 0; n-- > 0; ++i) 154276881Sbapt re_putc(el, visbuf[i], 1); 155276881Sbapt break; 156276881Sbapt } 157276881Sbapt } 15884260Sobrien} 1591573Srgrimes 1601573Srgrimes 1611573Srgrimes/* re_putc(): 1621573Srgrimes * Draw the character given 1631573Srgrimes */ 1641573Srgrimesprotected void 165313981Spfgre_putc(EditLine *el, wint_t c, int shift) 1661573Srgrimes{ 167276881Sbapt int i, w = Width(c); 168313981Spfg ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c)); 1691573Srgrimes 170276881Sbapt while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h)) 171276881Sbapt re_putc(el, ' ', 1); 1721573Srgrimes 173276881Sbapt el->el_vdisplay[el->el_refresh.r_cursor.v] 174313981Spfg [el->el_refresh.r_cursor.h] = (Char)c; 175276881Sbapt /* assumes !shift is only used for single-column chars */ 176276881Sbapt i = w; 177276881Sbapt while (--i > 0) 178276881Sbapt el->el_vdisplay[el->el_refresh.r_cursor.v] 179276881Sbapt [el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR; 180276881Sbapt 18184260Sobrien if (!shift) 18284260Sobrien return; 1831573Srgrimes 184276881Sbapt el->el_refresh.r_cursor.h += w; /* advance to next place */ 185276881Sbapt if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) { 18684260Sobrien /* assure end of line */ 187276881Sbapt el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h] 188237448Spfg = '\0'; 189237448Spfg re_nextline(el); 190237448Spfg } 19184260Sobrien} 19284260Sobrien 19384260Sobrien 1941573Srgrimes/* re_refresh(): 1951573Srgrimes * draws the new virtual screen image from the current input 196313981Spfg * line, then goes line-by-line changing the real image to the new 1971573Srgrimes * virtual image. The routine to re-draw a line can be replaced 1981573Srgrimes * easily in hopes of a smarter one being placed there. 1991573Srgrimes */ 2001573Srgrimesprotected void 20184260Sobrienre_refresh(EditLine *el) 2021573Srgrimes{ 20384260Sobrien int i, rhdiff; 204276881Sbapt Char *cp, *st; 20584260Sobrien coord_t cur; 20684260Sobrien#ifdef notyet 20784260Sobrien size_t termsz; 20884260Sobrien#endif 2091573Srgrimes 210313981Spfg ELRE_DEBUG(1, (__F, "el->el_line.buffer = :" FSTR ":\r\n", 21184260Sobrien el->el_line.buffer)); 2121573Srgrimes 21384260Sobrien /* reset the Drawing cursor */ 21484260Sobrien el->el_refresh.r_cursor.h = 0; 21584260Sobrien el->el_refresh.r_cursor.v = 0; 2161573Srgrimes 21784260Sobrien /* temporarily draw rprompt to calculate its size */ 21884260Sobrien prompt_print(el, EL_RPROMPT); 2191573Srgrimes 22084260Sobrien /* reset the Drawing cursor */ 22184260Sobrien el->el_refresh.r_cursor.h = 0; 22284260Sobrien el->el_refresh.r_cursor.v = 0; 2231573Srgrimes 224148834Sstefanf if (el->el_line.cursor >= el->el_line.lastchar) { 225148834Sstefanf if (el->el_map.current == el->el_map.alt 226148834Sstefanf && el->el_line.lastchar != el->el_line.buffer) 227148834Sstefanf el->el_line.cursor = el->el_line.lastchar - 1; 228148834Sstefanf else 229148834Sstefanf el->el_line.cursor = el->el_line.lastchar; 230148834Sstefanf } 231148834Sstefanf 23284260Sobrien cur.h = -1; /* set flag in case I'm not set */ 23384260Sobrien cur.v = 0; 23484260Sobrien 23584260Sobrien prompt_print(el, EL_PROMPT); 23684260Sobrien 23784260Sobrien /* draw the current input buffer */ 23884260Sobrien#if notyet 239276881Sbapt termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v; 24084260Sobrien if (el->el_line.lastchar - el->el_line.buffer > termsz) { 24184260Sobrien /* 24284260Sobrien * If line is longer than terminal, process only part 24384260Sobrien * of line which would influence display. 24484260Sobrien */ 24584260Sobrien size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; 24684260Sobrien 24784260Sobrien st = el->el_line.lastchar - rem 248276881Sbapt - (termsz - (((rem / el->el_terminal.t_size.v) - 1) 249276881Sbapt * el->el_terminal.t_size.v)); 25084260Sobrien } else 25184260Sobrien#endif 25284260Sobrien st = el->el_line.buffer; 25384260Sobrien 25484260Sobrien for (cp = st; cp < el->el_line.lastchar; cp++) { 25584260Sobrien if (cp == el->el_line.cursor) { 256276881Sbapt int w = Width(*cp); 25784260Sobrien /* save for later */ 25884260Sobrien cur.h = el->el_refresh.r_cursor.h; 25984260Sobrien cur.v = el->el_refresh.r_cursor.v; 260276881Sbapt /* handle being at a linebroken doublewidth char */ 261276881Sbapt if (w > 1 && el->el_refresh.r_cursor.h + w > 262276881Sbapt el->el_terminal.t_size.h) { 263276881Sbapt cur.h = 0; 264276881Sbapt cur.v++; 265276881Sbapt } 26684260Sobrien } 267276881Sbapt re_addc(el, *cp); 2681573Srgrimes } 2691573Srgrimes 27084260Sobrien if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */ 27184260Sobrien cur.h = el->el_refresh.r_cursor.h; 27284260Sobrien cur.v = el->el_refresh.r_cursor.v; 27384260Sobrien } 274276881Sbapt rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h - 27584260Sobrien el->el_rprompt.p_pos.h; 27684260Sobrien if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && 27784260Sobrien !el->el_refresh.r_cursor.v && rhdiff > 1) { 27884260Sobrien /* 27984260Sobrien * have a right-hand side prompt that will fit 28084260Sobrien * on the end of the first line with at least 28184260Sobrien * one character gap to the input buffer. 28284260Sobrien */ 28384260Sobrien while (--rhdiff > 0) /* pad out with spaces */ 28484260Sobrien re_putc(el, ' ', 1); 28584260Sobrien prompt_print(el, EL_RPROMPT); 28684260Sobrien } else { 28784260Sobrien el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */ 28884260Sobrien el->el_rprompt.p_pos.v = 0; 28984260Sobrien } 2901573Srgrimes 29184260Sobrien re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */ 2921573Srgrimes 29384260Sobrien el->el_refresh.r_newcv = el->el_refresh.r_cursor.v; 2941573Srgrimes 29584260Sobrien ELRE_DEBUG(1, (__F, 29684260Sobrien "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", 297276881Sbapt el->el_terminal.t_size.h, el->el_refresh.r_cursor.h, 298313981Spfg el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0], 299313981Spfg &el->el_scratch))); 3001573Srgrimes 30184260Sobrien ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv)); 30284260Sobrien for (i = 0; i <= el->el_refresh.r_newcv; i++) { 30384260Sobrien /* NOTE THAT re_update_line MAY CHANGE el_display[i] */ 30484260Sobrien re_update_line(el, el->el_display[i], el->el_vdisplay[i], i); 30584260Sobrien 30684260Sobrien /* 30784260Sobrien * Copy the new line to be the current one, and pad out with 30884260Sobrien * spaces to the full width of the terminal so that if we try 30984260Sobrien * moving the cursor by writing the character that is at the 31084260Sobrien * end of the screen line, it won't be a NUL or some old 31184260Sobrien * leftover stuff. 31284260Sobrien */ 31384260Sobrien re__copy_and_pad(el->el_display[i], el->el_vdisplay[i], 314276881Sbapt (size_t) el->el_terminal.t_size.h); 31584260Sobrien } 31684260Sobrien ELRE_DEBUG(1, (__F, 31784260Sobrien "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", 31884260Sobrien el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i)); 31984260Sobrien 32084260Sobrien if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) 32184260Sobrien for (; i <= el->el_refresh.r_oldcv; i++) { 322276881Sbapt terminal_move_to_line(el, i); 323276881Sbapt terminal_move_to_char(el, 0); 324276881Sbapt /* This Strlen should be safe even with MB_FILL_CHARs */ 325276881Sbapt terminal_clear_EOL(el, (int) Strlen(el->el_display[i])); 3261573Srgrimes#ifdef DEBUG_REFRESH 327313981Spfg terminal_overwrite(el, STR("C\b"), 2); 3281573Srgrimes#endif /* DEBUG_REFRESH */ 32984260Sobrien el->el_display[i][0] = '\0'; 33084260Sobrien } 3318870Srgrimes 33284260Sobrien el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ 33384260Sobrien ELRE_DEBUG(1, (__F, 33484260Sobrien "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", 33584260Sobrien el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, 33684260Sobrien cur.h, cur.v)); 337276881Sbapt terminal_move_to_line(el, cur.v); /* go to where the cursor is */ 338276881Sbapt terminal_move_to_char(el, cur.h); 33984260Sobrien} 3401573Srgrimes 3411573Srgrimes 3421573Srgrimes/* re_goto_bottom(): 3438870Srgrimes * used to go to last used screen line 3441573Srgrimes */ 3451573Srgrimesprotected void 34684260Sobrienre_goto_bottom(EditLine *el) 3471573Srgrimes{ 3481573Srgrimes 349276881Sbapt terminal_move_to_line(el, el->el_refresh.r_oldcv); 350276881Sbapt terminal__putc(el, '\n'); 35184260Sobrien re_clear_display(el); 352276881Sbapt terminal__flush(el); 35384260Sobrien} 3541573Srgrimes 35584260Sobrien 3561573Srgrimes/* re_insert(): 3571573Srgrimes * insert num characters of s into d (in front of the character) 3588870Srgrimes * at dat, maximum length of d is dlen 3591573Srgrimes */ 3601573Srgrimesprivate void 3611573Srgrimes/*ARGSUSED*/ 362276881Sbaptre_insert(EditLine *el __attribute__((__unused__)), 363276881Sbapt Char *d, int dat, int dlen, Char *s, int num) 3641573Srgrimes{ 365276881Sbapt Char *a, *b; 3661573Srgrimes 36784260Sobrien if (num <= 0) 36884260Sobrien return; 36984260Sobrien if (num > dlen - dat) 37084260Sobrien num = dlen - dat; 3711573Srgrimes 37284260Sobrien ELRE_DEBUG(1, 37384260Sobrien (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", 374313981Spfg num, dat, dlen, ct_encode_string(d, &el->el_scratch))); 375313981Spfg ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s, 376313981Spfg &el->el_scratch))); 3771573Srgrimes 37884260Sobrien /* open up the space for num chars */ 37984260Sobrien if (num > 0) { 38084260Sobrien b = d + dlen - 1; 38184260Sobrien a = b - num; 38284260Sobrien while (a >= &d[dat]) 38384260Sobrien *b-- = *a--; 38484260Sobrien d[dlen] = '\0'; /* just in case */ 38584260Sobrien } 386276881Sbapt 38784260Sobrien ELRE_DEBUG(1, (__F, 3881573Srgrimes "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", 389313981Spfg num, dat, dlen, ct_encode_string(d, &el->el_scratch))); 390313981Spfg ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s, 391313981Spfg &el->el_scratch))); 3921573Srgrimes 39384260Sobrien /* copy the characters */ 39484260Sobrien for (a = d + dat; (a < d + dlen) && (num > 0); num--) 39584260Sobrien *a++ = *s++; 3961573Srgrimes 397276881Sbapt#ifdef notyet 398276881Sbapt /* ct_encode_string() uses a static buffer, so we can't conveniently 399276881Sbapt * encode both d & s here */ 40084260Sobrien ELRE_DEBUG(1, 40184260Sobrien (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", 40284260Sobrien num, dat, dlen, d, s)); 403153079Sstefanf ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); 404276881Sbapt#endif 40584260Sobrien} 4061573Srgrimes 4071573Srgrimes 4081573Srgrimes/* re_delete(): 4098870Srgrimes * delete num characters d at dat, maximum length of d is dlen 4101573Srgrimes */ 4111573Srgrimesprivate void 4121573Srgrimes/*ARGSUSED*/ 413276881Sbaptre_delete(EditLine *el __attribute__((__unused__)), 414276881Sbapt Char *d, int dat, int dlen, int num) 4151573Srgrimes{ 416276881Sbapt Char *a, *b; 4171573Srgrimes 41884260Sobrien if (num <= 0) 41984260Sobrien return; 42084260Sobrien if (dat + num >= dlen) { 42184260Sobrien d[dat] = '\0'; 42284260Sobrien return; 42384260Sobrien } 42484260Sobrien ELRE_DEBUG(1, 42584260Sobrien (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", 426313981Spfg num, dat, dlen, ct_encode_string(d, &el->el_scratch))); 4271573Srgrimes 42884260Sobrien /* open up the space for num chars */ 42984260Sobrien if (num > 0) { 43084260Sobrien b = d + dat; 43184260Sobrien a = b + num; 43284260Sobrien while (a < &d[dlen]) 43384260Sobrien *b++ = *a++; 43484260Sobrien d[dlen] = '\0'; /* just in case */ 43584260Sobrien } 43684260Sobrien ELRE_DEBUG(1, 43784260Sobrien (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", 438313981Spfg num, dat, dlen, ct_encode_string(d, &el->el_scratch))); 43984260Sobrien} 4401573Srgrimes 4411573Srgrimes 4421573Srgrimes/* re__strncopy(): 4431573Srgrimes * Like strncpy without padding. 4441573Srgrimes */ 4451573Srgrimesprivate void 446276881Sbaptre__strncopy(Char *a, Char *b, size_t n) 4471573Srgrimes{ 4481573Srgrimes 44984260Sobrien while (n-- && *b) 45084260Sobrien *a++ = *b++; 45184260Sobrien} 4521573Srgrimes 453153079Sstefanf/* re_clear_eol(): 454153079Sstefanf * Find the number of characters we need to clear till the end of line 455153079Sstefanf * in order to make sure that we have cleared the previous contents of 456153079Sstefanf * the line. fx and sx is the number of characters inserted or deleted 457276881Sbapt * in the first or second diff, diff is the difference between the 458313981Spfg * number of characters between the new and old line. 459153079Sstefanf */ 460153079Sstefanfprivate void 461153079Sstefanfre_clear_eol(EditLine *el, int fx, int sx, int diff) 462153079Sstefanf{ 46384260Sobrien 464153079Sstefanf ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n", 465153079Sstefanf sx, fx, diff)); 466153079Sstefanf 467153079Sstefanf if (fx < 0) 468153079Sstefanf fx = -fx; 469153079Sstefanf if (sx < 0) 470153079Sstefanf sx = -sx; 471153079Sstefanf if (fx > diff) 472153079Sstefanf diff = fx; 473153079Sstefanf if (sx > diff) 474153079Sstefanf diff = sx; 475153079Sstefanf 476153079Sstefanf ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff)); 477276881Sbapt terminal_clear_EOL(el, diff); 478153079Sstefanf} 479153079Sstefanf 48084260Sobrien/***************************************************************** 4811573Srgrimes re_update_line() is based on finding the middle difference of each line 4821573Srgrimes on the screen; vis: 4831573Srgrimes 4841573Srgrimes /old first difference 4851573Srgrimes /beginning of line | /old last same /old EOL 4861573Srgrimes v v v v 4871573Srgrimesold: eddie> Oh, my little gruntle-buggy is to me, as lurgid as 4881573Srgrimesnew: eddie> Oh, my little buggy says to me, as lurgid as 4891573Srgrimes ^ ^ ^ ^ 4901573Srgrimes \beginning of line | \new last same \new end of line 4911573Srgrimes \new first difference 4921573Srgrimes 4931573Srgrimes all are character pointers for the sake of speed. Special cases for 4941573Srgrimes no differences, as well as for end of line additions must be handled. 4951573Srgrimes**************************************************************** */ 4961573Srgrimes 4971573Srgrimes/* Minimum at which doing an insert it "worth it". This should be about 4981573Srgrimes * half the "cost" of going into insert mode, inserting a character, and 4991573Srgrimes * going back out. This should really be calculated from the termcap 5001573Srgrimes * data... For the moment, a good number for ANSI terminals. 5011573Srgrimes */ 50284260Sobrien#define MIN_END_KEEP 4 5031573Srgrimes 5041573Srgrimesprivate void 505276881Sbaptre_update_line(EditLine *el, Char *old, Char *new, int i) 5061573Srgrimes{ 507276881Sbapt Char *o, *n, *p, c; 508276881Sbapt Char *ofd, *ols, *oe, *nfd, *nls, *ne; 509276881Sbapt Char *osb, *ose, *nsb, *nse; 51084260Sobrien int fx, sx; 511237448Spfg size_t len; 5121573Srgrimes 51384260Sobrien /* 51484260Sobrien * find first diff 51584260Sobrien */ 51684260Sobrien for (o = old, n = new; *o && (*o == *n); o++, n++) 51784260Sobrien continue; 51884260Sobrien ofd = o; 51984260Sobrien nfd = n; 5201573Srgrimes 52184260Sobrien /* 52284260Sobrien * Find the end of both old and new 52384260Sobrien */ 52484260Sobrien while (*o) 52584260Sobrien o++; 52684260Sobrien /* 52784260Sobrien * Remove any trailing blanks off of the end, being careful not to 52884260Sobrien * back up past the beginning. 52984260Sobrien */ 53084260Sobrien while (ofd < o) { 53184260Sobrien if (o[-1] != ' ') 53284260Sobrien break; 53384260Sobrien o--; 53484260Sobrien } 53584260Sobrien oe = o; 53684260Sobrien *oe = '\0'; 5378870Srgrimes 53884260Sobrien while (*n) 53984260Sobrien n++; 5401573Srgrimes 54184260Sobrien /* remove blanks from end of new */ 54284260Sobrien while (nfd < n) { 54384260Sobrien if (n[-1] != ' ') 54484260Sobrien break; 54584260Sobrien n--; 5461573Srgrimes } 54784260Sobrien ne = n; 54884260Sobrien *ne = '\0'; 5491573Srgrimes 55084260Sobrien /* 55184260Sobrien * if no diff, continue to next line of redraw 55284260Sobrien */ 55384260Sobrien if (*ofd == '\0' && *nfd == '\0') { 55484260Sobrien ELRE_DEBUG(1, (__F, "no difference.\r\n")); 55584260Sobrien return; 5561573Srgrimes } 55784260Sobrien /* 55884260Sobrien * find last same pointer 55984260Sobrien */ 56084260Sobrien while ((o > ofd) && (n > nfd) && (*--o == *--n)) 56184260Sobrien continue; 56284260Sobrien ols = ++o; 56384260Sobrien nls = ++n; 5641573Srgrimes 56584260Sobrien /* 566298896Spfg * find same beginning and same end 56784260Sobrien */ 5681573Srgrimes osb = ols; 56984260Sobrien nsb = nls; 5701573Srgrimes ose = ols; 5711573Srgrimes nse = nls; 5721573Srgrimes 5731573Srgrimes /* 57484260Sobrien * case 1: insert: scan from nfd to nls looking for *ofd 57584260Sobrien */ 57684260Sobrien if (*ofd) { 57784260Sobrien for (c = *ofd, n = nfd; n < nls; n++) { 57884260Sobrien if (c == *n) { 57984260Sobrien for (o = ofd, p = n; 58084260Sobrien p < nls && o < ols && *o == *p; 58184260Sobrien o++, p++) 58284260Sobrien continue; 58384260Sobrien /* 58484260Sobrien * if the new match is longer and it's worth 58584260Sobrien * keeping, then we take it 58684260Sobrien */ 58784260Sobrien if (((nse - nsb) < (p - n)) && 58884260Sobrien (2 * (p - n) > n - nfd)) { 58984260Sobrien nsb = n; 59084260Sobrien nse = p; 59184260Sobrien osb = ofd; 59284260Sobrien ose = o; 59384260Sobrien } 59484260Sobrien } 59584260Sobrien } 59684260Sobrien } 5971573Srgrimes /* 59884260Sobrien * case 2: delete: scan from ofd to ols looking for *nfd 59984260Sobrien */ 60084260Sobrien if (*nfd) { 60184260Sobrien for (c = *nfd, o = ofd; o < ols; o++) { 60284260Sobrien if (c == *o) { 60384260Sobrien for (n = nfd, p = o; 60484260Sobrien p < ols && n < nls && *p == *n; 60584260Sobrien p++, n++) 60684260Sobrien continue; 60784260Sobrien /* 60884260Sobrien * if the new match is longer and it's worth 60984260Sobrien * keeping, then we take it 61084260Sobrien */ 61184260Sobrien if (((ose - osb) < (p - o)) && 61284260Sobrien (2 * (p - o) > o - ofd)) { 61384260Sobrien nsb = nfd; 61484260Sobrien nse = n; 61584260Sobrien osb = o; 61684260Sobrien ose = p; 61784260Sobrien } 61884260Sobrien } 61984260Sobrien } 6201573Srgrimes } 62184260Sobrien /* 62284260Sobrien * Pragmatics I: If old trailing whitespace or not enough characters to 62384260Sobrien * save to be worth it, then don't save the last same info. 62484260Sobrien */ 62584260Sobrien if ((oe - ols) < MIN_END_KEEP) { 62684260Sobrien ols = oe; 62784260Sobrien nls = ne; 6281573Srgrimes } 6291573Srgrimes /* 63084260Sobrien * Pragmatics II: if the terminal isn't smart enough, make the data 63184260Sobrien * dumber so the smart update doesn't try anything fancy 63284260Sobrien */ 63384260Sobrien 6341573Srgrimes /* 63584260Sobrien * fx is the number of characters we need to insert/delete: in the 63684260Sobrien * beginning to bring the two same begins together 63784260Sobrien */ 638237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 63984260Sobrien /* 64084260Sobrien * sx is the number of characters we need to insert/delete: in the 64184260Sobrien * end to bring the two same last parts together 64284260Sobrien */ 643237448Spfg sx = (int)((nls - nse) - (ols - ose)); 6441573Srgrimes 64584260Sobrien if (!EL_CAN_INSERT) { 64684260Sobrien if (fx > 0) { 64784260Sobrien osb = ols; 64884260Sobrien ose = ols; 64984260Sobrien nsb = nls; 65084260Sobrien nse = nls; 65184260Sobrien } 65284260Sobrien if (sx > 0) { 65384260Sobrien ols = oe; 65484260Sobrien nls = ne; 65584260Sobrien } 65684260Sobrien if ((ols - ofd) < (nls - nfd)) { 65784260Sobrien ols = oe; 65884260Sobrien nls = ne; 65984260Sobrien } 6601573Srgrimes } 66184260Sobrien if (!EL_CAN_DELETE) { 66284260Sobrien if (fx < 0) { 66384260Sobrien osb = ols; 66484260Sobrien ose = ols; 66584260Sobrien nsb = nls; 66684260Sobrien nse = nls; 66784260Sobrien } 66884260Sobrien if (sx < 0) { 66984260Sobrien ols = oe; 67084260Sobrien nls = ne; 67184260Sobrien } 67284260Sobrien if ((ols - ofd) > (nls - nfd)) { 67384260Sobrien ols = oe; 67484260Sobrien nls = ne; 67584260Sobrien } 6761573Srgrimes } 6771573Srgrimes /* 67884260Sobrien * Pragmatics III: make sure the middle shifted pointers are correct if 67984260Sobrien * they don't point to anything (we may have moved ols or nls). 68084260Sobrien */ 68184260Sobrien /* if the change isn't worth it, don't bother */ 68284260Sobrien /* was: if (osb == ose) */ 68384260Sobrien if ((ose - osb) < MIN_END_KEEP) { 68484260Sobrien osb = ols; 68584260Sobrien ose = ols; 68684260Sobrien nsb = nls; 68784260Sobrien nse = nls; 68884260Sobrien } 6891573Srgrimes /* 69084260Sobrien * Now that we are done with pragmatics we recompute fx, sx 69184260Sobrien */ 692237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 693237448Spfg sx = (int)((nls - nse) - (ols - ose)); 6941573Srgrimes 695153079Sstefanf ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx)); 696313981Spfg ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n", 69784260Sobrien ofd - old, osb - old, ose - old, ols - old, oe - old)); 698313981Spfg ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n", 69984260Sobrien nfd - new, nsb - new, nse - new, nls - new, ne - new)); 70084260Sobrien ELRE_DEBUG(1, (__F, 70184260Sobrien "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n")); 70284260Sobrien ELRE_DEBUG(1, (__F, 70384260Sobrien "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n")); 70484260Sobrien#ifdef DEBUG_REFRESH 70584260Sobrien re_printstr(el, "old- oe", old, oe); 70684260Sobrien re_printstr(el, "new- ne", new, ne); 70784260Sobrien re_printstr(el, "old-ofd", old, ofd); 70884260Sobrien re_printstr(el, "new-nfd", new, nfd); 70984260Sobrien re_printstr(el, "ofd-osb", ofd, osb); 71084260Sobrien re_printstr(el, "nfd-nsb", nfd, nsb); 71184260Sobrien re_printstr(el, "osb-ose", osb, ose); 71284260Sobrien re_printstr(el, "nsb-nse", nsb, nse); 71384260Sobrien re_printstr(el, "ose-ols", ose, ols); 71484260Sobrien re_printstr(el, "nse-nls", nse, nls); 71584260Sobrien re_printstr(el, "ols- oe", ols, oe); 71684260Sobrien re_printstr(el, "nls- ne", nls, ne); 71784260Sobrien#endif /* DEBUG_REFRESH */ 71884260Sobrien 7191573Srgrimes /* 72084260Sobrien * el_cursor.v to this line i MUST be in this routine so that if we 72184260Sobrien * don't have to change the line, we don't move to it. el_cursor.h to 72284260Sobrien * first diff char 72384260Sobrien */ 724276881Sbapt terminal_move_to_line(el, i); 7251573Srgrimes 72684260Sobrien /* 72784260Sobrien * at this point we have something like this: 72884260Sobrien * 72984260Sobrien * /old /ofd /osb /ose /ols /oe 73084260Sobrien * v.....................v v..................v v........v 73184260Sobrien * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as 73284260Sobrien * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as 73384260Sobrien * ^.....................^ ^..................^ ^........^ 73484260Sobrien * \new \nfd \nsb \nse \nls \ne 73584260Sobrien * 73684260Sobrien * fx is the difference in length between the chars between nfd and 73784260Sobrien * nsb, and the chars between ofd and osb, and is thus the number of 73884260Sobrien * characters to delete if < 0 (new is shorter than old, as above), 73984260Sobrien * or insert (new is longer than short). 74084260Sobrien * 74184260Sobrien * sx is the same for the second differences. 74284260Sobrien */ 7431573Srgrimes 74484260Sobrien /* 74584260Sobrien * if we have a net insert on the first difference, AND inserting the 74684260Sobrien * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful 74784260Sobrien * character (which is ne if nls != ne, otherwise is nse) off the edge 748276881Sbapt * of the screen (el->el_terminal.t_size.h) else we do the deletes first 74984260Sobrien * so that we keep everything we need to. 75084260Sobrien */ 7511573Srgrimes 7521573Srgrimes /* 75384260Sobrien * if the last same is the same like the end, there is no last same 75484260Sobrien * part, otherwise we want to keep the last same part set p to the 75584260Sobrien * last useful old character 75684260Sobrien */ 75784260Sobrien p = (ols != oe) ? oe : ose; 75884260Sobrien 75984260Sobrien /* 76084260Sobrien * if (There is a diffence in the beginning) && (we need to insert 76184260Sobrien * characters) && (the number of characters to insert is less than 76284260Sobrien * the term width) 76384260Sobrien * We need to do an insert! 76484260Sobrien * else if (we need to delete characters) 76584260Sobrien * We need to delete characters! 76684260Sobrien * else 76784260Sobrien * No insert or delete 76884260Sobrien */ 76984260Sobrien if ((nsb != nfd) && fx > 0 && 770276881Sbapt ((p - old) + fx <= el->el_terminal.t_size.h)) { 77184260Sobrien ELRE_DEBUG(1, 772313981Spfg (__F, "first diff insert at %td...\r\n", nfd - new)); 7731573Srgrimes /* 77484260Sobrien * Move to the first char to insert, where the first diff is. 7751573Srgrimes */ 776276881Sbapt terminal_move_to_char(el, (int)(nfd - new)); 77784260Sobrien /* 77884260Sobrien * Check if we have stuff to keep at end 77984260Sobrien */ 78084260Sobrien if (nsb != ne) { 78184260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 78284260Sobrien /* 78384260Sobrien * insert fx chars of new starting at nfd 78484260Sobrien */ 78584260Sobrien if (fx > 0) { 78684260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 78784260Sobrien "ERROR: cannot insert in early first diff\n")); 788276881Sbapt terminal_insertwrite(el, nfd, fx); 789237448Spfg re_insert(el, old, (int)(ofd - old), 790276881Sbapt el->el_terminal.t_size.h, nfd, fx); 79184260Sobrien } 79284260Sobrien /* 79384260Sobrien * write (nsb-nfd) - fx chars of new starting at 79484260Sobrien * (nfd + fx) 79584260Sobrien */ 796237448Spfg len = (size_t) ((nsb - nfd) - fx); 797276881Sbapt terminal_overwrite(el, (nfd + fx), len); 798237448Spfg re__strncopy(ofd + fx, nfd + fx, len); 79984260Sobrien } else { 80084260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 801237448Spfg len = (size_t)(nsb - nfd); 802276881Sbapt terminal_overwrite(el, nfd, len); 803237448Spfg re__strncopy(ofd, nfd, len); 80484260Sobrien /* 80584260Sobrien * Done 80684260Sobrien */ 80784260Sobrien return; 80884260Sobrien } 80984260Sobrien } else if (fx < 0) { 81084260Sobrien ELRE_DEBUG(1, 811313981Spfg (__F, "first diff delete at %td...\r\n", ofd - old)); 81284260Sobrien /* 81384260Sobrien * move to the first char to delete where the first diff is 81484260Sobrien */ 815276881Sbapt terminal_move_to_char(el, (int)(ofd - old)); 81684260Sobrien /* 81784260Sobrien * Check if we have stuff to save 81884260Sobrien */ 81984260Sobrien if (osb != oe) { 82084260Sobrien ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); 82184260Sobrien /* 82284260Sobrien * fx is less than zero *always* here but we check 82384260Sobrien * for code symmetry 82484260Sobrien */ 82584260Sobrien if (fx < 0) { 82684260Sobrien ELRE_DEBUG(!EL_CAN_DELETE, (__F, 82784260Sobrien "ERROR: cannot delete in first diff\n")); 828276881Sbapt terminal_deletechars(el, -fx); 829237448Spfg re_delete(el, old, (int)(ofd - old), 830276881Sbapt el->el_terminal.t_size.h, -fx); 83184260Sobrien } 83284260Sobrien /* 83384260Sobrien * write (nsb-nfd) chars of new starting at nfd 83484260Sobrien */ 835237448Spfg len = (size_t) (nsb - nfd); 836276881Sbapt terminal_overwrite(el, nfd, len); 837237448Spfg re__strncopy(ofd, nfd, len); 8381573Srgrimes 83984260Sobrien } else { 84084260Sobrien ELRE_DEBUG(1, (__F, 84184260Sobrien "but with nothing left to save\r\n")); 84284260Sobrien /* 84384260Sobrien * write (nsb-nfd) chars of new starting at nfd 84484260Sobrien */ 845276881Sbapt terminal_overwrite(el, nfd, (size_t)(nsb - nfd)); 846237448Spfg re_clear_eol(el, fx, sx, 847237448Spfg (int)((oe - old) - (ne - new))); 84884260Sobrien /* 84984260Sobrien * Done 85084260Sobrien */ 85184260Sobrien return; 85284260Sobrien } 85384260Sobrien } else 85484260Sobrien fx = 0; 8551573Srgrimes 856276881Sbapt if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) { 85784260Sobrien ELRE_DEBUG(1, (__F, 858313981Spfg "second diff delete at %td...\r\n", (ose - old) + fx)); 85984260Sobrien /* 86084260Sobrien * Check if we have stuff to delete 86184260Sobrien */ 86284260Sobrien /* 86384260Sobrien * fx is the number of characters inserted (+) or deleted (-) 86484260Sobrien */ 8651573Srgrimes 866276881Sbapt terminal_move_to_char(el, (int)((ose - old) + fx)); 86784260Sobrien /* 86884260Sobrien * Check if we have stuff to save 86984260Sobrien */ 87084260Sobrien if (ols != oe) { 87184260Sobrien ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); 87284260Sobrien /* 87384260Sobrien * Again a duplicate test. 87484260Sobrien */ 87584260Sobrien if (sx < 0) { 87684260Sobrien ELRE_DEBUG(!EL_CAN_DELETE, (__F, 87784260Sobrien "ERROR: cannot delete in second diff\n")); 878276881Sbapt terminal_deletechars(el, -sx); 87984260Sobrien } 88084260Sobrien /* 88184260Sobrien * write (nls-nse) chars of new starting at nse 88284260Sobrien */ 883276881Sbapt terminal_overwrite(el, nse, (size_t)(nls - nse)); 88484260Sobrien } else { 88584260Sobrien ELRE_DEBUG(1, (__F, 88684260Sobrien "but with nothing left to save\r\n")); 887276881Sbapt terminal_overwrite(el, nse, (size_t)(nls - nse)); 888237448Spfg re_clear_eol(el, fx, sx, 889237448Spfg (int)((oe - old) - (ne - new))); 89084260Sobrien } 8911573Srgrimes } 89284260Sobrien /* 89384260Sobrien * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... 89484260Sobrien */ 89584260Sobrien if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { 896313981Spfg ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n", 89784260Sobrien nfd - new)); 8981573Srgrimes 899276881Sbapt terminal_move_to_char(el, (int)(nfd - new)); 90084260Sobrien /* 90184260Sobrien * Check if we have stuff to keep at the end 90284260Sobrien */ 90384260Sobrien if (nsb != ne) { 90484260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 90584260Sobrien /* 90684260Sobrien * We have to recalculate fx here because we set it 90784260Sobrien * to zero above as a flag saying that we hadn't done 90884260Sobrien * an early first insert. 90984260Sobrien */ 910237448Spfg fx = (int)((nsb - nfd) - (osb - ofd)); 91184260Sobrien if (fx > 0) { 91284260Sobrien /* 91384260Sobrien * insert fx chars of new starting at nfd 91484260Sobrien */ 91584260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 91684260Sobrien "ERROR: cannot insert in late first diff\n")); 917276881Sbapt terminal_insertwrite(el, nfd, fx); 918237448Spfg re_insert(el, old, (int)(ofd - old), 919276881Sbapt el->el_terminal.t_size.h, nfd, fx); 92084260Sobrien } 92184260Sobrien /* 92284260Sobrien * write (nsb-nfd) - fx chars of new starting at 92384260Sobrien * (nfd + fx) 92484260Sobrien */ 925237448Spfg len = (size_t) ((nsb - nfd) - fx); 926276881Sbapt terminal_overwrite(el, (nfd + fx), len); 927237448Spfg re__strncopy(ofd + fx, nfd + fx, len); 92884260Sobrien } else { 92984260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 930237448Spfg len = (size_t) (nsb - nfd); 931276881Sbapt terminal_overwrite(el, nfd, len); 932237448Spfg re__strncopy(ofd, nfd, len); 93384260Sobrien } 9341573Srgrimes } 93584260Sobrien /* 93684260Sobrien * line is now NEW up to nse 93784260Sobrien */ 93884260Sobrien if (sx >= 0) { 93984260Sobrien ELRE_DEBUG(1, (__F, 940237448Spfg "second diff insert at %d...\r\n", (int)(nse - new))); 941276881Sbapt terminal_move_to_char(el, (int)(nse - new)); 94284260Sobrien if (ols != oe) { 94384260Sobrien ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); 94484260Sobrien if (sx > 0) { 94584260Sobrien /* insert sx chars of new starting at nse */ 94684260Sobrien ELRE_DEBUG(!EL_CAN_INSERT, (__F, 94784260Sobrien "ERROR: cannot insert in second diff\n")); 948276881Sbapt terminal_insertwrite(el, nse, sx); 94984260Sobrien } 95084260Sobrien /* 95184260Sobrien * write (nls-nse) - sx chars of new starting at 95284260Sobrien * (nse + sx) 95384260Sobrien */ 954276881Sbapt terminal_overwrite(el, (nse + sx), 955237448Spfg (size_t)((nls - nse) - sx)); 95684260Sobrien } else { 95784260Sobrien ELRE_DEBUG(1, (__F, "without anything to save\r\n")); 958276881Sbapt terminal_overwrite(el, nse, (size_t)(nls - nse)); 9591573Srgrimes 96084260Sobrien /* 96184260Sobrien * No need to do a clear-to-end here because we were 96284260Sobrien * doing a second insert, so we will have over 96384260Sobrien * written all of the old string. 96484260Sobrien */ 96584260Sobrien } 96684260Sobrien } 96784260Sobrien ELRE_DEBUG(1, (__F, "done.\r\n")); 96884260Sobrien} 9691573Srgrimes 97084260Sobrien 9711573Srgrimes/* re__copy_and_pad(): 9721573Srgrimes * Copy string and pad with spaces 9731573Srgrimes */ 9741573Srgrimesprivate void 975276881Sbaptre__copy_and_pad(Char *dst, const Char *src, size_t width) 9761573Srgrimes{ 977148834Sstefanf size_t i; 9781573Srgrimes 97984260Sobrien for (i = 0; i < width; i++) { 98084260Sobrien if (*src == '\0') 98184260Sobrien break; 98284260Sobrien *dst++ = *src++; 98384260Sobrien } 9841573Srgrimes 98584260Sobrien for (; i < width; i++) 98684260Sobrien *dst++ = ' '; 9871573Srgrimes 98884260Sobrien *dst = '\0'; 98984260Sobrien} 9901573Srgrimes 99184260Sobrien 9921573Srgrimes/* re_refresh_cursor(): 9931573Srgrimes * Move to the new cursor position 9941573Srgrimes */ 9951573Srgrimesprotected void 99684260Sobrienre_refresh_cursor(EditLine *el) 9971573Srgrimes{ 998276881Sbapt Char *cp; 999276881Sbapt int h, v, th, w; 10001573Srgrimes 1001148834Sstefanf if (el->el_line.cursor >= el->el_line.lastchar) { 1002148834Sstefanf if (el->el_map.current == el->el_map.alt 1003148834Sstefanf && el->el_line.lastchar != el->el_line.buffer) 1004148834Sstefanf el->el_line.cursor = el->el_line.lastchar - 1; 1005148834Sstefanf else 1006148834Sstefanf el->el_line.cursor = el->el_line.lastchar; 1007148834Sstefanf } 1008148834Sstefanf 100984260Sobrien /* first we must find where the cursor is... */ 101084260Sobrien h = el->el_prompt.p_pos.h; 101184260Sobrien v = el->el_prompt.p_pos.v; 1012276881Sbapt th = el->el_terminal.t_size.h; /* optimize for speed */ 10131573Srgrimes 101484260Sobrien /* do input buffer to el->el_line.cursor */ 101584260Sobrien for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) { 1016276881Sbapt switch (ct_chr_class(*cp)) { 1017276881Sbapt case CHTYPE_NL: /* handle newline in data part too */ 101884260Sobrien h = 0; 101984260Sobrien v++; 1020237448Spfg break; 1021276881Sbapt case CHTYPE_TAB: /* if a tab, to next tab stop */ 1022237448Spfg while (++h & 07) 1023237448Spfg continue; 1024237448Spfg break; 1025237448Spfg default: 1026276881Sbapt w = Width(*cp); 1027276881Sbapt if (w > 1 && h + w > th) { /* won't fit on line */ 1028276881Sbapt h = 0; 1029276881Sbapt v++; 1030276881Sbapt } 1031276881Sbapt h += ct_visual_width(*cp); 1032237448Spfg break; 1033276881Sbapt } 103484260Sobrien 103584260Sobrien if (h >= th) { /* check, extra long tabs picked up here also */ 1036237448Spfg h -= th; 103784260Sobrien v++; 10381573Srgrimes } 10391573Srgrimes } 1040276881Sbapt /* if we have a next character, and it's a doublewidth one, we need to 1041276881Sbapt * check whether we need to linebreak for it to fit */ 1042276881Sbapt if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1) 1043276881Sbapt if (h + w > th) { 1044276881Sbapt h = 0; 1045276881Sbapt v++; 1046276881Sbapt } 10471573Srgrimes 104884260Sobrien /* now go there */ 1049276881Sbapt terminal_move_to_line(el, v); 1050276881Sbapt terminal_move_to_char(el, h); 1051276881Sbapt terminal__flush(el); 105284260Sobrien} 10531573Srgrimes 10541573Srgrimes 10551573Srgrimes/* re_fastputc(): 10561573Srgrimes * Add a character fast. 10571573Srgrimes */ 10581573Srgrimesprivate void 1059313981Spfgre_fastputc(EditLine *el, wint_t c) 10601573Srgrimes{ 1061276881Sbapt int w = Width((Char)c); 1062276881Sbapt while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) 1063276881Sbapt re_fastputc(el, ' '); 10641573Srgrimes 1065276881Sbapt terminal__putc(el, c); 1066313981Spfg el->el_display[el->el_cursor.v][el->el_cursor.h++] = (Char)c; 1067276881Sbapt while (--w > 0) 1068276881Sbapt el->el_display[el->el_cursor.v][el->el_cursor.h++] 1069276881Sbapt = MB_FILL_CHAR; 1070276881Sbapt 1071276881Sbapt if (el->el_cursor.h >= el->el_terminal.t_size.h) { 107284260Sobrien /* if we must overflow */ 107384260Sobrien el->el_cursor.h = 0; 10741573Srgrimes 107584260Sobrien /* 107684260Sobrien * If we would overflow (input is longer than terminal size), 107784260Sobrien * emulate scroll by dropping first line and shuffling the rest. 107884260Sobrien * We do this via pointer shuffling - it's safe in this case 107984260Sobrien * and we avoid memcpy(). 108084260Sobrien */ 1081276881Sbapt if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { 1082276881Sbapt int i, lins = el->el_terminal.t_size.v; 1083276881Sbapt Char *firstline = el->el_display[0]; 1084313981Spfg 1085237448Spfg for(i = 1; i < lins; i++) 1086237448Spfg el->el_display[i - 1] = el->el_display[i]; 108784260Sobrien 1088276881Sbapt re__copy_and_pad(firstline, STR(""), (size_t)0); 1089237448Spfg el->el_display[i - 1] = firstline; 109084260Sobrien } else { 109184260Sobrien el->el_cursor.v++; 109284260Sobrien el->el_refresh.r_oldcv++; 109384260Sobrien } 109484260Sobrien if (EL_HAS_AUTO_MARGINS) { 109584260Sobrien if (EL_HAS_MAGIC_MARGINS) { 1096276881Sbapt terminal__putc(el, ' '); 1097276881Sbapt terminal__putc(el, '\b'); 109884260Sobrien } 109984260Sobrien } else { 1100276881Sbapt terminal__putc(el, '\r'); 1101276881Sbapt terminal__putc(el, '\n'); 110284260Sobrien } 110384260Sobrien } 110484260Sobrien} 110584260Sobrien 110684260Sobrien 11071573Srgrimes/* re_fastaddc(): 11081573Srgrimes * we added just one char, handle it fast. 11098870Srgrimes * Assumes that screen cursor == real cursor 11101573Srgrimes */ 11111573Srgrimesprotected void 111284260Sobrienre_fastaddc(EditLine *el) 11131573Srgrimes{ 1114276881Sbapt Char c; 111584260Sobrien int rhdiff; 11161573Srgrimes 1117276881Sbapt c = el->el_line.cursor[-1]; 11181573Srgrimes 111984260Sobrien if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { 112084260Sobrien re_refresh(el); /* too hard to handle */ 112184260Sobrien return; 112284260Sobrien } 1123276881Sbapt rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - 112484260Sobrien el->el_rprompt.p_pos.h; 112584260Sobrien if (el->el_rprompt.p_pos.h && rhdiff < 3) { 112684260Sobrien re_refresh(el); /* clear out rprompt if less than 1 char gap */ 112784260Sobrien return; 112884260Sobrien } /* else (only do at end of line, no TAB) */ 1129276881Sbapt switch (ct_chr_class(c)) { 1130276881Sbapt case CHTYPE_TAB: /* already handled, should never happen here */ 1131276881Sbapt break; 1132276881Sbapt case CHTYPE_NL: 1133276881Sbapt case CHTYPE_PRINT: 113484260Sobrien re_fastputc(el, c); 1135276881Sbapt break; 1136276881Sbapt case CHTYPE_ASCIICTL: 1137276881Sbapt case CHTYPE_NONPRINT: { 1138276881Sbapt Char visbuf[VISUAL_WIDTH_MAX]; 1139276881Sbapt ssize_t i, n = 1140276881Sbapt ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); 1141276881Sbapt for (i = 0; n-- > 0; ++i) 1142276881Sbapt re_fastputc(el, visbuf[i]); 1143276881Sbapt break; 114484260Sobrien } 1145276881Sbapt } 1146276881Sbapt terminal__flush(el); 114784260Sobrien} 11481573Srgrimes 11491573Srgrimes 11501573Srgrimes/* re_clear_display(): 1151330446Seadler * clear the screen buffers so that new prompt starts fresh. 11521573Srgrimes */ 11531573Srgrimesprotected void 115484260Sobrienre_clear_display(EditLine *el) 11551573Srgrimes{ 115684260Sobrien int i; 11571573Srgrimes 115884260Sobrien el->el_cursor.v = 0; 115984260Sobrien el->el_cursor.h = 0; 1160276881Sbapt for (i = 0; i < el->el_terminal.t_size.v; i++) 116184260Sobrien el->el_display[i][0] = '\0'; 116284260Sobrien el->el_refresh.r_oldcv = 0; 116384260Sobrien} 11641573Srgrimes 11651573Srgrimes 11661573Srgrimes/* re_clear_lines(): 11678870Srgrimes * Make sure all lines are *really* blank 11681573Srgrimes */ 11691573Srgrimesprotected void 117084260Sobrienre_clear_lines(EditLine *el) 11711573Srgrimes{ 117284260Sobrien 117384260Sobrien if (EL_CAN_CEOL) { 117484260Sobrien int i; 1175237448Spfg for (i = el->el_refresh.r_oldcv; i >= 0; i--) { 117684260Sobrien /* for each line on the screen */ 1177276881Sbapt terminal_move_to_line(el, i); 1178276881Sbapt terminal_move_to_char(el, 0); 1179276881Sbapt terminal_clear_EOL(el, el->el_terminal.t_size.h); 118084260Sobrien } 118184260Sobrien } else { 1182276881Sbapt terminal_move_to_line(el, el->el_refresh.r_oldcv); 118384260Sobrien /* go to last line */ 1184276881Sbapt terminal__putc(el, '\r'); /* go to BOL */ 1185276881Sbapt terminal__putc(el, '\n'); /* go to new line */ 11861573Srgrimes } 118784260Sobrien} 1188