about summary refs log tree commit diff
path: root/emacs/.emacs.d/wpc/fonts.el
blob: ad77b512d78e1a8950a42a3c6b92f716e8caf4f3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
;;; fonts.el --- Font preferences -*- lexical-binding: t -*-

;; Author: William Carroll <wpcarro@gmail.com>
;; Version: 0.0.1
;; URL: https://git.wpcarro.dev/wpcarro/briefcase
;; Package-Requires: ((emacs "24.3"))

;;; Commentary:
;; Control my font preferences with ELisp.

;;; Code:

;; TODO: `defcustom' font-size.
;; TODO: `defcustom' fonts.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Dependencies
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(require 'prelude)
(require 'cycle)
(require 'device)
(require 'maybe)
(require 'cl-lib)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Constants
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: Troubleshoot why "8" appears so large on my desktop.

;; TODO: Consider having a different font size when I'm using my 4K monitor.

(defconst fonts-size
  (pcase (device-classify)
    ('work-laptop "10")
    ('work-desktop "10"))
  "My preferred default font-size, which is device specific.")

(defconst fonts-size-step 10
  "The amount (%) by which to increase or decrease a font.")

(defconst fonts-hacker-news-recommendations
  '("APL385 Unicode"
    "Go Mono"
    "Sudo"
    "Monoid"
    "Input Mono Medium" ;; NOTE: Also "Input Mono Thin" is nice.
    )
  "List of fonts optimized for programming I found in a HN article.")

(defconst fonts-whitelist
  (cycle-from-list
   (list-concat
    fonts-hacker-news-recommendations
    '("JetBrainsMono"
      "Mononoki Medium"
      "Monospace"
      "Operator Mono Light"
      "Courier"
      "Andale Mono"
      "Source Code Pro"
      "Terminus")))
  "This is a list of my preferred fonts.")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; TODO: fonts and fonts-whitelist make it difficult to name functions like
;; fonts-set as a generic Emacs function vs choosing a font from the whitelist.

(cl-defun fonts-cycle (&key forward?)
  "Cycle forwards when `FORWARD?' non-nil."
  (let ((font (if forward?
                  (cycle-next fonts-whitelist)
                (cycle-prev fonts-whitelist))))
    (message (s-concat "Active font: " font))
    (fonts-set font)))

(defun fonts-next ()
  "Quickly cycle through preferred fonts."
  (interactive)
  (fonts-cycle :forward? t))

(defun fonts-prev ()
  "Quickly cycle through preferred fonts."
  (interactive)
  (fonts-cycle :forward? nil))

(defun fonts-set (font &optional size)
  "Change the font to `FONT' with option integer, SIZE, in pixels."
  (if (maybe-some? size)
      (set-frame-font (string-format "%s %s" font size) nil t)
    (set-frame-font font nil t)))

(defun fonts-whitelist-set (font)
  "Focuses the FONT in the `fonts-whitelist' cycle.
The size of the font is determined by `fonts-size'."
  (prelude-assert (cycle-contains? font fonts-whitelist))
  (cycle-focus (lambda (x) (equal x font)) fonts-whitelist)
  (fonts-set (fonts-current) fonts-size))

(defun fonts-ivy-select ()
  "Select a font from an ivy prompt."
  (interactive)
  (fonts-whitelist-set
   (ivy-read "Font: " (cycle-to-list fonts-whitelist))))

(defun fonts-print-current ()
  "Message the currently enabled font."
  (interactive)
  (message
   (string-format "[fonts] Current font: \"%s\""
                  (fonts-current))))

(defun fonts-current ()
  "Return the currently enabled font."
  (cycle-current fonts-whitelist))

(defun fonts-increase-size ()
  "Increase font size."
  (interactive)
  (->> (face-attribute 'default :height)
       (+ fonts-size-step)
       (set-face-attribute 'default (selected-frame) :height)))

(defun fonts-decrease-size ()
  "Decrease font size."
  (interactive)
  (->> (face-attribute 'default :height)
       (+ (- fonts-size-step))
       (set-face-attribute 'default (selected-frame) :height)))

(defun fonts-reset-size ()
  "Restore font size to its default value."
  (interactive)
  (fonts-whitelist-set (fonts-current)))

(defun fonts-enable-ligatures ()
  "Call this function to enable ligatures."
  (interactive)
  (let ((alist '((33 . ".\\(?:\\(?:==\\|!!\\)\\|[!=]\\)")
                 (35 . ".\\(?:###\\|##\\|_(\\|[#(?[_{]\\)") ;;
                 (36 . ".\\(?:>\\)")
                 (37 . ".\\(?:\\(?:%%\\)\\|%\\)")
                 (38 . ".\\(?:\\(?:&&\\)\\|&\\)")
                 (42 . ".\\(?:\\(?:\\*\\*/\\)\\|\\(?:\\*[*/]\\)\\|[*/>]\\)") ;;
                 (43 . ".\\(?:\\(?:\\+\\+\\)\\|[+>]\\)")
                 (45 . ".\\(?:\\(?:-[>-]\\|<<\\|>>\\)\\|[<>}~-]\\)")
                 (46 . ".\\(?:\\(?:\\.[.<]\\)\\|[.=-]\\)") ;;
                 (47 . ".\\(?:\\(?:\\*\\*\\|//\\|==\\)\\|[*/=>]\\)")
                 (48 . ".\\(?:x[a-zA-Z]\\)")
                 (58 . ".\\(?:::\\|[:=]\\)")
                 (59 . ".\\(?:;;\\|;\\)")
                 (60 . ".\\(?:\\(?:!--\\)\\|\\(?:~~\\|->\\|\\$>\\|\\*>\\|\\+>\\|--\\|<[<=-]\\|=[<=>]\\||>\\)\\|[*$+~/<=>|-]\\)")
                 (61 . ".\\(?:\\(?:/=\\|:=\\|<<\\|=[=>]\\|>>\\)\\|[<=>~]\\)")
                 (62 . ".\\(?:\\(?:=>\\|>[=>-]\\)\\|[=>-]\\)")
                 (63 . ".\\(?:\\(\\?\\?\\)\\|[:=?]\\)")
                 (91 . ".\\(?:]\\)")
                 (92 . ".\\(?:\\(?:\\\\\\\\\\)\\|\\\\\\)")
                 (94 . ".\\(?:=\\)")
                 (119 . ".\\(?:ww\\)")
                 (123 . ".\\(?:-\\)")
                 (124 . ".\\(?:\\(?:|[=|]\\)\\|[=>|]\\)")
                 (126 . ".\\(?:~>\\|~~\\|[>=@~-]\\)"))))
    (dolist (char-regexp alist)
      (set-char-table-range composition-function-table (car char-regexp)
                            `([,(cdr char-regexp) 0 font-shape-gstring])))))

(provide 'fonts)
;;; fonts.el ends here