[plt-scheme] Overriding the keymap in drscheme

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Thu Jul 27 16:57:17 EDT 2006


On Tue, 25 Jul 2006, Robby Findler wrote:

> I wonder if another approach might make more sense for you (like
> overriding on-insert/after-insert or maybe on-event). Perhaps you can
> explain the bigger picture a little bit (like what the diva scheme
> keymap binds and why chained keymaps are a problem)?

DivaScheme lets you edit scheme code without ever having to manually 
balance parentheses.  Conversely, DivaScheme assumes that the parentheses 
are correctly balanced, else it complains and aborts out to normal 
DrScheme.

What's happening is that DivaScheme has a special keybinding for pretty 
much everything.  Any key that touches the text needs to go through 
DivaScheme, else it might break the parentheses.  DivaScheme needs to 
override the '[' key, it needs to override 'delete' and 'backspace', etc.

On the other hand, DivaScheme needs to maintain keybindings that do not 
touch the text.  We want C-x C-s to work as usual, F5 and F6 too, etc.

In this sense, DivaScheme is a major mode, if I can use Emacs terminology, 
and CHAIN-TO-KEYMAP works like Emacs' minor modes.


> But if keymaps are what you really want, you might try subclassing 
> chain-to-keymap and other keymap methods to remember what happened and 
> then replay that when you remove the divascheme keymap.

We tried many different permutations of this, but couldn't make it work. 
It seems that there are too many ad-hoc ways to install a keymap used 
all-over DrScheme; I can not reliably override them all.


We got a little bit closer to a solution by installing a dummy-head at the 
front of the chained keymap list:

   (define (diva-link:text-mixin keymap:remove-chained-keymap super%)
     (class super%
       ...

       (define (to-command-mode)
         (preferences:set 'divascheme:on? #t)
         (send (get-keymap) chain-to-keymap command-keymap #t))

       (define/public (to-normal-mode)
         (preferences:set 'divascheme:on? #f)
         (keymap:remove-chained-keymap this command-keymap))

       (define (toggle-divascheme)
         (if (preferences:get 'divascheme:on?)
             (to-normal-mode)
             (to-command-mode)))

       (define f4-keymap (new keymap:aug-keymap%))
       (send f4-keymap add-function "diva:toggle"
             (lambda (any event) (toggle-divascheme)))
       (send f4-keymap map-function "f4" "diva:toggle")

       (let ([dummy-head-keymap (new keymap:aug-keymap%)]
             [original-keymap (get-keymap)])
         (send dummy-head-keymap chain-to-keymap original-keymap #t)
         (send dummy-head-keymap chain-to-keymap f4-keymap #t)
         (set-keymap dummy-head-keymap))

       (when (preferences:get 'divascheme:on?)
         (to-command-mode)))))


With the DUMMY-HEAD-KEYMAP, I can chain the ORIGINAL-KEYMAP, then chain 
the COMMAND-KEYMAP before it.

This correctly overrides all keys with the exception of those which
initialized themselves after DivaScheme initialized by sending #t to 
CHAIN-TO-KEYMAP.  The piece of DrScheme code that installs the '[' 
keybinding does that (I think).


> You might also try calling to-dvascheme-mode at a different time (later 
> on), but that's still fragile.

Right, though I couldn't think of what time that would be.  Any ideas?


Posted on the users mailing list.