(require 'cl-lib)
(require 'f)

(defconst *tempfile-dir* "/dev/shm")


(defun tex-paragraph-preview ()
  (interactive)
  (let* ((tex-paragraph (save-excursion
                          (mark-paragraph)
                          (buffer-substring (point) (mark))))
         (tex-document (tex-equation-context
                        tex-paragraph))
         (png-file (tex-compile-to-image
                    tex-document)))
    (when png-file
      (tex-insert-image/normalize-paragraph png-file))))


(defvar-keymap tex-notes-mode-map
  "C-c C-l" #'tex-paragraph-preview)


(defun tex-equation-context (tex-paragraph)
  (concat
   "\\documentclass[fleqn]{article}
\\thispagestyle{empty}
\\usepackage[margin=3pt,a6paper]{geometry}
\\usepackage{amsmath}
\\begin{document}
\\begin{equation*}"
   tex-paragraph
   "\\end{equation*}
\\end{document}"))
;; (cheap hack: avoid page numbering, so that cropping out
;;  an equation from the output page is trivial)


(defun tex-compile-to-image (tex-input)
  (with-current-buffer (get-buffer-create "*tex-errors*")
    (cl-loop
     with default-directory = *tempfile-dir*
     with run-id = (symbol-name (gensym "tex"))
     with tex-file = (format "%s/%s.tex" *tempfile-dir* run-id)
     with dvi-file = (format "%s/%s.dvi" *tempfile-dir* run-id)
     with png-file = (format "%s/%s.png" *tempfile-dir* run-id)
     initially do (f-write tex-input 'utf-8 tex-file)
     for (program . args)
     in `(("latex" ,tex-file)
          ("dvipng" "-D" "400" ,dvi-file "-o" ,png-file)
          ("magick" ,png-file "-bordercolor" "white"
           "-border" "30" ,png-file)
          ("magick" ,png-file "-transparent" "white" ,png-file))
     when (/= 0 (apply #'call-process program nil t nil args))
     do (progn (switch-to-buffer "*tex-errors*")
               (cl-return nil))
     finally (cl-return png-file))))



(defun tex-insert-image/normalize-paragraph (png-file)
  (save-excursion
    (beginning-of-line) (end-of-paragraph-text)
    (unless (looking-at "\n") (insert "\n"))
    (save-excursion
      (let ((limit (save-excursion
                     (end-of-paragraph-text) (point))))
        (save-excursion
          (when (re-search-forward "%magic-string%" limit t)
            (delete-region (match-beginning 0) (match-end 0))
            (cl-loop repeat 4 while (looking-at "\n")
                     do (kill-region (point) (1+ (point))))
            (newline 1)))
        (forward-paragraph)
        (insert-image (create-image png-file 'png nil :scale 0.75)
                      "%magic-string%")
        (newline 1)))))


(define-derived-mode tex-notes-mode latex-mode
  "TeX notes"
  ""
  (progn (setq buffer-offer-save t)))


(provide 'tex-notes-mode)