summaryrefslogtreecommitdiff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/compcore.c14
-rw-r--r--Src/Zle/compctl.c4
-rw-r--r--Src/Zle/complist.c19
-rw-r--r--Src/Zle/compresult.c2
-rw-r--r--Src/Zle/computil.c10
-rw-r--r--Src/Zle/iwidgets.list1
-rw-r--r--Src/Zle/zle_hist.c4
-rw-r--r--Src/Zle/zle_main.c66
-rw-r--r--Src/Zle/zle_misc.c28
-rw-r--r--Src/Zle/zle_params.c2
-rw-r--r--Src/Zle/zle_refresh.c9
-rw-r--r--Src/Zle/zle_tricky.c5
-rw-r--r--Src/Zle/zle_utils.c52
-rw-r--r--Src/Zle/zle_vi.c37
14 files changed, 199 insertions, 54 deletions
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 5c5628a8d..ac7785ab7 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1260,6 +1260,20 @@ check_param(char *s, int set, int test)
ispar = (br >= 2 ? 2 : 1);
b[we-wb] = '\0';
return b;
+ } else if (offs > e - s && *e == ':') {
+ /*
+ * Guess whether we are in modifiers.
+ * If the name is followed by a : and the stuff after
+ * that is either colons or alphanumerics we probably are.
+ * This is a very rough guess.
+ */
+ char *offsptr = s + offs;
+ for (; e < offsptr; e++) {
+ if (*e != ':' && !ialnum(*e))
+ break;
+ }
+ ispar = (br >= 2 ? 2 : 1);
+ return NULL;
}
}
return NULL;
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index ab1857c0a..52b9e9c82 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -193,7 +193,7 @@ compctlread(char *name, char **args, Options ops, char *reply)
/* only allowed to be called for completion */
if (!incompctlfunc) {
- zwarnnam(name, "option valid only in functions called for completion");
+ zwarnnam(name, "option valid only in functions called via compctl");
return 1;
}
@@ -3391,7 +3391,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
mflags |= CMF_FILE;
for (n = firstnode(l); n; incnode(n))
addmatch(getdata(n), NULL);
- mflags &= !CMF_FILE;
+ mflags &= ~CMF_FILE;
}
opts[NULLGLOB] = ng;
} else {
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index bcf356179..5e5ba9f20 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -383,12 +383,25 @@ getcoldef(char *s)
} else if (*s == '=') {
char *p = ++s, *t, *cols[MAX_POS];
int ncols = 0;
+ int nesting = 0;
Patprog prog;
/* This is for a pattern. */
- while (*s && *s != '=')
- s++;
+ while (*s && (nesting || *s != '=')) {
+ switch (*s++) {
+ case '\\':
+ if (*s)
+ s++;
+ break;
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ nesting--;
+ break;
+ }
+ }
if (!*s)
return s;
*s++ = '\0';
@@ -2500,7 +2513,7 @@ domenuselect(Hookdef dummy, Chdata dat)
mlbeg--;
}
}
- if ((space = zterm_lines - pl - mhasstat))
+ if ((space = zterm_lines - pl - mhasstat) > 0)
while (mline >= mlbeg + space)
if ((mlbeg += step) + space > mlines)
mlbeg = mlines - space;
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index c0e5ff3d8..fcceb670c 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -1131,7 +1131,7 @@ do_single(Cmatch m)
/* If a suffix was added, and is removable, let *
* `,' and `}' remove it. */
if (isset(AUTOPARAMKEYS))
- addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixnoinslen);
+ addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixlen);
} else if (!menucmp) {
/*{{*/
/* Otherwise, add a `,' suffix, and let `}' remove it. */
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index f5e6ba195..b11c39f25 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -1500,9 +1500,11 @@ parse_cadef(char *nam, char **args)
nodopts++;
/* If this is for single-letter option we also store a
- * pointer for the definition in the array for fast lookup. */
+ * pointer for the definition in the array for fast lookup.
+ * But don't treat '--' as a single option called '-' */
- if (single && name[1] && !name[2])
+
+ if (single && name[1] && !name[2] && name[1] != '-')
ret->single[STOUC(name[1])] = opt;
if (again == 1) {
@@ -2034,7 +2036,9 @@ ca_parse_line(Cadef d, int multi, int first)
state.optbeg = state.argbeg = state.inopt = cur;
state.argend = argend;
state.singles = (d->single && (!pe || !*pe) &&
- state.curopt->name[1] && !state.curopt->name[2]);
+ state.curopt->name[1] && !state.curopt->name[2] &&
+ /* Don't treat '--' as a single option called '-' */
+ state.curopt->name[1] != '-');
if (!state.oargs[state.curopt->num])
state.oargs[state.curopt->num] = znewlinklist();
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index 4372fe36e..e3ffe3e8c 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -102,6 +102,7 @@
"self-insert-unmeta", selfinsertunmeta, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"send-break", sendbreak, 0
"set-mark-command", setmarkcommand, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"split-undo", splitundo, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_NOTCOMMAND
"spell-word", spellword, 0
"set-local-history", setlocalhistory, 0
"transpose-chars", transposechars, 0
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index bd5bc36d5..44b39d186 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -890,6 +890,10 @@ zgetline(UNUSED(char **args))
free(s);
free(lineadd);
clearlist = 1;
+ if (stackhist != -1) {
+ histline = stackhist;
+ stackhist = -1;
+ }
}
return 0;
}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 040b7cb83..442c31995 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -157,10 +157,10 @@ mod_export char *statusline;
/**/
int stackhist, stackcs;
-/* != 0 if we are making undo records */
+/* position in undo stack from when the current vi change started */
/**/
-int undoing;
+zlong vistartchange;
/* current modifier status */
@@ -525,7 +525,8 @@ raw_getbyte(long do_keytmout, char *cptr)
#endif
#ifndef HAVE_POLL
# ifdef HAVE_SELECT
- fd_set foofd;
+ fd_set foofd, errfd;
+ FD_ZERO(&errfd);
# endif
#endif
@@ -613,11 +614,14 @@ raw_getbyte(long do_keytmout, char *cptr)
if (!errtry) {
for (i = 0; i < nwatch; i++) {
int fd = watch_fds[i].fd;
+ if (FD_ISSET(fd, &errfd))
+ continue;
FD_SET(fd, &foofd);
if (fd > fdmax)
fdmax = fd;
}
}
+ FD_ZERO(&errfd);
if (tmout.tp != ZTM_NONE) {
expire_tv.tv_sec = tmout.exp100ths / 100;
@@ -732,9 +736,10 @@ raw_getbyte(long do_keytmout, char *cptr)
Watch_fd lwatch_fd = lwatch_fds + i;
if (
# ifdef HAVE_POLL
- (fds[i+1].revents & POLLIN)
+ (fds[i+1].revents & (POLLIN|POLLERR|POLLHUP|POLLNVAL))
# else
- FD_ISSET(lwatch_fd->fd, &foofd)
+ FD_ISSET(lwatch_fd->fd, &foofd) ||
+ FD_ISSET(lwatch_fd->fd, &errfd)
# endif
) {
/* Handle the fd. */
@@ -765,6 +770,9 @@ raw_getbyte(long do_keytmout, char *cptr)
if (fds[i+1].revents & POLLNVAL)
zaddlinknode(funcargs, ztrdup("nval"));
# endif
+# else
+ if (FD_ISSET(lwatch_fd->fd, &errfd))
+ zaddlinknode(funcargs, ztrdup("err"));
# endif
callhookfunc(lwatch_fd->func, funcargs, 0, NULL);
freelinklist(funcargs, freestr);
@@ -786,6 +794,31 @@ raw_getbyte(long do_keytmout, char *cptr)
for (i = 0; i < lnwatch; i++)
zsfree(lwatch_fds[i].func);
zfree(lwatch_fds, lnwatch*sizeof(struct watch_fd));
+
+# ifdef HAVE_POLL
+ /* Function may have added or removed handlers */
+ nfds = 1 + nwatch;
+ if (nfds > 1) {
+ fds = zrealloc(fds, sizeof(struct pollfd) * nfds);
+ for (i = 0; i < nwatch; i++) {
+ /*
+ * This is imperfect because it assumes fds[] and
+ * watch_fds[] remain in sync, which may be false
+ * if handlers are shuffled. However, it should
+ * be harmless (e.g., produce one extra pass of
+ * the loop) in the event they fall out of sync.
+ */
+ if (fds[i+1].fd == watch_fds[i].fd &&
+ (fds[i+1].revents & (POLLERR|POLLHUP|POLLNVAL))) {
+ fds[i+1].events = 0; /* Don't poll this */
+ } else {
+ fds[i+1].fd = watch_fds[i].fd;
+ fds[i+1].events = POLLIN;
+ }
+ fds[i+1].revents = 0;
+ }
+ }
+# endif
}
}
# ifdef HAVE_POLL
@@ -1080,8 +1113,7 @@ zlecore(void)
if (invicmdmode() && zlecs > findbol() &&
(zlecs == zlell || zleline[zlecs] == ZWC('\n')))
DECCS();
- if (undoing)
- handleundo();
+ handleundo();
} else {
errflag = 1;
break;
@@ -1190,7 +1222,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
zlereadflags = flags;
zlecontext = context;
histline = curhist;
- undoing = 1;
+ vistartchange = -1;
zleline = (ZLE_STRING_T)zalloc(((linesz = 256) + 2) * ZLE_CHAR_SIZE);
*zleline = ZWC('\0');
virangeflag = lastcmd = done = zlecs = zlell = mark = 0;
@@ -1198,14 +1230,7 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
viinsbegin = 0;
statusline = NULL;
selectkeymap("main", 1);
- /*
- * If main is linked to the viins keymap, we need to register
- * explicitly that we're now in vi insert mode as there's
- * no user operation to indicate this.
- */
- if (openkeymap("main") == openkeymap("viins"))
- viinsert(NULL);
- selectlocalmap(NULL);
+ initundo();
fixsuffix();
if ((s = getlinknode(bufstack))) {
setline(s, ZSL_TOEND);
@@ -1222,7 +1247,14 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
stackhist = -1;
}
}
- initundo();
+ /*
+ * If main is linked to the viins keymap, we need to register
+ * explicitly that we're now in vi insert mode as there's
+ * no user operation to indicate this.
+ */
+ if (openkeymap("main") == openkeymap("viins"))
+ viinsert_init();
+ selectlocalmap(NULL);
if (isset(PROMPTCR))
putc('\r', shout);
if (tmout)
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 7be0ebbd1..9bc1cf6f5 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -1249,10 +1249,14 @@ static char *suffixfunc;
/* Length associated with the suffix function */
static int suffixfunclen;
-/* Length associated with uninsertable characters */
+/* Whether to remove suffix on uninsertable characters */
+/**/
+int suffixnoinsrem;
+
+/* Length of the currently active, auto-removable suffix. */
/**/
mod_export int
-suffixnoinslen;
+suffixlen;
/**/
mod_export void
@@ -1309,7 +1313,8 @@ makesuffix(int n)
if ((suffixchars = getsparam("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars)
addsuffixstring(SUFTYP_POSSTR, SUFFLAGS_SPACE, suffixchars, n);
- suffixnoinslen = n;
+ suffixlen = n;
+ suffixnoinsrem = 1;
}
/* Set up suffix for parameter names: the last n characters are a suffix *
@@ -1358,15 +1363,10 @@ makesuffixstr(char *f, char *s, int n)
s = metafy(s, i, META_USEHEAP);
ws = stringaszleline(s, 0, &i, NULL, NULL);
- if (z)
- suffixnoinslen = inv ? 0 : n;
- else if (inv) {
- /*
- * negative match, \- wasn't present, so it *should*
- * have this suffix length
- */
- suffixnoinslen = n;
- }
+ /* Remove suffix on uninsertable characters if \- was given *
+ * and the character class wasn't negated -- or vice versa. */
+ suffixnoinsrem = z ^ inv;
+ suffixlen = n;
lasts = wptr = ws;
while (i) {
@@ -1444,7 +1444,7 @@ iremovesuffix(ZLE_INT_T c, int keep)
struct suffixset *ss;
if (c == NO_INSERT_CHAR) {
- sl = suffixnoinslen;
+ sl = suffixnoinsrem ? suffixlen : 0;
} else {
ZLE_CHAR_T ch = c;
/*
@@ -1538,5 +1538,5 @@ fixsuffix(void)
suffixlist = next;
}
- suffixfunclen = suffixnoinslen = 0;
+ suffixfunclen = suffixnoinsrem = suffixlen = 0;
}
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index a9bbf136a..5845207fa 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -363,7 +363,7 @@ get_prebuffer(UNUSED(Param pm))
static char *
get_widget(UNUSED(Param pm))
{
- return bindk->nam;
+ return bindk ? bindk->nam : "";
}
/**/
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index fd5485770..80be27f03 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -444,6 +444,7 @@ void
set_region_highlight(UNUSED(Param pm), char **aval)
{
int len;
+ char **av = aval;
struct region_highlight *rhp;
len = aval ? arrlen(aval) : 0;
@@ -490,6 +491,8 @@ set_region_highlight(UNUSED(Param pm), char **aval)
match_highlight(strp, &rhp->atr);
}
+
+ freearray(av);
}
@@ -977,7 +980,7 @@ zrefresh(void)
int tmpalloced; /* flag to free tmpline when finished */
int remetafy; /* flag that zle line is metafied */
int txtchange; /* attributes set after prompts */
- int rprompt_off; /* Offset of rprompt from right of screen */
+ int rprompt_off = 1; /* Offset of rprompt from right of screen */
struct rparams rpms;
#ifdef MULTIBYTE_SUPPORT
int width; /* width of wide character */
@@ -1046,8 +1049,8 @@ zrefresh(void)
region_highlights[1].start = region_highlights[1].end = -1;
}
/* check for an active completion suffix */
- if (suffixnoinslen) {
- region_highlights[2].start = zlecs - suffixnoinslen;
+ if (suffixlen) {
+ region_highlights[2].start = zlecs - suffixlen;
region_highlights[2].end = zlecs;
} else {
region_highlights[2].start = region_highlights[2].end = -1;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 9d163ad9e..499c4ae77 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -611,8 +611,6 @@ docomplete(int lst)
active = 1;
comprecursive = 0;
makecommaspecial(0);
- if (undoing)
- setlastline();
/* From the C-code's point of view, we can only use compctl as a default
* type of completion. Load it if it hasn't been loaded already and
@@ -1164,7 +1162,7 @@ get_comp_string(void)
* being separated by tokens | & &! |& || &&). The loop stops when *
* the end of the command containing the cursor is reached. What *
* makes this messy is checking for things like redirections, loops *
- * and whatnot. */
+ * and whatnot. */
do {
qsub = noword = 0;
@@ -2797,6 +2795,7 @@ doexpandhist(void)
if (!err) {
zlemetacs = excs;
if (strcmp(zlemetaline, ol)) {
+ zle_free_positions();
unmetafy_line();
/* For vi mode -- reset the beginning-of-insertion pointer *
* to the beginning of the line. This seems a little silly, *
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index b82e54ce5..1089e274f 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -710,6 +710,27 @@ zle_restore_positions(void)
}
/*
+ * Discard positions previously saved, the line has been updated.
+ */
+
+/**/
+mod_export void
+zle_free_positions(void)
+{
+ struct zle_position *oldpos = zle_positions;
+ struct zle_region *oldrhp;
+
+ zle_positions = oldpos->next;
+ oldrhp = oldpos->regions;
+ while (oldrhp) {
+ struct zle_region *nextrhp = oldrhp->next;
+ zfree(oldrhp, sizeof(*oldrhp));
+ oldrhp = nextrhp;
+ }
+ zfree(oldpos, sizeof(*oldpos));
+}
+
+/*
* Basic utility functions for adding to line or removing from line.
* At this level the counts supplied are raw character counts, so
* the calling code must be aware of combining characters where
@@ -1354,7 +1375,10 @@ handlesuffix(UNUSED(char **args))
/* head of the undo list, and the current position */
-static struct change *changes, *curchange;
+/**/
+struct change *curchange;
+
+static struct change *changes;
/* list of pending changes, not yet in the undo system */
@@ -1629,6 +1653,32 @@ viundochange(char **args)
return undo(args);
}
+/**/
+int
+splitundo(char **args)
+{
+ if (vistartchange >= 0) {
+ mergeundo();
+ vistartchange = (curchange && curchange->prev) ?
+ curchange->prev->changeno : 0;
+ }
+ handleundo();
+ return 0;
+}
+
+/**/
+void
+mergeundo(void)
+{
+ struct change *current;
+ for (current = curchange->prev;
+ current && current->prev && current->changeno > vistartchange+1;
+ current = current->prev) {
+ current->flags |= CH_PREV;
+ current->prev->flags |= CH_NEXT;
+ }
+}
+
/*
* Call a ZLE hook: a user-defined widget called at a specific point
* within the line editor.
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 173a49ef9..9e39143d0 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -67,15 +67,23 @@ int viinsbegin;
static struct modifier lastmod;
static int inrepeat, vichgrepeat;
+/**
+ * im: >= 0: is an insertmode
+ * -1: skip setting insert mode
+ * -2: entering viins at start of editing from clean --- don't use
+ * inrepeat or lastchar, synthesise an i to enter insert mode.
+ */
+
/**/
static void
startvichange(int im)
{
if (im != -1) {
- insmode = im;
vichgflag = 1;
+ if (im > -1)
+ insmode = im;
}
- if (inrepeat) {
+ if (inrepeat && im != -2) {
zmod = lastmod;
inrepeat = vichgflag = 0;
vichgrepeat = 1;
@@ -84,7 +92,12 @@ startvichange(int im)
if (vichgbuf)
free(vichgbuf);
vichgbuf = (char *)zalloc(vichgbufsz = 16);
- vichgbuf[0] = lastchar;
+ if (im == -2) {
+ vichgbuf[0] =
+ zlell ? (insmode ? (zlecs < zlell ? 'i' : 'a') : 'R') : 'o';
+ } else {
+ vichgbuf[0] = lastchar;
+ }
vichgbufptr = 1;
vichgrepeat = 0;
}
@@ -96,7 +109,7 @@ startvitext(int im)
{
startvichange(im);
selectkeymap("main", 1);
- undoing = 0;
+ vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0;
viinsbegin = zlecs;
}
@@ -303,6 +316,18 @@ viinsert(UNUSED(char **args))
return 0;
}
+/*
+ * Go to vi insert mode when we first start the line editor.
+ * Iniialises some other stuff.
+ */
+
+/**/
+void
+viinsert_init(void)
+{
+ startvitext(-2);
+}
+
/**/
int
viinsertbol(UNUSED(char **args))
@@ -376,7 +401,7 @@ vichange(UNUSED(char **args))
forekill(c2 - zlecs, CUT_RAW);
selectkeymap("main", 1);
viinsbegin = zlecs;
- undoing = 0;
+ vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0;
}
return ret;
}
@@ -561,7 +586,7 @@ vicmdmode(UNUSED(char **args))
{
if (invicmdmode() || selectkeymap("vicmd", 0))
return 1;
- undoing = 1;
+ mergeundo();
vichgflag = 0;
if (zlecs != findbol())
DECCS();