diff options
author | Axel Beckert <abe@deuxchevaux.org> | 2015-05-05 23:32:59 +0200 |
---|---|---|
committer | Axel Beckert <abe@deuxchevaux.org> | 2015-05-05 23:58:59 +0200 |
commit | db38e167634b6c2217eec3a5aafc37c46d9e5a8d (patch) | |
tree | daa342d423febbd3a5a7ef97053037677fab004a /Src/Zle | |
parent | 01eea47617a6e06debdb4330f92ae69f92089fd2 (diff) | |
parent | 3c3c8d3d13fd4cf6c03f81ca8dc18a1efd561728 (diff) | |
download | zsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.tar.gz zsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.zip |
Merge branch 'upstream' into debian
Diffstat (limited to 'Src/Zle')
-rw-r--r-- | Src/Zle/compcore.c | 8 | ||||
-rw-r--r-- | Src/Zle/compctl.c | 26 | ||||
-rw-r--r-- | Src/Zle/complist.c | 28 | ||||
-rw-r--r-- | Src/Zle/compmatch.c | 3 | ||||
-rw-r--r-- | Src/Zle/compresult.c | 7 | ||||
-rw-r--r-- | Src/Zle/computil.c | 3 | ||||
-rw-r--r-- | Src/Zle/iwidgets.list | 55 | ||||
-rw-r--r-- | Src/Zle/textobjects.c | 322 | ||||
-rw-r--r-- | Src/Zle/zle.h | 21 | ||||
-rw-r--r-- | Src/Zle/zle.mdd | 3 | ||||
-rw-r--r-- | Src/Zle/zle_bindings.c | 10 | ||||
-rw-r--r-- | Src/Zle/zle_hist.c | 28 | ||||
-rw-r--r-- | Src/Zle/zle_keymap.c | 59 | ||||
-rw-r--r-- | Src/Zle/zle_main.c | 72 | ||||
-rw-r--r-- | Src/Zle/zle_misc.c | 238 | ||||
-rw-r--r-- | Src/Zle/zle_move.c | 61 | ||||
-rw-r--r-- | Src/Zle/zle_params.c | 2 | ||||
-rw-r--r-- | Src/Zle/zle_refresh.c | 26 | ||||
-rw-r--r-- | Src/Zle/zle_tricky.c | 62 | ||||
-rw-r--r-- | Src/Zle/zle_utils.c | 105 | ||||
-rw-r--r-- | Src/Zle/zle_vi.c | 411 | ||||
-rw-r--r-- | Src/Zle/zle_word.c | 113 |
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)) ; |