summaryrefslogtreecommitdiff
path: root/Src/Zle/textobjects.c
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/textobjects.c
parent01eea47617a6e06debdb4330f92ae69f92089fd2 (diff)
parent3c3c8d3d13fd4cf6c03f81ca8dc18a1efd561728 (diff)
downloadzsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.tar.gz
zsh-db38e167634b6c2217eec3a5aafc37c46d9e5a8d.zip
Merge branch 'upstream' into debian
Diffstat (limited to 'Src/Zle/textobjects.c')
-rw-r--r--Src/Zle/textobjects.c322
1 files changed, 322 insertions, 0 deletions
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;
+}