summaryrefslogtreecommitdiff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/complist.c6
-rw-r--r--Src/Zle/zle.h2
-rw-r--r--Src/Zle/zle_hist.c2
-rw-r--r--Src/Zle/zle_keymap.c111
-rw-r--r--Src/Zle/zle_main.c53
-rw-r--r--Src/Zle/zle_refresh.c6
-rw-r--r--Src/Zle/zle_thingy.c7
7 files changed, 170 insertions, 17 deletions
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 29aaee82a..0ccb88505 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -2584,6 +2584,12 @@ domenuselect(Hookdef dummy, Chdata dat)
if (!do_last_key) {
zmult = 1;
cmd = getkeycmd();
+ /*
+ * On interrupt, we'll exit due to cmd being empty.
+ * Don't propagate the interrupt any further, which
+ * can screw up redrawing.
+ */
+ errflag &= ~ERRFLAG_INT;
if (mtab_been_reallocated) {
do_last_key = 1;
continue;
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 2d672de3b..e9b14281d 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -213,6 +213,8 @@ struct widget {
#define ZLE_KEEPSUFFIX (1<<9) /* DON'T remove added suffix */
#define ZLE_NOTCOMMAND (1<<10) /* widget should not alter lastcmd */
#define ZLE_ISCOMP (1<<11) /* usable for new style completion */
+#define WIDGET_INUSE (1<<12) /* widget is in use */
+#define WIDGET_FREE (1<<13) /* request to free when no longer in use */
/* thingies */
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 95d96c95c..abd6e1749 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -1480,6 +1480,7 @@ doisearch(char **args, int dir, int pattern)
isearch_active = 0;
ref:
zlecallhook("zle-isearch-update", NULL);
+ redrawhook();
zrefresh();
if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
int i;
@@ -1694,6 +1695,7 @@ doisearch(char **args, int dir, int pattern)
statusline = NULL;
unmetafy_line();
zlecallhook("zle-isearch-exit", NULL);
+ redrawhook();
if (exitfn)
exitfn(zlenoargs);
selectkeymap(okeymap, 1);
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index 069580f8a..382eb8d41 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -1449,6 +1449,104 @@ default_bindings(void)
/*************************/
/* reading key sequences */
/*************************/
+/**/
+#ifdef MULTIBYTE_SUPPORT
+/*
+ * Get the remainder of a character if we support multibyte
+ * input strings. It may not require any more input, but
+ * we haven't yet checked. What's read in so far is available
+ * in keybuf; if we read more we will top keybuf up.
+ *
+ * This version is used when we are still resolving the input key stream
+ * into bindings. Once that has been done this function shouldn't be
+ * used: instead, see getrestchar() in zle_main.c.
+ *
+ * This supports a self-insert binding at any stage of a key sequence.
+ * Typically we handle 8-bit characters by having only the first byte
+ * bound to self insert; then we immediately get here and read in as
+ * many further bytes as necessary. However, it's possible that any set
+ * of bytes up to full character is bound to self-insert; then we get
+ * here later and read as much as possible, which could be a complete
+ * character, from keybuf before attempting further input.
+ *
+ * At the end of the process, the full multibyte character is available
+ * in keybuf, so the return value may be superfluous.
+ */
+
+/**/
+mod_export ZLE_INT_T
+getrestchar_keybuf(void)
+{
+ char c;
+ wchar_t outchar;
+ int inchar, timeout, bufind = 0, buflen = keybuflen;
+ static mbstate_t mbs;
+ size_t cnt;
+
+ /*
+ * We are guaranteed to set a valid wide last character,
+ * although it may be WEOF (which is technically not
+ * a wide character at all...)
+ */
+ lastchar_wide_valid = 1;
+ memset(&mbs, 0, sizeof mbs);
+
+ /*
+ * Return may be zero if we have a NULL; handle this like
+ * any other character.
+ */
+ while (1) {
+ if (bufind < buflen) {
+ c = STOUC(keybuf[bufind++]);
+ if (c == Meta) {
+ DPUTS(bufind == buflen, "Meta at end of keybuf");
+ c = STOUC(keybuf[bufind++]) ^ 32;
+ }
+ } else {
+ /*
+ * Always apply KEYTIMEOUT to the remains of the input
+ * character. The parts of a multibyte character should
+ * arrive together. If we don't do this the input can
+ * get stuck if an invalid byte sequence arrives.
+ */
+ inchar = getbyte(1L, &timeout);
+ /* getbyte deliberately resets lastchar_wide_valid */
+ lastchar_wide_valid = 1;
+ if (inchar == EOF) {
+ memset(&mbs, 0, sizeof mbs);
+ if (timeout)
+ {
+ /*
+ * This case means that we got a valid initial byte
+ * (since we tested for EOF above), but the followup
+ * timed out. This probably indicates a duff character.
+ * Return a '?'.
+ */
+ lastchar = '?';
+ return lastchar_wide = L'?';
+ }
+ else
+ return lastchar_wide = WEOF;
+ }
+ c = inchar;
+ addkeybuf(inchar);
+ }
+
+ cnt = mbrtowc(&outchar, &c, 1, &mbs);
+ if (cnt == MB_INVALID) {
+ /*
+ * Invalid input. Hmm, what's the right thing to do here?
+ */
+ memset(&mbs, 0, sizeof mbs);
+ return lastchar_wide = WEOF;
+ }
+ if (cnt != MB_INCOMPLETE)
+ break;
+ }
+ return lastchar_wide = (ZLE_INT_T)outchar;
+}
+/**/
+#endif
/* read a sequence of keys that is bound to some command in a keymap */
@@ -1503,16 +1601,9 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
f->widget->flags & ZLE_VIOPER);
#ifdef MULTIBYTE_SUPPORT
if ((f == Th(z_selfinsert) || f == Th(z_selfinsertunmeta)) &&
- !lastchar_wide_valid) {
- int len;
- VARARR(char, mbc, MB_CUR_MAX);
- ZLE_INT_T inchar = getrestchar(lastchar, mbc, &len);
- if (inchar != WEOF && len) {
- char *ptr = mbc;
- while (len--)
- addkeybuf(STOUC(*ptr++));
- lastlen = keybuflen;
- }
+ !lastchar_wide_valid && !ispfx) {
+ (void)getrestchar_keybuf();
+ lastlen = keybuflen;
}
#endif
}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 38427e8e3..6e2bfded8 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1025,6 +1025,32 @@ getrestchar(int inchar, char *outstr, int *outcount)
/**/
#endif
+/**/
+void redrawhook(void)
+{
+ Thingy initthingy;
+ if ((initthingy = rthingy_nocreate("zle-line-pre-redraw"))) {
+ int lastcmd_prev = lastcmd;
+ int old_incompfunc = incompfunc;
+ char *args[2];
+ Thingy lbindk_save = lbindk, bindk_save = bindk;
+ refthingy(lbindk_save);
+ refthingy(bindk_save);
+ args[0] = initthingy->nam;
+ args[1] = NULL;
+ incompfunc = 0;
+ execzlefunc(initthingy, args, 0);
+ incompfunc = old_incompfunc;
+ unrefthingy(initthingy);
+ unrefthingy(lbindk);
+ unrefthingy(bindk);
+ lbindk = lbindk_save;
+ bindk = bindk_save;
+ /* we can't set ZLE_NOTCOMMAND since it's not a legit widget, so
+ * restore lastcmd manually so that we don't mess up the global state */
+ lastcmd = lastcmd_prev;
+ }
+}
/**/
void
@@ -1084,6 +1110,8 @@ zlecore(void)
errflag |= ERRFLAG_ERROR;
break;
}
+
+ redrawhook();
#ifdef HAVE_POLL
if (baud && !(lastcmd & ZLE_MENUCMP)) {
struct pollfd pfd;
@@ -1113,6 +1141,7 @@ zlecore(void)
zrefresh();
freeheap();
+
}
region_active = 0;
@@ -1191,7 +1220,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
vistartchange = -1;
zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE);
*zleline = ZWC('\0');
- virangeflag = lastcmd = done = zlecs = zlell = mark = 0;
+ virangeflag = lastcmd = done = zlecs = zlell = mark = yankb = yanke = 0;
vichgflag = 0;
viinsbegin = 0;
statusline = NULL;
@@ -1344,6 +1373,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
eofsent = 1;
ret = 1;
} else {
+ int inuse = wflags & WIDGET_INUSE;
+ w->flags |= WIDGET_INUSE;
if(!(wflags & ZLE_KEEPSUFFIX))
removesuffix();
if(!(wflags & ZLE_MENUCMP)) {
@@ -1367,6 +1398,12 @@ execzlefunc(Thingy func, char **args, int set_bindk)
ret = w->u.fn(args);
unqueue_signals();
}
+ if (!inuse) {
+ if (w->flags & WIDGET_FREE)
+ freewidget(w);
+ else
+ w->flags &= ~WIDGET_INUSE;
+ }
if (!(wflags & ZLE_NOTCOMMAND))
lastcmd = wflags;
}
@@ -1387,6 +1424,8 @@ execzlefunc(Thingy func, char **args, int set_bindk)
int osc = sfcontext, osi = movefd(0);
int oxt = isset(XTRACE);
LinkList largs = NULL;
+ int inuse = w->flags & WIDGET_INUSE;
+ w->flags |= WIDGET_INUSE;
if (*args) {
largs = newlinklist();
@@ -1402,8 +1441,15 @@ execzlefunc(Thingy func, char **args, int set_bindk)
opts[XTRACE] = oxt;
sfcontext = osc;
endparamscope();
- lastcmd = w->flags;
- w->flags = 0;
+ lastcmd = w->flags & ~(WIDGET_INUSE|WIDGET_FREE);
+ if (inuse) {
+ w->flags &= WIDGET_INUSE|WIDGET_FREE;
+ } else {
+ if (w->flags & WIDGET_FREE)
+ freewidget(w);
+ else
+ w->flags = 0;
+ }
r = 1;
redup(osi, 0);
}
@@ -1795,6 +1841,7 @@ recursiveedit(UNUSED(char **args))
{
int locerror;
+ redrawhook();
zrefresh();
zlecore();
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 6facff429..3d2471e27 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -338,9 +338,9 @@ zle_set_highlight(void)
for (; *atrs; atrs++) {
if (!strcmp(*atrs, "none")) {
/* reset attributes for consistency... usually unnecessary */
- special_atr_on = default_atr_on =
- paste_atr_on_set = 0;
- special_atr_on_set = region_atr_on_set =
+ special_atr_on = default_atr_on = 0;
+ special_atr_on_set = 1;
+ paste_atr_on_set = region_atr_on_set =
isearch_atr_on_set = suffix_atr_on_set = 1;
} else if (strpfx("default:", *atrs)) {
match_highlight(*atrs + 8, &default_atr_on);
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 271fd8efc..21495b6f2 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -253,9 +253,14 @@ unbindwidget(Thingy t, int override)
/* Free a widget. */
/**/
-static void
+void
freewidget(Widget w)
{
+ if (w->flags & WIDGET_INUSE) {
+ w->flags |= WIDGET_FREE;
+ return;
+ }
+
if (w->flags & WIDGET_NCOMP) {
zsfree(w->u.comp.wid);
zsfree(w->u.comp.func);