Set custom keybinding for specific Emacs mode
Asked Answered
J

4

64

Though I know how to set a global key-binding in Emacs, I find it hard to even Google out the code for a local (minor-mode specific) key-binding. For instance, I have this code in my .emacs:

;; PDFLaTeX from AucTeX
(global-set-key (kbd "C-c M-p")
        (lambda ()
          (interactive)
          (shell-command (concat "pdflatex " buffer-file-name))))

I don't want to set it globally. Is there a function like local-set-key?

Jalousie answered 31/3, 2011 at 12:45 Comment(2)
More and more I find myself going to the Emacs Wiki for help: emacswiki.org/emacs/KeyBindingDiscussion There it shows that you can add a key binding to a mode key map and also shows how to find that map.Berezina
Yepp... I saw that one already, but I get Symbol's value as variable is void: LaTeX-mode-map all the time. Hmmm...Jalousie
S
49

To bind a key in a mode, you need to wait for the mode to be loaded before defining the key. One could require the mode, or use eval-after-load

   (eval-after-load 'latex 
                    '(define-key LaTeX-mode-map [(tab)] 'outline-cycle))

Don't forget either 'eval-after-load is not a macro, so it needs them.

Santinasantini answered 31/3, 2011 at 20:24 Comment(5)
How do you determine the first argument to eval-after-load programmatically?Falco
I think it's enough to provide any function which belongs to the mode – e.g. 'LaTeX-mode instead of 'latex would do just as well.Nanice
For me the variable is called latex-mode-map (all lower case). LaTeX-mode-map doesn't exist.Kenji
[(tab)] is old syntax for (kbd "TAB")Shofar
@LenarHoyt: actually, no: [(tab)] is the same as [tab] which is the key-sequence sent when you hit the TAB key in the GUI version of Emacs. (kbd "TAB") OTOH is the same as [?\t] which is the key-sequence sent when you hit that same TAB key in a text terminal (which is also the same key-sequence sent when you hit C-i). The two options are "unified" inside Emacs by function-key-map which remaps [tab] to (kbd "TAB") if there's no binding to [tab]. So if you want your binding to work both in a GUI and in a tty, better use (kbd "TAB").Henning
R
53

I use the following:

(add-hook 'LaTeX-mode-hook
          (lambda () (local-set-key (kbd "C-0") #'run-latexmk)))

to have a bind defined for LaTeX mode alone.

Retentive answered 9/1, 2013 at 8:3 Comment(3)
The # was redundant with me.Longfellow
I had to set 'latex-mode-hook instead (no caps). I also found the # unnecessary.Sectary
On sharp quoting #' endlessparentheses.com/…Pasticcio
S
49

To bind a key in a mode, you need to wait for the mode to be loaded before defining the key. One could require the mode, or use eval-after-load

   (eval-after-load 'latex 
                    '(define-key LaTeX-mode-map [(tab)] 'outline-cycle))

Don't forget either 'eval-after-load is not a macro, so it needs them.

Santinasantini answered 31/3, 2011 at 20:24 Comment(5)
How do you determine the first argument to eval-after-load programmatically?Falco
I think it's enough to provide any function which belongs to the mode – e.g. 'LaTeX-mode instead of 'latex would do just as well.Nanice
For me the variable is called latex-mode-map (all lower case). LaTeX-mode-map doesn't exist.Kenji
[(tab)] is old syntax for (kbd "TAB")Shofar
@LenarHoyt: actually, no: [(tab)] is the same as [tab] which is the key-sequence sent when you hit the TAB key in the GUI version of Emacs. (kbd "TAB") OTOH is the same as [?\t] which is the key-sequence sent when you hit that same TAB key in a text terminal (which is also the same key-sequence sent when you hit C-i). The two options are "unified" inside Emacs by function-key-map which remaps [tab] to (kbd "TAB") if there's no binding to [tab]. So if you want your binding to work both in a GUI and in a tty, better use (kbd "TAB").Henning
A
13

You need to identify the key map for that mode (for example, LaTeX-mode-map) and use the function define-key. As an example, along with activating outline-minor-mode within LaTeX mode, I have:

  (define-key LaTeX-mode-map [(tab)] 'outline-cycle))

In this case the major mode (LaTeX) holds the key binding, but there is also an outline-minor-mode-map.

Allantois answered 31/3, 2011 at 12:58 Comment(0)
S
5

None of the other answers satisfied my needs. So this may help other people. I wanted Tab to jump to the beginning of the line if I'm in Evil's normal mode (basically this means everywhere in Emacs), but I instead wanted it to cycle between org item states if I am in an org-mode document.

One option was to mess around with separate bindings and constant binding-rebinding whenever I switched buffers (because evil allows only one binding per key in its normal state).

But a more efficient option was to make Tab run my own code which runs the required function based on which major mode the current buffer uses. So if I am in a org buffer, this code runs org-cycle, and otherwise it runs evil-first-non-blank (go to the first non-whitespace character on the line).

The technique I used here can also be used by calling your custom function via global-set-key instead, for people who use regular non-evil Emacs.

For those who don't know Emacs lisp, the first line after the "if" statement is the true-action, and the line after that is the false-action. So if major-mode equals org-mode, we run org-cycle, otherwise we run evil-first-non-blank in all other modes:

  (defun my/tab-jump-or-org-cycle ()
    "jumps to beginning of line in all modes except org mode, where it cycles"
    (interactive)
    (if (equal major-mode 'org-mode)
        (org-cycle)
      (evil-first-non-blank))
    )
  (define-key evil-normal-state-map (kbd "<tab>") 'my/tab-jump-or-org-cycle)
Shirker answered 10/12, 2016 at 20:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.