How to make a buffer-local key binding in Emacs?
Asked Answered
C

4

9

I've been working on an Emacs minor mode lately and part of its functionality was displaying images in separate buffers. So far I've been using a function like this:

(defun create-buffer-with-image (name)
  (let ((buffer (generate-new-buffer name))
        (image (get-svg-for-kanji-code name)))
    (switch-to-buffer buffer)
    (turn-on-iimage-mode)
    (iimage-mode-buffer t)
    (insert-image image)))

and it produces a buffer with the image passed as argument, but closing the buffer requires hitting C-x k and Return, which started to get cumbersome after a while. The way to simplify closing of such transient buffers would be to have a key binding for the kill-this-buffer function, but it would need to be buffer-specific, so as not to mess up anything else. The question is how to make such a binding with the creation of a buffer.

Carrnan answered 5/12, 2014 at 17:23 Comment(0)
C
2

I was a bit mislead by some posts on the web suggesting the use of local-key-binding, but somehow it did not work for me - when the image was displayed and I examined the key bindings, my choice of q was not in effect. After some experimentation and digging through elisp references I found that I needed to use local-set-key. So now my function looks like this:

(defun create-buffer-with-image (name)
  (let ((buffer (generate-new-buffer name))
        (image (get-svg-for-kanji-code name)))
    (switch-to-buffer buffer)
    (local-set-key (kbd "q") 'kill-this-buffer)
    (turn-on-iimage-mode)
    (iimage-mode-buffer t)
    (insert-image image)))

and the newly created image buffer can easily be closed by pressing q.

Carrnan answered 5/12, 2014 at 17:23 Comment(5)
local-set-key modifies the local key map, which in most cases is the major mode keymap, which will affect all buffers using that major mode. So local-set-key is not a buffer-local effect. (It's only "local" as opposed to the "global" key map which is visible to every buffer.)Novgorod
Thanks for your response, @phils. I did some investigation regarding your remark. When I display the image using iimage-mode, the major mode for that buffer is Fundamental (additional minor modes are iImg and MRev). I examined the keybindings in all these modes after making the local-set-key binding and none of them showed the behavior you warned me about. The way I see it in light of this is that it really causes a buffer-local effect. Correct me if I'm missing something important here.Carrnan
In fundamental-mode that is correct. It doesn't set a local keymap, and it appears that local-set-key in this circumstance does create a buffer-local keymap. Just be aware that this is not the normal behaviour, as most major modes do set (and share) a local keymap.Novgorod
Thanks. I'll keep an eye on it :)Carrnan
Your solution with local-set-key and the peculiarities of fundamental-mode is very useful. You should accept it as the solution to your original question so that it will be singled out when we visit this page.Ensconce
W
11

From EmacsWiki: https://www.emacswiki.org/emacs/BufferLocalKeys

For buffer-local keys, you cannot use local-set-key, unless you want to modify the keymap of the entire major-mode in question: local-set-key is local to a major-mode, not to a buffer.

For buffer-local modifications, use this instead:

(use-local-map (copy-keymap foo-mode-map))
(local-set-key "d" 'some-function)

Written by:  TiagoSaboga


To inspect the change, type C-h b aka M-x describe-bindings

Wreak answered 8/5, 2018 at 21:30 Comment(0)
A
3

I'd suggest you add a call to special-mode after the call to switch-to-buffer. In the longer run, you'll want to use your own major mode, so you'd do:

(define-derived-mode my-image-mode special-mode "MyImage"
  "My own major mode to display images."
  ;; We could add more things here
  )

(defun create-buffer-with-image (name)
  (with-current-buffer (generate-new-buffer name)
    (my-image-mode)
    (let ((image (get-svg-for-kanji-code name)))
      (turn-on-iimage-mode)
      (iimage-mode-buffer t)
      (insert-image image)
      (pop-to-bffer (current-buffer)))))
Adele answered 5/12, 2014 at 19:9 Comment(0)
C
2

I was a bit mislead by some posts on the web suggesting the use of local-key-binding, but somehow it did not work for me - when the image was displayed and I examined the key bindings, my choice of q was not in effect. After some experimentation and digging through elisp references I found that I needed to use local-set-key. So now my function looks like this:

(defun create-buffer-with-image (name)
  (let ((buffer (generate-new-buffer name))
        (image (get-svg-for-kanji-code name)))
    (switch-to-buffer buffer)
    (local-set-key (kbd "q") 'kill-this-buffer)
    (turn-on-iimage-mode)
    (iimage-mode-buffer t)
    (insert-image image)))

and the newly created image buffer can easily be closed by pressing q.

Carrnan answered 5/12, 2014 at 17:23 Comment(5)
local-set-key modifies the local key map, which in most cases is the major mode keymap, which will affect all buffers using that major mode. So local-set-key is not a buffer-local effect. (It's only "local" as opposed to the "global" key map which is visible to every buffer.)Novgorod
Thanks for your response, @phils. I did some investigation regarding your remark. When I display the image using iimage-mode, the major mode for that buffer is Fundamental (additional minor modes are iImg and MRev). I examined the keybindings in all these modes after making the local-set-key binding and none of them showed the behavior you warned me about. The way I see it in light of this is that it really causes a buffer-local effect. Correct me if I'm missing something important here.Carrnan
In fundamental-mode that is correct. It doesn't set a local keymap, and it appears that local-set-key in this circumstance does create a buffer-local keymap. Just be aware that this is not the normal behaviour, as most major modes do set (and share) a local keymap.Novgorod
Thanks. I'll keep an eye on it :)Carrnan
Your solution with local-set-key and the peculiarities of fundamental-mode is very useful. You should accept it as the solution to your original question so that it will be singled out when we visit this page.Ensconce
U
0

Create a minor mode:

(define-minor-mode my-mode "my doc" nil nil (make-sparse-keymap))

Then you can use this mode's my-mode-map to define your keybindings. Activate the mode with (my-mode).

Undercool answered 23/5, 2021 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.