diff options
Diffstat (limited to 'bin/cash/libedit/refresh.c')
-rw-r--r-- | bin/cash/libedit/refresh.c | 1219 |
1 files changed, 0 insertions, 1219 deletions
diff --git a/bin/cash/libedit/refresh.c b/bin/cash/libedit/refresh.c deleted file mode 100644 index 37c6041d..00000000 --- a/bin/cash/libedit/refresh.c +++ /dev/null @@ -1,1219 +0,0 @@ -/* $NetBSD: refresh.c,v 1.51.8.1 2017/07/23 14:41:26 snj Exp $ */ - -/*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Christos Zoulas of Cornell University. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "config.h" -#if !defined(lint) && !defined(SCCSID) -#if 0 -static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; -#else -__RCSID("$NetBSD: refresh.c,v 1.51.8.1 2017/07/23 14:41:26 snj Exp $"); -#endif -#endif /* not lint && not SCCSID */ - -/* - * refresh.c: Lower level screen refreshing functions - */ -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "el.h" - -static void re_nextline(EditLine *); -static void re_addc(EditLine *, wint_t); -static void re_update_line(EditLine *, wchar_t *, wchar_t *, int); -static void re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int); -static void re_delete(EditLine *, wchar_t *, int, int, int); -static void re_fastputc(EditLine *, wint_t); -static void re_clear_eol(EditLine *, int, int, int); -static void re__strncopy(wchar_t *, wchar_t *, size_t); -static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t); - -#ifdef DEBUG_REFRESH -static void re_printstr(EditLine *, const char *, wchar_t *, wchar_t *); -#define __F el->el_errfile -#define ELRE_ASSERT(a, b, c) do \ - if (/*CONSTCOND*/ a) { \ - (void) fprintf b; \ - c; \ - } \ - while (/*CONSTCOND*/0) -#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) - -/* re_printstr(): - * Print a string on the debugging pty - */ -static void -re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t) -{ - - ELRE_DEBUG(1, (__F, "%s:\"", str)); - while (f < t) - ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); - ELRE_DEBUG(1, (__F, "\"\r\n")); -} -#else -#define ELRE_ASSERT(a, b, c) -#define ELRE_DEBUG(a, b) -#endif - -/* re_nextline(): - * Move to the next line or scroll - */ -static void -re_nextline(EditLine *el) -{ - el->el_refresh.r_cursor.h = 0; /* reset it. */ - - /* - * If we would overflow (input is longer than terminal size), - * emulate scroll by dropping first line and shuffling the rest. - * We do this via pointer shuffling - it's safe in this case - * and we avoid memcpy(). - */ - if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { - int i, lins = el->el_terminal.t_size.v; - wchar_t *firstline = el->el_vdisplay[0]; - - for(i = 1; i < lins; i++) - el->el_vdisplay[i - 1] = el->el_vdisplay[i]; - - firstline[0] = '\0'; /* empty the string */ - el->el_vdisplay[i - 1] = firstline; - } else - el->el_refresh.r_cursor.v++; - - ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.v, - (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", - el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), - abort()); -} - -/* re_addc(): - * Draw c, expanding tabs, control chars etc. - */ -static void -re_addc(EditLine *el, wint_t c) -{ - switch (ct_chr_class(c)) { - case CHTYPE_TAB: /* expand the tab */ - for (;;) { - re_putc(el, ' ', 1); - if ((el->el_refresh.r_cursor.h & 07) == 0) - break; /* go until tab stop */ - } - break; - case CHTYPE_NL: { - int oldv = el->el_refresh.r_cursor.v; - re_putc(el, '\0', 0); /* assure end of line */ - if (oldv == el->el_refresh.r_cursor.v) /* XXX */ - re_nextline(el); - break; - } - case CHTYPE_PRINT: - re_putc(el, c, 1); - break; - default: { - wchar_t visbuf[VISUAL_WIDTH_MAX]; - ssize_t i, n = - ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); - for (i = 0; n-- > 0; ++i) - re_putc(el, visbuf[i], 1); - break; - } - } -} - -/* re_putliteral(): - * Place the literal string given - */ -libedit_private void -re_putliteral(EditLine *el, const wchar_t *begin, const wchar_t *end) -{ - coord_t *cur = &el->el_refresh.r_cursor; - wint_t c; - int sizeh = el->el_terminal.t_size.h; - int i, w; - - c = literal_add(el, begin, end, &w); - if (c == 0 || w <= 0) - return; - el->el_vdisplay[cur->v][cur->h] = c; - - i = w; - if (i > sizeh - cur->h) /* avoid overflow */ - i = sizeh - cur->h; - while (--i > 0) - el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR; - - cur->h += w; - if (cur->h >= sizeh) { - /* assure end of line */ - el->el_vdisplay[cur->v][sizeh] = '\0'; - re_nextline(el); - } -} - -/* re_putc(): - * Draw the character given - */ -libedit_private void -re_putc(EditLine *el, wint_t c, int shift) -{ - coord_t *cur = &el->el_refresh.r_cursor; - int i, w = wcwidth(c); - int sizeh = el->el_terminal.t_size.h; - - ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c)); - if (w == -1) - w = 0; - - while (shift && (cur->h + w > sizeh)) - re_putc(el, ' ', 1); - - el->el_vdisplay[cur->v][cur->h] = c; - /* assumes !shift is only used for single-column chars */ - i = w; - while (--i > 0) - el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR; - - if (!shift) - return; - - cur->h += w; /* advance to next place */ - if (cur->h >= sizeh) { - /* assure end of line */ - el->el_vdisplay[cur->v][sizeh] = '\0'; - re_nextline(el); - } -} - - -/* re_refresh(): - * draws the new virtual screen image from the current input - * line, then goes line-by-line changing the real image to the new - * virtual image. The routine to re-draw a line can be replaced - * easily in hopes of a smarter one being placed there. - */ -libedit_private void -re_refresh(EditLine *el) -{ - int i, rhdiff; - wchar_t *cp, *st; - coord_t cur; -#ifdef notyet - size_t termsz; -#endif - - ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n", - el->el_line.buffer)); - - literal_clear(el); - /* reset the Drawing cursor */ - el->el_refresh.r_cursor.h = 0; - el->el_refresh.r_cursor.v = 0; - - terminal_move_to_char(el, 0); - - /* temporarily draw rprompt to calculate its size */ - prompt_print(el, EL_RPROMPT); - - /* reset the Drawing cursor */ - el->el_refresh.r_cursor.h = 0; - el->el_refresh.r_cursor.v = 0; - - if (el->el_line.cursor >= el->el_line.lastchar) { - if (el->el_map.current == el->el_map.alt - && el->el_line.lastchar != el->el_line.buffer) - el->el_line.cursor = el->el_line.lastchar - 1; - else - el->el_line.cursor = el->el_line.lastchar; - } - - cur.h = -1; /* set flag in case I'm not set */ - cur.v = 0; - - prompt_print(el, EL_PROMPT); - - /* draw the current input buffer */ -#if notyet - termsz = el->el_terminal.t_size.h * el->el_terminal.t_size.v; - if (el->el_line.lastchar - el->el_line.buffer > termsz) { - /* - * If line is longer than terminal, process only part - * of line which would influence display. - */ - size_t rem = (el->el_line.lastchar-el->el_line.buffer)%termsz; - - st = el->el_line.lastchar - rem - - (termsz - (((rem / el->el_terminal.t_size.v) - 1) - * el->el_terminal.t_size.v)); - } else -#endif - st = el->el_line.buffer; - - for (cp = st; cp < el->el_line.lastchar; cp++) { - if (cp == el->el_line.cursor) { - int w = wcwidth(*cp); - /* save for later */ - cur.h = el->el_refresh.r_cursor.h; - cur.v = el->el_refresh.r_cursor.v; - /* handle being at a linebroken doublewidth char */ - if (w > 1 && el->el_refresh.r_cursor.h + w > - el->el_terminal.t_size.h) { - cur.h = 0; - cur.v++; - } - } - re_addc(el, *cp); - } - - if (cur.h == -1) { /* if I haven't been set yet, I'm at the end */ - cur.h = el->el_refresh.r_cursor.h; - cur.v = el->el_refresh.r_cursor.v; - } - rhdiff = el->el_terminal.t_size.h - el->el_refresh.r_cursor.h - - el->el_rprompt.p_pos.h; - if (el->el_rprompt.p_pos.h && !el->el_rprompt.p_pos.v && - !el->el_refresh.r_cursor.v && rhdiff > 1) { - /* - * have a right-hand side prompt that will fit - * on the end of the first line with at least - * one character gap to the input buffer. - */ - while (--rhdiff > 0) /* pad out with spaces */ - re_putc(el, ' ', 1); - prompt_print(el, EL_RPROMPT); - } else { - el->el_rprompt.p_pos.h = 0; /* flag "not using rprompt" */ - el->el_rprompt.p_pos.v = 0; - } - - re_putc(el, '\0', 0); /* make line ended with NUL, no cursor shift */ - - el->el_refresh.r_newcv = el->el_refresh.r_cursor.v; - - ELRE_DEBUG(1, (__F, - "term.h=%d vcur.h=%d vcur.v=%d vdisplay[0]=\r\n:%80.80s:\r\n", - el->el_terminal.t_size.h, el->el_refresh.r_cursor.h, - el->el_refresh.r_cursor.v, ct_encode_string(el->el_vdisplay[0], - &el->el_scratch))); - - ELRE_DEBUG(1, (__F, "updating %d lines.\r\n", el->el_refresh.r_newcv)); - for (i = 0; i <= el->el_refresh.r_newcv; i++) { - /* NOTE THAT re_update_line MAY CHANGE el_display[i] */ - re_update_line(el, el->el_display[i], el->el_vdisplay[i], i); - - /* - * Copy the new line to be the current one, and pad out with - * spaces to the full width of the terminal so that if we try - * moving the cursor by writing the character that is at the - * end of the screen line, it won't be a NUL or some old - * leftover stuff. - */ - re__copy_and_pad(el->el_display[i], el->el_vdisplay[i], - (size_t) el->el_terminal.t_size.h); - } - ELRE_DEBUG(1, (__F, - "\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", - el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i)); - - if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) - for (; i <= el->el_refresh.r_oldcv; i++) { - terminal_move_to_line(el, i); - terminal_move_to_char(el, 0); - /* This wcslen should be safe even with MB_FILL_CHARs */ - terminal_clear_EOL(el, (int) wcslen(el->el_display[i])); -#ifdef DEBUG_REFRESH - terminal_overwrite(el, L"C\b", 2); -#endif /* DEBUG_REFRESH */ - el->el_display[i][0] = '\0'; - } - - el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ - ELRE_DEBUG(1, (__F, - "\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", - el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, - cur.h, cur.v)); - terminal_move_to_line(el, cur.v); /* go to where the cursor is */ - terminal_move_to_char(el, cur.h); -} - - -/* re_goto_bottom(): - * used to go to last used screen line - */ -libedit_private void -re_goto_bottom(EditLine *el) -{ - - terminal_move_to_line(el, el->el_refresh.r_oldcv); - terminal__putc(el, '\n'); - re_clear_display(el); - terminal__flush(el); -} - - -/* re_insert(): - * insert num characters of s into d (in front of the character) - * at dat, maximum length of d is dlen - */ -static void -/*ARGSUSED*/ -re_insert(EditLine *el __attribute__((__unused__)), - wchar_t *d, int dat, int dlen, wchar_t *s, int num) -{ - wchar_t *a, *b; - - if (num <= 0) - return; - if (num > dlen - dat) - num = dlen - dat; - - ELRE_DEBUG(1, - (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d, &el->el_scratch))); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s, - &el->el_scratch))); - - /* open up the space for num chars */ - if (num > 0) { - b = d + dlen - 1; - a = b - num; - while (a >= &d[dat]) - *b-- = *a--; - d[dlen] = '\0'; /* just in case */ - } - - ELRE_DEBUG(1, (__F, - "re_insert() after insert: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d, &el->el_scratch))); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", ct_encode_string(s, - &el->el_scratch))); - - /* copy the characters */ - for (a = d + dat; (a < d + dlen) && (num > 0); num--) - *a++ = *s++; - -#ifdef notyet - /* ct_encode_string() uses a static buffer, so we can't conveniently - * encode both d & s here */ - ELRE_DEBUG(1, - (__F, "re_insert() after copy: %d at %d max %d, %s == \"%s\"\n", - num, dat, dlen, d, s)); - ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); -#endif -} - - -/* re_delete(): - * delete num characters d at dat, maximum length of d is dlen - */ -static void -/*ARGSUSED*/ -re_delete(EditLine *el __attribute__((__unused__)), - wchar_t *d, int dat, int dlen, int num) -{ - wchar_t *a, *b; - - if (num <= 0) - return; - if (dat + num >= dlen) { - d[dat] = '\0'; - return; - } - ELRE_DEBUG(1, - (__F, "re_delete() starting: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d, &el->el_scratch))); - - /* open up the space for num chars */ - if (num > 0) { - b = d + dat; - a = b + num; - while (a < &d[dlen]) - *b++ = *a++; - d[dlen] = '\0'; /* just in case */ - } - ELRE_DEBUG(1, - (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", - num, dat, dlen, ct_encode_string(d, &el->el_scratch))); -} - - -/* re__strncopy(): - * Like strncpy without padding. - */ -static void -re__strncopy(wchar_t *a, wchar_t *b, size_t n) -{ - - while (n-- && *b) - *a++ = *b++; -} - -/* re_clear_eol(): - * Find the number of characters we need to clear till the end of line - * in order to make sure that we have cleared the previous contents of - * the line. fx and sx is the number of characters inserted or deleted - * in the first or second diff, diff is the difference between the - * number of characters between the new and old line. - */ -static void -re_clear_eol(EditLine *el, int fx, int sx, int diff) -{ - - ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n", - sx, fx, diff)); - - if (fx < 0) - fx = -fx; - if (sx < 0) - sx = -sx; - if (fx > diff) - diff = fx; - if (sx > diff) - diff = sx; - - ELRE_DEBUG(1, (__F, "re_clear_eol %d\n", diff)); - terminal_clear_EOL(el, diff); -} - -/***************************************************************** - re_update_line() is based on finding the middle difference of each line - on the screen; vis: - - /old first difference - /beginning of line | /old last same /old EOL - v v v v -old: eddie> Oh, my little gruntle-buggy is to me, as lurgid as -new: eddie> Oh, my little buggy says to me, as lurgid as - ^ ^ ^ ^ - \beginning of line | \new last same \new end of line - \new first difference - - all are character pointers for the sake of speed. Special cases for - no differences, as well as for end of line additions must be handled. -**************************************************************** */ - -/* Minimum at which doing an insert it "worth it". This should be about - * half the "cost" of going into insert mode, inserting a character, and - * going back out. This should really be calculated from the termcap - * data... For the moment, a good number for ANSI terminals. - */ -#define MIN_END_KEEP 4 - -static void -re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i) -{ - wchar_t *o, *n, *p, c; - wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne; - wchar_t *osb, *ose, *nsb, *nse; - int fx, sx; - size_t len; - - /* - * find first diff - */ - for (o = old, n = new; *o && (*o == *n); o++, n++) - continue; - ofd = o; - nfd = n; - - /* - * Find the end of both old and new - */ - while (*o) - o++; - /* - * Remove any trailing blanks off of the end, being careful not to - * back up past the beginning. - */ - while (ofd < o) { - if (o[-1] != ' ') - break; - o--; - } - oe = o; - *oe = '\0'; - - while (*n) - n++; - - /* remove blanks from end of new */ - while (nfd < n) { - if (n[-1] != ' ') - break; - n--; - } - ne = n; - *ne = '\0'; - - /* - * if no diff, continue to next line of redraw - */ - if (*ofd == '\0' && *nfd == '\0') { - ELRE_DEBUG(1, (__F, "no difference.\r\n")); - return; - } - /* - * find last same pointer - */ - while ((o > ofd) && (n > nfd) && (*--o == *--n)) - continue; - ols = ++o; - nls = ++n; - - /* - * find same beginning and same end - */ - osb = ols; - nsb = nls; - ose = ols; - nse = nls; - - /* - * case 1: insert: scan from nfd to nls looking for *ofd - */ - if (*ofd) { - for (c = *ofd, n = nfd; n < nls; n++) { - if (c == *n) { - for (o = ofd, p = n; - p < nls && o < ols && *o == *p; - o++, p++) - continue; - /* - * if the new match is longer and it's worth - * keeping, then we take it - */ - if (((nse - nsb) < (p - n)) && - (2 * (p - n) > n - nfd)) { - nsb = n; - nse = p; - osb = ofd; - ose = o; - } - } - } - } - /* - * case 2: delete: scan from ofd to ols looking for *nfd - */ - if (*nfd) { - for (c = *nfd, o = ofd; o < ols; o++) { - if (c == *o) { - for (n = nfd, p = o; - p < ols && n < nls && *p == *n; - p++, n++) - continue; - /* - * if the new match is longer and it's worth - * keeping, then we take it - */ - if (((ose - osb) < (p - o)) && - (2 * (p - o) > o - ofd)) { - nsb = nfd; - nse = n; - osb = o; - ose = p; - } - } - } - } - /* - * Pragmatics I: If old trailing whitespace or not enough characters to - * save to be worth it, then don't save the last same info. - */ - if ((oe - ols) < MIN_END_KEEP) { - ols = oe; - nls = ne; - } - /* - * Pragmatics II: if the terminal isn't smart enough, make the data - * dumber so the smart update doesn't try anything fancy - */ - - /* - * fx is the number of characters we need to insert/delete: in the - * beginning to bring the two same begins together - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - /* - * sx is the number of characters we need to insert/delete: in the - * end to bring the two same last parts together - */ - sx = (int)((nls - nse) - (ols - ose)); - - if (!EL_CAN_INSERT) { - if (fx > 0) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - if (sx > 0) { - ols = oe; - nls = ne; - } - if ((ols - ofd) < (nls - nfd)) { - ols = oe; - nls = ne; - } - } - if (!EL_CAN_DELETE) { - if (fx < 0) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - if (sx < 0) { - ols = oe; - nls = ne; - } - if ((ols - ofd) > (nls - nfd)) { - ols = oe; - nls = ne; - } - } - /* - * Pragmatics III: make sure the middle shifted pointers are correct if - * they don't point to anything (we may have moved ols or nls). - */ - /* if the change isn't worth it, don't bother */ - /* was: if (osb == ose) */ - if ((ose - osb) < MIN_END_KEEP) { - osb = ols; - ose = ols; - nsb = nls; - nse = nls; - } - /* - * Now that we are done with pragmatics we recompute fx, sx - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - sx = (int)((nls - nse) - (ols - ose)); - - ELRE_DEBUG(1, (__F, "fx %d, sx %d\n", fx, sx)); - ELRE_DEBUG(1, (__F, "ofd %td, osb %td, ose %td, ols %td, oe %td\n", - ofd - old, osb - old, ose - old, ols - old, oe - old)); - ELRE_DEBUG(1, (__F, "nfd %td, nsb %td, nse %td, nls %td, ne %td\n", - nfd - new, nsb - new, nse - new, nls - new, ne - new)); - ELRE_DEBUG(1, (__F, - "xxx-xxx:\"00000000001111111111222222222233333333334\"\r\n")); - ELRE_DEBUG(1, (__F, - "xxx-xxx:\"01234567890123456789012345678901234567890\"\r\n")); -#ifdef DEBUG_REFRESH - re_printstr(el, "old- oe", old, oe); - re_printstr(el, "new- ne", new, ne); - re_printstr(el, "old-ofd", old, ofd); - re_printstr(el, "new-nfd", new, nfd); - re_printstr(el, "ofd-osb", ofd, osb); - re_printstr(el, "nfd-nsb", nfd, nsb); - re_printstr(el, "osb-ose", osb, ose); - re_printstr(el, "nsb-nse", nsb, nse); - re_printstr(el, "ose-ols", ose, ols); - re_printstr(el, "nse-nls", nse, nls); - re_printstr(el, "ols- oe", ols, oe); - re_printstr(el, "nls- ne", nls, ne); -#endif /* DEBUG_REFRESH */ - - /* - * el_cursor.v to this line i MUST be in this routine so that if we - * don't have to change the line, we don't move to it. el_cursor.h to - * first diff char - */ - terminal_move_to_line(el, i); - - /* - * at this point we have something like this: - * - * /old /ofd /osb /ose /ols /oe - * v.....................v v..................v v........v - * eddie> Oh, my fredded gruntle-buggy is to me, as foo var lurgid as - * eddie> Oh, my fredded quiux buggy is to me, as gruntle-lurgid as - * ^.....................^ ^..................^ ^........^ - * \new \nfd \nsb \nse \nls \ne - * - * fx is the difference in length between the chars between nfd and - * nsb, and the chars between ofd and osb, and is thus the number of - * characters to delete if < 0 (new is shorter than old, as above), - * or insert (new is longer than short). - * - * sx is the same for the second differences. - */ - - /* - * if we have a net insert on the first difference, AND inserting the - * net amount ((nsb-nfd) - (osb-ofd)) won't push the last useful - * character (which is ne if nls != ne, otherwise is nse) off the edge - * of the screen (el->el_terminal.t_size.h) else we do the deletes first - * so that we keep everything we need to. - */ - - /* - * if the last same is the same like the end, there is no last same - * part, otherwise we want to keep the last same part set p to the - * last useful old character - */ - p = (ols != oe) ? oe : ose; - - /* - * if (There is a diffence in the beginning) && (we need to insert - * characters) && (the number of characters to insert is less than - * the term width) - * We need to do an insert! - * else if (we need to delete characters) - * We need to delete characters! - * else - * No insert or delete - */ - if ((nsb != nfd) && fx > 0 && - ((p - old) + fx <= el->el_terminal.t_size.h)) { - ELRE_DEBUG(1, - (__F, "first diff insert at %td...\r\n", nfd - new)); - /* - * Move to the first char to insert, where the first diff is. - */ - terminal_move_to_char(el, (int)(nfd - new)); - /* - * Check if we have stuff to keep at end - */ - if (nsb != ne) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - /* - * insert fx chars of new starting at nfd - */ - if (fx > 0) { - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in early first diff\n")); - terminal_insertwrite(el, nfd, fx); - re_insert(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, nfd, fx); - } - /* - * write (nsb-nfd) - fx chars of new starting at - * (nfd + fx) - */ - len = (size_t) ((nsb - nfd) - fx); - terminal_overwrite(el, (nfd + fx), len); - re__strncopy(ofd + fx, nfd + fx, len); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - len = (size_t)(nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - /* - * Done - */ - return; - } - } else if (fx < 0) { - ELRE_DEBUG(1, - (__F, "first diff delete at %td...\r\n", ofd - old)); - /* - * move to the first char to delete where the first diff is - */ - terminal_move_to_char(el, (int)(ofd - old)); - /* - * Check if we have stuff to save - */ - if (osb != oe) { - ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); - /* - * fx is less than zero *always* here but we check - * for code symmetry - */ - if (fx < 0) { - ELRE_DEBUG(!EL_CAN_DELETE, (__F, - "ERROR: cannot delete in first diff\n")); - terminal_deletechars(el, -fx); - re_delete(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, -fx); - } - /* - * write (nsb-nfd) chars of new starting at nfd - */ - len = (size_t) (nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - - } else { - ELRE_DEBUG(1, (__F, - "but with nothing left to save\r\n")); - /* - * write (nsb-nfd) chars of new starting at nfd - */ - terminal_overwrite(el, nfd, (size_t)(nsb - nfd)); - re_clear_eol(el, fx, sx, - (int)((oe - old) - (ne - new))); - /* - * Done - */ - return; - } - } else - fx = 0; - - if (sx < 0 && (ose - old) + fx < el->el_terminal.t_size.h) { - ELRE_DEBUG(1, (__F, - "second diff delete at %td...\r\n", (ose - old) + fx)); - /* - * Check if we have stuff to delete - */ - /* - * fx is the number of characters inserted (+) or deleted (-) - */ - - terminal_move_to_char(el, (int)((ose - old) + fx)); - /* - * Check if we have stuff to save - */ - if (ols != oe) { - ELRE_DEBUG(1, (__F, "with stuff to save at end\r\n")); - /* - * Again a duplicate test. - */ - if (sx < 0) { - ELRE_DEBUG(!EL_CAN_DELETE, (__F, - "ERROR: cannot delete in second diff\n")); - terminal_deletechars(el, -sx); - } - /* - * write (nls-nse) chars of new starting at nse - */ - terminal_overwrite(el, nse, (size_t)(nls - nse)); - } else { - ELRE_DEBUG(1, (__F, - "but with nothing left to save\r\n")); - terminal_overwrite(el, nse, (size_t)(nls - nse)); - re_clear_eol(el, fx, sx, - (int)((oe - old) - (ne - new))); - } - } - /* - * if we have a first insert AND WE HAVEN'T ALREADY DONE IT... - */ - if ((nsb != nfd) && (osb - ofd) <= (nsb - nfd) && (fx == 0)) { - ELRE_DEBUG(1, (__F, "late first diff insert at %td...\r\n", - nfd - new)); - - terminal_move_to_char(el, (int)(nfd - new)); - /* - * Check if we have stuff to keep at the end - */ - if (nsb != ne) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - /* - * We have to recalculate fx here because we set it - * to zero above as a flag saying that we hadn't done - * an early first insert. - */ - fx = (int)((nsb - nfd) - (osb - ofd)); - if (fx > 0) { - /* - * insert fx chars of new starting at nfd - */ - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in late first diff\n")); - terminal_insertwrite(el, nfd, fx); - re_insert(el, old, (int)(ofd - old), - el->el_terminal.t_size.h, nfd, fx); - } - /* - * write (nsb-nfd) - fx chars of new starting at - * (nfd + fx) - */ - len = (size_t) ((nsb - nfd) - fx); - terminal_overwrite(el, (nfd + fx), len); - re__strncopy(ofd + fx, nfd + fx, len); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - len = (size_t) (nsb - nfd); - terminal_overwrite(el, nfd, len); - re__strncopy(ofd, nfd, len); - } - } - /* - * line is now NEW up to nse - */ - if (sx >= 0) { - ELRE_DEBUG(1, (__F, - "second diff insert at %d...\r\n", (int)(nse - new))); - terminal_move_to_char(el, (int)(nse - new)); - if (ols != oe) { - ELRE_DEBUG(1, (__F, "with stuff to keep at end\r\n")); - if (sx > 0) { - /* insert sx chars of new starting at nse */ - ELRE_DEBUG(!EL_CAN_INSERT, (__F, - "ERROR: cannot insert in second diff\n")); - terminal_insertwrite(el, nse, sx); - } - /* - * write (nls-nse) - sx chars of new starting at - * (nse + sx) - */ - terminal_overwrite(el, (nse + sx), - (size_t)((nls - nse) - sx)); - } else { - ELRE_DEBUG(1, (__F, "without anything to save\r\n")); - terminal_overwrite(el, nse, (size_t)(nls - nse)); - - /* - * No need to do a clear-to-end here because we were - * doing a second insert, so we will have over - * written all of the old string. - */ - } - } - ELRE_DEBUG(1, (__F, "done.\r\n")); -} - - -/* re__copy_and_pad(): - * Copy string and pad with spaces - */ -static void -re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width) -{ - size_t i; - - for (i = 0; i < width; i++) { - if (*src == '\0') - break; - *dst++ = *src++; - } - - for (; i < width; i++) - *dst++ = ' '; - - *dst = '\0'; -} - - -/* re_refresh_cursor(): - * Move to the new cursor position - */ -libedit_private void -re_refresh_cursor(EditLine *el) -{ - wchar_t *cp; - int h, v, th, w; - - if (el->el_line.cursor >= el->el_line.lastchar) { - if (el->el_map.current == el->el_map.alt - && el->el_line.lastchar != el->el_line.buffer) - el->el_line.cursor = el->el_line.lastchar - 1; - else - el->el_line.cursor = el->el_line.lastchar; - } - - /* first we must find where the cursor is... */ - h = el->el_prompt.p_pos.h; - v = el->el_prompt.p_pos.v; - th = el->el_terminal.t_size.h; /* optimize for speed */ - - /* do input buffer to el->el_line.cursor */ - for (cp = el->el_line.buffer; cp < el->el_line.cursor; cp++) { - switch (ct_chr_class(*cp)) { - case CHTYPE_NL: /* handle newline in data part too */ - h = 0; - v++; - break; - case CHTYPE_TAB: /* if a tab, to next tab stop */ - while (++h & 07) - continue; - break; - default: - w = wcwidth(*cp); - if (w > 1 && h + w > th) { /* won't fit on line */ - h = 0; - v++; - } - h += ct_visual_width(*cp); - break; - } - - if (h >= th) { /* check, extra long tabs picked up here also */ - h -= th; - v++; - } - } - /* if we have a next character, and it's a doublewidth one, we need to - * check whether we need to linebreak for it to fit */ - if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1) - if (h + w > th) { - h = 0; - v++; - } - - /* now go there */ - terminal_move_to_line(el, v); - terminal_move_to_char(el, h); - terminal__flush(el); -} - - -/* re_fastputc(): - * Add a character fast. - */ -static void -re_fastputc(EditLine *el, wint_t c) -{ - int w = wcwidth(c); - while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) - re_fastputc(el, ' '); - - terminal__putc(el, c); - el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; - while (--w > 0) - el->el_display[el->el_cursor.v][el->el_cursor.h++] - = MB_FILL_CHAR; - - if (el->el_cursor.h >= el->el_terminal.t_size.h) { - /* if we must overflow */ - el->el_cursor.h = 0; - - /* - * If we would overflow (input is longer than terminal size), - * emulate scroll by dropping first line and shuffling the rest. - * We do this via pointer shuffling - it's safe in this case - * and we avoid memcpy(). - */ - if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { - int i, lins = el->el_terminal.t_size.v; - wchar_t *firstline = el->el_display[0]; - - for(i = 1; i < lins; i++) - el->el_display[i - 1] = el->el_display[i]; - - re__copy_and_pad(firstline, L"", (size_t)0); - el->el_display[i - 1] = firstline; - } else { - el->el_cursor.v++; - el->el_refresh.r_oldcv++; - } - if (EL_HAS_AUTO_MARGINS) { - if (EL_HAS_MAGIC_MARGINS) { - terminal__putc(el, ' '); - terminal__putc(el, '\b'); - } - } else { - terminal__putc(el, '\r'); - terminal__putc(el, '\n'); - } - } -} - - -/* re_fastaddc(): - * we added just one char, handle it fast. - * Assumes that screen cursor == real cursor - */ -libedit_private void -re_fastaddc(EditLine *el) -{ - wchar_t c; - int rhdiff; - - c = el->el_line.cursor[-1]; - - if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { - re_refresh(el); /* too hard to handle */ - return; - } - rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - - el->el_rprompt.p_pos.h; - if (el->el_rprompt.p_pos.h && rhdiff < 3) { - re_refresh(el); /* clear out rprompt if less than 1 char gap */ - return; - } /* else (only do at end of line, no TAB) */ - switch (ct_chr_class(c)) { - case CHTYPE_TAB: /* already handled, should never happen here */ - break; - case CHTYPE_NL: - case CHTYPE_PRINT: - re_fastputc(el, c); - break; - case CHTYPE_ASCIICTL: - case CHTYPE_NONPRINT: { - wchar_t visbuf[VISUAL_WIDTH_MAX]; - ssize_t i, n = - ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); - for (i = 0; n-- > 0; ++i) - re_fastputc(el, visbuf[i]); - break; - } - } - terminal__flush(el); -} - - -/* re_clear_display(): - * clear the screen buffers so that new new prompt starts fresh. - */ -libedit_private void -re_clear_display(EditLine *el) -{ - int i; - - el->el_cursor.v = 0; - el->el_cursor.h = 0; - for (i = 0; i < el->el_terminal.t_size.v; i++) - el->el_display[i][0] = '\0'; - el->el_refresh.r_oldcv = 0; -} - - -/* re_clear_lines(): - * Make sure all lines are *really* blank - */ -libedit_private void -re_clear_lines(EditLine *el) -{ - - if (EL_CAN_CEOL) { - int i; - for (i = el->el_refresh.r_oldcv; i >= 0; i--) { - /* for each line on the screen */ - terminal_move_to_line(el, i); - terminal_move_to_char(el, 0); - terminal_clear_EOL(el, el->el_terminal.t_size.h); - } - } else { - terminal_move_to_line(el, el->el_refresh.r_oldcv); - /* go to last line */ - terminal__putc(el, '\r'); /* go to BOL */ - terminal__putc(el, '\n'); /* go to new line */ - } -} |