Move :ui pretty-code to :ui ligatures

Includes a major refactor of the module.
This commit is contained in:
Henrik Lissner 2020-08-12 18:52:14 -04:00
parent ed264dcdb2
commit 7081d833f6
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
32 changed files with 899 additions and 920 deletions

View file

@ -0,0 +1,123 @@
;;; ui/ligatures/+fira.el -*- lexical-binding: t; -*-
(+ligatures--def-font fira
("Fira Code Symbol"
:range '(#Xe100 . #Xe16f)
:url "https://github.com/tonsky/FiraCode/raw/13234c0/distr/ttf/%s"
:files '("FiraCode-Bold.ttf"
"FiraCode-Light.ttf"
"FiraCode-Medium.ttf"
"FiraCode-Regular.ttf"
"FiraCode-Retina.ttf"))
("www" . #Xe100)
("**" . #Xe101)
("***" . #Xe102)
("**/" . #Xe103)
("*>" . #Xe104)
("*/" . #Xe105)
("\\\\" . #Xe106)
("\\\\\\" . #Xe107)
("{-" . #Xe108)
("[]" . #Xe109)
("::" . #Xe10a)
(":::" . #Xe10b)
(":=" . #Xe10c)
("!!" . #Xe10d)
("!=" . #Xe10e)
("!==" . #Xe10f)
("-}" . #Xe110)
("--" . #Xe111)
("---" . #Xe112)
("-->" . #Xe113)
("->" . #Xe114)
("->>" . #Xe115)
("-<" . #Xe116)
("-<<" . #Xe117)
("-~" . #Xe118)
("#{" . #Xe119)
("#[" . #Xe11a)
("##" . #Xe11b)
("###" . #Xe11c)
("####" . #Xe11d)
("#(" . #Xe11e)
("#?" . #Xe11f)
("#_" . #Xe120)
("#_(" . #Xe121)
(".-" . #Xe122)
(".=" . #Xe123)
(".." . #Xe124)
("..<" . #Xe125)
("..." . #Xe126)
("?=" . #Xe127)
("??" . #Xe128)
(";;" . #Xe129)
("/*" . #Xe12a)
("/**" . #Xe12b)
("/=" . #Xe12c)
("/==" . #Xe12d)
("/>" . #Xe12e)
("//" . #Xe12f)
("///" . #Xe130)
("&&" . #Xe131)
("||" . #Xe132)
("||=" . #Xe133)
("|=" . #Xe134)
("|>" . #Xe135)
("^=" . #Xe136)
("$>" . #Xe137)
("++" . #Xe138)
("+++" . #Xe139)
("+>" . #Xe13a)
("=:=" . #Xe13b)
("==" . #Xe13c)
("===" . #Xe13d)
("==>" . #Xe13e)
("=>" . #Xe13f)
("=>>" . #Xe140)
("=<" . #Xe141)
("=<<" . #Xe142)
("=/=" . #Xe143)
(">-" . #Xe144)
(">=" . #Xe145)
(">=>" . #Xe146)
(">>" . #Xe147)
(">>-" . #Xe148)
(">>=" . #Xe149)
(">>>" . #Xe14a)
("<*" . #Xe14b)
("<*>" . #Xe14c)
("<|" . #Xe14d)
("<|>" . #Xe14e)
("<$" . #Xe14f)
("<$>" . #Xe150)
("<!--" . #Xe151)
("<-" . #Xe152)
("<--" . #Xe153)
("<->" . #Xe154)
("<+" . #Xe155)
("<+>" . #Xe156)
("<=" . #Xe157)
("<==" . #Xe158)
("<=>" . #Xe159)
("<=<" . #Xe15a)
("<>" . #Xe15b)
("<<" . #Xe15c)
("<<-" . #Xe15d)
("<<=" . #Xe15e)
("<<<" . #Xe15f)
("<~" . #Xe160)
("<~~" . #Xe161)
("</" . #Xe162)
("</>" . #Xe163)
("~@" . #Xe164)
("~-" . #Xe165)
("~=" . #Xe166)
("~>" . #Xe167)
("~~" . #Xe168)
("~~>" . #Xe169)
("%%" . #Xe16a)
("x" . #Xe16b)
(":" . #Xe16c)
("+" . #Xe16d)
("+" . #Xe16e)
("*" . #Xe16f))

View file

@ -0,0 +1,62 @@
;;; ui/ligatures/+hasklig.el -*- lexical-binding: t; -*-
(+ligatures--def-font hasklig
("Hasklig"
:range '(#Xe100 . #Xe129)
:url "https://github.com/jsravn/hasklig-emacs/raw/33354a3/%s"
:files '("Hasklig-Black.otf"
"Hasklig-BlackIt.otf"
"Hasklig-Bold.otf"
"Hasklig-BoldIt.otf"
"Hasklig-ExtraLight.otf"
"Hasklig-ExtraLightIt.otf"
"Hasklig-It.otf"
"Hasklig-Light.otf"
"Hasklig-LightIt.otf"
"Hasklig-Medium.otf"
"Hasklig-MediumIt.otf"
"Hasklig-Regular.otf"
"Hasklig-Semibold.otf"
"Hasklig-SemiboldIt.otf"))
("&&" . #Xe100)
("***" . #Xe101)
("*>" . #Xe102)
("\\\\" . #Xe103)
("||" . #Xe104)
("|>" . #Xe105)
("::" . #Xe106)
("==" . #Xe107)
("===" . #Xe108)
("==>" . #Xe109)
("=>" . #Xe10a)
("=<<" . #Xe10b)
("!!" . #Xe10c)
(">>" . #Xe10d)
(">>=" . #Xe10e)
(">>>" . #Xe10f)
(">>-" . #Xe110)
(">-" . #Xe111)
("->" . #Xe112)
("-<" . #Xe113)
("-<<" . #Xe114)
("<*" . #Xe115)
("<*>" . #Xe116)
("<|" . #Xe117)
("<|>" . #Xe118)
("<$>" . #Xe119)
("<>" . #Xe11a)
("<-" . #Xe11b)
("<<" . #Xe11c)
("<<<" . #Xe11d)
("<+>" . #Xe11e)
(".." . #Xe11f)
("..." . #Xe120)
("++" . #Xe121)
("+++" . #Xe122)
("/=" . #Xe123)
(":::" . #Xe124)
(">=>" . #Xe125)
("->>" . #Xe126)
("<=>" . #Xe127)
("<=<" . #Xe128)
("<->" . #Xe129))

View file

@ -0,0 +1,244 @@
;;; ui/ligatures/+iosevka.el -*- lexical-binding: t; -*-
(+ligatures--def-font iosevka
("Iosevka"
:range '(#Xe100 . #Xe1cc)
:url "https://github.com/jsravn/iosevka-emacs/raw/20fc2c4/%s"
:files '("iosevka-custom-lightoblique.ttf"
"iosevka-custom-thinoblique.ttf"
"iosevka-custom-mediumitalic.ttf"
"iosevka-custom-light.ttf"
"iosevka-custom-heavy.ttf"
"iosevka-custom-bolditalic.ttf"
"iosevka-custom-bold.ttf"
"iosevka-custom-lightitalic.ttf"
"iosevka-custom-thin.ttf"
"iosevka-custom-extralight.ttf"
"iosevka-custom-oblique.ttf"
"iosevka-custom-italic.ttf"
"iosevka-custom-heavyoblique.ttf"
"iosevka-custom-heavyitalic.ttf"
"iosevka-custom-extralightitalic.ttf"
"iosevka-custom-thinitalic.ttf"
"iosevka-custom-medium.ttf"
"iosevka-custom-mediumoblique.ttf"
"iosevka-custom-extralightoblique.ttf"
"iosevka-custom-boldoblique.ttf"
"iosevka-custom-regular.ttf"))
;; Double-ended hyphen arrows
("<->" . #Xe100)
("<-->" . #Xe101)
("<--->" . #Xe102)
("<---->" . #Xe103)
("<----->" . #Xe104)
;; Double-ended equals arrows
("<=>" . #Xe105)
("<==>" . #Xe106)
("<===>" . #Xe107)
("<====>" . #Xe108)
("<=====>" . #Xe109)
;; Double-ended asterisk operators
("<**>" . #Xe10a)
("<***>" . #Xe10b)
("<****>" . #Xe10c)
("<*****>" . #Xe10d)
;; HTML comments
("<!--" . #Xe10e)
("<!---" . #Xe10f)
;; Three-char ops with discards
("<$" . #Xe110)
("<$>" . #Xe111)
("$>" . #Xe112)
("<." . #Xe113)
("<.>" . #Xe114)
(".>" . #Xe115)
("<*" . #Xe116)
("<*>" . #Xe117)
("*>" . #Xe118)
("<\\" . #Xe119)
("<\\>" . #Xe11a)
("\\>" . #Xe11b)
("</" . #Xe11c)
("</>" . #Xe11d)
("/>" . #Xe11e)
("<\"" . #Xe11f)
("<\">" . #Xe120)
("\">" . #Xe121)
("<'" . #Xe122)
("<'>" . #Xe123)
("'>" . #Xe124)
("<^" . #Xe125)
("<^>" . #Xe126)
("^>" . #Xe127)
("<&" . #Xe128)
("<&>" . #Xe129)
("&>" . #Xe12a)
("<%" . #Xe12b)
("<%>" . #Xe12c)
("%>" . #Xe12d)
("<@" . #Xe12e)
("<@>" . #Xe12f)
("@>" . #Xe130)
("<#" . #Xe131)
("<#>" . #Xe132)
("#>" . #Xe133)
("<+" . #Xe134)
("<+>" . #Xe135)
("+>" . #Xe136)
("<-" . #Xe137)
("<->" . #Xe138)
("->" . #Xe139)
("<!" . #Xe13a)
("<!>" . #Xe13b)
("!>" . #Xe13c)
("<?" . #Xe13d)
("<?>" . #Xe13e)
("?>" . #Xe13f)
("<|" . #Xe140)
("<|>" . #Xe141)
("|>" . #Xe142)
("<:" . #Xe143)
("<:>" . #Xe144)
(":>" . #Xe145)
;; Colons
("::" . #Xe146)
(":::" . #Xe147)
("::::" . #Xe148)
;; Arrow-like operators
("->" . #Xe149)
("->-" . #Xe14a)
("->--" . #Xe14b)
("->>" . #Xe14c)
("->>-" . #Xe14d)
("->>--" . #Xe14e)
("->>>" . #Xe14f)
("->>>-" . #Xe150)
("->>>--" . #Xe151)
("-->" . #Xe152)
("-->-" . #Xe153)
("-->--" . #Xe154)
("-->>" . #Xe155)
("-->>-" . #Xe156)
("-->>--" . #Xe157)
("-->>>" . #Xe158)
("-->>>-" . #Xe159)
("-->>>--" . #Xe15a)
(">-" . #Xe15b)
(">--" . #Xe15c)
(">>-" . #Xe15d)
(">>--" . #Xe15e)
(">>>-" . #Xe15f)
(">>>--" . #Xe160)
("=>" . #Xe161)
("=>=" . #Xe162)
("=>==" . #Xe163)
("=>>" . #Xe164)
("=>>=" . #Xe165)
("=>>==" . #Xe166)
("=>>>" . #Xe167)
("=>>>=" . #Xe168)
("=>>>==" . #Xe169)
("==>" . #Xe16a)
("==>=" . #Xe16b)
("==>==" . #Xe16c)
("==>>" . #Xe16d)
("==>>=" . #Xe16e)
("==>>==" . #Xe16f)
("==>>>" . #Xe170)
("==>>>=" . #Xe171)
("==>>>==" . #Xe172)
(">=" . #Xe173)
(">==" . #Xe174)
(">>=" . #Xe175)
(">>==" . #Xe176)
(">>>=" . #Xe177)
(">>>==" . #Xe178)
("<-" . #Xe179)
("-<-" . #Xe17a)
("--<-" . #Xe17b)
("<<-" . #Xe17c)
("-<<-" . #Xe17d)
("--<<-" . #Xe17e)
("<<<-" . #Xe17f)
("-<<<-" . #Xe180)
("--<<<-" . #Xe181)
("<--" . #Xe182)
("-<--" . #Xe183)
("--<--" . #Xe184)
("<<--" . #Xe185)
("-<<--" . #Xe186)
("--<<--" . #Xe187)
("<<<--" . #Xe188)
("-<<<--" . #Xe189)
("--<<<--" . #Xe18a)
("-<" . #Xe18b)
("--<" . #Xe18c)
("-<<" . #Xe18d)
("--<<" . #Xe18e)
("-<<<" . #Xe18f)
("--<<<" . #Xe190)
("<=" . #Xe191)
("=<=" . #Xe192)
("==<=" . #Xe193)
("<<=" . #Xe194)
("=<<=" . #Xe195)
("==<<=" . #Xe196)
("<<<=" . #Xe197)
("=<<<=" . #Xe198)
("==<<<=" . #Xe199)
("<==" . #Xe19a)
("=<==" . #Xe19b)
("==<==" . #Xe19c)
("<<==" . #Xe19d)
("=<<==" . #Xe19e)
("==<<==" . #Xe19f)
("<<<==" . #Xe1a0)
("=<<<==" . #Xe1a1)
("==<<<==" . #Xe1a2)
("=<" . #Xe1a3)
("==<" . #Xe1a4)
("=<<" . #Xe1a5)
("==<<" . #Xe1a6)
("=<<<" . #Xe1a7)
("==<<<" . #Xe1a8)
;; Monadic operators
(">=>" . #Xe1a9)
(">->" . #Xe1aa)
(">-->" . #Xe1ab)
(">==>" . #Xe1ac)
("<=<" . #Xe1ad)
("<-<" . #Xe1ae)
("<--<" . #Xe1af)
("<==<" . #Xe1b0)
;; Composition operators
(">>" . #Xe1b1)
(">>>" . #Xe1b2)
("<<" . #Xe1b3)
("<<<" . #Xe1b4)
;; Lens operators
(":+" . #Xe1b5)
(":-" . #Xe1b6)
(":=" . #Xe1b7)
("+:" . #Xe1b8)
("-:" . #Xe1b9)
("=:" . #Xe1ba)
("=^" . #Xe1bb)
("=+" . #Xe1bc)
("=-" . #Xe1bd)
("=*" . #Xe1be)
("=/" . #Xe1bf)
("=%" . #Xe1c0)
("^=" . #Xe1c1)
("+=" . #Xe1c2)
("-=" . #Xe1c3)
("*=" . #Xe1c4)
("/=" . #Xe1c5)
("%=" . #Xe1c6)
;; Logical
("/\\" . #Xe1c7)
("\\/" . #Xe1c8)
;; Semigroup/monoid operators
("<>" . #Xe1c9)
("<+" . #Xe1ca)
("<+>" . #Xe1cb)
("+>" . #Xe1cc))

View file

@ -0,0 +1,249 @@
;;; ui/ligatures/+pragmata-pro.el -*- lexical-binding: t; -*-
(+ligatures--def-font pragmata-pro
("PragmataPro")
;; Double-ended hyphen arrows
("[ERROR]" . #XE2C0)
("[DEBUG]" . #XE2C1)
("[INFO]" . #XE2C2)
("[WARN]" . #XE2C3)
("[WARNING]" . #XE2C4)
("[ERR]" . #XE2C5)
("[FATAL]" . #XE2C6)
("[TRACE]" . #XE2C7)
("[FIXME]" . #XE2C8)
("[TODO]" . #XE2C9)
("[BUG]" . #XE2CA)
("[NOTE]" . #XE2CB)
("[HACK]" . #XE2CC)
("[MARK]" . #XE2CD)
("# ERROR" . #XE2F0)
("# DEBUG" . #XE2F1)
("# INFO" . #XE2F2)
("# WARN" . #XE2F3)
("# WARNING" . #XE2F4)
("# ERR" . #XE2F5)
("# FATAL" . #XE2F6)
("# TRACE" . #XE2F7)
("# FIXME" . #XE2F8)
("# TODO" . #XE2F9)
("# BUG" . #XE2FA)
("# NOTE" . #XE2FB)
("# HACK" . #XE2FC)
("# MARK" . #XE2FD)
("// ERROR" . #XE2E0)
("// DEBUG" . #XE2E1)
("// INFO" . #XE2E2)
("// WARN" . #XE2E3)
("// WARNING". #XE2E4)
("// ERR" . #XE2E5)
("// FATAL" . #XE2E6)
("// TRACE" . #XE2E7)
("// FIXME" . #XE2E8)
("// TODO" . #XE2E9)
("// BUG" . #XE2EA)
("// NOTE" . #XE2EB)
("// HACK" . #XE2EC)
("// MARK" . #XE2ED)
("!!" . #XE900)
("!=" . #XE901)
("!==" . #XE902)
("!!!" . #XE903)
("!≡" . #XE904)
("!≡≡" . #XE905)
("!>" . #XE906)
("!=<" . #XE907)
("#(" . #XE920)
("#_" . #XE921)
("#{" . #XE922)
("#?" . #XE923)
("#>" . #XE924)
("##" . #XE925)
("#_(" . #XE926)
("%=" . #XE930)
("%>" . #XE931)
("%>%" . #XE932)
("%<%" . #XE933)
("&%" . #XE940)
("&&" . #XE941)
("&*" . #XE942)
("&+" . #XE943)
("&-" . #XE944)
("&/" . #XE945)
("&=" . #XE946)
("&&&" . #XE947)
("&>" . #XE948)
("$>" . #XE955)
("***" . #XE960)
("*=" . #XE961)
("*/" . #XE962)
("*>" . #XE963)
("++" . #XE970)
("+++" . #XE971)
("+=" . #XE972)
("+>" . #XE973)
("++=" . #XE974)
("--" . #XE980)
("-<" . #XE981)
("-<<" . #XE982)
("-=" . #XE983)
("->" . #XE984)
("->>" . #XE985)
("---" . #XE986)
("-->" . #XE987)
("-+-" . #XE988)
("-\\/" . #XE989)
("-|>" . #XE98A)
("-<|" . #XE98B)
(".." . #XE990)
("..." . #XE991)
("..<" . #XE992)
(".>" . #XE993)
(".~" . #XE994)
(".=" . #XE995)
("/*" . #XE9A0)
("//" . #XE9A1)
("/>" . #XE9A2)
("/=" . #XE9A3)
("/==" . #XE9A4)
("///" . #XE9A5)
("/**" . #XE9A6)
(":::" . #XE9AF)
("::" . #XE9B0)
(":=" . #XE9B1)
(":≡" . #XE9B2)
(":>" . #XE9B3)
(":=>" . #XE9B4)
(":(" . #XE9B5)
(":-(" . #XE9B6)
(":)" . #XE9B7)
(":-)" . #XE9B8)
(":/" . #XE9B9)
(":\\" . #XE9BA)
(":3" . #XE9BB)
(":D" . #XE9BC)
(":P" . #XE9BD)
(":>:" . #XE9BE)
(":<:" . #XE9BF)
("<$>" . #XE9C0)
("<*" . #XE9C1)
("<*>" . #XE9C2)
("<+>" . #XE9C3)
("<-" . #XE9C4)
("<<" . #XE9C5)
("<<<" . #XE9C6)
("<<=" . #XE9C7)
("<=" . #XE9C8)
("<=>" . #XE9C9)
("<>" . #XE9CA)
("<|>" . #XE9CB)
("<<-" . #XE9CC)
("<|" . #XE9CD)
("<=<" . #XE9CE)
("<~" . #XE9CF)
("<~~" . #XE9D0)
("<<~" . #XE9D1)
("<$" . #XE9D2)
("<+" . #XE9D3)
("<!>" . #XE9D4)
("<@>" . #XE9D5)
("<#>" . #XE9D6)
("<%>" . #XE9D7)
("<^>" . #XE9D8)
("<&>" . #XE9D9)
("<?>" . #XE9DA)
("<.>" . #XE9DB)
("</>" . #XE9DC)
("<\\>" . #XE9DD)
("<\">" . #XE9DE)
("<:>" . #XE9DF)
("<~>" . #XE9E0)
("<**>" . #XE9E1)
("<<^" . #XE9E2)
("<!" . #XE9E3)
("<@" . #XE9E4)
("<#" . #XE9E5)
("<%" . #XE9E6)
("<^" . #XE9E7)
("<&" . #XE9E8)
("<?" . #XE9E9)
("<." . #XE9EA)
("</" . #XE9EB)
("<\\" . #XE9EC)
("<\"" . #XE9ED)
("<:" . #XE9EE)
("<->" . #XE9EF)
("<!--" . #XE9F0)
("<--" . #XE9F1)
("<~<" . #XE9F2)
("<==>" . #XE9F3)
("<|-" . #XE9F4)
("<<|" . #XE9F5)
("<-<" . #XE9F7)
("<-->" . #XE9F8)
("<<==" . #XE9F9)
("<==" . #XE9FA)
("=<<" . #XEA00)
("==" . #XEA01)
("===" . #XEA02)
("==>" . #XEA03)
("=>" . #XEA04)
("=~" . #XEA05)
("=>>" . #XEA06)
("=/=" . #XEA07)
("=~=" . #XEA08)
("==>>" . #XEA09)
("≡≡" . #XEA10)
("≡≡≡" . #XEA11)
("≡:≡" . #XEA12)
(">-" . #XEA20)
(">=" . #XEA21)
(">>" . #XEA22)
(">>-" . #XEA23)
(">>=" . #XEA24)
(">>>" . #XEA25)
(">=>" . #XEA26)
(">>^" . #XEA27)
(">>|" . #XEA28)
(">!=" . #XEA29)
(">->" . #XEA2A)
("??" . #XEA40)
("?~" . #XEA41)
("?=" . #XEA42)
("?>" . #XEA43)
("???" . #XEA44)
("?." . #XEA45)
("^=" . #XEA48)
("^." . #XEA49)
("^?" . #XEA4A)
("^.." . #XEA4B)
("^<<" . #XEA4C)
("^>>" . #XEA4D)
("^>" . #XEA4E)
("\\\\" . #XEA50)
("\\>" . #XEA51)
("\\/-" . #XEA52)
("@>" . #XEA57)
("|=" . #XEA60)
("||" . #XEA61)
("|>" . #XEA62)
("|||" . #XEA63)
("|+|" . #XEA64)
("|->" . #XEA65)
("|-->" . #XEA66)
("|=>" . #XEA67)
("|==>" . #XEA68)
("|>-" . #XEA69)
("|<<" . #XEA6A)
("||>" . #XEA6B)
("|>>" . #XEA6C)
("|-" . #XEA6D)
("||-" . #XEA6E)
("~=" . #XEA70)
("~>" . #XEA71)
("~~>" . #XEA72)
("~>>" . #XEA73)
("[[" . #XEA80)
("]]" . #XEA81)
("\">" . #XEA90)
("_|_" . #XEA97))

View file

@ -0,0 +1,108 @@
#+TITLE: ui/ligatures
#+DATE: June 16, 2018
#+SINCE: v2.0.9
#+STARTUP: inlineimages nofold
* Table of Contents :TOC_3:noexport:
- [[#description][Description]]
- [[#maintainers][Maintainers]]
- [[#module-flags][Module Flags]]
- [[#font-ligatures-module-flags][Font ligatures module flags]]
- [[#plugins][Plugins]]
- [[#prerequisites][Prerequisites]]
- [[#mutsuharus-emacs-mac-port-or-emacs-28-with-harfbuzz-support][Mutsuharu's emacs-mac port or Emacs 28+ with Harfbuzz support]]
- [[#not-emacs-mac-and-emacs--27][Not Emacs-mac and Emacs <= 27]]
- [[#features][Features]]
- [[#mathematical-symbols-replacement][Mathematical symbols replacement]]
- [[#coding-ligatures][Coding ligatures]]
- [[#configuration][Configuration]]
- [[#set-ligatures][~set-ligatures!~]]
- [[#troubleshooting][Troubleshooting]]
* Description
This module enables ligatures and arbitrary symbol substitutions with
~mac-auto-operator-composition-mode~ (on supported macOS systems) or composition
tables (harfbuzz on Emacs 28), falling back on ~prettify-symbols-mode~
otherwise.
** Maintainers
This module has no dedicated maintainers.
** Module Flags
+ =+extra= Enables extra symbol substitutions in certain modes, for example
~lambda~ in lisps are replaced with ~λ~.
*** Font ligatures module flags
This module provides four flags for enabling fall-back ligature support for a
particular font. They are:
+ =+fira= Enables =Fira Code= ligatures. This requires Fira Code Symbol and a
patched version of Fira Code (see below).
+ =+hasklig= Enable =Hasklig= ligatures. This requires a patched version of the
HaskLig font (see below).
+ =+iosevka= Enable =Iosevka= ligatures. This requires a patched version of the
Iosevka font (see below).
+ =+pragmata-pro= Enable =Pragmata Pro= ligatures. This requires the [[https://www.fsd.it/shop/fonts/pragmatapro/][Pragmata
Pro font]].
#+begin_quote
All these flags are ignored _if_ you're sporting either a) Emacs 28+ with
Harfbuzz support (which can compose ligatures natively), or b) Mitsuharu's
=emacs-mac= build on macOS (which uses ~mac-auto-operator-composition-mode~).
#+end_quote
** Plugins
This module installs no packages.
* Prerequisites
This module requires one of three setups for ligatures to work:
- A recent enough version of Emacs which will compose ligatures automatically
(Emacs 28 with Harfbuzz support), or
- Mitsuharu's =emacs-mac= build on macOS (available on homebrew), or
- A patched font for Doom's fallback ligature support.
** Mutsuharu's emacs-mac port or Emacs 28+ with Harfbuzz support
Ligatures should be handled without any additional configuration.
** Not Emacs-mac and Emacs <= 27
1. Enable one of the four ligature font flags: =+fira=, =+hasklig=, =+iosevka=
or =+pragmata-pro=.
2. Install the patched version of the associated font with ~M-x
+ligatures/install-patched-font~. Note: Pragmata Pro cannot be installed this
way because it is a non-free font and must be purchased and installed
manually.
* TODO Features
** TODO Mathematical symbols replacement
** Coding ligatures
This module includes configuration to compose combinations like =->= or =::=
into prettier glyphs (called a ligature). Depending on the current version of
emacs, this is implemented in two different ways :
- prettify-symbols-mode method :: this is the "legacy" method. It uses a font
which haves the ligatures as separate unicode symbols, and using
prettify-symbols-mode, =->=-like combinations are manually listed and replaced
with the correct symbol. The mapping between =->=-like sequences and unicode
values in the font are font-specific ; therefore =+fira=, =+iosevka=... files
and specific fonts are necessary for it to work.
- composition-function-table method :: regexps are used to match all the usual
sequences which are composed into ligatures. These regexps are passed to emacs
directly, which asks Harfbuzz to shape it. Ligatures are obtained
automatically depending on the capabilities of the font, and no font-specific
configuration is necessary.
Emacs-mac port implements the /composition-function-table/ method in [[https://bitbucket.org/mituharu/emacs-mac/src/26c8fd9920db9d34ae8f78bceaec714230824dac/lisp/term/mac-win.el?at=master#lines-345:805][its code]],
nothing is necessary on Doom side; otherwise, Doom implements the
/composition-function-table/ for emacs 28+ built with Harfbuzz support, and the
/prettify-symbols-mode/ method otherwise.
Even though harfbuzz has been included in emacs 27, there is currently a [[https://lists.gnu.org/archive/html/bug-gnu-emacs/2020-04/msg01121.html][bug
(#40864)]] which prevents a safe usage of /composition-function-table/ method in
emacs 27.
* TODO Configuration
** TODO ~set-ligatures!~
* TODO Troubleshooting
# Common issues and their solution, or places to look for help.

View file

@ -0,0 +1,58 @@
;;; ui/ligatures/autoload/install.el -*- lexical-binding: t; -*-
;;;###if (or (featurep! +fira) (featurep! +hasklig) (featurep! +iosevka))
(defun +ligatures--install-font (prefix name url-format fonts-alist &optional extra-fonts)
"Install fonts to the local system.
If PREFIX is nil, will prompt whether or not to download. NAME is informational
only. URL-FORMAT is a format string that should be a url and have a single %s,
which is expanded for each font in FONTS-ALIST. FONTS-ALIST should be the
filename of each font. It is used as the source and destination filename."
(unless (or prefix
(yes-or-no-p
(format "This will download and install the %s fonts, continue?"
name)))
(user-error "Aborted"))
(let* ((font-dest
(cond (IS-LINUX
(expand-file-name
"fonts/" (or (getenv "XDG_DATA_HOME")
"~/.local/share")))
(IS-MAC
(expand-file-name "~/Library/Fonts/"))))
(known-dest-p (stringp font-dest))
(font-dest (or font-dest (read-directory-name "Font installation directory: " "~/"))))
(unless (file-directory-p font-dest)
(mkdir font-dest t))
(dolist (font fonts-alist)
(url-copy-file (format url-format font)
(expand-file-name font font-dest)
t))
(when known-dest-p
(message "Font downloaded, updating font cache... <fc-cache -f -v> ")
(shell-command-to-string "fc-cache -f -v"))
(if IS-WINDOW
(when (y-or-n-p "The %S font was downloaded, but Windows users must install them manually.\n\nShow files in windows explorer?")
(call-process "explorer.exe" nil nil nil font-dest))
(message "Successfully %s %S fonts to %S!"
(if known-dest-p "installed" "downloaded")
name font-dest))))
;;;###autoload
(defun +ligatures/install-patched-font (font-id &optional arg)
"Install the font FONT-ID on your system.
FONT-ID must be a key from `+ligatures--font-alist'.
If PREFIX is non-nil, don't ask for confirmation and install it."
(interactive
(list
(car (cl-find (completing-read
"Install font: "
(mapcar #'cadr +ligatures--font-alist))
+ligatures--font-alist
:key #'cadr
:test #'equal))
current-prefix-arg))
(cl-destructuring-bind (font-name &keys _range url files)
(or (alist-get font-id +ligatures--font-alist)
(user-error "%S is not a valid font" font-id))
(+ligatures--install-font prefix font-name url files)))

View file

@ -0,0 +1,50 @@
;;; ui/ligatures/autoload/ligatures.el -*- lexical-binding: t; -*-
;; DEPRECATED
;;;###autodef
(define-obsolete-function-alias 'set-pretty-symbols! 'set-ligatures! "3.0.0")
;;;###autodef
(defun set-ligatures! (modes &rest plist)
"Associates string patterns with icons in certain major-modes.
MODES is a major mode symbol or a list of them.
PLIST is a property list whose keys must match keys in `+ligatures-classes',
and whose values are strings representing the text to be replaced with that
symbol. If the car of PLIST is nil, then unset any pretty symbols previously
defined for MODES.
This function accepts one special property:
:alist ALIST
Appends ALIST to `prettify-symbols-alist' literally, without mapping text to
`+ligatures-classes'.
For example, the rule for emacs-lisp-mode is very simple:
(set-ligatures! 'emacs-lisp-mode
:lambda \"lambda\")
This will replace any instances of \"lambda\" in emacs-lisp-mode with the symbol
assicated with :lambda in `+ligatures-classes'.
Pretty symbols can be unset for emacs-lisp-mode with:
(set-ligatures! 'emacs-lisp-mode nil)"
(declare (indent defun))
(if (null (car-safe plist))
(dolist (mode (doom-enlist modes))
(assq-delete-all mode +ligatures-extra-alist))
(let (results)
(while plist
(let ((key (pop plist)))
(if (eq key :alist)
(prependq! results (pop plist))
(when-let (char (plist-get +ligatures-classes key))
(push (cons (pop plist) char) results)))))
(dolist (mode (doom-enlist modes))
(setf (alist-get mode +ligatures-extra-alist)
(if-let (old-results (alist-get mode +ligatures-extra-alist))
(dolist (cell results old-results)
(setf (alist-get (car cell) old-results) (cdr cell)))
results))))))

View file

@ -0,0 +1,213 @@
;;; ui/ligatures/config.el -*- lexical-binding: t; -*-
(defvar +ligatures-classes
'(;; org
:name "»"
:src_block "»"
:src_block_end "«"
:quote ""
:quote_end ""
;; Functional
:lambda "λ"
:def "ƒ"
:composition ""
:map ""
;; Types
:null ""
:true "𝕋"
:false "𝔽"
:int ""
:float ""
:str "𝕊"
:bool "𝔹"
:list "𝕃"
;; Flow
:not ""
:in ""
:not-in ""
:and ""
:or ""
:for ""
:some ""
:return ""
:yield ""
;; Other
:union ""
:intersect ""
:diff ""
:tuple ""
:pipe "" ;; FIXME: find a non-private char
:dot "")
"Options plist for `set-ligatures!'.
This should not contain any symbols from the Unicode Private Area! There is no
universal way of getting the correct symbol as that area varies from font to
font.")
(defvar +ligatures-composition-alist
'((?! . "\\(?:!\\(?:==\\|[!=]\\)\\)") ; (regexp-opt '("!!" "!=" "!=="))
(?# . "\\(?:#\\(?:###?\\|_(\\|[#(:=?[_{]\\)\\)") ; (regexp-opt '("##" "###" "####" "#(" "#:" "#=" "#?" "#[" "#_" "#_(" "#{"))
(?$ . "\\(?:\\$>>?\\)") ; (regexp-opt '("$>" "$>>"))
(?% . "\\(?:%%%?\\)") ; (regexp-opt '("%%" "%%%"))
(?& . "\\(?:&&&?\\)") ; (regexp-opt '("&&" "&&&"))
(?* . "\\(?:\\*\\(?:\\*[*/]\\|[)*/>]\\)?\\)") ; (regexp-opt '("*" "**" "***" "**/" "*/" "*>" "*)"))
(?+ . "\\(?:\\+\\(?:\\+\\+\\|[+:>]\\)?\\)") ; (regexp-opt '("+" "++" "+++" "+>" "+:"))
(?- . "\\(?:-\\(?:-\\(?:->\\|[>-]\\)\\|<[<-]\\|>[>-]\\|[:<>|}~-]\\)\\)") ; (regexp-opt '("--" "---" "-->" "--->" "->-" "-<" "-<-" "-<<" "->" "->>" "-}" "-~" "-:" "-|"))
(?. . "\\(?:\\.\\(?:\\.[.<]\\|[.=>-]\\)\\)") ; (regexp-opt '(".-" ".." "..." "..<" ".=" ".>"))
(?/ . "\\(?:/\\(?:\\*\\*\\|//\\|==\\|[*/=>]\\)\\)") ; (regexp-opt '("/*" "/**" "//" "///" "/=" "/==" "/>"))
(?: . "\\(?::\\(?:::\\|[+:<=>]\\)?\\)") ; (regexp-opt '(":" "::" ":::" ":=" ":<" ":=" ":>" ":+"))
(?\; . ";;") ; (regexp-opt '(";;"))
(?0 . "0\\(?:\\(x[a-fA-F0-9]\\).?\\)") ; Tries to match the x in 0xDEADBEEF
;; (?x . "x") ; Also tries to match the x in 0xDEADBEEF
;; (regexp-opt '("<!--" "<$" "<$>" "<*" "<*>" "<**>" "<+" "<+>" "<-" "<--" "<---" "<->" "<-->" "<--->" "</" "</>" "<<" "<<-" "<<<" "<<=" "<=" "<=<" "<==" "<=>" "<===>" "<>" "<|" "<|>" "<~" "<~~" "<." "<.>" "<..>"))
(?< . "\\(?:<\\(?:!--\\|\\$>\\|\\*\\(?:\\*?>\\)\\|\\+>\\|-\\(?:-\\(?:->\\|[>-]\\)\\|[>-]\\)\\|\\.\\(?:\\.?>\\)\\|/>\\|<[<=-]\\|=\\(?:==>\\|[<=>]\\)\\||>\\|~~\\|[$*+./<=>|~-]\\)\\)")
(?= . "\\(?:=\\(?:/=\\|:=\\|<<\\|=[=>]\\|>>\\|[=>]\\)\\)") ; (regexp-opt '("=/=" "=:=" "=<<" "==" "===" "==>" "=>" "=>>"))
(?> . "\\(?:>\\(?:->\\|=>\\|>[=>-]\\|[:=>-]\\)\\)") ; (regexp-opt '(">-" ">->" ">:" ">=" ">=>" ">>" ">>-" ">>=" ">>>"))
(?? . "\\(?:\\?[.:=?]\\)") ; (regexp-opt '("??" "?." "?:" "?="))
(?\[ . "\\(?:\\[\\(?:|]\\|[]|]\\)\\)") ; (regexp-opt '("[]" "[|]" "[|"))
(?\\ . "\\(?:\\\\\\\\[\\n]?\\)") ; (regexp-opt '("\\\\" "\\\\\\" "\\\\n"))
(?^ . "\\(?:\\^==?\\)") ; (regexp-opt '("^=" "^=="))
(?w . "\\(?:wwww?\\)") ; (regexp-opt '("www" "wwww"))
(?{ . "\\(?:{\\(?:|\\(?:|}\\|[|}]\\)\\|[|-]\\)\\)") ; (regexp-opt '("{-" "{|" "{||" "{|}" "{||}"))
(?| . "\\(?:|\\(?:->\\|=>\\||=\\|[]=>|}-]\\)\\)") ; (regexp-opt '("|=" "|>" "||" "||=" "|->" "|=>" "|]" "|}" "|-"))
(?_ . "\\(?:_\\(?:|?_\\)\\)") ; (regexp-opt '("_|_" "__"))
(?\( . "\\(?:(\\*\\)") ; (regexp-opt '("(*"))
(?~ . "\\(?:~\\(?:~>\\|[=>@~-]\\)\\)")) ; (regexp-opt '("~-" "~=" "~>" "~@" "~~" "~~>"))
"An alist of all ligatures used by `+ligatures-extras-in-modes'.
The car is the character ASCII number, cdr is a regex which will call
`font-shape-gstring' when matched.
Because of the underlying code in :ui ligatures module, the regex should match a
string starting with the character contained in car.
This variable is used only if you built Emacs with Harfbuzz on a version >= 28")
(defvar +ligatures-extra-alist '((t))
"An alist mapping major modes to `prettify-symbols-alist' values.")
(defvar +ligatures-in-modes
'(not special-mode comint-mode eshell-mode term-mode vterm-mode)
"List of major modes where ligatures should be enabled.
If t, enable it everywhere (except `fundamental-mode').
If the first element is 'not, enable it in any mode besides what is listed.
If nil, don't enable ligatures anywhere.")
(defvar +ligatures-extras-in-modes t
"List of major modes where extra ligatures should be enabled.
Extra ligatures are mode-specific substituions, defined in `+ligatures-classes'
and assigned with `set-ligatures!'. This variable controls where these are
enabled.
If t, enable it everywhere (except `fundamental-mode').
If the first element is 'not, enable it in any mode besides what is listed.
If nil, don't enable these extra ligatures anywhere (though it's more
efficient to remove the `+extra' flag from the :ui ligatures module instead).")
(defvar +ligatures--init-font-hook nil)
(defun +ligatures--correct-symbol-bounds (ligature-alist)
"Prepend non-breaking spaces to a ligature.
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'."
(let ((len (length (car ligature-alist)))
(acc (list (cdr ligature-alist))))
(while (> len 1)
(setq acc (cons #X00a0 (cons '(Br . Bl) acc))
len (1- len)))
(cons (car ligature-alist) acc)))
(defun +ligatures--enable-p (modes)
"Return t if ligatures should be enabled in this buffer depending on MODES."
(unless (eq major-mode 'fundamental-mode)
(or (eq modes t)
(if (eq (car modes) 'not)
(not (apply #'derived-mode-p (cdr modes)))
(apply #'derived-mode-p modes)))))
(defun +ligatures-init-buffer-h ()
"Set up ligatures for the current buffer.
Extra ligatures are mode-specific substituions, defined in
`+ligatures-classes', assigned with `set-ligatures!', and made possible
with `prettify-symbols-mode'. This variable controls where these are enabled.
See `+ligatures-extras-in-modes' to control what major modes this function can
and cannot run in."
(when after-init-time
(when (+ligatures--enable-p +ligatures-in-modes)
(if (boundp '+ligature--composition-table)
(setq-local composition-function-table +ligature--composition-table)
(run-hooks '+ligatures--init-font-hook)
(setq +ligatures--init-font-hook nil)))
(when (and (featurep! +extra)
(+ligatures--enable-p +ligatures-extras-in-modes))
(prependq! prettify-symbols-alist (alist-get major-mode +ligatures-extra-alist)))
(when prettify-symbols-alist
(if prettify-symbols-mode (prettify-symbols-mode -1))
(prettify-symbols-mode +1))))
;;
;;; Bootstrap
;;;###package prettify-symbols
;; When you get to the right edge, it goes back to how it normally prints
(setq prettify-symbols-unprettify-at-point 'right-edge)
(add-hook! 'doom-init-ui-hook :append
(defun +ligatures-init-h ()
(add-hook 'after-change-major-mode-hook #'+ligatures-init-buffer-h)))
(cond
;; The emacs-mac build of Emacs appears to have built-in support for ligatures,
;; using the same composition-function-table method
;; https://bitbucket.org/mituharu/emacs-mac/src/26c8fd9920db9d34ae8f78bceaec714230824dac/lisp/term/mac-win.el?at=master#lines-345:805
;; so use that instead if this module is enabled.
((and IS-MAC (fboundp 'mac-auto-operator-composition-mode))
(add-hook 'doom-init-ui-hook #'mac-auto-operator-composition-mode 'append))
;; Harfbuzz and Mac builds do not need font-specific ligature support
;; if they are above emacs-27.
((and EMACS28+
(or (featurep 'ns)
(string-match-p "HARFBUZZ" system-configuration-features))
(featurep 'composite)) ; Emacs loads `composite' at startup
(defvar +ligature--composition-table (make-char-table nil))
(add-hook! 'doom-init-ui-hook :append
(defun +ligature-init-composition-table-h ()
(dolist (char-regexp +ligatures-composition-alist)
(set-char-table-range
+ligature--composition-table
(car char-regexp) `([,(cdr char-regexp) 0 font-shape-gstring])))
(set-char-table-parent +ligature--composition-table composition-function-table)
(add-hook 'after-change-major-mode-hook #'+ligatures-init-buffer-composition-table-h))))
;; Fallback ligature support for certain, patched fonts. Install them with
;; `+ligatures/install-patched-font'
((defmacro +ligatures--def-font (id font-plist &rest alist)
(declare (indent 2))
(let ((alist-var (intern (format "+ligatures-%s-font-alist" id)))
(setup-fn (intern (format "+ligatures-init-%s-font-h" id))))
`(progn
(setf (alist-get ',id +ligatures--font-alist) (list ,@font-plist))
(defvar ,alist-var ',alist ,(format "Name of the %s ligature font." id))
(defun ,setup-fn (&rest _)
(cl-destructuring-bind (name &key _url files range)
(or (alist-get ',id +ligatures--font-alist)
(error "No ligature font called %s" ',id))
(when range
(set-fontset-font t range name nil 'prepend))
(setq-default prettify-symbols-alist
(append (default-value 'prettify-symbols-alist)
(mapcar #'+ligatures--correct-symbol-bounds ,alist-var)))))
(add-hook '+ligatures--init-font-hook #',setup-fn))))
(defvar +ligatures--font-alist ())
(cond ((featurep! +fira) (load! "+fira"))
((featurep! +iosevka) (load! "+iosevka"))
((featurep! +hasklig) (load! "+hasklig"))
((featurep! +pragmata-pro) (load! "+pragmata-pro")))))