Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create keybindings for a custom minor mode in Emacs

Question:

How do I create custom keybindings for minor modes? Something like this.

Here is what I have so far. I'm trying to get just one custom keybinding to work:

(define-minor-mode num-mode
       "Toggle the Num pad keys.
     With no argument, this command toggles the mode.
     Non-null prefix argument turns on the mode.
     Null prefix argument turns off the mode.

     When Num mode is enabled, the num pad inserts the
     keys you see on the pad. This may over ried existing
     definitions, and is probably only usefule if you aref
     running Emacs through a terminal."
      ;; The initial value.
      nil
      ;; The indicator for the mode line.
      " NumPad"
      ;; The minor mode bindings.
      ;; This doesn't work right now!!!!
       '(((kbd "<kp-1>") . "a"))
      :global 1
)

When I hit "1" on the num pad after calling my custom minor mode, "num-mode" and verifying it is on in the mini buffer, I get the error <kp-1> is undefined. What I want to happen is a is printed out where the pointer is when I hit <kp-1>. (just a test)

Context:

So, I usually use my num pad to move between buffers (the arrow keys move me the appropriate directions). This is set globally. I want to create a minor mode that I can call when I want to use my num-pad to simply enter numbers.

By default, the keys on my num-pad are undefined. I use <kp-0> to <kp-9> to define the keybindings for the numpad keys.

I can create a minor mode that I can call, but I can't attach any keybindings. This is true for all keybindings, including one not defined anywhere else.

Thanks for any help!

like image 200
Peter Ajtai Avatar asked Jun 25 '10 02:06

Peter Ajtai


2 Answers

Short Answer

Problem line:

'(((kbd "<kp-1>") . "a"))

Solution (force the evaluation of the macro):

;; Single quote changed to back-quote and added a comma
`((,(kbd "<kp-1>") . "a"))

Long Answer

The define-minor-mode macro allows you to create minor modes relatively easily (as far as Emacs) goes.

First I'll show how it's done, then I'll explain how it works:

In general form:

(define-minor-mode NAME-mode
  "DOCUMENTATION"
  INIT-VALUE
  "LIGHTER"
  ;; keymap
  '(
    (KEY-SEQUENCE . DEFINITION)
    (KEY-SEQUENCE . DEFINITION)
    ... ETC ...
   )
  ;; other options
  :KEYWORD-ARG VALUE
  :KEYWORD-ARG VALUE
  ... ETC ...       
)

Specific example with forced evaluation of macros in the alist:

;; Custom Minor Mode
(define-minor-mode custom-mode
  "Doc description, yada yada yada."
  ;; The initial value - Set to 1 to enable by default
  nil
  ;; The indicator for the mode line.
  " CustomMode"
  ;; The minor mode keymap
  `(
    (,(kbd "C-c C-a") . some-command)
    (,(kbd "C-c C-b") . other-command)
    ("\C-c\C-c" . "This works too")
   )
   ;; Make mode global rather than buffer local
   :global 1
)

An alternative way, if you wish to use a variable for the keymap is to define the keymap variable and the keymap before the minor mode declaration something like this:

(defvar custom-mode-keymap (make-keymap) "num-mode keymap.")
(define-key custom-mode-keymap (kbd "C-c C-a") 'some-command)

And then, in your minor mode definition, simple list the variable name for your keymap, instead of the alist

(define-key custom-mode-keymap (kbd "C-c C-b") 'other-command)
;; Num pad enable
(define-minor-mode custom-mode
...

      ;; The minor mode bindings.
      custom-mode-keymap

How it all works

From top to bottom, right after define-minor-mode we define a command name to toggle the minor mode. custom-mode in this case (M-x custom-mode to toggle the mode). This also defines a variable of the same name.

Right after the command name, we list the documentation string for the minor mode in quotes. This can pretty much be as long as you want.

Next we have several choices. The simplest choice is to simply list three things and then any additional options. The three things have to be listed in the order below. These three things are:

  1. The initilization value for the minor mode variable. nil will have the mode off by default. Something other than nil will have it on by default.

  2. The lighter. The lighter is simply what is display in the mode line at the bottom when your minor mode is on. This should be short, and it'll often help, in terms of formatting, to start it with a space.

  3. The keymap. The keymap can either be defined as a variable or an alist (association list). Since using an alist is simpler and shorter, that's what I used in the example. The alist should be in the form (key-sequence . definition).

If you define the keymap as an alist, there's a few things to watch out for, especially if you're used to defining global keybindings. First, command names are not quoted. Second, if you want to use a macro, you have to force it to evaluate (and on SO). This is done with a combination of the back-quote (not single quote) and comma. You can see how this is done in the example with the kbd macro. I also included a keystroke definition if you don't use the kbd macro. If you simply quote a string in your keymap, that'll print out when the defined key combination is pressed (just like for defining global key bindings).

The keymap will not work with kbd macros if you do not force the evaluation of the kbd macros with a combination of the back quote and comma. Like this:

`((,(kbd "C-c C-a") . some-command))

Finally, you can add additional options using keyword-args of the form :blah. In the example I used :global. We could have defined the entire mode with keyword-args, but it's shorter to just list the init value, lighter, and keymap in the right order.

like image 181
Peter Ajtai Avatar answered Oct 04 '22 15:10

Peter Ajtai


You need to have code like this in your minor mode definition:

(defvar your-mode-map
  (let ((map (make-sparse-keymap)))
    (set-keymap-parent map parent-mode-shared-map)
    (define-key map "\C-c\C-a" 'some-defun)
    (define-key map "\C-c\C-b" 'some-other-sexp)
    map)

(use-local-map your-mode-map)

You could have a look at the many modes available in EmacsWiki for reference.

like image 26
Bozhidar Batsov Avatar answered Oct 04 '22 15:10

Bozhidar Batsov