Emacs key binding fallback

前端 未结 3 856
天命终不由人
天命终不由人 2020-12-06 11:42

I have a minor mode. If that mode is active and the user hits DEL, I want to do some action, but only if some condition holds. If the condition holds and the action is execu

相关标签:
3条回答
  • 2020-12-06 12:04

    There doesn't seem to be a way to do what you want reliably. If your new command is bound to DEL, then whatever was bound to DEL before in the current keymap isn't there anymore. The other approach you proposed won't work because pre-command-hooks don't prevent the following action from taking place. You might also think to interrupt further execution with ^G (Keyboard-Quit), but that's an uncontrolled interrupt that might stop more things than you want.

    Even if you make the process of setting up the new binding a little more sophisticated than just re-bind, and remember what was bound there before, so you can call it afterwards, you don't really have what your looking for. If someone wants to rebind the "default" action, they have to do it by modifying to your function rather than replacing the key binding.

    What you want to do doesn't fit Emacs' model of how key binding works.

    0 讨论(0)
  • 2020-12-06 12:15

    This is what I use for my smart-tab package which does exactly that.

    (defun smart-tab-default ()
      "Indents region if mark is active, or current line otherwise."
      (interactive)
      (if mark-active
          (indent-region (region-beginning)
                         (region-end))
    
        (call-interactively
         (or
          ;; Minor mode maps for tab (without smart-tab-mode)
          (cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding "\t")))
          (cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding [(tab)])))
          (local-key-binding "\t")
          (local-key-binding [(tab)])
          (global-key-binding "\t")
          (global-key-binding [(tab)])))))
    

    And in the command smart-tab (which is the one bound to tab in the minor mode), it has the following:

    (if (smart-tab-must-expand prefix)
        ;; use smart tab
      (smart-tab-default))
    

    It first checks if there are any minor mode bindings for tab (not including smart-tab-mode), then local, and finally global keybindings.

    0 讨论(0)
  • 2020-12-06 12:17

    The way to do this is to temporarily disable your minor mode, then look up the key binding.

    Pretend that you've bound 'do-thingy to DEL. Then this would do the trick (assuming the condition you want to trigger off is (equal last-input-event 'backspace):

    (defun do-thingy ()
      "Do something, unless last event was backspace."
      (interactive)
      (if (equal last-input-event 'backspace)
          (let* ((my-minor-mode nil)
                 (original-func (key-binding (kbd "DEL"))))
            ;; original-func is whatever DEL would be if
            ;; my-minor-mode were disabled
            (call-interactively original-func))
        (message "Here's my minor mode behavior!")))
    

    Note: This behavior assumes you have set up your key bindings the standard way a minor-mode would. Specifically, you should add your keymap to the variable minor-mode-map-alist by adding an element (my-minor-mode . my-minor-mode-keymap). That's how the above let statement works, it looks up the binding you want with your mode temporarily disabled.

    If you use define-minor-mode to define your minor mode, the keymap gets set up the "right way" automatically.

    0 讨论(0)
提交回复
热议问题