run-pdflatex.rkt (4193B)
1 #lang scheme/base 2 3 (require scheme/system scheme/port) 4 5 (provide run-pdflatex run-dvipdf-latex run-xelatex) 6 7 (define (run-pdflatex file [notify void]) (run file notify 'pdflatex)) 8 (define (run-dvipdf-latex file [notify void]) 9 (parameterize ([function-name 'run-dvipdf-latex]) 10 (run file notify 'dvipdf))) 11 (define (run-xelatex file [notify void]) 12 (parameterize ([function-name 'run-xelatex]) 13 (run file notify 'xelatex))) 14 15 (define max-runs 5) 16 (define (run file notify type) 17 (define latex-cmd-name (cond [(equal? type 'pdflatex) "pdflatex"] 18 [(equal? type 'dvipdf) "latex"] 19 [(equal? type 'xelatex) "xelatex"] 20 [else (err "unknown run type ~a" type)])) 21 (define cmd 22 (list (get-latex-binary latex-cmd-name) 23 "-interaction=batchmode" 24 (format "~a" file))) 25 (define logfile (path-replace-suffix file #".log")) 26 (define (run) 27 (unless (parameterize ([current-output-port (open-output-nowhere)]) 28 (apply system* cmd)) 29 (unless (file-exists? logfile) 30 (err "did not generate a log file at ~a" logfile)) 31 (call-with-input-file* logfile 32 (lambda (log) (copy-port log (current-error-port)))) 33 (err "got error exit code"))) 34 (let loop ([n 0]) 35 (when (= n max-runs) 36 (err "didn't get a stable result after ~a runs" n)) 37 (if (zero? n) 38 (notify "running ~a on ~a" latex-cmd-name file) 39 (notify " running ~a~a time" 40 (add1 n) 41 (case (normalize-for-suffix (add1 n)) [(2) 'nd] [(3) 'rd] [else 'th]))) 42 (run) 43 ;; see if we get a "Rerun" note, these seem to come in two flavors 44 ;; * Label(s) may have changed. Rerun to get cross-references right. 45 ;; * Package longtable Warning: Table widths have changed. Rerun LaTeX. 46 (cond [(call-with-input-file* logfile 47 (lambda (log) (regexp-match? #px#"changed\\.\\s+Rerun" log))) 48 (loop (add1 n))] 49 [(zero? n) 50 (notify "WARNING: no \"Rerun\" found in first run of pdflatex for ~a" 51 file)])) 52 (when (equal? type 'dvipdf) 53 (define dvi-file (path-replace-suffix file #".dvi")) 54 (define ps-file (path-replace-suffix file #".ps")) 55 (unless (file-exists? dvi-file) (err "didn't find .dvi file")) 56 (define dvips (get-latex-binary "dvips")) 57 (define pstopdf (get-latex-binary "pstopdf")) 58 (notify "running dvips on ~a" dvi-file) 59 (define stderr (open-output-bytes)) 60 (unless (parameterize ([current-output-port (open-output-nowhere)] 61 [current-error-port stderr]) 62 (system* dvips dvi-file)) 63 (displayln (get-output-bytes stderr)) 64 (err "got error exit code")) 65 (unless (parameterize ([current-output-port (open-output-nowhere)] 66 [current-error-port stderr]) 67 (system* pstopdf ps-file)) 68 (displayln (get-output-bytes stderr)) 69 (err "got error exit code"))) 70 (path-replace-suffix file #".pdf")) 71 72 (define (normalize-for-suffix n) 73 (cond 74 [(<= 10 n 20) 0] 75 [else (modulo n 10)])) 76 77 (define (get-latex-binary name) 78 (define ans 79 (case (system-type) 80 [(macosx) (or (find-executable-path name) 81 (for/or ([macosx-candidate-dir (in-list macosx-candidate-dirs)]) 82 (define macosx-candidate (build-path macosx-candidate-dir name)) 83 (and (file-exists? macosx-candidate) 84 macosx-candidate)))] 85 [(windows) (or (find-executable-path name) 86 (find-executable-path (format "~a.exe" name)))] 87 [(unix) (find-executable-path name)])) 88 (unless ans 89 (err (format "could not find a `~a' executable" name))) 90 ans) 91 92 (define function-name (make-parameter 'run-pdflatex)) 93 (define (err fmt . args) (apply error (function-name) fmt args)) 94 95 ;; under mac os x, gui apps do not get started with 96 ;; a good path environment, so put likely candidates 97 ;; for directories holding latex/pdflatex binaries 98 ;; here so that the "scribble pdf" button is more 99 ;; likely to work in drracket 100 (define macosx-candidate-dirs 101 '("/usr/texbin" "/Library/TeX/texbin"))