2020-08-12 18:52:14 -04:00
|
|
|
|
;;; ui/ligatures/config.el -*- lexical-binding: t; -*-
|
2018-07-05 19:37:06 -07:00
|
|
|
|
|
2020-08-20 02:40:57 -04:00
|
|
|
|
(defvar +ligatures-extra-symbols
|
2019-10-28 21:44:42 -04:00
|
|
|
|
'(;; org
|
|
|
|
|
:name "»"
|
|
|
|
|
:src_block "»"
|
|
|
|
|
:src_block_end "«"
|
2020-04-03 12:01:34 +02:00
|
|
|
|
:quote "“"
|
|
|
|
|
:quote_end "”"
|
2019-10-28 21:44:42 -04:00
|
|
|
|
;; Functional
|
|
|
|
|
:lambda "λ"
|
|
|
|
|
:def "ƒ"
|
|
|
|
|
:composition "∘"
|
|
|
|
|
:map "↦"
|
|
|
|
|
;; Types
|
|
|
|
|
:null "∅"
|
|
|
|
|
:true "𝕋"
|
|
|
|
|
:false "𝔽"
|
|
|
|
|
:int "ℤ"
|
|
|
|
|
:float "ℝ"
|
|
|
|
|
:str "𝕊"
|
|
|
|
|
:bool "𝔹"
|
2020-06-07 14:21:45 -04:00
|
|
|
|
:list "𝕃"
|
2019-10-28 21:44:42 -04:00
|
|
|
|
;; Flow
|
|
|
|
|
:not "¬"
|
|
|
|
|
:in "∈"
|
|
|
|
|
:not-in "∉"
|
|
|
|
|
:and "∧"
|
|
|
|
|
:or "∨"
|
|
|
|
|
:for "∀"
|
|
|
|
|
:some "∃"
|
|
|
|
|
:return "⟼"
|
|
|
|
|
:yield "⟻"
|
|
|
|
|
;; Other
|
2020-06-07 14:21:45 -04:00
|
|
|
|
:union "⋃"
|
|
|
|
|
:intersect "∩"
|
|
|
|
|
:diff "∖"
|
2019-10-28 21:44:42 -04:00
|
|
|
|
:tuple "⨂"
|
|
|
|
|
:pipe "" ;; FIXME: find a non-private char
|
|
|
|
|
:dot "•")
|
2020-08-20 02:40:57 -04:00
|
|
|
|
"Maps identifiers to symbols, recognized by `set-ligatures'.
|
2019-10-28 21:44:42 -04:00
|
|
|
|
|
|
|
|
|
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.")
|
|
|
|
|
|
2020-08-20 02:40:57 -04:00
|
|
|
|
(defvar +ligatures-extra-alist '((t))
|
|
|
|
|
"A map of major modes to symbol lists (for `prettify-symbols-alist').")
|
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(defvar +ligatures-composition-alist
|
2020-05-06 13:53:54 -04:00
|
|
|
|
'((?! . "\\(?:!\\(?:==\\|[!=]\\)\\)") ; (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 '("<!--" "<$" "<$>" "<*" "<*>" "<**>" "<+" "<+>" "<-" "<--" "<---" "<->" "<-->" "<--->" "</" "</>" "<<" "<<-" "<<<" "<<=" "<=" "<=<" "<==" "<=>" "<===>" "<>" "<|" "<|>" "<~" "<~~" "<." "<.>" "<..>"))
|
|
|
|
|
(?< . "\\(?:<\\(?:!--\\|\\$>\\|\\*\\(?:\\*?>\\)\\|\\+>\\|-\\(?:-\\(?:->\\|[>-]\\)\\|[>-]\\)\\|\\.\\(?:\\.?>\\)\\|/>\\|<[<=-]\\|=\\(?:==>\\|[<=>]\\)\\||>\\|~~\\|[$*+./<=>|~-]\\)\\)")
|
2022-02-19 11:14:25 +01:00
|
|
|
|
(?= . "\\(?:=\\(?:/=\\|:=\\|<[<=]\\|=[=>]\\|>[=>]\\|[=>]\\)\\)") ; (regexp-opt '("=/=" "=:=" "=<<" "==" "===" "==>" "=>" "=>>" "=>=" "=<="))
|
2020-05-06 13:53:54 -04:00
|
|
|
|
(?> . "\\(?:>\\(?:->\\|=>\\|>[=>-]\\|[:=>-]\\)\\)") ; (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 '("~-" "~=" "~>" "~@" "~~" "~~>"))
|
2020-08-12 18:52:14 -04:00
|
|
|
|
"An alist of all ligatures used by `+ligatures-extras-in-modes'.
|
2020-04-30 19:23:49 -04:00
|
|
|
|
|
|
|
|
|
The car is the character ASCII number, cdr is a regex which will call
|
|
|
|
|
`font-shape-gstring' when matched.
|
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
Because of the underlying code in :ui ligatures module, the regex should match a
|
|
|
|
|
string starting with the character contained in car.
|
2020-03-31 00:59:14 -04:00
|
|
|
|
|
2020-04-30 19:23:49 -04:00
|
|
|
|
This variable is used only if you built Emacs with Harfbuzz on a version >= 28")
|
2020-03-31 00:59:14 -04:00
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(defvar +ligatures-in-modes
|
2021-09-11 14:18:57 +02:00
|
|
|
|
'(not special-mode comint-mode eshell-mode term-mode vterm-mode Info-mode
|
|
|
|
|
elfeed-search-mode elfeed-show-mode)
|
2020-08-12 18:52:14 -04:00
|
|
|
|
"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.
|
2020-04-30 19:23:49 -04:00
|
|
|
|
|
2020-08-20 02:40:57 -04:00
|
|
|
|
Extra ligatures are mode-specific substituions, defined in
|
|
|
|
|
`+ligatures-extra-symbols' and assigned with `set-ligatures!'. This variable
|
|
|
|
|
controls where these are enabled.
|
2020-03-31 00:59:14 -04:00
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
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).")
|
2020-03-31 00:59:14 -04:00
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(defvar +ligatures--init-font-hook nil)
|
2020-03-31 00:59:14 -04:00
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(defun +ligatures--correct-symbol-bounds (ligature-alist)
|
2019-10-28 21:44:42 -04:00
|
|
|
|
"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)))
|
2018-07-05 19:37:06 -07:00
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(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
|
2020-08-20 02:40:57 -04:00
|
|
|
|
`+ligatures-extra-symbols', assigned with `set-ligatures!', and made possible
|
2020-08-12 18:52:14 -04:00
|
|
|
|
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
|
2021-03-06 10:04:54 -05:00
|
|
|
|
(let ((in-mode-p
|
|
|
|
|
(+ligatures--enable-p +ligatures-in-modes))
|
|
|
|
|
(in-mode-extras-p
|
|
|
|
|
(and (featurep! +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)
|
|
|
|
|
(run-hooks '+ligatures--init-font-hook)
|
|
|
|
|
(setq +ligatures--init-font-hook nil)))
|
|
|
|
|
(when in-mode-extras-p
|
|
|
|
|
(prependq! prettify-symbols-alist
|
|
|
|
|
(alist-get major-mode +ligatures-extra-alist)))
|
|
|
|
|
(when (and (or in-mode-p in-mode-extras-p)
|
|
|
|
|
prettify-symbols-alist)
|
|
|
|
|
(when prettify-symbols-mode
|
|
|
|
|
(prettify-symbols-mode -1))
|
|
|
|
|
(prettify-symbols-mode +1)))))
|
2018-07-06 20:18:04 +02:00
|
|
|
|
|
2020-01-09 10:24:41 +01:00
|
|
|
|
|
2020-04-30 19:23:49 -04:00
|
|
|
|
;;
|
|
|
|
|
;;; 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)
|
|
|
|
|
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(add-hook! 'doom-init-ui-hook :append
|
|
|
|
|
(defun +ligatures-init-h ()
|
|
|
|
|
(add-hook 'after-change-major-mode-hook #'+ligatures-init-buffer-h)))
|
|
|
|
|
|
2020-04-30 19:23:49 -04:00
|
|
|
|
(cond
|
2020-08-12 18:52:14 -04:00
|
|
|
|
;; The emacs-mac build of Emacs appears to have built-in support for ligatures,
|
2020-04-30 19:23:49 -04:00
|
|
|
|
;; 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))
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(add-hook 'doom-init-ui-hook #'mac-auto-operator-composition-mode 'append))
|
2020-04-30 19:23:49 -04:00
|
|
|
|
|
2020-08-09 14:09:05 +02:00
|
|
|
|
;; Harfbuzz and Mac builds do not need font-specific ligature support
|
2020-08-12 18:52:14 -04:00
|
|
|
|
;; if they are above emacs-27.
|
2020-04-30 19:23:49 -04:00
|
|
|
|
((and EMACS28+
|
2020-08-09 14:09:05 +02:00
|
|
|
|
(or (featurep 'ns)
|
|
|
|
|
(string-match-p "HARFBUZZ" system-configuration-features))
|
2020-08-12 18:52:14 -04:00
|
|
|
|
(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
|
2021-06-06 17:36:23 -04:00
|
|
|
|
(car char-regexp) `([,(cdr char-regexp) 0 font-shape-gstring])))
|
2020-08-20 03:31:40 -04:00
|
|
|
|
(set-char-table-parent +ligature--composition-table composition-function-table))))
|
2020-08-12 18:52:14 -04:00
|
|
|
|
|
|
|
|
|
;; 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")))))
|