diff --git a/modules/ui/ligatures/+fira.el b/modules/ui/ligatures/+fira.el deleted file mode 100644 index 191dabe1e..000000000 --- a/modules/ui/ligatures/+fira.el +++ /dev/null @@ -1,123 +0,0 @@ -;;; 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) - ("" . #Xe101) - ("<--->" . #Xe102) - ("<---->" . #Xe103) - ("<----->" . #Xe104) - ;; Double-ended equals arrows - ("<=>" . #Xe105) - ("<==>" . #Xe106) - ("<===>" . #Xe107) - ("<====>" . #Xe108) - ("<=====>" . #Xe109) - ;; Double-ended asterisk operators - ("<**>" . #Xe10a) - ("<***>" . #Xe10b) - ("<****>" . #Xe10c) - ("<*****>" . #Xe10d) - ;; HTML comments - ("" . #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)) diff --git a/modules/ui/ligatures/+pragmata-pro.el b/modules/ui/ligatures/+pragmata-pro.el deleted file mode 100644 index eff991ac9..000000000 --- a/modules/ui/ligatures/+pragmata-pro.el +++ /dev/null @@ -1,259 +0,0 @@ -;;; ui/ligatures/+pragmata-pro.el -*- lexical-binding: t; -*- - -(+ligatures--def-font pragmata-pro - ("PragmataPro") - ;; Double-ended hyphen arrows - ("[INFO]" . #Xe2b0) - ("[WARN]" . #Xe2b1) - ("[PASS]" . #Xe2b2) - ("[VERBOSE]" . #Xe2b3) - ("[KO]" . #Xe2b4) - ("[OK]" . #Xe2b5) - ("[PASS]" . #Xe2b6) - ("[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) - ("[FAIL]" . #Xe2ce) - ("// 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) - ("// FAIL" . #Xe2ee) - ("# 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) - ("# FAIL" . #Xe2fe) - ("!=" . #Xe900) - ("!==" . #Xe901) - ("!≡" . #Xe902) - ("!≡≡" . #Xe903) - ("!=<" . #Xe904) - ("#(" . #Xe90c) - ("#_" . #Xe90d) - ("#{" . #Xe90e) - ("#?" . #Xe90f) - ("##" . #Xe910) - ("#_(" . #Xe911) - ("#[" . #Xe912) - ("%=" . #Xe920) - ("&%" . #Xe92c) - ("&&" . #Xe92d) - ("&+" . #Xe92e) - ("&-" . #Xe92f) - ("&/" . #Xe930) - ("&=" . #Xe931) - ("&&&" . #Xe932) - ("$>" . #Xe93a) - ("(|" . #Xe940) - ("*>" . #Xe946) - ("++" . #Xe94c) - ("+++" . #Xe94d) - ("+=" . #Xe94e) - ("+>" . #Xe94f) - ("++=" . #Xe950) - ("--" . #Xe960) - ("-<" . #Xe961) - ("-<<" . #Xe962) - ("-=" . #Xe963) - ("->" . #Xe964) - ("->>" . #Xe965) - ("---" . #Xe966) - ("-->" . #Xe967) - ("-+-" . #Xe968) - ("-\\/" . #Xe969) - ("-|>" . #Xe96a) - ("-<|" . #Xe96b) - ("->-" . #Xe96c) - ("-<-" . #Xe96d) - ("-|" . #Xe96e) - ("-||" . #Xe96f) - ("-|:" . #Xe970) - (".=" . #Xe979) - ("//=" . #Xe994) - ("/=" . #Xe995) - ("/==" . #Xe996) - ("/-\\" . #Xe997) - ("/-:" . #Xe998) - ("/->" . #Xe999) - ("/=>" . #Xe99a) - ("/-<" . #Xe99b) - ("/=<" . #Xe99c) - ("/=:" . #Xe99d) - (":=" . #Xe9ac) - (":≡" . #Xe9ad) - (":=>" . #Xe9ae) - (":-\\" . #Xe9af) - (":=\\" . #Xe9b0) - (":-/" . #Xe9b1) - (":=/" . #Xe9b2) - (":-|" . #Xe9b3) - (":=|" . #Xe9b4) - (":|-" . #Xe9b5) - (":|=" . #Xe9b6) - ("<$>" . #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) - ("" . #Xe9eb) - ("<<==" . #Xe9ec) - ("<==" . #Xe9ed) - ("<-\\" . #Xe9ee) - ("<-/" . #Xe9ef) - ("<=\\" . #Xe9f0) - ("<=/" . #Xe9f1) - ("=<<" . #Xea00) - ("==" . #Xea01) - ("===" . #Xea02) - ("==>" . #Xea03) - ("=>" . #Xea04) - ("=~" . #Xea05) - ("=>>" . #Xea06) - ("=~=" . #Xea07) - ("==>>" . #Xea08) - ("=>=" . #Xea09) - ("=<=" . #Xea0a) - ("=<" . #Xea0b) - ("==<" . #Xea0c) - ("=<|" . #Xea0d) - ("=/" . #Xea0e) - ("=/=" . #Xea0f) - ("=/<" . #Xea10) - ("=|" . #Xea11) - ("=||" . #Xea12) - ("=|:" . #Xea13) - (">-" . #Xea20) - (">=" . #Xea21) - (">>-" . #Xea22) - (">>=" . #Xea23) - (">=>" . #Xea24) - (">>^" . #Xea25) - (">>|" . #Xea26) - (">!=" . #Xea27) - (">->" . #Xea28) - (">==" . #Xea29) - (">=" . #Xea2a) - (">/=" . #Xea2b) - (">-|" . #Xea2c) - (">=|" . #Xea2d) - (">-\\" . #Xea2e) - (">=\\" . #Xea2f) - (">-/" . #Xea30) - (">=/" . #Xea31) - (">λ=" . #Xea32) - ("?." . #Xea3f) - ("^=" . #Xea43) - ("^^" . #Xea44) - ("^<<" . #Xea48) - ("^>>" . #Xea49) - ("\\=" . #Xea54) - ("\\==" . #Xea55) - ("\\/-" . #Xea56) - ("\\-/" . #Xea57) - ("\\-:" . #Xea58) - ("\\->" . #Xea59) - ("\\=>" . #Xea5a) - ("\\-<" . #Xea5b) - ("\\=<" . #Xea5c) - ("\\=:" . #Xea5d) - ("|=" . #Xea69) - ("|>=" . #Xea6a) - ("|>" . #Xea6b) - ("|+|" . #Xea6c) - ("|->" . #Xea6d) - ("|-->" . #Xea6e) - ("|=>" . #Xea6f) - ("|==>" . #Xea70) - ("|>-" . #Xea71) - ("|<<" . #Xea72) - ("||>" . #Xea73) - ("|>>" . #Xea74) - ("|-" . #Xea75) - ("||-" . #Xea76) - ("||=" . #Xea77) - ("|)" . #Xea78) - ("|]" . #Xea79) - ("|-:" . #Xea7a) - ("|=:" . #Xea7b) - ("|-<" . #Xea7c) - ("|=<" . #Xea7d) - ("|--<" . #Xea7e) - ("|==<" . #Xea7f) - ("~=" . #Xea8a) - ("~>" . #Xea8b) - ("~~>" . #Xea8c) - ("~>>" . #Xea8d) - ("[[" . #Xea8f) - ("[|" . #Xea90) - ("_|_" . #Xea97) - ("]]" . #Xeaa0)) diff --git a/modules/ui/ligatures/README.org b/modules/ui/ligatures/README.org index 4ea059781..29a298b53 100644 --- a/modules/ui/ligatures/README.org +++ b/modules/ui/ligatures/README.org @@ -4,39 +4,40 @@ #+since: 21.12.0 * Description :unfold: -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. +* Table of Contents :TOC_3:noexport: +- [[#description][Description]] + - [[#maintainers][Maintainers]] + - [[#module-flags][Module flags]] + - [[#packages][Packages]] + - [[#hacks][Hacks]] + - [[#changelog][Changelog]] +- [[#installation][Installation]] +- [[#usage][Usage]] + - [[#mathematical-symbols-replacement][Mathematical symbols replacement]] + - [[#coding-ligatures][Coding ligatures]] + - [[#details][Details]] +- [[#configuration][Configuration]] + - [[#symbol-replacements-λ-for-lambda][Symbol replacements (λ for "lambda"...)]] + - [[#font-ligatures-turning--into-an-arrow][Font ligatures (turning "=>" into an arrow...)]] + - [[#setting-ligatures-for-specific-font-or-major-mode][Setting ligatures for specific font or major mode]] + - [[#overwriting-all-default-ligatures][Overwriting all default ligatures]] +- [[#troubleshooting][Troubleshooting]] + - [[#some-symbols-are-not-rendering-correctly][Some symbols are not rendering correctly]] +- [[#frequently-asked-questions][Frequently asked questions]] +- [[#appendix][Appendix]] ** Maintainers -/This module has no dedicated maintainers./ [[doom-contrib-maintainer:][Become a maintainer?]] +- [[doom-user:][@gagbo]] + +[[doom-contrib-maintainer:][Become a maintainer?]] ** Module flags - +extra :: Enables extra symbol substitutions in certain modes, for example ~lambda~ in lisps are replaced with ~λ~. -- +fira :: - Enable =Fira Code= ligatures. This requires Fira Code Symbol and [[id:a7e7402b-e202-4860-878b-d1933cff1d16][a patched - version of Fira Code]]. -- +hasklig :: - Enable =Hasklig= ligatures. This requires [[id:a7e7402b-e202-4860-878b-d1933cff1d16][a patched version of the HaskLig - font]]. -- +iosevka :: - Enable =Iosevka= ligatures. This requires [[id:a7e7402b-e202-4860-878b-d1933cff1d16][a patched version of the Iosevka - font]]. -- +pragmata-pro :: - Enable =Pragmata Pro= ligatures. This requires the [[https://www.fsd.it/shop/fonts/pragmatapro/][Pragmata Pro font]]. - -#+begin_quote - 🚧 Font 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 ** Packages -/This module doesn't install any packages./ +- [[https://github.com/mickeynp/ligature.el][ligature.el]] (on Emacs 28+ with Harfbuzz) ** Hacks /No hacks documented for this module./ @@ -55,63 +56,20 @@ This module requires one of three setups for ligatures to work: - 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. + /This module does not have specific installation instructions/ -** Not Emacs-mac and Emacs <= 27 -:PROPERTIES: -:ID: a7e7402b-e202-4860-878b-d1933cff1d16 -:END: -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. + ~doom doctor~ will tell you if the module is incompatible with your current + Emacs version, and what you can do to remediate. -* TODO Usage +* Usage #+begin_quote 🔨 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]] #+end_quote -** 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 [[doom-module:+fira]], [[doom-module:+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 -#+begin_quote - 🔨 /This module's configuration documentation is incomplete./ [[doom-contrib-module:][Complete it?]] -#+end_quote - -** Setting ligatures -If you want to set ligatures for modules that don't have them by default you can -use the ~set-ligatures!~ macro: -#+begin_src emacs-lisp -;; in $DOOMDIR/config.el +** Mathematical symbols replacement +If you want to set symbol replacements for modules that don't have them by +default you can use the ~set-ligatures!~ function in your config.el file +#+BEGIN_SRC emacs-lisp (after! PACKAGE (set-ligatures! 'MAJOR-MODE :symbol "keyword")) @@ -128,7 +86,7 @@ E.g. :int "int" :str "string" :float "float" :bool "bool" :for "for" - :return "return" :yeild "yeild")) + :return "return" :yield "yield")) #+end_src You can set these symbols out of the box: @@ -146,7 +104,7 @@ You can set these symbols out of the box: :int "int keyword" :float "float keyword" :str "string keyword" - :bool "boolean keywork" + :bool "boolean keyword" :list "list keyword" ;; Flow :not "not operator" @@ -163,7 +121,7 @@ You can set these symbols out of the box: :intersect "Intersect keyword" :diff "diff keyword" :tuple "Tuple Keyword " - :pipe "Pipe Keyword" ;; FIXME: find a non-private char + :pipe "Pipe Keyword" :dot "Dot operator") #+end_src @@ -174,7 +132,38 @@ If you have multiple versions of the same keyword you can set the symbol twice: :null "None") #+end_src -** Changing ligatures + +** Coding ligatures +This module includes configuration to compose combinations like =->= or =::= +into prettier glyphs (called a ligature), specific for your font, or specific +for the major modes that you want to use. + +As these ligatures come from the font itself instead of elisp symbols, we use +=set-font-ligatures!= + +#+begin_src elisp +(set-font-ligatures! '(haskell-mode clojure-mode) ">>=" ">>-") +#+end_src + +*** Details +Ligatures are implemented using a **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 same method natively 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 uses the [[https://github.com/mickeynp/ligature.el][ligature.el]] package that +implements this method for Emacs 28+ built with Harfbuzz support. Therefore, the +module will not work with Emacs 27 or previous. + +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 the /composition-function-table/ method in +Emacs 27. + +* Configuration +** Symbol replacements (λ for "lambda"...) if you don't like the symbols chosen you can change them by using: #+begin_src emacs-lisp ;; you don't need to include all of them you can pick and mix @@ -214,10 +203,44 @@ if you don't like the symbols chosen you can change them by using: :intersect "∩" :diff "∖" :tuple "⨂" - :pipe "" ;; FIXME: find a non-private char + :pipe "" :dot "•") ;; you could also add your own if you want #+end_src +** Font ligatures (turning "=>" into an arrow...) +*** Setting ligatures for specific font or major mode +As the [[https://github.com/mickeynp/ligature.el][README]] for ligature.el states, you can manipulate the ligatures that you +want to enable, specific for your font, or specific for the major modes that you +want to use. =set-font-ligatures!= is a thin wrapper around =ligature.el= to control these. + +#+begin_src elisp +(set-font-ligatures! '(haskell-mode clojure-mode) ">>=" ">>-") +#+end_src + +This call will: +- overwrite all preceding calls to =set-font-ligatures!= + for =haskell-mode= and =clojure-mode= specifically, but +- keep the inheritance to ligatures set for all modes, or parent modes like =prog-mode= + +*** Overwriting all default ligatures +If you want to "start from scratch" and get control over all ligatures that +happen in all modes, you can use + +#+begin_src elisp +;; Set all your custom ligatures for all prog-modes here +;; This section is *out of* the after! block +;; Example: only get ligatures for "==" and "===" in programming modes +;; by default, and get only "www" in all buffers by default. +(setq +ligatures-prog-mode-list '("==" "===") + +ligatures-all-modes-list '("www")) +;; Set any of those variables to nil to wipe all defaults. + + ;; Set all your additional custom ligatures for other major modes here. + ;; Example: enable traditional ligature support in eww-mode, if the + ;; `variable-pitch' face supports it +(set-font-ligatures! 'eww-mode "ff" "fi" "ffi") +#+end_src + * Troubleshooting [[doom-report:][Report an issue?]] diff --git a/modules/ui/ligatures/autoload/install.el b/modules/ui/ligatures/autoload/install.el deleted file mode 100644 index fd7d096d2..000000000 --- a/modules/ui/ligatures/autoload/install.el +++ /dev/null @@ -1,58 +0,0 @@ -;;; ui/ligatures/autoload/install.el -*- lexical-binding: t; -*- -;;;###if (or (modulep! +fira) (modulep! +hasklig) (modulep! +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... ") - (shell-command-to-string "fc-cache -f -v")) - (if IS-WINDOWS - (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 &key _range url files) - (or (alist-get font-id +ligatures--font-alist) - (user-error "%S is not a valid font" font-id)) - (+ligatures--install-font arg font-name url files))) diff --git a/modules/ui/ligatures/autoload/ligatures.el b/modules/ui/ligatures/autoload/ligatures.el index 3711124c4..97cf5685a 100644 --- a/modules/ui/ligatures/autoload/ligatures.el +++ b/modules/ui/ligatures/autoload/ligatures.el @@ -11,40 +11,66 @@ MODES is a major mode symbol or a list of them. PLIST is a property list whose keys must match keys in `+ligatures-extra-symbols', 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. +to be replaced with that symbol. -This function accepts one special property: - - :alist ALIST - Appends ALIST to `prettify-symbols-alist' literally, without mapping text to - `+ligatures-extra-symbols'. +If the car of PLIST is nil, then unset any +pretty symbols and ligatures previously defined for MODES. For example, the rule for emacs-lisp-mode is very simple: - (set-ligatures! 'emacs-lisp-mode + (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-extra-symbols'. +associated with :lambda in `+ligatures-extra-symbols'. Pretty symbols can be unset for emacs-lisp-mode with: - (set-ligatures! 'emacs-lisp-mode nil)" + (set-ligatures! \\='emacs-lisp-mode nil) + +Note that this will keep all ligatures in `+ligatures-prog-mode-list' active, as +`emacs-lisp-mode' is derived from `prog-mode'." (declare (indent defun)) (if (null (car-safe plist)) (dolist (mode (ensure-list modes)) (delq! mode +ligatures-extra-alist 'assq)) - (let (results) + (let ((results)) (while plist (let ((key (pop plist))) - (if (eq key :alist) - (prependq! results (pop plist)) (when-let (char (plist-get +ligatures-extra-symbols key)) - (push (cons (pop plist) char) results))))) + (push (cons (pop plist) char) results)))) (dolist (mode (ensure-list 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)))))) + +;;;###autodef +(defun set-font-ligatures! (modes &rest ligatures) + "Associates string patterns with ligatures in certain major-modes. + + MODES is a major mode symbol or a list of them. + LIGATURES is a list of ligatures that should be handled by the font, + like \"==\" or \"-->\". LIGATURES is a list of strings. + +For example, the rule for emacs-lisp-mode is very simple: + + (set-font-ligatures! \\='emacs-lisp-mode \"->\") + +This will ligate \"->\" into the arrow of choice according to your font. + +Font ligatures can be unset for emacs-lisp-mode with: + + (set-font-ligatures! \\='emacs-lisp-mode nil) + +Note that this will keep all ligatures in `+ligatures-prog-mode-list' active, as +`emacs-lisp-mode' is derived from `prog-mode'." + (declare (indent defun)) + (if (null ligatures) + (dolist (mode (ensure-list modes)) + (add-to-list 'ligature-ignored-major-modes mode)) + (after! ligature + (dolist (mode (ensure-list modes)) + (setq ligature-ignored-major-modes (delq mode ligature-ignored-major-modes))) + (ligature-set-ligatures (ensure-list modes) font-ligatures)))) diff --git a/modules/ui/ligatures/config.el b/modules/ui/ligatures/config.el index 8a38bc944..e11d19579 100644 --- a/modules/ui/ligatures/config.el +++ b/modules/ui/ligatures/config.el @@ -47,44 +47,25 @@ font.") (defvar +ligatures-extra-alist '((t)) "A map of major modes to symbol lists (for `prettify-symbols-alist').") -(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'. +(defvar +ligatures-prog-mode-list + '("|||>" "<|||" "<==>" "" "---" "-<<" + "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->" + "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "" "###" "#_(" "..<" + "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~=" + "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|" + "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:" + ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:" + "<$" "<=" "<>" "<-" "<<" "<+" "" "++" "?:" + "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)" + "\\\\" "://") + "A list of ligatures to enable in all `prog-mode' buffers.") -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-all-modes-list + '() + "A list of ligatures to enable in all buffers.") (defvar +ligatures-in-modes '(not special-mode comint-mode eshell-mode term-mode vterm-mode Info-mode @@ -144,8 +125,10 @@ and cannot run in." (and (modulep! +extra) (+ligatures--enable-p +ligatures-extras-in-modes)))) (when in-mode-p - (if (boundp '+ligature--composition-table) - (setq-local composition-function-table +ligature--composition-table) + ;; If ligature-mode has been installed, there's no + ;; need to do anything, we activate global-ligature-mode + ;; later and handle all settings from `set-ligatures!' later. + (unless (fboundp #'ligature-mode-turn-on) (run-hooks '+ligatures--init-font-hook) (setq +ligatures--init-font-hook nil))) (when in-mode-extras-p @@ -177,44 +160,21 @@ and cannot run in." ((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. + ;; NOTE: the module does not support Emacs 27 and less, but if we still try to enable ligatures, + ;; it will end up in catastrophic work-loss errors, so we leave the check here for safety. ((and (> emacs-major-version 27) (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)) + (featurep 'composite)) ; Emacs loads `composite' at startup + + (use-package! ligature + :config + ;; Enable all `+ligatures-prog-mode-list' ligatures in programming modes + (ligature-set-ligatures 'prog-mode +ligatures-prog-mode-list) + (ligature-set-ligatures 't +ligatures-all-modes-list)) + (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)))) - - ;; 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 ((modulep! +fira) (load! "+fira")) - ((modulep! +iosevka) (load! "+iosevka")) - ((modulep! +hasklig) (load! "+hasklig")) - ((modulep! +pragmata-pro) (load! "+pragmata-pro"))))) + (defun +ligature-enable-globally-h () + "Enables ligature checks globally in all buffers. +You can also do it per mode with `ligature-mode'." + (global-ligature-mode t))))) diff --git a/modules/ui/ligatures/doctor.el b/modules/ui/ligatures/doctor.el new file mode 100644 index 000000000..9ae683ab4 --- /dev/null +++ b/modules/ui/ligatures/doctor.el @@ -0,0 +1,16 @@ +;; This cond expression mimics the activation conditional of ligatures, +;; with a fallback that triggers a warning. +(cond + ((and IS-MAC (fboundp 'mac-auto-operator-composition-mode)) + (ignore)) + + ((and (> emacs-major-version 27) + (or (featurep 'ns) + (string-match-p "HARFBUZZ" system-configuration-features)) + (featurep 'composite)) ; Emacs loads `composite' at startup + (ignore)) + + (t + (if IS-MAC + (warn! "The (:ui ligatures) module does not support your version of Emacs. Install emacs-plus with at least Emacs 28, or emacs-mac.") + (warn! "The (:ui ligatures) module does not support your version of Emacs. Make sure to have at least Emacs 28 with Harfbuzz configured (should be the default).")))) diff --git a/modules/ui/ligatures/packages.el b/modules/ui/ligatures/packages.el new file mode 100644 index 000000000..813e08649 --- /dev/null +++ b/modules/ui/ligatures/packages.el @@ -0,0 +1,5 @@ +(when (and (or (featurep 'ns) + (string-match-p "HARFBUZZ" system-configuration-features)) + (featurep 'composite)) + (package! ligature + :pin "0e5d0a8554622bcb0ec634e364795650ff4f2457"))