summaryrefslogtreecommitdiff
path: root/Src/Zle
diff options
context:
space:
mode:
authorAxel Beckert <abe@deuxchevaux.org>2015-05-05 23:32:59 +0200
committerAxel Beckert <abe@deuxchevaux.org>2015-05-05 23:58:59 +0200
commitdb38e167634b6c2217eec3a5aafc37c46d9e5a8d (patch)
treedaa342d423febbd3a5a7ef97053037677fab004a /Src/Zle
parent01eea47617a6e06debdb4330f92ae69f92089fd2 (diff)
parent3c3c8d3d13fd4cf6c03f81ca8dc18a1efd561728 (diff)
downloadzsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.tar.gz
zsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.zip
Merge branch 'upstream' into debian
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/compcore.c8
-rw-r--r--Src/Zle/compctl.c26
-rw-r--r--Src/Zle/complist.c28
-rw-r--r--Src/Zle/compmatch.c3
-rw-r--r--Src/Zle/compresult.c7
-rw-r--r--Src/Zle/computil.c3
-rw-r--r--Src/Zle/iwidgets.list55
-rw-r--r--Src/Zle/textobjects.c322
-rw-r--r--Src/Zle/zle.h21
-rw-r--r--Src/Zle/zle.mdd3
-rw-r--r--Src/Zle/zle_bindings.c10
-rw-r--r--Src/Zle/zle_hist.c28
-rw-r--r--Src/Zle/zle_keymap.c59
-rw-r--r--Src/Zle/zle_main.c72
-rw-r--r--Src/Zle/zle_misc.c238
-rw-r--r--Src/Zle/zle_move.c61
-rw-r--r--Src/Zle/zle_params.c2
-rw-r--r--Src/Zle/zle_refresh.c26
-rw-r--r--Src/Zle/zle_tricky.c62
-rw-r--r--Src/Zle/zle_utils.c105
-rw-r--r--Src/Zle/zle_vi.c411
-rw-r--r--Src/Zle/zle_word.c113
22 files changed, 1228 insertions, 435 deletions
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 35d410cc6..000f9da2a 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -1524,7 +1524,7 @@ set_comp_sep(void)
ol = zlemetaline;
addedx = 1;
noerrs = 1;
- lexsave();
+ zcontext_save();
lexflags = LEXFLAGS_ZLE;
/*
* tl is the length of the temporary string including
@@ -1671,9 +1671,9 @@ set_comp_sep(void)
noaliases = ona;
strinend();
inpop();
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
noerrs = ne;
- lexrestore();
+ zcontext_restore();
wb = owb;
we = owe;
zlemetaline = ol;
@@ -3492,7 +3492,7 @@ freematch(Cmatch m, int nbeg, int nend)
if (m->brsl)
zfree(m->brsl, nend * sizeof(int));
- zfree(m, sizeof(m));
+ zfree(m, sizeof(*m));
}
/* This frees the groups of matches. */
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 0b7a32445..189582d22 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1515,7 +1515,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
if (cclist & COMP_LIST)
printf(" --");
}
- if (cc && cc->xor) {
+ if (cc->xor) {
/* print xor'd (+) completions */
printf(" +");
if (cc->xor != &cc_default)
@@ -1879,7 +1879,7 @@ ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat)
if (!m || !(m = m->next))
break;
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
}
redup(osi, 0);
dat->lst = 1;
@@ -2121,7 +2121,7 @@ getreal(char *str)
if (!errflag && nonempty(l) &&
((char *) peekfirst(l)) && ((char *) peekfirst(l))[0])
return dupstring(peekfirst(l));
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
return dupstring(str);
}
@@ -2599,7 +2599,7 @@ makecomplistlist(Compctl cc, char *s, int incmd, int compadd)
makecomplistflags(cc, s, incmd, compadd);
/* Reset some information variables for the next try. */
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
offs = oloffs;
wb = owb;
we = owe;
@@ -2795,7 +2795,7 @@ sep_comp_string(char *ss, char *s, int noffs)
* get the words we have to expand. */
addedx = 1;
noerrs = 1;
- lexsave();
+ zcontext_save();
lexflags = LEXFLAGS_ZLE;
tmp = (char *) zhalloc(tl = sl + 3 + strlen(s));
strcpy(tmp, ss);
@@ -2847,9 +2847,9 @@ sep_comp_string(char *ss, char *s, int noffs)
noaliases = ona;
strinend();
inpop();
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
noerrs = ne;
- lexrestore();
+ zcontext_restore();
wb = owb;
we = owe;
zlemetacs = ocs;
@@ -3685,7 +3685,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
for (i = 0; i <= maxjob; i++)
if ((jobtab[i].stat & STAT_INUSE) &&
- jobtab[i].procs && jobtab[i].procs->text) {
+ jobtab[i].procs && jobtab[i].procs->text[0]) {
int stopped = jobtab[i].stat & STAT_STOPPED;
j = dupstring(jobtab[i].procs->text);
@@ -3707,7 +3707,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
/* Put the string in the lexer buffer and call the lexer to *
* get the words we have to expand. */
- lexsave();
+ zcontext_save();
lexflags = LEXFLAGS_ZLE;
tmpbuf = (char *)zhalloc(strlen(cc->str) + 5);
sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
@@ -3725,8 +3725,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
noaliases = ona;
strinend();
inpop();
- errflag = 0;
- lexrestore();
+ errflag &= ~ERRFLAG_ERROR;
+ zcontext_restore();
/* Fine, now do full expansion. */
prefork(foo, 0);
if (!errflag) {
@@ -3853,7 +3853,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
yaptr = get_user_var(uv);
if ((tt = cc->explain)) {
tt = dupstring(tt);
- if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
+ if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) {
singsub(&tt);
untokenize(tt);
}
@@ -3873,7 +3873,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
}
} else if ((tt = cc->explain)) {
tt = dupstring(tt);
- if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) {
+ if ((cc->mask & CC_EXPANDEXPL) && !parsestr(&tt)) {
singsub(&tt);
untokenize(tt);
}
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 5e5ba9f20..f54206619 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -780,6 +780,7 @@ clnicezputs(int do_colors, char *s, int ml)
/* Is the screen full? */
if (ml == mlend - 1 && col == zterm_columns - 1) {
mlprinted = ml - oml;
+ free(ums);
return 0;
}
if (t < wptr) {
@@ -804,6 +805,7 @@ clnicezputs(int do_colors, char *s, int ml)
ml++;
if (mscroll && !--mrestlines && (ask = asklistscroll(ml))) {
mlprinted = ml - oml;
+ free(ums);
return ask;
}
col -= zterm_columns;
@@ -1375,7 +1377,7 @@ compprintlist(int showall)
tcout(TCCLEAREOD);
g = ((lasttype && lastg) ? lastg : amatches);
- while (g) {
+ while (g && !errflag) {
char **pp = g->ylist;
#ifdef ZSH_HEAP_DEBUG
@@ -1389,7 +1391,7 @@ compprintlist(int showall)
ml = lastml;
lastused = 1;
}
- while (*e) {
+ while (*e && !errflag) {
if (((*e)->count || (*e)->always) &&
(!listdat.onlyexpl ||
(listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) {
@@ -1469,11 +1471,11 @@ compprintlist(int showall)
nl = nc = g->lins;
- while (n && nl--) {
+ while (n && nl-- && !errflag) {
i = g->cols;
mc = 0;
pq = pp;
- while (n && i--) {
+ while (n && i-- && !errflag) {
if (pq - g->ylist >= g->lcount)
break;
if (compzputs(*pq, mscroll))
@@ -1582,7 +1584,7 @@ compprintlist(int showall)
} else
p = skipnolist(g->matches, showall);
- while (n && nl--) {
+ while (n && nl-- && !errflag) {
if (!lasttype && ml >= mlbeg) {
lasttype = 3;
lastg = g;
@@ -1596,7 +1598,7 @@ compprintlist(int showall)
i = g->cols;
mc = 0;
q = p;
- while (n && i--) {
+ while (n && i-- && !errflag) {
wid = (g->widths ? g->widths[mc] : g->width);
if (!(m = *q)) {
if (clprintm(g, NULL, mc, ml, (!i), wid))
@@ -2059,8 +2061,8 @@ complistmatches(UNUSED(Hookdef dummy), Chdata dat)
i = zterm_columns * listdat.nlines;
free(mtab);
- mtab = (Cmatch **) zalloc(i * sizeof(Cmatch **));
- memset(mtab, 0, i * sizeof(Cmatch **));
+ mtab = (Cmatch **) zalloc(i * sizeof(Cmatch *));
+ memset(mtab, 0, i * sizeof(Cmatch *));
free(mgtab);
mgtab = (Cmgroup *) zalloc(i * sizeof(Cmgroup));
#ifdef DEBUG
@@ -2790,7 +2792,9 @@ domenuselect(Hookdef dummy, Chdata dat)
Menustack s = (Menustack) zhalloc(sizeof(*s));
int ol;
- mode = 0;
+ if (mode == MM_INTER)
+ do_single(*minfo.cur);
+ mode = 0;
s->prev = u;
u = s;
s->line = dupstring(zlemetaline);
@@ -2880,7 +2884,8 @@ domenuselect(Hookdef dummy, Chdata dat)
brend = dupbrinfo(u->brend, &lastbrend, 0);
nbrbeg = u->nbrbeg;
nbrend = u->nbrend;
- origline = u->origline;
+ zsfree(origline);
+ origline = ztrdup(u->origline);
origcs = u->origcs;
origll = u->origll;
strcpy(status, u->status);
@@ -3234,7 +3239,8 @@ domenuselect(Hookdef dummy, Chdata dat)
* don't want that, just what the user typed,
* so restore the information.
*/
- origline = modeline;
+ zsfree(origline);
+ origline = ztrdup(modeline);
origcs = modecs;
origll = modell;
zlemetacs = 0;
diff --git a/Src/Zle/compmatch.c b/Src/Zle/compmatch.c
index 4cd3b9ffe..05ae43ae6 100644
--- a/Src/Zle/compmatch.c
+++ b/Src/Zle/compmatch.c
@@ -1014,6 +1014,7 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
Brinfo *bpl, int bcp, Brinfo *bsl, int bcs, int *exact)
{
char *r = NULL;
+ int onoerrs = noerrs;
if (cp) {
/* We have a globcomplete-like pattern, just use that. */
@@ -1033,12 +1034,14 @@ comp_match(char *pfx, char *sfx, char *w, Patprog cp, Cline *clp, int qu,
*/
teststr = dupstring(r);
tokenize(teststr);
+ noerrs = 1;
if (parse_subst_string(teststr))
teststr = r;
else {
remnulargs(teststr);
untokenize(teststr);
}
+ noerrs = onoerrs;
} else
teststr = r;
if (!pattry(cp, teststr))
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index fcceb670c..9f383f4b8 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -1090,15 +1090,16 @@ do_single(Cmatch m)
}
if (tryit) {
noerrs = 1;
- parsestr(p);
+ p = dupstring(p);
+ parsestr(&p);
singsub(&p);
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
noerrs = ne;
}
} else {
p = (char *) zhalloc(strlen(prpre) + strlen(str) +
strlen(psuf) + 3);
- sprintf(p, "%s%s%s", ((prpre && *prpre) ?
+ sprintf(p, "%s%s%s", (*prpre ?
prpre : "./"), str, psuf);
}
/* And do the stat. */
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index b11c39f25..a81d1ddad 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -4060,7 +4060,8 @@ cfp_test_exact(LinkList names, char **accept, char *skipped)
if (sl > PATH_MAX2)
return NULL;
- suf = dyncat(skipped, rembslash(dyncat(compprefix, compsuffix)));
+ suf = dyncat(skipped, rembslash(dyncat(compprefix ? compprefix : "",
+ compsuffix ? compsuffix : "")));
for (node = firstnode(names); node; incnode(node)) {
l = strlen(p = (char *) getdata(node));
diff --git a/Src/Zle/iwidgets.list b/Src/Zle/iwidgets.list
index e3ffe3e8c..b41661a7d 100644
--- a/Src/Zle/iwidgets.list
+++ b/Src/Zle/iwidgets.list
@@ -24,7 +24,7 @@
"backward-kill-word", backwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
"backward-word", backwardword, 0
"beep", handlefeep, 0
-"beginning-of-buffer-or-history", beginningofbufferorhistory, 0
+"beginning-of-buffer-or-history", beginningofbufferorhistory, ZLE_LINEMOVE
"beginning-of-history", beginningofhistory, 0
"beginning-of-line", beginningofline, 0
"beginning-of-line-hist", beginningoflinehist, 0
@@ -41,11 +41,12 @@
"digit-argument", digitargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"down-case-word", downcaseword, 0
"down-history", downhistory, 0
+"down-line", downline, ZLE_LINEMOVE | ZLE_LASTCOL
"down-line-or-history", downlineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
"down-line-or-search", downlineorsearch, ZLE_LINEMOVE | ZLE_LASTCOL
"emacs-backward-word", emacsbackwardword, 0
"emacs-forward-word", emacsforwardword, 0
-"end-of-buffer-or-history", endofbufferorhistory, 0
+"end-of-buffer-or-history", endofbufferorhistory, ZLE_LINEMOVE
"end-of-history", endofhistory, 0
"end-of-line", endofline, 0
"end-of-line-hist", endoflinehist, 0
@@ -88,6 +89,7 @@
"push-input", pushinput, 0
"push-line", pushline, 0
"push-line-or-edit", pushlineoredit, 0
+"put-replace-selection", putreplaceselection, ZLE_KEEPSUFFIX
"quoted-insert", quotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"quote-line", quoteline, 0
"quote-region", quoteregion, 0
@@ -98,13 +100,19 @@
"reset-prompt", resetprompt, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"reverse-menu-complete", reversemenucomplete, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_ISCOMP
"run-help", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
+"select-a-word", selectword, ZLE_KEEPSUFFIX
+"select-in-word", selectword, ZLE_KEEPSUFFIX
+"select-a-blank-word", selectword, ZLE_KEEPSUFFIX
+"select-in-blank-word", selectword, ZLE_KEEPSUFFIX
+"select-a-shell-word", selectargument, ZLE_KEEPSUFFIX
+"select-in-shell-word", selectargument, ZLE_KEEPSUFFIX
"self-insert", selfinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"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
+"split-undo", splitundo, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"spell-word", spellword, 0
-"set-local-history", setlocalhistory, 0
+"set-local-history", setlocalhistory, ZLE_LASTCOL
"transpose-chars", transposechars, 0
"transpose-words", transposewords, 0
"undefined-key", undefinedkey, 0
@@ -112,6 +120,7 @@
"universal-argument", universalargument, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_NOTCOMMAND
"up-case-word", upcaseword, 0
"up-history", uphistory, 0
+"up-line", upline, ZLE_LINEMOVE | ZLE_LASTCOL
"up-line-or-history", uplineorhistory, ZLE_LINEMOVE | ZLE_LASTCOL
"up-line-or-search", uplineorsearch, ZLE_LINEMOVE | ZLE_LASTCOL
"vi-add-eol", viaddeol, 0
@@ -119,20 +128,22 @@
"vi-backward-blank-word", vibackwardblankword, 0
"vi-backward-char", vibackwardchar, 0
"vi-backward-delete-char", vibackwarddeletechar, ZLE_KEEPSUFFIX
-"vi-backward-kill-word", vibackwardkillword, ZLE_KILL | ZLE_KEEPSUFFIX
+"vi-backward-kill-word", vibackwardkillword, ZLE_KEEPSUFFIX
"vi-backward-word", vibackwardword, 0
+"vi-backward-word-end", vibackwardwordend, 0
+"vi-backward-blank-word-end", vibackwardblankwordend, 0
"vi-beginning-of-line", vibeginningofline, 0
-"vi-caps-lock-panic", vicapslockpanic, 0
-"vi-change", vichange, 0
+"vi-caps-lock-panic", vicapslockpanic, ZLE_LASTCOL
+"vi-change", vichange, ZLE_LASTCOL | ZLE_VIOPER
"vi-change-eol", vichangeeol, 0
"vi-change-whole-line", vichangewholeline, 0
"vi-cmd-mode", vicmdmode, 0
-"vi-delete", videlete, ZLE_KILL | ZLE_KEEPSUFFIX
+"vi-delete", videlete, ZLE_KEEPSUFFIX | ZLE_LASTCOL | ZLE_VIOPER
"vi-delete-char", videletechar, ZLE_KEEPSUFFIX
"vi-digit-or-beginning-of-line", vidigitorbeginningofline, 0
"vi-down-line-or-history", vidownlineorhistory, ZLE_LINEMOVE
"vi-end-of-line", viendofline, ZLE_LASTCOL
-"vi-fetch-history", vifetchhistory, 0
+"vi-fetch-history", vifetchhistory, ZLE_LINEMOVE
"vi-find-next-char", vifindnextchar, 0
"vi-find-next-char-skip", vifindnextcharskip, 0
"vi-find-prev-char", vifindprevchar, 0
@@ -145,22 +156,22 @@
"vi-forward-word-end", viforwardwordend, 0
"vi-goto-column", vigotocolumn, 0
"vi-goto-mark", vigotomark, 0
-"vi-goto-mark-line", vigotomarkline, 0
+"vi-goto-mark-line", vigotomarkline, ZLE_LINEMOVE
"vi-history-search-backward", vihistorysearchbackward, 0
"vi-history-search-forward", vihistorysearchforward, 0
-"vi-indent", viindent, 0
+"vi-indent", viindent, ZLE_LASTCOL | ZLE_VIOPER
"vi-insert", viinsert, 0
"vi-insert-bol", viinsertbol, 0
"vi-join", vijoin, 0
-"vi-kill-eol", vikilleol, ZLE_KILL | ZLE_KEEPSUFFIX
-"vi-kill-line", vikillline, ZLE_KILL | ZLE_KEEPSUFFIX
+"vi-kill-eol", vikilleol, ZLE_KEEPSUFFIX
+"vi-kill-line", vikillline, ZLE_KEEPSUFFIX
"vi-match-bracket", vimatchbracket, 0
"vi-open-line-above", viopenlineabove, 0
"vi-open-line-below", viopenlinebelow, 0
-"vi-oper-swap-case", vioperswapcase, 0
+"vi-oper-swap-case", vioperswapcase, ZLE_LASTCOL | ZLE_VIOPER
"vi-pound-insert", vipoundinsert, 0
-"vi-put-after", viputafter, ZLE_YANK | ZLE_KEEPSUFFIX
-"vi-put-before", viputbefore, ZLE_YANK | ZLE_KEEPSUFFIX
+"vi-put-after", viputafter, ZLE_YANKAFTER | ZLE_KEEPSUFFIX
+"vi-put-before", viputbefore, ZLE_YANKBEFORE | ZLE_KEEPSUFFIX
"vi-quoted-insert", viquotedinsert, ZLE_MENUCMP | ZLE_KEEPSUFFIX
"vi-repeat-change", virepeatchange, 0
"vi-repeat-find", virepeatfind, 0
@@ -172,15 +183,17 @@
"vi-set-buffer", visetbuffer, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"vi-set-mark", visetmark, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"vi-substitute", visubstitute, 0
-"vi-swap-case", viswapcase, 0
+"vi-swap-case", viswapcase, ZLE_LASTCOL
"vi-undo-change", viundochange, ZLE_KEEPSUFFIX
-"vi-unindent", viunindent, 0
+"vi-unindent", viunindent, ZLE_LASTCOL | ZLE_VIOPER
"vi-up-line-or-history", viuplineorhistory, ZLE_LINEMOVE
-"vi-yank", viyank, 0
+"vi-yank", viyank, ZLE_LASTCOL | ZLE_VIOPER
"vi-yank-eol", viyankeol, 0
"vi-yank-whole-line", viyankwholeline, 0
+"visual-line-mode", visuallinemode, ZLE_MENUCMP | ZLE_LASTCOL
+"visual-mode", visualmode, ZLE_MENUCMP | ZLE_LASTCOL
"what-cursor-position", whatcursorposition, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"where-is", whereis, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
"which-command", processcmd, ZLE_MENUCMP | ZLE_KEEPSUFFIX | ZLE_LASTCOL
-"yank", yank, ZLE_YANK | ZLE_KEEPSUFFIX
-"yank-pop", yankpop, ZLE_YANK | ZLE_KEEPSUFFIX
+"yank", yank, ZLE_YANKBEFORE | ZLE_KEEPSUFFIX
+"yank-pop", yankpop, ZLE_KEEPSUFFIX | ZLE_NOTCOMMAND
diff --git a/Src/Zle/textobjects.c b/Src/Zle/textobjects.c
new file mode 100644
index 000000000..9b3277a97
--- /dev/null
+++ b/Src/Zle/textobjects.c
@@ -0,0 +1,322 @@
+/*
+ * textobjects.c - ZLE module implementing Vim style text objects
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2014 Oliver Kiddle
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Oliver Kiddle or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Oliver Kiddle and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Oliver Kiddle and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Oliver Kiddle and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "zle.mdh"
+#include "textobjects.pro"
+
+/* class of character: 0 is whitespace, 1 is word character, 2 is other */
+static int
+wordclass(ZLE_CHAR_T x)
+{
+ return (ZC_iblank(x) ? 0 : ((ZC_ialnum(x) || (ZWC('_') == x)) ? 1 : 2));
+}
+
+static int
+blankwordclass(ZLE_CHAR_T x)
+{
+ return (ZC_iblank(x) ? 0 : 1);
+}
+
+/**/
+int
+selectword(UNUSED(char **args))
+{
+ int n = zmult;
+ int all = (bindk == t_selectaword || bindk == t_selectablankword);
+ int (*viclass)(ZLE_CHAR_T) = (bindk == t_selectaword ||
+ bindk == t_selectinword) ? wordclass : blankwordclass;
+ int sclass = viclass(zleline[zlecs]);
+ int doblanks = all && sclass;
+
+ if (!invicmdmode()) {
+ region_active = 1;
+ mark = zlecs;
+ }
+ if (!region_active || zlecs == mark) {
+ /* search back to first character of same class as the start position
+ * also stop at the beginning of the line */
+ mark = zlecs;
+ while (mark) {
+ int pos = mark;
+ DECPOS(pos);
+ if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass)
+ break;
+ mark = pos;
+ }
+ /* similarly scan forward over characters of the same class */
+ while (zlecs < zlell) {
+ INCCS();
+ int pos = zlecs;
+ /* single newlines within blanks are included */
+ if (all && !sclass && pos < zlell && zleline[pos] == ZWC('\n'))
+ INCPOS(pos);
+
+ if (zleline[pos] == ZWC('\n') || viclass(zleline[pos]) != sclass)
+ break;
+ }
+
+ if (all) {
+ int nclass = viclass(zleline[zlecs]);
+ /* if either start or new position is blank advance over
+ * a new block of characters of a common type */
+ if (!nclass || !sclass) {
+ while (zlecs < zlell) {
+ INCCS();
+ if (zleline[zlecs] == ZWC('\n') ||
+ viclass(zleline[zlecs]) != nclass)
+ break;
+ }
+ if (n < 2)
+ doblanks = 0;
+ }
+ }
+ } else {
+ /* For visual mode, advance one char so repeated
+ * invocations select subsequent words */
+ if (zlecs > mark) {
+ if (zlecs < zlell)
+ INCCS();
+ } else if (zlecs)
+ DECCS();
+ if (zlecs < mark) {
+ /* visual mode with the cursor before the mark: move cursor back */
+ while (n-- > 0) {
+ int pos = zlecs;
+ /* first over blanks */
+ if (all && (!viclass(zleline[pos]) ||
+ zleline[pos] == ZWC('\n'))) {
+ all = 0;
+ while (pos) {
+ DECPOS(pos);
+ if (zleline[pos] == ZWC('\n'))
+ break;
+ zlecs = pos;
+ if (viclass(zleline[pos]))
+ break;
+ }
+ } else if (zlecs && zleline[zlecs] == ZWC('\n')) {
+ /* for in widgets pass over one newline */
+ DECPOS(pos);
+ if (zleline[pos] != ZWC('\n'))
+ zlecs = pos;
+ }
+ pos = zlecs;
+ sclass = viclass(zleline[zlecs]);
+ /* now retreat over non-blanks */
+ while (zleline[pos] != ZWC('\n') &&
+ viclass(zleline[pos]) == sclass) {
+ zlecs = pos;
+ if (!pos) {
+ zlecs = 0;
+ break;
+ }
+ DECPOS(pos);
+ }
+ /* blanks again but only if there were none first time */
+ if (all && zlecs) {
+ pos = zlecs;
+ DECPOS(pos);
+ if (!viclass(zleline[pos])) {
+ while (pos) {
+ DECPOS(pos);
+ if (zleline[pos] == ZWC('\n') ||
+ viclass(zleline[pos]))
+ break;
+ zlecs = pos;
+ }
+ }
+ }
+ }
+ return 0;
+ }
+ n++;
+ doblanks = 0;
+ }
+ region_active = !!region_active; /* force to character wise */
+
+ /* for each digit argument, advance over further block of one class */
+ while (--n > 0) {
+ if (zlecs < zlell && zleline[zlecs] == ZWC('\n'))
+ INCCS();
+ sclass = viclass(zleline[zlecs]);
+ while (zlecs < zlell) {
+ INCCS();
+ if (zleline[zlecs] == ZWC('\n') ||
+ viclass(zleline[zlecs]) != sclass)
+ break;
+ }
+ /* for 'a' widgets, advance extra block if either consists of blanks */
+ if (all) {
+ if (zlecs < zlell && zleline[zlecs] == ZWC('\n'))
+ INCCS();
+ if (!sclass || !viclass(zleline[zlecs]) ) {
+ sclass = viclass(zleline[zlecs]);
+ if (n == 1 && !sclass)
+ doblanks = 0;
+ while (zlecs < zlell) {
+ INCCS();
+ if (zleline[zlecs] == ZWC('\n') ||
+ viclass(zleline[zlecs]) != sclass)
+ break;
+ }
+ }
+ }
+ }
+
+ /* if we didn't remove blanks at either end we remove some at the start */
+ if (doblanks) {
+ int pos = mark;
+ while (pos) {
+ DECPOS(pos);
+ /* don't remove blanks at the start of the line, i.e indentation */
+ if (zleline[pos] == ZWC('\n'))
+ break;
+ if (!ZC_iblank(zleline[pos])) {
+ INCPOS(pos);
+ mark = pos;
+ break;
+ }
+ }
+ }
+ /* Adjustment: vi operators don't include the cursor position, in insert
+ * or emacs mode the region also doesn't but for vi visual mode it is
+ * included. */
+ if (zlecs && zlecs > mark && !virangeflag)
+ DECCS();
+
+ return 0;
+}
+
+/**/
+int
+selectargument(UNUSED(char **args))
+{
+ int ne = noerrs, ocs = zlemetacs;
+ int owb = wb, owe= we, oadx = addedx, ona = noaliases;
+ char *p;
+ int ll, cs;
+ char *linein;
+ int wend = 0, wcur = 0;
+ int n = zmult;
+ int *wstarts;
+ int tmpsz;
+
+ if (n < 1 || 2*n > zlell + 1)
+ return 1;
+
+ /* if used from emacs mode enable the region */
+ if (!invicmdmode()) {
+ region_active = 1;
+ mark = zlecs;
+ }
+
+ wstarts = (int *) zhalloc(n * sizeof(int));
+ memset(wstarts, 0, n * sizeof(int));
+
+ addedx = 0;
+ noerrs = 1;
+ zcontext_save();
+ lexflags = LEXFLAGS_ACTIVE;
+ linein = zlegetline(&ll, &cs);
+ zlemetall = ll;
+ zlemetacs = cs;
+
+ if (!isfirstln && chline) {
+ p = (char *) zhalloc(hptr - chline + zlemetall + 2);
+ memcpy(p, chline, hptr - chline);
+ memcpy(p + (hptr - chline), linein, ll);
+ p[(hptr - chline) + ll] = '\0';
+ inpush(p, 0, NULL);
+ zlemetacs += hptr - chline;
+ } else {
+ p = (char *) zhalloc(ll + 1);
+ memcpy(p, linein, ll);
+ p[ll] = '\0';
+ inpush(p, 0, NULL);
+ }
+ if (zlemetacs)
+ zlemetacs--;
+ strinbeg(0);
+ noaliases = 1;
+ do {
+ wstarts[wcur++] = wend;
+ wcur %= n;
+ ctxtlex();
+ if (tok == ENDINPUT || tok == LEXERR)
+ break;
+ wend = zlemetall - inbufct;
+ } while (tok != ENDINPUT && tok != LEXERR && wend <= zlemetacs);
+ noaliases = ona;
+ strinend();
+ inpop();
+ errflag &= ~ERRFLAG_ERROR;
+ noerrs = ne;
+ zcontext_restore();
+ zlemetacs = ocs;
+ wb = owb;
+ we = owe;
+ addedx = oadx;
+
+ /* convert offsets for mark and zlecs back to ZLE internal format */
+ linein[wend] = '\0'; /* a bit of a hack to get two offsets */
+ free(stringaszleline(linein, wstarts[wcur], &zlecs, &tmpsz, &mark));
+ free(linein);
+
+ if (bindk == t_selectinshellword) {
+ ZLE_CHAR_T *match = ZWS("`\'\"");
+ ZLE_CHAR_T *lmatch = ZWS("\'({"), *rmatch = ZWS("\')}");
+ ZLE_CHAR_T *ematch = match, *found;
+ int start, end = zlecs;
+ /* for 'in' widget, don't include initial blanks ... */
+ while (mark < zlecs && ZC_iblank(zleline[mark]))
+ INCPOS(mark);
+ /* ... or a matching pair of quotes */
+ start = mark;
+ if (zleline[start] == ZWC('$')) {
+ match = lmatch;
+ ematch = rmatch;
+ INCPOS(start);
+ }
+ found = ZS_strchr(match, zleline[start]);
+ if (found) {
+ DECPOS(end);
+ if (zleline[end] == ematch[found-match]) {
+ zlecs = end;
+ INCPOS(start);
+ mark = start;
+ }
+ }
+ }
+
+ /* Adjustment: vi operators don't include the cursor position */
+ if (!virangeflag)
+ DECCS();
+
+ return 0;
+}
diff --git a/Src/Zle/zle.h b/Src/Zle/zle.h
index 870e2149d..3c652909e 100644
--- a/Src/Zle/zle.h
+++ b/Src/Zle/zle.h
@@ -203,13 +203,16 @@ struct widget {
#define WIDGET_INT (1<<0) /* widget is internally implemented */
#define WIDGET_NCOMP (1<<1) /* new style completion widget */
#define ZLE_MENUCMP (1<<2) /* DON'T invalidate completion list */
-#define ZLE_YANK (1<<3)
-#define ZLE_LINEMOVE (1<<4) /* command is a line-oriented movement */
-#define ZLE_LASTCOL (1<<5) /* command maintains lastcol correctly */
-#define ZLE_KILL (1<<6)
-#define ZLE_KEEPSUFFIX (1<<7) /* DON'T remove added suffix */
-#define ZLE_NOTCOMMAND (1<<8) /* widget should not alter lastcmd */
-#define ZLE_ISCOMP (1<<9) /* usable for new style completion */
+#define ZLE_YANKAFTER (1<<3)
+#define ZLE_YANKBEFORE (1<<4)
+#define ZLE_YANK (ZLE_YANKAFTER | ZLE_YANKBEFORE)
+#define ZLE_LINEMOVE (1<<5) /* command is a line-oriented movement */
+#define ZLE_VIOPER (1<<6) /* widget reads further keys so wait if prefix */
+#define ZLE_LASTCOL (1<<7) /* command maintains lastcol correctly */
+#define ZLE_KILL (1<<8)
+#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 */
/* thingies */
@@ -240,6 +243,9 @@ struct modifier {
#define MOD_VIBUF (1<<2) /* a vi cut buffer has been selected */
#define MOD_VIAPP (1<<3) /* appending to the vi cut buffer */
#define MOD_NEG (1<<4) /* last command was negate argument */
+#define MOD_NULL (1<<5) /* throw away text for the vi cut buffer */
+#define MOD_CHAR (1<<6) /* force character-wise movement */
+#define MOD_LINE (1<<7) /* force line-wise movement */
/* current modifier status */
@@ -256,6 +262,7 @@ struct modifier {
* of visible characters directly input by
* the user.
*/
+#define CUT_YANK (1<<3) /* vi yank: use register 0 instead of 1-9 */
/* undo system */
diff --git a/Src/Zle/zle.mdd b/Src/Zle/zle.mdd
index c6e4d11c2..dd69eff2c 100644
--- a/Src/Zle/zle.mdd
+++ b/Src/Zle/zle.mdd
@@ -7,7 +7,8 @@ autofeatures="b:bindkey b:vared b:zle"
objects="zle_bindings.o zle_hist.o zle_keymap.o zle_main.o \
zle_misc.o zle_move.o zle_params.o zle_refresh.o \
-zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o"
+zle_thingy.o zle_tricky.o zle_utils.o zle_vi.o zle_word.o \
+textobjects.o"
headers="zle.h zle_things.h"
diff --git a/Src/Zle/zle_bindings.c b/Src/Zle/zle_bindings.c
index 682691347..2ae8c8764 100644
--- a/Src/Zle/zle_bindings.c
+++ b/Src/Zle/zle_bindings.c
@@ -278,7 +278,7 @@ int viinsbind[32] = {
/* ^U */ z_vikillline,
/* ^V */ z_viquotedinsert,
/* ^W */ z_vibackwardkillword,
- /* ^X */ z_selfinsert,
+ /* ^X */ z_undefinedkey,
/* ^Y */ z_selfinsert,
/* ^Z */ z_selfinsert,
/* ^[ */ z_vicmdmode,
@@ -308,7 +308,7 @@ int vicmdbind[128] = {
/* ^O */ z_undefinedkey,
/* ^P */ z_uphistory,
/* ^Q */ z_undefinedkey,
- /* ^R */ z_redisplay,
+ /* ^R */ z_redo,
/* ^S */ z_undefinedkey,
/* ^T */ z_undefinedkey,
/* ^U */ z_undefinedkey,
@@ -376,7 +376,7 @@ int vicmdbind[128] = {
/* S */ z_vichangewholeline,
/* T */ z_vifindprevcharskip,
/* U */ z_undefinedkey,
- /* V */ z_undefinedkey,
+ /* V */ z_visuallinemode,
/* W */ z_viforwardblankword,
/* X */ z_vibackwarddeletechar,
/* Y */ z_viyankwholeline,
@@ -407,8 +407,8 @@ int vicmdbind[128] = {
/* r */ z_vireplacechars,
/* s */ z_visubstitute,
/* t */ z_vifindnextcharskip,
- /* u */ z_viundochange,
- /* v */ z_undefinedkey,
+ /* u */ z_undo,
+ /* v */ z_visualmode,
/* w */ z_viforwardword,
/* x */ z_videletechar,
/* y */ z_viyank,
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index 44b39d186..cc66f99ae 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -227,14 +227,14 @@ uphistory(UNUSED(char **args))
}
/**/
-static int
-upline(void)
+int
+upline(char **args)
{
int n = zmult;
if (n < 0) {
zmult = -zmult;
- n = -downline();
+ n = -downline(args);
zmult = -zmult;
return n;
}
@@ -270,7 +270,7 @@ int
uplineorhistory(char **args)
{
int ocs = zlecs;
- int n = upline();
+ int n = upline(args);
if (n) {
int m = zmult, ret;
@@ -300,7 +300,7 @@ int
uplineorsearch(char **args)
{
int ocs = zlecs;
- int n = upline();
+ int n = upline(args);
if (n) {
int m = zmult, ret;
@@ -316,14 +316,14 @@ uplineorsearch(char **args)
}
/**/
-static int
-downline(void)
+int
+downline(char **args)
{
int n = zmult;
if (n < 0) {
zmult = -zmult;
- n = -upline();
+ n = -upline(args);
zmult = -zmult;
return n;
}
@@ -358,7 +358,7 @@ int
downlineorhistory(char **args)
{
int ocs = zlecs;
- int n = downline();
+ int n = downline(args);
if (n) {
int m = zmult, ret;
@@ -388,7 +388,7 @@ int
downlineorsearch(char **args)
{
int ocs = zlecs;
- int n = downline();
+ int n = downline(args);
if (n) {
int m = zmult, ret;
@@ -821,6 +821,8 @@ pushline(UNUSED(char **args))
zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0));
while (--n)
zpushnode(bufstack, ztrdup(""));
+ if (invicmdmode())
+ INCCS();
stackcs = zlecs;
*zleline = ZWC('\0');
zlell = zlecs = 0;
@@ -851,8 +853,10 @@ pushlineoredit(char **args)
free(zhline);
}
ret = pushline(args);
- if (!isfirstln)
- errflag = done = 1;
+ if (!isfirstln) {
+ errflag |= ERRFLAG_ERROR|ERRFLAG_INT;
+ done = 1;
+ }
clearlist = 1;
return ret;
}
diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c
index e21e769bd..c6fae251d 100644
--- a/Src/Zle/zle_keymap.c
+++ b/Src/Zle/zle_keymap.c
@@ -503,7 +503,18 @@ selectkeymap(char *name, int fb)
mod_export void
selectlocalmap(Keymap m)
{
+ Keymap oldm = localkeymap;
localkeymap = m;
+ if (oldm && !m)
+ {
+ /*
+ * No local keymap; so we are returning to the global map. If
+ * the user ^Ced in the local map, they probably just want to go
+ * back to normal editing. So remove the interrupt error
+ * status.
+ */
+ errflag &= ~ERRFLAG_INT;
+ }
}
/* Reopen the currently selected keymap, in case it got deleted. This *
@@ -1191,7 +1202,7 @@ init_keymaps(void)
{
createkeymapnamtab();
default_bindings();
- keybuf = (char *)zalloc(keybufsz);
+ keybuf = (char *)zshcalloc(keybufsz);
lastnamed = refthingy(t_undefinedkey);
}
@@ -1277,8 +1288,10 @@ default_bindings(void)
Keymap vmap = newkeymap(NULL, "viins");
Keymap emap = newkeymap(NULL, "emacs");
Keymap amap = newkeymap(NULL, "vicmd");
+ Keymap oppmap = newkeymap(NULL, "viopp");
+ Keymap vismap = newkeymap(NULL, "visual");
Keymap smap = newkeymap(NULL, ".safe");
- Keymap vimaps[2], kptr;
+ Keymap vimaps[2], vilmaps[2], kptr;
char buf[3], *ed;
int i;
@@ -1332,6 +1345,36 @@ default_bindings(void)
add_cursor_key(kptr, TCLEFTCURSOR, t_vibackwardchar, 'D');
add_cursor_key(kptr, TCRIGHTCURSOR, t_viforwardchar, 'C');
}
+ vilmaps[0] = oppmap;
+ vilmaps[1] = vismap;
+ for (i = 0; i < 2; i++) {
+ /* vi visual selection and operator pending local maps */
+ kptr = vilmaps[i];
+ add_cursor_key(kptr, TCUPCURSOR, t_upline, 'A');
+ add_cursor_key(kptr, TCDOWNCURSOR, t_downline, 'B');
+ bindkey(kptr, "k", refthingy(t_upline), NULL);
+ bindkey(kptr, "j", refthingy(t_downline), NULL);
+ bindkey(kptr, "aa", refthingy(t_selectashellword), NULL);
+ bindkey(kptr, "ia", refthingy(t_selectinshellword), NULL);
+ bindkey(kptr, "aw", refthingy(t_selectaword), NULL);
+ bindkey(kptr, "iw", refthingy(t_selectinword), NULL);
+ bindkey(kptr, "aW", refthingy(t_selectablankword), NULL);
+ bindkey(kptr, "iW", refthingy(t_selectinblankword), NULL);
+ }
+ /* escape in operator pending cancels the operation */
+ bindkey(oppmap, "\33", refthingy(t_vicmdmode), NULL);
+ bindkey(vismap, "o", refthingy(t_exchangepointandmark), NULL);
+ bindkey(vismap, "p", refthingy(t_putreplaceselection), NULL);
+ bindkey(vismap, "x", refthingy(t_videlete), NULL);
+ bindkey(vismap, "~", refthingy(t_vioperswapcase), NULL);
+
+ /* vi mode: some common vim bindings */
+ bindkey(amap, "ga", refthingy(t_whatcursorposition), NULL);
+ bindkey(amap, "ge", refthingy(t_vibackwardwordend), NULL);
+ bindkey(amap, "gE", refthingy(t_vibackwardblankwordend), NULL);
+ bindkey(amap, "gg", refthingy(t_beginningofbufferorhistory), NULL);
+ bindkey(amap, "g~", refthingy(t_vioperswapcase), NULL);
+ bindkey(amap, "g~~", NULL, "g~g~");
/* emacs mode: arrow keys */
add_cursor_key(emap, TCUPCURSOR, t_uplineorhistory, 'A');
@@ -1373,6 +1416,8 @@ default_bindings(void)
linkkeymap(vmap, "viins", 0);
linkkeymap(emap, "emacs", 0);
linkkeymap(amap, "vicmd", 0);
+ linkkeymap(oppmap, "viopp", 0);
+ linkkeymap(vismap, "visual", 0);
linkkeymap(smap, ".safe", 1);
if (((ed = zgetenv("VISUAL")) && strstr(ed, "vi")) ||
((ed = zgetenv("EDITOR")) && strstr(ed, "vi")))
@@ -1408,6 +1453,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
Thingy func = t_undefinedkey;
char *str = NULL;
int lastlen = 0, lastc = lastchar;
+ int timeout = 0;
keybuflen = 0;
keybuf[0] = 0;
@@ -1425,7 +1471,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
* argument to bindkey is in the correct form for the locale.
* That's beyond our control.
*/
- while(getkeybuf(!!lastlen) != EOF) {
+ while(getkeybuf(timeout) != EOF) {
char *s;
Thingy f;
int loc = !!localkeymap;
@@ -1435,7 +1481,7 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
loc = ((f = keybind(localkeymap, keybuf, &s)) != t_undefinedkey);
ispfx = keyisprefix(localkeymap, keybuf);
}
- if (!loc)
+ if (!loc && !ispfx)
f = keybind(km, keybuf, &s);
ispfx |= keyisprefix(km, keybuf);
@@ -1444,6 +1490,11 @@ getkeymapcmd(Keymap km, Thingy *funcp, char **strp)
func = f;
str = s;
lastc = lastchar;
+
+ /* can be patient with vi commands that need a motion operator: *
+ * they wait till a key is pressed for the movement anyway */
+ timeout = !(!virangeflag && !region_active && f && f->widget &&
+ f->widget->flags & ZLE_VIOPER);
}
if (!ispfx)
break;
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 442c31995..cec44c0ed 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -187,10 +187,6 @@ mod_export char *zlenoargs[1] = { NULL };
static char **raw_lp, **raw_rp;
-#ifdef FIONREAD
-static int delayzsetterm;
-#endif
-
/*
* File descriptors we are watching as well as the terminal fd.
* These are all for reading; we don't watch for writes or exceptions.
@@ -210,9 +206,6 @@ mod_export void
zsetterm(void)
{
struct ttyinfo ti;
-#if defined(FIONREAD)
- int val;
-#endif
if (fetchttyinfo) {
/*
@@ -224,30 +217,6 @@ zsetterm(void)
fetchttyinfo = 0;
}
-#if defined(FIONREAD)
- ioctl(SHTTY, FIONREAD, (char *)&val);
- if (val) {
- /*
- * Problems can occur on some systems when switching from
- * canonical to non-canonical input. The former is usually
- * set while running programmes, but the latter is necessary
- * for zle. If there is input in canonical mode, then we
- * need to read it without setting up the terminal. Furthermore,
- * while that input gets processed there may be more input
- * being typed (i.e. further typeahead). This means that
- * we can't set up the terminal for zle *at all* until
- * we are sure there is no more typeahead to come. So
- * if there is typeahead, we set the flag delayzsetterm.
- * Then getbyte() performs another FIONREAD call; if that is
- * 0, we have finally used up all the typeahead, and it is
- * safe to alter the terminal, which we do at that point.
- */
- delayzsetterm = 1;
- return;
- } else
- delayzsetterm = 0;
-#endif
-
/* sanitize the tty */
#ifdef HAS_TIO
shttyinfo.tio.c_lflag |= ICANON | ECHO;
@@ -343,7 +312,7 @@ zsetterm(void)
ti.ltchars.t_dsuspc = ti.ltchars.t_lnextc = -1;
#endif
-#if defined(TTY_NEEDS_DRAINING) && defined(TIOCOUTQ) && defined(HAVE_SELECT)
+#if defined(TIOCOUTQ) && defined(HAVE_SELECT)
if (baud) { /**/
int n = 0;
@@ -541,11 +510,7 @@ raw_getbyte(long do_keytmout, char *cptr)
* timeouts may be external, so we may have both a permanent watched
* fd and a long-term timeout.
*/
- if ((nwatch || tmout.tp != ZTM_NONE)
-#ifdef FIONREAD
- && ! delayzsetterm
-#endif
- ) {
+ if ((nwatch || tmout.tp != ZTM_NONE)) {
#if defined(HAVE_SELECT) || defined(HAVE_POLL)
int i, errtry = 0, selret;
# ifdef HAVE_POLL
@@ -779,7 +744,7 @@ raw_getbyte(long do_keytmout, char *cptr)
}
if (errflag) {
/* No sensible way of handling errors here */
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
/*
* Paranoia: don't run the hooks again this
* time.
@@ -883,14 +848,6 @@ getbyte(long do_keytmout, int *timeout)
if (kungetct)
ret = STOUC(kungetbuf[--kungetct]);
else {
-#ifdef FIONREAD
- if (delayzsetterm) {
- int val;
- ioctl(SHTTY, FIONREAD, (char *)&val);
- if (!val)
- zsetterm();
- }
-#endif
for (;;) {
int q = queue_signal_level();
dont_queue_signals();
@@ -925,7 +882,7 @@ getbyte(long do_keytmout, int *timeout)
die = 0;
if (!errflag && !retflag && !breaks && !exit_pending)
continue;
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
breaks = obreaks;
errno = old_errno;
return lastchar = EOF;
@@ -1067,6 +1024,7 @@ getrestchar(int inchar)
void
zlecore(void)
{
+ Keymap km;
#if !defined(HAVE_POLL) && defined(HAVE_SELECT)
struct timeval tv;
fd_set foofd;
@@ -1088,8 +1046,10 @@ zlecore(void)
statusline = NULL;
vilinerange = 0;
reselectkeymap();
- selectlocalmap(NULL);
+ selectlocalmap(invicmdmode() && region_active && (km = openkeymap("visual"))
+ ? km : NULL);
bindk = getkeycmd();
+ selectlocalmap(NULL);
if (bindk) {
if (!zlell && isfirstln && !(zlereadflags & ZLRF_IGNOREEOF) &&
lastchar == eofchar) {
@@ -1115,7 +1075,7 @@ zlecore(void)
DECCS();
handleundo();
} else {
- errflag = 1;
+ errflag |= ERRFLAG_ERROR;
break;
}
#ifdef HAVE_POLL
@@ -1273,6 +1233,10 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
zleactive = 1;
resetneeded = 1;
+ /*
+ * Start of the main zle read.
+ * Fully reset error conditions, including user interrupt.
+ */
errflag = retflag = 0;
lastcol = -1;
initmodifier(&zmod);
@@ -1289,7 +1253,9 @@ zleread(char **lp, char **rp, int flags, int context, char *init, char *finish)
zlecore();
if (errflag)
- setsparam("ZLE_LINE_ABORTED", zlegetline(NULL, NULL));
+ setsparam((zlecontext == ZLCON_VARED) ?
+ "ZLE_VARED_ABORTED" :
+ "ZLE_LINE_ABORTED", zlegetline(NULL, NULL));
if (done && !exit_pending && !errflag)
zlecallhook(finish, NULL);
@@ -1698,7 +1664,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
}
if (!t || errflag) {
/* error in editing */
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
breaks = obreaks;
if (t)
zsfree(t);
@@ -1818,7 +1784,7 @@ recursiveedit(UNUSED(char **args))
zrefresh();
zlecore();
- locerror = errflag;
+ locerror = errflag ? 1 : 0;
errflag = done = eofsent = 0;
return locerror;
@@ -2128,7 +2094,7 @@ finish_(UNUSED(Module m))
free(kring[i].buf);
zfree(kring, kringsize * sizeof(struct cutbuffer));
}
- for(i = 35; i--; )
+ for(i = 36; i--; )
zfree(vibuf[i].buf, vibuf[i].len);
/* editor entry points */
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 9bc1cf6f5..4669ef2ad 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -47,13 +47,13 @@ doinsert(ZLE_STRING_T zstr, int len)
iremovesuffix(c1, 0);
invalidatelist();
- if (insmode)
+ /* In overwrite mode, don't replace newlines. */
+ if (insmode || zleline[zlecs] == ZWC('\n'))
spaceinline(m * len);
else
-#ifdef MULTIBYTE_SUPPORT
{
int pos = zlecs, diff, i;
-
+#ifdef MULTIBYTE_SUPPORT
/*
* Calculate the number of character positions we are
* going to be using. The algorithm is that
@@ -68,15 +68,18 @@ doinsert(ZLE_STRING_T zstr, int len)
* useful there anyway and this doesn't cause any
* particular harm.
*/
- for (i = 0, count = 0; i < len; i++) {
+ for (i = 0, count = 0; i < len * m; i++) {
if (!IS_COMBINING(zstr[i]))
count++;
}
+#else
+ count = len * m;
+#endif
/*
- * Ensure we replace a complete combining character
- * for each character we overwrite.
+ * Ensure we replace a complete combining characterfor each
+ * character we overwrite. Switch to inserting at first newline.
*/
- for (i = count; pos < zlell && i--; ) {
+ for (i = count; pos < zlell && zleline[pos] != ZWC('\n') && i--; ) {
INCPOS(pos);
}
/*
@@ -96,10 +99,6 @@ doinsert(ZLE_STRING_T zstr, int len)
shiftchars(zlecs, diff);
}
}
-#else
- if (zlecs + m * len > zlell)
- spaceinline(zlecs + m * len - zlell);
-#endif
while (m--)
for (s = zstr, count = len; count; s++, count--)
zleline[zlecs++] = *s;
@@ -440,15 +439,52 @@ killline(char **args)
}
/**/
+void
+regionlines(int *start, int *end)
+{
+ int origcs = zlecs;
+
+ UNMETACHECK();
+ if (zlecs < mark) {
+ *start = findbol();
+ zlecs = (mark > zlell) ? zlell : mark;
+ *end = findeol();
+ } else {
+ *end = findeol();
+ zlecs = mark;
+ *start = findbol();
+ }
+ zlecs = origcs;
+}
+
+/**/
int
killregion(UNUSED(char **args))
{
if (mark > zlell)
mark = zlell;
- if (mark > zlecs)
+ if (region_active == 2) {
+ int a, b;
+ regionlines(&a, &b);
+ zlecs = a;
+ region_active = 0;
+ cut(zlecs, b - zlecs, CUT_RAW);
+ shiftchars(zlecs, b - zlecs);
+ if (zlell) {
+ if (zlecs == zlell)
+ DECCS();
+ foredel(1, 0);
+ vifirstnonblank(zlenoargs);
+ }
+ } else if (mark > zlecs) {
+ if (invicmdmode())
+ INCPOS(mark);
forekill(mark - zlecs, CUT_RAW);
- else
+ } else {
+ if (invicmdmode())
+ INCCS();
backkill(zlecs - mark, CUT_FRONT|CUT_RAW);
+ }
return 0;
}
@@ -456,6 +492,7 @@ killregion(UNUSED(char **args))
int
copyregionaskill(char **args)
{
+ int start, end;
if (*args) {
int len;
ZLE_STRING_T line = stringaszleline(*args, 0, &len, NULL, NULL);
@@ -464,10 +501,16 @@ copyregionaskill(char **args)
} else {
if (mark > zlell)
mark = zlell;
- if (mark > zlecs)
- cut(zlecs, mark - zlecs, 0);
- else
- cut(mark, zlecs - mark, CUT_FRONT);
+ if (mark > zlecs) {
+ start = zlecs;
+ end = mark;
+ } else {
+ start = mark;
+ end = zlecs;
+ }
+ if (invicmdmode())
+ INCPOS(end);
+ cut(start, end - start, mark > zlecs ? 0 : CUT_FRONT);
}
return 0;
}
@@ -475,8 +518,10 @@ copyregionaskill(char **args)
/*
* kct: index into kill ring, or -1 for original cutbuffer of yank.
* yankb, yanke: mark the start and end of last yank in editing buffer.
+ * yankcs marks the cursor position preceding the last yank
*/
-static int kct, yankb, yanke;
+static int kct, yankb, yanke, yankcs;
+
/* The original cutbuffer, either cutbuf or one of the vi buffers. */
static Cutbuffer kctbuf;
@@ -494,8 +539,7 @@ yank(UNUSED(char **args))
kctbuf = &cutbuf;
if (!kctbuf->buf)
return 1;
- mark = zlecs;
- yankb = zlecs;
+ yankb = yankcs = mark = zlecs;
while (n--) {
kct = -1;
spaceinline(kctbuf->len);
@@ -506,11 +550,140 @@ yank(UNUSED(char **args))
return 0;
}
+/* position: 0 is before, 1 after, 2 split the line */
+static void pastebuf(Cutbuffer buf, int mult, int position)
+{
+ int cc;
+ if (buf->flags & CUTBUFFER_LINE) {
+ if (position == 2) {
+ if (!zlecs)
+ position = 0;
+ else if (zlecs == zlell)
+ position = 1;
+ }
+ if (position == 2) {
+ yankb = zlecs;
+ spaceinline(buf->len + 2);
+ zleline[zlecs++] = ZWC('\n');
+ ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
+ zlecs += buf->len;
+ zleline[zlecs] = ZWC('\n');
+ yanke = zlecs + 1;
+ } else if (position != 0) {
+ yankb = zlecs = findeol();
+ spaceinline(buf->len + 1);
+ zleline[zlecs++] = ZWC('\n');
+ yanke = zlecs + buf->len;
+ ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
+ } else {
+ yankb = zlecs = findbol();
+ spaceinline(buf->len + 1);
+ ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
+ yanke = zlecs + buf->len + 1;
+ zleline[zlecs + buf->len] = ZWC('\n');
+ }
+ vifirstnonblank(zlenoargs);
+ } else {
+ if (position == 1 && zlecs != findeol())
+ INCCS();
+ yankb = zlecs;
+ cc = buf->len;
+ while (mult--) {
+ spaceinline(cc);
+ ZS_memcpy(zleline + zlecs, buf->buf, cc);
+ zlecs += cc;
+ }
+ yanke = zlecs;
+ if (zlecs)
+ DECCS();
+ }
+}
+
+/**/
+int
+viputbefore(UNUSED(char **args))
+{
+ int n = zmult;
+
+ startvichange(-1);
+ if (n < 0 || zmod.flags & MOD_NULL)
+ return 1;
+ if (zmod.flags & MOD_VIBUF)
+ kctbuf = &vibuf[zmod.vibuf];
+ else
+ kctbuf = &cutbuf;
+ if (!kctbuf->buf)
+ return 1;
+ kct = -1;
+ yankcs = zlecs;
+ pastebuf(kctbuf, n, 0);
+ return 0;
+}
+
+/**/
+int
+viputafter(UNUSED(char **args))
+{
+ int n = zmult;
+
+ startvichange(-1);
+ if (n < 0 || zmod.flags & MOD_NULL)
+ return 1;
+ if (zmod.flags & MOD_VIBUF)
+ kctbuf = &vibuf[zmod.vibuf];
+ else
+ kctbuf = &cutbuf;
+ if (!kctbuf->buf)
+ return 1;
+ kct = -1;
+ yankcs = zlecs;
+ pastebuf(kctbuf, n, 1);
+ return 0;
+}
+
+/**/
+int
+putreplaceselection(UNUSED(char **args))
+{
+ int n = zmult;
+ struct cutbuffer prevbuf;
+ Cutbuffer putbuf;
+ int clear = 0;
+ int pos = 2;
+
+ startvichange(-1);
+ if (n < 0 || zmod.flags & MOD_NULL)
+ return 1;
+ putbuf = (zmod.flags & MOD_VIBUF) ? &vibuf[zmod.vibuf] : &cutbuf;
+ if (!putbuf->buf)
+ return 1;
+ memcpy(&prevbuf, putbuf, sizeof(prevbuf));
+
+ /* if "9 was specified, prevent killregion from freeing it */
+ if (zmod.vibuf == 35) {
+ putbuf->buf = 0;
+ clear = 1;
+ }
+
+ zmod.flags = 0; /* flags apply to paste not kill */
+ if (region_active == 2 && prevbuf.flags & CUTBUFFER_LINE) {
+ int a, b;
+ regionlines(&a, &b);
+ pos = (b == zlell);
+ }
+ killregion(zlenoargs);
+
+ pastebuf(&prevbuf, n, pos);
+ if (clear)
+ free(prevbuf.buf);
+ return 0;
+}
+
/**/
int
yankpop(UNUSED(char **args))
{
- int cc, kctstart = kct;
+ int kctstart = kct;
Cutbuffer buf;
if (!(lastcmd & ZLE_YANK) || !kring || !kctbuf) {
@@ -557,11 +730,8 @@ yankpop(UNUSED(char **args))
zlecs = yankb;
foredel(yanke - yankb, CUT_RAW);
- cc = buf->len;
- spaceinline(cc);
- ZS_memcpy(zleline + zlecs, buf->buf, cc);
- zlecs += cc;
- yanke = zlecs;
+ zlecs = yankcs;
+ pastebuf(buf, 1, !!(lastcmd & ZLE_YANKAFTER));
return 0;
}
@@ -871,7 +1041,7 @@ copyprevshellword(UNUSED(char **args))
int
sendbreak(UNUSED(char **args))
{
- errflag = 1;
+ errflag |= ERRFLAG_ERROR|ERRFLAG_INT;
return 1;
}
@@ -881,15 +1051,25 @@ quoteregion(UNUSED(char **args))
{
ZLE_STRING_T str;
size_t len;
+ int extra = invicmdmode();
if (mark > zlell)
mark = zlell;
- if (mark < zlecs) {
+ if (region_active == 2) {
+ int a, b;
+ regionlines(&a, &b);
+ zlecs = a;
+ mark = b;
+ extra = 0;
+ } else if (mark < zlecs) {
int tmp = mark;
mark = zlecs;
zlecs = tmp;
}
- str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) * ZLE_CHAR_SIZE);
+ if (extra)
+ INCPOS(mark);
+ str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) *
+ ZLE_CHAR_SIZE);
ZS_memcpy(str, zleline + zlecs, len);
foredel(len, CUT_RAW);
str = makequote(str, &len);
diff --git a/Src/Zle/zle_move.c b/Src/Zle/zle_move.c
index 7312b3f20..d751c4333 100644
--- a/Src/Zle/zle_move.c
+++ b/Src/Zle/zle_move.c
@@ -509,6 +509,55 @@ exchangepointandmark(UNUSED(char **args))
/**/
int
+visualmode(UNUSED(char **args))
+{
+ if (virangeflag) {
+ prefixflag = 1;
+ zmod.flags &= ~MOD_LINE;
+ zmod.flags |= MOD_CHAR;
+ return 0;
+ }
+ switch (region_active) {
+ case 1:
+ region_active = 0;
+ break;
+ case 0:
+ mark = zlecs;
+ /* fall through */
+ case 2:
+ region_active = 1;
+ break;
+ }
+ return 0;
+}
+
+/**/
+int
+visuallinemode(UNUSED(char **args))
+{
+ if (virangeflag) {
+ prefixflag = 1;
+ zmod.flags &= ~MOD_CHAR;
+ zmod.flags |= MOD_LINE;
+ return 0;
+ }
+ switch (region_active) {
+ case 2:
+ region_active = 0;
+ break;
+ case 0:
+ mark = zlecs;
+ /* fall through */
+ case 1:
+ region_active = 2;
+ break;
+ }
+ return 0;
+}
+
+
+/**/
+int
vigotocolumn(UNUSED(char **args))
{
int x, y, n = zmult;
@@ -538,7 +587,8 @@ vimatchbracket(UNUSED(char **args))
if ((zlecs == zlell || zleline[zlecs] == '\n') && zlecs > 0)
DECCS();
-
+ if (virangeflag)
+ mark = zlecs;
otog:
if (zlecs == zlell || zleline[zlecs] == '\n') {
zlecs = ocs;
@@ -550,7 +600,6 @@ vimatchbracket(UNUSED(char **args))
oth = '}';
break;
case /*{*/ '}':
- virangeflag = -virangeflag;
dir = -1;
oth = '{'; /*}*/
break;
@@ -559,7 +608,6 @@ vimatchbracket(UNUSED(char **args))
oth = ')';
break;
case ')':
- virangeflag = -virangeflag;
dir = -1;
oth = '(';
break;
@@ -568,7 +616,6 @@ vimatchbracket(UNUSED(char **args))
oth = ']';
break;
case ']':
- virangeflag = -virangeflag;
dir = -1;
oth = '[';
break;
@@ -576,6 +623,8 @@ vimatchbracket(UNUSED(char **args))
INCCS();
goto otog;
}
+ if (virangeflag && dir < 0)
+ INCPOS(mark); /* include starting position when going backwards */
ct = 1;
while (zlecs >= 0 && zlecs < zlell && ct) {
if (dir < 0)
@@ -599,7 +648,7 @@ vimatchbracket(UNUSED(char **args))
int
viforwardchar(char **args)
{
- int lim = findeol() - invicmdmode();
+ int lim = findeol();
int n = zmult;
if (n < 0) {
@@ -609,6 +658,8 @@ viforwardchar(char **args)
zmult = n;
return ret;
}
+ if (invicmdmode() && !virangeflag)
+ DECPOS(lim);
if (zlecs >= lim)
return 1;
while (n-- && zlecs < lim)
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 5845207fa..dc5fed4ce 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -198,7 +198,7 @@ set_buffer(UNUSED(Param pm), char *x)
setline(x, 0);
zsfree(x);
} else
- zlecs = zlell = 0;
+ viinsbegin = zlecs = zlell = 0;
fixsuffix();
menucmp = 0;
}
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 684ac13a2..fe337993f 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -396,8 +396,10 @@ get_region_highlight(UNUSED(Param pm))
struct region_highlight *rhp;
/* region_highlights may not have been set yet */
- if (arrsize)
- arrsize -= N_SPECIAL_HIGHLIGHTS;
+ if (!arrsize)
+ return hmkarray(NULL);
+ arrsize -= N_SPECIAL_HIGHLIGHTS;
+ DPUTS(arrsize < 0, "arrsize is negative from n_region_highlights");
arrp = retarr = (char **)zhalloc((arrsize+1)*sizeof(char *));
/* ignore special highlighting */
@@ -449,10 +451,15 @@ set_region_highlight(UNUSED(Param pm), char **aval)
len = aval ? arrlen(aval) : 0;
if (n_region_highlights != len + N_SPECIAL_HIGHLIGHTS) {
/* no null termination, but include special highlighting at start */
- n_region_highlights = len + N_SPECIAL_HIGHLIGHTS;
+ int newsize = len + N_SPECIAL_HIGHLIGHTS;
+ int diffsize = newsize - n_region_highlights;
region_highlights = (struct region_highlight *)
zrealloc(region_highlights,
- sizeof(struct region_highlight) * n_region_highlights);
+ sizeof(struct region_highlight) * newsize);
+ if (diffsize > 0)
+ memset(region_highlights + newsize - diffsize, 0,
+ sizeof(struct region_highlight) * diffsize);
+ n_region_highlights = newsize;
}
if (!aval)
@@ -1028,6 +1035,8 @@ zrefresh(void)
/* this will create region_highlights if it's still NULL */
zle_set_highlight();
+ DPUTS(!region_highlights, "region_highlights not created");
+
/* check for region between point ($CURSOR) and mark ($MARK) */
if (region_active) {
if (zlecs <= mark) {
@@ -1037,6 +1046,15 @@ zrefresh(void)
region_highlights[0].start = mark;
region_highlights[0].end = zlecs;
}
+ if (region_active == 2) {
+ int origcs = zlecs;
+ zlecs = region_highlights[0].end;
+ region_highlights[0].end = findeol();
+ zlecs = region_highlights[0].start;
+ region_highlights[0].start = findbol();
+ zlecs = origcs;
+ } else if (invicmdmode())
+ INCPOS(region_highlights[0].end);
} else {
region_highlights[0].start = region_highlights[0].end = -1;
}
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 499c4ae77..f18ad170e 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -634,7 +634,8 @@ docomplete(int lst)
metafy_line();
ocs = zlemetacs;
- origline = dupstring(zlemetaline);
+ zsfree(origline);
+ origline = ztrdup(zlemetaline);
origcs = zlemetacs;
origll = zlemetall;
if (!isfirstln && (chline != NULL || zle_chline != NULL)) {
@@ -662,8 +663,9 @@ docomplete(int lst)
* NOTE: get_comp_string() calls pushheap(), but not popheap(). */
noerrs = 1;
s = get_comp_string();
- DPUTS(wb < 0 || zlemetacs < wb || zlemetacs > we,
- "BUG: 0 <= wb <= zlemetacs <= we is not true!");
+ DPUTS3(wb < 0 || zlemetacs < wb || zlemetacs > we,
+ "BUG: 0 <= wb (%d) <= zlemetacs (%d) <= we (%d) is not true!",
+ wb, zlemetacs, we);
noerrs = ne;
/* For vi mode, reset the start-of-insertion pointer to the beginning *
* of the word being completed, if it is currently later. Vi itself *
@@ -696,7 +698,7 @@ docomplete(int lst)
freeheap();
/* Save the lexer state, in case the completion code uses the lexer *
* somewhere (e.g. when processing a compctl -s flag). */
- lexsave();
+ zcontext_save();
if (inwhat == IN_ENV)
lincmd = 0;
if (s) {
@@ -828,7 +830,7 @@ docomplete(int lst)
if (olst == COMP_EXPAND_COMPLETE &&
!strcmp(ol, zlemetaline)) {
zlemetacs = ocs;
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
if (!compfunc) {
char *p;
@@ -866,7 +868,7 @@ docomplete(int lst)
} else
ret = 1;
/* Reset the lexer state, pop the heap. */
- lexrestore();
+ zcontext_restore();
popheap();
dat[0] = lst;
@@ -876,6 +878,19 @@ docomplete(int lst)
active = 0;
makecommaspecial(0);
+
+ /*
+ * As a special case, we reset user interrupts here.
+ * That's because completion is an intensive piece of
+ * computation that the user might want to interrupt separately
+ * from anything else going on. If they do, they probably
+ * want to keep the line edit buffer intact.
+ *
+ * There's a race here that the user might hit ^C just
+ * after completion exited anyway, but that's inevitable.
+ */
+ errflag &= ~ERRFLAG_INT;
+
return dat[1];
}
@@ -1149,7 +1164,7 @@ get_comp_string(void)
varname = NULL;
insubscr = 0;
clwpos = -1;
- lexsave();
+ zcontext_save();
lexflags = LEXFLAGS_ZLE;
inpush(dupstrspace(linptr), 0, NULL);
strinbeg(0);
@@ -1393,7 +1408,8 @@ get_comp_string(void)
}
strinend();
inpop();
- errflag = lexflags = 0;
+ lexflags = 0;
+ errflag &= ~ERRFLAG_ERROR;
if (parbegin != -1) {
/* We are in command or process substitution if we are not in
* a $((...)). */
@@ -1406,7 +1422,7 @@ get_comp_string(void)
zlemetall -= parend;
zlemetaline[zlemetall + addedx] = '\0';
}
- lexrestore();
+ zcontext_restore();
tt = NULL;
goto start;
}
@@ -1480,12 +1496,12 @@ get_comp_string(void)
if (tmp) {
tmp = NULL;
linptr = zlemetaline;
- lexrestore();
+ zcontext_restore();
addedx = 0;
goto start;
}
noaliases = ona;
- lexrestore();
+ zcontext_restore();
return NULL;
}
@@ -1720,9 +1736,11 @@ get_comp_string(void)
for (pe = p + 2; *pe && *pe != Snull && i + (pe - p) < zlemetacs;
pe++)
;
- if (!*pe) {
+ if (*pe != Snull) {
/* no terminating Snull, can't substitute */
skipchars = 2;
+ if (*pe)
+ j = 1;
} else {
/*
* Try and substitute the $'...' expression.
@@ -1795,6 +1813,10 @@ get_comp_string(void)
* first clue how the completion system actually works.
*/
skipchars = 2;
+ /*
+ * Also pretend we're in single quotes.
+ */
+ j = 1;
}
}
}
@@ -1817,7 +1839,7 @@ get_comp_string(void)
ocs = zlemetacs;
zlemetacs = i;
foredel(skipchars, CUT_RAW);
- if ((zlemetacs = ocs) > (i -= skipchars))
+ if ((zlemetacs = ocs) > --i)
zlemetacs -= skipchars;
we -= skipchars;
}
@@ -2129,7 +2151,7 @@ get_comp_string(void)
offs = boffs;
}
}
- lexrestore();
+ zcontext_restore();
return (char *)s;
}
@@ -2769,7 +2791,7 @@ doexpandhist(void)
expanding = 1;
excs = zlemetacs;
zlemetall = zlemetacs = 0;
- lexsave();
+ zcontext_save();
/* We push ol as it will remain unchanged */
inpush(ol, 0, NULL);
strinbeg(1);
@@ -2781,7 +2803,7 @@ doexpandhist(void)
} while (tok != ENDINPUT && tok != LEXERR);
while (!lexstop)
hgetc();
- /* We have to save errflags because it's reset in lexrestore. Since *
+ /* We have to save errflags because it's reset in zcontext_restore. Since *
* noerrs was set to 1 errflag is true if there was a habort() which *
* means that the expanded string is unusable. */
err = errflag;
@@ -2789,7 +2811,7 @@ doexpandhist(void)
noaliases = ona;
strinend();
inpop();
- lexrestore();
+ zcontext_restore();
expanding = 0;
if (!err) {
@@ -2888,7 +2910,7 @@ getcurcmd(void)
int curlincmd;
char *s = NULL;
- lexsave();
+ zcontext_save();
lexflags = LEXFLAGS_ZLE;
metafy_line();
inpush(dupstrspace(zlemetaline), 0, NULL);
@@ -2910,9 +2932,9 @@ getcurcmd(void)
popheap();
strinend();
inpop();
- errflag = 0;
+ errflag &= ~ERRFLAG_ERROR;
unmetafy_line();
- lexrestore();
+ zcontext_restore();
return s;
}
diff --git a/Src/Zle/zle_utils.c b/Src/Zle/zle_utils.c
index 1089e274f..e4ab97a54 100644
--- a/Src/Zle/zle_utils.c
+++ b/Src/Zle/zle_utils.c
@@ -43,10 +43,10 @@ struct cutbuffer *kring;
int kringsize, kringnum;
/* Vi named cut buffers. 0-25 are the named buffers "a to "z, and *
- * 26-34 are the numbered buffer stack "1 to "9. */
+ * 26-35 are the numbered buffer stack "0 to "9. */
/**/
-struct cutbuffer vibuf[35];
+struct cutbuffer vibuf[36];
/* the line before last mod (for undo purposes) */
@@ -117,7 +117,7 @@ int
zlecharasstring(ZLE_CHAR_T inchar, char *buf)
{
#ifdef MULTIBYTE_SUPPORT
- size_t ret;
+ int ret;
char *ptr;
#ifdef __STDC_ISO_10646__
@@ -675,35 +675,42 @@ zle_restore_positions(void)
zlell = oldpos->ll;
}
- /* Count number of regions and see if the array needs resizing */
- for (nreg = 0, oldrhp = oldpos->regions;
- oldrhp;
- nreg++, oldrhp = oldrhp->next)
- ;
- if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) {
- n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS;
- region_highlights = (struct region_highlight *)
- zrealloc(region_highlights,
- sizeof(struct region_highlight) * n_region_highlights);
- }
- oldrhp = oldpos->regions;
- rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
- while (oldrhp) {
- struct zle_region *nextrhp = oldrhp->next;
-
- rhp->atr = oldrhp->atr;
- rhp->flags = oldrhp->flags;
- if (zlemetaline) {
- rhp->start_meta = oldrhp->start;
- rhp->end_meta = oldrhp->end;
- } else {
- rhp->start = oldrhp->start;
- rhp->end = oldrhp->end;
+ if (oldpos->regions) {
+ /* Count number of regions and see if the array needs resizing */
+ for (nreg = 0, oldrhp = oldpos->regions;
+ oldrhp;
+ nreg++, oldrhp = oldrhp->next)
+ ;
+ if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) {
+ n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS;
+ region_highlights = (struct region_highlight *)
+ zrealloc(region_highlights,
+ sizeof(struct region_highlight) * n_region_highlights);
}
+ oldrhp = oldpos->regions;
+ rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
+ while (oldrhp) {
+ struct zle_region *nextrhp = oldrhp->next;
- zfree(oldrhp, sizeof(*oldrhp));
- oldrhp = nextrhp;
- rhp++;
+ rhp->atr = oldrhp->atr;
+ rhp->flags = oldrhp->flags;
+ if (zlemetaline) {
+ rhp->start_meta = oldrhp->start;
+ rhp->end_meta = oldrhp->end;
+ } else {
+ rhp->start = oldrhp->start;
+ rhp->end = oldrhp->end;
+ }
+
+ zfree(oldrhp, sizeof(*oldrhp));
+ oldrhp = nextrhp;
+ rhp++;
+ }
+ } else if (region_highlights) {
+ zfree(region_highlights, sizeof(struct region_highlight) *
+ n_region_highlights);
+ region_highlights = NULL;
+ n_region_highlights = 0;
}
zfree(oldpos, sizeof(*oldpos));
@@ -785,6 +792,8 @@ spaceinline(int ct)
if (mark > zlecs)
mark += ct;
+ if (viinsbegin > zlecs)
+ viinsbegin = 0;
if (region_highlights) {
for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
@@ -914,7 +923,7 @@ cut(int i, int ct, int flags)
void
cuttext(ZLE_STRING_T line, int ct, int flags)
{
- if (!ct)
+ if (!(ct || vilinerange) || zmod.flags & MOD_NULL)
return;
UNMETACHECK();
@@ -941,17 +950,23 @@ cuttext(ZLE_STRING_T line, int ct, int flags)
ZS_memcpy(b->buf + len, line, ct);
b->len = len + ct;
}
- return;
- } else {
- /* Save in "1, shifting "1-"8 along to "2-"9 */
- int n;
- free(vibuf[34].buf);
- for(n=34; n>26; n--)
- vibuf[n] = vibuf[n-1];
+ } else if (flags & CUT_YANK) {
+ /* Save in "0 */
+ free(vibuf[26].buf);
vibuf[26].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
ZS_memcpy(vibuf[26].buf, line, ct);
vibuf[26].len = ct;
vibuf[26].flags = vilinerange ? CUTBUFFER_LINE : 0;
+ } else {
+ /* Save in "1, shifting "1-"8 along to "2-"9 */
+ int n;
+ free(vibuf[35].buf);
+ for(n=35; n>27; n--)
+ vibuf[n] = vibuf[n-1];
+ vibuf[27].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
+ ZS_memcpy(vibuf[27].buf, line, ct);
+ vibuf[27].len = ct;
+ vibuf[27].flags = vilinerange ? CUTBUFFER_LINE : 0;
}
if (!cutbuf.buf) {
cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE);
@@ -981,8 +996,9 @@ cuttext(ZLE_STRING_T line, int ct, int flags)
cutbuf.buf = s;
cutbuf.len += ct;
} else {
+ /* don't alloc 0 bytes; length 0 occurs for blank lines in vi mode */
cutbuf.buf = realloc((char *)cutbuf.buf,
- (cutbuf.len + ct) * ZLE_CHAR_SIZE);
+ (cutbuf.len + (ct ? ct : 1)) * ZLE_CHAR_SIZE);
ZS_memcpy(cutbuf.buf + cutbuf.len, line, ct);
cutbuf.len += ct;
}
@@ -1098,6 +1114,7 @@ setline(char *s, int flags)
*/
free(zleline);
+ viinsbegin = 0;
zleline = stringaszleline(scp, 0, &zlell, &linesz, NULL);
if ((flags & ZSL_TOEND) && (zlecs = zlell) && invicmdmode())
@@ -1356,7 +1373,6 @@ int
handlefeep(UNUSED(char **args))
{
zbeep();
- region_active = 0;
return 0;
}
@@ -1386,7 +1402,8 @@ static struct change *nextchanges, *endnextchanges;
/* incremented to provide a unique change number */
-static zlong undo_changeno;
+/**/
+zlong undo_changeno;
/* If non-zero, the last increment to undo_changeno was for the variable */
@@ -1659,8 +1676,7 @@ splitundo(char **args)
{
if (vistartchange >= 0) {
mergeundo();
- vistartchange = (curchange && curchange->prev) ?
- curchange->prev->changeno : 0;
+ vistartchange = undo_changeno;
}
handleundo();
return 0;
@@ -1706,7 +1722,8 @@ zlecallhook(char *name, char *arg)
execzlefunc(thingy, args, 1);
unrefthingy(thingy);
- errflag = saverrflag;
+ /* Retain any user interrupt error status */
+ errflag = saverrflag | (errflag & ERRFLAG_INT);
retflag = savretflag;
}
diff --git a/Src/Zle/zle_vi.c b/Src/Zle/zle_vi.c
index 9e39143d0..1a11ca7d5 100644
--- a/Src/Zle/zle_vi.c
+++ b/Src/Zle/zle_vi.c
@@ -75,7 +75,7 @@ static int inrepeat, vichgrepeat;
*/
/**/
-static void
+void
startvichange(int im)
{
if (im != -1) {
@@ -109,7 +109,7 @@ startvitext(int im)
{
startvichange(im);
selectkeymap("main", 1);
- vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0;
+ vistartchange = undo_changeno;
viinsbegin = zlecs;
}
@@ -161,75 +161,87 @@ vigetkey(void)
static int
getvirange(int wf)
{
- int pos = zlecs, ret = 0;
+ int pos = zlecs, mpos = mark, ret = 0;
+ int visual = region_active; /* movement command might set it */
int mult1 = zmult, hist1 = histline;
Thingy k2;
- virangeflag = 1;
- wordflag = wf;
- /* Now we need to execute the movement command, to see where it *
- * actually goes. virangeflag here indicates to the movement *
- * function that it should place the cursor at the end of the *
- * range, rather than where the cursor would actually go if it *
- * were executed normally. This makes a difference to some *
- * commands, but not all. For example, if searching forward *
- * for a character, under normal circumstances the cursor lands *
- * on the character. For a range, the range must include the *
- * character, so the cursor gets placed after the character if *
- * virangeflag is set. vi-match-bracket needs to change the *
- * value of virangeflag under some circumstances, meaning that *
- * we need to change the *starting* position. */
- zmod.flags &= ~MOD_TMULT;
- do {
- vilinerange = 0;
- prefixflag = 0;
- if (!(k2 = getkeycmd()) || (k2->flags & DISABLED) ||
- k2 == Th(z_sendbreak)) {
- wordflag = 0;
- virangeflag = 0;
+ if (visual) {
+ if (!zlell)
+ return -1;
+ pos = mark;
+ vilinerange = (visual == 2);
+ region_active = 0;
+ } else {
+ virangeflag = 1;
+ wordflag = wf;
+ mark = -1;
+ /* use operator-pending keymap if one exists */
+ Keymap km = openkeymap("viopp");
+ if (km)
+ selectlocalmap(km);
+ /* Now we need to execute the movement command, to see where it *
+ * actually goes. virangeflag here indicates to the movement *
+ * function that it should place the cursor at the end of the *
+ * range, rather than where the cursor would actually go if it *
+ * were executed normally. This makes a difference to some *
+ * commands, but not all. For example, if searching forward *
+ * for a character, under normal circumstances the cursor lands *
+ * on the character. For a range, the range must include the *
+ * character, so the cursor gets placed after the character if *
+ * virangeflag is set. */
+ zmod.flags &= ~MOD_TMULT;
+ do {
+ vilinerange = 0;
+ prefixflag = 0;
+ if (!(k2 = getkeycmd()) || (k2->flags & DISABLED) ||
+ k2 == Th(z_sendbreak)) {
+ wordflag = 0;
+ virangeflag = 0;
+ mark = mpos;
+ return -1;
+ }
+ /*
+ * With k2 == bindk, the command key is repeated:
+ * a number of lines is used. If the function used
+ * returns 1, we fail.
+ */
+ if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1))
+ ret = -1;
+ if(vichgrepeat)
+ zmult = mult1;
+ else
+ zmult = mult1 * zmod.tmult;
+ } while(prefixflag && !ret);
+ wordflag = 0;
+ selectlocalmap(NULL);
+
+ /* It is an error to use a non-movement command to delimit the *
+ * range. We here reject the case where the command modified *
+ * the line, or selected a different history line. */
+ if (histline != hist1 || zlell != lastll || memcmp(zleline, lastline, zlell)) {
+ histline = hist1;
+ ZS_memcpy(zleline, lastline, zlell = lastll);
+ zlecs = pos;
+ mark = mpos;
return -1;
}
- /*
- * With k2 == bindk, the command key is repeated:
- * a number of lines is used. If the function used
- * returns 1, we fail.
- */
- if ((k2 == bindk) ? dovilinerange() : execzlefunc(k2, zlenoargs, 1))
- ret = -1;
- if(vichgrepeat)
- zmult = mult1;
- else
- zmult = mult1 * zmod.tmult;
- } while(prefixflag && !ret);
- wordflag = 0;
- virangeflag = 0;
-
- /* It is an error to use a non-movement command to delimit the *
- * range. We here reject the case where the command modified *
- * the line, or selected a different history line. */
- if (histline != hist1 || zlell != lastll || memcmp(zleline, lastline, zlell)) {
- histline = hist1;
- ZS_memcpy(zleline, lastline, zlell = lastll);
- zlecs = pos;
- return -1;
- }
- /* Can't handle an empty file. Also, if the movement command *
- * failed, or didn't move, it is an error. */
- if (!zlell || (zlecs == pos && virangeflag != 2) || ret == -1)
- return -1;
+ /* Can't handle an empty file. Also, if the movement command *
+ * failed, or didn't move, it is an error. */
+ if (!zlell || (zlecs == pos && (mark == -1 || mark == zlecs) &&
+ virangeflag != 2) || ret == -1) {
+ mark = mpos;
+ return -1;
+ }
+ virangeflag = 0;
- /* vi-match-bracket changes the value of virangeflag when *
- * moving to the opening bracket, meaning that we need to *
- * change the *starting* position. */
- if(virangeflag == -1)
- {
- int origcs = zlecs;
- zlecs = pos;
- INCCS();
- pos = zlecs;
- zlecs = origcs;
+ /* if the mark has moved, ignore the original cursor position *
+ * and use the mark. */
+ if (mark != -1)
+ pos = mark;
}
+ mark = mpos;
/* Get the range the right way round. zlecs is placed at the *
* start of the range, and pos (the return value of this *
@@ -240,17 +252,31 @@ getvirange(int wf)
pos = tmp;
}
+ /* visual selection mode needs to include additional position */
+ if (visual == 1 && invicmdmode())
+ INCPOS(pos);
+
/* Was it a line-oriented move? If so, the command will have set *
* the vilinerange flag. In this case, entire lines are taken, *
* rather than just the sequence of characters delimited by pos *
- * and zlecs. The terminating newline is left out of the range, *
+ * and zlecs. The terminating newline is left out of the range, *
* which the real command must deal with appropriately. At this *
* point we just need to make the range encompass entire lines. */
- if(vilinerange) {
+ vilinerange = (zmod.flags & MOD_LINE) ||
+ (vilinerange && !(zmod.flags & MOD_CHAR));
+ if (vilinerange) {
int newcs = findbol();
+ lastcol = zlecs - newcs;
zlecs = pos;
pos = findeol();
zlecs = newcs;
+ } else if (!visual) {
+ /* for a character-wise move don't include a newline at the *
+ * end of the range */
+ int prev = pos;
+ DECPOS(prev);
+ if (zleline[prev] == ZWC('\n'))
+ pos = prev;
}
return pos;
}
@@ -348,6 +374,7 @@ videlete(UNUSED(char **args))
forekill(c2 - zlecs, CUT_RAW);
ret = 0;
if (vilinerange && zlell) {
+ lastcol = -1;
if (zlecs == zlell)
DECCS();
foredel(1, 0);
@@ -365,6 +392,7 @@ videletechar(char **args)
int n = zmult;
startvichange(-1);
+
/* handle negative argument */
if (n < 0) {
int ret;
@@ -401,7 +429,7 @@ vichange(UNUSED(char **args))
forekill(c2 - zlecs, CUT_RAW);
selectkeymap("main", 1);
viinsbegin = zlecs;
- vistartchange = (curchange && curchange->prev) ? curchange->prev->changeno : 0;
+ vistartchange = undo_changeno;
}
return ret;
}
@@ -418,12 +446,16 @@ visubstitute(UNUSED(char **args))
/* it is an error to be on the end of line */
if (zlecs == zlell || zleline[zlecs] == '\n')
return 1;
- /* Put argument into the acceptable range -- it is not an error to *
- * specify a greater count than the number of available characters. */
- if (n > findeol() - zlecs)
- n = findeol() - zlecs;
- /* do the substitution */
- forekill(n, CUT_RAW);
+ if (region_active) {
+ killregion(zlenoargs);
+ } else {
+ /* Put argument into the acceptable range -- it is not an error to *
+ * specify a greater count than the number of available characters. */
+ if (n > findeol() - zlecs)
+ n = findeol() - zlecs;
+ /* do the substitution */
+ forekill(n, CUT_RAW);
+ }
startvitext(1);
return 0;
}
@@ -432,7 +464,15 @@ visubstitute(UNUSED(char **args))
int
vichangeeol(UNUSED(char **args))
{
- forekill(findeol() - zlecs, CUT_RAW);
+ int a, b;
+ if (region_active) {
+ regionlines(&a, &b);
+ zlecs = a;
+ region_active = 0;
+ cut(zlecs, b - zlecs, CUT_RAW);
+ shiftchars(zlecs, b - zlecs);
+ } else
+ forekill(findeol() - zlecs, CUT_RAW);
startvitext(1);
return 0;
}
@@ -449,15 +489,30 @@ vichangewholeline(char **args)
int
viyank(UNUSED(char **args))
{
- int oldcs = zlecs, c2, ret = 1;
+ int c2, ret = 1;
startvichange(1);
if ((c2 = getvirange(0)) != -1) {
- cut(zlecs, c2 - zlecs, 0);
+ cut(zlecs, c2 - zlecs, CUT_YANK);
ret = 0;
}
vichgflag = 0;
- zlecs = oldcs;
+ /* cursor now at the start of the range yanked. For line mode
+ * restore the column position */
+ if (vilinerange && lastcol != -1) {
+ int x = findeol();
+
+ if ((zlecs += lastcol) >= x) {
+ zlecs = x;
+ if (zlecs > findbol() && invicmdmode())
+ DECCS();
+ }
+#ifdef MULTIBYTE_SUPPORT
+ else
+ CCRIGHT();
+#endif
+ lastcol = -1;
+ }
return ret;
}
@@ -470,7 +525,7 @@ viyankeol(UNUSED(char **args))
startvichange(-1);
if (x == zlecs)
return 1;
- cut(zlecs, x - zlecs, 0);
+ cut(zlecs, x - zlecs, CUT_YANK);
return 0;
}
@@ -492,7 +547,7 @@ viyankwholeline(UNUSED(char **args))
zlecs = findeol() + 1;
}
vilinerange = 1;
- cut(bol, zlecs - bol - 1, 0);
+ cut(bol, zlecs - bol - 1, CUT_YANK);
zlecs = oldcs;
return 0;
}
@@ -526,16 +581,40 @@ vireplacechars(UNUSED(char **args))
int n = zmult, fail = 0, newchars = 0;
if (n > 0) {
- int pos = zlecs;
- while (n-- > 0) {
- if (pos == zlell || zleline[pos] == ZWC('\n')) {
- fail = 1;
- break;
+ if (region_active) {
+ int a, b;
+ if (region_active == 1) {
+ if (mark > zlecs) {
+ a = zlecs;
+ b = mark;
+ } else {
+ a = mark;
+ b = zlecs;
+ }
+ INCPOS(b);
+ } else
+ regionlines(&a, &b);
+ zlecs = a;
+ if (b > zlell)
+ b = zlell;
+ n = b - a;
+ while (a < b) {
+ newchars++;
+ INCPOS(a);
+ }
+ region_active = 0;
+ } else {
+ int pos = zlecs;
+ while (n-- > 0) {
+ if (pos == zlell || zleline[pos] == ZWC('\n')) {
+ fail = 1;
+ break;
+ }
+ newchars++;
+ INCPOS(pos);
}
- newchars++;
- INCPOS(pos);
+ n = pos - zlecs;
}
- n = pos - zlecs;
}
startvichange(1);
/* check argument range */
@@ -567,6 +646,8 @@ vireplacechars(UNUSED(char **args))
* buffer offset.
* Use shiftchars so as not to adjust the cursor position;
* we are overwriting anything that remains directly.
+ * With a selection this will replace newlines which vim
+ * doesn't do but this simplifies things a lot.
*/
if (n > newchars)
shiftchars(zlecs, n - newchars);
@@ -675,8 +756,11 @@ viindent(UNUSED(char **args))
{
int oldcs = zlecs, c2;
- /* get the range */
startvichange(1);
+ /* force line range */
+ if (region_active == 1)
+ region_active = 2;
+ /* get the range */
if ((c2 = getvirange(0)) == -1) {
vichgflag = 0;
return 1;
@@ -689,10 +773,14 @@ viindent(UNUSED(char **args))
}
oldcs = zlecs;
/* add a tab to the beginning of each line within range */
- while (zlecs < c2) {
- spaceinline(1);
- zleline[zlecs] = '\t';
- zlecs = findeol() + 1;
+ while (zlecs <= c2 + 1) {
+ if (zleline[zlecs] == '\n') { /* leave blank lines alone */
+ ++zlecs;
+ } else {
+ spaceinline(1);
+ zleline[zlecs] = '\t';
+ zlecs = findeol() + 1;
+ }
}
/* go back to the first line of the range */
zlecs = oldcs;
@@ -706,8 +794,11 @@ viunindent(UNUSED(char **args))
{
int oldcs = zlecs, c2;
- /* get the range */
startvichange(1);
+ /* force line range */
+ if (region_active == 1)
+ region_active = 2;
+ /* get the range */
if ((c2 = getvirange(0)) == -1) {
vichgflag = 0;
return 1;
@@ -739,6 +830,7 @@ vibackwarddeletechar(char **args)
if (invicmdmode())
startvichange(-1);
+
/* handle negative argument */
if (n < 0) {
int ret;
@@ -776,95 +868,44 @@ vikillline(UNUSED(char **args))
/**/
int
-viputbefore(UNUSED(char **args))
+vijoin(UNUSED(char **args))
{
- Cutbuffer buf = &cutbuf;
+ int x, pos;
int n = zmult;
+ int visual = region_active;
startvichange(-1);
- if (n < 0)
- return 1;
- if (zmod.flags & MOD_VIBUF)
- buf = &vibuf[zmod.vibuf];
- if (!buf->buf)
+ if (n < 1)
return 1;
- if(buf->flags & CUTBUFFER_LINE) {
- zlecs = findbol();
- spaceinline(buf->len + 1);
- ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
- zleline[zlecs + buf->len] = ZWC('\n');
- vifirstnonblank(zlenoargs);
- } else {
- while (n--) {
- spaceinline(buf->len);
- ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
- zlecs += buf->len;
+ if (visual && zlecs > mark) {
+ exchangepointandmark(zlenoargs);
+ x = findeol();
+ if (x >= mark) {
+ exchangepointandmark(zlenoargs);
+ return 1;
}
- if (zlecs)
- DECCS();
- }
- return 0;
-}
-
-/**/
-int
-viputafter(UNUSED(char **args))
-{
- Cutbuffer buf = &cutbuf;
- int n = zmult;
-
- startvichange(-1);
- if (n < 0)
- return 1;
- if (zmod.flags & MOD_VIBUF)
- buf = &vibuf[zmod.vibuf];
- if (!buf->buf)
+ } else if ((x = findeol()) == zlell || (visual && x >= mark))
return 1;
- if(buf->flags & CUTBUFFER_LINE) {
- zlecs = findeol();
- spaceinline(buf->len + 1);
- zleline[zlecs++] = ZWC('\n');
- ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
- vifirstnonblank(zlenoargs);
- } else {
- if (zlecs != findeol())
- INCCS();
- while (n--) {
- spaceinline(buf->len);
- ZS_memcpy(zleline + zlecs, buf->buf, buf->len);
- zlecs += buf->len;
- }
- if (zlecs)
- DECCS();
- }
- return 0;
-}
-
-/**/
-int
-vijoin(UNUSED(char **args))
-{
- int x, pos;
- startvichange(-1);
- if ((x = findeol()) == zlell)
- return 1;
- zlecs = x + 1;
- pos = zlecs;
- for (; zlecs != zlell && ZC_iblank(zleline[zlecs]); INCPOS(zlecs))
- ;
- x = 1 + (zlecs - pos);
- backdel(x, CUT_RAW);
- if (zlecs) {
- int pos = zlecs;
- DECPOS(pos);
- if (ZC_iblank(zleline[pos])) {
- zlecs = pos;
- return 0;
+ do {
+ zlecs = x + 1;
+ pos = zlecs;
+ for (; zlecs != zlell && ZC_iblank(zleline[zlecs]); INCPOS(zlecs))
+ ;
+ x = 1 + (zlecs - pos);
+ backdel(x, CUT_RAW);
+ if (zlecs) {
+ int pos = zlecs;
+ DECPOS(pos);
+ if (ZC_iblank(zleline[pos])) {
+ zlecs = pos;
+ continue;
+ }
}
- }
- spaceinline(1);
- zleline[zlecs] = ZWC(' ');
+ spaceinline(1);
+ zleline[zlecs] = ZWC(' ');
+ } while (!((!visual && --n < 2) || (x = findeol()) == zlell || (visual && x >= mark)));
+
return 0;
}
@@ -878,6 +919,8 @@ viswapcase(UNUSED(char **args))
if (n < 1)
return 1;
eol = findeol();
+ if (zlecs == eol)
+ return 1;
while (zlecs < eol && n--) {
if (ZC_ilower(zleline[zlecs]))
zleline[zlecs] = ZC_toupper(zleline[zlecs]);
@@ -905,14 +948,26 @@ vicapslockpanic(UNUSED(char **args))
/**/
int
-visetbuffer(UNUSED(char **args))
+visetbuffer(char **args)
{
ZLE_INT_T ch;
- if ((zmod.flags & MOD_VIBUF) ||
- (((ch = getfullchar(0)) < ZWC('1') || ch > ZWC('9')) &&
+ if (*args) {
+ ch = **args;
+ if (args[1] || (ch && (*args)[1]))
+ return 1;
+ } else {
+ ch = getfullchar(0);
+ }
+ if (ch == ZWC('_')) {
+ zmod.flags |= MOD_NULL;
+ prefixflag = 1;
+ return 0;
+ } else
+ zmod.flags &= ~MOD_NULL;
+ if ((ch < ZWC('0') || ch > ZWC('9')) &&
(ch < ZWC('a') || ch > ZWC('z')) &&
- (ch < ZWC('A') || ch > ZWC('Z'))))
+ (ch < ZWC('A') || ch > ZWC('Z')))
return 1;
if (ch >= ZWC('A') && ch <= ZWC('Z')) /* needed in cut() */
zmod.flags |= MOD_VIAPP;
@@ -920,8 +975,8 @@ visetbuffer(UNUSED(char **args))
zmod.flags &= ~MOD_VIAPP;
/* FIXME how portable is it for multibyte encoding? */
zmod.vibuf = ZC_tolower(ch);
- if (ch >= ZWC('1') && ch <= ZWC('9'))
- zmod.vibuf += - (int)ZWC('1') + 26;
+ if (ch >= ZWC('0') && ch <= ZWC('9'))
+ zmod.vibuf += - (int)ZWC('0') + 26;
else
zmod.vibuf += - (int)ZWC('a');
zmod.flags |= MOD_VIBUF;
diff --git a/Src/Zle/zle_word.c b/Src/Zle/zle_word.c
index e59304ecd..2e6d75e86 100644
--- a/Src/Zle/zle_word.c
+++ b/Src/Zle/zle_word.c
@@ -80,16 +80,21 @@ viforwardword(char **args)
return ret;
}
while (n--) {
+ int nl;
if (Z_vialnum(zleline[zlecs]))
while (zlecs != zlell && Z_vialnum(zleline[zlecs]))
INCCS();
else
- while (zlecs != zlell && !Z_vialnum(zleline[zlecs]) && !ZC_iblank(zleline[zlecs]))
+ while (zlecs != zlell && !Z_vialnum(zleline[zlecs]) &&
+ !ZC_inblank(zleline[zlecs]))
INCCS();
if (wordflag && !n)
return 0;
- while (zlecs != zlell && ZC_inblank(zleline[zlecs]))
+ nl = (zleline[zlecs] == ZWC('\n'));
+ while (zlecs != zlell && nl < 2 && ZC_inblank(zleline[zlecs])) {
INCCS();
+ nl += (zleline[zlecs] == ZWC('\n'));
+ }
}
return 0;
}
@@ -108,12 +113,16 @@ viforwardblankword(char **args)
return ret;
}
while (n--) {
- while (zlecs != zlell && !ZC_iblank(zleline[zlecs]))
+ int nl;
+ while (zlecs != zlell && !ZC_inblank(zleline[zlecs]))
INCCS();
if (wordflag && !n)
return 0;
- while (zlecs != zlell && ZC_iblank(zleline[zlecs]))
+ nl = (zleline[zlecs] == ZWC('\n'));
+ while (zlecs != zlell && nl < 2 && ZC_inblank(zleline[zlecs])) {
INCCS();
+ nl += (zleline[zlecs] == ZWC('\n'));
+ }
}
return 0;
}
@@ -148,20 +157,25 @@ viforwardblankwordend(UNUSED(char **args))
{
int n = zmult;
- if (n < 0)
- return 1;
+ if (n < 0) {
+ int ret;
+ zmult = -n;
+ ret = viforwardblankwordend(args);
+ zmult = n;
+ return ret;
+ }
while (n--) {
while (zlecs != zlell) {
int pos = zlecs;
INCPOS(pos);
- if (!ZC_iblank(zleline[pos]))
+ if (!ZC_inblank(zleline[pos]))
break;
zlecs = pos;
}
while (zlecs != zlell) {
int pos = zlecs;
INCPOS(pos);
- if (ZC_iblank(zleline[pos]))
+ if (ZC_inblank(zleline[pos]))
break;
zlecs = pos;
}
@@ -180,7 +194,7 @@ viforwardwordend(char **args)
if (n < 0) {
int ret;
zmult = -n;
- ret = backwardword(args);
+ ret = vibackwardwordend(args);
zmult = n;
return ret;
}
@@ -211,7 +225,7 @@ viforwardwordend(char **args)
if (zlecs == zlell)
break;
INCPOS(pos);
- if (Z_vialnum(zleline[pos]) || ZC_iblank(zleline[pos]))
+ if (Z_vialnum(zleline[pos]) || ZC_inblank(zleline[pos]))
break;
}
}
@@ -268,16 +282,19 @@ vibackwardword(char **args)
return ret;
}
while (n--) {
+ int nl = 0;
while (zlecs) {
- int pos = zlecs;
- DECPOS(pos);
- if (!ZC_iblank(zleline[pos]))
+ DECCS();
+ if (!ZC_inblank(zleline[zlecs]))
break;
- zlecs = pos;
+ nl += (zleline[zlecs] == ZWC('\n'));
+ if (nl == 2) {
+ INCCS();
+ break;
+ }
}
if (zlecs) {
int pos = zlecs;
- DECPOS(pos);
if (Z_vialnum(zleline[pos])) {
for (;;) {
zlecs = pos;
@@ -293,7 +310,7 @@ vibackwardword(char **args)
if (zlecs == 0)
break;
DECPOS(pos);
- if (Z_vialnum(zleline[pos]) || ZC_iblank(zleline[pos]))
+ if (Z_vialnum(zleline[pos]) || ZC_inblank(zleline[pos]))
break;
}
}
@@ -316,17 +333,20 @@ vibackwardblankword(char **args)
return ret;
}
while (n--) {
+ int nl = 0;
while (zlecs) {
int pos = zlecs;
DECPOS(pos);
- if (!ZC_iblank(zleline[pos]))
+ if (!ZC_inblank(zleline[pos]))
break;
+ nl += (zleline[pos] == ZWC('\n'));
+ if (nl == 2) break;
zlecs = pos;
}
while (zlecs) {
int pos = zlecs;
DECPOS(pos);
- if (ZC_iblank(zleline[pos]))
+ if (ZC_inblank(zleline[pos]))
break;
zlecs = pos;
}
@@ -336,6 +356,62 @@ vibackwardblankword(char **args)
/**/
int
+vibackwardwordend(char **args)
+{
+ int n = zmult;
+
+ if (n < 0) {
+ int ret;
+ zmult = -n;
+ ret = viforwardwordend(args);
+ zmult = n;
+ return ret;
+ }
+ while (n-- && zlecs > 1) {
+ int start = 0;
+ if (Z_vialnum(zleline[zlecs]))
+ start = 1;
+ else if (!ZC_inblank(zleline[zlecs]))
+ start = 2;
+ DECCS();
+ while (zlecs) {
+ int same = (start != 1) && ZC_iblank(zleline[zlecs]);
+ if (start)
+ same |= Z_vialnum(zleline[zlecs]);
+ if (same == (start == 2))
+ break;
+ DECCS();
+ }
+ while (zlecs && ZC_iblank(zleline[zlecs]))
+ DECCS();
+ }
+ return 0;
+}
+
+/**/
+int
+vibackwardblankwordend(char **args)
+{
+ int n = zmult;
+
+ if (n < 0) {
+ int ret;
+ zmult = -n;
+ ret = viforwardblankwordend(args);
+ zmult = n;
+ return ret;
+ }
+ while (n--) {
+ while (zlecs && !ZC_inblank(zleline[zlecs]))
+ DECCS();
+ while (zlecs && ZC_inblank(zleline[zlecs]))
+ DECCS();
+ }
+ return 0;
+}
+
+/**/
+int
emacsbackwardword(char **args)
{
int n = zmult;
@@ -629,7 +705,6 @@ transposewords(UNUSED(char **args))
DECPOS(pos);
if (zleline[pos] == ZWC('\n'))
return 1;
- x = pos;
}
for (p4 = x; p4 != zlell && ZC_iword(zleline[p4]); INCPOS(p4))
;