Browse Source

org-e-latex: Change tables attributes and implement matrix support

* contrib/lisp/org-e-latex.el (org-e-latex-table-matrix-macros,
  org-e-latex-default-table-mode): New variables.
(org-e-latex-tables-verbatim): Removed variable.
(org-e-latex-tables-booktabs): Update docstring.
(org-e-latex--align-string, org-e-latex--org-table,
org-e-latex--table.el-table): Rename functions from, respectively
`org-e-latex-table--align-string', `org-e-latex-table--org-table' and
`org-e-latex-table--table.el-table'.  Use new attributes.
(org-e-latex-table,org-e-latex-table-row): Use new attributes.
(org-e-latex--math-table): New function.
Nicolas Goaziou 13 years ago
parent
commit
82c88878bc
1 changed files with 225 additions and 121 deletions
  1. 225 121
      contrib/lisp/org-e-latex.el

+ 225 - 121
contrib/lisp/org-e-latex.el

@@ -22,16 +22,54 @@
 ;;
 ;;
 ;; This library implements a LaTeX back-end for Org generic exporter.
 ;; This library implements a LaTeX back-end for Org generic exporter.
 ;;
 ;;
-;; To test it, run
+;; Depending on the desired output format, three commands are provided
+;; for export: `org-e-latex-export-as-latex' (temporary buffer),
+;; `org-e-latex-export-to-latex' ("tex" file) and
+;; `org-e-latex-export-to-pdf' ("pdf" file).  Also, two publishing
+;; functions are available: `org-e-latex-publish-to-latex' and
+;; `org-e-latex-publish-to-pdf'.
 ;;
 ;;
-;;   M-: (org-export-to-buffer 'e-latex "*Test e-LaTeX*") RET
+;; The library introduces three new buffer keywords: "LATEX_CLASS",
+;; "LATEX_CLASS_OPTIONS" and "LATEX_HEADER".
 ;;
 ;;
-;; in an org-mode buffer then switch to the buffer to see the LaTeX
-;; export.  See contrib/lisp/org-export.el for more details on how
-;; this exporter works.
+;; Table export can be controlled with a number of attributes (through
+;; ATTR_LATEX keyword).
 ;;
 ;;
-;; It introduces three new buffer keywords: "LATEX_CLASS",
-;; "LATEX_CLASS_OPTIONS" and "LATEX_HEADER".
+;; - The main one is the `:mode' attribute, which can be set to
+;;   `table', `math', `inline-math' and `verbatim'.  In particular,
+;;   when in `math' or `inline-math' mode, every cell is exported
+;;   as-is and the table will be wrapped in a math environment.  Also,
+;;   horizontal rules are ignored.  These modes are particularly
+;;   useful to write matrices.  Default mode is stored in
+;;   `org-e-latex-default-table-mode'.
+;;
+;; - The second most important attribute is `:environment'.  It is the
+;;   environment used for the table and defaults to
+;;   `org-e-latex-default-table-environment' value.  It can be set to
+;;   anything, including "tabularx", "longtable", "array",
+;;   "bmatrix"...
+;;
+;; - `:float' attribute defines a float environment for the table.
+;;   Possible values are `sidewaystable', `multicolumn' and `table'.
+;;
+;; - `:width' and `:align' attributes set, respectively, the width of
+;;   the table and its alignment string.
+;;
+;; - `:booktabs', `:center' and `:rmlines' values are booleans.  They
+;;   toggle, respectively "booktabs" usage (assuming the package is
+;;   properly loaded), table centering and removal of every horizontal
+;;   rule but the first one (in a "table.el" table only).
+;;
+;; - `:math-prefix', `:math-suffix' and `:math-arguments' are string
+;;   which will be inserted, respectively, before the table within the
+;;   math environment, after the table within the math environment,
+;;   and between the macro name and the contents of the table.  The
+;;   latter attribute is necessary to matrix macros that require more
+;;   than one argument (i.e. "qbordermatrix").
+;;
+;; This back-end also offers enhanced support for footnotes.  Thus, it
+;; handles nested footnotes, footnotes in tables and footnotes in item
+;; descriptions.
 
 
 ;;; Code:
 ;;; Code:
 
 
@@ -164,6 +202,11 @@
     ("uk" . "ukrainian"))
     ("uk" . "ukrainian"))
   "Alist between language code and corresponding Babel option.")
   "Alist between language code and corresponding Babel option.")
 
 
+(defconst org-e-latex-table-matrix-macros '(("bordermatrix" . "\\cr")
+					    ("qbordermatrix" . "\\cr")
+					    ("kbordermatrix" . "\\\\"))
+  "Alist between matrix macros and their row ending.")
+
 
 
 
 
 ;;; User Configurable Variables
 ;;; User Configurable Variables
@@ -436,13 +479,36 @@ default we use here encompasses both."
   :group 'org-export-e-latex
   :group 'org-export-e-latex
   :type 'string)
   :type 'string)
 
 
-(defcustom org-e-latex-tables-centered t
-  "When non-nil, tables are exported in a center environment."
+(defcustom org-e-latex-default-table-mode 'table
+  "Default mode for tables.
+
+Value can be a symbol among:
+
+  `table' Regular LaTeX table.
+
+  `math' In this mode, every cell is considered as being in math
+     mode and the complete table will be wrapped within a math
+     environment.  It is particularly useful to write matrices.
+
+  `inline-math' This mode is almost the same as `math', but the
+     math environment will be inlined.
+
+  `verbatim' The table is exported as it appears in the Org
+     buffer, within a verbatim environment.
+
+This value can be overridden locally with, i.e. \":mode math\" in
+LaTeX attributes.
+
+When modifying this variable, it may be useful to change
+`org-e-latex-default-table-environment' accordingly."
   :group 'org-export-e-latex
   :group 'org-export-e-latex
-  :type 'boolean)
+  :type '(choice (const :tag "Table" table)
+		 (const :tag "Matrix" math)
+		 (const :tag "Inline matrix" inline-math)
+		 (const :tag "Verbatim" verbatim)))
 
 
-(defcustom org-e-latex-tables-verbatim nil
-  "When non-nil, tables are exported verbatim."
+(defcustom org-e-latex-tables-centered t
+  "When non-nil, tables are exported in a center environment."
   :group 'org-export-e-latex
   :group 'org-export-e-latex
   :type 'boolean)
   :type 'boolean)
 
 
@@ -450,7 +516,7 @@ default we use here encompasses both."
   "When non-nil, display tables in a formal \"booktabs\" style.
   "When non-nil, display tables in a formal \"booktabs\" style.
 This option assumes that the \"booktabs\" package is properly
 This option assumes that the \"booktabs\" package is properly
 loaded in the header of the document.  This value can be ignored
 loaded in the header of the document.  This value can be ignored
-locally with \"booktabs=yes\" and \"booktabs=no\" LaTeX
+locally with \":booktabs t\" and \":booktabs nil\" LaTeX
 attributes."
 attributes."
   :group 'org-export-e-latex
   :group 'org-export-e-latex
   :type 'boolean)
   :type 'boolean)
@@ -2184,48 +2250,45 @@ contextual information."
 ;;;; Table
 ;;;; Table
 ;;
 ;;
 ;; `org-e-latex-table' is the entry point for table transcoding.  It
 ;; `org-e-latex-table' is the entry point for table transcoding.  It
-;; takes care of tables with a "verbatim" attribute.  Otherwise, it
-;; delegates the job to either `org-e-latex-table--table.el-table' or
-;; `org-e-latex-table--org-table' functions, depending of the type of
-;; the table.
+;; takes care of tables with a "verbatim" mode.  Otherwise, it
+;; delegates the job to either `org-e-latex--table.el-table',
+;; `org-e-latex--org-table' or `org-e-latex--math-table' functions,
+;; depending of the type of the table and the mode requested.
 ;;
 ;;
-;; `org-e-latex-table--align-string' is a subroutine used to build
-;; alignment string for Org tables.
+;; `org-e-latex--align-string' is a subroutine used to build alignment
+;; string for Org tables.
 
 
 (defun org-e-latex-table (table contents info)
 (defun org-e-latex-table (table contents info)
   "Transcode a TABLE element from Org to LaTeX.
   "Transcode a TABLE element from Org to LaTeX.
 CONTENTS is the contents of the table.  INFO is a plist holding
 CONTENTS is the contents of the table.  INFO is a plist holding
 contextual information."
 contextual information."
-  (cond
-   ;; Case 1: verbatim table.
-   ((or org-e-latex-tables-verbatim
-	(let ((attr (mapconcat 'identity
-			       (org-element-property :attr_latex table)
-			       " ")))
-	  (and attr (string-match "\\<verbatim\\>" attr))))
-    (format "\\begin{verbatim}\n%s\n\\end{verbatim}"
-	    ;; Re-create table, without affiliated keywords.
-	    (org-trim
-	     (org-element-interpret-data
-	      `(table nil ,@(org-element-contents table))))))
-   ;; Case 2: table.el table.  Convert it using appropriate tools.
-   ((eq (org-element-property :type table) 'table.el)
-    (org-e-latex-table--table.el-table table contents info))
-   ;; Case 3: Standard table.
-   (t (concat (org-e-latex-table--org-table table contents info)
-	      ;; When there are footnote references within the table,
-	      ;; insert they definitions just after it.
-	      (org-e-latex--delayed-footnotes-definitions table info)))))
-
-(defun org-e-latex-table--align-string (table info)
+  (if (eq (org-element-property :type table) 'table.el)
+      ;; "table.el" table.  Convert it using appropriate tools.
+      (org-e-latex--table.el-table table info)
+    (let ((type (or (org-export-read-attribute :attr_latex table :mode)
+		    org-e-latex-default-table-mode)))
+      (cond
+       ;; Case 1: Verbatim table.
+       ((string= type "verbatim")
+	(format "\\begin{verbatim}\n%s\n\\end{verbatim}"
+		;; Re-create table, without affiliated keywords.
+		(org-trim (org-element-interpret-data
+			   `(table nil ,@(org-element-contents table))))))
+       ;; Case 2: Matrix.
+       ((or (string= type "math") (string= type "inline-math"))
+	(org-e-latex--math-table table info))
+       ;; Case 3: Standard table.
+       (t (concat (org-e-latex--org-table table contents info)
+		  ;; When there are footnote references within the
+		  ;; table, insert their definition just after it.
+		  (org-e-latex--delayed-footnotes-definitions table info)))))))
+
+(defun org-e-latex--align-string (table info)
   "Return an appropriate LaTeX alignment string.
   "Return an appropriate LaTeX alignment string.
 TABLE is the considered table.  INFO is a plist used as
 TABLE is the considered table.  INFO is a plist used as
 a communication channel."
 a communication channel."
-  (let ((attr (mapconcat 'identity
-			 (org-element-property :attr_latex table)
-			 " ")))
-    (if (string-match "\\<align=\\(\\S-+\\)" attr) (match-string 1 attr)
-      (let (alignment)
+  (or (org-export-read-attribute :attr_latex table :align)
+      (let (align)
 	;; Extract column groups and alignment from first (non-rule)
 	;; Extract column groups and alignment from first (non-rule)
 	;; row.
 	;; row.
 	(org-element-map
 	(org-element-map
@@ -2238,96 +2301,89 @@ a communication channel."
 	 (lambda (cell)
 	 (lambda (cell)
 	   (let ((borders (org-export-table-cell-borders cell info)))
 	   (let ((borders (org-export-table-cell-borders cell info)))
 	     ;; Check left border for the first cell only.
 	     ;; Check left border for the first cell only.
-	     (when (and (memq 'left borders) (not alignment))
-	       (push "|" alignment))
+	     (when (and (memq 'left borders) (not align))
+	       (push "|" align))
 	     (push (case (org-export-table-cell-alignment cell info)
 	     (push (case (org-export-table-cell-alignment cell info)
 		     (left "l")
 		     (left "l")
 		     (right "r")
 		     (right "r")
 		     (center "c"))
 		     (center "c"))
-		   alignment)
-	     (when (memq 'right borders) (push "|" alignment))))
+		   align)
+	     (when (memq 'right borders) (push "|" align))))
 	 info)
 	 info)
-	(apply 'concat (reverse alignment))))))
+	(apply 'concat (nreverse align)))))
 
 
-(defun org-e-latex-table--org-table (table contents info)
+(defun org-e-latex--org-table (table contents info)
   "Return appropriate LaTeX code for an Org table.
   "Return appropriate LaTeX code for an Org table.
 
 
 TABLE is the table type element to transcode.  CONTENTS is its
 TABLE is the table type element to transcode.  CONTENTS is its
 contents, as a string.  INFO is a plist used as a communication
 contents, as a string.  INFO is a plist used as a communication
 channel.
 channel.
 
 
-This function assumes TABLE has `org' as its `:type' attribute."
-  (let* ((label (org-element-property :name table))
-	 (caption (org-e-latex--caption/label-string table info))
-	 (attr (mapconcat 'identity
-			  (org-element-property :attr_latex table)
-			  " "))
+This function assumes TABLE has `org' as its `:type' property and
+`table' as its `:mode' attribute."
+  (let* ((caption (org-e-latex--caption/label-string table info))
+	 (attr (org-export-read-attribute :attr_latex table))
 	 ;; Determine alignment string.
 	 ;; Determine alignment string.
-	 (alignment (org-e-latex-table--align-string table info))
+	 (alignment (org-e-latex--align-string table info))
 	 ;; Determine environment for the table: longtable, tabular...
 	 ;; Determine environment for the table: longtable, tabular...
-	 (table-env (cond
-		     ((not attr) org-e-latex-default-table-environment)
-		     ((string-match "\\<longtable\\>" attr) "longtable")
-		     ((string-match "\\<tabular.?\\>" attr)
-		      (org-match-string-no-properties 0 attr))
-		     (t org-e-latex-default-table-environment)))
+	 (table-env (let ((env (plist-get attr :environment)))
+		      (if env (format "%s" env)
+			org-e-latex-default-table-environment)))
 	 ;; If table is a float, determine environment: table, table*
 	 ;; If table is a float, determine environment: table, table*
 	 ;; or sidewaystable.
 	 ;; or sidewaystable.
-	 (float-env (cond
-		     ((string= "longtable" table-env) nil)
-		     ((and attr (string-match "\\<sidewaystable\\>" attr))
-		      "sidewaystable")
-		     ((and attr
-			   (or (string-match (regexp-quote "table*") attr)
-			       (string-match "\\<multicolumn\\>" attr)))
-		      "table*")
-		     ((or (not (string= caption "")) label) "table")))
+	 (float-env (unless (equal "longtable" table-env)
+		      (let ((float (plist-get attr :float)))
+			(cond
+			 ((string= float "sidewaystable") "sidewaystable")
+			 ((string= float "multicolumn") "table*")
+			 ((or (string= float "table")
+			      (org-element-property :caption table))
+			  "table")))))
 	 ;; Extract others display options.
 	 ;; Extract others display options.
-	 (width (and attr (string-match "\\<width=\\(\\S-+\\)" attr)
-		     (org-match-string-no-properties 1 attr)))
-	 (placement
-	  (if (and attr (string-match "\\<placement=\\(\\S-+\\)" attr))
-	      (org-match-string-no-properties 1 attr)
-	    (format "[%s]" org-e-latex-default-figure-position))))
+	 (width (plist-get attr :width))
+	 (placement (or (plist-get attr :placement)
+			(format "[%s]" org-e-latex-default-figure-position)))
+	 (centerp (if (plist-member attr :center) (plist-get attr :center)
+		    org-e-latex-tables-centered)))
     ;; Prepare the final format string for the table.
     ;; Prepare the final format string for the table.
     (cond
     (cond
      ;; Longtable.
      ;; Longtable.
-     ((string= "longtable" table-env)
+     ((equal "longtable" table-env)
       (format
       (format
        "\\begin{longtable}{%s}\n%s%s%s\\end{longtable}"
        "\\begin{longtable}{%s}\n%s%s%s\\end{longtable}"
        alignment
        alignment
        (if (or (not org-e-latex-table-caption-above) (string= "" caption)) ""
        (if (or (not org-e-latex-table-caption-above) (string= "" caption)) ""
-	 (concat (org-trim caption) "\\\\\n"))
+	 (concat caption "\\\\\n"))
        contents
        contents
        (if (or org-e-latex-table-caption-above (string= "" caption)) ""
        (if (or org-e-latex-table-caption-above (string= "" caption)) ""
-	 (concat (org-trim caption) "\\\\\n"))))
+	 (concat caption "\\\\\n"))))
      ;; Others.
      ;; Others.
-     (t (concat (if float-env
-		    (concat
-		     (format "\\begin{%s}%s\n" float-env placement)
-		     (if org-e-latex-table-caption-above caption "")
-		     (when org-e-latex-tables-centered "\\centering\n"))
-		  (when org-e-latex-tables-centered "\\begin{center}\n"))
+     (t (concat (cond
+		 (float-env
+		  (concat (format "\\begin{%s}%s\n" float-env placement)
+			  (if org-e-latex-table-caption-above caption "")
+			  (when centerp "\\centering\n")))
+		 (centerp "\\begin{center}\n"))
 		(format "\\begin{%s}%s{%s}\n%s\\end{%s}"
 		(format "\\begin{%s}%s{%s}\n%s\\end{%s}"
 			table-env
 			table-env
 			(if width (format "{%s}" width) "")
 			(if width (format "{%s}" width) "")
 			alignment
 			alignment
 			contents
 			contents
 			table-env)
 			table-env)
-		(if float-env
-		    (concat (if org-e-latex-table-caption-above "" caption)
-			    (format "\n\\end{%s}" float-env))
-		  (when org-e-latex-tables-centered "\n\\end{center}")))))))
+		(cond
+		 (float-env
+		  (concat (if org-e-latex-table-caption-above "" caption)
+			  (format "\n\\end{%s}" float-env)))
+		 (centerp "\n\\end{center}")))))))
 
 
-(defun org-e-latex-table--table.el-table (table contents info)
+(defun org-e-latex--table.el-table (table info)
   "Return appropriate LaTeX code for a table.el table.
   "Return appropriate LaTeX code for a table.el table.
 
 
-TABLE is the table type element to transcode.  CONTENTS is its
-contents, as a string.  INFO is a plist used as a communication
-channel.
+TABLE is the table type element to transcode.  INFO is a plist
+used as a communication channel.
 
 
 This function assumes TABLE has `table.el' as its `:type'
 This function assumes TABLE has `table.el' as its `:type'
-attribute."
+property."
   (require 'table)
   (require 'table)
   ;; Ensure "*org-export-table*" buffer is empty.
   ;; Ensure "*org-export-table*" buffer is empty.
   (with-current-buffer (get-buffer-create "*org-export-table*")
   (with-current-buffer (get-buffer-create "*org-export-table*")
@@ -2345,18 +2401,67 @@ attribute."
       (setq output (replace-match "" t t output)))
       (setq output (replace-match "" t t output)))
     ;; When the "rmlines" attribute is provided, remove all hlines but
     ;; When the "rmlines" attribute is provided, remove all hlines but
     ;; the the one separating heading from the table body.
     ;; the the one separating heading from the table body.
-    (let ((attr (mapconcat 'identity
-			   (org-element-property :attr_latex table)
-			   " ")))
-      (when (and attr (string-match "\\<rmlines\\>" attr))
-	(let ((n 0) (pos 0))
-	  (while (and (< (length output) pos)
-		      (setq pos (string-match "^\\\\hline\n?" output pos)))
-	    (incf n)
-	    (unless (= n 2)
-	      (setq output (replace-match "" nil nil output)))))))
-    (if (not org-e-latex-tables-centered) output
-      (format "\\begin{center}\n%s\n\\end{center}" output))))
+    (when (org-export-read-attribute :attr_latex table :rmlines)
+      (let ((n 0) (pos 0))
+	(while (and (< (length output) pos)
+		    (setq pos (string-match "^\\\\hline\n?" output pos)))
+	  (incf n)
+	  (unless (= n 2) (setq output (replace-match "" nil nil output))))))
+    (let ((centerp (if (plist-member attr :center) (plist-get attr :center)
+		     org-e-latex-tables-centered)))
+      (if (not centerp) output
+	(format "\\begin{center}\n%s\n\\end{center}" output)))))
+
+(defun org-e-latex--math-table (table info)
+  "Return appropriate LaTeX code for a matrix.
+
+TABLE is the table type element to transcode.  INFO is a plist
+used as a communication channel.
+
+This function assumes TABLE has `org' as its `:type' property and
+`inline-math' or `math' as its `:mode' attribute.."
+  (let* ((caption (org-e-latex--caption/label-string table info))
+	 (attr (org-export-read-attribute :attr_latex table))
+	 (inlinep (eq (plist-get attr :mode) 'inline-math))
+	 (env (let ((env (plist-get attr :environment)))
+		(if env (format "%s" env)
+		  org-e-latex-default-table-environment)))
+	 (contents
+	  (mapconcat
+	   (lambda (row)
+	     ;; Ignore horizontal rules.
+	     (when (eq (org-element-property :type row) 'standard)
+	       ;; Return each cell unmodified.
+	       (concat
+		(mapconcat
+		 (lambda (cell)
+		   (substring (org-element-interpret-data cell) 0 -1))
+		 (org-element-map row 'table-cell 'identity info) "&")
+		(or (cdr (assoc env org-e-latex-table-matrix-macros)) "\\\\")
+		"\n")))
+	   (org-element-map table 'table-row 'identity info) "")))
+    (concat
+     ;; Opening string.
+     (cond (inlinep "\\(")
+	   ((org-string-nw-p caption) (concat "\\begin{equation}\n" caption))
+	   (t "\\["))
+     ;; Prefix (make sure it is a string).
+     (format "%s" (or (plist-get attr :math-prefix) ""))
+     ;; Environment.  Also treat special cases.
+     (cond ((equal env "array")
+	    (let ((align (org-e-latex--align-string table info)))
+	      (format "\\begin{array}{%s}\n%s\\end{array}" align contents)))
+	   ((assoc env org-e-latex-table-matrix-macros)
+	    (format "\\%s%s{\n%s}" env
+		    (format "%s" (or (plist-get attr :math-arguments) ""))
+		    contents))
+	   (t (format "\\begin{%s}\n%s\\end{%s}" env contents env)))
+     ;; Suffix (make sure it is a string).
+     (format "%s" (or (plist-get attr :math-suffix) ""))
+     ;; Closing string.
+     (cond (inlinep "\\)")
+	   ((org-string-nw-p caption) "\\end{equation}")
+	   (t "\\]")))))
 
 
 
 
 ;;;; Table Cell
 ;;;; Table Cell
@@ -2386,18 +2491,17 @@ a communication channel."
   ;; Rules are ignored since table separators are deduced from
   ;; Rules are ignored since table separators are deduced from
   ;; borders of the current row.
   ;; borders of the current row.
   (when (eq (org-element-property :type table-row) 'standard)
   (when (eq (org-element-property :type table-row) 'standard)
-    (let* ((attr (mapconcat 'identity
-			    (org-element-property
-			     :attr_latex (org-export-get-parent table-row))
-			    " "))
-	   (longtablep (and attr (string-match "\\<longtable\\>" attr)))
-	   (booktabsp
-	    (or (and attr (string-match "\\<booktabs=\\(yes\\|t\\)\\>" attr))
-		org-e-latex-tables-booktabs))
+    (let* ((attr (org-export-read-attribute :attr_latex
+					    (org-export-get-parent table-row)))
+	   (longtablep (string= (or (plist-get attr :environment)
+				    org-e-latex-default-table-environment)
+				"longtable"))
+	   (booktabsp (if (plist-member attr :booktabs)
+			  (plist-get attr :booktabs)
+			org-e-latex-tables-booktabs))
 	   ;; TABLE-ROW's borders are extracted from its first cell.
 	   ;; TABLE-ROW's borders are extracted from its first cell.
-	   (borders
-	    (org-export-table-cell-borders
-	     (car (org-element-contents table-row)) info)))
+	   (borders (org-export-table-cell-borders
+		     (car (org-element-contents table-row)) info)))
       (concat
       (concat
        ;; When BOOKTABS are activated enforce top-rule even when no
        ;; When BOOKTABS are activated enforce top-rule even when no
        ;; hline was specifically marked.
        ;; hline was specifically marked.