about summary refs log tree commit diff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/zle_thingy.c251
1 files changed, 216 insertions, 35 deletions
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index c4f2e25e1..7e81e2f88 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -49,7 +49,7 @@
 /* Hashtable of thingies.  Enabled nodes are those that refer to widgets. */
 
 /**/
-HashTable thingytab;
+mod_export HashTable thingytab;
 
 /**********************************/
 /* hashtable management functions */
@@ -64,6 +64,7 @@ createthingytab(void)
     thingytab->hash        = hasher;
     thingytab->emptytable  = emptythingytab;
     thingytab->filltable   = NULL;
+    thingytab->cmpnodes    = strcmp;
     thingytab->addnode     = addhashnode;
     thingytab->getnode     = gethashnode;
     thingytab->getnode2    = gethashnode2;
@@ -133,7 +134,7 @@ freethingynode(HashNode hn)
  * correctly.                                                          */
 
 /**/
-Thingy
+mod_export Thingy
 refthingy(Thingy th)
 {
     if(th)
@@ -244,7 +245,10 @@ unbindwidget(Thingy t, int override)
 static void
 freewidget(Widget w)
 {
-    if(!(w->flags & WIDGET_INT))
+    if (w->flags & WIDGET_NCOMP) {
+	zsfree(w->u.comp.wid);
+	zsfree(w->u.comp.func);
+    } else if(!(w->flags & WIDGET_INT))
 	zsfree(w->u.fnnam);
     zfree(w, sizeof(*w));
 }
@@ -257,7 +261,7 @@ freewidget(Widget w)
  * returned.                                                            */
 
 /**/
-Widget
+mod_export Widget
 addzlefunction(char *name, ZleIntFunc ifunc, int flags)
 {
     VARARR(char, dotn, strlen(name) + 2);
@@ -282,13 +286,11 @@ addzlefunction(char *name, ZleIntFunc ifunc, int flags)
     return w;
 }
 
-#ifdef DYNAMIC
-
 /* Delete an internal widget provided by a module.  Don't try to delete *
  * a widget from the fixed table -- it would be bad.  (Thanks, Egon.)   */
 
 /**/
-void
+mod_export void
 deletezlefunction(Widget w)
 {
     Thingy p, n;
@@ -305,8 +307,6 @@ deletezlefunction(Widget w)
     }
 }
 
-#endif /* DYNAMIC */
-
 /***************/
 /* zle builtin */
 /***************/
@@ -314,9 +314,10 @@ deletezlefunction(Widget w)
 /*
  * The available operations are:
  *
- *   -l   list user-defined widgets (no arguments)
+ *   -l   list widgets/test for existence
  *   -D   delete widget names
  *   -A   link the two named widgets (2 arguments)
+ *   -C   create completion widget (3 arguments)
  *   -N   create new user-defined widget (1 or 2 arguments)
  *        invoke a widget (1 argument)
  */
@@ -330,36 +331,36 @@ bin_zle(char *name, char **args, char *ops, int func)
 	int (*func) _((char *, char **, char *, char));
 	int min, max;
     } const opns[] = {
-	{ 'l', bin_zle_list, 0,  0 },
+	{ 'l', bin_zle_list, 0, -1 },
 	{ 'D', bin_zle_del,  1, -1 },
 	{ 'A', bin_zle_link, 2,  2 },
 	{ 'N', bin_zle_new,  1,  2 },
+	{ 'C', bin_zle_complete, 3, 3 },
+	{ 'R', bin_zle_refresh, 0, -1 },
+	{ 'M', bin_zle_mesg, 1, 1 },
+	{ 'U', bin_zle_unget, 1, 1 },
 	{ 0,   bin_zle_call, 0, -1 },
     };
     struct opn const *op, *opp;
     int n;
 
     /* select operation and ensure no clashing arguments */
-    for(op = opns; op->o && !ops[op->o]; op++) ;
+    for(op = opns; op->o && !ops[STOUC(op->o)]; op++) ;
     if(op->o)
 	for(opp = op; (++opp)->o; )
-	    if(ops[opp->o]) {
-		zerrnam(name, "incompatible operation selection options",
+	    if(ops[STOUC(opp->o)]) {
+		zwarnnam(name, "incompatible operation selection options",
 		    NULL, 0);
 		return 1;
 	    }
 
     /* check number of arguments */
     for(n = 0; args[n]; n++) ;
-    if(!op->o && n != 1) {
-	zerrnam(name, "wrong number of arguments", NULL, 0);
-	return 1;
-    }
     if(n < op->min) {
-	zerrnam(name, "not enough arguments for -%c", NULL, op->o);
+	zwarnnam(name, "not enough arguments for -%c", NULL, op->o);
 	return 1;
     } else if(op->max != -1 && n > op->max) {
-	zerrnam(name, "too many arguments for -%c", NULL, op->o);
+	zwarnnam(name, "too many arguments for -%c", NULL, op->o);
 	return 1;
     }
 
@@ -371,7 +372,96 @@ bin_zle(char *name, char **args, char *ops, int func)
 static int
 bin_zle_list(char *name, char **args, char *ops, char func)
 {
-    scanhashtable(thingytab, 1, 0, DISABLED, scanlistwidgets, ops['L']);
+    if (!*args) {
+	scanhashtable(thingytab, 1, 0, DISABLED, scanlistwidgets,
+		      (ops['a'] ? -1 : ops['L']));
+	return 0;
+    } else {
+	int ret = 0;
+	Thingy t;
+
+	for (; *args && !ret; args++) {
+	    if (!(t = (Thingy) thingytab->getnode2(thingytab, *args)) ||
+		(!ops['a'] && (t->widget->flags & WIDGET_INT)))
+		ret = 1;
+	}
+	return ret;
+    }
+}
+
+/**/
+static int
+bin_zle_refresh(char *name, char **args, char *ops, char func)
+{
+    char *s = statusline;
+    int sl = statusll, ocl = clearlist;
+
+    if (!zleactive) {
+	zwarnnam(name, "can only be called from widget function", NULL, 0);
+	return 1;
+    }
+    statusline = NULL;
+    statusll = 0;
+    if (*args) {
+	if (**args) {
+	    statusline = *args;
+	    statusll = strlen(statusline);
+	}
+	if (*++args) {
+	    LinkList l = newlinklist();
+	    int zmultsav = zmult;
+
+	    for (; *args; args++)
+		addlinknode(l, *args);
+
+	    zmult = 1;
+	    listlist(l);
+	    if (statusline)
+		lastlistlen++;
+	    showinglist = clearlist = 0;
+	    zmult = zmultsav;
+	} else if (ops['c']) {
+	    clearlist = 1;
+	    lastlistlen = 0;
+	}
+    } else if (ops['c']) {
+	clearlist = listshown = 1;
+	lastlistlen = 0;
+    }
+    zrefresh();
+
+    clearlist = ocl;
+    statusline = s;
+    statusll = sl;
+    return 0;
+}
+
+/**/
+static int
+bin_zle_mesg(char *name, char **args, char *ops, char func)
+{
+    if (!zleactive) {
+	zwarnnam(name, "can only be called from widget function", NULL, 0);
+	return 1;
+    }
+    showmsg(*args);
+    if (sfcontext != SFC_WIDGET)
+	zrefresh();
+    return 0;
+}
+
+/**/
+static int
+bin_zle_unget(char *name, char **args, char *ops, char func)
+{
+    char *b = *args, *p = b + strlen(b);
+
+    if (!zleactive) {
+	zwarnnam(name, "can only be called from widget function", NULL, 0);
+	return 1;
+    }
+    while (p > b)
+	ungetkey((int) *--p);
     return 0;
 }
 
@@ -382,20 +472,34 @@ scanlistwidgets(HashNode hn, int list)
     Thingy t = (Thingy) hn;
     Widget w = t->widget;
 
+    if(list < 0) {
+	printf("%s\n", hn->nam);
+	return;
+    }
     if(w->flags & WIDGET_INT)
 	return;
     if(list) {
-	fputs("zle -N ", stdout);
+	printf("zle -%c ", (w->flags & WIDGET_NCOMP) ? 'C' : 'N');
 	if(t->nam[0] == '-')
 	    fputs("-- ", stdout);
 	quotedzputs(t->nam, stdout);
-	if(strcmp(t->nam, w->u.fnnam)) {
+	if (w->flags & WIDGET_NCOMP) {
+	    fputc(' ', stdout);
+	    quotedzputs(w->u.comp.wid, stdout);
+	    fputc(' ', stdout);
+	    quotedzputs(w->u.comp.func, stdout);
+	} else if(strcmp(t->nam, w->u.fnnam)) {
 	    fputc(' ', stdout);
 	    quotedzputs(w->u.fnnam, stdout);
 	}
     } else {
 	nicezputs(t->nam, stdout);
-	if(strcmp(t->nam, w->u.fnnam)) {
+	if (w->flags & WIDGET_NCOMP) {
+	    fputs(" -C ", stdout);
+	    nicezputs(w->u.comp.wid, stdout);
+	    fputc(' ', stdout);
+	    nicezputs(w->u.comp.func, stdout);
+	} else if(strcmp(t->nam, w->u.fnnam)) {
 	    fputs(" (", stdout);
 	    nicezputs(w->u.fnnam, stdout);
 	    fputc(')', stdout);
@@ -430,10 +534,10 @@ bin_zle_link(char *name, char **args, char *ops, char func)
     Thingy t = (Thingy) thingytab->getnode(thingytab, args[0]);
 
     if(!t) {
-	zerrnam(name, "no such widget `%s'", args[0], 0);
+	zwarnnam(name, "no such widget `%s'", args[0], 0);
 	return 1;
     } else if(bindwidget(t->widget, rthingy(args[1]))) {
-	zerrnam(name, "widget name `%s' is protected", args[1], 0);
+	zwarnnam(name, "widget name `%s' is protected", args[1], 0);
 	return 1;
     }
     return 0;
@@ -452,29 +556,106 @@ bin_zle_new(char *name, char **args, char *ops, char func)
     if(!bindwidget(w, rthingy(args[0])))
 	return 0;
     freewidget(w);
-    zerrnam(name, "widget name `%s' is protected", args[0], 0);
+    zwarnnam(name, "widget name `%s' is protected", args[0], 0);
     return 1;
 }
 
 /**/
 static int
-bin_zle_call(char *name, char **args, char *ops, char func)
+bin_zle_complete(char *name, char **args, char *ops, char func)
 {
     Thingy t;
+    Widget w, cw;
 
-    if(!zleactive || incompctlfunc) {
-	zerrnam(name, "widgets can only be called when ZLE is active",
-	    NULL, 0);
+    if (!require_module(name, "zsh/complete", 0, 0)) {
+	zwarnnam(name, "can't load complete module", NULL, 0);
 	return 1;
     }
-    t = rthingy(args[0]);
-    PERMALLOC {
-      execzlefunc(t);
-    } LASTALLOC;
+    t = rthingy((args[1][0] == '.') ? args[1] : dyncat(".", args[1]));
+    cw = t->widget;
     unrefthingy(t);
+    if (!cw || !(cw->flags & ZLE_ISCOMP)) {
+	zwarnnam(name, "invalid widget `%s'", args[1], 0);
+	return 1;
+    }
+    w = zalloc(sizeof(*w));
+    w->flags = WIDGET_NCOMP|ZLE_MENUCMP|ZLE_KEEPSUFFIX;
+    w->first = NULL;
+    w->u.comp.fn = cw->u.fn;
+    w->u.comp.wid = ztrdup(args[1]);
+    w->u.comp.func = ztrdup(args[2]);
+    if (bindwidget(w, rthingy(args[0]))) {
+	freewidget(w);
+	zwarnnam(name, "widget name `%s' is protected", args[0], 0);
+	return 1;
+    }
     return 0;
 }
 
+/**/
+static int
+bin_zle_call(char *name, char **args, char *ops, char func)
+{
+    Thingy t;
+    struct modifier modsave;
+    int ret, saveflag = 0;
+    char *wname = *args++;
+
+    if (!wname) {
+	if (saveflag)
+	    zmod = modsave;
+	return (!zleactive || incompctlfunc || incompfunc ||
+		sfcontext != SFC_WIDGET);
+    }
+    if(!zleactive || incompctlfunc || incompfunc || sfcontext != SFC_WIDGET) {
+	zwarnnam(name, "widgets can only be called when ZLE is active",
+	    NULL, 0);
+	return 1;
+    }
+
+    while (*args && **args == '-') {
+	char *num;
+	if (!args[0][1] || args[0][1] == '-') {
+	    args++;
+	    break;
+	}
+	while (*++(*args)) {
+	    switch (**args) {
+	    case 'n':
+		num = args[0][1] ? args[0]+1 : args[1];
+		if (!num) {
+		    zwarnnam(name, "number expected after -%c", NULL, **args);
+		    return 1;
+		}
+		if (!args[0][1])
+		    *++args = "" - 1;
+		modsave = zmod;
+		saveflag = 1;
+		zmod.mult = atoi(num);
+		zmod.flags |= MOD_MULT;
+		break;
+	    case 'N':
+		modsave = zmod;
+		saveflag = 1;
+		zmod.mult = 1;
+		zmod.flags &= ~MOD_MULT;
+		break;
+	    default:
+		zwarnnam(name, "unknown option: %s", *args, 0);
+		return 1;
+	    }
+	}
+	args++;
+    }
+
+    t = rthingy(wname);
+    ret = execzlefunc(t, args);
+    unrefthingy(t);
+    if (saveflag)
+	zmod = modsave;
+    return ret;
+}
+
 /*******************/
 /* initialiasation */
 /*******************/