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:
parent
4075662c29
commit
c940b460c7
|
@ -489,6 +489,13 @@ support in LaTeX. The new =babel= syntax for loading languages via
|
||||||
=ini= files and the new command =\babelprovide= (see:
|
=ini= files and the new command =\babelprovide= (see:
|
||||||
https://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf)
|
https://mirrors.ctan.org/macros/latex/required/babel/base/babel.pdf)
|
||||||
are also supported.
|
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
|
* Version 9.5
|
||||||
|
|
||||||
** Important announcements and breaking changes
|
** Important announcements and breaking changes
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
(require 'ox)
|
(require 'ox)
|
||||||
|
|
||||||
(defvar orgtbl-exp-regexp)
|
(defvar orgtbl-exp-regexp)
|
||||||
|
(defvar org-texinfo-supports-math--cache)
|
||||||
|
|
||||||
|
|
||||||
;;; Define Back-End
|
;;; Define Back-End
|
||||||
|
@ -58,6 +58,8 @@
|
||||||
(italic . org-texinfo-italic)
|
(italic . org-texinfo-italic)
|
||||||
(item . org-texinfo-item)
|
(item . org-texinfo-item)
|
||||||
(keyword . org-texinfo-keyword)
|
(keyword . org-texinfo-keyword)
|
||||||
|
(latex-environment . org-texinfo-latex-environment)
|
||||||
|
(latex-fragment . org-texinfo-latex-fragment)
|
||||||
(line-break . org-texinfo-line-break)
|
(line-break . org-texinfo-line-break)
|
||||||
(link . org-texinfo-link)
|
(link . org-texinfo-link)
|
||||||
(node-property . org-texinfo-node-property)
|
(node-property . org-texinfo-node-property)
|
||||||
|
@ -123,7 +125,9 @@
|
||||||
(:texinfo-text-markup-alist nil nil org-texinfo-text-markup-alist)
|
(:texinfo-text-markup-alist nil nil org-texinfo-text-markup-alist)
|
||||||
(:texinfo-format-drawer-function nil nil org-texinfo-format-drawer-function)
|
(:texinfo-format-drawer-function nil nil org-texinfo-format-drawer-function)
|
||||||
(:texinfo-format-inlinetask-function nil nil org-texinfo-format-inlinetask-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
|
;;; User Configurable Variables
|
||||||
|
@ -358,6 +362,22 @@ The function should return the string to be exported."
|
||||||
:group 'org-export-texinfo
|
:group 'org-export-texinfo
|
||||||
:type 'function)
|
: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
|
;;;; Itemx
|
||||||
|
|
||||||
(defcustom org-texinfo-compact-itemx nil
|
(defcustom org-texinfo-compact-itemx nil
|
||||||
|
@ -1215,6 +1235,52 @@ CONTENTS is nil. INFO is a plist holding contextual information."
|
||||||
(concat "@listoffloats "
|
(concat "@listoffloats "
|
||||||
(org-export-translate "Listing" :utf-8 info))))))))
|
(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
|
;;;; Line Break
|
||||||
|
|
||||||
(defun org-texinfo-line-break (_line-break _contents _info)
|
(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.")
|
(message "Process completed.")
|
||||||
output))
|
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)
|
(provide 'ox-texinfo)
|
||||||
|
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue