So, here's something I came up with, but it's still not perfect. There are two main problems:
catdvi
can't be made to use Unicode subscripts and superscripts, instead it places normal sized characters on the line below and above, which makes inline LaTeX bits look bad. There are also related problems such as the rendering of \frac{}{}
, \binom{}{}
and similar inline, where they appear on the same line and completely disintegrate into surrounding text.
Multiline LaTeX code is noticeably better, but sometimes catdvi
adds extra blank lines (it's hard to know whether to remove them, but I could post-process the output to remove blank lines).
Below is the code I used and some examples generated:
(defmacro by-backend (&rest body)
`(cl-case (when (boundp 'backend)
(org-export-backend-name backend))
,@body))
(defun my/org-latex-headers ()
(mapcar
(lambda (record) (plist-get (cl-second record) :value))
(cl-remove-if-not
(lambda (record)
(let* ((data (cl-second record))
(key (plist-get data :key)))
(or (string-equal key "LATEX_HEADER")
(string-equal key "LATEX_HEADER_EXTRA"))))
(org-element-map (org-element-parse-buffer) 'keyword 'identity))))
(defun my/org-latex-template-with-header (body)
(org-latex-template
body
`(:title ""
:exported-data ,(make-hash-table)
:language "latex"
:latex-classes ,org-latex-classes
:latex-class "article"
:latex-header ,(mapconcat 'identity (my/org-latex-headers) "\n"))))
(defun my/latex-to-ascii (latex &optional multiline)
(let* ((catdvi-buf (get-buffer-create "*catdvi-buf*"))
(tmpname (make-temp-file "catdvi" nil ".tex"))
(dviname (format "%s.dvi" (file-name-sans-extension tmpname)))
(template (my/org-latex-template-with-header latex)))
(with-current-buffer catdvi-buf (erase-buffer))
(with-temp-file tmpname
(insert template)
tmpname)
(call-process (executable-find "texi2dvi")
nil (get-buffer-create "*texi2dvi-buf*") nil
"-o" dviname tmpname)
(if multiline
(progn
(call-process (executable-find "catdvi") nil (list catdvi-buf nil) nil
"-e" "0" dviname)
(replace-regexp-in-string
;; removes page numbering and page break
"[\f\v\t\n ]*1[\f\n\t \\.]*\\'" ""
(with-current-buffer catdvi-buf (buffer-string))))
(progn
(call-process (executable-find "catdvi") nil (list catdvi-buf nil) nil
"-s" "-e" "0" dviname)
(org-trim
(replace-regexp-in-string
;; removes page numbering and page break
"1[\f\n\t \\.]*\\'" ""
(with-current-buffer catdvi-buf (buffer-string))))))))
(defun my/org-ascii-latex-fragment (orig latex-fragment contents info)
(when (plist-get info :with-latex)
(my/latex-to-ascii
(org-element-property :value latex-fragment))))
(defun my/org-ascii-latex-environment (orig latex-environment contents info)
(message "my/org-ascii-latex-environment")
(when (plist-get info :with-latex)
(org-ascii--justify-element
(my/latex-to-ascii
(org-remove-indentation (org-element-property :value latex-environment)) t)
latex-environment info)))
(advice-add 'org-ascii-latex-fragment :around 'my/org-ascii-latex-fragment)
(advice-add 'org-ascii-latex-environment :around 'my/org-ascii-latex-environment)
Note that you will also need to compile catdvi
from sources. There's also a minor problem with compiling it: some C file uses a variable defined in a dependent header file (typically installed separately) without a const
, while the header needs it to be a const
(easily fixed by just adding the necessary declaration bit). texi2dvi
should be available for installing from the package manager.
Alternatives for inline LaTeX:
I was thinking about using TeX
input method, which can use Unicode subscript and superscript characters, however, this would require parsing and pre-processing LaTeX code in order to feed it to TeX
input method.
Another alternative is to try to use AUCTeX parsing to figure out subscripts and superscripts, but both of these demand too much effort... It's easier at the moment to use catdvi
for inline formulas and then to fix the subscripts / superscripts by hand.
(defun my/prepare-tex-ime (input)
(cl-loop for paren in '("[]{}") do
(setq input (replace-regexp-in-string
(format "\\\\%s" paren) paren input)))
input)
(defun my/tex-ime-translate (input)
(with-temp-buffer
(set-input-method 'TeX)
(setq quail-current-key "")
(cl-loop for c across input do
(setq last-command-event c)
(call-interactively 'quail-self-insert-command))
(buffer-string)))
Examples:
** Problem 1
Prove that
#+HEADER: :exports results
#+HEADER: :results (by-backend (pdf "latex") (t "raw"))
#+BEGIN_SRC latex
\begin{align*}
L = \{w \in \{a, b, c, d\}^* \;|\; w=dv, v \in \{a, b, c\}^*,
\#_a(w) \cdot \#_c(w) < \#_b(w) \}
\end{align*}
#+END_SRC
is not regular.
Translates into
1.1 Problem 1
─────────────
Prove that
∗ ∗
L = {w ∈ {a,b,c,d} | w = dv,v ∈ {a,b,c} ,# (w)·# (w) < # (w)}
a c b
is not regular.
catdvi
actually do?catdvi
generates Unicode + ASCII-art to represent DVI graphics. This is hardly an improvement on LaTeX, but it is needed for people who can't read LaTeX source / PDF or DVI aren't available in that environment (eg. when interacting with a text terminal, or sending text-only emails).