ox-latex: Protect [...] after \\ to be interpreted as LaTeX argument

* lisp/ox-latex.el (org-latex-linebreak-safe): New constant holding
safe version of LaTeX line break.
(org-latex-table-matrix-macros):
(org-latex-clock):
(org-latex-line-break):
(org-latex-plain-text):
(org-latex-planning):
(org-latex--org-table):
(org-latex--math-table):
(org-latex-table-row):
(org-latex-verse-block): Use the new constant.

* testing/lisp/test-org-table.el (test-org-table/to-latex): Update
tests.

Reported-by: Stewart Thomas <sjt015@bucknell.edu>
Link: https://orgmode.org/list/ce760fc3-5aae-144d-2d02-7dea215f73fc@gmail.com
This commit is contained in:
Ihor Radchenko 2022-10-07 16:24:32 +08:00
parent 4d07df718b
commit 3f60acff77
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
2 changed files with 36 additions and 17 deletions

View File

@ -278,10 +278,23 @@ list can be:
- `:lang-name' the actual name of the language.") - `:lang-name' the actual name of the language.")
(defconst org-latex-line-break-safe "\\\\\\relax"
"Linebreak protecting the following [...].
(defconst org-latex-table-matrix-macros '(("bordermatrix" . "\\cr") Without \"\\relax\" it would be interpreted as an optional argument to
the \\\\.
This constant, for example, makes the below code not err:
\\begin{tabular}{c|c}
[t] & s\\\\\\relax
[I] & A\\\\\\relax
[m] & kg
\\end{tabular}")
(defconst org-latex-table-matrix-macros `(("bordermatrix" . "\\cr")
("qbordermatrix" . "\\cr") ("qbordermatrix" . "\\cr")
("kbordermatrix" . "\\\\")) ("kbordermatrix" . ,org-latex-line-break-safe))
"Alist between matrix macros and their row ending.") "Alist between matrix macros and their row ending.")
(defconst org-latex-math-environments-re (defconst org-latex-math-environments-re
@ -2062,7 +2075,7 @@ information."
(concat (org-timestamp-translate (org-element-property :value clock)) (concat (org-timestamp-translate (org-element-property :value clock))
(let ((time (org-element-property :duration clock))) (let ((time (org-element-property :duration clock)))
(and time (format " (%s)" time))))) (and time (format " (%s)" time)))))
"\\\\")) org-latex-line-break-safe))
;;;; Code ;;;; Code
@ -2659,7 +2672,7 @@ CONTENTS is nil. INFO is a plist holding contextual information."
(defun org-latex-line-break (_line-break _contents _info) (defun org-latex-line-break (_line-break _contents _info)
"Transcode a LINE-BREAK object from Org to LaTeX. "Transcode a LINE-BREAK object from Org to LaTeX.
CONTENTS is nil. INFO is a plist holding contextual information." CONTENTS is nil. INFO is a plist holding contextual information."
"\\\\\n") (concat org-latex-line-break-safe "\n"))
;;;; Link ;;;; Link
@ -3005,7 +3018,9 @@ contextual information."
;; Handle break preservation if required. ;; Handle break preservation if required.
(when (plist-get info :preserve-breaks) (when (plist-get info :preserve-breaks)
(setq output (replace-regexp-in-string (setq output (replace-regexp-in-string
"\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" output nil t))) "\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n"
(concat org-latex-line-break-safe "\n")
output nil t)))
;; Return value. ;; Return value.
output)) output))
@ -3041,7 +3056,7 @@ information."
(format (plist-get info :latex-active-timestamp-format) (format (plist-get info :latex-active-timestamp-format)
(org-timestamp-translate scheduled))))))) (org-timestamp-translate scheduled)))))))
" ") " ")
"\\\\")) org-latex-line-break-safe))
;;;; Property Drawer ;;;; Property Drawer
@ -3821,11 +3836,11 @@ This function assumes TABLE has `org' as its `:type' property and
(format "\\begin{%s}%s{%s}\n" table-env width alignment) (format "\\begin{%s}%s{%s}\n" table-env width alignment)
(and above? (and above?
(org-string-nw-p caption) (org-string-nw-p caption)
(concat caption "\\\\\n")) (concat caption org-latex-line-break-safe "\n"))
contents contents
(and (not above?) (and (not above?)
(org-string-nw-p caption) (org-string-nw-p caption)
(concat caption "\\\\\n")) (concat caption org-latex-line-break-safe "\n"))
(format "\\end{%s}" table-env) (format "\\end{%s}" table-env)
(and fontsize "}")))) (and fontsize "}"))))
(t (t
@ -3910,7 +3925,7 @@ This function assumes TABLE has `org' as its `:type' property and
(lambda (cell) (lambda (cell)
(substring (org-element-interpret-data cell) 0 -1)) (substring (org-element-interpret-data cell) 0 -1))
(org-element-map row 'table-cell #'identity info) "&") (org-element-map row 'table-cell #'identity info) "&")
(or (cdr (assoc env org-latex-table-matrix-macros)) "\\\\") (or (cdr (assoc env org-latex-table-matrix-macros)) org-latex-line-break-safe)
"\n"))) "\n")))
(org-element-map table 'table-row #'identity info) ""))) (org-element-map table 'table-row #'identity info) "")))
(concat (concat
@ -3982,7 +3997,7 @@ a communication channel."
;; hline was specifically marked. ;; hline was specifically marked.
(and booktabsp (not (org-export-get-previous-element table-row info)) (and booktabsp (not (org-export-get-previous-element table-row info))
"\\toprule\n") "\\toprule\n")
contents "\\\\\n" contents org-latex-line-break-safe "\n"
(cond (cond
;; Special case for long tables. Define header and footers. ;; Special case for long tables. Define header and footers.
((and longtablep (org-export-table-row-ends-header-p table-row info)) ((and longtablep (org-export-table-row-ends-header-p table-row info))
@ -3990,9 +4005,9 @@ a communication channel."
(org-export-get-parent-table table-row) info)))) (org-export-get-parent-table table-row) info))))
(format "%s (format "%s
\\endfirsthead \\endfirsthead
\\multicolumn{%d}{l}{%s} \\\\ \\multicolumn{%d}{l}{%s} \\\\\\relax
%s %s
%s \\\\\n %s \\\\\\relax\n
%s %s
\\endhead \\endhead
%s\\multicolumn{%d}{r}{%s} \\\\ %s\\multicolumn{%d}{r}{%s} \\\\
@ -4092,8 +4107,12 @@ contextual information."
(replace-regexp-in-string (replace-regexp-in-string
"^[ \t]*\\\\\\\\$" "\\vspace*{1em}" "^[ \t]*\\\\\\\\$" "\\vspace*{1em}"
(replace-regexp-in-string (replace-regexp-in-string
"\\([ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" "\\([ \t]*\\\\\\\\\\)?[ \t]*\n"
contents nil t) nil t) nil t) linreset) (concat org-latex-line-break-safe "\n")
contents nil t)
nil t)
nil t)
linreset)
info) info)
;; Insert footnote definitions, if any, after the environment, so ;; Insert footnote definitions, if any, after the environment, so
;; the special formatting above is not applied to them. ;; the special formatting above is not applied to them.

View File

@ -1635,11 +1635,11 @@ See also `test-org-table/copy-field'."
(ert-deftest test-org-table/to-latex () (ert-deftest test-org-table/to-latex ()
"Test `orgtbl-to-latex' specifications." "Test `orgtbl-to-latex' specifications."
(should (should
(equal "\\begin{tabular}{l}\na\\\\\n\\end{tabular}" (equal "\\begin{tabular}{l}\na\\\\\\relax\n\\end{tabular}"
(orgtbl-to-latex (org-table-to-lisp "| a |") nil))) (orgtbl-to-latex (org-table-to-lisp "| a |") nil)))
;; Test :environment parameter. ;; Test :environment parameter.
(should (should
(equal "\\begin{tabularx}{l}\na\\\\\n\\end{tabularx}" (equal "\\begin{tabularx}{l}\na\\\\\\relax\n\\end{tabularx}"
(orgtbl-to-latex (org-table-to-lisp "| a |") (orgtbl-to-latex (org-table-to-lisp "| a |")
'(:environment "tabularx")))) '(:environment "tabularx"))))
;; Test :booktabs parameter. ;; Test :booktabs parameter.
@ -1648,7 +1648,7 @@ See also `test-org-table/copy-field'."
"\\toprule" (orgtbl-to-latex (org-table-to-lisp "| a |") '(:booktabs t)))) "\\toprule" (orgtbl-to-latex (org-table-to-lisp "| a |") '(:booktabs t))))
;; Handle LaTeX snippets. ;; Handle LaTeX snippets.
(should (should
(equal "\\begin{tabular}{l}\n\\(x\\)\\\\\n\\end{tabular}" (equal "\\begin{tabular}{l}\n\\(x\\)\\\\\\relax\n\\end{tabular}"
(orgtbl-to-latex (org-table-to-lisp "| $x$ |") nil))) (orgtbl-to-latex (org-table-to-lisp "| $x$ |") nil)))
;; Test pseudo objects and :raw parameter. ;; Test pseudo objects and :raw parameter.
(should (should