8

I am trying to find a way to export an Org document with lots of formulas in plain text, but the results aren't great so far.

What I tried:

  1. pandoc - basically keeps all math in LaTeX unchanged, doesn't even strip the environment makrers.
  2. detex - doesn't replace Greek symbols (simply removes them), there are artefacts in the produced formulas (s.a. ampersands left from alignment etc.)
  3. tex2mail - looks funny and very hard to read, leaves artefacts, environment markers etc.
  4. catdvi - is the best so far, however, I only need it to run on the LaTeX fragments in the Org file, the rest of the file looks very bad (indenting, titles etc).
  5. hevea - this program is used by texi2dvi to generate text output. Doesn't really work, the output looks very strange / some Greek letters are translated into Unicode, others aren't, the alignment is all wrong...

I could probably write a special backend to first export all LaTeX fragments to DVI and then to run catdvi on those, but before I get to it, maybe there's a simpler way to do it?

  • If only we could export the file with the previewed math in org-mode that would do the job. But I don't know if it's easy to do or not. – DJJ Oct 26 '15 at 14:49
  • @DJJ I'm working on advising ASCII backend functions handling the export, I hope to have some results by evening. – wvxvw Oct 26 '15 at 15:35
  • Can you clarify what your desired output is? I'm not sure how you would improve on LaTeX to represent formulas in plain text. What does catdvi actually do? – Tyler Oct 26 '15 at 15:46
  • @Tyler 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). – wvxvw Oct 26 '15 at 15:54
  • @wvxvw That would be quite an interesting feature. May the force be with you. – DJJ Oct 26 '15 at 15:59
2

So, here's something I came up with, but it's still not perfect. There are two main problems:

  1. 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.

  2. 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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.