3

I'm using use-package for my configuration in init.el. How can I bind a key to a map that has not yet been defined?

As a specific example, I'm using the following configuration of

(use-package latex-mode
  :ensure auctex
  :mode "\\.tex\\'" "\\.sty\\'")

I'm also using the citar package for LaTeX and Org bibliographies:

(use-package citar
  :hook ((LaTeX-mode org-mode) . citar-capf-setup)
  :bind (:map LaTeX-mode-map ("C-c [" . #'citar-insert-citation)))

Unfortunately, if I open an .org file first, I get the following error: "File mode specification error: (void-variable LaTeX-mode-map)".

Within the use-package framework, what is the correct way to resolve this error? I could always hook the keybinding into LaTeX-mode-hook, but I'm wondering if there is a use-package-based solution?

EDIT: Here is a minimal init.el that produces the above error if I first open a .org file before opening a .tex file.

(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
(add-to-list 'package-archives '("gnu"   . "https://elpa.gnu.org/packages/"))
(add-to-list 'package-archives '("org"   . "https://orgmode.org/elpa/"))

(package-initialize)
(unless package-archive-contents
  (package-refresh-contents))

(unless (package-installed-p 'use-package)
  (package-refresh-contents)
  (package-install 'use-package))

(eval-and-compile
  (setq use-package-always-ensure t
        use-package-expand-minimally t))

;; LaTeX mode and citar

(use-package tex
  :ensure auctex)

(use-package citar
  :hook ((LaTeX-mode org-mode) . citar-capf-setup)
  :bind (:map LaTeX-mode-map ("C-c [" . #'citar-insert-citation)))

3 Answers 3

3
+100

EDIT In response to @Tyler's comments here, and his answer and the comments there

After looking again at the 'Binding to local keymaps' section of the use-package documentation, I now understand that that method should only be used for keymaps defined in the package getting declared. Therefore, I would suggest that the cleanest solution (i.e. deferred and without any errors) is to simply load the latex package as follows:

(use-package latex
  :ensure auctex
  :ensure citar
  :hook ((LaTeX-mode org-mode) . citar-capf-setup)
  :bind (:map LaTeX-mode-map ("C-c [" . citar-insert-citation)))

That we can use the :ensure keyword twice was found by trial and error combined with M-x pp-macroexpand-last-sexp. Of course :defer is implied by using :hook and/or :bind.

SECOND EDIT In response to question in the comments

The

(use-package tex
  :ensure auctex)

could be considered 'arbitrary' and 'undesired'; arbitrary because any of the files that provides a 'feature' could have been used, and 'undesired' because it makes the 'tex.el' file load immediately (not deferred). It is really only used for installing auctex, but use-package/require can only declare libraries that provide a feature, and the author of the documentation has arbitrarily chosen the tex package in order to install via use-package. You could also just install via package-install and the 'auctex' package will load fine. The only auctex file that has got to be loaded immediately is tex-site.el(c), but that is taken care of by using the autoload mechanism to 'require it' (see the auctex-autoloads.el file)

The :bind section is executed after loading the declared package. Because LaTeX-mode-map is defined in the latex.el file, it is not yet defined after loading tex.el. As the only way to load the definition is by loading latex.el, we simply declare 'latex' so that it is loaded when the :bind section gets executed.

END EDIT

The latex-mode-map exists already on Emacs startup. Just downcase the full name LaTeX-mode-map to latex-mode-map, and your use-package declaration should work fine. You should also downcase LaTeX-mode to latex-mode in the :hook keyword.

Additionally, latex-mode is defined in the tex-mode mode library, so your first use-package declaration should declare tex-mode instead of latex-mode.

"\\.tex\\'" and "\\.sty\\'" are already included in the auto-mode-alist by default, so you can remove that :mode keyword from the tex-mode declaration. Your .tex documents will be opened in latex-mode as long as your tex-default-mode is set to latex-mode (the default).

In case you would have to add latex-mode via the :mode keyword in the tex-mode declaration, then you can find in the ':mode' section of the use-package documentation how to do that.

Finally, in case the latex-mode-map had not been defined yet, as far as I understand from the 'Binding to local keymaps' section in the use-package documentation, using the :map keyword in the :bind section should automatically defer defining the keybinding until the tex-mode package got loaded. I don't see a (sharp-)quote in that documentation, so let's remove it.

In the end, the following should be correct declarations:

(use-package tex-mode
  :ensure auctex)

(use-package citar
  :hook ((latex-mode org-mode) . citar-capf-setup)
  :bind (:map latex-mode-map ("C-c [" . citar-insert-citation)))
5
  • 3
    latex-mode and LaTeX-mode are not the same thing. The first is part of Emacs, defined in tex-mode.el, and the second is part of AucTeX, defined in latex.el in that package.
    – Tyler
    Oct 16, 2023 at 2:32
  • Thanks! I am not using AUCTeX at the moment, so I did not notice that indeed. Oct 16, 2023 at 12:39
  • it can be very confusing, but these libraries are very old and the names are stuck now!
    – Tyler
    Oct 16, 2023 at 12:41
  • I've added a (what I think is the) correct and cleanest solution. Oct 16, 2023 at 23:51
  • Thanks! The code from your edit does indeed work the way I'd like. One thing still puzzles me however. The AUCTeX manual does indeed suggest (use-package tex :ensure auctex), but I was not able to get your code to work with use-package tex. I had to use use-package latex (which is what you have). Do you have any idea why there is this discrepancy with the AUCTeX manual? It's not a big deal; I'm just curious. Oct 17, 2023 at 19:27
1

I think there is a problem with this code:

(use-package latex-mode
  :ensure auctex
  :mode "\\.tex\\'" "\\.sty\\'")

latex-mode is the built-in LaTeX mode for Emacs, which is not the same as LaTeX-mode provided by the AucTeX package. If you want to use the AucTeX version, this section will over-ride your intentions, and directs Emacs to use latex-mode for tex files.

It's probably not necessary at all, but if you want to use use-package as part of your AucTeX config, the recommended code (from the manual) is:

(use-package tex
  :ensure auctex)

After you remove the problematic first section, the second section should work as you expect (it does for me, with AucTeX and citar both installed via the package system):

(use-package citar
  :hook ((LaTeX-mode org-mode) . citar-capf-setup)
  :bind (:map LaTeX-mode-map ("C-c [" . #'citar-insert-citation)))

If you want to use the non-AucTeX version, latex-mode, make sure to use this version (i.e., all lower case) in your :hook and :bind arguments.

7
  • The :bind here does not work when visiting an org buffer first, because latex.el then has not been loaded yet. Now as the binding is added to the LaTeX-mode-map, we can just add it via :config and a (with-eval-after-load 'latex ..., however, the :config block here, for some weird reason, only gets called when visiting an org file, but not when visiting a tex file, even though the 'hook' runs successfully for both. So then we can add it via the :init keyword, in which case it finally works correctly. Oct 16, 2023 at 14:18
  • @dalanicolai ah, I missed the part about visiting an org file first, I only tested on a .tex file! thanks
    – Tyler
    Oct 16, 2023 at 15:10
  • @dalanicolai after testing, it 'works' without error for me when opening an org file? Can you or Henry/OP provide the steps to reproduce the error?
    – Tyler
    Oct 16, 2023 at 15:17
  • @Tyler and @dalanicolai I've attached a minimal init.el that produces the error if I open an .org file before opening a .tex file. Oct 16, 2023 at 16:38
  • @dalanicolai @Tyler Yes, I could certainly do something with with-eval-after-load as dalanicolai suggests, but I was hoping that there would be a more paradigmatic use-package solution. Oct 16, 2023 at 16:43
0

Based on @dalanicolai's suggestion of two :ensures, I realized that use-package citar could be split in two, with the :bind with LaTeX-mode-map being guarded by :after latex (and not the more permissive :after (:any latex org)). This seems to work correctly for me.

(use-package latex
  :ensure auctex
  :mode ("\\.tex\\'" . LaTeX-mode))

(use-package citar
  :after (:any latex org)
  :hook ((LaTeX-mode org-mode) . citar-capf-setup))

(use-package citar
  :after latex
  :bind (:map LaTeX-mode-map ("C-c [" . citar-insert-citation)))

The inclusion of :mode ("\\.tex\\'" . LaTeX-mode) is necessary to defer loading of AUCTeX until a .tex buffer is created. It may also be possible to replace this with :defer because, as @dalanicolai pointed out, "\\.tex\\'" is among auto-mode-alist.

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.