ox-texinfo: Include LaTeX in Texinfo exports

* lisp/ox-texinfo.el (org-texinfo-with-latex): New customize.
* lisp/ox-texinfo.el (org-texinfo-latex-environment): New function.
* lisp/ox-texinfo.el (org-texinfo-latex-fragment): New function.
* lisp/ox-texinfo.el (org-texinfo-supports-math-p): New function.
* lisp/ox-texinfo.el (org-texinfo-supports-math--cache): New variable.
* lisp/ox-texinfo.el (texinfo): Set latex-environment.
* lisp/ox-texinfo.el (texinfo): Set latex-fragment.
* testing/lisp/test-ox-texinfo.el: Add basic tests.
This commit is contained in:
Rudolf Adamkovič 2022-03-26 16:46:47 +01:00 committed by Ihor Radchenko
parent 4075662c29
commit c940b460c7
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
3 changed files with 396 additions and 2 deletions

View File

@ -489,6 +489,13 @@ support in LaTeX. The new =babel= syntax for loading languages via
=ini= files and the new command =\babelprovide= (see:
https://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf)
are also supported.
*** Texinfo exports include LaTeX
With the new customization option ~org-texinfo-with-latex~ set to (its
default value) ~'detect~, if the system runs Texinfo 6.8 (3 July 2021)
or newer, Org will export all LaTeX fragments and environments using
Texinfo ~@math~ and ~@displaymath~ commands respectively.
* Version 9.5
** Important announcements and breaking changes

View File

@ -33,7 +33,7 @@
(require 'ox)
(defvar orgtbl-exp-regexp)
(defvar org-texinfo-supports-math--cache)
;;; Define Back-End
@ -58,6 +58,8 @@
(italic . org-texinfo-italic)
(item . org-texinfo-item)
(keyword . org-texinfo-keyword)
(latex-environment . org-texinfo-latex-environment)
(latex-fragment . org-texinfo-latex-fragment)
(line-break . org-texinfo-line-break)
(link . org-texinfo-link)
(node-property . org-texinfo-node-property)
@ -123,7 +125,9 @@
(:texinfo-text-markup-alist nil nil org-texinfo-text-markup-alist)
(:texinfo-format-drawer-function nil nil org-texinfo-format-drawer-function)
(:texinfo-format-inlinetask-function nil nil org-texinfo-format-inlinetask-function)
(:texinfo-compact-itemx nil "compact-itemx" org-texinfo-compact-itemx)))
(:texinfo-compact-itemx nil "compact-itemx" org-texinfo-compact-itemx)
;; Redefine regular options.
(:with-latex nil "tex" org-texinfo-with-latex)))
;;; User Configurable Variables
@ -358,6 +362,22 @@ The function should return the string to be exported."
:group 'org-export-texinfo
:type 'function)
;;;; LaTeX
(defcustom org-texinfo-with-latex (and org-export-with-latex 'detect)
"When non-nil, the Texinfo exporter attempts to process LaTeX math.
When set to t, the exporter will process LaTeX environments and
fragments as Texinfo \"@displaymath\" and \"@math\" commands
respectively. Alternatively, when set to `detect', the exporter
does so only if the installed version of Texinfo supports the
necessary commands."
:group 'org-export-texinfo
:type '(choice
(const :tag "Detect" detect)
(const :tag "Yes" t)
(const :tag "No" nil)))
;;;; Itemx
(defcustom org-texinfo-compact-itemx nil
@ -1215,6 +1235,52 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(concat "@listoffloats "
(org-export-translate "Listing" :utf-8 info))))))))
;;;; LaTeX Environment
(defun org-texinfo-latex-environment (environment _contents info)
"Transcode a LaTeX ENVIRONMENT from Org to Texinfo.
CONTENTS is ignored. INFO is a plist holding contextual information."
(let ((with-latex (plist-get info :with-latex)))
(when (or (eq with-latex t)
(and (eq with-latex 'detect)
(org-texinfo-supports-math-p)))
(let ((value (org-element-property :value environment)))
(string-join (list "@displaymath"
(string-trim (org-remove-indentation value))
"@end displaymath")
"\n")))))
;;;; LaTeX Fragment
(defun org-texinfo-latex-fragment (fragment _contents info)
"Transcode a LaTeX FRAGMENT from Org to Texinfo.
INFO is a plist holding contextual information."
(let ((with-latex (plist-get info :with-latex)))
(when (or (eq with-latex t)
(and (eq with-latex 'detect)
(org-texinfo-supports-math-p)))
(let ((value (org-remove-indentation
(org-element-property :value fragment))))
(cond
((or (string-match-p "^\\\\\\[" value)
(string-match-p "^\\$\\$" value))
(concat "\n"
"@displaymath"
"\n"
(string-trim (substring value 2 -2))
"\n"
"@end displaymath"
"\n"))
((string-match-p "^\\$" value)
(concat "@math{"
(string-trim (substring value 1 -1))
"}"))
((string-match-p "^\\\\(" value)
(concat "@math{"
(string-trim (substring value 2 -2))
"}"))
(t value))))))
;;;; Line Break
(defun org-texinfo-line-break (_line-break _contents _info)
@ -1951,6 +2017,31 @@ Return INFO file name or an error if it couldn't be produced."
(message "Process completed.")
output))
(defun org-texinfo-supports-math-p ()
"Return t if the installed version of Texinfo supports \"@math\".
Once computed, the results remain cached."
(unless (boundp 'org-texinfo-supports-math--cache)
(setq org-texinfo-supports-math--cache
(let ((math-example "1 + 1 = 2"))
(let* ((input-file
(make-temp-file "test" nil ".info"))
(input-content
(concat (format "@setfilename %s" input-file) "\n"
"@node Top" "\n"
(format "@displaymath{%s}" math-example) "\n")))
(with-temp-file input-file
(insert input-content))
(let* ((output-file (org-texinfo-compile input-file))
(output-content (with-temp-buffer
(insert-file-contents output-file)
(buffer-string))))
(let ((result (string-match-p (regexp-quote math-example)
output-content)))
(delete-file input-file)
(delete-file output-file)
(if result t nil)))))))
org-texinfo-supports-math--cache)
(provide 'ox-texinfo)

View File

@ -0,0 +1,296 @@
;;; test-ox-texinfo.el --- Tests for ox-texinfo.el
;; Copyright (C) 2022 Rudolf Adamkovič
;; Author: Rudolf Adamkovič <salutis@me.com>
;; This file is not part of GNU Emacs.
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'cl-lib)
(require 'ox-texinfo)
(unless (featurep 'ox-texinfo)
(signal 'missing-test-dependency "org-export-texinfo"))
;;; TeX fragments
(ert-deftest test-ox-texinfo/tex-fragment-inline ()
"Test inline TeX fragment."
(should
(equal "@math{a^2 = b}"
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
'(:value "$a^2 = b$"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/tex-fragment-inline-padded ()
"Test inline TeX fragment padded with whitespace."
(should
(equal "@math{a^2 = b}"
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
'(:value "$ a^2 = b $"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/tex-fragment-displayed ()
"Test displayed TeX fragment."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value "$$a ^ 2 = b$$"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/tex-fragment-displayed-padded ()
"Test displayed TeX fragment padded with whitespace."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value "$$ a ^ 2 = b $$"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/tex-fragment-displayed-multi-line ()
"Test displayed TeX fragment with multiple lines."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"b ^ 2 = c"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value
(string-join
(list "$$"
"a ^ 2 = b"
"b ^ 2 = c"
"$$")
"\n")))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/tex-fragment-displayed-indented ()
"Test displayed TeX fragment with indentation."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"b ^ 2 = c"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value
(string-join
(list " $$"
" a ^ 2 = b"
" b ^ 2 = c"
" $$")
"\n")))
nil
'(:with-latex t))))))
;;; LaTeX fragments
(ert-deftest test-ox-texinfo/latex-fragment-inline ()
"Test inline LaTeX fragment."
(should
(equal "@math{a^2 = b}"
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
'(:value "\\(a^2 = b\\)"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-fragment-inline-padded ()
"Test inline LaTeX fragment padded with whitespace."
(should
(equal "@math{a^2 = b}"
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
'(:value "\\( a^2 = b \\)"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-fragment-displayed ()
"Test displayed LaTeX fragment."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value "\\[a ^ 2 = b\\]"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-fragment-displayed-padded ()
"Test displayed LaTeX fragment with multiple lines."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value "\\[ a ^ 2 = b \\]"))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-fragment-displayed-multi-line ()
"Test displayed LaTeX fragment with multiple lines."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"b ^ 2 = c"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value
(string-join
(list "\\["
"a ^ 2 = b"
"b ^ 2 = c"
"\\]")
"\n")))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-fragment-displayed-indented ()
"Test displayed LaTeX fragment with indentation."
(should
(equal (string-join
(list ""
"@displaymath"
"a ^ 2 = b"
"b ^ 2 = c"
"@end displaymath"
"")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-fragment
(org-element-create 'latex-fragment
(list :value
(string-join
(list " \\["
" a ^ 2 = b"
" b ^ 2 = c"
" \\]")
"\n")))
nil
'(:with-latex t))))))
;;; LaTeX environments
(ert-deftest test-ox-texinfo/latex-environment ()
"Test LaTeX environment."
(should
(equal (string-join
(list "@displaymath"
"\\begin{equation}"
"a ^ 2 = b"
"b ^ 2 = c"
"\\end{equation}"
"@end displaymath")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-environment
(org-element-create 'latex-environment
(list :value
(string-join
(list "\\begin{equation}"
"a ^ 2 = b"
"b ^ 2 = c"
"\\end{equation}")
"\n")))
nil
'(:with-latex t))))))
(ert-deftest test-ox-texinfo/latex-environment-indented ()
"Test LaTeX environment with indentation."
(should
(equal (string-join
(list "@displaymath"
"\\begin{equation}"
"a ^ 2 = b"
"b ^ 2 = c"
"\\end{equation}"
"@end displaymath")
"\n")
(let ((org-texinfo-with-latex t))
(org-texinfo-latex-environment
(org-element-create 'latex-environment
(list :value
(string-join
(list " \\begin{equation}"
" a ^ 2 = b"
" b ^ 2 = c"
" \\end{equation}")
"\n")))
nil
'(:with-latex t))))))
(provide 'test-ox-texinfo)
;;; test-ox-texinfo.el end here