Since version 24.1, Emacs' BibTeX mode supports biblatex entries. This works very nice indeed. However, I make heavy use of biblatex's extensiblility, with custom entrytypes and corresponding entryfields, and this leaves BibTeX mode at a loss in dealing with these entries.

In trying to sort this out, I examined bibtex.el and found two customizable alists, which seemed the way to go: bibtex-biblatex-field-alist and bibtex-biblatex-entry-alist.

So I customized them with:

(use-package bibtex
  (bibtex-dialect (quote biblatex));; biblatex as default bib format

  ;; Support for custom biblatex entries and fields in BibTeX mode
  (setq my/primary-bibtex-biblatex-field-alist
  (setq bibtex-biblatex-field-alist
        (append bibtex-biblatex-field-alist my/primary-bibtex-biblatex-field-alist))

  (setq my/primary-bibtex-biblatex-entry-alist
        '(("Archive" "Archive"
           (("location") ("shortarchive")))))
  (setq bibtex-biblatex-entry-alist
        (append bibtex-biblatex-entry-alist my/primary-bibtex-biblatex-entry-alist)))

To support an entrytype with the following structure:

  title = {},
  OPTlocation = {},
  OPTshortarchive = {},

Examination of bibtex-biblatex-field-alist and bibtex-biblatex-entry-alist shows they are configured as expected, and indeed issuing bibtex-clean-entry with C-c C-c works as expected (prior to customization, I received a Not inside a BibTeX entry error).

However, the new entrytype does not show up in the "Entry-Types" menu. Also, the command bibtex-Archive is not available with M-x as with the standard entrytypes. How could I achieve both these things in order to be able to insert an empty template of my custom entrytype for edition, as I can with the usual entrytypes?


As far as I searched, both in the web and in Emacs internal documentation, I couldn't find an up to date manual for BibTeX mode (If anyone knows where to find it, please let me know). There are the docstrings in bibtex.el of course, which already go a long way. But there is an old version of a manual made available online by a good soul.

There, we find the following comment regarding bibtex-entry-field-alist:

If you want to change this variable, the best idea might be to get the source code of BibTeX mode from file 'bibtex.el', copy this variable's definition to your '.emacs' file, change it to a setq statement (see section 'Setting Variables' in Emacs Lisp Manual), and modify the variable's contents.

That's quite certainly the proper/canonical way do deal with this. It does work indeed. You can also customize bibtex-biblatex-field-alist and bibtex-biblatex-entry-alist to equivalent effect.

The only "problem" with that, is that bibtex-biblatex-entry-alist is about 250 lines of code and bibtex-biblatex-field-alist another almost 90. Plus the ones I want to add. That's quite a lot, in my view.

What goes wrong with my initial approach as set in the question is that the menus and commands get built upon loading bibtex.el, thus using the original value of the lists as defined there, and my appends come too late, when menu/commands are already built.

An alternative to redefining the full lists would be to rebuild the menu/commands after I've appended to the lists. Unfortunately, bibtex.el does not wrap this routine in any sort of function we could then call, so we'd have to bring the corresponding code.

(use-package bibtex
  (bibtex-dialect (quote biblatex));; biblatex as default bib format

  ;; Support for custom biblatex entries and fields in BibTeX mode
  (setq bibtex-biblatex-field-alist
        (append bibtex-biblatex-field-alist

  (setq bibtex-biblatex-entry-alist
        (append bibtex-biblatex-entry-alist
                '(("Archive" "Archive"
                   (("location") ("shortarchive"))))))

  ;; Taken from bibtex.el, the routine that builds the menus etc.
  ;; This must be (re)executed after `bibtex-biblatex-entry-alist` and
  ;; `bibtex-biblatex-field-alist` have been redefined. Alternative is to
  ;; redefine the *full* lists with `setq` in the `:init` section
  (let ((select-map (make-sparse-keymap)))
  ;; Submenu for selecting the dialect
  (dolist (dialect (reverse bibtex-dialect-list))
    (define-key select-map (vector dialect)
      `(menu-item ,(symbol-name dialect)
                  (lambda () (interactive) (bibtex-set-dialect ',dialect t))
                  :button (:radio . (eq bibtex-dialect ',dialect)))))
  ;; We define a menu for each dialect.
  ;; Then we select the menu we want via the :visible keyword
  (dolist (dialect bibtex-dialect-list)
    (let ((entry-alist (bibtex-entry-alist dialect))
          (menu-map (make-sparse-keymap)))
      (define-key menu-map [select]
        `(menu-item "BibTeX dialect" ,select-map))
      (define-key menu-map [nil-2] '(menu-item "--"))
      (define-key menu-map [bibtex-preamble]
        '(menu-item "Preamble" bibtex-Preamble))
      (define-key menu-map [bibtex-String]
        '(menu-item "String" bibtex-String))
      (define-key menu-map [nil-1] '(menu-item "--"))
      (dolist (elt (reverse entry-alist))
        ;; Entry commands
        (let* ((entry (car elt))
               (fname (intern (format "bibtex-%s" entry))))
          (unless (fboundp fname)
            (eval (list 'defun fname nil
                        (format "Insert a template for a @%s entry; see also `bibtex-entry'."
                        '(interactive "*")
                        `(bibtex-entry ,entry))))
          ;; Menu entries
          (define-key menu-map (vector fname)
            `(menu-item ,(or (nth 1 elt) (car elt)) ,fname))))
      (define-key bibtex-mode-map
        (vector 'menu-bar dialect)
        `(menu-item "Entry-Types" ,menu-map
                    :visible (eq bibtex-dialect ',dialect))))))
  ;; End of taken from bibtex.el

That's shorter, I'm not sure it is wiser though. Still, it does work.

Update: For the record. I eventually chose to customize the full lists. It feels wiser, despite the code overhead.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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