diff --git a/quad/fontproof/command.rkt b/quad/fontproof/command.rkt index 605c2701..fe5648b2 100755 --- a/quad/fontproof/command.rkt +++ b/quad/fontproof/command.rkt @@ -1,58 +1,78 @@ #lang debug racket -(require "main.rkt") +(require racket/logging + "main.rkt") (module+ raco - ;; pull text out of stdin, if any - ;; todo: make this cooperate with `read` for confirmation of replace - (define text (string-join (for/list ([t (in-port read)]) - (format "~a" t)) " ")) - (define command-name (with-handlers ([exn:fail? (λ (exn) #f)]) - (vector-ref (current-command-line-arguments) 0))) - (dispatch command-name text)) + (with-logging-to-port + (current-error-port) + handle-raco-command + #:logger fontproof-logger + 'info + 'fontproof)) (module+ main (println "this is fontproof command")) -(define (dispatch command-name text) - (when (positive? (vector-length (current-command-line-arguments))) - (define output-file-path #false) - (define page-size #false) - (define font-sizes #false) - (define line-heights #false) - (define doc #false) - (define replace #false) - (define families - (command-line - #:program "fontproof" - #:argv (current-command-line-arguments) - #:once-each - [("-p" "--page") page-size-arg - "page size" - (set! page-size page-size-arg)] - [("-r" "--replace") "replace existing" - (set! replace #true)] - [("-d" "--doc") doc-arg - "sample text" - (set! doc doc-arg)] - [("-o" "--output") output-file-path-arg - "output file path" - (set! output-file-path output-file-path-arg)] - [("-s" "--size") font-sizes-arg - "font sizes" - (set! font-sizes font-sizes-arg)] - [("-l" "--leading") line-heights-arg - "font size" - (set! line-heights line-heights-arg)] - #:args families - families)) - (cond - [(null? families) (displayln "no family given")] - [else (for ([family (in-list families)]) - (make-proof family (if (non-empty-string? text) text doc) - #:page-size page-size - #:font-sizes font-sizes - #:line-heights line-heights - #:output-file-path output-file-path - #:replace replace))]))) +(define (handle-raco-command) + (define command-name (with-handlers ([exn:fail? (λ (exn) #f)]) + (vector-ref (current-command-line-arguments) 0))) + (define output-file-path #false) + (define page-size #false) + (define font-sizes #false) + (define line-heights #false) + (define doc #false) + (define replace #false) + (define output-qml? #false) + (define make-bold? #false) + (define make-italic? #false) + (define families + (command-line + #:program "fontproof" + #:argv (current-command-line-arguments) + #:once-each + [("-p" "--page") page-size-arg + "page size" + (set! page-size page-size-arg)] + [("-r" "--replace") "replace existing" + (set! replace #true)] + [("-d" "--doc") doc-arg + "sample text" + (set! doc doc-arg)] + [("-o" "--output") output-file-path-arg + "output file path" + (set! output-file-path output-file-path-arg)] + [("-s" "--size") font-sizes-arg + "font sizes" + (set! font-sizes font-sizes-arg)] + [("-l" "--leading") line-heights-arg + "font size" + (set! line-heights line-heights-arg)] + [("-b" "--bold") "also generate bold proof" + (set! make-bold? #true)] + [("-i" "--italic") "also generate italic proof" + (set! make-italic? #true)] + [("-q" "--qml") "output QML" + (set! output-qml? #true)] + #:args families + families)) + (match families + [(? null?) (raise-user-error "No font to proof. Exiting.")] + [_ (for ([family (in-list families)]) + (make-proof family + (or doc (match (current-input-port) + ;; pull text out of stdin, if any + ;; use `terminal-port?` to distinguish piped input from tty input + [(not (? terminal-port?)) + (string-join (for/list ([t (in-port read)]) + (format "~a" t)) " ")] + [_ #false])) + #:page-size page-size + #:bold make-bold? + #:italic make-italic? + #:font-sizes font-sizes + #:line-heights line-heights + #:output-file-path output-file-path + #:replace replace + #:qml output-qml?))])) diff --git a/quad/fontproof/main.rkt b/quad/fontproof/main.rkt index 71b04814..eca37f30 100755 --- a/quad/fontproof/main.rkt +++ b/quad/fontproof/main.rkt @@ -1,68 +1,106 @@ #lang debug racket/base (require quadwriter/core racket/date + racket/file racket/string racket/list racket/match - txexpr) -(provide make-proof) + racket/path + txexpr + quad/qexpr) +(provide (all-defined-out)) +(define-logger fontproof) (define (increment-path path) - (for*/first ([path (in-value path)] - [i (in-naturals 2)] - [incremented-path (in-value (path-replace-extension path (string->bytes/utf-8 (format " ~a~a.pdf" (if (< i 10) "0" "") i))))] + (for*/first ([i (in-naturals 2)] + [incremented-path (in-value + (path-replace-extension path + (string->bytes/utf-8 + (format " ~a~a.pdf" (if (< i 10) "0" "") i))))] #:unless (file-exists? incremented-path)) incremented-path)) - -(define (make-proof family-name [doc-arg #f] +(define (boolean->string bool) (if bool "true" "false")) + +(define (make-proof font-or-qml [sample-text #f] + #:bold [make-bold #false] + #:italic [make-italic #false] #:font-sizes [font-sizes-arg #false] #:page-size [page-size-arg #false] #:line-heights [line-heights-arg #false] #:output-file-path [output-file-path-arg #false] + #:qml [output-qml? #true] #:replace [replace #false]) - (define output-file-path - (match (path->complete-path - (or output-file-path-arg - (build-path (find-system-path 'desk-dir) - (format "~a proof.pdf" family-name)))) - [(? file-exists? path) #:when (not replace) - (displayln (format "File \"~a\" exists" path)) - (display "Overwrite? [y]es [n]o [k]eep both: ") - (case (read) - [(y yes) path] - [(k keep) (increment-path path)] - [else #false])] - [path path])) - (when output-file-path - (displayln (format "generating test for ~a" family-name)) - (define page-size (or page-size-arg "letter")) - (define font-sizes (string-split (or font-sizes-arg "12 10.5 9"))) - (define line-heights (string-split (or line-heights-arg "1.25em"))) - (define sample-text (or doc-arg "no doc provided")) - (define doc-interior - (cons 'q - (add-between - (for*/list ([font-size (in-list font-sizes)] - [line-height (in-list line-heights)]) - (attr-set* - (list - 'q sample-text) - 'font-size font-size - 'line-height line-height - 'footer-text (format "~a test ~a/~a · ~a" - family-name - font-size - line-height - (date->string (current-date) #t)))) - page-break))) - (define doc (attr-set* - doc-interior - 'page-size page-size - 'page-margin-left "12p" - 'page-margin-right "12p" - 'font-family family-name - 'hyphenate "false" - 'footer-display "true")) - (render-pdf doc output-file-path))) \ No newline at end of file + (define-values (doc output-file-path) + (match font-or-qml + [(? qml-path? qml-ps) + (define doc (qml->qexpr (file->string qml-ps))) + (define output-file-path (path-replace-extension qml-ps #".pdf")) + (values doc output-file-path)] + [font-name-arg + (unless sample-text + (raise-user-error "Nothing to proof. Exiting.")) + (define-values (initial-font-family initial-font-bold initial-font-italic) + (let ([bi-suffix-pat #px"\\s*((?i:bold))?\\s*((?i:italic))?$"]) + (match-define (list suffix bold? italic?) (regexp-match bi-suffix-pat font-name-arg)) + (values (string-trim font-name-arg suffix #:left? #false) bold? italic?))) + (log-fontproof-info (format "generating proof for ~a" font-name-arg)) + (define page-size (or page-size-arg "letter")) + (define font-sizes (string-split (or font-sizes-arg "12 10.5 9"))) + (define line-heights (string-split (or line-heights-arg "1.25em"))) + (define bold-variants (cond + [initial-font-bold '(#t)] + [make-bold '(#f #t)] + [else '(#f)])) + (define italic-variants (cond + [initial-font-italic '(#t)] + [make-italic '(#f #t)] + [else '(#f)])) + (when (and initial-font-bold make-bold) + (log-fontproof-info (format "starting font is bold; omitting bold proof~a" (match (length italic-variants) [2 "s"] [_ ""])))) + (when (and initial-font-italic make-italic) + (log-fontproof-info (format "starting font is italic; omitting italic proof~a" (format "starting font is bold; omitting bold proof~a" (match (length italic-variants) [2 "s"] [_ ""]))))) + (define doc-interior + (cons 'q + (add-between + (for*/list ([font-size (in-list font-sizes)] + [font-bold (in-list bold-variants)] + [font-italic (in-list italic-variants)] + [line-height (in-list line-heights)]) + (attr-set* + (list + 'q sample-text) + 'font-size font-size + 'font-italic (boolean->string font-italic) + 'font-bold (boolean->string font-bold) + 'line-height line-height + 'footer-text (format "~a test ~a/~a · ~a" + initial-font-family + font-size + line-height + (date->string (current-date) #t)))) + page-break))) + (define doc (attr-set* + doc-interior + 'page-size page-size + 'page-margin-left "12p" + 'page-margin-right "12p" + 'font-family initial-font-family + 'hyphenate "false" + 'footer-display "true")) + (define output-file-path + (match (path->complete-path + (or output-file-path-arg + (build-path (find-system-path 'desk-dir) + (format "~a proof.pdf" font-name-arg)))) + [(? file-exists? path) #:when (not replace) (increment-path path)] + [path path])) + (values doc output-file-path)])) + (begin0 + (render-pdf doc output-file-path) + (when output-qml? + (define qml-path (path-replace-extension output-file-path #".qml")) + (call-with-output-file* qml-path + (λ (op) (display (qexpr->qml doc) op )) + #:exists 'replace)))) \ No newline at end of file