3

I am trying to use different keybindings for basic movement and deletion in emacs. What I would like to use are the following keybindings:

  • Ctrl+i/k/j/l : up/down/left/right
  • Ctrl+u/o : backward/forward word
  • Ctrl+d/f : delete left/right
  • Ctrl+e/r : delete word left/right
  • Ctrl+Alt+e/r : delete to begining/end of line
  • Ctrl+c/x/v : copy/cut/paste
  • Ctrl+m Alt+m : search history backwards/forwards
  • etc

Which I managed to make work in most of the cases. Nevertheless I still face two problems:

  • Some major modes keybindings takes precedence over my settings. For example some python mode might set C-j to newline-and-indent, and I have to figure out each problem for each minor mode I am using, find the correct keymap and free my key. Tedious.
  • Some major modes use a slightly modified command for basics movements. For example org-mode might use org-end-of-line for C-e instead of end-of-line. This allows to jump to the end of the line, without taking into account the tags on the right. Or some mode would change the delete backward command to a custom one, more fitted to the desired task. Same for C-n and C-p that often change signification through modes. These are some sine features that I would like to use without explicitely search for them, find their command names, rebind them for each major mode I use. I want my C-k to work the same as would C-n in every mode I use, without having to do anything.

So my question is, how can I create a minor mode, containing all my keybindings, that would precede all other mode's keybindings, and that would do something like:
C-n : "please bind C-k (my preference for down movement) to whatever command C-n was meant to be bound to in this mode"

I guess I have to create a minor mode for this, maybe have to load it through a hook in before each major mode, and use some emacs function that returns the function bound to a given keybinding.

Any idea on how to do that?

Antoine Gallix
  • 662
  • 1
  • 11
  • 28

1 Answers1

1
  1. First, you should probably take a look at evil mode, which brings a lot of Vim-style keyboard shortcuts to Emacs, many of which mirror your own preferences.

  2. If you still want a universal minor mode that will dynamically rebind functions from any given major or minor mode, you'll probably want to work with functions like find-function-on-key to sniff out bindings which you can then rebind as needed.

  3. A less ambitious approach may be to define a personal keymap and bind that to one key. That saves you having to rebind keys everytime you switch modes. For example, I use the following:

    (define-prefix-command 'ty-keymap)
    (global-set-key "\M- " ty-keymap)
    (define-key ty-keymap " " 'just-one-space) 
    

This rebinds M-<space> for my own use, then rebinds just-one-space to M-<space><space>. This frees me up to do weird things like this:

(define-key ty-keymap "j" #'(lambda () (interactive) (ty-move-mode ?j)))
(define-key ty-keymap ";" #'(lambda () (interactive) (ty-move-mode ?\;)))
(define-key ty-keymap "k" #'(lambda () (interactive) (ty-move-mode ?k)))
(define-key ty-keymap "l" #'(lambda () (interactive) (ty-move-mode ?l)))

(defun ty-move-mode (mv)
  "Move over windows with right homerow keys."
  (interactive "k")
  (case mv
    (?j (windmove-left)
        (ty-move-mode (read-event)))
    (?; (windmove-right)
        (ty-move-mode (read-event)))
    (?k (windmove-down)
        (ty-move-mode (read-event)))
    (?l (windmove-up)
        (ty-move-mode (read-event)))
    (?\r (message "done!"))
    (t (push last-input-event unread-command-events))))

This gives me access to j, k, l and ; for moving directionally around my windows. It would be easy enough to modify this to give you a mini-mode for movement by single characters:

(defun ty-move-mode (mv)
  "Move over windows with right homerow keys."
  (interactive "k")
  (case mv
    (?j (backward-char 1)
        (ty-move-mode (read-event)))
    (?; (forward-char 1)
        (ty-move-mode (read-event)))
    (?k (previous-line 1)
        (ty-move-mode (read-event)))
    (?l (next-line 1)
        (ty-move-mode (read-event)))
    (?\r (message "done!"))
    (t (push last-input-event unread-command-events))))

Perhaps someone else will have a better idea of how to do exactly what you want.

Tyler
  • 9,872
  • 2
  • 33
  • 57