fix(org-latex): filter-based tabularx with guaranteed registration

Root cause of \begin{tabularx}{lll} error: org-latex in this version does not
add \linewidth for tabularx environment, generating invalid LaTeX.

Fix: org-export-filter-table-functions filter that transforms rendered output:
  - \begin{tabular}{spec}     → \begin{tabularx}{\linewidth}{spec}
  - \begin{tabularx}{spec}    → \begin{tabularx}{\linewidth}{spec} (missing width fix)
  - \end{tabular}             → \end{tabularx}

No buffer modification → no recursion, works on Emacs 31.

Belt+suspenders registration: with-eval-after-load 'ox-latex + explicit
require+add-to-list in org-export-before-processing-hook ensures the filter
is always registered before the export transcoder runs.
This commit is contained in:
2026-02-23 15:17:15 +01:00
parent 7a1498cdd7
commit 854a6de40a

View File

@@ -325,19 +325,48 @@ Bound to cmd+v in org-mode and markdown-mode."
;;; ORG MODE — LATEX EXPORT
;;; ============================================================
;; LaTeX table export: use tabularx automatically — no buffer modification.
;; Setting a buffer-local variable in the hook is safe (no insert = no recursion).
;; org-latex.el natively handles tabularx/tabulary by adding \linewidth width arg.
(defun my/org-set-tabularx (backend)
"Set tabularx as default LaTeX table environment for this export."
(when (org-export-derived-backend-p backend 'latex)
(setq-local org-latex-default-table-environment "tabularx")))
(add-hook 'org-export-before-processing-hook #'my/org-set-tabularx)
;; LaTeX table export: tabular → tabularx{\linewidth}
;; Filter on rendered LaTeX string — no buffer modification, no recursion.
;; Handles both cases:
;; \begin{tabular}{lll} → \begin{tabularx}{\linewidth}{lll}
;; \begin{tabularx}{lll} → \begin{tabularx}{\linewidth}{lll} (missing width)
(defun my/org-latex-fix-tabularx (table _backend _info)
"Convert tabular → tabularx{\\linewidth} in LaTeX table transcoder output."
(when (stringp table)
;; Fix tabularx with missing width (org versions that don't add \linewidth)
(setq table
(replace-regexp-in-string
"\\\\begin{tabularx}{\\([^\\\\][^}]*\\)}"
"\\\\begin{tabularx}{\\\\linewidth}{\\1}"
table))
;; Convert plain tabular to tabularx
(setq table
(replace-regexp-in-string
"\\\\begin{tabular}{\\([^}]*\\)}"
"\\\\begin{tabularx}{\\\\linewidth}{\\1}"
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
;; (belt+suspenders: whichever fires first wins, both are idempotent).
(with-eval-after-load 'ox-latex
(add-to-list 'org-export-filter-table-functions #'my/org-latex-fix-tabularx)
(add-to-list 'org-latex-packages-alist '("" "tabularx")))
(defun my/org-ensure-tabularx-filter (backend)
"Force ox-latex load and register tabularx filter before LaTeX export."
(when (org-export-derived-backend-p backend 'latex)
(require 'ox-latex)
(add-to-list 'org-export-filter-table-functions #'my/org-latex-fix-tabularx)
(add-to-list 'org-latex-packages-alist '("" "tabularx"))))
(add-hook 'org-export-before-processing-hook #'my/org-ensure-tabularx-filter)
;; Optional: enable booktabs style (horizontal rules in tables)
;; (setq org-latex-tables-booktabs t)