From 17dee17e4e5ab99cd50e6ee3a21a8d6faa4aac96 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 5 Sep 2010 19:24:44 +0000 Subject: 28227: improved documentation on keymaps 28226: improve bindkey -lL for aliased keymaps --- ChangeLog | 10 ++++- Doc/Zsh/zle.yo | 30 +++++++------ Src/Zle/zle_keymap.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 133 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index faf8b0680..fec8ce11e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2010-09-05 Peter Stephenson + + * 28226: Doc/Zsh/zle.yo, Src/Zle/zle_keymap.c: "bindkey -lL" now + lists aliased keymaps in a more useful way. + + * 28227: Doc/Zsh/zle.yo: a few remarks on the question of + keymaps. + 2010-09-02 Peter Stephenson * users/15350: Doc/expn.yo: explain the strange rounding rules for @@ -13591,5 +13599,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5068 $ +* $Revision: 1.5069 $ ***************************************************** diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo index 708467cb0..64012fd2f 100644 --- a/Doc/Zsh/zle.yo +++ b/Doc/Zsh/zle.yo @@ -149,21 +149,27 @@ xitem(tt(bindkey) [ var(options) ] tt(-r) var(in-string) ...) xitem(tt(bindkey) [ var(options) ] tt(-s) var(in-string out-string) ...) xitem(tt(bindkey) [ var(options) ] var(in-string command) ...) item(tt(bindkey) [ var(options) ] [ var(in-string) ])( -tt(bindkey)'s options can be divided into three categories: keymap selection, -operation selection, and others. The keymap selection options are: +tt(bindkey)'s options can be divided into three categories: keymap +selection for the current command, operation selection, and others. The +keymap selection options are: startitem() item(tt(-e))( -Selects keymap `tt(emacs)', and also links it to `tt(main)'. +Selects keymap `tt(emacs)' for any operations by the current command, +and also links `tt(emacs)' to `tt(main)' so that it is selected by +default the next time the editor starts. ) item(tt(-v))( -Selects keymap `tt(viins)', and also links it to `tt(main)'. +Selects keymap `tt(viins)' for any operations by the current command, +and also links `tt(viins)' to `tt(main)' so that it is selected by default +the next time the editor starts. ) item(tt(-a))( -Selects keymap `tt(vicmd)'. +Selects keymap `tt(vicmd)' for any operations by the current command. ) item(tt(-M) var(keymap))( -The var(keymap) specifies a keymap name. +The var(keymap) specifies a keymap name that is selected for any +operations by the current command. ) enditem() @@ -175,7 +181,8 @@ startitem() item(tt(-l))( List all existing keymap names. If the tt(-L) option is also used, list in the form of tt(bindkey) -commands to create the keymaps. +commands to create the keymaps; this combination also shows +which keymap is linked to `tt(main)', if any. ) item(tt(-d))( Delete all existing keymaps and reset to the default state. @@ -1207,11 +1214,10 @@ mini-buffer. ) enditem() -Any multi-character string that is not bound to one of the above functions -will beep and interrupt the search, leaving the last found line in the -buffer. Any single character that is not bound to one of the above -functions, or tt(self-insert) or tt(self-insert-unmeta), will have the same -effect but the function will be executed. +Any character that is not bound to one of the above functions, or +tt(self-insert) or tt(self-insert-unmeta), will cause the mode to be +exited. The character is then looked up and executed in the keymap in +effect at that point. When called from a widget function by the tt(zle) command, the incremental search commands can take a string argument. This will be treated as a diff --git a/Src/Zle/zle_keymap.c b/Src/Zle/zle_keymap.c index 7f59d9d9b..0d250c585 100644 --- a/Src/Zle/zle_keymap.c +++ b/Src/Zle/zle_keymap.c @@ -58,11 +58,24 @@ struct keymapname { Keymap keymap; /* the keymap itsef */ }; +/* Can't be deleted (.safe) */ #define KMN_IMMORTAL (1<<1) struct keymap { Thingy first[256]; /* base binding of each character */ HashTable multi; /* multi-character bindings */ + /* + * The "real" name of this keymap. + * For an aliased keymap, this is the first name to be defined. + * If this is deleted but there are other names we randomly pick another + * one, avoiding the name "main". The principal use + * for this is to make it clear what "main" is aliased to. + * + * If "main" is the only name for this map, this will be NULL. + * That's fine, there's no alias. We'll pick a primary if we + * alias "main" again. + */ + KeymapName primary; int flags; /* various flags (see below) */ int rc; /* reference count */ }; @@ -162,6 +175,70 @@ makekeymapnamnode(Keymap keymap) return kmn; } + +/* + * Reference a keymap from a keymapname. + * Used when linking keymaps. This includes the first link to a + * newly created keymap. + */ + +static void +refkeymap_by_name(KeymapName kmn) +{ + refkeymap(kmn->keymap); + if (!kmn->keymap->primary && strcmp(kmn->nam, "main") != 0) + kmn->keymap->primary = kmn; +} + +/* + * Communication to keymap scanner when looking for a new primary name. + */ +static Keymap km_rename_me; + +/* Find a new primary name for a keymap. See below. */ + +static void +scanprimaryname(HashNode hn, int ignored) +{ + KeymapName n = (KeymapName) hn; + + (void)ignored; + + /* Check if we've already found a new primary name. */ + if (km_rename_me->primary) + return; + /* Don't use "main". */ + if (!strcmp(n->nam, "main")) + return; + if (n->keymap == km_rename_me) + km_rename_me->primary = n; +} + +/* + * Unreference a keymap from a keymapname. + * Used when unlinking keymaps to ensure there is still a primary + * name for the keymap, unless it is an unaliased "main". + */ +static void +unrefkeymap_by_name(KeymapName kmname) +{ + Keymap km = kmname->keymap; + if (unrefkeymap(km) && km->primary == kmname) { + /* + * The primary name for the keymap has gone, + * but the keymap is still referred to; find a new primary name + * for it. Sort the keymap to make the result deterministic. + */ + /* Set the primary name to NULL so we can check if we've found one */ + km->primary = NULL; + km_rename_me = km; + scanhashtable(keymapnamtab, 1, 0, 0, scanprimaryname, 0); + /* Just for neatness */ + km_rename_me = NULL; + } +} + + /**/ static void freekeymapnamnode(HashNode hn) @@ -169,7 +246,7 @@ freekeymapnamnode(HashNode hn) KeymapName kmn = (KeymapName) hn; zsfree(kmn->nam); - unrefkeymap(kmn->keymap); + unrefkeymap_by_name(kmn); zfree(kmn, sizeof(*kmn)); } @@ -354,7 +431,7 @@ linkkeymap(Keymap km, char *name, int imm) return 1; if(n->keymap == km) return 0; - unrefkeymap(n->keymap); + unrefkeymap_by_name(n); n->keymap = km; } else { n = makekeymapnamnode(km); @@ -362,21 +439,29 @@ linkkeymap(Keymap km, char *name, int imm) n->flags |= KMN_IMMORTAL; keymapnamtab->addnode(keymapnamtab, ztrdup(name), n); } - refkeymap(km); + refkeymap_by_name(n); return 0; } /**/ -void refkeymap(Keymap km) +void +refkeymap(Keymap km) { km->rc++; } +/* Unreference keymap, returning new reference count, 0 if deleted */ + /**/ -void unrefkeymap(Keymap km) +int +unrefkeymap(Keymap km) { - if (!--km->rc) + if (!--km->rc) { deletekeymap(km); + return 0; + } + + return km->rc; } /* Select a keymap as the current ZLE keymap. Can optionally fall back * @@ -734,10 +819,21 @@ scanlistmaps(HashNode hn, int list) { KeymapName n = (KeymapName) hn; - if(list) { - fputs("bindkey -N ", stdout); - if(n->nam[0] == '-') - fputs("-- ", stdout); + if (list) { + Keymap km = n->keymap; + fputs("bindkey -", stdout); + if (km->primary && km->primary != n) { + KeymapName pn = km->primary; + fputs("A ", stdout); + if (pn->nam[0] == '-') + fputs("-- ", stdout); + quotedzputs(pn->nam, stdout); + fputc(' ', stdout); + } else { + fputs("N ", stdout); + if(n->nam[0] == '-') + fputs("-- ", stdout); + } quotedzputs(n->nam, stdout); } else nicezputs(n->nam, stdout); -- cgit 1.4.1