18

Is it possible to set key bindings specific to buffer?

I have the following in one of my org files:

# Local Variables:
# eval: (local-set-key (kbd "<f10>") 'some-custom-defun-specific-to-this-buffer)
# End:

But this binding persists for other org-mode files too. If I open a file with a different major mode, then my default key binding kicks in.

It looks like local-set-key is setting bindings specific to the major-mode not specific to the buffer.

How can I have bindings that activate only in a particular buffer?

5
  • 2
    Oh wow, you're right: "The binding goes in the current buffer's local map, which in most cases is shared with all other buffers in the same major mode." I never knew that.
    – shosti
    Commented Sep 30, 2014 at 18:44
  • Now that I think about it, local-unset-key hooked with org-mode-hook might work if that is executed before the Local Variables: section is. Commented Sep 30, 2014 at 18:48
  • Or you could make a minor mode with a semi sparse keymap and toggle it using Local Variables:
    – Vamsi
    Commented Sep 30, 2014 at 18:54
  • @Vamsi Thanks! This is an elegant solution! I have updated your solution. Commented Sep 30, 2014 at 19:35
  • 1
    stackoverflow.com/questions/21486934/…
    – phils
    Commented Oct 1, 2014 at 5:08

2 Answers 2

19

For closure, here is an answer that expands upon my comment. I define a minor mode with the required keybinding and toggle it in the required buffer using file local variables.

  (define-minor-mode my-org-buffer-local-mode
    "Minor mode to simulate buffer local keybindings."
    :init-value nil)
  (define-key my-org-buffer-local-mode-map (kbd "<f10>") 'some-custom-defun-specific-to-this-buffer)

You can toggle it in necessary files by setting the local variables section at the end of the file as follows. You can also change or add the keybinding here. You will still need to define different minor modes for each buffer that maps the same key-sequence to different commands.

 # Local Variables:
 # my-org-buffer-local-mode: t
 # eval:(define-key my-org-buffer-local-mode-map (kbd "<f10>") 'some-other-custom-defun-specific-to-this-buffer)
 # End:
4
  • @kaushalmodi: You might want to spin off your edits into a separate answer since it is more complete. Also, you would not be able to map the same key-sequence to two different functions simultaneously unless you use a buffer specific name.
    – Vamsi
    Commented Sep 30, 2014 at 19:41
  • I get this error: eval-buffer: Symbol's value as variable is void: my-org-buffer-local-mode-map when I try to run this (define-minor-mode my-org-buffer-local-mode "Minor mode to simulate buffer local keybindings." :init-value nil) (define-key my-org-buffer-local-mode-map (kbd "<f10>") 'some-custom-defun-specific-to-this-buffer) Commented Jul 30, 2015 at 1:39
  • I also get the same error. any idea?
    – zeltak
    Commented Aug 1, 2017 at 10:02
  • @incandescentman call (make-keymap) with :keymap keyword, check nullprogram.com/blog/2013/02/06
    – nichijou
    Commented Dec 30, 2018 at 9:47
7

Here is a generic way to set buffer-specific key bindings.

  • Create a temporary minor mode (save the below snippet to temp-mode.el and require it in your init.el.
  • Enable that temp-mode minor mode and define that minor-mode's keymap only in the buffer(s) you need.

Put the below Local Variables snippet in the buffer where you want the custom key binding. Below are examples of org-mode files.

In buffer ONE

# Local Variables:
# eval: (temp-mode 1)
# eval: (define-key temp-mode-map (kbd "<f10>") 'function-ONE)
# End:

If some other buffer redefines the same key-binding using,

In buffer TWO

# Local Variables:
# eval: (temp-mode 1)
# eval: (define-key temp-mode-map (kbd "<f10>") 'function-TWO)
# End:

then the new binding become effective on doing M-x revert-buffer.

This is what I would do if I need to switch between these two buffers very frequently and if I have to use the F10 binding in both:

  • Work in buffer ONE, C-x C-s (save) and switch to buffer TWO
  • revert-buffer (refresh bindings), work in buffer TWO, C-x C-s and switch to buffer ONE
  • revert-buffer (refresh bindings), work in buffer ONE, C-x C-s and switch to buffer TWO

But I would rather bind the different buffer-specific commands to different keys.


Temporary minor mode

;; temp-mode.el
;; Temporary minor mode
;; Main use is to enable it only in specific buffers to achieve the goal of
;; buffer-specific keymaps

(defvar temp-mode-map (make-sparse-keymap)
  "Keymap while temp-mode is active.")

;;;###autoload
(define-minor-mode temp-mode
  "A temporary minor mode to be activated only specific to a buffer."
  nil
  :lighter " Temp"
  temp-mode-map)

(provide 'temp-mode)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.