#lang scheme/base

(require scheme/system scheme/port scheme/promise)

(provide run-pdflatex)

(define (run-pdflatex file [notify void])
  (define (err fmt . args) (apply error 'run-pdflatex fmt args))
  (define cmd
    (list (or (find-executable-path "pdflatex")
              (and (eq? 'windows (system-type))
                   (find-executable-path "pdflatex.exe"))
              (err "could not find a `pdflatex' executable"))
          "-interaction=batchmode"
          (format "~a" file)))
  (define logfile (path-replace-suffix file #".log"))
  (define (run)
    (unless (parameterize ([current-output-port (open-output-nowhere)])
              (apply system* cmd))
      (unless (file-exists? logfile)
        (err "did not generate a log file at ~a" logfile))
      (call-with-input-file* logfile
        (lambda (log) (copy-port log (current-error-port))))
      (err "got error exit code")))
  (let loop ([n 0])
    (when (= n 5)
      (err "didn't get a stable result after ~a runs" n))
    (if (zero? n)
      (notify "running pdflatex on ~a" file)
      (notify " re-running ~a~a time"
                    (add1 n) (case (add1 n) [(2) 'nd] [(3) 'rd] [else 'th])))
    (run)
    ;; see if we get a "Rerun" note, these seem to come in two flavors
    ;; * Label(s) may have changed. Rerun to get cross-references right.
    ;; * Package longtable Warning: Table widths have changed. Rerun LaTeX.
    (cond [(call-with-input-file* logfile
             (lambda (log) (regexp-match? #px#"changed\\.\\s+Rerun" log)))
           (loop (add1 n))]
          [(zero? n)
           (notify "WARNING: no \"Rerun\" found in first run of pdflatex for ~a"
                   file)]))
  (path-replace-suffix file #".pdf"))
