fix(org-latex): rewrite tabularx filter using with-temp-buffer + replace-match
Emacs 31 changed behavior of replace-regexp-in-string with lambda replacements
containing backslashes: 'Invalid use of backslash in replacement text' error.
Fix: use with-temp-buffer + re-search-forward + replace-match (literal t t).
replace-match with LITERAL=t never processes backslash sequences.
Also fixes \end{tabular} → \end{tabularx} regex to not match existing tabularx.
This commit is contained in:
47
config.el
47
config.el
@@ -326,41 +326,32 @@ Bound to cmd+v in org-mode and markdown-mode."
|
|||||||
;;; ============================================================
|
;;; ============================================================
|
||||||
|
|
||||||
;; LaTeX table export: tabular → tabularx{\linewidth} with lYYY column spec.
|
;; LaTeX table export: tabular → tabularx{\linewidth} with lYYY column spec.
|
||||||
;; Filter on rendered LaTeX string — no buffer modification, no recursion.
|
;; Uses with-temp-buffer + replace-match (literal t t) — avoids backslash issues
|
||||||
|
;; in replace-regexp-in-string lambda replacements on Emacs 31.
|
||||||
;; Uses Y column type (defined in document.org template: RaggedRight + auto-width X).
|
;; Uses Y column type (defined in document.org template: RaggedRight + auto-width X).
|
||||||
;; Handles:
|
|
||||||
;; \begin{tabular}{lll} → \begin{tabularx}{\linewidth}{lYY}
|
|
||||||
;; \begin{tabularx}{lll} → \begin{tabularx}{\linewidth}{lYY} (missing width fix)
|
|
||||||
(defun my/org-latex-col-to-lyyy (spec)
|
(defun my/org-latex-col-to-lyyy (spec)
|
||||||
"Convert tabular column SPEC to tabularx lYYY format.
|
"Convert tabular column SPEC to lYYY: first col l, rest Y (auto-width)."
|
||||||
Counts l/r/c columns; first → l, rest → Y (auto-width, defined in template)."
|
(let ((ncols (max 1 (length (replace-regexp-in-string "[^lrcLRCpP]" "" spec)))))
|
||||||
(let* ((ncols (length (replace-regexp-in-string "[^lrcLRCpP]" "" spec)))
|
|
||||||
(ncols (max 1 ncols)))
|
|
||||||
(if (= ncols 1) "Y"
|
(if (= ncols 1) "Y"
|
||||||
(concat "l" (make-string (1- ncols) ?Y)))))
|
(concat "l" (make-string (1- ncols) ?Y)))))
|
||||||
|
|
||||||
(defun my/org-latex-fix-tabularx (table _backend _info)
|
(defun my/org-latex-fix-tabularx (table _backend _info)
|
||||||
"Convert tabular → tabularx{\\linewidth}{lYYY} in LaTeX table output."
|
"Convert tabular/tabularx → tabularx{\\linewidth}{lYYY} in LaTeX output."
|
||||||
(when (stringp table)
|
(when (stringp table)
|
||||||
;; Fix tabularx{colspec} missing width (some org versions omit \linewidth)
|
(with-temp-buffer
|
||||||
(setq table
|
(insert table)
|
||||||
(replace-regexp-in-string
|
(goto-char (point-min))
|
||||||
"\\\\begin{tabularx}{\\([^\\\\][^}]*\\)}"
|
;; \begin{tabular}{spec} or \begin{tabularx}{spec} → \begin{tabularx}{\linewidth}{lYYY}
|
||||||
(lambda (m)
|
(while (re-search-forward "\\\\begin{tabular[x]?}{\\([^}]*\\)}" nil t)
|
||||||
(format "\\begin{tabularx}{\\linewidth}{%s}"
|
(let* ((spec (match-string 1))
|
||||||
(my/org-latex-col-to-lyyy (match-string 1 m))))
|
(new-spec (my/org-latex-col-to-lyyy spec))
|
||||||
table))
|
(repl (concat "\\begin{tabularx}{\\linewidth}{" new-spec "}")))
|
||||||
;; Convert tabular{colspec} → tabularx{\linewidth}{lYYY}
|
(replace-match repl t t)))
|
||||||
(setq table
|
;; \end{tabular} → \end{tabularx} (skip if already tabularx)
|
||||||
(replace-regexp-in-string
|
(goto-char (point-min))
|
||||||
"\\\\begin{tabular}{\\([^}]*\\)}"
|
(while (re-search-forward "\\\\end{tabular}" nil t)
|
||||||
(lambda (m)
|
(replace-match "\\end{tabularx}" t t))
|
||||||
(format "\\begin{tabularx}{\\linewidth}{%s}"
|
(buffer-string))))
|
||||||
(my/org-latex-col-to-lyyy (match-string 1 m))))
|
|
||||||
table))
|
|
||||||
(setq table
|
|
||||||
(replace-regexp-in-string "\\\\end{tabular}" "\\\\end{tabularx}" table)))
|
|
||||||
table)
|
|
||||||
|
|
||||||
;; Register filter on ox-latex load AND ensure it via a pre-processing hook
|
;; Register filter on ox-latex load AND ensure it via a pre-processing hook
|
||||||
;; (belt+suspenders: whichever fires first wins, both are idempotent).
|
;; (belt+suspenders: whichever fires first wins, both are idempotent).
|
||||||
|
|||||||
Reference in New Issue
Block a user