From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id wAonIvYHQWOPzAAAbAwnHQ (envelope-from ) for ; Sat, 08 Oct 2022 07:17:42 +0200 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id UCFPIfYHQWNvtAAAG6o9tA (envelope-from ) for ; Sat, 08 Oct 2022 07:17:42 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 5369D10022 for ; Sat, 8 Oct 2022 07:17:41 +0200 (CEST) Received: from localhost ([::1]:53710 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oh2DU-00013r-GF for larch@yhetil.org; Sat, 08 Oct 2022 01:17:40 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:37858) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oh2CW-00013b-CL for emacs-orgmode@gnu.org; Sat, 08 Oct 2022 01:16:40 -0400 Received: from mail-pg1-x52d.google.com ([2607:f8b0:4864:20::52d]:42903) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1oh2CU-0002Jw-7F for emacs-orgmode@gnu.org; Sat, 08 Oct 2022 01:16:40 -0400 Received: by mail-pg1-x52d.google.com with SMTP id e129so6269820pgc.9 for ; Fri, 07 Oct 2022 22:16:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to; bh=+A1G+yO/fQWpsFeqegObHyLGTTBiB+dV65Nuna11FI0=; b=U2R+JVeQ+zySuFutI54MNIhBCC55Lzudw/PN2Lt47wJGgXGyM7z22OoYKzonxtnJiz qf9aYZMHyTUpkL7D0zHuIl8w9H01L0snjVSY68PjF73pH5FdALclt3FJtYg4ybWITIQ4 gGEGtyAT2fKloGZ/IA0dG48xpSA0FZJ/r4g9xH5gH1Xkv2qqeLWpiWfwWQatNfubhW/j E8c4btE8K/lrdHu0zTkpyRYCIoavEOzkD5IOZm6XnrzK+qj6HEb7XqwkcolsDWIIXvHK N2z9z0NP+g7kGztDzbMgV3ucaKCyIuRI6IlYxWNnQMrXAFc+T2oVwws+yeaHR2mZ843M 1YEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=+A1G+yO/fQWpsFeqegObHyLGTTBiB+dV65Nuna11FI0=; b=TTAejhWX17gNKsuLxZ5YvR6pL/4gkHkERtbyRxhWbrV2NiCpLJu6gJf2bqyn+ilN4F bvNNTjXUm16ke5F6wgd4rXwBPz8rkFxZTImZb8ApNJMlHNpK4+lt79D1Q2bKYRmol3j4 ovAf3hiJ8Tp0ikyuidgs47OOWV7Rq3mgKjjgcE72VvjX4aq3+6y8PQ68khtc21COQFA3 BWCpGalTZmzUHm7pJoQUlxl1+RVkZqemAl1xqkIq8siXs1gr1q9cRNEqhWoVr9XCyq0N v0cC7K6k5aWUer27enzVVsb5pgV29x4MI3t7OJ1fPQpD4NDINTyCy+iN0SNT4XOEt4Ln lYsw== X-Gm-Message-State: ACrzQf1cP4U3ioO8JdGtIUPdKOjLTvQc70i08fSvcJGCZkH2b+nSJptV AuefiJWUxywBfNFPrUu8wpGhxxGDzQyNvA== X-Google-Smtp-Source: AMsMyM7CkxwzIg1xwZSmz4oldcy9rPbIoiQPqGeB10BxxzCh/MsdVWBqn3u2tQl8y4+HEdy2SwnDrQ== X-Received: by 2002:a05:6a00:230f:b0:53e:2c2c:5c03 with SMTP id h15-20020a056a00230f00b0053e2c2c5c03mr8772266pfh.11.1665206196639; Fri, 07 Oct 2022 22:16:36 -0700 (PDT) Received: from localhost ([1.83.155.53]) by smtp.gmail.com with ESMTPSA id n1-20020a17090a2bc100b0020a0571b354sm2320300pje.57.2022.10.07.22.16.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 07 Oct 2022 22:16:35 -0700 (PDT) From: Ihor Radchenko To: Max Nikulin Cc: emacs-orgmode@gnu.org Subject: [PATCH v2] Re: [BUG] Tables with square brackets do not compile in PDF (latex) export [9.5 (release_9.5-59-g52e6f1 @ /home/sjt015/repo/emacs/lisp/org/)] In-Reply-To: References: <8735c0kpb9.fsf@localhost> Date: Sat, 08 Oct 2022 13:17:18 +0800 Message-ID: <87lepqlwrl.fsf@localhost> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Received-SPF: pass client-ip=2607:f8b0:4864:20::52d; envelope-from=yantar92@gmail.com; helo=mail-pg1-x52d.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Migadu-Flow: FLOW_IN X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1665206261; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=+A1G+yO/fQWpsFeqegObHyLGTTBiB+dV65Nuna11FI0=; b=TkUrn+zd0XR0Z+wPlUr4x4loaOoJyne+jKZ6Pw7Gc5MAvSblYxn4TyxbfcjEC0ZYb9SbI9 YuFDw3/kOlPjC/67pSvd4gip8bfBiS0pOJEUxb8vjoBokgSYMSimh3cYUPQsvbg5+d/Q4T ioAMFYIAQCYYau0tDg+KYzYulnfI9SySh/fkb1fBBQH27sMEt/zdT6/1UFQumcmnUYmKyY 3UOdJ0uxR8N5Z0m76jwKicbywDZth3EZN0Dh/EuPvNqWLHVX70S+StZj7fK9hD+G3C7pT9 4B0ffjlIVfZH/mjyyoK3Bco6keYh/MfUIZhh7cjsWpgeK1q9xwoe4MNId+bgOg== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1665206261; a=rsa-sha256; cv=none; b=L2r6KxdGhU+MWk3KTy8QxqAAirxdvuZImfBg/E4I5zWm24hKzT7f6FmMs5zgUlG8oNbYqk KOOBTz2ZN44lvRqkYwVPNtAIAGGJ6CcRZnxE4BSHcagxoQxjcJujEIuWijyCWC9S/JisN8 nLlZ1lScEUAYYGNPqEmtJLgD0qGAvDUemLtNPdH9hqxjWv3nKRzsG/i1SrDKFpYXjx1Tp1 Uzj/zAW3TaUnDKcXbumpOi6fiyPqf9YazEU4MRfHtQZrtHECI+G33arXW0UxxuA4EaOLHo 2H72n7VGfXBcjg9AtNk6O2XImihEYzefopST38wl5xaafVAJY/5fCGsHopYEFw== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=U2R+JVeQ; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -3.38 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20210112 header.b=U2R+JVeQ; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: 5369D10022 X-Spam-Score: -3.38 X-Migadu-Scanner: scn1.migadu.com X-TUID: GqIn/hlb8+RJ --=-=-= Content-Type: text/plain Max Nikulin writes: >> +(defconst org-latex-linebreak-safe "\\\\\\relax" > > Is there a reason why you did not add \n at the end? It could help to > avoid a lot of `concat' calls. Mostly because there are a couple of places where we need the version without newline. I though that `concat' is better than `replace-regexp-in-string' or introducing two constants with/without newline. I guess, we can introduce the two constants. It might be slightly more optimal. See the updated version of the patch. >> - (equal "\\begin{tabular}{l}\n\\(x\\)\\\\\n\\end{tabular}" >> + (equal "\\begin{tabular}{l}\n\\(x\\)\\\\\\relax\n\\end{tabular}" > > May be left as is since the line next to \\ does not start from square > brackets. Nope. It can't. These are ERT tests for the ox-latex output. --=-=-= Content-Type: text/x-patch Content-Disposition: inline; filename=v2-0001-ox-latex-Protect-.-after-to-be-interpreted-as-LaT.patch >From 14dceebeff73ff49e197f18b8235a40497bdbf55 Mon Sep 17 00:00:00 2001 Message-Id: <14dceebeff73ff49e197f18b8235a40497bdbf55.1665206183.git.yantar92@gmail.com> From: Ihor Radchenko Date: Fri, 7 Oct 2022 16:24:32 +0800 Subject: [PATCH v2] 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-linebreak-safe-newline): New constant holding `org-latex-linebreak-safe' with newline appended. (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 constants. * testing/lisp/test-org-table.el (test-org-table/to-latex): Update tests. Reported-by: Stewart Thomas Link: https://orgmode.org/list/ce760fc3-5aae-144d-2d02-7dea215f73fc@gmail.com --- lisp/ox-latex.el | 50 ++++++++++++++++++++++++---------- testing/lisp/test-org-table.el | 6 ++-- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/lisp/ox-latex.el b/lisp/ox-latex.el index 34ff52b81..d340b9c95 100644 --- a/lisp/ox-latex.el +++ b/lisp/ox-latex.el @@ -278,10 +278,26 @@ (defconst org-latex-language-alist - `:lang-name' the actual name of the language.") +(defconst org-latex-linebreak-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-linebreak-safe-newline (concat org-latex-linebreak-safe "\n") + "`org-latex-linebreak-safe' with newline.") + +(defconst org-latex-table-matrix-macros `(("bordermatrix" . "\\cr") ("qbordermatrix" . "\\cr") - ("kbordermatrix" . "\\\\")) + ("kbordermatrix" . ,org-latex-linebreak-safe)) "Alist between matrix macros and their row ending.") (defconst org-latex-math-environments-re @@ -2062,7 +2078,7 @@ (defun org-latex-clock (clock _contents info) (concat (org-timestamp-translate (org-element-property :value clock)) (let ((time (org-element-property :duration clock))) (and time (format " (%s)" time))))) - "\\\\")) + org-latex-linebreak-safe)) ;;;; Code @@ -2659,7 +2675,7 @@ ;;;; Line Break (defun org-latex-line-break (_line-break _contents _info) "Transcode a LINE-BREAK object from Org to LaTeX. CONTENTS is nil. INFO is a plist holding contextual information." - "\\\\\n") + org-latex-linebreak-safe-newline) ;;;; Link @@ -3005,7 +3021,9 @@ (defun org-latex-plain-text (text info) ;; Handle break preservation if required. (when (plist-get info :preserve-breaks) (setq output (replace-regexp-in-string - "\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" output nil t))) + "\\(?:[ \t]*\\\\\\\\\\)?[ \t]*\n" + org-latex-linebreak-safe-newline + output nil t))) ;; Return value. output)) @@ -3041,7 +3059,7 @@ (defun org-latex-planning (planning _contents info) (format (plist-get info :latex-active-timestamp-format) (org-timestamp-translate scheduled))))))) " ") - "\\\\")) + org-latex-linebreak-safe)) ;;;; Property Drawer @@ -3821,11 +3839,11 @@ (defun org-latex--org-table (table contents info) (format "\\begin{%s}%s{%s}\n" table-env width alignment) (and above? (org-string-nw-p caption) - (concat caption "\\\\\n")) + org-latex-linebreak-safe-newline) contents (and (not above?) (org-string-nw-p caption) - (concat caption "\\\\\n")) + org-latex-linebreak-safe-newline) (format "\\end{%s}" table-env) (and fontsize "}")))) (t @@ -3910,7 +3928,7 @@ (defun org-latex--math-table (table info) (lambda (cell) (substring (org-element-interpret-data cell) 0 -1)) (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-linebreak-safe) "\n"))) (org-element-map table 'table-row #'identity info) ""))) (concat @@ -3982,7 +4000,7 @@ (defun org-latex-table-row (table-row contents info) ;; hline was specifically marked. (and booktabsp (not (org-export-get-previous-element table-row info)) "\\toprule\n") - contents "\\\\\n" + contents org-latex-linebreak-safe-newline (cond ;; Special case for long tables. Define header and footers. ((and longtablep (org-export-table-row-ends-header-p table-row info)) @@ -3990,9 +4008,9 @@ (defun org-latex-table-row (table-row contents info) (org-export-get-parent-table table-row) info)))) (format "%s \\endfirsthead -\\multicolumn{%d}{l}{%s} \\\\ +\\multicolumn{%d}{l}{%s} \\\\\\relax %s -%s \\\\\n +%s \\\\\\relax\n %s \\endhead %s\\multicolumn{%d}{r}{%s} \\\\ @@ -4092,8 +4110,12 @@ (defun org-latex-verse-block (verse-block contents info) (replace-regexp-in-string "^[ \t]*\\\\\\\\$" "\\vspace*{1em}" (replace-regexp-in-string - "\\([ \t]*\\\\\\\\\\)?[ \t]*\n" "\\\\\n" - contents nil t) nil t) nil t) linreset) + "\\([ \t]*\\\\\\\\\\)?[ \t]*\n" + org-latex-linebreak-safe-newline + contents nil t) + nil t) + nil t) + linreset) info) ;; Insert footnote definitions, if any, after the environment, so ;; the special formatting above is not applied to them. diff --git a/testing/lisp/test-org-table.el b/testing/lisp/test-org-table.el index 76fe41630..3e7f18a10 100644 --- a/testing/lisp/test-org-table.el +++ b/testing/lisp/test-org-table.el @@ -1635,11 +1635,11 @@ (ert-deftest test-org-table/to-generic () (ert-deftest test-org-table/to-latex () "Test `orgtbl-to-latex' specifications." (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))) ;; Test :environment parameter. (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 |") '(:environment "tabularx")))) ;; Test :booktabs parameter. @@ -1648,7 +1648,7 @@ (ert-deftest test-org-table/to-latex () "\\toprule" (orgtbl-to-latex (org-table-to-lisp "| a |") '(:booktabs t)))) ;; Handle LaTeX snippets. (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))) ;; Test pseudo objects and :raw parameter. (should -- 2.35.1 --=-=-= Content-Type: text/plain -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at . Support Org development at , or support my work at --=-=-=--