unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-11 22:56 Enhancements to "minor-mode-map-alist" functionality Kim F. Storm
@ 2002-04-11 22:43 ` Stefan Monnier
  2002-04-12  9:31   ` Kim F. Storm
  2002-04-13 19:05 ` Richard Stallman
  1 sibling, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-11 22:43 UTC (permalink / raw)
  Cc: emacs-devel

> 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,

As you probably know, I'm not too excited about this, since it shouldn't
be necessary if we could enforce a bit more discipline in the way
entries are added to minor-mode-map-alist.
[ Yes, I wish we had "watchers" so we could trap modifications of
  particular variables. ]

But I guess that I can live with it.

BTW, should emulation-mode-map-alists take precedence over
minor-mode-overriding-map-alist or not ?

Also, have you contacted Michael Kifer to see if that would satisfy his
needs for viper (I know he also had to do some funky post-command
fiddling of the minor-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 generally like the idea of having the keymaps more dynamic,
but I'd rather not add another form of dynamism that isn't quite
good enough for everything.  To be more precise, currently you can get
the above "select the keymap dynamically" in a more generic way
(i.e. not just for minor mode maps) by using an entry of the form:

	'(menu-item "foo" data :filter fun)

It is mostly used for dynamic menus, but also works in other keymaps.
Problem is, it only works for submaps because it is not itself
a keymap and thus can't be used for a toplevel map.
So if the dynamism you need is only in the `command-remap' submap,
for example, your new hack is not needed.

I'd rather not add a hack that's specific to minor-mode-map-alist
if we could do the same for all cases instead.

> 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:

In the patch, you end up evaluating elisp code from a function
that already has a comment about the fact that it needs to be extra-careful
about memory allocation.  Also I'm not sure that all places that call this
function are ready to have elisp code executed at that point (you might
need some GCPROs added here and there).

In other words, maybe we shouldn't evaluate the form inside this
current_minor_maps function.


	Stefan

PS: by the way, isn't it enough to fiddle with minor-mode-map-alist
    in after-load-hook rather than in post-command-hook ?
    [ assuming we had such an after-load-hook. ]

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Enhancements to "minor-mode-map-alist" functionality.
@ 2002-04-11 22:56 Kim F. Storm
  2002-04-11 22:43 ` Stefan Monnier
  2002-04-13 19:05 ` Richard Stallman
  0 siblings, 2 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-11 22:56 UTC (permalink / 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.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-11 22:43 ` Stefan Monnier
@ 2002-04-12  9:31   ` Kim F. Storm
  2002-04-12 13:20     ` Kim F. Storm
                       ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-12  9:31 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > 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,
> 
> As you probably know, I'm not too excited about this, since it shouldn't
> be necessary if we could enforce a bit more discipline in the way
> entries are added to minor-mode-map-alist.

I doubt we can find a way to enforce that.

> [ Yes, I wish we had "watchers" so we could trap modifications of
>   particular variables. ]
> 
Which would still not ensure anything -- if multiple packages are
watching minor-mode-map-alist and rearranges it, we'd still not
be able to _ensure_ any specific ordering...

> But I guess that I can live with it.

Good :-)

> 
> BTW, should emulation-mode-map-alists take precedence over
> minor-mode-overriding-map-alist or not ?

Based on the two existing uses of minor-mode-overriding-map-alist, I
don't think it matters much, but e-m-m-a should probably take
precedence over m-m-o-m-a...  I'll change that.

> 
> Also, have you contacted Michael Kifer to see if that would satisfy his
> needs for viper (I know he also had to do some funky post-command
> fiddling of the minor-mode-map-alist).
> 

As far as I can see, it is _exactly_ the same problem (viper has 9 keymaps).

> > 2) Allow selection of the active keymaps in the alist to
> > be based on evaluating a form in addition to a simple variable.
> 
> I generally like the idea of having the keymaps more dynamic,
> but I'd rather not add another form of dynamism that isn't quite
> good enough for everything.  To be more precise, currently you can get
> the above "select the keymap dynamically" in a more generic way
> (i.e. not just for minor mode maps) by using an entry of the form:
> 
> 	'(menu-item "foo" data :filter fun)
> 
> It is mostly used for dynamic menus, but also works in other keymaps.
> Problem is, it only works for submaps because it is not itself
> a keymap and thus can't be used for a toplevel map.

I need this at the top-level maps, so it is not applicable here.
But if we could support something like (keymap :filter fun ...),
it would satisfy the needs for cua.

> So if the dynamism you need is only in the `command-remap' submap,
> for example, your new hack is not needed.

I don't think this is a hack!  If so, the minor-mode-map-alist itself
is a hack, since it has several obvious limitations.  One of which
is remedied by the minor-mode-overriding-map-alist!

Actually, we could discard that feature (don't say that we should)
and use either the dynamic keymap selection suggested, e.g.

From diff-mode.el:

  ;; Neat trick from Dave Love to add more bindings in read-only mode:
  (add-to-list (make-local-variable 'minor-mode-overriding-map-alist)
  	       (cons 'buffer-read-only diff-mode-shared-map))

could be replaced by:

  ;; Neat trick from Dave Love to add more bindings in read-only mode:
  (add-to-list 'minor-mode-map-alist
        `(lambda . (and diff-minor-mode buffer-read-only
                   '(diff-minor-mode . ,diff-mode-shared-map))))

Or maybe a simple command remapping the the buffer's local map would
do just as well, e.g.

From help-mode.el:

      ;; View mode steals RET from us.
      (set (make-local-variable 'minor-mode-overriding-map-alist)
           (list (cons 'view-mode
                       (let ((map (make-sparse-keymap)))
                         (set-keymap-parent map view-mode-map)
                         (define-key map "\r" 'help-follow)
                         map))))

could simply be

      ;; View mode steals RET from us.
      (local-set-key [remap View-scroll-line-forward] 'help-follow)

[Actually, I think I'll install that change in any case].

That's the two uses of minor-mode-overriding-map-alist I could find.

> 
> I'd rather not add a hack that's specific to minor-mode-map-alist
> if we could do the same for all cases instead.
>

Sure.  But what device do you suggest then?
  (keymap :filter fun ...) ?

I don't object to that, but it would be _less_ efficient, since
we have to search the keymap for the :filter property (like we do
for a menu-item, but that is much shorter)  [unless we ensure
it stays at the head of the keymap list].

Also, the keymap lookup code would also have to be careful not to 
interpret the FUN part as a binding, and when we add binding to
a map, we should be careful not to split the ":filter FUN" pair.
 
> > 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:
> 
> In the patch, you end up evaluating elisp code from a function
> that already has a comment about the fact that it needs to be extra-careful
> about memory allocation.

I know, but given the other options, I would expect this to do a lot
less memory allocations (if any!) than the alternative (of
regenerating minor-mode-map-alist after every command - and setting
the 9 destinct variables needed to control it - as viper does [more or
less]).

In my case (cua), I don't think I make any memory allocations there at all
since I only test a number of variables -- not modify anything.

>                        Also I'm not sure that all places that call this
> function are ready to have elisp code executed at that point (you might
> need some GCPROs added here and there).

As I've pointed out before, a lot of functions in keymap already lack
proper GCPROs due to the autoload enhancements to get_keymap...

And now you tell me that get_keyelt can GC as well...  I don't see
any GCPROs related to that either...

So GC-wise this only makes things marginally worse :-/

> 
> In other words, maybe we shouldn't evaluate the form inside this
> current_minor_maps function.
> 

I still think it is pretty safe to do so.

But I think it would be better to use menu_item_eval_property than
safe_eval for this purpose.

> 
> 	Stefan
> 
> PS: by the way, isn't it enough to fiddle with minor-mode-map-alist
>     in after-load-hook rather than in post-command-hook ?
>     [ assuming we had such an after-load-hook. ]
> 
> 

If some packages decide to fiddle with minor-mode-map-alist when you
activate the mode the first time (rather than on load), I don't
think an after-load-hook will catch that.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12  9:31   ` Kim F. Storm
@ 2002-04-12 13:20     ` Kim F. Storm
  2002-04-12 18:46       ` Stefan Monnier
  2002-04-12 18:20     ` Stefan Monnier
  2002-04-13 19:05     ` Richard Stallman
  2 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-12 13:20 UTC (permalink / raw)
  Cc: emacs-devel


I have been thinking more about this and I've now got a more generic
solution (I think) which has a lot of potential:
        Nested, Conditioned Keymaps.

The idea is as follows:

1) A keymap may be conditioned with

        (keymap :filter FORM ...)

   We already discussed that, and although some precautions are needed
   to handle this, it should be fairly trivial to implement.

2) A keymap may be nested with

        (keymap ... (keymap ...) ... (keymap ...) ...)

   The idea is that when we scan through a keymap (searching for a binding),
   if we encounter a nested keymap, we will [recursively] scan that
   keymap before continuing through the original keymap.

Now, if we combine those two ideas, I can write a "single" cua-mode
master keymap which contains all of the conditioned sub-keymaps I need,
i.e. something like this  [I know this isn't the proper way to create
a keymap, but it illustrates the point I'm making]:

  (setq cua-mode-map
        (keymap :filter cua-mode
           (keymap :filter (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-keymap)
	   (keymap :filter (and mark-active
			        (timerp cua--prefix-override-timer))
            ,cua--prefix-repeat-keymap)
	   (keymap :filter (or (eq cua-enable-cua-keys t)
			       cua--last-region-shifted)
	    ,cua--cua-keys-keymap)
	   (keymap :filter (and cua--global-mark-active
			        (not (window-minibuffer-p)))
	    ,cua--global-mark-keymap)
           (keymap :filter cua--rectangle ,cua--rectangle-keymap)
	   (keymap :filter mark-active ,cua--region-keymap)
	   ,cua-global-keymap))

  (add-to-list 'minor-mode-map-alist `(cua-mode . ,cua-mode-map))

So doing this would remove the need for the emulation-mode-map-alists
(which you dislike :-) as well  

I can easily ensure that cua-mode-map stays at the beginning of
minor-mode-map-alist [will be simple in a post-command hook, or maybe
by adding it to minor-mode-overriding-map-alist :-) ]


Some functions may be needed to manage this, e.g.

  (add-keymap keymap nested &optional after)
        -> inserts NESTED at the beginning of KEYMAP,
           or after optional AFTER keymap (or last if AFTER is t)
           Returns NESTED.

  (remove-keymap keymap nested)
        -> removes NESTED from the KEYMAP.

  (set-keymap-filter keymap filter &optional new)
        -> sets the :filter property on KEYMAP to FILTER,
        removes the :filter property if FILTER is nil.
        If NEW is non-nil, create a new keymap and use KEYMAP as a nested
        of that keymap, and apply the FILTER on the new keymap.
        This means that we can apply a filter to an existing keymap without
        adding a filter to that keymap.
        -> returns KEYMAP if NEW is nil,
           or the new keymap if NEW is non-nil.

  (get-keymap-filter keymap)
        -> returns the :filter property on KEYMAP


This can also be used instead of minor-mode-overriding-map-alist:
 
>From diff-mode.el:
 
   ;; Neat trick from Dave Love to add more bindings in read-only mode:
   (add-to-list (make-local-variable 'minor-mode-overriding-map-alist)
   	       (cons 'buffer-read-only diff-mode-shared-map))
 
could be replaced by:
 
   ;; Neat trick from Kim Storm to add more bindings in read-only mode:
   (add-keymap 'diff-mode-map (set-keymap-filter diff-mode-shared-map 'buffer-read-only t))
 
-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12  9:31   ` Kim F. Storm
  2002-04-12 13:20     ` Kim F. Storm
@ 2002-04-12 18:20     ` Stefan Monnier
  2002-04-12 21:05       ` Kim F. Storm
  2002-04-13 19:05     ` Richard Stallman
  2 siblings, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-12 18:20 UTC (permalink / raw)
  Cc: Stefan Monnier, emacs-devel

> "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> 
> > > 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,
> > 
> > As you probably know, I'm not too excited about this, since it shouldn't
> > be necessary if we could enforce a bit more discipline in the way
> > entries are added to minor-mode-map-alist.
> 
> I doubt we can find a way to enforce that.

In an ideal world, all modifications of the alist would go through
either add-minor-mode or define-minor-mode, where we could enforce it.
I agree that it's not realistic.

> > [ Yes, I wish we had "watchers" so we could trap modifications of
> >   particular variables. ]
> > 
> Which would still not ensure anything -- if multiple packages are
> watching minor-mode-map-alist and rearranges it, we'd still not
> be able to _ensure_ any specific ordering...

Well, there would be a single watcher that provided the same functionality
as your emulation alist and both viper and cua would use it.

> > Also, have you contacted Michael Kifer to see if that would satisfy his
> > needs for viper (I know he also had to do some funky post-command
> > fiddling of the minor-mode-map-alist).
> As far as I can see, it is _exactly_ the same problem (viper has 9 keymaps).

That's my impression as well, but maybe he has some other idea of what
the ideal solution should look like.

> > > 2) Allow selection of the active keymaps in the alist to
> > > be based on evaluating a form in addition to a simple variable.
> > 
> > I generally like the idea of having the keymaps more dynamic,
> > but I'd rather not add another form of dynamism that isn't quite
> > good enough for everything.  To be more precise, currently you can get
> > the above "select the keymap dynamically" in a more generic way
> > (i.e. not just for minor mode maps) by using an entry of the form:
> > 
> > 	'(menu-item "foo" data :filter fun)
> > 
> > It is mostly used for dynamic menus, but also works in other keymaps.
> > Problem is, it only works for submaps because it is not itself
> > a keymap and thus can't be used for a toplevel map.
> 
> I need this at the top-level maps, so it is not applicable here.

I kind of expected it :-(

> But if we could support something like (keymap :filter fun ...),
> it would satisfy the needs for cua.

I had something like that working in the past.  I don't think
I have the code around any more, tho.  IIRC it wasn't too difficult
to add.  The evaluation of the function was done in `get_keymap'
(this is not to say that it was the right place to do it, but that
it was my choice at the time, because it seemed simpler).

Another idea I have been toying with (but it never got far enough
for me to start writing any code, not even tentatively) is to use
a "null event".  Assuming this event is called `nil', you could
replace the above dynamic keymap with:

	(defvar dynmap (make-sparse-keymap))
	(define-key dynmap [nil] '(menu-item "foo" data :filter fun))

Ideally this would also allow multiple such "same-level submaps"
which would then provide multiple keymap inheritance.

> > So if the dynamism you need is only in the `command-remap' submap,
> > for example, your new hack is not needed.
> I don't think this is a hack!

I said "hack" because I think it's more ad-hoc than it should.

>   ;; Neat trick from Dave Love to add more bindings in read-only mode:
>   (add-to-list 'minor-mode-map-alist
>         `(lambda . (and diff-minor-mode buffer-read-only
>                    '(diff-minor-mode . ,diff-mode-shared-map))))

Indeed.

>       ;; View mode steals RET from us.
>       (local-set-key [remap View-scroll-line-forward] 'help-follow)

That one looks completely bogus to me.  Do you really want to prevent
the use of View-scroll-line-forward from a help-mode buffer even if
it's bound to something else than RET ?

> [Actually, I think I'll install that change in any case].

Please don't.

> > I'd rather not add a hack that's specific to minor-mode-map-alist
> > if we could do the same for all cases instead.
> 
> Sure.  But what device do you suggest then?
>   (keymap :filter fun ...) ?
> 
> I don't object to that, but it would be _less_ efficient, since
> we have to search the keymap for the :filter property (like we do
> for a menu-item, but that is much shorter)  [unless we ensure
> it stays at the head of the keymap list].

I don't care much for efficiency at this stage.

> Also, the keymap lookup code would also have to be careful not to
> interpret the FUN part as a binding,

You can force it to be a symbol.

> and when we add binding to
> a map, we should be careful not to split the ":filter FUN" pair.

Of course, it might need some care.  Doing it in get_keymap works
around the above problem, tho since the keymap that's modified
is the one returned by get_keymap.

> So GC-wise this only makes things marginally worse :-/

I'd rather try to make it better than to make it marginally worse.

> > In other words, maybe we shouldn't evaluate the form inside this
> > current_minor_maps function.
> I still think it is pretty safe to do so.

Despite the comment that's just above ?  Do you really think the
coders went to the trouble of not using xmalloc/xrealloc and of
sometimes returning an incorrect result (hoping that the cause of
the problem will cause something else to abort later on) just
for the fun of it ?

> If some packages decide to fiddle with minor-mode-map-alist when you
> activate the mode the first time (rather than on load), I don't
> think an after-load-hook will catch that.

And if some package decides to fiddle with it from an idle-hook, the
post-command-hook will fail as well.  The question is not "is it theoretically
safe" but "is it safe in practice" ?  I believe it'd be good enough in practice
because I don't see much fiddling of minor-mode-map-alist outside of
toplevel expressions.


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12 13:20     ` Kim F. Storm
@ 2002-04-12 18:46       ` Stefan Monnier
       [not found]         ` <5xofgoobzr.fsf@kfs2.cua.dk>
  2002-04-14 23:11         ` Kim F. Storm
  0 siblings, 2 replies; 46+ messages in thread
From: Stefan Monnier @ 2002-04-12 18:46 UTC (permalink / raw)
  Cc: Stefan Monnier, emacs-devel

> 2) A keymap may be nested with
> 
>         (keymap ... (keymap ...) ... (keymap ...) ...)
> 
>    The idea is that when we scan through a keymap (searching for a binding),
>    if we encounter a nested keymap, we will [recursively] scan that
>    keymap before continuing through the original keymap.

I like this idea so much that I have implemented it already, but
for the purpose of multiple inheritance and to get rid of the infamous
fix_submap_inheritance ugliness.  It requires several non-trivial
changes, tho.  And I haven't finished taking care of all the "problems"
it introduces (not all of them need to be addressed right away: for
example, it doesn't work for menus yet).

> So doing this would remove the need for the emulation-mode-map-alists
> (which you dislike :-) as well
> 
> I can easily ensure that cua-mode-map stays at the beginning of
> minor-mode-map-alist [will be simple in a post-command hook, or maybe
> by adding it to minor-mode-overriding-map-alist :-) ]

I don't understand.  In what way is it easier ?
It still seems like you need some kind of post-command-hook thingy.


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12 21:05       ` Kim F. Storm
@ 2002-04-12 20:30         ` Stefan Monnier
  2002-04-12 22:08           ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-12 20:30 UTC (permalink / raw)
  Cc: Stefan Monnier, emacs-devel

> But I still think the use of the minor-mode-overriding-map-alist for
> this purpose is pretty obscure (although I suspect that is the
> purpose for which it was invented...)

I still think it's the best solution so far.
Better than a `keymap' text-property (help-follow also works on non-buttons
and I care about it, since I wrote the code for it ;-).

> > > Also, the keymap lookup code would also have to be careful not to
> > > interpret the FUN part as a binding,
> > 
> > You can force it to be a symbol.
> 
> I would prefer not to do that; an alternative would be to put a
> cons cell (:filter . FORM) into the keymap, causing the rest of
> the keymap to be ignored if FORM returns nil.

Note that if the evaluation is done inside get_keymap then there
is no problem whatsoever and the map can have any shape we want
(the only reason to start it with `keymap' is convenience, for instance).

> I would be much easier if an element in the minor-mode-map-alist
> could be tagged as `keep at head of list'.  IIRC we discussed this
> some time ago on this list, and really didn't find a way to
> accomplish that.

Indeed, it would be easy to do in add-minor-mode and define-minor-mode
or with a watcher, but in the current context, it seems hopeless.
Although you could of course write a general post-command-hook that
does what you want and that both cua and viper could use.

> But maybe such modes could simply put their map on
> minor-mode-overriding-map-alist instead ?  Is that "legal practice"?

I don't think there's anything illegal about it, but since that variable is
automatically made buffer-local, it will also require some care, although
it shouldn't be too bad.


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12 18:20     ` Stefan Monnier
@ 2002-04-12 21:05       ` Kim F. Storm
  2002-04-12 20:30         ` Stefan Monnier
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-12 21:05 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> 
> > But if we could support something like (keymap :filter fun ...),
> > it would satisfy the needs for cua.
> 
> I had something like that working in the past.  I don't think
> I have the code around any more, tho.  IIRC it wasn't too difficult
> to add.  The evaluation of the function was done in `get_keymap'
> (this is not to say that it was the right place to do it, but that
> it was my choice at the time, because it seemed simpler).

I'll give it a try...

> 
> Another idea I have been toying with (but it never got far enough
> for me to start writing any code, not even tentatively) is to use
> a "null event".  Assuming this event is called `nil', you could
> replace the above dynamic keymap with:
> 
> 	(defvar dynmap (make-sparse-keymap))
> 	(define-key dynmap [nil] '(menu-item "foo" data :filter fun))
> 
> Ideally this would also allow multiple such "same-level submaps"
> which would then provide multiple keymap inheritance.
> 
This is very similar to my new proposal for nested keymaps, but
it looks like a hack to use menu-item that way.

> > > So if the dynamism you need is only in the `command-remap' submap,
> > > for example, your new hack is not needed.
> > I don't think this is a hack!
> 
> I said "hack" because I think it's more ad-hoc than it should.
> 
> >   ;; Neat trick from Dave Love to add more bindings in read-only mode:
> >   (add-to-list 'minor-mode-map-alist
> >         `(lambda . (and diff-minor-mode buffer-read-only
> >                    '(diff-minor-mode . ,diff-mode-shared-map))))
> 
> Indeed.
> 
> >       ;; View mode steals RET from us.
> >       (local-set-key [remap View-scroll-line-forward] 'help-follow)
> 
> That one looks completely bogus to me.  Do you really want to prevent
> the use of View-scroll-line-forward from a help-mode buffer even if
> it's bound to something else than RET ?

No, that wasn't the intention ... I must have been sleeping...

> 
> > [Actually, I think I'll install that change in any case].
> 
> Please don't.

I wont.  

But I still think the use of the minor-mode-overriding-map-alist for
this purpose is pretty obscure (although I suspect that is the
purpose for which it was invented...)

An alternative would be to put a keymap property on the link
like this:  [in CVS emacs, keymap properties take precedence over
minor mode keymaps!]

(defun help-xref-button (match-number type &rest args)
  "Make a hyperlink for cross-reference text previously matched.
MATCH-NUMBER is the subexpression of interest in the last matched
regexp.  TYPE is the type of button to use.  Any remaining arguments are
passed to the button's help-function when it is invoked.
See `help-make-xrefs'."
  ;; Don't mung properties we've added specially in some instances.
  (unless (button-at (match-beginning match-number))
    (make-text-button (match-beginning match-number)
                      (match-end match-number)
                      'type type 'help-args args 'keymap help-mode-map)))
                                                 ^^^^^^^^^^^^^^^^^^^^^


> 
> > > I'd rather not add a hack that's specific to minor-mode-map-alist
> > > if we could do the same for all cases instead.
> > 
> > Sure.  But what device do you suggest then?
> >   (keymap :filter fun ...) ?
> > 
> > I don't object to that, but it would be _less_ efficient, since
> > we have to search the keymap for the :filter property (like we do
> > for a menu-item, but that is much shorter)  [unless we ensure
> > it stays at the head of the keymap list].
> 
> I don't care much for efficiency at this stage.

Neither do I !!

> 
> > Also, the keymap lookup code would also have to be careful not to
> > interpret the FUN part as a binding,
> 
> You can force it to be a symbol.

I would prefer not to do that; an alternative would be to put a
cons cell (:filter . FORM) into the keymap, causing the rest of
the keymap to be ignored if FORM returns nil.

Along this line, we could also add (lambda . FORM) in a keymap which
will evaluate FORM to get a nested keymap.

> 
> > and when we add binding to
> > a map, we should be careful not to split the ":filter FUN" pair.
> 
> Of course, it might need some care.  Doing it in get_keymap works
> around the above problem, tho since the keymap that's modified
> is the one returned by get_keymap.

I guess using (:filter . FORM) would make it easier to ensure this.

> 
> > So GC-wise this only makes things marginally worse :-/
> 
> I'd rather try to make it better than to make it marginally worse.

Sure.  

> 
> > > In other words, maybe we shouldn't evaluate the form inside this
> > > current_minor_maps function.
> > I still think it is pretty safe to do so.
> 
> Despite the comment that's just above ?  Do you really think the
> coders went to the trouble of not using xmalloc/xrealloc and of
> sometimes returning an incorrect result (hoping that the cause of
> the problem will cause something else to abort later on) just
> for the fun of it ?

You are right.  I overlooked the finer details of that comment.

> 
> > If some packages decide to fiddle with minor-mode-map-alist when you
> > activate the mode the first time (rather than on load), I don't
> > think an after-load-hook will catch that.
> 
> And if some package decides to fiddle with it from an idle-hook, the
> post-command-hook will fail as well.  The question is not "is it theoretically
> safe" but "is it safe in practice" ?  I believe it'd be good enough in practice
> because I don't see much fiddling of minor-mode-map-alist outside of
> toplevel expressions.

I would be much easier if an element in the minor-mode-map-alist
could be tagged as `keep at head of list'.  IIRC we discussed this
some time ago on this list, and really didn't find a way to
accomplish that.

But maybe such modes could simply put their map on
minor-mode-overriding-map-alist instead ?  Is that "legal practice"?


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12 20:30         ` Stefan Monnier
@ 2002-04-12 22:08           ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-12 22:08 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > But I still think the use of the minor-mode-overriding-map-alist for
> > this purpose is pretty obscure (although I suspect that is the
> > purpose for which it was invented...)
> 
> I still think it's the best solution so far.
> Better than a `keymap' text-property (help-follow also works on non-buttons
> and I care about it, since I wrote the code for it ;-).

What you want to accomplish is that RET runs help-follow in a help
buffer.

But view-mode [accidentally] has a binding for RET which shadows the
help buffer's local binding of RET.

Now, using the minor-mode-overriding-map-alist fixes this, but the
reason I think it is obscure is that it explicitly has to mention
which minor-mode is obscuring its binding...

But after having discussed this with you, I now believe that the
minor-mode-overriding-map-alist *is* the proper way to deal with this
situation, since other minor modes may also [temporarily] rebind RET
for valid reasons, so it is the view-mode binding which must be
specifically overridden.

As always, I appreciate the education.  Thanks!

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-11 22:56 Enhancements to "minor-mode-map-alist" functionality Kim F. Storm
  2002-04-11 22:43 ` Stefan Monnier
@ 2002-04-13 19:05 ` Richard Stallman
  2002-04-13 23:30   ` Kim F. Storm
  1 sibling, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-13 19:05 UTC (permalink / raw)
  Cc: emacs-devel

    - 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

I am surprised that the present facilities can't be used more easily.
Could you explain WHY you think this is necessary?  Perhaps there
is already a better way.

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

Any extension to the keymap mechanism calls for careful thought.
Please don't rush ahead to install any changes there before we
have time to discuss this.

First let's see if change is really needed.  If so, then let's
understand what the problem is.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12  9:31   ` Kim F. Storm
  2002-04-12 13:20     ` Kim F. Storm
  2002-04-12 18:20     ` Stefan Monnier
@ 2002-04-13 19:05     ` Richard Stallman
  2 siblings, 0 replies; 46+ messages in thread
From: Richard Stallman @ 2002-04-13 19:05 UTC (permalink / raw)
  Cc: monnier+gnu/emacs, emacs-devel

    So GC-wise this only makes things marginally worse :-/

We won't install any changes that make this problem marginally worse.
Please do not suggest such a thing.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-13 19:05 ` Richard Stallman
@ 2002-04-13 23:30   ` Kim F. Storm
  2002-04-15 12:34     ` Stefan Monnier
  2002-04-15 21:54     ` Richard Stallman
  0 siblings, 2 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-13 23:30 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     - 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
> 
> I am surprised that the present facilities can't be used more easily.
> Could you explain WHY you think this is necessary?  Perhaps there
> is already a better way.

I'm pretty confiden that there isn't a _better_ way already.
There are various ways to do this with the current facilities, but
none of them are really satisfactory (take a look at viper mode's
frequent checking of the minor-mode-map-alist to see what I mean).

I'm trying to come up with a way to transparently enhance emacs'
ability to "change personality" in a way that can be configured
more statically.

> 
>     2) Allow selection of the active keymaps in the alist to
>     be based on evaluating a form in addition to a simple variable.
> 
> Any extension to the keymap mechanism calls for careful thought.
> Please don't rush ahead to install any changes there before we
> have time to discuss this.

Sure!  I did expect some feedback on this, and although my changes
looks fairly simple, I've already been convinced that my approach
isn't sufficiently generic.

> 
> First let's see if change is really needed.  If so, then let's
> understand what the problem is.

I've tried to explain this several times already...

The fundamental problem is that some modes (like viper and cua) makes
some quite fundamental changes to the way some of the standard keys
works [cua remaps C-c and C-x depending on the current state of the
mark (and other conditions), while viper operates in command or insert
mode].

Although the current facilities are sufficient (99% at least), they
_definitely_ are neither elegant, nor efficient, so I would like emacs
to provide some kind of standard feature to better support such modes.

E.g. for cua, I need to ensure that those 7 keymaps are in the front
of minor-mode-map-alist after every command, and I need to set 7
different variables based on the current state so that the next
command can be interpreted correctly... and then I have to be careful
to modify that state if a timer is run which changes the state [which
isn't always possible in theory, although I haven't seen the problem
in practice.]

I'm thinking about other ways to do this...

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
       [not found]           ` <200204122021.g3CKLh217680@rum.cs.yale.edu>
@ 2002-04-14 22:32             ` Kim F. Storm
  2002-04-16 20:18               ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-14 22:32 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > > I like this idea so much that I have implemented it already, but
> > > for the purpose of multiple inheritance and to get rid of the infamous
> > > fix_submap_inheritance ugliness.  It requires several non-trivial
> > > changes, tho.  And I haven't finished taking care of all the "problems"
> > > it introduces (not all of them need to be addressed right away: for
> > > example, it doesn't work for menus yet).
> > 
> > Very good.  When can I expect to see this in the tree (so I can use it?)
> 
> I'd say "not very sooon".  I can send you the code, if you want to try it out.
> There are several issues as well as details about the implementation that
> some developers might object to, so it's not clear that it would be accepted.
> For example, access_keymap can now allocate cons cells to build the
> return value (and often does).


What about a very different approach:

1) We define a keymap as a list

        (keymap PROPS &rest bindings)

   where [PROPS] is an optional vector with 3 elements:

        [FILTER SUBMAPS PARENT]

   FILTER is a form which is eval'ed to determine whether this
   bindings in keymap should be used or ignored

   SUBMAPS is a list of keymaps which are used at the same
   level as the bindings of this keyamp, but comes before those
   bindings.

   PARENT is the parent keymap (or nil) which is the parent
   keymap if this keymap.


2) We modify current_minor_maps to return a array of active keymaps
   which includes _all_ the submaps and parent maps of any of the
   active keymaps.

   The keymaps are added in the proper order, (i.e. for each keymap
   first the submaps (and any submaps of those etc), then then map
   itself, and finally the parent map).

   If we do this, the existing keymap lookup functionality will take
   care of (among other things) multiple submap inheritance.  [and
   it should NOT bother looking at the submaps or the parent maps,
   as they are included in the maps list.


3) I understand that there is a problem with evaling code which may
   do consing in current_minor_maps, but for most practical
   applications I would suppose that this isn't necessary.

   So maybe we can just restrict the FILTER forms/functions to
   not being allowed to do consing and document this restriction
   in the set-keymap-filter function.

4) If this is not acceptable [why not?], the interpretation of the
   FILTER functions must be done by the callers before actually using
   a keymap -- this is of course possible, but complicates the code
   (as we would then need to return the 'nesting level' of the
   keymaps in the returned maps array, so we can skip submaps of
   ignored maps).

5) It could be considered to rename current_minor_maps to
   current_maps and expand it to include the keymap and local-map
   property maps, the buffer local map, and the global map
   in the returned maps array.  This would simplify the
   callers of current_minor_maps, and it would also allow
   the global map, buffer local maps, and property keymaps
   to have (conditioned) submaps and a parent keymap. 

I haven't had time to consider all the implications of this on
the rest of the code, but besides the trivial changes needed
to cope with the addition of the [PROPS] vector to keymaps,
there are probably a few places where a little extra work
is needed to get things to work smoothly.

But maybe current_maps will use a helper function which
can cope with expanding a single keymap into an array
of submaps, and if necessary, other parts of the code
can use this.

Any interest in investigating these ideas further, or do you
think it is a(nother) dead end?

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-12 18:46       ` Stefan Monnier
       [not found]         ` <5xofgoobzr.fsf@kfs2.cua.dk>
@ 2002-04-14 23:11         ` Kim F. Storm
  1 sibling, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-14 23:11 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> > 
> > I can easily ensure that cua-mode-map stays at the beginning of
> > minor-mode-map-alist [will be simple in a post-command hook, or maybe
> > by adding it to minor-mode-overriding-map-alist :-) ]
> 
> I don't understand.  In what way is it easier ?
> It still seems like you need some kind of post-command-hook thingy.

In any case, I would like to get cua into CVS, so I'll stick to using
the existing minor-mode-map-alist (through the post-command-hook) for
the time being.

If and when better alternatives become available, I'll switch to using
that.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  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
  1 sibling, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-15 12:34 UTC (permalink / raw)
  Cc: emacs-devel

> The fundamental problem is that some modes (like viper and cua) makes
> some quite fundamental changes to the way some of the standard keys
> works [cua remaps C-c and C-x depending on the current state of the
> mark (and other conditions), while viper operates in command or insert
> mode].

BTW: some code in keyboard.c does something very much like function-key-map,
except in a hard-coded way (drop down-mouse events if they're unbound,
turn doube-clicks into single clicks if unbound, turn upper case into
lower case if unbound, my own local code has added down-modifier
and up-modifier events (I wanted to see if we could get a behavior
similar to Windows' Alt-TAB thingy which requires catching the up-Alt
event) and has correspondingly added code to drop those modifiers
if they're not bound, ...).
I was thinking of adding some kind of predicate binding, halfway
between normal bindings and default bindings.  Something like

	(define-key function-key-map [uppercase-p] 'map-to-lowercase)

where uppercase-p is a function that takes an event and returns a boolean.
In your case maybe you could save some keymap handling by doing something like

	(define-key cua-mode-map [conditional-control-x] 'cua-cut)

where conditional-control-x returns non-nil iff the event is C-x and
the mark is active.  Or maybe in your specific case we could more
simply reuse something existing:

	(define-key cua-mode-map [?\C-x]
	  '(menu-item "cut" 'cua-cut :enable mark-active))

Making this work might be a simple matter of a few lines in get_keyelt.


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-13 23:30   ` Kim F. Storm
  2002-04-15 12:34     ` Stefan Monnier
@ 2002-04-15 21:54     ` Richard Stallman
  2002-04-15 23:55       ` Kim F. Storm
  1 sibling, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-15 21:54 UTC (permalink / raw)
  Cc: emacs-devel

    > I am surprised that the present facilities can't be used more easily.
    > Could you explain WHY you think this is necessary?  Perhaps there
    > is already a better way.

    I'm pretty confiden that there isn't a _better_ way already.

Would you please explain to me why not?
Before I agree that we need a new feature,
I want to make sure we have not overlooked an
existing good solution.  Please show the reasons
why (you believe) these 7 keymaps are the only way.

    E.g. for cua, I need to ensure that those 7 keymaps are in the front
    of minor-mode-map-alist after every command,

The first question is why you need 7 keymaps at all.  Why isn't one
enough?  Why can't one key binding for a given key sequence handle all
the various different circumstances, through conditionals in the code?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-15 21:54     ` Richard Stallman
@ 2002-04-15 23:55       ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-15 23:55 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     > I am surprised that the present facilities can't be used more easily.
>     > Could you explain WHY you think this is necessary?  Perhaps there
>     > is already a better way.
> 
>     I'm pretty confiden that there isn't a _better_ way already.
> 
> Would you please explain to me why not?
> Before I agree that we need a new feature,
> I want to make sure we have not overlooked an
> existing good solution.  Please show the reasons
> why (you believe) these 7 keymaps are the only way.

They are not the only way!

In the CUA mode I've been promoting for the last few years I use
(only) three keymaps, a pretty complicated pre-command-hook to select
the proper keymap (to emulate the equivalent to the new command
remapping feature!), and a very ugly/messy piece of code bound to C-c
and C-x in the key-translation-map.

In addition, most functions are pretty overloaded with conditionals
to select the "proper action" for the current state.

With the new code I've written to use the new command remapping, and
the 7 keymaps, the code is _much_ simpler, as all the conditional code
is now moved out of the functions and centralized around selecting the
proper keymaps based on the current state.

I know for sure that using 7 keymaps is a vast improvement to the
old code which has been increasingly complex to maintain, so I definitely
didn't want to include that code with the emacs base.

> 
>     E.g. for cua, I need to ensure that those 7 keymaps are in the front
>     of minor-mode-map-alist after every command,
> 
> The first question is why you need 7 keymaps at all.  Why isn't one
> enough?  Why can't one key binding for a given key sequence handle all
> the various different circumstances, through conditionals in the code?

I did that to some extent in the old version of CUA.  I don't want
to repeat that mistake (in this context), as it contributed significantly
to the complexity of the old code.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-14 22:32             ` Kim F. Storm
@ 2002-04-16 20:18               ` Richard Stallman
  2002-04-16 22:34                 ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-16 20:18 UTC (permalink / raw)
  Cc: emacs-devel

       SUBMAPS is a list of keymaps which are used at the same
       level as the bindings of this keyamp, but comes before those
       bindings.

What does that mean?
What problem is it meant to solve?

    3) I understand that there is a problem with evaling code which may
       do consing in current_minor_maps, but for most practical
       applications I would suppose that this isn't necessary.

       So maybe we can just restrict the FILTER forms/functions to
       not being allowed to do consing and document this restriction
       in the set-keymap-filter function.

There is no way to implement such a restriction,
and users don't generally know which functions do consing.

What we should do is make this code work correctly.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-16 20:18               ` Richard Stallman
@ 2002-04-16 22:34                 ` Kim F. Storm
  2002-04-18 18:46                   ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-16 22:34 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>        SUBMAPS is a list of keymaps which are used at the same
>        level as the bindings of this keyamp, but comes before those
>        bindings.
> 
> What does that mean?

Consider a keymap K which has a binding for [C-x 1],
a keymap P which has a binding for [C-x 2], and
a keymap S which has a binding for [C-x 3].

Keymap S has a filter which means that it is only active
if mark-active is non-nil.

Now, we want keymap P to be a parent map for K, and
we want S to be a submap of K.

With my proposal, C-x 1, C-x 2, and (if mark-active) C-x 3 will all
work seemlessly *without* having to rely on fix_submap_inheritance
(which only works for one submap [the parent map] anyway).


> What problem is it meant to solve?

Multiple keymap inheritance as well as conditional keymaps.

> 
>     3) I understand that there is a problem with evaling code which may
>        do consing in current_minor_maps, but for most practical
>        applications I would suppose that this isn't necessary.
> 
>        So maybe we can just restrict the FILTER forms/functions to
>        not being allowed to do consing and document this restriction
>        in the set-keymap-filter function.
> 
> There is no way to implement such a restriction,
> and users don't generally know which functions do consing.

This is not intended to be a user feature, it is for package
writers. 

I didn't think we should `implement' the restriction -- simply
document it.  It could be a fairly short list of
`safe' functions to apply to variables, e.g. 
and, or, not, if, eq, equal, quote,
member, memq, get, assoc, car, cdr, aref, 
=, /=, >, >=, <, <=,
symbolp, numberp, vectorp, timerp, (etc)
boundp, fboundp, featurep, (etc)

I believe this would cover all practical purposes, so I don't see why
we need to make a significantly more complex solution to handle some
theoritical cases.

> 
> What we should do is make this code work correctly.
> 

If you still think this is what you think is necessary,
one solution could be:

- memory_full set a global variable 'out-of-memory'.

- the command loop will (somehow) determine whether
  the out-of-memory condition is no longer present
  e.g.
        if (out_of_memory)
          {
            void *tem = malloc(100000);
            if (tem)
              {
                out_of_memory = 0;
                free(tem);
              }
          }

- if out_of_memory is set, the current_maps function will not evaluate
  the keymap filters, but just assume they evaluate to the most recent
  result of evaluting the filter.


*) I proposed to use a vector [FILTER SUBMAPS PARENT] for the keymap
properties.  This could easily be extended to store the result of the
most recent evaluation of the FILTER, e.g.
        [FILTER FRES SUBMAPS PARENT]

where current_maps would store the result of eval'ing FILTER in
FRES.

Maybe not a perfect solution, but I believe it would work well enough
for this particular purpose (after all, running out of memory
fortunately isn't something we experience every day [anymore]).

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-15 12:34     ` Stefan Monnier
@ 2002-04-17 16:03       ` Richard Stallman
  0 siblings, 0 replies; 46+ messages in thread
From: Richard Stallman @ 2002-04-17 16:03 UTC (permalink / raw)
  Cc: storm, emacs-devel

We could consider replacing part of the command loop or the keymap
lookup with Lisp code.  That should make it easier to extend, and
eliminate any tricky requirements about consing.  On the other hand,
it might cause increased storage use.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-16 22:34                 ` Kim F. Storm
@ 2002-04-18 18:46                   ` Richard Stallman
  2002-04-18 23:07                     ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-18 18:46 UTC (permalink / raw)
  Cc: emacs-devel

    Consider a keymap K which has a binding for [C-x 1],
    a keymap P which has a binding for [C-x 2], and
    a keymap S which has a binding for [C-x 3].

    Keymap S has a filter which means that it is only active
    if mark-active is non-nil.

    Now, we want keymap P to be a parent map for K, and
    we want S to be a submap of K.

Why do we want that?  What job are you trying to do?

    With my proposal, C-x 1, C-x 2, and (if mark-active) C-x 3 will all
    work seemlessly

What does it mean for them to "work"?  Once again, what job
are you trying to do?  It is not useful to address this backwards.

We must not introduce more complex features merely because they look
appealing in the abstract.  We have to look at the job first, then
determine how much complexity is really *necessary*.

    > What problem is it meant to solve?

    Multiple keymap inheritance as well as conditional keymaps.

Multiple inheritance is a mess.  We should avoid it if we can.

    > There is no way to implement such a restriction,
    > and users don't generally know which functions do consing.

    This is not intended to be a user feature, it is for package
    writers. 

I know which users this feature is for.  The users of Emacs Lisp
don't generally know which functions do consing.  That can change.

    I didn't think we should `implement' the restriction -- simply
    document it.

No way.

This proposal includes many aspects each of which is very undesirable.
The entire approach is wrong.  We need to start by looking at the actual
problem that we actually need to solve.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  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 18:42                       ` Richard Stallman
  0 siblings, 2 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-18 23:07 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     Consider a keymap K which has a binding for [C-x 1],
>     a keymap P which has a binding for [C-x 2], and
>     a keymap S which has a binding for [C-x 3].
> 
>     Keymap S has a filter which means that it is only active
>     if mark-active is non-nil.
> 
>     Now, we want keymap P to be a parent map for K, and
>     we want S to be a submap of K.
> 
> Why do we want that?  What job are you trying to do?

I've described that several times by now -- I'm trying to find the
right approach to address the issues with complex modes which uses a
lot of keymaps (like cua and viper) and base the selection between
those keymaps on combining various state information, i.e. to provide
a more versatile keymap functionality than what is currently
available.

I think I have ironed this out for cua by now via a (tedious)
post-command-hook to do this through minor-mode-map-alist, but where I
could just condition a keymap with `mark-active' if the decision is
made when a key is actually processed, I need an expression like (and
mark-active (not deactivate-mark)) in the post-command-hook -- and
hope that nothing else changes the mark state under my feet....

Here is the current cua code where the cua--fix-keymaps function is run
by the post-command-hook after every command:

now>    (defvar cua-global-keymap (make-sparse-keymap))
now>    (defvar cua--cua-keys-keymap (make-sparse-keymap))
now>    (defvar cua--prefix-override-keymap (make-sparse-keymap))
now>    (defvar cua--prefix-repeat-keymap (make-sparse-keymap))
now>    (defvar cua--global-mark-keymap (make-sparse-keymap))
now>    (defvar cua--rectangle-keymap (make-sparse-keymap))
now>    (defvar cua--region-keymap (make-sparse-keymap))
now>    
now>    (defvar cua--ena-cua-keys-keymap nil)
now>    (defvar cua--ena-prefix-override-keymap nil)
now>    (defvar cua--ena-prefix-repeat-keymap nil)
now>    (defvar cua--ena-region-keymap nil)
now>    (defvar cua--ena-global-mark-keymap nil)
now>    
now>    (defvar cua--mmap-prefix-override-keymap (cons 'cua--ena-prefix-override-keymap cua--prefix-override-keymap))
now>    (defvar cua--mmap-prefix-repeat-keymap (cons 'cua--ena-prefix-repeat-keymap cua--prefix-repeat-keymap))
now>    (defvar cua--mmap-cua-keys-keymap (cons 'cua--ena-cua-keys-keymap cua--cua-keys-keymap))
now>    (defvar cua--mmap-global-mark-keymap (cons 'cua--ena-global-mark-keymap cua--global-mark-keymap))
now>    (defvar cua--mmap-rectangle-keymap (cons 'cua--rectangle cua--rectangle-keymap))
now>    (defvar cua--mmap-region-keymap (cons 'cua--ena-region-keymap cua--region-keymap))
now>    (defvar cua--mmap-global-keymap (cons 'cua-mode cua-global-keymap))
now>    
now>    (defvar cua--mmap-list
now>      (list cua--mmap-prefix-override-keymap
now>    	cua--mmap-prefix-repeat-keymap
now>    	cua--mmap-cua-keys-keymap
now>    	cua--mmap-global-mark-keymap
now>    	cua--mmap-rectangle-keymap
now>    	cua--mmap-region-keymap
now>    	cua--mmap-global-keymap))
now>    
now>    (defun cua--fix-keymaps (disable)
now>      ;; Ensure that cua's keymaps are in minor-mode-map-alist and
now>      ;; in the correct order, and set control variables.
now>      (let (fix
now>    	(mmap minor-mode-map-alist)
now>    	(ml cua--mmap-list))
now>        (while (and (not fix) mmap ml)
now>          (if (not (eq (car mmap) (car ml)))
now>    	  (setq fix t)
now>    	(setq mmap (cdr mmap)
now>    	      ml (cdr ml))))
now>        (if ml
now>    	(setq fix t))
now>        (when (or fix disable)
now>          (setq ml cua--mmap-list)
now>          (while ml
now>    	(setq minor-mode-map-alist (delq (car ml) minor-mode-map-alist))
now>    	(setq ml (cdr ml))))
now>        (when (and fix (not disable))
now>          (setq minor-mode-map-alist
now>    	    (append (copy-sequence cua--mmap-list) minor-mode-map-alist))))
now>      (setq cua--ena-region-keymap
now>    	(and mark-active (not deactivate-mark)))
now>      (setq cua--ena-prefix-override-keymap
now>    	(and cua--ena-region-keymap
now>    	     cua-enable-cua-keys
now>    	     (or (eq cua-enable-cua-keys t)
now>    		 (not cua--explicit-region-start))
now>    	     (not executing-kbd-macro)
now>    	     (not cua--prefix-override-timer)))
now>      (setq cua--ena-prefix-repeat-keymap
now>    	(and cua--ena-region-keymap
now>    	     (timerp cua--prefix-override-timer)))
now>      (setq cua--ena-cua-keys-keymap
now>    	(and cua-enable-cua-keys
now>    	     (or (eq cua-enable-cua-keys t)
now>    		 cua--last-region-shifted)))
now>      (setq cua--ena-global-mark-keymap
now>    	(and cua--global-mark-active
now>    	     (not (window-minibuffer-p)))))

to the code as it would look like with a dynamic setup via the
proposed emulation-mode-map-alists (andn nothing is needed in the
post-command-hook):

emma>   (defvar cua-global-keymap (make-sparse-keymap))
emma>   (defvar cua--cua-keys-keymap (make-sparse-keymap))
emma>   (defvar cua--prefix-override-keymap (make-sparse-keymap))
emma>   (defvar cua--prefix-repeat-keymap (make-sparse-keymap))
emma>   (defvar cua--global-mark-keymap (make-sparse-keymap)) ; Initalized when cua-gmrk.el is loaded
emma>   (defvar cua--rectangle-keymap (make-sparse-keymap))   ; Initalized when cua-rect.el is loaded
emma>   (defvar cua--region-keymap (make-sparse-keymap))
emma>   
emma>   (setq emulation-mode-map-alists
emma>         (cons
emma>   	`((lambda . (and mark-active
emma>   			 cua-enable-cua-keys
emma>   			 (or (eq cua-enable-cua-keys t)
emma>   			     (not cua--explicit-region-start))
emma>   			 (not executing-kbd-macro)
emma>   			 (not cua--prefix-override-timer)
emma>   			 '(cua--prefix-override . ,cua--prefix-override-keymap)))
emma>   	  (lambda . (and mark-active
emma>   			 (timerp cua--prefix-override-timer)
emma>   			 '(cua--prefix-override . ,cua--prefix-repeat-keymap)))
emma>   	  (lambda . (and cua-enable-cua-keys
emma>   			 (or (eq cua-enable-cua-keys t)
emma>   			     cua--last-region-shifted)
emma>   			 '(cua-enable-cua-keys . ,cua--cua-keys-keymap)))
emma>   	  (lambda . (and cua--global-mark-active
emma>   			 (not (window-minibuffer-p))
emma>   			 '(cua--global-mark-active . ,cua--global-mark-keymap)))
emma>   	  (cua--rectangle . ,cua--rectangle-keymap)
emma>   	  (mark-active . ,cua--region-keymap)
emma>   	  (cua-mode . ,cua-global-keymap))
emma>           emulation-mode-map-alists))


> 
>     With my proposal, C-x 1, C-x 2, and (if mark-active) C-x 3 will all
>     work seemlessly
> 
> What does it mean for them to "work"?  Once again, what job
> are you trying to do?  It is not useful to address this backwards.
> 

I have N keymaps which all make bindings starting with C-x -- and I want
all of those bindings to "work".

I tried the `simple' approach by putting these keymaps into the proposed
`emulation-mode-map-alists', but that idea was turned down.  

If it wasn't for the problem evalling code in the current_minor_maps
function [I believe there are ways to solve that], would that solution
be acceptable?


> We must not introduce more complex features merely because they look
> appealing in the abstract.  We have to look at the job first, then
> determine how much complexity is really *necessary*.
> 
>     > What problem is it meant to solve?
> 
>     Multiple keymap inheritance as well as conditional keymaps.
> 
> Multiple inheritance is a mess.  We should avoid it if we can.

But the `parent keymap' inheritance is already pretty messy.
A clean way to add multiple inheritance would fix that!

Stefan told me he was working on a way to support things like this,
but it had a number of problems (such as unnecessary consing), so I
made another proposal (which doesn't do consing), but has other
implications...  


> 
>     > There is no way to implement such a restriction,
>     > and users don't generally know which functions do consing.
> 
>     This is not intended to be a user feature, it is for package
>     writers. 
> 
> I know which users this feature is for.  The users of Emacs Lisp
> don't generally know which functions do consing.  That can change.
> 
>     I didn't think we should `implement' the restriction -- simply
>     document it.
> 
> No way.

Ok.

> 
> This proposal includes many aspects each of which is very undesirable.
> The entire approach is wrong.  We need to start by looking at the actual
> problem that we actually need to solve.

Ok, that's what I've tried to do all along!  I've already described it
several times now, so what aspects of the problem are still unclear?

So, please look at the problem!

You (and others) don't approve of the proposals I've made to solve
this.  That's ok, but then I ask you to come up with a better proposal
which deals with the problem at hand.

Thank you!

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  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 18:42                       ` Richard Stallman
  1 sibling, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-19 13:43 UTC (permalink / raw)
  Cc: rms, emacs-devel

> I've described that several times by now -- I'm trying to find the
> right approach to address the issues with complex modes which uses a
> lot of keymaps (like cua and viper) and base the selection between
> those keymaps on combining various state information, i.e. to provide
> a more versatile keymap functionality than what is currently
> available.

I haven't heard any comment about my proposal to use `menu-item'
bindings with a :enable setting in order to get conditional bindings
(this doesn't currently work, but it should be pretty easy to make
it work).
Would it help you solve your problems ?


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-19 15:36                         ` Kim F. Storm
@ 2002-04-19 14:46                           ` Stefan Monnier
  2002-04-21 17:46                             ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-19 14:46 UTC (permalink / raw)
  Cc: Stefan Monnier, emacs-devel

> "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> 
> > > I've described that several times by now -- I'm trying to find the
> > > right approach to address the issues with complex modes which uses a
> > > lot of keymaps (like cua and viper) and base the selection between
> > > those keymaps on combining various state information, i.e. to provide
> > > a more versatile keymap functionality than what is currently
> > > available.
> > 
> > I haven't heard any comment about my proposal to use `menu-item'
> > bindings with a :enable setting in order to get conditional bindings
> > (this doesn't currently work, but it should be pretty easy to make
> > it work).
> > Would it help you solve your problems ?
> 
> Considering that cua has approx 100 bindings in 7 keymaps,
> it seems like absolute overkill IMO to condition each of those
> 100 bindings individually instead of just the 7 keymaps which
> contain those bindings...

Is that 7*100 bindings or 7*14 bindings ?
How much overlap ?
How many different conditions would there be ?
For the sake of describe-key, I think it's better to have fewer bindings
(with the dispatch done more often in the bound function rather
than in the :enable conditionals) so that the docstring can describe what
happens when.


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-19 13:43                       ` Stefan Monnier
@ 2002-04-19 15:36                         ` Kim F. Storm
  2002-04-19 14:46                           ` Stefan Monnier
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-19 15:36 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > I've described that several times by now -- I'm trying to find the
> > right approach to address the issues with complex modes which uses a
> > lot of keymaps (like cua and viper) and base the selection between
> > those keymaps on combining various state information, i.e. to provide
> > a more versatile keymap functionality than what is currently
> > available.
> 
> I haven't heard any comment about my proposal to use `menu-item'
> bindings with a :enable setting in order to get conditional bindings
> (this doesn't currently work, but it should be pretty easy to make
> it work).
> Would it help you solve your problems ?

Considering that cua has approx 100 bindings in 7 keymaps,
it seems like absolute overkill IMO to condition each of those
100 bindings individually instead of just the 7 keymaps which
contain those bindings...

I don't think that is a _better_ solution.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-18 23:07                     ` Kim F. Storm
  2002-04-19 13:43                       ` Stefan Monnier
@ 2002-04-19 18:42                       ` Richard Stallman
  2002-04-19 22:05                         ` Kim F. Storm
  1 sibling, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-19 18:42 UTC (permalink / raw)
  Cc: emacs-devel

    > Why do we want that?  What job are you trying to do?

    I've described that several times by now

Not specifically enough that I can try to determine
whether there is another way to do the job.

     -- I'm trying to find the
    right approach to address the issues with complex modes which uses a
    lot of keymaps (like cua and viper) and base the selection between
    those keymaps on combining various state information

Selecting between keymaps is one possible avenue for doing a certain
job.  Before we assume it should be done this way, what are the other
avenues?  What is the job?

    I have N keymaps which all make bindings starting with C-x -- and I want
    all of those bindings to "work".

What job are these bindings supposed to *do*?  Given time I could
figure that out from the code you sent, but I don't have that time.

    If it wasn't for the problem evalling code in the current_minor_maps
    function [I believe there are ways to solve that], would that solution
    be acceptable?

Not necessarily.  It would still be a big extension in an area where
the code is already too complex.  Multiple inheritance is inherently a
mess.  Once it was added, it would probably require subsequent work to
fix bugs or to add more features so people can "fully use" it.

    > Multiple inheritance is a mess.  We should avoid it if we can.

    But the `parent keymap' inheritance is already pretty messy.

That is why we should not make it any hairier.

Please don't use arguments of the form "We already have this kind of
problem, therefore it it doesn't matter if we add to it."  That is the
wrong approach for any serious problem, and I can promise you I will
say no.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-19 18:42                       ` Richard Stallman
@ 2002-04-19 22:05                         ` Kim F. Storm
  2002-04-20 17:27                           ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-19 22:05 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

> 
>      -- I'm trying to find the
>     right approach to address the issues with complex modes which uses a
>     lot of keymaps (like cua and viper) and base the selection between
>     those keymaps on combining various state information
> 
> Selecting between keymaps is one possible avenue for doing a certain
> job.  Before we assume it should be done this way, what are the other
> avenues?  What is the job?

Consider C-x.

Normally, it works as a prefix key for things like C-x C-f etc.

Basically, with cua, if the mark is active, hitting C-x starts a 0.2 seconds timer.

If the timer runs out, C-x works like C-w (kill-ring-save).

If the user enters another C-x within those 0.2 seconds, the first C-x
is ignored and the second C-x works like a normal prefix key.

Also if the user enters another key, e.g. C-f, within those 0.2 seconds,
the first C-x now works like a prefix key, i.e. as C-x C-f.

[all of this was discussed a year ago as ways to let the user circumvent
cua's C-x handling].

The actual interpretation of C-x is done via three of cua's 7 keymaps.


To complicate things, cua also supports rectangles and a global mark, which
all work using the same command set as is used for the region, e.g. you
also use C-x (or C-w) to kill the rectangle  (and C-y to insert it), or
if the global mark is set, C-x will move the selected region or rectangle
to the global mark position...

To facilitate this, three more keymaps are used which selectively does
command remapping of `kill-ring-save' to handle either region, rectangle,
or the global mark.

The final keymap is used to allow users to take advantage of cua's
uniform command set for rectangles (and the global mark), but still
continue to use C-w, M-w and C-y instead of C-x, C-c, and C-v (which
are the normal cua bindings).


Having gone through a major overhaul of the cua code, I can definitely
say that basing this on multiple minor-mode keymaps is a major improvement.
The primary advantage is that code is much simpler to maintain now.

> 
>     I have N keymaps which all make bindings starting with C-x -- and I want
>     all of those bindings to "work".
> 
> What job are these bindings supposed to *do*?  Given time I could
> figure that out from the code you sent, but I don't have that time.
> 
Ok, but considering that I've spent more than 200 hours on this project
maybe you could give my views some weight -- I have tried various alternatives
to the current approach, and it is by far the best approach so far!!

>     If it wasn't for the problem evalling code in the current_minor_maps
>     function [I believe there are ways to solve that], would that solution
>     be acceptable?
> 
> Not necessarily.  It would still be a big extension in an area where
> the code is already too complex.  Multiple inheritance is inherently a
> mess.  Once it was added, it would probably require subsequent work to
> fix bugs or to add more features so people can "fully use" it.


The emulation-mode-map-alist and conditioned keymaps doesn't add
multiple inheritance  (that was part of my other proposal, once the
emulation-mode-map-alist idea was rejected).  It is primarily a
way for packages like cua to be able to configure its (multiple)
keymaps once and for all without worrying about other packages
messing them up.

I don't see why this is a significant complication.

And what ever errors is potentially associated with it, I feel
confident I can fix.

> 
>     > Multiple inheritance is a mess.  We should avoid it if we can.
> 
>     But the `parent keymap' inheritance is already pretty messy.
> 
> That is why we should not make it any hairier.
> 
> Please don't use arguments of the form "We already have this kind of
> problem, therefore it it doesn't matter if we add to it."  That is the
> wrong approach for any serious problem, and I can promise you I will
> say no.
> 

Ok, since this wasn't really an issue with my initial proposal (the
emulation-mode-map-alist), I will leave it to Stefan to defend any
changes added for the purpose of multiple inheritance.

Please do not confuse my requirements for cua with multiple
inheritance issues.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-19 22:05                         ` Kim F. Storm
@ 2002-04-20 17:27                           ` Richard Stallman
  2002-04-21 11:08                             ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-20 17:27 UTC (permalink / raw)
  Cc: emacs-devel

    The actual interpretation of C-x is done via three of cua's 7 keymaps.

Using separate keymaps for C-x seems reasonable.

I wonder, though, why simply putting all three in minor-mode-map-alist
won't do the job.  As I recall, if any active keymap defines a binding
with a non-prefix definition, that should override all prefix
definitions regardless of the precedence order of the maps.  Is that
not true now?  If not, maybe we could make it true again.  So there is
no need to worry about the relative order of your maps and all other
maps.

If you need to condition some of these maps on some symbol's being
false, then we could make the minimal extension so far proposed, which
is to allow minor-mode-map-alist (or another new alist) to have
conditions which are more complex than just a symbol.  But you do see
if you can easily get away without that.

    To facilitate this, three more keymaps are used which selectively does
    command remapping of `kill-ring-save' to handle either region, rectangle,
    or the global mark.

It would be cleaner to define a single new command for that purpose.

    The final keymap is used to allow users to take advantage of cua's
    uniform command set for rectangles (and the global mark), but still
    continue to use C-w, M-w and C-y instead of C-x, C-c, and C-v (which
    are the normal cua bindings).

Which characters does this map redefine?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-20 17:27                           ` Richard Stallman
@ 2002-04-21 11:08                             ` Kim F. Storm
  2002-04-22  7:47                               ` Richard Stallman
                                                 ` (2 more replies)
  0 siblings, 3 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-21 11:08 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     The actual interpretation of C-x is done via three of cua's 7 keymaps.
> 
> Using separate keymaps for C-x seems reasonable.
> 
> I wonder, though, why simply putting all three in minor-mode-map-alist
> won't do the job.  As I recall, if any active keymap defines a binding
> with a non-prefix definition, that should override all prefix
> definitions regardless of the precedence order of the maps.  Is that
> not true now?  If not, maybe we could make it true again. 

I wasn't aware of this functionality.  I'll see if it is true now.

> So there is
> no need to worry about the relative order of your maps and all other
> maps.
> 

There are other cases where the ordering of those maps matters, but I
might be able to further limit the dependence on the ordering (by
making sure only one condition is true at a time), but I would still
prefer if I could just rely on having my own (separate)
cua-minor-mode-map-alist (on the emulation-mode-map-alists list), and
be sure that noone would mess with it.  And since I've already implemented
it, I know the change to add emulation-mode-map-alists is trivial!


> If you need to condition some of these maps on some symbol's being
> false, then we could make the minimal extension so far proposed, which
> is to allow minor-mode-map-alist (or another new alist) to have
> conditions which are more complex than just a symbol.  But you do see
> if you can easily get away without that.

If we don't allow some form of simple logical expression [e.g. the
functions I listed in a previous mail], I really don't see any
alternative to the present code cua (and viper) which refreshes a list
of state variables and fixes any ordering problems in
minor-mode-map-alist after each command.

> 
>     To facilitate this, three more keymaps are used which selectively does
>     command remapping of `kill-ring-save' to handle either region, rectangle,
>     or the global mark.
> 
> It would be cleaner to define a single new command for that purpose.

I don't agree.  There are many other commands which are specific for
the region, rectangle, and global mark cases, and handling those in
separate functions is a lot clearer (to me).

Actually, the new cua package consists of three files now: 
        cua-base.el  (for the basic functionality and region handling)
        cua-rect.el  (for rectangle commands)
        cua-gmrk.el  (for the global mark functionality)


> 
>     The final keymap is used to allow users to take advantage of cua's
>     uniform command set for rectangles (and the global mark), but still
>     continue to use C-w, M-w and C-y instead of C-x, C-c, and C-v (which
>     are the normal cua bindings).
> 
> Which characters does this map redefine?
> 

C-z -> undo, C-v -> yank

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-19 14:46                           ` Stefan Monnier
@ 2002-04-21 17:46                             ` Kim F. Storm
  2002-04-22  9:28                               ` Stefan Monnier
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-21 17:46 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> > > I haven't heard any comment about my proposal to use `menu-item'
> > > bindings with a :enable setting in order to get conditional bindings
> > > (this doesn't currently work, but it should be pretty easy to make
> > > it work).
> > > Would it help you solve your problems ?
> > 
> > Considering that cua has approx 100 bindings in 7 keymaps,
> > it seems like absolute overkill IMO to condition each of those
> > 100 bindings individually instead of just the 7 keymaps which
> > contain those bindings...
> 
> Is that 7*100 bindings or 7*14 bindings ?

It is 8 + 7 + 2 + 10 + 17 + 60 + 16 bindings...

> How much overlap ?

None.

> How many different conditions would there be ?

There are 7 different conditions.

> For the sake of describe-key, I think it's better to have fewer bindings
> (with the dispatch done more often in the bound function rather
> than in the :enable conditionals) so that the docstring can describe what
> happens when.

I don't think you will see any difference whether this is done
via conditions in the minor-mode-map-alist (or emulation-mode-map-alist),
or by conditioning each command individually.

Also, I don't see why it is better to eval the various conditions 100 times
rather than just 7 times?

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  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-22 22:36                               ` Richard Stallman
  2 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-22  7:47 UTC (permalink / raw)
  Cc: emacs-devel

    >     To facilitate this, three more keymaps are used which selectively does
    >     command remapping of `kill-ring-save' to handle either region, rectangle,
    >     or the global mark.
    > 
    > It would be cleaner to define a single new command for that purpose.

    I don't agree.  There are many other commands which are specific for
    the region, rectangle, and global mark cases, and handling those in
    separate functions is a lot clearer (to me).

You said that the function of these maps is to remap
`kill-ring-save'.  I based my comment on what you said.
Rather than remap `kill-ring-save', which is the usual
key binding of M-w, I think it would be cleaner to bind M-w
to one new command.

What do these "many other commands" have to do with remapping
`kill-ring-save'?  I don't see the connection.  Do these three maps do
something else besides remap `kill-ring-save'?  If so, would you
please say precisely what other jobs they do?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-21 17:46                             ` Kim F. Storm
@ 2002-04-22  9:28                               ` Stefan Monnier
  2002-04-22 15:15                                 ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Stefan Monnier @ 2002-04-22  9:28 UTC (permalink / raw)
  Cc: Stefan Monnier, emacs-devel

> "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> 
> > > "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> > > > I haven't heard any comment about my proposal to use `menu-item'
> > > > bindings with a :enable setting in order to get conditional bindings
> > > > (this doesn't currently work, but it should be pretty easy to make
> > > > it work).
> > > > Would it help you solve your problems ?
> > > 
> > > Considering that cua has approx 100 bindings in 7 keymaps,
> > > it seems like absolute overkill IMO to condition each of those
> > > 100 bindings individually instead of just the 7 keymaps which
> > > contain those bindings...
> > 
> > Is that 7*100 bindings or 7*14 bindings ?
> 
> It is 8 + 7 + 2 + 10 + 17 + 60 + 16 bindings...

So, more like 7*14.
How many of those bindings are in submaps (rather in the toplevel maps)
such that the :enable condition could be put on the prefix and thus shared ?

> > How much overlap ?
> None.

You mean that C-x is only bound in one of those 7 keymaps ?
But if there's no overlap, then the order of those maps relative
to each other is irrelevant.

> > How many different conditions would there be ?
> There are 7 different conditions.

If there's really no overlap and thus only 7 conditions, then the only
difference between my proposal and yours is that in my proposition
the condition is put on each binding inside the toplevel map rather
than being "outside the toplevel".

So the situation is very much like the use of :filter.  Actually
we could use :filter to get the :enable behavior without any change
to the C code at all.  I.e. if a binding was made like

	(define-key cua-foo-map key bind)

and assuming that the conditional corresponding to cua-foo-map is
cua-foo-predicate, the new code would simply do:

	(defun cua-foo-filter (b) (if (eval cua-foo-predicate) b))
	(define-key cua-mode-map key
	  '(menu-item "bla" bind :filter cua-foo-filter))

> > For the sake of describe-key, I think it's better to have fewer bindings
> > (with the dispatch done more often in the bound function rather
> > than in the :enable conditionals) so that the docstring can describe what
> > happens when.
> 
> I don't think you will see any difference whether this is done
> via conditions in the minor-mode-map-alist (or emulation-mode-map-alist),
> or by conditioning each command individually.

I was assuming that there would be overlap between the maps such that
C-x is bound in several of your maps, so that C-h k would point you
to a different function/docstring depending on the circumstance.
Whereas if the conditional is tested inside the C code, then C-h k
gets you to the function that can then conveniently describe the
difference circumstances and their effect.

Of course, if there's no overlap, there's indeed no difference.

> Also, I don't see why it is better to eval the various conditions 100 times
> rather than just 7 times?

I don't see why the condition should be evaluated more times with my
proposal than with yours.  Actually, in your proposal, 7 conditions
are being evaluated for each command (they're evaluated right at the
beginning, in order to know which keymaps to look up), whereas in
mine only between 1 and 7 conditions would be evaluated (if there's
no overlap between the 7 maps, only 1, but if the current key pressed
is present in all 7 of your maps, then 7).


	Stefan

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-22  7:47                               ` Richard Stallman
@ 2002-04-22 13:53                                 ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-22 13:53 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     >     To facilitate this, three more keymaps are used which selectively does
>     >     command remapping of `kill-ring-save' to handle either region, rectangle,
>     >     or the global mark.
>     > 
>     > It would be cleaner to define a single new command for that purpose.
> 
>     I don't agree.  There are many other commands which are specific for
>     the region, rectangle, and global mark cases, and handling those in
>     separate functions is a lot clearer (to me).
> 
> You said that the function of these maps is to remap
> `kill-ring-save'.  I based my comment on what you said.

I explained how C-x is handled as an example.

> Rather than remap `kill-ring-save', which is the usual
> key binding of M-w, I think it would be cleaner to bind M-w
> to one new command.

But the remapping is the elegant part of cua ---  in each
of the keymaps for the region, rectangle, and global mark
I simply remap kill-ring-save to cua-kill-region, cua-kill-rectangle
or cua-kill-to-global-mark ... ignoring the specific keybindings the
user may be using for kill-ring-save  (and copy-region-as-kill BTW).

> 
> What do these "many other commands" have to do with remapping
> `kill-ring-save'?  I don't see the connection.  Do these three maps do
> something else besides remap `kill-ring-save'?  If so, would you
> please say precisely what other jobs they do?

Well, they define other bindings which are specific for cua's
handling of the region, rectangles, and global mark.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-22  9:28                               ` Stefan Monnier
@ 2002-04-22 15:15                                 ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-22 15:15 UTC (permalink / raw)
  Cc: emacs-devel

"Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:

> > "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> > 
> > > > "Stefan Monnier" <monnier+gnu/emacs@rum.cs.yale.edu> writes:
> > > > > I haven't heard any comment about my proposal to use `menu-item'
> > > > > bindings with a :enable setting in order to get conditional bindings
> > > > > (this doesn't currently work, but it should be pretty easy to make
> > > > > it work).
> > > > > Would it help you solve your problems ?
> > > > 
> > > > Considering that cua has approx 100 bindings in 7 keymaps,
> > > > it seems like absolute overkill IMO to condition each of those
> > > > 100 bindings individually instead of just the 7 keymaps which
> > > > contain those bindings...
> > > 
> > > Is that 7*100 bindings or 7*14 bindings ?
> > 
> > It is 8 + 7 + 2 + 10 + 17 + 60 + 16 bindings...
> 
> So, more like 7*14.
> How many of those bindings are in submaps (rather in the toplevel maps)
> such that the :enable condition could be put on the prefix and thus shared ?
> 
> > > How much overlap ?
> > None.
> 
> You mean that C-x is only bound in one of those 7 keymaps ?
> But if there's no overlap, then the order of those maps relative
> to each other is irrelevant.

Oh, sorry I don't know why I said that....

Of course there is some overlap between some of those keymaps.
E.g. C-x is bound in various ways in three of the keymaps, and
`kill-ring-save' is remapped differently in three other keymaps.

See the completely list of bindings (with overlap) at the end of this
message.

> 
> > > How many different conditions would there be ?
> > There are 7 different conditions.
> 
> If there's really no overlap and thus only 7 conditions, then the only
> difference between my proposal and yours is that in my proposition
> the condition is put on each binding inside the toplevel map rather
> than being "outside the toplevel".
> 
> So the situation is very much like the use of :filter.  Actually
> we could use :filter to get the :enable behavior without any change
> to the C code at all.  I.e. if a binding was made like
> 
> 	(define-key cua-foo-map key bind)
> 
> and assuming that the conditional corresponding to cua-foo-map is
> cua-foo-predicate, the new code would simply do:
> 
> 	(defun cua-foo-filter (b) (if (eval cua-foo-predicate) b))
> 	(define-key cua-mode-map key
> 	  '(menu-item "bla" bind :filter cua-foo-filter))

Yes, I can see the potential.

AFAICS, the overlap can be handled by something like this:

        (defun cua-krs-filter (b) 
           (cond 
             (cua-global-mark-active 'cua-kill-to-global-mark)
             (cua-rectangle 'cua-kill-rectangle)
             (mark-active  'cua-kill-region)
             (t nil)))    
        (define-key cua-mode-map [remap kill-ring-save]
 	  '(menu-item "-" nil :filter cua-krs-filter))

But that would not be practical for cua (too much overlap).

> 
> > > For the sake of describe-key, I think it's better to have fewer bindings
> > > (with the dispatch done more often in the bound function rather
> > > than in the :enable conditionals) so that the docstring can describe what
> > > happens when.
> > 
> > I don't think you will see any difference whether this is done
> > via conditions in the minor-mode-map-alist (or emulation-mode-map-alist),
> > or by conditioning each command individually.
> 
> I was assuming that there would be overlap between the maps such that
> C-x is bound in several of your maps, so that C-h k would point you
> to a different function/docstring depending on the circumstance.
> Whereas if the conditional is tested inside the C code, then C-h k
> gets you to the function that can then conveniently describe the
> difference circumstances and their effect.
> 

Exactly.

> Of course, if there's no overlap, there's indeed no difference.
> 
> > Also, I don't see why it is better to eval the various conditions 100 times
> > rather than just 7 times?
> 
> I don't see why the condition should be evaluated more times with my
> proposal than with yours.  Actually, in your proposal, 7 conditions
> are being evaluated for each command (they're evaluated right at the
> beginning, in order to know which keymaps to look up), whereas in
> mine only between 1 and 7 conditions would be evaluated (if there's
> no overlap between the 7 maps, only 1, but if the current key pressed
> is present in all 7 of your maps, then 7).

I stand corrected.

Again, I'm sorry about the misinformation re. overlap.
But I still fail to see how this approach can address all 
the requirements for cua.

Here is the complete list of keymaps and bindings used by
cua in its current state:

				1 - cua--prefix-override-keymap
				.   2 - cua--prefix-repeat-keymap
				.   .  	3 - cua--cua-keys-keymap
				.   .  	.   4 - cua--global-mark-keymap
				.   .  	.   .	5 - cua--rectangle-keymap
				.   .  	.   .	.   6 - cua--region-keymap
Key binding			.   .  	.   .	.   .	7 - cua--global-keymap
(* indicates remap)		.   .  	.   .	.   .   .
-----------------------------------------------------------------------------
C-x				1  (2) (3)
C-c				1  (2) (3)
C-x C-x			       (1)  2
C-x up	    		       (1)  2
C-x down    		       (1)  2
C-x left    		       (1)  2
C-x right   		       (1)  2
C-x timeout		       (1)	3
S-C-x					3
C-c C-c			       (1)  2
C-c up	    		       (1)  2
C-c down    		       (1)  2
C-c left    		       (1)  2
C-c right   		       (1)  2
C-c timeout		       (1)	3
S-C-c					3
C-z					3
C-v					3
RET					    4	5
TAB						5
S-return					5   6	7
H-space						5   6	7
mouse-1						5
down-mouse-1					5
drag-mouse-1					5
mouse-3						5
down-mouse-3					5
drag-mouse-3					5
H-mouse-1						7
S-C-SPC							7
C-?						5
M-up						5
M-down						5
M-left						5
M-right						5
C-M-up						5
C-M-down					5
M-a						5
M-b						5
M-c						5
M-f						5
M-F						5
M-i						5
M-k						5
M-l						5
M-m						5
M-n						5
M-o						5
M-p						5
M-P						5
M-r						5
M-R						5
M-s						5
M-t						5
M-u						5
M-|						5
M-'						5
M-/						5

*exchange-point-and-mark		3
*yank					    4		7
*clipboard-yank						7
*yank-pop						7
*set-mark-command				5	7
*undo							7
*advertised-undo					7
*self-insert-command			    4	5   6
*self-insert-iso			    4	5   6
*insert-register				    6
*newline-and-indent			    4	    6
*newline				    4	    6
*open-line					    6
*delete-backward-char			    4	5   6
*backward-delete-char			    4	5   6
*backward-delete-char-untabify		    4	5   6
*delete-char				    4	5   6
*kill-region				    4	5   6
*copy-region-as-kill			    4	5   6
*kill-ring-save				    4	5   6
*keyboard-escape-quit			    4	    6
*keyboard-quit				    4	    6
*forward-char					5
*backward-char					5
*next-line					5
*previous-line					5
*end-of-line					5
*beginning-of-line				5
*end-of-buffer					5
*beginning-of-buffer				5
*scroll-down					5
*scroll-up					5


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-21 11:08                             ` Kim F. Storm
  2002-04-22  7:47                               ` Richard Stallman
@ 2002-04-22 22:36                               ` Richard Stallman
  2002-04-23 10:58                                 ` Kim F. Storm
  2002-04-22 22:36                               ` Richard Stallman
  2 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-22 22:36 UTC (permalink / raw)
  Cc: emacs-devel

    > If you need to condition some of these maps on some symbol's being
    > false, then we could make the minimal extension so far proposed, which
    > is to allow minor-mode-map-alist (or another new alist) to have
    > conditions which are more complex than just a symbol.  But you do see
    > if you can easily get away without that.

    If we don't allow some form of simple logical expression [e.g. the
    functions I listed in a previous mail],

What are the three conditions that you want to test for?
Let's see what features they require.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-21 11:08                             ` Kim F. Storm
  2002-04-22  7:47                               ` Richard Stallman
  2002-04-22 22:36                               ` Richard Stallman
@ 2002-04-22 22:36                               ` Richard Stallman
  2002-04-23 11:02                                 ` Kim F. Storm
  2 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-22 22:36 UTC (permalink / raw)
  Cc: emacs-devel

    >     The final keymap is used to allow users to take advantage of cua's
    >     uniform command set for rectangles (and the global mark), but still
    >     continue to use C-w, M-w and C-y instead of C-x, C-c, and C-v (which
    >     are the normal cua bindings).
    > 
    > Which characters does this map redefine?
    > 

    C-z -> undo, C-v -> yank

This should be feasible with existing facilities, right?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-22 22:36                               ` Richard Stallman
@ 2002-04-23 10:58                                 ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-04-23 10:58 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     > If you need to condition some of these maps on some symbol's being
>     > false, then we could make the minimal extension so far proposed, which
>     > is to allow minor-mode-map-alist (or another new alist) to have
>     > conditions which are more complex than just a symbol.  But you do see
>     > if you can easily get away without that.
> 
>     If we don't allow some form of simple logical expression [e.g. the
>     functions I listed in a previous mail],
> 
> What are the three conditions that you want to test for?
> Let's see what features they require.
> 

Here are the keymap conditionals used by cua:
 
  (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))

  (and mark-active
       (timerp cua--prefix-override-timer))

  (or (eq cua-enable-cua-keys t)
      cua--last-region-shifted)

  (and cua--global-mark-active
       (not (window-minibuffer-p)))


The last one calls `windows-minibuffer-p' -- that's probably
not considered as `trivial' ?

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-22 22:36                               ` Richard Stallman
@ 2002-04-23 11:02                                 ` Kim F. Storm
  2002-04-24 17:55                                   ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-23 11:02 UTC (permalink / raw)
  Cc: emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     >     The final keymap is used to allow users to take advantage of cua's
>     >     uniform command set for rectangles (and the global mark), but still
>     >     continue to use C-w, M-w and C-y instead of C-x, C-c, and C-v (which
>     >     are the normal cua bindings).
>     > 
>     > Which characters does this map redefine?
>     > 
> 
>     C-z -> undo, C-v -> yank
> 
> This should be feasible with existing facilities, right?

Yes, except that the condition on this keymap is 

  (or (eq cua-enable-cua-keys t)
      cua--last-region-shifted)


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-23 11:02                                 ` Kim F. Storm
@ 2002-04-24 17:55                                   ` Richard Stallman
  2002-04-26 13:44                                     ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-24 17:55 UTC (permalink / raw)
  Cc: emacs-devel

    > This should be feasible with existing facilities, right?

    Yes, except that the condition on this keymap is 

      (or (eq cua-enable-cua-keys t)
	  cua--last-region-shifted)

Could you make a new variable to control this keymap,
and set it from post-command-hook?

Likewise, maybe you could control the other maps
with variables set in post-command-hook.
This would not be much more complicated
and it probably would be about as fast.
Perhaps faster, since the hook function could be
byte-compiled, whereas if these expressions go straight
into the keymap they would have to be interpreted.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-24 17:55                                   ` Richard Stallman
@ 2002-04-26 13:44                                     ` Kim F. Storm
  2002-04-27 22:41                                       ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-26 13:44 UTC (permalink / raw)
  Cc: storm, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     > This should be feasible with existing facilities, right?
> 
>     Yes, except that the condition on this keymap is 
> 
>       (or (eq cua-enable-cua-keys t)
> 	  cua--last-region-shifted)
> 
> Could you make a new variable to control this keymap,
> and set it from post-command-hook?
> 
> Likewise, maybe you could control the other maps
> with variables set in post-command-hook.
> This would not be much more complicated
> and it probably would be about as fast.
> Perhaps faster, since the hook function could be
> byte-compiled, whereas if these expressions go straight
> into the keymap they would have to be interpreted.


That is exactly what I've done now.
I set a total of 5 such variables in the post-command-hook
to control the various cua related keymaps.

The problem with this approach is that -- in some cases --
a subsequent post-command-hook function or another external
event may change the state [notably clear the mark active state]
so my state variables no longer contain the proper values.

I still belive evalling those expressions when the keymaps are used is
preferable (safer, simpler and more logical) rather than doing it in the
post-command-hook.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-26 13:44                                     ` Kim F. Storm
@ 2002-04-27 22:41                                       ` Richard Stallman
  2002-04-29  9:17                                         ` Kai Großjohann
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-27 22:41 UTC (permalink / raw)
  Cc: emacs-devel

    The problem with this approach is that -- in some cases --
    a subsequent post-command-hook function or another external
    event may change the state [notably clear the mark active state]
    so my state variables no longer contain the proper values.

Hmm.  What sort of external event deactivates the mark?
What package has a post-command-hook function that deactivates the mark?

    I still belive evalling those expressions when the keymaps are used is
    preferable (safer, simpler and more logical) rather than doing it in the
    post-command-hook.

All in all, if the post-command-hook works, I think that is simpler.
However, if making the post-command-hook work requires added complexity,
that could tip the scales in favor of some other solution.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-27 22:41                                       ` Richard Stallman
@ 2002-04-29  9:17                                         ` Kai Großjohann
  2002-04-30  5:18                                           ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kai Großjohann @ 2002-04-29  9:17 UTC (permalink / raw)
  Cc: kfs, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> All in all, if the post-command-hook works, I think that is simpler.
> However, if making the post-command-hook work requires added complexity,
> that could tip the scales in favor of some other solution.

Please note that Kim has already implemented the post-command-hook
completion.  And Kim has already made a suggestion for another
implementation.

The post-command-hook implementation requires quite complex code and
is hard to maintain, he says, whereas his proposed
emulation-mode-minor-map-alist leads to considerably simpler and
easier to maintain code.

I hope I have helped to clear this up a bit.  I was feeling that
there is still some misunderstanding.
kai
-- 
Silence is foo!

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-29  9:17                                         ` Kai Großjohann
@ 2002-04-30  5:18                                           ` Richard Stallman
  2002-04-30 21:25                                             ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-04-30  5:18 UTC (permalink / raw)
  Cc: kfs, emacs-devel

What exactly is the emulation-mode-minor-map-alist suggestion?

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-30  5:18                                           ` Richard Stallman
@ 2002-04-30 21:25                                             ` Kim F. Storm
  2002-05-01  7:14                                               ` Richard Stallman
  0 siblings, 1 reply; 46+ messages in thread
From: Kim F. Storm @ 2002-04-30 21:25 UTC (permalink / raw)
  Cc: Kai.Grossjohann, emacs-devel

Richard Stallman <rms@gnu.org> writes:

> What exactly is the emulation-mode-minor-map-alist suggestion?

The basic emulation-mode-map-alists functionality is simply a way to
allow packages like cua and viper to install and manage their own 
keymap alists independent of minor-mode-map-alist:

It is a list of alists with the same format and interpretation as
minor-mode-map-alist.

The documentation for emulation-mode-map-alists is as follows:

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'.



The second - independent - part of the proposed functionality was
to allow more complex expressions to select the active keymaps in
the minor-mode-map-alist (and emulation-mode-map-alists):

The following minor-mode-map-alist documentation describes this
added functionality:

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.



-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-04-30 21:25                                             ` Kim F. Storm
@ 2002-05-01  7:14                                               ` Richard Stallman
  2002-05-01 17:37                                                 ` Kim F. Storm
  0 siblings, 1 reply; 46+ messages in thread
From: Richard Stallman @ 2002-05-01  7:14 UTC (permalink / raw)
  Cc: Kai.Grossjohann, emacs-devel

    It is a list of alists with the same format and interpretation as
    minor-mode-map-alist.

Would a single added alist do the job?

    Alternatively, an element may look like (lambda . FORM) where FORM is 
    evaluated and should return either nil or a cons (SYMBOL . KEYMAP);

That seems kludgy and ugly.  I would rather allow replacing VARIABLE
with a boolean expression.  Wouldn't that be enough?

I think this is the sort of area where it is better to make smaller
extensions, not larger ones.

^ permalink raw reply	[flat|nested] 46+ messages in thread

* Re: Enhancements to "minor-mode-map-alist" functionality.
  2002-05-01  7:14                                               ` Richard Stallman
@ 2002-05-01 17:37                                                 ` Kim F. Storm
  0 siblings, 0 replies; 46+ messages in thread
From: Kim F. Storm @ 2002-05-01 17:37 UTC (permalink / raw)
  Cc: Kai.Grossjohann, emacs-devel

Richard Stallman <rms@gnu.org> writes:

>     It is a list of alists with the same format and interpretation as
>     minor-mode-map-alist.
> 
> Would a single added alist do the job?

I think a package should be able to create its own alist and
link it into the -map-alists list.  Then packages like cua and
viper don't need to worry about each other...

Having one extra alist or a list of alists doesn't make much
difference for the implementation - but it makes a big difference
at the lisp level.

> 
>     Alternatively, an element may look like (lambda . FORM) where FORM is 
>     evaluated and should return either nil or a cons (SYMBOL . KEYMAP);
> 
> That seems kludgy and ugly.

I fully agree.

>                I would rather allow replacing VARIABLE
> with a boolean expression.  Wouldn't that be enough?

So would I, but what symbol should describe-bindings show in case
of a boolean expression?  E.g.

`cua--ena-cua-keys-keymap' Minor Mode Bindings:


Maybe it could just be nil - in which case describe-bindings would print a heading with no specific symbol, e.g.

Misc. Emulation Mode Bindings:

> 
> I think this is the sort of area where it is better to make smaller
> extensions, not larger ones.

I don't think I'm advocating for large extensions here.  The
functionality is confined to adding one new variable, and modifying
one or two functions at the C level.

But I need to take care of the [potential] memory allocation problems
in current_minor_maps.  Either by explicitly defining (and evalling)
a specific set of functions which may be used in the expression, or
by inhibiting evaluation of the boolean expressions if we have run
out of memory.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 46+ messages in thread

end of thread, other threads:[~2002-05-01 17:37 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-04-11 22:56 Enhancements to "minor-mode-map-alist" functionality Kim F. Storm
2002-04-11 22:43 ` 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

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).