62

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?

N.N.
  • 8,336
  • 12
  • 54
  • 94
aL3xa
  • 35,415
  • 18
  • 79
  • 112
  • More and more I find myself going to the Emacs Wiki for help: http://www.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. – drysdam Mar 31 '11 at 12:50
  • Yepp... I saw that one already, but I get `Symbol's value as variable is void: LaTeX-mode-map` all the time. Hmmm... – aL3xa Mar 31 '11 at 13:30

4 Answers4

52

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.

Dror
  • 12,174
  • 21
  • 90
  • 160
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.

Evgeniy Berezovsky
  • 18,571
  • 13
  • 82
  • 156
Rémi
  • 8,172
  • 2
  • 27
  • 32
  • 10
    How do you determine the first argument to `eval-after-load` programmatically? – ealfonso Sep 26 '13 at 18:01
  • 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. – Emily Sep 26 '14 at 18:51
  • For me the variable is called latex-mode-map (all lower case). LaTeX-mode-map doesn't exist. – Anton Eliasson Nov 30 '14 at 09:26
  • 2
    `[(tab)]` is old syntax for `(kbd "TAB")` – Lenar Hoyt Nov 26 '15 at 10:50
  • 3
    @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")`. – Stefan Oct 25 '17 at 18:09
10

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.

Kirk Kelsey
  • 4,259
  • 1
  • 23
  • 26
4

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)