Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Handling for ZLE modules



Zefram wrote:
> >The other question is how to handle unloading.  One has to be careful
> >when bindings remain which point to the function; also, the functions
> >are in a linear array like the builtin functions and you may not be
> >deleting at the end.  I have arranged it so that the function is
> >marked as deleted with name "<deleted>" (which should only be used for
> >output), but the table entry is kept.
> 
> I don't like this.  Do we retain the binding or not?  If not, we have
> to go through every key binding, changing them to undefined-key.  The
> alternative would be to maintain link counts for loaded bindings, to
> avoid reusing a slot that is bound to some key.

O.K., the only rational way of doing this is to seek and destroy any
binding to a function which is deleted.  Having written this, it
seemed stupid not to make it directly available to the user as well,
so I added the bindkey -u option which undefines any binding to the
given command, which could be a builtin just as easily as one loaded
(though if it is, bindkey -d will still restore any predefined binding
to it, just as if you'd removed it with bindkey -r).

Since bindkey usually restricts itself to the current (or with -a, the
alternate) keymap, I made -u do that, and added another option -U
which deletes the command in every keymap (which is what
deletezlefunction() requires) --- the addition is trivial.

(It's really time the manual entry for bindkey was tidied up, too.)

I made addzlefunction() safer in case the function is already defined,
and modified the sample accordingly.

I don't think this clashes with anything recent, but you need the
first ZLE module patch, of course.

Maybe a bug or maybe not:  `bindkey -s -u string' doesn't work.

*** Doc/zshbuiltins.man.mod2	Mon Nov 11 11:46:10 1996
--- Doc/zshbuiltins.man	Mon Nov 11 13:45:41 1996
***************
*** 64,69 ****
--- 64,71 ----
  .TP
  \fBbindkey\fP \-\fBr\fP \fIin-string\fP ...
  .TP
+ \fBbindkey\fP \-\fBuU\fP \fIcommand\fP ...
+ .TP
  \fBbindkey\fP [ \-\fBa\fP ] \fIin-string\fP [ \fIcommand\fP ] ...
  .TP
  \fBbindkey\fP \-\fBs\fP [ \-\fBa\fP ] \fIin-string\fP \fIout-string\fP ...
***************
*** 77,83 ****
  loads the compiled-in bindings of these characters for the mode determined by
  the preceding options, or the current mode if used alone. Any previous bindings
  done by the user will be preserved. If the \-\fBr\fP option is given, remove
! any binding for each \fIin-string\fP. If the \-\fBs\fP option is not
  specified, bind each \fIin-string\fP to a specified \fIcommand\fP. If no
  \fIcommand\fP is specified, print the binding of \fIin-string\fP if it is
  bound, or return a nonzero exit code if it is not bound. If the \-\fBs\fP
--- 79,88 ----
  loads the compiled-in bindings of these characters for the mode determined by
  the preceding options, or the current mode if used alone. Any previous bindings
  done by the user will be preserved. If the \-\fBr\fP option is given, remove
! any binding for each \fIin-string\fP. If the \-\fBu\fP option is
! given, undefine every key bound to \fIcommand\fP in the current
! keymap; with \-\fBU\fP, do so in every keymap.  If the \-\fBs\fP
! option is not
  specified, bind each \fIin-string\fP to a specified \fIcommand\fP. If no
  \fIcommand\fP is specified, print the binding of \fIin-string\fP if it is
  bound, or return a nonzero exit code if it is not bound. If the \-\fBs\fP
*** Src/hashtable.h.mod2	Mon Nov 11 10:08:33 1996
--- Src/hashtable.h	Mon Nov 11 13:44:40 1996
***************
*** 259,265 ****
      {NULL, "alias", BINF_MAGICEQUALS, bin_alias, 0, -1, 0, "Lgmr", NULL},
      {NULL, "autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "t", "u"},
      {NULL, "bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL},
!     {NULL, "bindkey", 0, bin_bindkey, 0, -1, 0, "asvemdr", NULL},
      {NULL, "break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL},
      {NULL, "bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL},
      {NULL, "cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL},
--- 259,265 ----
      {NULL, "alias", BINF_MAGICEQUALS, bin_alias, 0, -1, 0, "Lgmr", NULL},
      {NULL, "autoload", BINF_TYPEOPTS, bin_functions, 0, -1, 0, "t", "u"},
      {NULL, "bg", 0, bin_fg, 0, -1, BIN_BG, NULL, NULL},
!     {NULL, "bindkey", 0, bin_bindkey, 0, -1, 0, "asvemdruU", NULL},
      {NULL, "break", BINF_PSPECIAL, bin_break, 0, 1, BIN_BREAK, NULL, NULL},
      {NULL, "bye", 0, bin_break, 0, 1, BIN_EXIT, NULL, NULL},
      {NULL, "cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL},
*** Src/mod_deltochar.c.mod2	Mon Nov 11 11:41:45 1996
--- Src/mod_deltochar.c	Mon Nov 11 11:43:01 1996
***************
*** 73,80 ****
  int
  boot_mod_deltochar(void *dummy)
  {
!     z_deltochar = addzlefunction("delete-to-char", deltochar, ZLE_DELETE);
!     return 0;
  }
  
  /**/
--- 73,84 ----
  int
  boot_mod_deltochar(void *dummy)
  {
!     int newfunc = addzlefunction("delete-to-char", deltochar, ZLE_DELETE);
!     if (newfunc > 0) {
! 	z_deltochar = newfunc;
! 	return 0;
!     } else
! 	return -1;
  }
  
  /**/
*** Src/module.c.mod2	Mon Nov 11 11:35:47 1996
--- Src/module.c	Mon Nov 11 13:33:00 1996
***************
*** 268,281 ****
      struct zlecmd *zc = NULL;
      int slot, addsize = zlecmdtot - ZLECMDCOUNT;
  
!     /* Should we check for a name clash, or let the module do it? */
  
!     /* First try and find a free slot.
!      * Slight problem:  if we re-use a slot then any key-binding
!      * which has not been deleted picks up the new function.
!      * It's not clear this is up to ZLE to deal with:  the
!      * use can fix it with bindkey if (s)he wants
!      */
      for (slot = 0; slot < addsize; slot++)
  	if (zlecmdadd[slot].flags & ZLE_DELETED) {
  	    zc = zlecmdadd + slot;
--- 268,278 ----
      struct zlecmd *zc = NULL;
      int slot, addsize = zlecmdtot - ZLECMDCOUNT;
  
!     /* Check for a clash */
!     if (zlefindfunc(name) != zlecmdtot)
! 	return -1;
  
!     /* First try and find a free slot. */
      for (slot = 0; slot < addsize; slot++)
  	if (zlecmdadd[slot].flags & ZLE_DELETED) {
  	    zc = zlecmdadd + slot;
***************
*** 309,318 ****
  
      if (zcn < ZLECMDCOUNT || zcn >= zlecmdtot)
  	return;
      zcn -= ZLECMDCOUNT;
  
      zc = zlecmdadd + zcn;
!     zc->name = "<deleted>";
      zc->func = feep;
      zc->flags = ZLE_DELETED;
  }
--- 306,317 ----
  
      if (zcn < ZLECMDCOUNT || zcn >= zlecmdtot)
  	return;
+     /* Remove all key bindings to zcn, wherever */
+     unbindzlefunc(zcn, 0);
      zcn -= ZLECMDCOUNT;
  
      zc = zlecmdadd + zcn;
!     zc->name = "";
      zc->func = feep;
      zc->flags = ZLE_DELETED;
  }
*** Src/zle_main.c.mod2	Mon Nov 11 09:52:17 1996
--- Src/zle_main.c	Mon Nov 11 13:44:27 1996
***************
*** 963,968 ****
--- 963,980 ----
  	char *s;
  	int func, len, firstzero = 0;
  
+ 	if (ops['u'] || ops['U']) {
+ 	    /* unbind all references to given function */
+ 	    func = zlefindfunc(*argv);
+ 	    if (func == zlecmdtot) {
+ 		zerr("undefined function: %s", *argv, 0);
+ 		return 1;
+ 	    }
+ 	    unbindzlefunc(func, ops['U'] ? 0 : ops['a'] ? 2 : 1);
+ 	    argv++;
+ 	    continue;
+ 	}
+ 
  	s = getkeystring(*argv++, &len, 2, NULL);
  	if (len > 1) {
  	    if (s[0])
***************
*** 989,1027 ****
  		    tab[STOUC(*s)] = z_undefinedkey;
  		    if (func == z_sendstring)
  			free(keybindtab->removenode(keybindtab, s));
! 		} else {
! 		    if (ky && ky->prefixct) {
! 			if (ky->func == z_sendstring) {
! 			    zfree(ky->str, ky->len);
! 			    ky->str = NULL;
! 			}
! 			ky->func = z_undefinedkey;
! 		    } else
! 			free(keybindtab->removenode(keybindtab, s));
! 		    if (len > 1) {
! 			s[--len] = '\0';
! 			while (len > 1) {
! 			    (ky = (Key) keybindtab->getnode(keybindtab, s))->prefixct--;
! 			    if (!ky->prefixct && ky->func == z_undefinedkey)
! 				free(keybindtab->removenode(keybindtab, s));
! 			    s[--len] = '\0';
! 			}
! 			(ky = (Key) keybindtab->getnode(keybindtab, s))->prefixct--;
! 			if (!ky->prefixct) {
! 			    int *otab = ops['a'] ? mainbindtab : altbindtab;
! 			    tab[STOUC(*s)] = ky->func;
! 			    /*
! 			     * If the bindtab we are not using also
! 			     * adds this key as a prefix, it must also
! 			     * be reset.
! 			     */
! 			    if (otab[STOUC(*s)] == z_prefix)
! 				otab[STOUC(*s)] = ky->func;
! 			    if (ky->func != z_sendstring)
! 				free(keybindtab->removenode(keybindtab, s));
! 			}
! 		    }
! 		}
  		zfree(s, len);
  		continue;
  	    }
--- 1001,1008 ----
  		    tab[STOUC(*s)] = z_undefinedkey;
  		    if (func == z_sendstring)
  			free(keybindtab->removenode(keybindtab, s));
! 		} else
! 		    delprefbinding(keybindtab, ky, s, len);
  		zfree(s, len);
  		continue;
  	    }
***************
*** 1094,1099 ****
--- 1075,1127 ----
      return 0;
  }
  
+ /* Delete a binding for a key sequence with prefixes */
+ 
+ /**/
+ void
+ delprefbinding(HashTable ktab, Key ky, char *s, int len)
+ {
+     if (ky && ky->prefixct) {
+ 	if (ky->func == z_sendstring) {
+ 	    zfree(ky->str, ky->len);
+ 	    ky->str = NULL;
+ 	}
+ 	ky->func = z_undefinedkey;
+     } else
+ 	free(ktab->removenode(ktab, s));
+     if (len > 1) {
+ 	s[--len] = '\0';
+ 	while (len > 1) {
+ 	    (ky = (Key) ktab->getnode(ktab, s))->prefixct--;
+ 	    if (!ky->prefixct && ky->func == z_undefinedkey)
+ 		free(ktab->removenode(ktab, s));
+ 	    s[--len] = '\0';
+ 	}
+ 	(ky = (Key) ktab->getnode(ktab, s))->prefixct--;
+ 	if (!ky->prefixct) {
+ 	    /*
+ 	     * Both the main and alternate binding tables use
+ 	     * the same keybindings, so we need to delete them here.
+ 	     * We need to pick the table associated with the right ktab
+ 	     * (i.e. vi or emacs).  If the ktab we are passed is not
+ 	     * current (i.e. not keybindtab), the alternate table
+ 	     * is not relevant, so don't touch it.
+ 	     */
+ 	    int *tab = (ktab == emkeybindtab) ? emacs_cur_bindtab :
+ 		viins_cur_bindtab;
+ 	    if (tab[STOUC(*s)] == z_prefix)
+ 		tab[STOUC(*s)] = ky->func;
+ 	    if (ktab == keybindtab) {
+ 		if (altbindtab[STOUC(*s)] == z_prefix)
+ 		    altbindtab[STOUC(*s)] = ky->func;
+ 	    }
+ 	    if (ky->func != z_sendstring)
+ 		free(ktab->removenode(ktab, s));
+ 	}
+     }
+ 
+ }
+ 
  /**/
  void
  freekeynode(HashNode hn)
***************
*** 1197,1202 ****
--- 1225,1301 ----
      else
  	putc('\n', shout);
      showinglist = 0;
+ }
+ 
+ LinkList bindremlist;
+ 
+ /**/
+ void
+ zerobinding(HashNode hn, int ifunc)
+ {
+     if (((Key)hn)->func == ifunc)
+ 	addlinknode(bindremlist, hn);
+ }
+ 
+ /*
+  * Unbind the given zle function ifunc wherever it occurs.
+  * With notall = 0, do this for all binding tables.
+  *	       = 1, do this in the main binding table.
+  *             = 2, do this in the alternate binding table.
+  * Note that the main and alternate binding tables share
+  * the same table for sequences with prefixes.
+  */
+ 
+ /**/
+ void
+ unbindzlefunc(int ifunc, int notall)
+ {
+     int i, **bindptr;
+     int *bindlist[] = { altbindtab, emacs_cur_bindtab, viins_cur_bindtab,
+ 			    NULL };
+     HashTable keybindlist[] = { emkeybindtab, vikeybindtab, NULL };
+     HashTable *keybindptr;
+ 
+     PERMALLOC {
+ 	for (keybindptr = keybindlist; *keybindptr; keybindptr++) {
+ 	    LinkNode ln;
+ 	    bindremlist = newlinklist();
+ 	    if (notall)
+ 		keybindptr = &keybindtab;
+ 
+ 	    /*
+ 	     * Search the key binding tables for the function.
+ 	     * It's dangerous to modify a hash table while scanning,
+ 	     * so put the bindings found in a list and
+ 	     * delete the bindings one by one later.
+ 	     */
+ 	    scanhashtable(*keybindptr, 0, 0, 0, zerobinding, ifunc);
+ 
+ 	    for (ln = firstnode(bindremlist); ln; incnode(ln)) {
+ 		Key k = (Key) ln->dat;
+ 		char *s = ztrdup(k->nam);
+ 		int sl = strlen(s);
+ 		delprefbinding(*keybindptr, k, s, sl);
+ 		zfree(s, sl);
+ 	    }
+ 
+ 	    freelinklist(bindremlist, NULL);
+ 	    if (notall)
+ 		break;
+ 	}
+ 	bindremlist = NULL;
+     } LASTALLOC;
+ 
+     for (bindptr = bindlist; *bindptr; bindptr++) {
+ 	/* if notall == 2, we are doing altbindtab first anyway */
+ 	if (notall == 1)
+ 	    bindptr = &mainbindtab;
+ 	for (i = 0; i < 256; i++)
+ 	    if ((*bindptr)[i] == ifunc)
+ 		(*bindptr)[i] = z_undefinedkey;
+ 	if (notall)
+ 	    break;
+     }
  }
  
  /**/

-- 
Peter Stephenson <pws@xxxxxx>       Tel: +49 33762 77366
WWW:  http://www.ifh.de/~pws/       Fax: +49 33762 77413
Deutches Electronen-Synchrotron --- Institut fuer Hochenergiephysik Zeuthen
DESY-IfH, 15735 Zeuthen, Germany.



Messages sorted by: Reverse Date, Date, Thread, Author