After installing the JetBrains Mono Font and setting it as my default face. I am wandering how to enable Ligatures in Emacs.
I tried a solution based on this answer that show how to do this with Fira Code, with what I think are the required modifications I am speaking about:
EDIT: @Piquan's answer, suggested to me that I wasn't clear about what are the required modifications to the fira-code-mode, so here they are:
- Search and replace from fira-code to jetbrains-mono
- Change the code points from
#Xe100 . #Xe16f
to#X10001 . #X1009c
- Update the
jetbrains-ligature-mode--ligatures
constant to reflect the actual character map of the JetBrains Mono font as I see them (using FontForge). - Since the
#X10001 . #X1009c
contains some diacritics I didn't wish to be part of the resultingprettify-symbols-alist
, I put somenil
s into the said constant, and introduced an(if ...)
expression to thejetbrains-ligature-mode--make-alist
function to ignore thosenil
s and just increment the code point. - AFAIK, the reason the Fira Code Ligature was created for Emacs compatibility, is to be compatible with the upstream haskling-mode that used those code points. But since I modified the numbers to be compatible with the JetBrains Mono original font, this is not needed.
- I should be able to do without
jetbrains-ligature-mode--setup
function, but I figured out it shouldn't hurt to keep it (and indeed removing it as a troubleshooting step didn't help).
Thus the resulting code is:
(defun jetbrains-ligature-mode--make-alist (list)
"Generate prettify-symbols alist from LIST."
(let ((idx -1))
(mapcar
(lambda (s)
(setq idx (1+ idx))
(if s
(let* ((code (+ #X10001 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 jetbrains-ligature-mode--ligatures
'("-->" "//" "/**" "/*" "*/" "<!--" ":=" "->>" "<<-" "->" "<-"
"<=>" "==" "!=" "<=" ">=" "=:=" "!==" "&&" "||" "..." ".."
nil nil nil nil nil nil nil nil nil nil nil nil nil nil
"|||" "///" "&&&" "===" "++" "--" "=>" "|>" "<|" "||>" "<||"
"|||>" "<|||" ">>" "<<" nil nil "::=" "|]" "[|" "{|" "|}"
"[<" ">]" ":?>" ":?" nil "/=" "[||]" "!!" "?:" "?." "::"
"+++" "??" "###" "##" ":::" "####" ".?" "?=" "=!=" "<|>"
"<:" ":<" ":>" ">:" "<>" "***" ";;" "/==" ".=" ".-" "__"
"=/=" "<-<" "<<<" ">>>" "<=<" "<<=" "<==" "<==>" "==>" "=>>"
">=>" ">>=" ">>-" ">-" "<~>" "-<" "-<<" "=<<" "---" "<-|"
"<=|" "/\\" "\\/" "|=>" "|~>" "<~~" "<~" "~~" "~~>" "~>"
"<$>" "<$" "$>" "<+>" "<+" "+>" "<*>" "<*" "*>" "</>" "</" "/>"
"<->" "..<" "~=" "~-" "-~" "~@" "^=" "-|" "_|_" "|-" "||-"
"|=" "||=" "#{" "#[" "]#" "#(" "#?" "#_" "#_(" "#:" "#!" "#="
"&="))
(defvar jetbrains-ligature-mode--old-prettify-alist)
(defun jetbrains-ligature-mode--enable ()
"Enable JetBrains Mono ligatures in current buffer."
(setq-local jetbrains-ligature-mode--old-prettify-alist prettify-symbols-alist)
(setq-local prettify-symbols-alist (append (jetbrains-ligature-mode--make-alist jetbrains-ligature-mode--ligatures) jetbrains-ligature-mode--old-prettify-alist))
(prettify-symbols-mode t))
(defun jetbrains-ligature-mode--disable ()
"Disable JetBrains Mono ligatures in current buffer."
(setq-local prettify-symbols-alist jetbrains-ligature-mode--old-prettify-alist)
(prettify-symbols-mode -1))
(define-minor-mode jetbrains-ligature-mode
"JetBrains Mono ligatures minor mode"
:lighter " JetBrains Mono"
(setq-local prettify-symbols-unprettify-at-point 'right-edge)
(if jetbrains-ligature-mode
(jetbrains-ligature-mode--enable)
(jetbrains-ligature-mode--disable)))
(defun jetbrains-ligature-mode--setup ()
"Setup JetBrains Mono Symbols"
(set-fontset-font t '(#X10001 . #X1009c) "JetBrains Mono"))
(provide 'jetbrains-ligature-mode)
However the best I got so far is that the sequence is replaced with an empty space (although with the correct length).
What am I missing?
I am using Emacs 26.3 (from Kevin Kelley's PPA) on Kubuntu 18.04