b48c5c4976
A new section for my awesome website. Migrates an old blogpost from the github repository. Change-Id: I5fd0c2b2679a1367015fa098e3e787bbc0cdd973 Reviewed-on: https://cl.tvl.fyi/c/depot/+/3293 Tested-by: BuildkiteCI Reviewed-by: Profpatsch <mail@profpatsch.de>
123 lines
5.1 KiB
Markdown
123 lines
5.1 KiB
Markdown
title: Ligature Emulation in Emacs
|
||
date: 2017-05-04
|
||
|
||
Monday was (yet another)
|
||
[NixOS hackathon][hackathon] at [OpenLab Augsburg][ola].
|
||
[Maximilian][mhuber] was there and to my amazement
|
||
he got working ligatures in his Haskell files in Emacs! Ever since Hasklig
|
||
updated its format to use ligatures and private Unicode code points a while ago,
|
||
the hack I had used in my config stopped working.
|
||
|
||
Encouraged by that I decided to take a look on Tuesday. Long story short, I was
|
||
able to [get it working in a pretty satisfying way][done].
|
||
|
||
[hackathon]: https://www.meetup.com/Munich-NixOS-Meetup/events/239077247/
|
||
[mhuber]: https://github.com/maximilianhuber
|
||
[ola]: https://openlab-augsburg.de
|
||
[done]: https://github.com/i-tu/Hasklig/issues/84#issuecomment-298803495
|
||
|
||
What’s left to do is package it into a module and push to melpa.
|
||
|
||
|
||
### elisp still sucks, but it’s bearable, sometimes
|
||
|
||
I’m the kind of person who, when trying to fix something elisp related, normally
|
||
gives up two hours later and three macro calls deep. Yes, homoiconic,
|
||
non-lexically-scoped, self-rewriting code is not exactly my fetish.
|
||
This time the task and the library (`prettify-symbols-mode`) were simple enough
|
||
for that to not happen.
|
||
|
||
Some interesting technical trivia:
|
||
|
||
- elisp literal character syntax is `?c`. `?\t` is the tab character
|
||
- You join characters by `(string c1 c2 c3 ...)`
|
||
- [dash.el][dash] is pretty awesome and does what a functional programmer
|
||
expects. Also, Rainbow Dash.
|
||
- Hasklig and FiraCode multi-column symbols actually [only occupy one column, on
|
||
the far right of the glyph][glyph]. `my-correct-symbol-bounds` fixes emacs’
|
||
rendering in that case.
|
||
|
||
|
||
[dash]: https://github.com/magnars/dash.el
|
||
[glyph]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239082368
|
||
|
||
|
||
## Appendix A
|
||
|
||
For reference, here’s the complete code as it stands now. Feel free to paste
|
||
into your config; let’s make it [MIT][mit]. Maybe link to this site, in case there are
|
||
updates.
|
||
|
||
[mit]: https://opensource.org/licenses/MIT
|
||
|
||
```elisp
|
||
(defun my-correct-symbol-bounds (pretty-alist)
|
||
"Prepend a TAB character to each symbol in this alist,
|
||
this way compose-region called by prettify-symbols-mode
|
||
will use the correct width of the symbols
|
||
instead of the width measured by char-width."
|
||
(mapcar (lambda (el)
|
||
(setcdr el (string ?\t (cdr el)))
|
||
el)
|
||
pretty-alist))
|
||
|
||
(defun my-ligature-list (ligatures codepoint-start)
|
||
"Create an alist of strings to replace with
|
||
codepoints starting from codepoint-start."
|
||
(let ((codepoints (-iterate '1+ codepoint-start (length ligatures))))
|
||
(-zip-pair ligatures codepoints)))
|
||
|
||
; list can be found at https://github.com/i-tu/Hasklig/blob/master/GlyphOrderAndAliasDB#L1588
|
||
(setq my-hasklig-ligatures
|
||
(let* ((ligs '("&&" "***" "*>" "\\\\" "||" "|>" "::"
|
||
"==" "===" "==>" "=>" "=<<" "!!" ">>"
|
||
">>=" ">>>" ">>-" ">-" "->" "-<" "-<<"
|
||
"<*" "<*>" "<|" "<|>" "<$>" "<>" "<-"
|
||
"<<" "<<<" "<+>" ".." "..." "++" "+++"
|
||
"/=" ":::" ">=>" "->>" "<=>" "<=<" "<->")))
|
||
(my-correct-symbol-bounds (my-ligature-list ligs #Xe100))))
|
||
|
||
;; nice glyphs for haskell with hasklig
|
||
(defun my-set-hasklig-ligatures ()
|
||
"Add hasklig ligatures for use with prettify-symbols-mode."
|
||
(setq prettify-symbols-alist
|
||
(append my-hasklig-ligatures prettify-symbols-alist))
|
||
(prettify-symbols-mode))
|
||
|
||
(add-hook 'haskell-mode-hook 'my-set-hasklig-ligatures)
|
||
```
|
||
|
||
## Appendix B (Update 1): FiraCode integration
|
||
|
||
I also created a mapping for [FiraCode][fira]. You need to grab the [additional
|
||
symbol font][symbol] that adds (most) ligatures to the unicode private use area.
|
||
Consult your system documentation on how to add it to your font cache.
|
||
Next add `"Fira Code"` and `"Fira Code Symbol"` to your font preferences. Symbol
|
||
only contains the additional characters, so you need both.
|
||
|
||
If you are on NixOS, the font package should be on the main branch shortly, [I
|
||
added a package][symbol-pkg].
|
||
|
||
[fira]: https://github.com/tonsky/FiraCode/
|
||
[symbol]: https://github.com/tonsky/FiraCode/issues/211#issuecomment-239058632
|
||
[symbol-pkg]: https://github.com/NixOS/nixpkgs/pull/25517
|
||
|
||
Here’s the mapping adjusted for FiraCode:
|
||
|
||
```elisp
|
||
(setq my-fira-code-ligatures
|
||
(let* ((ligs '("www" "**" "***" "**/" "*>" "*/" "\\\\" "\\\\\\"
|
||
"{-" "[]" "::" ":::" ":=" "!!" "!=" "!==" "-}"
|
||
"--" "---" "-->" "->" "->>" "-<" "-<<" "-~"
|
||
"#{" "#[" "##" "###" "####" "#(" "#?" "#_" "#_("
|
||
".-" ".=" ".." "..<" "..." "?=" "??" ";;" "/*"
|
||
"/**" "/=" "/==" "/>" "//" "///" "&&" "||" "||="
|
||
"|=" "|>" "^=" "$>" "++" "+++" "+>" "=:=" "=="
|
||
"===" "==>" "=>" "=>>" "<=" "=<<" "=/=" ">-" ">="
|
||
">=>" ">>" ">>-" ">>=" ">>>" "<*" "<*>" "<|" "<|>"
|
||
"<$" "<$>" "<!--" "<-" "<--" "<->" "<+" "<+>" "<="
|
||
"<==" "<=>" "<=<" "<>" "<<" "<<-" "<<=" "<<<" "<~"
|
||
"<~~" "</" "</>" "~@" "~-" "~=" "~>" "~~" "~~>" "%%"
|
||
"x" ":" "+" "+" "*")))
|
||
(my-correct-symbol-bounds (my-ligature-list ligs #Xe100))))
|
||
```
|