unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: storm@cua.dk (Kim F. Storm)
Subject: Enhancements to "minor-mode-map-alist" functionality.
Date: 12 Apr 2002 00:56:14 +0200	[thread overview]
Message-ID: <5xbscpg7zl.fsf@kfs2.cua.dk> (raw)


I'm almost done reworking cua-mode to use the command remapping
feature, and it is much cleaner than the old package.

However, the new cua package need to make some quite ugly
modifications to the minor-mode-map-alist (in the post-command-hook)
after _every_ command, since:

- the new cua need a total of 7 minor mode keymaps, which must be
  processed in a specific order, and before all other minor mode
  keymaps

- the selection of which of these minor mode keymaps are active may
  depend on the values of as many as 6 different variables for a
  single keymap

However, this can be dramatically simplified by two (simple)
enhancements to the minor-mode-map-alist functionality:

1) Provide a separate emulation-mode-map-alists variable where
modes like cua can insert their own mode-map-alist,

2) Allow selection of the active keymaps in the alist to
be based on evaluating a form in addition to a simple variable.

I have already implemented these features (see attached patch),
which allows me to configure all the minor mode keymaps needed
by cua once and for all:

  (setq cua--emulation-map-alist
	`((lambda . (and mark-active
			 cua-enable-cua-keys
			 (or (eq cua-enable-cua-keys t)
			     (not cua--explicit-region-start))
			 (not executing-kbd-macro)
			 (not cua--prefix-override-timer)
			 '(cua--prefix-override . ,cua--prefix-override-keymap)))
	  (lambda . (and mark-active
			 (timerp cua--prefix-override-timer)
			 '(cua--prefix-override . ,cua--prefix-repeat-keymap)))
	  (lambda . (and (or (eq cua-enable-cua-keys t)
			     cua--last-region-shifted)
			 '(cua-enable-cua-keys . ,cua--cua-keys-keymap)))
	  (lambda . (and cua--global-mark-active
			 (not (window-minibuffer-p))
			 '(cua--global-mark-active . ,cua--global-mark-keymap)))
	  (cua--rectangle . ,cua--rectangle-keymap)
	  (mark-active . ,cua--region-keymap)
	  (cua-mode . ,cua-global-keymap)))

  (setq emulation-mode-map-alists
        (cons cua--emulation-map-alist emulation-mode-map-alists))

On the user visible part, this is added to the doc string for
minor-mode-map-alist:

Alternatively, an element may look like (lambda . FORM) where FORM is
evaluated and should return either nil or a cons (SYMBOL . KEYMAP);
in this case, KEYMAP is used unconditionally and SYMBOL is displayed
by `describe-bindings' as the variable controlling KEYMAP.


The doc string for emulation-mode-map-alists reads:

List of keymap alists to use for emulations modes.
It is intended for modes or packages using multiple minor-mode keymaps.
Each element is a keymap alist just like `minor-mode-map-alist', and it
is used the same way.  The "active" keymaps in this alist are used before
`minor-mode-map-alist' but after `minor-mode-overriding-map-alist'.



Here is the patch which I expect to commit in a few days (when I
install the new version of cua mode).

Index: keymap.c
===================================================================
RCS file: /cvs/emacs/src/keymap.c,v
retrieving revision 1.258
diff -c -r1.258 keymap.c
*** keymap.c	24 Feb 2002 00:23:20 -0000	1.258
--- keymap.c	11 Apr 2002 21:54:34 -0000
***************
*** 75,80 ****
--- 75,83 ----
     minor mode variables and keymaps.  */
  Lisp_Object Vminor_mode_overriding_map_alist;
  
+ /* List of emulation mode keymap alists.  */
+ Lisp_Object Vemulation_mode_map_alists;
+ 
  /* Keymap mapping ASCII function key sequences onto their preferred forms.
     Initialized by the terminal-specific lisp files.  See DEFVAR for more
     documentation.  */
***************
*** 1277,1358 ****
  {
    int i = 0;
    int list_number = 0;
!   Lisp_Object alist, assoc, var, val;
!   Lisp_Object lists[2];
  
!   lists[0] = Vminor_mode_overriding_map_alist;
!   lists[1] = Vminor_mode_map_alist;
  
!   for (list_number = 0; list_number < 2; list_number++)
!     for (alist = lists[list_number];
! 	 CONSP (alist);
! 	 alist = XCDR (alist))
!       if ((assoc = XCAR (alist), CONSP (assoc))
! 	  && (var = XCAR (assoc), SYMBOLP (var))
! 	  && (val = find_symbol_value (var), !EQ (val, Qunbound))
! 	  && !NILP (val))
! 	{
! 	  Lisp_Object temp;
! 
! 	  /* If a variable has an entry in Vminor_mode_overriding_map_alist,
! 	     and also an entry in Vminor_mode_map_alist,
! 	     ignore the latter.  */
! 	  if (list_number == 1)
  	    {
! 	      val = assq_no_quit (var, lists[0]);
! 	      if (!NILP (val))
! 		continue;
  	    }
  
! 	  if (i >= cmm_size)
! 	    {
! 	      Lisp_Object *newmodes, *newmaps;
  
! 	      /* Use malloc/realloc here.  See the comment above
! 		 this function.  */
! 	      if (cmm_maps)
! 		{
! 		  BLOCK_INPUT;
! 		  cmm_size *= 2;
! 		  newmodes
! 		    = (Lisp_Object *) realloc (cmm_modes,
! 						cmm_size * sizeof *newmodes);
! 		  newmaps
! 		    = (Lisp_Object *) realloc (cmm_maps,
! 						cmm_size * sizeof *newmaps);
! 		  UNBLOCK_INPUT;
! 		}
! 	      else
! 		{
! 		  BLOCK_INPUT;
! 		  cmm_size = 30;
! 		  newmodes
! 		    = (Lisp_Object *) malloc (cmm_size * sizeof *newmodes);
! 		  newmaps
! 		    = (Lisp_Object *) malloc (cmm_size * sizeof *newmaps);
! 		  UNBLOCK_INPUT;
! 		}
  
! 	      if (newmodes)
! 		cmm_modes = newmodes;
! 	      if (newmaps)
! 		cmm_maps = newmaps;
! 	      
! 	      if (newmodes == NULL || newmaps == NULL)
! 		break;
  	    }
  
! 	  /* Get the keymap definition--or nil if it is not defined.  */
! 	  temp = internal_condition_case_1 (Findirect_function,
! 					    XCDR (assoc),
! 					    Qerror, current_minor_maps_error);
! 	  if (!NILP (temp))
! 	    {
! 	      cmm_modes[i] = var;
! 	      cmm_maps [i] = temp;
! 	      i++;
! 	    }
  	}
  
    if (modeptr) *modeptr = cmm_modes;
    if (mapptr)  *mapptr  = cmm_maps;
--- 1280,1397 ----
  {
    int i = 0;
    int list_number = 0;
!   Lisp_Object alist, assoc, var, val, emul_list;
! 
!   emul_list = Vemulation_mode_map_alists;
!   alist = Vminor_mode_overriding_map_alist;
! 
!  next_alist:
!   for ( ; CONSP (alist); alist = XCDR (alist))
!     {
!       Lisp_Object temp;
! 
!       if (assoc = XCAR (alist), !CONSP (assoc))
! 	continue;
! 
!       /* Each element in the alist is a CONS cell:
! 	 The form (VAR . KEYMAP) causes the KEYMAP to be included if the
! 	 VAR is defined an non-nil.
! 	 The form (lambda . FORM) evaluates the FORM which shall result in 
! 	 nil or a CONS cell (SYMBOL . KEYMAP) where the KEYMAP is included
! 	 unconditionally (as associated with the specified SYMBOL.  */
! 	 
!       var = XCAR (assoc);
! 
!       if (EQ (var, Qlambda))
! 	{
! 	  if ((temp = XCDR (assoc), NILP (temp))
! 	      || (assoc = safe_eval (temp), !CONSP (assoc))
! 	      || (var = XCAR (assoc), !SYMBOLP (var)))
! 	    continue;
! 	}
!       else
! 	{
! 	  if (!SYMBOLP (var)
! 	      || (val = find_symbol_value (var), EQ (val, Qunbound))
! 	      || NILP (val))
! 	    continue;
! 	}
  
!       /* If a variable has an entry in Vminor_mode_overriding_map_alist,
! 	 and also an entry in Vminor_mode_map_alist, ignore the latter.  */
!       if (list_number == 2)
! 	{
! 	  val = assq_no_quit (var, Vminor_mode_overriding_map_alist);
! 	  if (!NILP (val))
! 	    continue;
! 	}
  
!       if (i >= cmm_size)
! 	{
! 	  Lisp_Object *newmodes, *newmaps;
! 
! 	  /* Use malloc/realloc here.  See the comment above
! 	     this function.  */
! 	  if (cmm_maps)
! 	    {
! 	      BLOCK_INPUT;
! 	      cmm_size *= 2;
! 	      newmodes = (Lisp_Object *) realloc (cmm_modes,
! 						  cmm_size * sizeof *newmodes);
! 	      newmaps = (Lisp_Object *) realloc (cmm_maps,
! 						 cmm_size * sizeof *newmaps);
! 	      UNBLOCK_INPUT;
! 	    }
! 	  else
  	    {
! 	      BLOCK_INPUT;
! 	      cmm_size = 30;
! 	      newmodes = (Lisp_Object *) malloc (cmm_size * sizeof *newmodes);
! 	      newmaps = (Lisp_Object *) malloc (cmm_size * sizeof *newmaps);
! 	      UNBLOCK_INPUT;
  	    }
  
! 	  if (newmodes)
! 	    cmm_modes = newmodes;
! 	  if (newmaps)
! 	    cmm_maps = newmaps;
! 	      
! 	  if (newmodes == NULL || newmaps == NULL)
! 	    break;
! 	}
  
!       /* Get the keymap definition--or nil if it is not defined.  */
!       temp = internal_condition_case_1 (Findirect_function,
! 					XCDR (assoc),
! 					Qerror, current_minor_maps_error);
!       if (!NILP (temp))
! 	{
! 	  cmm_modes[i] = var;
! 	  cmm_maps [i] = temp;
! 	  i++;
! 	}
!     }
  
!   if (list_number < 2)
!     {
!       while (CONSP (emul_list))
! 	{
! 	  alist = XCAR (emul_list);
! 	  emul_list = XCDR (emul_list);
! 	  if (CONSP (alist))
! 	    {
! 	      list_number = 1;
! 	      goto next_alist;
  	    }
+ 	}
  
!       alist = Vminor_mode_map_alist;
!       if (CONSP (alist))
! 	{
! 	  list_number = 2;
! 	  goto next_alist;
  	}
+     }
  
    if (modeptr) *modeptr = cmm_modes;
    if (mapptr)  *mapptr  = cmm_maps;
***************
*** 3568,3583 ****
  	       doc: /* Alist of keymaps to use for minor modes.
  Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read
  key sequences and look up bindings iff VARIABLE's value is non-nil.
  If two active keymaps bind the same key, the keymap appearing earlier
  in the list takes precedence.  */);
    Vminor_mode_map_alist = Qnil;
  
    DEFVAR_LISP ("minor-mode-overriding-map-alist", &Vminor_mode_overriding_map_alist,
  	       doc: /* Alist of keymaps to use for minor modes, in current major mode.
! This variable is a alist just like `minor-mode-map-alist', and it is
! used the same way (and before `minor-mode-map-alist'); however,
! it is provided for major modes to bind locally.  */);
    Vminor_mode_overriding_map_alist = Qnil;
  
    DEFVAR_LISP ("function-key-map", &Vfunction_key_map,
  	       doc: /* Keymap mapping ASCII function key sequences onto their preferred forms.
--- 3607,3635 ----
  	       doc: /* Alist of keymaps to use for minor modes.
  Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read
  key sequences and look up bindings iff VARIABLE's value is non-nil.
+ Alternatively, an element may look like (lambda . FORM) where FORM is 
+ evaluated and should return either nil or a cons (SYMBOL . KEYMAP);
+ in this case, KEYMAP is used unconditionally and SYMBOL is displayed
+ by `describe-bindings' as the variable controlling KEYMAP.
  If two active keymaps bind the same key, the keymap appearing earlier
  in the list takes precedence.  */);
    Vminor_mode_map_alist = Qnil;
  
    DEFVAR_LISP ("minor-mode-overriding-map-alist", &Vminor_mode_overriding_map_alist,
  	       doc: /* Alist of keymaps to use for minor modes, in current major mode.
! This variable is an alist just like `minor-mode-map-alist', and it is
! used the same way (and before `minor-mode-map-alist' and alists in
! `emulation-mode-map-alists'); however, it is provided for
! major modes to bind locally.  */);
    Vminor_mode_overriding_map_alist = Qnil;
+ 
+   DEFVAR_LISP ("emulation-mode-map-alists", &Vemulation_mode_map_alists,
+ 	       doc: /* List of keymap alists to use for emulations modes.
+ It is intended for modes or packages using multiple minor-mode keymaps.
+ Each element is a keymap alist just like `minor-mode-map-alist', and it
+ is used the same way.  The "active" keymaps in this alist are used before
+ `minor-mode-map-alist' but after `minor-mode-overriding-map-alist'.  */); 
+   Vemulation_mode_map_alists = Qnil;
  
    DEFVAR_LISP ("function-key-map", &Vfunction_key_map,
  	       doc: /* Keymap mapping ASCII function key sequences onto their preferred forms.

             reply	other threads:[~2002-04-11 22:56 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-04-11 22:56 Kim F. Storm [this message]
2002-04-11 22:43 ` Enhancements to "minor-mode-map-alist" functionality Stefan Monnier
2002-04-12  9:31   ` Kim F. Storm
2002-04-12 13:20     ` Kim F. Storm
2002-04-12 18:46       ` Stefan Monnier
     [not found]         ` <5xofgoobzr.fsf@kfs2.cua.dk>
     [not found]           ` <200204122021.g3CKLh217680@rum.cs.yale.edu>
2002-04-14 22:32             ` Kim F. Storm
2002-04-16 20:18               ` Richard Stallman
2002-04-16 22:34                 ` Kim F. Storm
2002-04-18 18:46                   ` Richard Stallman
2002-04-18 23:07                     ` Kim F. Storm
2002-04-19 13:43                       ` Stefan Monnier
2002-04-19 15:36                         ` Kim F. Storm
2002-04-19 14:46                           ` Stefan Monnier
2002-04-21 17:46                             ` Kim F. Storm
2002-04-22  9:28                               ` Stefan Monnier
2002-04-22 15:15                                 ` Kim F. Storm
2002-04-19 18:42                       ` Richard Stallman
2002-04-19 22:05                         ` Kim F. Storm
2002-04-20 17:27                           ` Richard Stallman
2002-04-21 11:08                             ` Kim F. Storm
2002-04-22  7:47                               ` Richard Stallman
2002-04-22 13:53                                 ` Kim F. Storm
2002-04-22 22:36                               ` Richard Stallman
2002-04-23 10:58                                 ` Kim F. Storm
2002-04-22 22:36                               ` Richard Stallman
2002-04-23 11:02                                 ` Kim F. Storm
2002-04-24 17:55                                   ` Richard Stallman
2002-04-26 13:44                                     ` Kim F. Storm
2002-04-27 22:41                                       ` Richard Stallman
2002-04-29  9:17                                         ` Kai Großjohann
2002-04-30  5:18                                           ` Richard Stallman
2002-04-30 21:25                                             ` Kim F. Storm
2002-05-01  7:14                                               ` Richard Stallman
2002-05-01 17:37                                                 ` Kim F. Storm
2002-04-14 23:11         ` Kim F. Storm
2002-04-12 18:20     ` Stefan Monnier
2002-04-12 21:05       ` Kim F. Storm
2002-04-12 20:30         ` Stefan Monnier
2002-04-12 22:08           ` Kim F. Storm
2002-04-13 19:05     ` Richard Stallman
2002-04-13 19:05 ` Richard Stallman
2002-04-13 23:30   ` Kim F. Storm
2002-04-15 12:34     ` Stefan Monnier
2002-04-17 16:03       ` Richard Stallman
2002-04-15 21:54     ` Richard Stallman
2002-04-15 23:55       ` Kim F. Storm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5xbscpg7zl.fsf@kfs2.cua.dk \
    --to=storm@cua.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).