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: