Recently Written · git

alt-hack0

The Hack font family with a non-weird zero, and other variants.

git clone https://github.com/equwal/alt-hack0

Log | Files | Refs


generator.ros (7905 bytes)

1 #!/bin/sh
2 #|-*- mode:lisp -*-|#
3 #|
4 exec ros -Q -- $0 "$@"
5 |#
6 ;;; This file (c) Spenser Truex 2021
7 ;;; MIT license.
8 
9 (progn ;;init forms
10   (ros:ensure-asdf)
11   #+quicklisp(ql:quickload '(:alexandria :uiop)
12                            :silent t))
13 
14 ;;; EXAMPLE USAGE:
15 ;;; cd alt-hack && ./generator.ros curve dot slabi
16 (defpackage :ros.script.generator.3783095582
17   (:use :cl))
18 (in-package :ros.script.generator.3783095582)
19 (defvar *weights* '("Bold" "BoldItalic" "Italic" "Regular"))
20 
21 (defun uncomment (spec)
22   (remove-if #'(lambda (item)
23                  (and (stringp item)
24                       (= 1 (length item))))
25              spec))
26 
27 (defparameter *helpful-groups*
28   '(
29     (curve "u0028-curved" "("
30      "u0029-curved" ")")
31     (round "u0028-rounder" "("
32      "u0029-rounder" ")")
33     (backslash "u0030-backslash" "0")
34     (diamond "u0030-diamond" "0")
35     (dot "u0030-dotted" "0")
36     (forwardslash "u0030-forwardslash" "0")
37     (noslab1 "u0031-noslab" "1")
38     (flattop3 "u0033-flattop" "3")
39     (wider "u003C-wider" "<"
40      "u003E-wider" ">")
41     (knife "u0066-knife" "f")
42     (slabi "u0069-slab" "i"
43      "u00EC-slab" "ì"
44      "u00ED-slab" "í"
45      "u00EE-slab" "î"
46      "u00EF-slab" "ï"
47      "u0129-slab" "ĩ"
48      "u012B-slab" "ī"
49      "u012D-slab" "ĭ"
50      "u012F-slab" "į"
51      "u0131-slab" "ı"
52      "u0456-slab" "і"
53      "u0457-slab" "ї"))
54   "Groups with extra information for user help.")
55 
56 (defun prune (test tree)
57   (labels ((rec (tree acc)
58              (cond
59                ((null tree) (nreverse acc))
60                ((consp (car tree))
61                 (rec (cdr tree)
62                      (cons (rec (car tree) nil) acc)))
63                (t (rec (cdr tree)
64                        (if (funcall test (car tree))
65                            acc
66                            (cons (car tree) acc)))))))
67     (rec tree nil)))
68 
69 (defun pprint-helpful-groups ()
70   (let ((more-helpful (prune #'(lambda (s)
71                                  (and (stringp s)
72                                       (< 1 (length s))))
73                              *helpful-groups*)))
74     (loop for g in more-helpful
75           do (format t "~A:~%" (car g))
76           do (format t "~{~A ~}~%" (cdr g)))))
77 (defparameter *groups*
78   (mapcar #'uncomment *helpful-groups*)
79   "Things you actually want to permute together.")
80 (defparameter *exclusions*
81   '((curve round)
82     (backslash diamond dot forwardslash))
83   "Things which you don't want specified at the same time.")
84 (defparameter *formats*
85   '("ttf" "woff" "woff2")
86   "Valid parameters to call as formats.")
87 
88 (define-symbol-macro help
89     (progn (pprint-lines
90             "generator.ros OPTIONS* {SHOW | SPEC+}")
91            (format t "These are valid OPTIONS: ~{~A ~}~%"
92                    (mapcar #'(lambda (f) (concatenate 'string "--" f))
93                            *formats*))
94            (pprint-lines "SPEC should be a list of:")
95            (pprint-helpful-groups)
96            (pprint-lines
97             "Keep in mind that it makes no sense to include"
98             "the same character spec twice."
99             "SHOW just finds all available glyphs in alt-hack."
100             "TEST runs the test functions for ttf, woff and woff2.")))
101 
102 (defun find-keyword (keyword group)
103   (when (not (null group))
104     (let ((c (car group)))
105       (if (eql keyword (car c))
106           c
107           (find-keyword keyword (cdr group))))))
108 
109 (defun folders (keyword)
110   (cdr (find-keyword keyword *groups*)))
111 
112 (defun pprint-lines (&rest strings)
113   (format t "~{~A~%~}" strings))
114 
115 (defun remove-hints ()
116   (let ((files (uiop:directory-files #P"Hack/postbuild_processing/tt-hinting")))
117     (dolist (f files)
118       (with-open-file (si f :direction :input)
119         (with-open-file (so f :direction :output
120                               :if-exists :supersede)
121           (let ((line (read-line si nil nil)))
122             (when (and line (char/= #\#(elt line 0)))
123               (write-line (format nil "# ~S~%" line) so))))))))
124 
125 (defun put-glyphs! (ufolders)
126   (dolist (arg ufolders)
127     (dolist (weight *weights*)
128       (dolist (f (uiop:directory-files
129                   (concatenate 'string "glyphs/" arg "/"
130                                (string-downcase weight) "/")))
131         (uiop:copy-file f
132                    (concatenate 'string
133                                 "Hack/source/Hack-"
134                                 weight
135                                 ".ufo/glyphs/"
136                                 (pathname-name f)
137                                 "."
138                                 (pathname-type f)))))))
139 (defun make-it (&optional subcommand)
140   ;; Cannot use uiop:launch-program since it is asynchronous.
141   (uiop:run-program (if subcommand
142                       (list "make" subcommand)
143                       "make")
144                   :output *standard-output*
145                   :directory #P"Hack"
146                   :error-output *standard-output*))
147 (defun build (&rest make-commands)
148   (dolist (m make-commands)
149     (make-it m)))
150 
151 (defun verify (spec)
152   "Ensure that the spec is not bogus."
153   (let ((group (not (set-difference spec (mapcar #'car *groups*))))
154         (exclusion (not (some #'identity
155                     (mapcar #'(lambda (ex)
156                                 (<= 2 (length (intersection spec ex))))
157                             *exclusions*)))))
158     (values (and group exclusion)
159             (if group (if exclusion 'group-and-exclusion 'group)
160                 (if exclusion 'exclusion 'unknown)))))
161 
162 (defun show-characters ()
163   (flet ((pprint-letters (letter-alist)
164            (dolist (p letter-alist)
165              (format t "~T~A~T~A~%"
166                      (string (cdr p)) (car p)))))
167     (let ((dirs (uiop:subdirectories "glyphs")))
168       (pprint-letters
169        (loop
170          for d in dirs
171          collecting
172          (let ((mat (car (last (pathname-directory d)))))
173            (cons
174             mat
175             (code-char (read-from-string
176                         (concatenate 'string
177                                      "#x"
178                                 (subseq mat 1 (search "-" mat))))))))))))
179 (defun format-parser (argv)
180   (when argv
181     (let ((c (car argv)))
182       (when (and (< 2 (length c))
183                  (string= "--" (subseq c 0 2)))
184        (cons (subseq c 2) (format-parser (cdr argv)))))))
185 (defun should-help (argv)
186   (or (null argv)
187       (dolist (a argv)
188         (when (or (search "-?" a)
189                   (search "-h" a)
190                   (search "help" a))
191           (return t)))))
192 (defun should-test (argv)
193   (string= (car argv) "test"))
194 
195 (define-symbol-macro test
196     (progn (format t "Helping you:~%")
197            (main "help")
198            (format t "~%DONE. Trying TTF.")
199            (main "--ttf")
200            (format t "~%DONE. Trying WOFF.")
201            (main "--woff")
202            (format t "~%DONE. Trying WOFF2.")
203            (main "--woff2")))
204 
205 (defun main (&rest argv)
206   (declare (ignorable argv))
207   (if (should-help argv)
208       help
209       (if (should-test argv)
210           test
211           (let ((formats (format-parser argv)))
212             (let ((argv (mapcar (lambda (g) (intern (string-upcase g)))
213                                 (nthcdr (length formats) argv)))
214                   (formats (or formats "ttf woff woff2")))
215               (if (and argv (string= "SHOW" (string-upcase (car argv))))
216                   (show-characters)
217                   (multiple-value-bind (bool name)
218                       (verify argv)
219                     (if bool
220                         (progn (remove-hints)
221                                (mapc #'put-glyphs!
222                                      (mapcar #'folders argv))
223                                ;; Can't get woff2 on my system.
224                                (mapc #'build formats))
225                         (progn (format t "Invalid ~S in spec: ~{~A ~}~%"
226                                        name
227                                        argv))))))))))
228 
229 ;;; vim: set ft=lisp lisp: