From 5e328077a88a6261f22397ea04fd90052f20dca9 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Wed, 21 Aug 2019 12:20:10 -0700 Subject: [PATCH] support output-path attribute --- quad/quad/scribblings/quad.scrbl | 22 ++++++++++++++---- quad/quadwriter/lang-helper.rkt | 40 ++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/quad/quad/scribblings/quad.scrbl b/quad/quad/scribblings/quad.scrbl index bdd71655..47405986 100644 --- a/quad/quad/scribblings/quad.scrbl +++ b/quad/quad/scribblings/quad.scrbl @@ -106,7 +106,7 @@ quadwriter: wrote PDF to /Users/Desktop/test.pdf Congratulations — you just made your first PDF. If you want to have a look, either open the file manually, or enter this command on the REPL, which will open the PDF in your default viewer: @terminal{ -> (view-result) +> (view-output) } Next, on the REPL enter this: @@ -121,7 +121,7 @@ You will see the actual input to Quadwriter, which is called a @tech{Q-expressio '(q () (q ((page-margin-left "120") (page-margin-top "80") (page-margin-bottom "120") (font-family "text") (line-height "17")) (q ((keep-first-lines "2") (keep-last-lines "3") (font-size-adjust "100%") (character-tracking "0") (hyphenate "true") (display "g49598")) "Brennan and Dale like fancy sauce."))) } -In the demos that follow, the input language will change slightly. But the PDF will be rendered the same way (by running the source file) and you can always look at @racket[doc] or use @racket[view-result]. +In the demos that follow, the input language will change slightly. But the PDF will be rendered the same way (by running the source file) and you can always look at @racket[doc] or use @racket[view-output]. @subsection{Quadwriter & Markdown} @@ -447,7 +447,7 @@ The @tech{Q-expression} @racketresult['#,para-break]. Used to denote the start o @defthing[section-break qexpr?]{ The @tech{Q-expression} @racketresult['#,section-break]. Used to denote the start of a new section. -A section is a contiguous series of pages. Each section has its own @secref{Page-level_attributes}. A document without any explicit section breaks still has one section (that includes all the pages). +A section is a contiguous series of pages. Each section has its own @secref{Section-level_attributes}. A document without any explicit section breaks still has one section (that includes all the pages). } @@ -457,8 +457,20 @@ These are the attributes that can be used inside a @tech{Q-expression} passed to A @deftech{dimension string} represents a distance in the plane. If unitless, it is treated as points (where 1 point = 1/72 of an inch). If the number has @racket[in], @racket[cm], or @racket[mm] as a suffix, it is treated as inches, centimeters, or millimeters respectively. +@subsubsection{Document-level attributes} + +Attributes that can only be set once for the whole document. + + +@defthing[#:kind "attribute" output-path symbol?]{ +Output path for the rendered PDF. Default is the name of the source file with its extension changed to @racket[.pdf]. For instance, @racket["my-source.rkt"] would become @racket["my-source.pdf"]. Unsaved source files are rendered as @racket["untitled.pdf"]. +} + + +@subsubsection{Section-level attributes} + +Attributes that can be set for each section. -@subsubsection{Page-level attributes} @deftogether[(@defthing[#:kind "attribute" page-size symbol?] @defthing[#:kind "attribute" page-orientation symbol?])]{ @@ -737,7 +749,7 @@ A @deftech{named color} is a hex color with a pre-existing name. @subsection{Utility} @defproc[ -(view-result) +(view-output) void?]{ On the REPL, after running a @racketmodname[quadwriter] dialect and generating a PDF, this function will open the PDF. } diff --git a/quad/quadwriter/lang-helper.rkt b/quad/quadwriter/lang-helper.rkt index ab3f4027..637427b6 100644 --- a/quad/quadwriter/lang-helper.rkt +++ b/quad/quadwriter/lang-helper.rkt @@ -32,8 +32,8 @@ [_ (loop kw-val-pairs)]))] ;; reverse in case of multiple values with same keyword, latest takes precedence (by becoming first) [else (reverse (for/list ([(kw val) (in-dict kw-val-pairs)]) - (list (string->symbol (string-trim (keyword->string kw) "#:")) - (format "~a" val))))]))) + (list (string->symbol (string-trim (keyword->string kw) "#:")) + (format "~a" val))))]))) (strip-context (with-syntax ([PATH-STRING path-string] [((ATTR-NAME ATTR-VAL) ...) kw-attrs] @@ -51,30 +51,36 @@ (syntax-case stx () [(_ PATH-STRING ATTRS . EXPRS) (with-syntax ([DOC (datum->syntax #'PATH-STRING 'doc)] - [VIEW-RESULT (datum->syntax #'PATH-STRING 'view-result)]) + [VIEW-OUTPUT (datum->syntax #'PATH-STRING 'view-output)]) #'(#%module-begin - (provide DOC VIEW-RESULT) - (define DOC `(q ATTRS ,(DOC-PROC (list . EXPRS)))) - (define pdf-path (path-string->pdf-path 'PATH-STRING)) - (define (VIEW-RESULT) + (provide DOC VIEW-OUTPUT) + (define attrs (let ([h (make-hasheq)]) + (for ([kvlist (in-list 'ATTRS)]) + (apply hash-set! h kvlist)) + h)) + (define pdf-path (hash-ref! attrs 'output-path (λ () (path-string->pdf-path 'PATH-STRING)))) + (define DOC `(q ,(for/list ([(k v) (in-hash attrs)]) + (list k v)) + ,(DOC-PROC (list . EXPRS)))) + (define (VIEW-OUTPUT) (define open-string (case (system-type 'os) [(macosx) "open '~a'"] [(windows) "start '~a'"] [(unix) "xdg-open '~a' &> /dev/null"] - [else (error "Don't know how to open PDF file.")])) + [else (error "Unknown platform. Don't know how to view PDF.")])) (when (file-exists? pdf-path) (void (system (format open-string pdf-path))))) (module+ main (with-logging-to-port - (current-output-port) - (λ () (with-logging-to-port - (current-output-port) - (λ () (render-pdf DOC pdf-path PATH-STRING)) - #:logger quadwriter-logger - 'debug)) - #:logger quad-logger - 'debug))))])))) + (current-output-port) + (λ () (with-logging-to-port + (current-output-port) + (λ () (render-pdf DOC pdf-path PATH-STRING)) + #:logger quadwriter-logger + 'debug)) + #:logger quad-logger + 'debug))))])))) (define (path-string->pdf-path path-string) (match (format "~a" path-string) @@ -122,7 +128,7 @@ (or (for/first ([pos (in-range line-start-pos line-end-pos)] #:unless (char-blank? (send text get-character pos))) - pos) + pos) line-start-pos)) (- first-vis-pos line-start-pos))] [else default])))