Changeset View
Changeset View
Standalone View
Standalone View
lib/libedit/refresh.c
/* $NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $ */ | /* $NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $ */ | ||||
/*- | /*- | ||||
* Copyright (c) 1992, 1993 | * Copyright (c) 1992, 1993 | ||||
* The Regents of the University of California. All rights reserved. | * The Regents of the University of California. All rights reserved. | ||||
* | * | ||||
* This code is derived from software contributed to Berkeley by | * This code is derived from software contributed to Berkeley by | ||||
* Christos Zoulas of Cornell University. | * Christos Zoulas of Cornell University. | ||||
* | * | ||||
Show All 22 Lines | |||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
*/ | */ | ||||
#include "config.h" | #include "config.h" | ||||
#if !defined(lint) && !defined(SCCSID) | #if !defined(lint) && !defined(SCCSID) | ||||
#if 0 | #if 0 | ||||
static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; | static char sccsid[] = "@(#)refresh.c 8.1 (Berkeley) 6/4/93"; | ||||
#else | #else | ||||
__RCSID("$NetBSD: refresh.c,v 1.45 2016/03/02 19:24:20 christos Exp $"); | __RCSID("$NetBSD: refresh.c,v 1.56 2019/01/04 03:03:44 uwe Exp $"); | ||||
#endif | #endif | ||||
#endif /* not lint && not SCCSID */ | #endif /* not lint && not SCCSID */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
/* | /* | ||||
* refresh.c: Lower level screen refreshing functions | * refresh.c: Lower level screen refreshing functions | ||||
*/ | */ | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "el.h" | #include "el.h" | ||||
private void re_nextline(EditLine *); | static void re_nextline(EditLine *); | ||||
private void re_addc(EditLine *, wint_t); | static void re_addc(EditLine *, wint_t); | ||||
private void re_update_line(EditLine *, Char *, Char *, int); | static void re_update_line(EditLine *, wchar_t *, wchar_t *, int); | ||||
private void re_insert (EditLine *, Char *, int, int, Char *, int); | static void re_insert (EditLine *, wchar_t *, int, int, wchar_t *, int); | ||||
private void re_delete(EditLine *, Char *, int, int, int); | static void re_delete(EditLine *, wchar_t *, int, int, int); | ||||
private void re_fastputc(EditLine *, wint_t); | static void re_fastputc(EditLine *, wint_t); | ||||
private void re_clear_eol(EditLine *, int, int, int); | static void re_clear_eol(EditLine *, int, int, int); | ||||
private void re__strncopy(Char *, Char *, size_t); | static void re__strncopy(wchar_t *, wchar_t *, size_t); | ||||
private void re__copy_and_pad(Char *, const Char *, size_t); | static void re__copy_and_pad(wchar_t *, const wchar_t *, size_t); | ||||
#ifdef DEBUG_REFRESH | #ifdef DEBUG_REFRESH | ||||
private void re_printstr(EditLine *, const char *, Char *, Char *); | static void re_printstr(EditLine *, const char *, wchar_t *, wchar_t *); | ||||
#define __F el->el_errfile | #define __F el->el_errfile | ||||
#define ELRE_ASSERT(a, b, c) do \ | #define ELRE_ASSERT(a, b, c) do \ | ||||
if (/*CONSTCOND*/ a) { \ | if (/*CONSTCOND*/ a) { \ | ||||
(void) fprintf b; \ | (void) fprintf b; \ | ||||
c; \ | c; \ | ||||
} \ | } \ | ||||
while (/*CONSTCOND*/0) | while (/*CONSTCOND*/0) | ||||
#define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) | #define ELRE_DEBUG(a, b) ELRE_ASSERT(a,b,;) | ||||
/* re_printstr(): | /* re_printstr(): | ||||
* Print a string on the debugging pty | * Print a string on the debugging pty | ||||
*/ | */ | ||||
private void | static void | ||||
re_printstr(EditLine *el, const char *str, Char *f, Char *t) | re_printstr(EditLine *el, const char *str, wchar_t *f, wchar_t *t) | ||||
{ | { | ||||
ELRE_DEBUG(1, (__F, "%s:\"", str)); | ELRE_DEBUG(1, (__F, "%s:\"", str)); | ||||
while (f < t) | while (f < t) | ||||
ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); | ELRE_DEBUG(1, (__F, "%c", *f++ & 0177)); | ||||
ELRE_DEBUG(1, (__F, "\"\r\n")); | ELRE_DEBUG(1, (__F, "\"\r\n")); | ||||
} | } | ||||
#else | #else | ||||
#define ELRE_ASSERT(a, b, c) | #define ELRE_ASSERT(a, b, c) | ||||
#define ELRE_DEBUG(a, b) | #define ELRE_DEBUG(a, b) | ||||
#endif | #endif | ||||
/* re_nextline(): | /* re_nextline(): | ||||
* Move to the next line or scroll | * Move to the next line or scroll | ||||
*/ | */ | ||||
private void | static void | ||||
re_nextline(EditLine *el) | re_nextline(EditLine *el) | ||||
{ | { | ||||
el->el_refresh.r_cursor.h = 0; /* reset it. */ | el->el_refresh.r_cursor.h = 0; /* reset it. */ | ||||
/* | /* | ||||
* If we would overflow (input is longer than terminal size), | * If we would overflow (input is longer than terminal size), | ||||
* emulate scroll by dropping first line and shuffling the rest. | * emulate scroll by dropping first line and shuffling the rest. | ||||
* We do this via pointer shuffling - it's safe in this case | * We do this via pointer shuffling - it's safe in this case | ||||
* and we avoid memcpy(). | * and we avoid memcpy(). | ||||
*/ | */ | ||||
if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { | if (el->el_refresh.r_cursor.v + 1 >= el->el_terminal.t_size.v) { | ||||
int i, lins = el->el_terminal.t_size.v; | int i, lins = el->el_terminal.t_size.v; | ||||
Char *firstline = el->el_vdisplay[0]; | wchar_t *firstline = el->el_vdisplay[0]; | ||||
for(i = 1; i < lins; i++) | for(i = 1; i < lins; i++) | ||||
el->el_vdisplay[i - 1] = el->el_vdisplay[i]; | el->el_vdisplay[i - 1] = el->el_vdisplay[i]; | ||||
firstline[0] = '\0'; /* empty the string */ | firstline[0] = '\0'; /* empty the string */ | ||||
el->el_vdisplay[i - 1] = firstline; | el->el_vdisplay[i - 1] = firstline; | ||||
} else | } else | ||||
el->el_refresh.r_cursor.v++; | el->el_refresh.r_cursor.v++; | ||||
ELRE_ASSERT(el->el_refresh.r_cursor.v >= el->el_terminal.t_size.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", | (__F, "\r\nre_putc: overflow! r_cursor.v == %d > %d\r\n", | ||||
el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), | el->el_refresh.r_cursor.v, el->el_terminal.t_size.v), | ||||
abort()); | abort()); | ||||
} | } | ||||
/* re_addc(): | /* re_addc(): | ||||
* Draw c, expanding tabs, control chars etc. | * Draw c, expanding tabs, control chars etc. | ||||
*/ | */ | ||||
private void | static void | ||||
re_addc(EditLine *el, wint_t c) | re_addc(EditLine *el, wint_t c) | ||||
{ | { | ||||
switch (ct_chr_class((Char)c)) { | switch (ct_chr_class(c)) { | ||||
case CHTYPE_TAB: /* expand the tab */ | case CHTYPE_TAB: /* expand the tab */ | ||||
for (;;) { | for (;;) { | ||||
re_putc(el, ' ', 1); | re_putc(el, ' ', 1); | ||||
if ((el->el_refresh.r_cursor.h & 07) == 0) | if ((el->el_refresh.r_cursor.h & 07) == 0) | ||||
break; /* go until tab stop */ | break; /* go until tab stop */ | ||||
} | } | ||||
break; | break; | ||||
case CHTYPE_NL: { | case CHTYPE_NL: { | ||||
int oldv = el->el_refresh.r_cursor.v; | int oldv = el->el_refresh.r_cursor.v; | ||||
re_putc(el, '\0', 0); /* assure end of line */ | re_putc(el, '\0', 0); /* assure end of line */ | ||||
if (oldv == el->el_refresh.r_cursor.v) /* XXX */ | if (oldv == el->el_refresh.r_cursor.v) /* XXX */ | ||||
re_nextline(el); | re_nextline(el); | ||||
break; | break; | ||||
} | } | ||||
case CHTYPE_PRINT: | case CHTYPE_PRINT: | ||||
re_putc(el, c, 1); | re_putc(el, c, 1); | ||||
break; | break; | ||||
default: { | default: { | ||||
Char visbuf[VISUAL_WIDTH_MAX]; | wchar_t visbuf[VISUAL_WIDTH_MAX]; | ||||
ssize_t i, n = | ssize_t i, n = | ||||
ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); | ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); | ||||
for (i = 0; n-- > 0; ++i) | for (i = 0; n-- > 0; ++i) | ||||
re_putc(el, visbuf[i], 1); | re_putc(el, visbuf[i], 1); | ||||
break; | 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(): | /* re_putc(): | ||||
* Draw the character given | * Draw the character given | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_putc(EditLine *el, wint_t c, int shift) | re_putc(EditLine *el, wint_t c, int shift) | ||||
{ | { | ||||
int i, w = Width(c); | 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)); | ELRE_DEBUG(1, (__F, "printing %5x '%lc'\r\n", c, c)); | ||||
if (w == -1) | |||||
w = 0; | |||||
while (shift && (el->el_refresh.r_cursor.h + w > el->el_terminal.t_size.h)) | while (shift && (cur->h + w > sizeh)) | ||||
re_putc(el, ' ', 1); | re_putc(el, ' ', 1); | ||||
el->el_vdisplay[el->el_refresh.r_cursor.v] | el->el_vdisplay[cur->v][cur->h] = c; | ||||
[el->el_refresh.r_cursor.h] = (Char)c; | |||||
/* assumes !shift is only used for single-column chars */ | /* assumes !shift is only used for single-column chars */ | ||||
i = w; | i = w; | ||||
while (--i > 0) | while (--i > 0) | ||||
el->el_vdisplay[el->el_refresh.r_cursor.v] | el->el_vdisplay[cur->v][cur->h + i] = MB_FILL_CHAR; | ||||
[el->el_refresh.r_cursor.h + i] = MB_FILL_CHAR; | |||||
if (!shift) | if (!shift) | ||||
return; | return; | ||||
el->el_refresh.r_cursor.h += w; /* advance to next place */ | cur->h += w; /* advance to next place */ | ||||
if (el->el_refresh.r_cursor.h >= el->el_terminal.t_size.h) { | if (cur->h >= sizeh) { | ||||
/* assure end of line */ | /* assure end of line */ | ||||
el->el_vdisplay[el->el_refresh.r_cursor.v][el->el_terminal.t_size.h] | el->el_vdisplay[cur->v][sizeh] = '\0'; | ||||
= '\0'; | |||||
re_nextline(el); | re_nextline(el); | ||||
} | } | ||||
} | } | ||||
/* re_refresh(): | /* re_refresh(): | ||||
* draws the new virtual screen image from the current input | * draws the new virtual screen image from the current input | ||||
* line, then goes line-by-line changing the real image to the new | * 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 | * virtual image. The routine to re-draw a line can be replaced | ||||
* easily in hopes of a smarter one being placed there. | * easily in hopes of a smarter one being placed there. | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_refresh(EditLine *el) | re_refresh(EditLine *el) | ||||
{ | { | ||||
int i, rhdiff; | int i, rhdiff; | ||||
Char *cp, *st; | wchar_t *cp, *st; | ||||
coord_t cur; | coord_t cur; | ||||
#ifdef notyet | #ifdef notyet | ||||
size_t termsz; | size_t termsz; | ||||
#endif | #endif | ||||
ELRE_DEBUG(1, (__F, "el->el_line.buffer = :" FSTR ":\r\n", | ELRE_DEBUG(1, (__F, "el->el_line.buffer = :%ls:\r\n", | ||||
el->el_line.buffer)); | el->el_line.buffer)); | ||||
literal_clear(el); | |||||
/* reset the Drawing cursor */ | /* reset the Drawing cursor */ | ||||
el->el_refresh.r_cursor.h = 0; | el->el_refresh.r_cursor.h = 0; | ||||
el->el_refresh.r_cursor.v = 0; | el->el_refresh.r_cursor.v = 0; | ||||
terminal_move_to_char(el, 0); | |||||
/* temporarily draw rprompt to calculate its size */ | /* temporarily draw rprompt to calculate its size */ | ||||
prompt_print(el, EL_RPROMPT); | prompt_print(el, EL_RPROMPT); | ||||
/* reset the Drawing cursor */ | /* reset the Drawing cursor */ | ||||
el->el_refresh.r_cursor.h = 0; | el->el_refresh.r_cursor.h = 0; | ||||
el->el_refresh.r_cursor.v = 0; | el->el_refresh.r_cursor.v = 0; | ||||
if (el->el_line.cursor >= el->el_line.lastchar) { | if (el->el_line.cursor >= el->el_line.lastchar) { | ||||
Show All 23 Lines | st = el->el_line.lastchar - rem | ||||
- (termsz - (((rem / el->el_terminal.t_size.v) - 1) | - (termsz - (((rem / el->el_terminal.t_size.v) - 1) | ||||
* el->el_terminal.t_size.v)); | * el->el_terminal.t_size.v)); | ||||
} else | } else | ||||
#endif | #endif | ||||
st = el->el_line.buffer; | st = el->el_line.buffer; | ||||
for (cp = st; cp < el->el_line.lastchar; cp++) { | for (cp = st; cp < el->el_line.lastchar; cp++) { | ||||
if (cp == el->el_line.cursor) { | if (cp == el->el_line.cursor) { | ||||
int w = Width(*cp); | int w = wcwidth(*cp); | ||||
/* save for later */ | /* save for later */ | ||||
cur.h = el->el_refresh.r_cursor.h; | cur.h = el->el_refresh.r_cursor.h; | ||||
cur.v = el->el_refresh.r_cursor.v; | cur.v = el->el_refresh.r_cursor.v; | ||||
/* handle being at a linebroken doublewidth char */ | /* handle being at a linebroken doublewidth char */ | ||||
if (w > 1 && el->el_refresh.r_cursor.h + w > | if (w > 1 && el->el_refresh.r_cursor.h + w > | ||||
el->el_terminal.t_size.h) { | el->el_terminal.t_size.h) { | ||||
cur.h = 0; | cur.h = 0; | ||||
cur.v++; | cur.v++; | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | #endif | ||||
ELRE_DEBUG(1, (__F, | ELRE_DEBUG(1, (__F, | ||||
"\r\nel->el_refresh.r_cursor.v=%d,el->el_refresh.r_oldcv=%d i=%d\r\n", | "\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)); | el->el_refresh.r_cursor.v, el->el_refresh.r_oldcv, i)); | ||||
if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) | if (el->el_refresh.r_oldcv > el->el_refresh.r_newcv) | ||||
for (; i <= el->el_refresh.r_oldcv; i++) { | for (; i <= el->el_refresh.r_oldcv; i++) { | ||||
terminal_move_to_line(el, i); | terminal_move_to_line(el, i); | ||||
terminal_move_to_char(el, 0); | terminal_move_to_char(el, 0); | ||||
/* This Strlen should be safe even with MB_FILL_CHARs */ | /* This wcslen should be safe even with MB_FILL_CHARs */ | ||||
terminal_clear_EOL(el, (int) Strlen(el->el_display[i])); | terminal_clear_EOL(el, (int) wcslen(el->el_display[i])); | ||||
#ifdef DEBUG_REFRESH | #ifdef DEBUG_REFRESH | ||||
terminal_overwrite(el, STR("C\b"), 2); | terminal_overwrite(el, L"C\b", 2); | ||||
#endif /* DEBUG_REFRESH */ | #endif /* DEBUG_REFRESH */ | ||||
el->el_display[i][0] = '\0'; | el->el_display[i][0] = '\0'; | ||||
} | } | ||||
el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ | el->el_refresh.r_oldcv = el->el_refresh.r_newcv; /* set for next time */ | ||||
ELRE_DEBUG(1, (__F, | ELRE_DEBUG(1, (__F, | ||||
"\r\ncursor.h = %d, cursor.v = %d, cur.h = %d, cur.v = %d\r\n", | "\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, | el->el_refresh.r_cursor.h, el->el_refresh.r_cursor.v, | ||||
cur.h, cur.v)); | cur.h, cur.v)); | ||||
terminal_move_to_line(el, cur.v); /* go to where the cursor is */ | terminal_move_to_line(el, cur.v); /* go to where the cursor is */ | ||||
terminal_move_to_char(el, cur.h); | terminal_move_to_char(el, cur.h); | ||||
} | } | ||||
/* re_goto_bottom(): | /* re_goto_bottom(): | ||||
* used to go to last used screen line | * used to go to last used screen line | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_goto_bottom(EditLine *el) | re_goto_bottom(EditLine *el) | ||||
{ | { | ||||
terminal_move_to_line(el, el->el_refresh.r_oldcv); | terminal_move_to_line(el, el->el_refresh.r_oldcv); | ||||
terminal__putc(el, '\n'); | terminal__putc(el, '\n'); | ||||
re_clear_display(el); | re_clear_display(el); | ||||
terminal__flush(el); | terminal__flush(el); | ||||
} | } | ||||
/* re_insert(): | /* re_insert(): | ||||
* insert num characters of s into d (in front of the character) | * insert num characters of s into d (in front of the character) | ||||
* at dat, maximum length of d is dlen | * at dat, maximum length of d is dlen | ||||
*/ | */ | ||||
private void | static void | ||||
/*ARGSUSED*/ | /*ARGSUSED*/ | ||||
re_insert(EditLine *el __attribute__((__unused__)), | re_insert(EditLine *el __attribute__((__unused__)), | ||||
Char *d, int dat, int dlen, Char *s, int num) | wchar_t *d, int dat, int dlen, wchar_t *s, int num) | ||||
{ | { | ||||
Char *a, *b; | wchar_t *a, *b; | ||||
if (num <= 0) | if (num <= 0) | ||||
return; | return; | ||||
if (num > dlen - dat) | if (num > dlen - dat) | ||||
num = dlen - dat; | num = dlen - dat; | ||||
ELRE_DEBUG(1, | ELRE_DEBUG(1, | ||||
(__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", | (__F, "re_insert() starting: %d at %d max %d, d == \"%s\"\n", | ||||
Show All 29 Lines | #ifdef notyet | ||||
ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); | ELRE_DEBUG(1, (__F, "s == \"%s\"\n", s)); | ||||
#endif | #endif | ||||
} | } | ||||
/* re_delete(): | /* re_delete(): | ||||
* delete num characters d at dat, maximum length of d is dlen | * delete num characters d at dat, maximum length of d is dlen | ||||
*/ | */ | ||||
private void | static void | ||||
/*ARGSUSED*/ | /*ARGSUSED*/ | ||||
re_delete(EditLine *el __attribute__((__unused__)), | re_delete(EditLine *el __attribute__((__unused__)), | ||||
Char *d, int dat, int dlen, int num) | wchar_t *d, int dat, int dlen, int num) | ||||
{ | { | ||||
Char *a, *b; | wchar_t *a, *b; | ||||
if (num <= 0) | if (num <= 0) | ||||
return; | return; | ||||
if (dat + num >= dlen) { | if (dat + num >= dlen) { | ||||
d[dat] = '\0'; | d[dat] = '\0'; | ||||
return; | return; | ||||
} | } | ||||
ELRE_DEBUG(1, | ELRE_DEBUG(1, | ||||
Show All 12 Lines | ELRE_DEBUG(1, | ||||
(__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", | (__F, "re_delete() after delete: %d at %d max %d, d == \"%s\"\n", | ||||
num, dat, dlen, ct_encode_string(d, &el->el_scratch))); | num, dat, dlen, ct_encode_string(d, &el->el_scratch))); | ||||
} | } | ||||
/* re__strncopy(): | /* re__strncopy(): | ||||
* Like strncpy without padding. | * Like strncpy without padding. | ||||
*/ | */ | ||||
private void | static void | ||||
re__strncopy(Char *a, Char *b, size_t n) | re__strncopy(wchar_t *a, wchar_t *b, size_t n) | ||||
{ | { | ||||
while (n-- && *b) | while (n-- && *b) | ||||
*a++ = *b++; | *a++ = *b++; | ||||
} | } | ||||
/* re_clear_eol(): | /* re_clear_eol(): | ||||
* Find the number of characters we need to clear till the end of line | * 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 | * 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 | * 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 | * in the first or second diff, diff is the difference between the | ||||
* number of characters between the new and old line. | * number of characters between the new and old line. | ||||
*/ | */ | ||||
private void | static void | ||||
re_clear_eol(EditLine *el, int fx, int sx, int diff) | 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", | ELRE_DEBUG(1, (__F, "re_clear_eol sx %d, fx %d, diff %d\n", | ||||
sx, fx, diff)); | sx, fx, diff)); | ||||
if (fx < 0) | if (fx < 0) | ||||
fx = -fx; | fx = -fx; | ||||
Show All 27 Lines | |||||
/* Minimum at which doing an insert it "worth it". This should be about | /* 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 | * half the "cost" of going into insert mode, inserting a character, and | ||||
* going back out. This should really be calculated from the termcap | * going back out. This should really be calculated from the termcap | ||||
* data... For the moment, a good number for ANSI terminals. | * data... For the moment, a good number for ANSI terminals. | ||||
*/ | */ | ||||
#define MIN_END_KEEP 4 | #define MIN_END_KEEP 4 | ||||
private void | static void | ||||
re_update_line(EditLine *el, Char *old, Char *new, int i) | re_update_line(EditLine *el, wchar_t *old, wchar_t *new, int i) | ||||
{ | { | ||||
Char *o, *n, *p, c; | wchar_t *o, *n, *p, c; | ||||
Char *ofd, *ols, *oe, *nfd, *nls, *ne; | wchar_t *ofd, *ols, *oe, *nfd, *nls, *ne; | ||||
Char *osb, *ose, *nsb, *nse; | wchar_t *osb, *ose, *nsb, *nse; | ||||
int fx, sx; | int fx, sx; | ||||
size_t len; | size_t len; | ||||
/* | /* | ||||
* find first diff | * find first diff | ||||
*/ | */ | ||||
for (o = old, n = new; *o && (*o == *n); o++, n++) | for (o = old, n = new; *o && (*o == *n); o++, n++) | ||||
continue; | continue; | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | #endif /* DEBUG_REFRESH */ | ||||
} | } | ||||
ELRE_DEBUG(1, (__F, "done.\r\n")); | ELRE_DEBUG(1, (__F, "done.\r\n")); | ||||
} | } | ||||
/* re__copy_and_pad(): | /* re__copy_and_pad(): | ||||
* Copy string and pad with spaces | * Copy string and pad with spaces | ||||
*/ | */ | ||||
private void | static void | ||||
re__copy_and_pad(Char *dst, const Char *src, size_t width) | re__copy_and_pad(wchar_t *dst, const wchar_t *src, size_t width) | ||||
{ | { | ||||
size_t i; | size_t i; | ||||
for (i = 0; i < width; i++) { | for (i = 0; i < width; i++) { | ||||
if (*src == '\0') | if (*src == '\0') | ||||
break; | break; | ||||
*dst++ = *src++; | *dst++ = *src++; | ||||
} | } | ||||
for (; i < width; i++) | for (; i < width; i++) | ||||
*dst++ = ' '; | *dst++ = ' '; | ||||
*dst = '\0'; | *dst = '\0'; | ||||
} | } | ||||
/* re_refresh_cursor(): | /* re_refresh_cursor(): | ||||
* Move to the new cursor position | * Move to the new cursor position | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_refresh_cursor(EditLine *el) | re_refresh_cursor(EditLine *el) | ||||
{ | { | ||||
Char *cp; | wchar_t *cp; | ||||
int h, v, th, w; | int h, v, th, w; | ||||
if (el->el_line.cursor >= el->el_line.lastchar) { | if (el->el_line.cursor >= el->el_line.lastchar) { | ||||
if (el->el_map.current == el->el_map.alt | if (el->el_map.current == el->el_map.alt | ||||
&& el->el_line.lastchar != el->el_line.buffer) | && el->el_line.lastchar != el->el_line.buffer) | ||||
el->el_line.cursor = el->el_line.lastchar - 1; | el->el_line.cursor = el->el_line.lastchar - 1; | ||||
else | else | ||||
el->el_line.cursor = el->el_line.lastchar; | el->el_line.cursor = el->el_line.lastchar; | ||||
Show All 11 Lines | case CHTYPE_NL: /* handle newline in data part too */ | ||||
h = 0; | h = 0; | ||||
v++; | v++; | ||||
break; | break; | ||||
case CHTYPE_TAB: /* if a tab, to next tab stop */ | case CHTYPE_TAB: /* if a tab, to next tab stop */ | ||||
while (++h & 07) | while (++h & 07) | ||||
continue; | continue; | ||||
break; | break; | ||||
default: | default: | ||||
w = Width(*cp); | w = wcwidth(*cp); | ||||
if (w > 1 && h + w > th) { /* won't fit on line */ | if (w > 1 && h + w > th) { /* won't fit on line */ | ||||
h = 0; | h = 0; | ||||
v++; | v++; | ||||
} | } | ||||
h += ct_visual_width(*cp); | h += ct_visual_width(*cp); | ||||
break; | break; | ||||
} | } | ||||
if (h >= th) { /* check, extra long tabs picked up here also */ | if (h >= th) { /* check, extra long tabs picked up here also */ | ||||
h -= th; | h -= th; | ||||
v++; | v++; | ||||
} | } | ||||
} | } | ||||
/* if we have a next character, and it's a doublewidth one, we need to | /* 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 */ | * check whether we need to linebreak for it to fit */ | ||||
if (cp < el->el_line.lastchar && (w = Width(*cp)) > 1) | if (cp < el->el_line.lastchar && (w = wcwidth(*cp)) > 1) | ||||
if (h + w > th) { | if (h + w > th) { | ||||
h = 0; | h = 0; | ||||
v++; | v++; | ||||
} | } | ||||
/* now go there */ | /* now go there */ | ||||
terminal_move_to_line(el, v); | terminal_move_to_line(el, v); | ||||
terminal_move_to_char(el, h); | terminal_move_to_char(el, h); | ||||
terminal__flush(el); | terminal__flush(el); | ||||
} | } | ||||
/* re_fastputc(): | /* re_fastputc(): | ||||
* Add a character fast. | * Add a character fast. | ||||
*/ | */ | ||||
private void | static void | ||||
re_fastputc(EditLine *el, wint_t c) | re_fastputc(EditLine *el, wint_t c) | ||||
{ | { | ||||
int w = Width((Char)c); | wchar_t *lastline; | ||||
int w; | |||||
w = wcwidth(c); | |||||
while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) | while (w > 1 && el->el_cursor.h + w > el->el_terminal.t_size.h) | ||||
re_fastputc(el, ' '); | re_fastputc(el, ' '); | ||||
terminal__putc(el, c); | terminal__putc(el, c); | ||||
el->el_display[el->el_cursor.v][el->el_cursor.h++] = (Char)c; | el->el_display[el->el_cursor.v][el->el_cursor.h++] = c; | ||||
while (--w > 0) | while (--w > 0) | ||||
el->el_display[el->el_cursor.v][el->el_cursor.h++] | el->el_display[el->el_cursor.v][el->el_cursor.h++] | ||||
= MB_FILL_CHAR; | = MB_FILL_CHAR; | ||||
if (el->el_cursor.h >= el->el_terminal.t_size.h) { | if (el->el_cursor.h >= el->el_terminal.t_size.h) { | ||||
/* if we must overflow */ | /* if we must overflow */ | ||||
el->el_cursor.h = 0; | el->el_cursor.h = 0; | ||||
/* | /* | ||||
* If we would overflow (input is longer than terminal size), | * If we would overflow (input is longer than terminal size), | ||||
* emulate scroll by dropping first line and shuffling the rest. | * emulate scroll by dropping first line and shuffling the rest. | ||||
* We do this via pointer shuffling - it's safe in this case | * We do this via pointer shuffling - it's safe in this case | ||||
* and we avoid memcpy(). | * and we avoid memcpy(). | ||||
*/ | */ | ||||
if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { | if (el->el_cursor.v + 1 >= el->el_terminal.t_size.v) { | ||||
int i, lins = el->el_terminal.t_size.v; | int i, lins = el->el_terminal.t_size.v; | ||||
Char *firstline = el->el_display[0]; | |||||
lastline = el->el_display[0]; | |||||
for(i = 1; i < lins; i++) | for(i = 1; i < lins; i++) | ||||
el->el_display[i - 1] = el->el_display[i]; | el->el_display[i - 1] = el->el_display[i]; | ||||
re__copy_and_pad(firstline, STR(""), (size_t)0); | el->el_display[i - 1] = lastline; | ||||
el->el_display[i - 1] = firstline; | |||||
} else { | } else { | ||||
el->el_cursor.v++; | el->el_cursor.v++; | ||||
el->el_refresh.r_oldcv++; | lastline = el->el_display[++el->el_refresh.r_oldcv]; | ||||
} | } | ||||
re__copy_and_pad(lastline, L"", (size_t)el->el_terminal.t_size.h); | |||||
if (EL_HAS_AUTO_MARGINS) { | if (EL_HAS_AUTO_MARGINS) { | ||||
if (EL_HAS_MAGIC_MARGINS) { | if (EL_HAS_MAGIC_MARGINS) { | ||||
terminal__putc(el, ' '); | terminal__putc(el, ' '); | ||||
terminal__putc(el, '\b'); | terminal__putc(el, '\b'); | ||||
} | } | ||||
} else { | } else { | ||||
terminal__putc(el, '\r'); | terminal__putc(el, '\r'); | ||||
terminal__putc(el, '\n'); | terminal__putc(el, '\n'); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* re_fastaddc(): | /* re_fastaddc(): | ||||
* we added just one char, handle it fast. | * we added just one char, handle it fast. | ||||
* Assumes that screen cursor == real cursor | * Assumes that screen cursor == real cursor | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_fastaddc(EditLine *el) | re_fastaddc(EditLine *el) | ||||
{ | { | ||||
Char c; | wchar_t c; | ||||
int rhdiff; | int rhdiff; | ||||
c = el->el_line.cursor[-1]; | c = el->el_line.cursor[-1]; | ||||
if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { | if (c == '\t' || el->el_line.cursor != el->el_line.lastchar) { | ||||
re_refresh(el); /* too hard to handle */ | re_refresh(el); /* too hard to handle */ | ||||
return; | return; | ||||
} | } | ||||
rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - | rhdiff = el->el_terminal.t_size.h - el->el_cursor.h - | ||||
el->el_rprompt.p_pos.h; | el->el_rprompt.p_pos.h; | ||||
if (el->el_rprompt.p_pos.h && rhdiff < 3) { | if (el->el_rprompt.p_pos.h && rhdiff < 3) { | ||||
re_refresh(el); /* clear out rprompt if less than 1 char gap */ | re_refresh(el); /* clear out rprompt if less than 1 char gap */ | ||||
return; | return; | ||||
} /* else (only do at end of line, no TAB) */ | } /* else (only do at end of line, no TAB) */ | ||||
switch (ct_chr_class(c)) { | switch (ct_chr_class(c)) { | ||||
case CHTYPE_TAB: /* already handled, should never happen here */ | case CHTYPE_TAB: /* already handled, should never happen here */ | ||||
break; | break; | ||||
case CHTYPE_NL: | case CHTYPE_NL: | ||||
case CHTYPE_PRINT: | case CHTYPE_PRINT: | ||||
re_fastputc(el, c); | re_fastputc(el, c); | ||||
break; | break; | ||||
case CHTYPE_ASCIICTL: | case CHTYPE_ASCIICTL: | ||||
case CHTYPE_NONPRINT: { | case CHTYPE_NONPRINT: { | ||||
Char visbuf[VISUAL_WIDTH_MAX]; | wchar_t visbuf[VISUAL_WIDTH_MAX]; | ||||
ssize_t i, n = | ssize_t i, n = | ||||
ct_visual_char(visbuf, VISUAL_WIDTH_MAX, (Char)c); | ct_visual_char(visbuf, VISUAL_WIDTH_MAX, c); | ||||
for (i = 0; n-- > 0; ++i) | for (i = 0; n-- > 0; ++i) | ||||
re_fastputc(el, visbuf[i]); | re_fastputc(el, visbuf[i]); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
terminal__flush(el); | terminal__flush(el); | ||||
} | } | ||||
/* re_clear_display(): | /* re_clear_display(): | ||||
* clear the screen buffers so that new prompt starts fresh. | * clear the screen buffers so that new prompt starts fresh. | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_clear_display(EditLine *el) | re_clear_display(EditLine *el) | ||||
{ | { | ||||
int i; | int i; | ||||
el->el_cursor.v = 0; | el->el_cursor.v = 0; | ||||
el->el_cursor.h = 0; | el->el_cursor.h = 0; | ||||
for (i = 0; i < el->el_terminal.t_size.v; i++) | for (i = 0; i < el->el_terminal.t_size.v; i++) | ||||
el->el_display[i][0] = '\0'; | el->el_display[i][0] = '\0'; | ||||
el->el_refresh.r_oldcv = 0; | el->el_refresh.r_oldcv = 0; | ||||
} | } | ||||
/* re_clear_lines(): | /* re_clear_lines(): | ||||
* Make sure all lines are *really* blank | * Make sure all lines are *really* blank | ||||
*/ | */ | ||||
protected void | libedit_private void | ||||
re_clear_lines(EditLine *el) | re_clear_lines(EditLine *el) | ||||
{ | { | ||||
if (EL_CAN_CEOL) { | if (EL_CAN_CEOL) { | ||||
int i; | int i; | ||||
for (i = el->el_refresh.r_oldcv; i >= 0; i--) { | for (i = el->el_refresh.r_oldcv; i >= 0; i--) { | ||||
/* for each line on the screen */ | /* for each line on the screen */ | ||||
terminal_move_to_line(el, i); | terminal_move_to_line(el, i); | ||||
Show All 10 Lines |