Search code examples
emacslatexelispfont-lock

Emacs-lisp: prettify-symbols-mode for LaTeX


I was trying to port over the "pretty entities" behaviour from org-mode to latex-mode using the Emacs builtin prettify-symbols-mode. This mode uses font-lock-mode to display character sequences in a buffer as a single (unicode) character. By default for instance emacs-lisp code

(lambda () t)

becomes

(λ () t)

It does however seem to require the character sequences to be separated by some characters, e.g. white-spaces. For instance in my setup, the replacement

\alpha \beta -> α β`

will work, but it will fail when the strings are not separated, e.g.

\alpha\beta -> \alphaβ

This is an issue specifically, because I wanted to use this prettification to make quantum mechanical equations more readable, where I e.g. the replacement like

|\psi\rangle -> |ψ⟩

Is it possible to avoid this delimiter-issue using prettify-symbols-mode? And if it is not, is it possible by using font-lock-mode on a lower level?


Solution

  • Here's the code that should do what you want:

    (defvar pretty-alist
      (cl-pairlis '("alpha" "beta" "gamma" "delta" "epsilon" "zeta" "eta"
                    "theta" "iota" "kappa" "lambda" "mu" "nu" "xi"
                    "omicron" "pi" "rho" "sigma_final" "sigma" "tau"
                    "upsilon" "phi" "chi" "psi" "omega")
                  (mapcar
                   (lambda (x) (make-char 'greek-iso8859-7 x))
                   (number-sequence 97 121))))
    (add-to-list 'pretty-alist '("rangle" . ?\⟩))
    (defun pretty-things ()
      (mapc
       (lambda (x)
         (let ((word (car x))
               (char (cdr x)))
           (font-lock-add-keywords
            nil
            `((,(concat "\\(^\\|[^a-zA-Z0-9]\\)\\(" word "\\)[a-zA-Z]")
                (0 (progn
                     (decompose-region (match-beginning 2) (match-end 2))
                     nil)))))
           (font-lock-add-keywords
            nil
            `((,(concat "\\(^\\|[^a-zA-Z0-9]\\)\\(" word "\\)[^a-zA-Z]")
                (0 (progn
                     (compose-region (1- (match-beginning 2)) (match-end 2)
                      ,char)
                     nil)))))))
       pretty-alist))
    

    As you can see above, pretty-alist starts out with greek chars. Then I add \rangle just to demonstrate how to add new things. To enable it automatically, add it to the hook:

    (add-hook 'LaTeX-mode-hook 'pretty-things)
    

    I used the code from here as a starting point, you can look there for a reference.