53

PragmataPro is a typeface that comes with a number of programming ligatures. My understanding is that these are OpenType face (OTF) ligatures.

I am aware that Emacs supports programmatic replacement of character combinations (for example -> to or lambda to λ). However, these are unicode faux ligatures, since they have their own code points, which real ligatures do not.

Am I correct that Emacs (as of 25) does not support OTF ligatures automatically? On a lower level, are there options available to manually specify glyph mappings?

If ligatures are unsupported, then what needs to be done for Emacs to support ligatures?

6
  • 3
    Looks like it's not yet supported: lists.gnu.org/archive/html/emacs-devel/2015-01/msg00024.html Feb 25, 2015 at 22:52
  • Out of curiosity, what are some of the "number of useful enhancements" you have in mind?
    – Dan
    Jun 8, 2015 at 12:16
  • 3
    Improved variable-width rendering in text mode, programming ligatures that make source code more attractive without affecting the shape of the code, and diagrammatic ligatures for boxes and arrows. In hindsight, "attractive" is probably a better descriptor than "useful". Jun 8, 2015 at 12:28
  • github.com/i-tu/Hasklig/issues/10 is tracking Emacs support for Hasklig. A partial solution, which works specifically for Hasklig and haskell-mode is detailed in this gist. Feb 19, 2016 at 15:36
  • 3
    A recent post on r/emacs posted a workaround using prettify-symbols-mode, and it works pretty good with PragmataPro 0.822. Aug 3, 2016 at 16:55

2 Answers 2

10

emacs for now doesn't support ligatures (on OSX there is some support, but not on other platforms). However, emacs 24.4+ supports prettify-symbols-mode which in some ways is better than normal ligatures support.

That mode allows to subsitute for display any regex with any glyph. I am personnally using this snippet to get Fira Code ligatures to work in emacs on linux. (EDIT: unfortunately the link is now dead, the policy of stackoverflow to always copy inline is obviously the good one...)

The link I originally put is dead and I'm not certain exactly what it contained but I think these links should be good: https://github.com/tonsky/FiraCode/wiki/Emacs-instructions#using-prettify-symbols and https://github.com/tonsky/FiraCode/issues/312#issuecomment-262878734

Given the dead link issue, I'm putting the code inline this time:

(defun fira-code-mode--make-alist (list)
  "Generate prettify-symbols alist from LIST."
  (let ((idx -1))
    (mapcar
     (lambda (s)
       (setq idx (1+ idx))
       (let* ((code (+ #Xe100 idx))
          (width (string-width s))
          (prefix ())
          (suffix '(?\s (Br . Br)))
          (n 1))
     (while (< n width)
       (setq prefix (append prefix '(?\s (Br . Bl))))
       (setq n (1+ n)))
     (cons s (append prefix suffix (list (decode-char 'ucs code))))))
     list)))

(defconst fira-code-mode--ligatures
  '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\"
    "{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}"
    "--" "---" "-->" "->" "->>" "-<" "-<<" "-~"
    "#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_("
    ".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*"
    "/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||="
    "|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "=="
    "===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">="
    ">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>"
    "<$" "<$>" "<!--" "<-" "<--" "<->" "<+" "<+>" "<="
    "<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" "<~"
    "<~~" "</" "</>" "~@" "~-" "~=" "~>" "~~" "~~>" "%%"
    "x" ":" "+" "+" "*"))

(defvar fira-code-mode--old-prettify-alist)

(defun fira-code-mode--enable ()
  "Enable Fira Code ligatures in current buffer."
  (setq-local fira-code-mode--old-prettify-alist prettify-symbols-alist)
  (setq-local prettify-symbols-alist (append (fira-code-mode--make-alist fira-code-mode--ligatures) fira-code-mode--old-prettify-alist))
  (prettify-symbols-mode t))

(defun fira-code-mode--disable ()
  "Disable Fira Code ligatures in current buffer."
  (setq-local prettify-symbols-alist fira-code-mode--old-prettify-alist)
  (prettify-symbols-mode -1))

(define-minor-mode fira-code-mode
  "Fira Code ligatures minor mode"
  :lighter " Fira Code"
  (setq-local prettify-symbols-unprettify-at-point 'right-edge)
  (if fira-code-mode
      (fira-code-mode--enable)
    (fira-code-mode--disable)))

(defun fira-code-mode--setup ()
  "Setup Fira Code Symbols"
  (set-fontset-font t '(#Xe100 . #Xe16f) "Fira Code Symbol"))

(provide 'fira-code-mode)

I said that in some ways this is better than normal ligatures.. That's because it's "a la carte". You can mix-and-match, take only the symbols you like. You can say, I want the ";;" ligature, EXCEPT if the next character is again ";" in that case I don't want it... And about mix-and-matching... I'm using the 'Fira Mono' font, together with the 'Fira Code' ligatures. You don't have to buy in the whole font.

It's worse than pure ligatures because it doesn't work out of the box and it requires the font to be tuned in a certain way to make it possible.

5
  • Hi! Could you share this snippet to get Fira Code ligatures work? Gist seems to be deleted.
    – xamenrax
    Mar 25, 2019 at 3:03
  • huh sorry... updated the answer, I hope it helps Mar 25, 2019 at 6:25
  • 1
    Thank you! Almost 3 years has passed by but something never changes - people desperate about making ligatures work in Emacs...
    – xamenrax
    Mar 25, 2019 at 7:52
  • This didn't work correctly for me with Emacs 26.3 on Ubuntu 18.04: I get the wrong symbols, when the line is highlighted and different wrong symbols when it doesn't. Also failed to use this method with JetBrains Mono font
    – Chen Levy
    Jan 23, 2020 at 7:12
  • prettify-symbols-mode doesn't work as fine as ligature. It can only render symbols to one character.
    – shynur
    Jul 15 at 1:31
0

If you are on OS X I believe the Carbon Mac Emacs port supports ligatures.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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