From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
To: Org Mode List <emacs-orgmode@gnu.org>
Subject: [RFC] Rewrite radio tables
Date: Sun, 24 Aug 2014 21:25:57 +0200 [thread overview]
Message-ID: <8761hh6662.fsf@nicolasgoaziou.fr> (raw)
[-- Attachment #1: Type: text/plain, Size: 1298 bytes --]
Hello,
The following patch implements radio tables and `orgtbl-to-...'
functions using Org export engine. The implementation is probably not
totally backward compatible, though.
In particular, I suppressed :remove-nil-lines parameter, as I couldn't
make any sense out of it. If someone has a clear definition of its job,
and if that job is useful, I could implement it back.
Also, process does not dynamically bind `org-table-last-alignment' and
`org-table-last-column-widths' anymore. It should be possible to have
them back with some computations before starting the conversion, but,
unless they are vital, I'd rather not do it. `orgtbl-to-generic' is
tricky enough.
OTOH, I added :raw parameter, which allows to treat cells as strings and
not as Org syntax.
#+ORGTBL: SEND ... :raw nil
| *a* |
=>
...
\textbf{a}
...
#+ORGTBL: SEND ... :raw t
| *a* |
=>
...
*a*
...
I also added some specific parameters to translation functions,
e.g. :booktabs or :environment for `orgtbl-to-latex'. See docstring for
more information.
The patch comes with a test suite. However, it is no real use case.
Therefore, I'd appreciate some human testing before going further.
Feedback welcome.
Regards,
--
Nicolas Goaziou 0x80A93738
[-- Attachment #2: 0001-org-table-Use-ox.el-internally-for-radio-tables.patch --]
[-- Type: text/x-diff, Size: 60314 bytes --]
From ac278792f9b6472f02bdd14e5472428bde083ccf Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <mail@nicolasgoaziou.fr>
Date: Sun, 24 Aug 2014 01:31:56 +0200
Subject: [PATCH] org-table: Use "ox.el" internally for radio tables
* lisp/org-table.el (org-table-clean-before-export, orgtbl-get-fmt,
orgtbl-apply-fmt, orgtbl-eval-str, orgtbl-format-line,
orgtbl-format-section): Remove functions.
(org-table-clean-did-remove-column, *orgtbl-table*, *orgtbl-rtn*,
*orgtbl-hline*, *orgtbl-sep*, *orgtbl-default-fmt*, *orgtbl-fmt*,
*orgtbl-efmt*, *orgtbl-lfmt*, *orgtbl-llfmt*, *orgtbl-lstart*,
*orgtbl-llstart*, *orgtbl-lend*, *orgtbl-llend*): Remove variables.
(org-table-export, orgtbl-send-table): Apply function removal. Do not
set `org-table-last-alignment' and `org-table-last-column-widths'
anymore.
(org-table-to-lisp, orgtbl-send-replace-tbl): Small refactoring.
(org-table--to-generic-table, org-table--to-generic-row,
org-table--to-generic-cell): New functions.
(orgtbl-to-generic): Rewrite function. Handle :skip and :skipcols
parameters.
(orgtbl-to-latex, orgtbl-to-html, orgtbl-to-texinfo, orgtbl-to-orgtbl,
orgtbl-to-unicode): Use new `orgtbl-to-generic' features.
* testing/lisp/test-org-table.el (test-org-table/to-generic,
test-org-table/to-latex, test-org-table/to-texinfo,
test-org-table/to-html, test-org-table/to-unicode,
test-org-table/send-region): New tests.
---
lisp/org-table.el | 1037 +++++++++++++++++++++-------------------
testing/lisp/test-org-table.el | 351 ++++++++++++++
2 files changed, 909 insertions(+), 479 deletions(-)
diff --git a/lisp/org-table.el b/lisp/org-table.el
index 06a1008..61be7d2 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -40,7 +40,9 @@
(declare-function org-export-string-as "ox"
(string backend &optional body-only ext-plist))
-(declare-function aa2u "ext:ascii-art-to-unicode" ())
+(declare-function org-export-create-backend "ox")
+(declare-function org-export-get-backend "ox" (name))
+
(declare-function calc-eval "calc" (str &optional separator &rest args))
(defvar orgtbl-mode) ; defined below
@@ -442,40 +444,6 @@ available parameters."
(org-split-string (match-string 1 line)
"[ \t]*|[ \t]*")))))))
-(defvar org-table-clean-did-remove-column nil) ; dynamically scoped
-(defun org-table-clean-before-export (lines &optional maybe-quoted)
- "Check if the table has a marking column.
-If yes remove the column and the special lines."
- (let ((special (if maybe-quoted
- "^[ \t]*| *\\\\?[\#!$*_^/ ] *|"
- "^[ \t]*| *[\#!$*_^/ ] *|"))
- (ignore (if maybe-quoted
- "^[ \t]*| *\\\\?[!$_^/] *|"
- "^[ \t]*| *[!$_^/] *|")))
- (setq org-table-clean-did-remove-column
- (not (memq nil
- (mapcar
- (lambda (line)
- (or (string-match org-table-hline-regexp line)
- (string-match special line)))
- lines))))
- (delq nil
- (mapcar
- (lambda (line)
- (cond
- ((or (org-table-colgroup-line-p line) ;; colgroup info
- (org-table-cookie-line-p line) ;; formatting cookies
- (and org-table-clean-did-remove-column
- (string-match ignore line))) ;; non-exportable data
- nil)
- ((and org-table-clean-did-remove-column
- (or (string-match "^\\([ \t]*\\)|-+\\+" line)
- (string-match "^\\([ \t]*\\)|[^|]*|" line)))
- ;; remove the first column
- (replace-match "\\1|" t nil line))
- (t line)))
- lines))))
-
(defconst org-table-translate-regexp
(concat "\\(" "@[-0-9I$]+" "\\|" "[a-zA-Z]\\{1,2\\}\\([0-9]+\\|&\\)" "\\)")
"Match a reference that needs translation, for reference display.")
@@ -624,8 +592,6 @@ are found, lines will be split on whitespace into fields."
(org-table-convert-region beg (+ (point) (- (point-max) pm)) arg)))
-(defvar org-table-last-alignment)
-(defvar org-table-last-column-widths)
;;;###autoload
(defun org-table-export (&optional file format)
"Export table to a file, with configurable format.
@@ -643,77 +609,61 @@ extension of the given file name, and finally on the variable
`org-table-export-default-format'."
(interactive)
(unless (org-at-table-p) (user-error "No table at point"))
- (org-table-align) ;; make sure we have everything we need
- (let* ((beg (org-table-begin))
- (end (org-table-end))
- (txt (buffer-substring-no-properties beg end))
- (file (or file (org-entry-get beg "TABLE_EXPORT_FILE" t)))
- (formats '("orgtbl-to-tsv" "orgtbl-to-csv"
- "orgtbl-to-latex" "orgtbl-to-html"
- "orgtbl-to-generic" "orgtbl-to-texinfo"
- "orgtbl-to-orgtbl"))
- (format (or format
- (org-entry-get beg "TABLE_EXPORT_FORMAT" t)))
- buf deffmt-readable fileext)
+ (org-table-align) ; Make sure we have everything we need.
+ (let ((file (or file (org-entry-get (point) "TABLE_EXPORT_FILE" t))))
(unless file
(setq file (read-file-name "Export table to: "))
(unless (or (not (file-exists-p file))
(y-or-n-p (format "Overwrite file %s? " file)))
(user-error "File not written")))
- (if (file-directory-p file)
- (user-error "This is a directory path, not a file"))
- (if (and (buffer-file-name)
- (equal (file-truename file)
- (file-truename (buffer-file-name))))
- (user-error "Please specify a file name that is different from current"))
- (setq fileext (concat (file-name-extension file) "$"))
- (unless format
- (setq deffmt-readable
- (or (car (delq nil (mapcar (lambda(f) (if (string-match fileext f) f)) formats)))
- org-table-export-default-format))
- (while (string-match "\t" deffmt-readable)
- (setq deffmt-readable (replace-match "\\t" t t deffmt-readable)))
- (while (string-match "\n" deffmt-readable)
- (setq deffmt-readable (replace-match "\\n" t t deffmt-readable)))
- (setq format (org-completing-read "Format: " formats nil nil deffmt-readable)))
- (if (string-match "\\([^ \t\r\n]+\\)\\( +.*\\)?" format)
- (let* ((transform (intern (match-string 1 format)))
- (params (if (match-end 2)
- (read (concat "(" (match-string 2 format) ")"))))
- (skip (plist-get params :skip))
- (skipcols (plist-get params :skipcols))
- (lines (nthcdr (or skip 0) (org-split-string txt "[ \t]*\n[ \t]*")))
- (lines (org-table-clean-before-export lines))
- (i0 (if org-table-clean-did-remove-column 2 1))
- (table (mapcar
- (lambda (x)
- (if (string-match org-table-hline-regexp x)
- 'hline
- (org-remove-by-index
- (org-split-string (org-trim x) "\\s-*|\\s-*")
- skipcols i0)))
- lines))
- (fun (if (= i0 2) 'cdr 'identity))
- (org-table-last-alignment
- (org-remove-by-index (funcall fun org-table-last-alignment)
- skipcols i0))
- (org-table-last-column-widths
- (org-remove-by-index (funcall fun org-table-last-column-widths)
- skipcols i0)))
-
- (unless (fboundp transform)
- (user-error "No such transformation function %s" transform))
- (setq txt (funcall transform table params))
-
- (with-current-buffer (find-file-noselect file)
- (setq buf (current-buffer))
- (erase-buffer)
- (fundamental-mode)
- (insert txt "\n")
- (save-buffer))
- (kill-buffer buf)
- (message "Export done."))
- (user-error "TABLE_EXPORT_FORMAT invalid"))))
+ (when (file-directory-p file)
+ (user-error "This is a directory path, not a file"))
+ (when (and (buffer-file-name (buffer-base-buffer))
+ (file-equal-p
+ (file-truename file)
+ (file-truename (buffer-file-name (buffer-base-buffer)))))
+ (user-error "Please specify a file name that is different from current"))
+ (let ((fileext (concat (file-name-extension file) "$"))
+ (format (or format (org-entry-get (point) "TABLE_EXPORT_FORMAT" t))))
+ (unless format
+ (let* ((formats '("orgtbl-to-tsv" "orgtbl-to-csv" "orgtbl-to-latex"
+ "orgtbl-to-html" "orgtbl-to-generic"
+ "orgtbl-to-texinfo" "orgtbl-to-orgtbl"
+ "orgtbl-to-unicode"))
+ (deffmt-readable
+ (replace-regexp-in-string
+ "\t" "\\t"
+ (replace-regexp-in-string
+ "\n" "\\n"
+ (or (car (delq nil
+ (mapcar
+ (lambda (f)
+ (and (org-string-match-p fileext f) f))
+ formats)))
+ org-table-export-default-format)
+ t t) t t)))
+ (setq format
+ (org-completing-read
+ "Format: " formats nil nil deffmt-readable))))
+ (if (string-match "\\([^ \t\r\n]+\\)\\( +.*\\)?" format)
+ (let ((transform (intern (match-string 1 format)))
+ (params (and (match-end 2)
+ (read (concat "(" (match-string 2 format) ")"))))
+ (table (org-table-to-lisp
+ (buffer-substring-no-properties
+ (org-table-begin) (org-table-end)))))
+ (unless (fboundp transform)
+ (user-error "No such transformation function %s" transform))
+ (let (buf)
+ (with-current-buffer (find-file-noselect file)
+ (setq buf (current-buffer))
+ (erase-buffer)
+ (fundamental-mode)
+ (insert (funcall transform table params) "\n")
+ (save-buffer))
+ (kill-buffer buf))
+ (message "Export done."))
+ (user-error "TABLE_EXPORT_FORMAT invalid")))))
(defvar org-table-aligned-begin-marker (make-marker)
"Marker at the beginning of the table last aligned.
@@ -4499,15 +4449,12 @@ a radio table."
(unless (re-search-forward
(concat "BEGIN +RECEIVE +ORGTBL +" name "\\([ \t]\\|$\\)") nil t)
(user-error "Don't know where to insert translated table"))
- (goto-char (match-beginning 0))
- (beginning-of-line 2)
- (save-excursion
- (let ((beg (point)))
- (unless (re-search-forward
- (concat "END +RECEIVE +ORGTBL +" name) nil t)
- (user-error "Cannot find end of insertion region"))
- (beginning-of-line 1)
- (delete-region beg (point))))
+ (let ((beg (line-beginning-position 2)))
+ (unless (re-search-forward
+ (concat "END +RECEIVE +ORGTBL +" name) nil t)
+ (user-error "Cannot find end of insertion region"))
+ (beginning-of-line)
+ (delete-region beg (point)))
(insert txt "\n")))
;;;###autoload
@@ -4516,76 +4463,43 @@ a radio table."
The structure will be a list. Each item is either the symbol `hline'
for a horizontal separator line, or a list of field values as strings.
The table is taken from the parameter TXT, or from the buffer at point."
- (unless txt
- (unless (org-at-table-p)
- (user-error "No table at point")))
- (let* ((txt (or txt
- (buffer-substring-no-properties (org-table-begin)
- (org-table-end))))
- (lines (org-split-string txt "[ \t]*\n[ \t]*")))
-
- (mapcar
- (lambda (x)
- (if (string-match org-table-hline-regexp x)
- 'hline
- (org-split-string (org-trim x) "\\s-*|\\s-*")))
- lines)))
+ (unless (or txt (org-at-table-p)) (user-error "No table at point"))
+ (let ((txt (or txt
+ (buffer-substring-no-properties (org-table-begin)
+ (org-table-end)))))
+ (mapcar (lambda (x)
+ (if (string-match org-table-hline-regexp x) 'hline
+ (org-split-string (org-trim x) "\\s-*|\\s-*")))
+ (org-split-string txt "[ \t]*\n[ \t]*"))))
(defun orgtbl-send-table (&optional maybe)
- "Send a transformed version of this table to the receiver position.
-With argument MAYBE, fail quietly if no transformation is defined for
-this table."
+ "Send a transformed version of table at point to the receiver position.
+With argument MAYBE, fail quietly if no transformation is defined
+for this table."
(interactive)
(catch 'exit
(unless (org-at-table-p) (user-error "Not at a table"))
;; when non-interactive, we assume align has just happened.
(when (org-called-interactively-p 'any) (org-table-align))
(let ((dests (orgtbl-gather-send-defs))
- (txt (buffer-substring-no-properties (org-table-begin)
- (org-table-end)))
+ (table (org-table-to-lisp
+ (buffer-substring-no-properties (org-table-begin)
+ (org-table-end))))
(ntbl 0))
- (unless dests (if maybe (throw 'exit nil)
- (user-error "Don't know how to transform this table")))
+ (unless dests
+ (if maybe (throw 'exit nil)
+ (user-error "Don't know how to transform this table")))
(dolist (dest dests)
- (let* ((name (plist-get dest :name))
- (transform (plist-get dest :transform))
- (params (plist-get dest :params))
- (skip (plist-get params :skip))
- (skipcols (plist-get params :skipcols))
- (no-escape (plist-get params :no-escape))
- beg
- (lines (org-table-clean-before-export
- (nthcdr (or skip 0)
- (org-split-string txt "[ \t]*\n[ \t]*"))))
- (i0 (if org-table-clean-did-remove-column 2 1))
- (lines (if no-escape lines
- (mapcar (lambda(l) (replace-regexp-in-string
- "\\([&%#_^]\\)" "\\\\\\1{}" l)) lines)))
- (table (mapcar
- (lambda (x)
- (if (string-match org-table-hline-regexp x)
- 'hline
- (org-remove-by-index
- (org-split-string (org-trim x) "\\s-*|\\s-*")
- skipcols i0)))
- lines))
- (fun (if (= i0 2) 'cdr 'identity))
- (org-table-last-alignment
- (org-remove-by-index (funcall fun org-table-last-alignment)
- skipcols i0))
- (org-table-last-column-widths
- (org-remove-by-index (funcall fun org-table-last-column-widths)
- skipcols i0))
- (txt (if (fboundp transform)
- (funcall transform table params)
- (user-error "No such transformation function %s" transform))))
- (orgtbl-send-replace-tbl name txt))
- (setq ntbl (1+ ntbl)))
+ (let ((name (plist-get dest :name))
+ (transform (plist-get dest :transform))
+ (params (plist-get dest :params)))
+ (unless (fboundp transform)
+ (user-error "No such transformation function %s" transform))
+ (orgtbl-send-replace-tbl name (funcall transform table params)))
+ (incf ntbl))
(message "Table converted and installed at %d receiver location%s"
ntbl (if (> ntbl 1) "s" ""))
- (if (> ntbl 0)
- ntbl
- nil))))
+ (and (> ntbl 0) ntbl))))
(defun org-remove-by-index (list indices &optional i0)
"Remove the elements in LIST with indices in INDICES.
@@ -4635,330 +4549,489 @@ First element has index 0, or I0 if given."
(insert txt)
(goto-char pos)))
-;; Dynamically bound input and output for table formatting.
-(defvar *orgtbl-table* nil
- "Carries the current table through formatting routines.")
-(defvar *orgtbl-rtn* nil
- "Formatting routines push the output lines here.")
-;; Formatting parameters for the current table section.
-(defvar *orgtbl-hline* nil "Text used for horizontal lines.")
-(defvar *orgtbl-sep* nil "Text used as a column separator.")
-(defvar *orgtbl-default-fmt* nil "Default format for each entry.")
-(defvar *orgtbl-fmt* nil "Format for each entry.")
-(defvar *orgtbl-efmt* nil "Format for numbers.")
-(defvar *orgtbl-lfmt* nil "Format for an entire line, overrides fmt.")
-(defvar *orgtbl-llfmt* nil "Specializes lfmt for the last row.")
-(defvar *orgtbl-lstart* nil "Text starting a row.")
-(defvar *orgtbl-llstart* nil "Specializes lstart for the last row.")
-(defvar *orgtbl-lend* nil "Text ending a row.")
-(defvar *orgtbl-llend* nil "Specializes lend for the last row.")
-
-(defsubst orgtbl-get-fmt (fmt i)
- "Retrieve the format from FMT corresponding to the Ith column."
- (if (and (not (functionp fmt)) (consp fmt))
- (plist-get fmt i)
- fmt))
-
-(defsubst orgtbl-apply-fmt (fmt &rest args)
- "Apply format FMT to arguments ARGS.
-When FMT is nil, return the first argument from ARGS."
- (cond ((functionp fmt) (apply fmt args))
- (fmt (apply 'format fmt args))
- (args (car args))
- (t args)))
-
-(defsubst orgtbl-eval-str (str)
- "If STR is a function, evaluate it with no arguments."
- (if (functionp str)
- (funcall str)
- str))
-
-(defun orgtbl-format-line (line)
- "Format LINE as a table row."
- (if (eq line 'hline) (if *orgtbl-hline* (push *orgtbl-hline* *orgtbl-rtn*))
- (let* ((i 0)
- (line
- (mapcar
- (lambda (f)
- (setq i (1+ i))
- (let* ((efmt (orgtbl-get-fmt *orgtbl-efmt* i))
- (f (if (and efmt (string-match orgtbl-exp-regexp f))
- (orgtbl-apply-fmt efmt (match-string 1 f)
- (match-string 2 f))
- f)))
- (orgtbl-apply-fmt (or (orgtbl-get-fmt *orgtbl-fmt* i)
- *orgtbl-default-fmt*)
- f)))
- line)))
- (push (if *orgtbl-lfmt*
- (apply #'orgtbl-apply-fmt *orgtbl-lfmt* line)
- (concat (orgtbl-eval-str *orgtbl-lstart*)
- (mapconcat 'identity line *orgtbl-sep*)
- (orgtbl-eval-str *orgtbl-lend*)))
- *orgtbl-rtn*))))
-
-(defun orgtbl-format-section (section-stopper)
- "Format lines until the first occurrence of SECTION-STOPPER."
- (let (prevline)
- (progn
- (while (not (eq (car *orgtbl-table*) section-stopper))
- (if prevline (orgtbl-format-line prevline))
- (setq prevline (pop *orgtbl-table*)))
- (if prevline (let ((*orgtbl-lstart* *orgtbl-llstart*)
- (*orgtbl-lend* *orgtbl-llend*)
- (*orgtbl-lfmt* *orgtbl-llfmt*))
- (orgtbl-format-line prevline))))))
-
;;;###autoload
-(defun orgtbl-to-generic (table params &optional backend)
+(defun orgtbl-to-generic (table params)
"Convert the orgtbl-mode TABLE to some other format.
+
This generic routine can be used for many standard cases.
-TABLE is a list, each entry either the symbol `hline' for a horizontal
-separator line, or a list of fields for that line.
-PARAMS is a property list of parameters that can influence the conversion.
-A third optional argument BACKEND can be used to convert the content of
-the cells using a specific export back-end.
-For the generic converter, some parameters are obligatory: you need to
-specify either :lfmt, or all of (:lstart :lend :sep).
+TABLE is a list, each entry either the symbol `hline' for
+a horizontal separator line, or a list of fields for that
+line. PARAMS is a property list of parameters that can
+influence the conversion.
Valid parameters are:
-:splice When set to t, return only table body lines, don't wrap
- them into :tstart and :tend. Default is nil. When :splice
- is non-nil, this also means that the exporter should not look
- for and interpret header and footer sections.
+:backend
+
+ Export back-end used as a basis to transcode elements of the
+ table, when no specific parameter applies to it. It is also
+ used to translate cells contents. You can prevent this by
+ setting :raw property to a non-nil value.
+
+:splice
+
+ When non-nil, return only table body lines (i.e, skip header
+ section). Also don't wrap them into :tstart and :tend.
+ Default is nil.
+
+:skip
+
+ When set to an integer N, skip the first N lines of the table.
+ Horizontal separation lines do count for this parameter!
+
+:skipcols
-:hline String to be inserted on horizontal separation lines.
- May be nil to ignore hlines.
+ List of columns that should be skipped. If the table has
+ a column with calculation marks, that column is automatically
+ discarded as well. Please note that the translator function
+ sees the table after the removal of these columns, the function
+ never knows that there have been additional columns.
-:sep Separator between two fields
-:remove-nil-lines Do not include lines that evaluate to nil.
+:hline
+
+ String to be inserted on horizontal separation lines. May
+ be nil to ignore hlines.
+
+:sep
+
+ Separator between two fields, as a string.
Each in the following group may be either a string or a function
of no arguments returning a string:
-:tstart String to start the table. Ignored when :splice is t.
-:tend String to end the table. Ignored when :splice is t.
-:lstart String to start a new table line.
-:llstart String to start the last table line, defaults to :lstart.
-:lend String to end a table line
-:llend String to end the last table line, defaults to :lend.
-
-Each in the following group may be a string, a function of one
-argument (the field or line) returning a string, or a plist
-mapping columns to either of the above:
-
-:lfmt Format for entire line, with enough %s to capture all fields.
- If this is present, :lstart, :lend, and :sep are ignored.
-:llfmt Format for the entire last line, defaults to :lfmt.
-:fmt A format to be used to wrap the field, should contain
- %s for the original field value. For example, to wrap
- everything in dollars, you could use :fmt \"$%s$\".
- This may also be a property list with column numbers and
- formats. For example :fmt (2 \"$%s$\" 4 \"%s%%\")
-:hlstart :hllstart :hlend :hllend :hlsep :hlfmt :hllfmt :hfmt
- Same as above, specific for the header lines in the table.
- All lines before the first hline are treated as header.
- If any of these is not present, the data line value is used.
+:tstart
+
+ String to start the table. Ignored when :splice is t.
+
+:tend
+
+ String to end the table. Ignored when :splice is t.
+
+:lstart
+
+ String to start a new table line.
+
+:llstart
+
+ String to start the last table line, defaults to :lstart.
+
+:lend
+
+ String to end a table line.
+
+:llend
+
+ String to end the last table line, defaults to :lend.
+
+Each in the following group may be a string or a function of
+several arguments (one for each cell in row) returning a string:
+
+:lfmt
+
+ Format for entire line, with enough %s to capture all fields.
+ If this is present, :lstart, :lend, and :sep are ignored.
+
+:llfmt
+
+ Format for the entire last line, defaults to :lfmt.
+
+:fmt
+
+ A format to be used to wrap the field, should contain %s for
+ the original field value. For example, to wrap everything in
+ dollars, you could use :fmt \"$%s$\". This may also be
+ a property list with column numbers and format strings, or
+ functions, e.g.,
+
+ \(:fmt (2 \"$%s$\" 4 (lambda (c) (format \"$%s$\" c))))
+
+:hlstart :hllstart :hlend :hllend :hsep :hlfmt :hllfmt :hfmt
+
+ Same as above, specific for the header lines in the table.
+ All lines before the first hline are treated as header. If
+ any of these is not present, the data line value is used.
This may be either a string or a function of two arguments:
-:efmt Use this format to print numbers with exponentials.
- The format should have %s twice for inserting mantissa
- and exponent, for example \"%s\\\\times10^{%s}\". This
- may also be a property list with column numbers and
- formats. :fmt will still be applied after :efmt.
-
-In addition to this, the parameters :skip and :skipcols are always handled
-directly by `orgtbl-send-table'. See manual."
- (let* ((splicep (plist-get params :splice))
- (hline (plist-get params :hline))
- (skipheadrule (plist-get params :skipheadrule))
- (remove-nil-linesp (plist-get params :remove-nil-lines))
- (remove-newlines (plist-get params :remove-newlines))
- (*orgtbl-hline* hline)
- (*orgtbl-table* table)
- (*orgtbl-sep* (plist-get params :sep))
- (*orgtbl-efmt* (plist-get params :efmt))
- (*orgtbl-lstart* (plist-get params :lstart))
- (*orgtbl-llstart* (or (plist-get params :llstart) *orgtbl-lstart*))
- (*orgtbl-lend* (plist-get params :lend))
- (*orgtbl-llend* (or (plist-get params :llend) *orgtbl-lend*))
- (*orgtbl-lfmt* (plist-get params :lfmt))
- (*orgtbl-llfmt* (or (plist-get params :llfmt) *orgtbl-lfmt*))
- (*orgtbl-fmt* (plist-get params :fmt))
- *orgtbl-rtn*)
- ;; Convert cells content to backend BACKEND
- (when backend
- (setq *orgtbl-table*
- (mapcar
- (lambda(r)
- (if (listp r)
- (mapcar
- (lambda (c)
- (org-trim (org-export-string-as c backend t '(:with-tables t))))
- r)
- r))
- *orgtbl-table*)))
- ;; Put header
- (unless splicep
- (when (plist-member params :tstart)
- (let ((tstart (orgtbl-eval-str (plist-get params :tstart))))
- (if tstart (push tstart *orgtbl-rtn*)))))
- ;; If we have a heading, format it and handle the trailing hline.
- (if (and (not splicep)
- (or (consp (car *orgtbl-table*))
- (consp (nth 1 *orgtbl-table*)))
- (memq 'hline (cdr *orgtbl-table*)))
- (progn
- (when (eq 'hline (car *orgtbl-table*))
- ;; There is a hline before the first data line
- (and hline (push hline *orgtbl-rtn*))
- (pop *orgtbl-table*))
- (let* ((*orgtbl-lstart* (or (plist-get params :hlstart)
- *orgtbl-lstart*))
- (*orgtbl-llstart* (or (plist-get params :hllstart)
- *orgtbl-llstart*))
- (*orgtbl-lend* (or (plist-get params :hlend) *orgtbl-lend*))
- (*orgtbl-llend* (or (plist-get params :hllend)
- (plist-get params :hlend) *orgtbl-llend*))
- (*orgtbl-lfmt* (or (plist-get params :hlfmt) *orgtbl-lfmt*))
- (*orgtbl-llfmt* (or (plist-get params :hllfmt)
- (plist-get params :hlfmt) *orgtbl-llfmt*))
- (*orgtbl-sep* (or (plist-get params :hlsep) *orgtbl-sep*))
- (*orgtbl-fmt* (or (plist-get params :hfmt) *orgtbl-fmt*)))
- (orgtbl-format-section 'hline))
- (if (and hline (not skipheadrule)) (push hline *orgtbl-rtn*))
- (pop *orgtbl-table*)))
- ;; Now format the main section.
- (orgtbl-format-section nil)
- (unless splicep
- (when (plist-member params :tend)
- (let ((tend (orgtbl-eval-str (plist-get params :tend))))
- (if tend (push tend *orgtbl-rtn*)))))
- (mapconcat (if remove-newlines
- (lambda (tend)
- (replace-regexp-in-string "[\n\r\t\f]" "\\\\n" tend))
- 'identity)
- (nreverse (if remove-nil-linesp
- (remq nil *orgtbl-rtn*)
- *orgtbl-rtn*)) "\n")))
+:efmt
+
+ Use this format to print numbers with exponential. The format
+ should have %s twice for inserting mantissa and exponent, for
+ example \"%s\\\\times10^{%s}\". This may also be a property
+ list with column numbers and format strings or functions.
+ :fmt will still be applied after :efmt."
+ (let ((backend (plist-get params :backend)))
+ (when (and backend (symbolp backend) (not (org-export-get-backend backend)))
+ (user-error "Unknown :backend value"))
+ (when (or (not backend) (plist-get params :raw)) (require 'ox-org))
+ (org-trim
+ (org-export-string-as
+ ;; Return TABLE as Org syntax. Tolerate non-string cells.
+ (with-output-to-string
+ (dolist (e table)
+ (cond ((eq e 'hline) (princ "|--\n"))
+ ((consp e)
+ (princ "| ") (dolist (c e) (princ c) (princ " |"))
+ (princ "\n")))))
+ ;; Build a custom back-end according to PARAMS. Before defining
+ ;; a translator, check if there is anything to do. When there
+ ;; isn't, let BACKEND handle the element.
+ (org-export-create-backend
+ :parent (or backend 'org)
+ :filters
+ '((:filter-parse-tree
+ ;; Handle :skip parameter.
+ (lambda (tree backend info)
+ (let ((skip (plist-get info :skip)))
+ (when skip
+ (unless (wholenump skip) (user-error "Wrong :skip value"))
+ (let ((n 0))
+ (org-element-map tree 'table-row
+ (lambda (row)
+ (if (>= n skip) t
+ (org-element-extract-element row)
+ (incf n)
+ nil))
+ info t))
+ tree)))
+ ;; Handle :skipcols parameter.
+ (lambda (tree backend info)
+ (let ((skipcols (plist-get info :skipcols)))
+ (when skipcols
+ (unless (consp skipcols) (user-error "Wrong :skipcols value"))
+ (org-element-map tree 'table
+ (lambda (table)
+ (let ((specialp
+ (org-export-table-has-special-column-p table)))
+ (dolist (row (org-element-contents table))
+ (when (eq (org-element-property :type row) 'standard)
+ (let ((c 1))
+ (dolist (cell (nthcdr (if specialp 1 0)
+ (org-element-contents row)))
+ (when (memq c skipcols)
+ (org-element-extract-element cell))
+ (incf c)))))))
+ info)
+ tree)))))
+ :transcoders
+ `((table . ,(org-table--to-generic-table params))
+ (table-row . ,(org-table--to-generic-row params))
+ (table-cell . ,(org-table--to-generic-cell params))
+ ;; Section. Return contents to avoid garbage around table.
+ (section . (lambda (s c i) c))))
+ 'body-only (org-combine-plists params '(:with-tables t))))))
+
+(defun org-table--to-generic-table (params)
+ "Return custom table transcoder according to PARAMS.
+PARAMS is a plist. See `orgtbl-to-generic' for more information.
+Return nil if no transcoder is needed."
+ (let ((backend (plist-get params :backend))
+ (splice (plist-get params :splice))
+ (tstart (plist-get params :tstart))
+ (tend (plist-get params :tend)))
+ `(lambda (table contents info)
+ (concat ,@(cond ((or splice (not tstart)) nil)
+ ((functionp tstart) `((funcall ',tstart) "\n"))
+ ((stringp tstart) `(,tstart "\n"))
+ (t (user-error "Wrong :tstart value")))
+ ,(if (and backend (not (or tstart tend splice)))
+ `(org-export-with-backend ',backend table contents info)
+ 'contents)
+ ,(cond ((or splice (not tend)) nil)
+ ((functionp tend) `(funcall ',tend))
+ ((stringp tend) tend)
+ (t (user-error "Wrong :tend value")))))))
+
+(defun org-table--to-generic-row (params)
+ "Return custom table row transcoder according to PARAMS.
+PARAMS is a plist. See `orgtbl-to-generic' for more
+information."
+ (let* ((backend (plist-get params :backend))
+ (lstart (plist-get params :lstart))
+ (llstart (or (plist-get params :llstart) lstart))
+ (hlstart (or (plist-get params :hlstart) lstart))
+ (hllstart (or (plist-get params :hllstart) hlstart))
+ (lend (plist-get params :lend))
+ (llend (or (plist-get params :llend) lend))
+ (hlend (or (plist-get params :hlend) lend))
+ (hllend (or (plist-get params :hllend) hlend))
+ (lfmt (plist-get params :lfmt))
+ (llfmt (or (plist-get params :llfmt) lfmt))
+ (hlfmt (or (plist-get params :hlfmt) lfmt))
+ (hllfmt (or (plist-get params :hllfmt) hlfmt))
+ (splice (plist-get params :splice)))
+ `(lambda (row contents info)
+ (if (eq (org-element-property :type row) 'rule)
+ ,(cond ((plist-member params :hline) (plist-get params :hline))
+ (backend `(org-export-with-backend ',backend row info)))
+ (let ((headerp
+ (and (org-export-table-has-header-p
+ (org-element-property :parent row) info)
+ (= (org-export-table-row-group row info) 1)))
+ (lastp (not (org-export-get-next-element row info)))
+ (last-header-p (org-export-table-row-ends-header-p row info)))
+ (when (and contents ,(or (not splice) '(not headerp)))
+ ;; Check if we can apply `:lfmt', `:llfmt', `:hlfmt', or
+ ;; `:hllfmt' to CONTENTS. Otherwise, fallback on
+ ;; `:lstart', `:lend' and their relatives.
+ ,(let ((use
+ (lambda (v p)
+ `(apply
+ ,@(cond
+ ((functionp v) `(',v))
+ ((stringp v) `(#'format ,v))
+ (t (user-error "Wrong %s value" p)))
+ (org-element-map row 'table-cell
+ (lambda (cell)
+ ;; Use `org-export-data-with-backend'
+ ;; instead of `org-export-data' to avoid
+ ;; cached values, which
+ ;; ignore :orgtbl-ignore-sep parameter.
+ (org-export-data-with-backend
+ cell
+ (plist-get info :back-end)
+ (org-combine-plists
+ info '(:orgtbl-ignore-sep t))))
+ info)))))
+ `(cond
+ ,(and hllfmt `(last-header-p ,(funcall use hllfmt ":hllfmt")))
+ ,(and hlfmt `(headerp ,(funcall use hlfmt ":hlfmt")))
+ ,(and llfmt `(lastp ,(funcall use llfmt ":llfmt")))
+ (t
+ ,(if lfmt (funcall use lfmt ":lfmt")
+ (let ((use
+ (lambda (v p)
+ (cond ((null v) nil)
+ ((functionp v) `(funcall ',v))
+ ((stringp v) v)
+ (t (user-error "Wrong %s value" p))))))
+ `(concat
+ (cond
+ ,(and (or hllstart hllend)
+ `(last-header-p
+ (concat ,(funcall use hllstart ":hllstart")
+ contents
+ ,(funcall use hllend ":hllend"))))
+ ,(and (or hlstart hlend)
+ `(headerp
+ (concat ,(funcall use hlstart ":hlstart")
+ contents
+ ,(funcall use hlend ":hlend"))))
+ ,(and (or llstart llend)
+ `(lastp
+ (concat ,(funcall use llstart ":llstart")
+ contents
+ ,(funcall use llend ":llend"))))
+ (t
+ ,(cond
+ ((or lstart lend)
+ `(concat ,(funcall use lstart ":lstart")
+ contents
+ ,(funcall use lend ":lend")))
+ (backend
+ `(org-export-with-backend
+ ',backend row contents info))
+ (t 'contents))))))))))))))))
+
+(defun org-table--to-generic-cell (params)
+ "Return custom table cell transcoder according to PARAMS.
+PARAMS is a plist. See `orgtbl-to-generic' for more
+information."
+ (let* ((backend (plist-get params :backend))
+ (efmt (plist-get params :efmt))
+ (fmt (plist-get params :fmt))
+ (hfmt (or (plist-get params :hfmt) fmt))
+ (sep (plist-get params :sep))
+ (hsep (or (plist-get params :hsep) sep)))
+ `(lambda (cell contents info)
+ (let ((column (1+ (cdr (org-export-table-cell-address cell info))))
+ (headerp (= (org-export-table-row-group
+ (org-export-get-parent-element cell) info)
+ 1))
+ (lastp (not (org-export-get-next-element cell info))))
+ ;; Make sure that contents are exported as Org data when :raw
+ ;; parameter is non-nil.
+ ,(when (and backend (plist-get params :raw))
+ `(setq contents
+ (org-export-data-with-backend
+ (org-element-contents cell) 'org info)))
+ (when contents
+ ;; Check if we can apply `:efmt' on CONTENTS. If `:efmt'
+ ;; binds columns to format strings or functions, first
+ ;; get the right one.
+ ,(when efmt
+ `(when (string-match orgtbl-exp-regexp contents)
+ (let ((mantissa (match-string 1 contents))
+ (exponent (match-string 2 contents)))
+ (setq contents
+ ,(cond
+ ((stringp efmt)
+ `(format ,efmt mantissa exponent))
+ ((functionp efmt)
+ `(funcall #',efmt mantissa exponent))
+ ((consp efmt)
+ `(let ((efmt (cadr (memq column ',efmt))))
+ (cond
+ ((null efmt) contents)
+ ((stringp efmt)
+ (format efmt mantissa exponent))
+ ((functionp efmt)
+ (funcall efmt mantissa exponent))
+ (t (user-error "Wrong :efmt value")))))
+ (t (user-error "Wrong :efmt value")))))))
+ ;; Check if we can apply FMT (or HFMT) on CONTENTS. If
+ ;; FMT binds columns to format strings, first get the
+ ;; right one.
+ ,(when hfmt
+ (let ((value
+ (lambda (v p)
+ (cond
+ ((null v) 'contents)
+ ((functionp v) `(funcall #',v contents))
+ ((stringp v) `(format ,v contents))
+ ((consp v)
+ `(let ((fmt (cadr (memq column ',v))))
+ (cond
+ ((null fmt) contents)
+ ((stringp fmt) (format fmt contents))
+ ((functionp fmt) (funcall fmt contents))
+ (t (user-error "Wrong %s value" p)))))
+ (t (user-error "Wrong %s value" p))))))
+ `(setq contents
+ (if headerp ,(funcall value hfmt ":hfmt")
+ ,(funcall value fmt ":fmt"))))))
+ ;; If a separator is provided, use it instead of BACKEND's.
+ ;; Separators are ignored when LFMT (or equivalent) is
+ ;; provided.
+ (if (and ,hsep
+ (not lastp)
+ (not (plist-get info :orgtbl-ignore-sep)))
+ (concat contents (or (and headerp ,hsep) ,sep))
+ ,(if (not backend) 'contents
+ `(org-export-with-backend ',backend cell contents info)))))))
;;;###autoload
(defun orgtbl-to-tsv (table params)
"Convert the orgtbl-mode table to TAB separated material."
(orgtbl-to-generic table (org-combine-plists '(:sep "\t") params)))
+
;;;###autoload
(defun orgtbl-to-csv (table params)
"Convert the orgtbl-mode table to CSV material.
This does take care of the proper quoting of fields with comma or quotes."
- (orgtbl-to-generic table (org-combine-plists
- '(:sep "," :fmt org-quote-csv-field)
- params)))
+ (orgtbl-to-generic table
+ (org-combine-plists '(:sep "," :fmt org-quote-csv-field)
+ params)))
;;;###autoload
(defun orgtbl-to-latex (table params)
"Convert the orgtbl-mode TABLE to LaTeX.
-TABLE is a list, each entry either the symbol `hline' for a horizontal
-separator line, or a list of fields for that line.
-PARAMS is a property list of parameters that can influence the conversion.
-Supports all parameters from `orgtbl-to-generic'. Most important for
-LaTeX are:
-
-:splice When set to t, return only table body lines, don't wrap
- them into a tabular environment. Default is nil.
-
-:fmt A format to be used to wrap the field, should contain %s for the
- original field value. For example, to wrap everything in dollars,
- use :fmt \"$%s$\". This may also be a property list with column
- numbers and formats. For example :fmt (2 \"$%s$\" 4 \"%s%%\")
- The format may also be a function that formats its one argument.
-
-:efmt Format for transforming numbers with exponentials. The format
- should have %s twice for inserting mantissa and exponent, for
- example \"%s\\\\times10^{%s}\". LaTeX default is \"%s\\\\,(%s)\".
- This may also be a property list with column numbers and formats.
- The format may also be a function that formats its two arguments.
-
-:llend If you find too much space below the last line of a table,
- pass a value of \"\" for :llend to suppress the final \\\\.
-The general parameters :skip and :skipcols have already been applied when
-this function is called."
- (let* ((alignment (mapconcat (lambda (x) (if x "r" "l"))
- org-table-last-alignment ""))
- (params2
- (list
- :tstart (concat "\\begin{tabular}{" alignment "}")
- :tend "\\end{tabular}"
- :lstart "" :lend " \\\\" :sep " & "
- :efmt "%s\\,(%s)" :hline "\\hline")))
- (require 'ox-latex)
- (orgtbl-to-generic table (org-combine-plists params2 params) 'latex)))
+TABLE is a list, each entry either the symbol `hline' for
+a horizontal separator line, or a list of fields for that line.
+PARAMS is a property list of parameters that can influence the
+conversion. All parameters from `orgtbl-to-generic' are
+supported. Additionally, it is also possible to use the
+following parameters:
+
+:booktabs
+
+ When non-nil, use formal \"booktabs\" style.
+
+:environment
+
+ Specify environment to use, as a string. If you use
+ \"longtable\", you may also want to specify :language property,
+ as a string, to get proper continuation strings.
+
+The general parameters :skip and :skipcols have already been
+applied when this function is called."
+ (require 'ox-latex)
+ (orgtbl-to-generic
+ table
+ (org-combine-plists
+ ;; Provide sane default values.
+ (list :backend 'latex
+ :latex-default-table-mode 'table
+ :latex-tables-centered nil
+ :latex-tables-booktabs (plist-get params :booktabs)
+ :latex-table-scientific-notation (plist-get params :efmt)
+ :latex-default-table-environment
+ (or (plist-get params :environment) "tabular"))
+ params
+ '(:efmt nil))))
;;;###autoload
(defun orgtbl-to-html (table params)
"Convert the orgtbl-mode TABLE to HTML.
-TABLE is a list, each entry either the symbol `hline' for a horizontal
-separator line, or a list of fields for that line.
-PARAMS is a property list of parameters that can influence the conversion.
-Currently this function recognizes the following parameters:
-:splice When set to t, return only table body lines, don't wrap
- them into a <table> environment. Default is nil.
+TABLE is a list, each entry either the symbol `hline' for
+a horizontal separator line, or a list of fields for that line.
+PARAMS is a property list of parameters that can influence the
+conversion. All parameters from `orgtbl-to-generic' are
+supported. Additionally, it is also possible to use the
+following parameter:
-The general parameters :skip and :skipcols have already been applied when
-this function is called. The function does *not* use `orgtbl-to-generic',
-so you cannot specify parameters for it."
+:attributes
+
+ Attributes and values, as a plist, which will be used in
+ <table> tag.
+
+The general parameters :skip and :skipcols have already been
+applied when this function is called."
(require 'ox-html)
- (let ((output (org-export-string-as
- (orgtbl-to-orgtbl table nil) 'html t '(:with-tables t))))
- (if (not (plist-get params :splice)) output
- (org-trim
- (replace-regexp-in-string
- "\\`<table .*>\n" ""
- (replace-regexp-in-string "</table>\n*\\'" "" output))))))
+ (orgtbl-to-generic
+ table
+ (org-combine-plists
+ ;; Provide sane default values.
+ (list :backend 'html
+ :html-table-data-tags '("<td%s>" . "</td>")
+ :html-table-use-header-tags-for-first-column nil
+ :html-table-align-individual-fields t
+ :html-table-row-tags '("<tr>" . "</tr>")
+ :html-table-attributes
+ (if (plist-member params :attributes)
+ (plist-get params :attributes)
+ '(:border "2" :cellspacing "0" :cellpadding "6" :rules "groups"
+ :frame "hsides")))
+ params)))
;;;###autoload
(defun orgtbl-to-texinfo (table params)
- "Convert the orgtbl-mode TABLE to TeXInfo.
-TABLE is a list, each entry either the symbol `hline' for a horizontal
-separator line, or a list of fields for that line.
-PARAMS is a property list of parameters that can influence the conversion.
-Supports all parameters from `orgtbl-to-generic'. Most important for
-TeXInfo are:
-
-:splice nil/t When set to t, return only table body lines, don't wrap
- them into a multitable environment. Default is nil.
-
-:fmt fmt A format to be used to wrap the field, should contain
- %s for the original field value. For example, to wrap
- everything in @kbd{}, you could use :fmt \"@kbd{%s}\".
- This may also be a property list with column numbers and
- formats. For example :fmt (2 \"@kbd{%s}\" 4 \"@code{%s}\").
- Each format also may be a function that formats its one
- argument.
-
-:cf \"f1 f2..\" The column fractions for the table. By default these
- are computed automatically from the width of the columns
- under org-mode.
+ "Convert the orgtbl-mode TABLE to Texinfo.
+
+TABLE is a list, each entry either the symbol `hline' for
+a horizontal separator line, or a list of fields for that line.
+PARAMS is a property list of parameters that can influence the
+conversion. All parameters from `orgtbl-to-generic' are
+supported. Additionally, it is also possible to use the
+following parameter:
+
+:columns
+
+ Column widths, as a string. When providing column fractions,
+ \"@columnfractions\" command can be omitted.
The general parameters :skip and :skipcols have already been applied when
this function is called."
- (let* ((total (float (apply '+ org-table-last-column-widths)))
- (colfrac (or (plist-get params :cf)
- (mapconcat
- (lambda (x) (format "%.3f" (/ (float x) total)))
- org-table-last-column-widths " ")))
- (params2
- (list
- :tstart (concat "@multitable @columnfractions " colfrac)
- :tend "@end multitable"
- :lstart "@item " :lend "" :sep " @tab "
- :hlstart "@headitem ")))
- (require 'ox-texinfo)
- (orgtbl-to-generic table (org-combine-plists params2 params) 'texinfo)))
+ (require 'ox-texinfo)
+ (let ((output
+ (orgtbl-to-generic
+ table
+ (org-combine-plists
+ (list :backend 'texinfo
+ :texinfo-tables-verbatim nil
+ :latex-table-scientific-notation (plist-get params :efmt))
+ params
+ (list :efmt nil))))
+ (columns (let ((w (plist-get params :columns)))
+ (cond ((not w) nil)
+ ((org-string-match-p "{\\|@columnfractions " w) w)
+ (t (concat "@columnfractions " w))))))
+ (if (not columns) output
+ (replace-regexp-in-string
+ "@multitable \\(.*\\)" columns output t nil 1))))
;;;###autoload
(defun orgtbl-to-orgtbl (table params)
@@ -4967,21 +5040,8 @@ Useful when slicing one table into many. The :hline, :sep,
:lstart, and :lend provide orgtbl framing. The default nil :tstart
and :tend suppress strings without splicing; they can be set to
provide ORGTBL directives for the generated table."
- (let* ((params2
- (list
- :remove-newlines t
- :tstart nil :tend nil
- :hline "|---"
- :sep " | "
- :lstart "| "
- :lend " |"))
- (params (org-combine-plists params2 params)))
- (with-temp-buffer
- (insert (orgtbl-to-generic table params))
- (goto-char (point-min))
- (while (re-search-forward org-table-hline-regexp nil t)
- (org-table-align))
- (buffer-substring 1 (buffer-size)))))
+ (require 'ox-org)
+ (orgtbl-to-generic table (org-combine-plists (list :backend 'org))))
(defun orgtbl-to-table.el (table params)
"Convert the orgtbl-mode TABLE into a table.el table."
@@ -4994,19 +5054,38 @@ provide ORGTBL directives for the generated table."
(defun orgtbl-to-unicode (table params)
"Convert the orgtbl-mode TABLE into a table with unicode characters.
-You need the ascii-art-to-unicode.el package for this. You can download
-it here: http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el."
- (with-temp-buffer
- (insert (orgtbl-to-table.el table params))
- (goto-char (point-min))
- (if (or (featurep 'ascii-art-to-unicode)
- (require 'ascii-art-to-unicode nil t))
- (aa2u)
- (unless (delq nil (mapcar (lambda (l) (string-match "aa2u" (car l))) org-stored-links))
- (push '("http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el"
- "Link to ascii-art-to-unicode.el") org-stored-links))
- (user-error "Please download ascii-art-to-unicode.el (use C-c C-l to insert the link to it)"))
- (buffer-string)))
+
+
+TABLE is a list, each entry either the symbol `hline' for
+a horizontal separator line, or a list of fields for that line.
+PARAMS is a property list of parameters that can influence the
+conversion. All parameters from `orgtbl-to-generic' are
+supported. Additionally, it is also possible to use the
+following parameters:
+
+:ascii-art
+
+ When non-nil, use \"ascii-art-to-unicode\" package to translate
+ the table. You can download it here:
+ http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el.
+
+:narrow
+
+ When non-nil, narrow columns width than provided width cookie,
+ using \"=>\" as an ellipsis, just like in an Org mode buffer.
+
+The general parameters :skip and :skipcols have already been
+applied when this function is called."
+ (require 'ox-ascii)
+ (orgtbl-to-generic
+ table
+ (org-combine-plists
+ (list :backend 'ascii
+ :ascii-charset 'utf-8
+ :ascii-table-keep-all-vertical-lines (plist-get params :)
+ :ascii-table-widen-columns (not (plist-get params :narrow))
+ :ascii-table-use-ascii-art (plist-get params :ascii-art))
+ params)))
(defun org-table-get-remote-range (name-or-id form)
"Get a field value or a list of values in a range from table at ID.
diff --git a/testing/lisp/test-org-table.el b/testing/lisp/test-org-table.el
index 40101be..d99d735 100644
--- a/testing/lisp/test-org-table.el
+++ b/testing/lisp/test-org-table.el
@@ -1168,6 +1168,357 @@ See also `test-org-table/copy-field'."
(should (string= got
expect)))))
+;;; Radio Tables
+
+(ert-deftest test-org-table/to-generic ()
+ "Test `orgtbl-to-generic' specifications."
+ ;; Test :splice parameter.
+ (should
+ (equal "b"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:splice t))))
+ (should
+ (equal "a\nb"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n| b |") '(:splice t))))
+ ;; Test :hline parameter.
+ (should
+ (equal "a\nb"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:hline nil))))
+ (should
+ (equal "a\n~\nb"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:hline "~"))))
+ ;; Test :sep parameter.
+ (should
+ (equal "a!b\nc!d"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:sep "!"))))
+ ;; Test :hsep parameter.
+ (should
+ (equal "a!b\nc?d"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:sep "?" :hsep "!"))))
+ ;; Test :tstart parameter.
+ (should
+ (equal "<begin>\na"
+ (orgtbl-to-generic (org-table-to-lisp "| a |") '(:tstart "<begin>"))))
+ (should
+ (equal "<begin>\na"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:tstart (lambda () "<begin>")))))
+ (should
+ (equal "a"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:tstart "<begin>" :splice t))))
+ ;; Test :tend parameter.
+ (should
+ (equal "a\n<end>"
+ (orgtbl-to-generic (org-table-to-lisp "| a |") '(:tend "<end>"))))
+ (should
+ (equal "a\n<end>"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:tend (lambda () "<end>")))))
+ (should
+ (equal "a"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:tend "<end>" :splice t))))
+ ;; Test :lstart parameter.
+ (should
+ (equal "> a"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a |") '(:lstart "> "))))
+ (should
+ (equal "> a"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:lstart (lambda () "> ")))))
+ ;; Test :llstart parameter.
+ (should
+ (equal "> a\n>> b"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:lstart "> " :llstart ">> "))))
+ ;; Test :hlstart parameter.
+ (should
+ (equal "!> a\n> b"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:lstart "> " :hlstart "!> "))))
+ ;; Test :hllstart parameter.
+ (should
+ (equal "!> a\n!!> b\n> c"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n| b |\n|---|\n| c |")
+ '(:lstart "> " :hlstart "!> " :hllstart "!!> "))))
+ ;; Test :lend parameter.
+ (should
+ (equal "a <"
+ (orgtbl-to-generic (org-table-to-lisp "| a |") '(:lend " <"))))
+ ;; Test :llend parameter.
+ (should
+ (equal "a <\nb <<"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:lend " <" :llend " <<"))))
+ ;; Test :hlend parameter.
+ (should
+ (equal "a <!\nb <"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:lend " <" :hlend " <!"))))
+ ;; Test :hllend parameter.
+ (should
+ (equal "a <!\nb <!!\nc <"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n| b |\n|---|\n| c |")
+ '(:lend " <" :hlend " <!" :hllend " <!!"))))
+ ;; Test :lfmt parameter.
+ (should
+ (equal "a!b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:lfmt "%s!%s"))))
+ (should
+ (equal "a+b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:lfmt (lambda (c1 c2) (concat c1 "+" c2))))))
+ (should
+ (equal "a!b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:lfmt "%s!%s" :lstart ">" :lend "<" :sep " "))))
+ ;; Test :llfmt parameter.
+ (should
+ (equal "a!b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:llfmt "%s!%s"))))
+ (should
+ (equal "a!b\nc+d"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n| c | d |")
+ '(:lfmt "%s!%s" :llfmt (lambda (c1 c2) (concat c1 "+" c2))))))
+ (should
+ (equal "a!b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:llfmt "%s!%s" :lstart ">" :lend "<" :sep " "))))
+ ;; Test :hlfmt parameter.
+ (should
+ (equal "a!b\ncd"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hlfmt "%s!%s"))))
+ (should
+ (equal "a+b\ncd"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hlfmt (lambda (c1 c2) (concat c1 "+" c2))))))
+ (should
+ (equal "a!b\n>c d<"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hlfmt "%s!%s" :lstart ">" :lend "<" :sep " "))))
+ ;; Test :hllfmt parameter.
+ (should
+ (equal "a!b\ncd"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hllfmt "%s!%s"))))
+ (should
+ (equal "a+b\ncd"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hllfmt (lambda (c1 c2) (concat c1 "+" c2))))))
+ (should
+ (equal "a!b\n>c d<"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |")
+ '(:hllfmt "%s!%s" :lstart ">" :lend "<" :sep " "))))
+ ;; Test :fmt parameter.
+ (should
+ (equal ">a<\n>b<"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:fmt ">%s<"))))
+ (should
+ (equal ">a<b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:fmt (1 ">%s<" 2 (lambda (c) c))))))
+ (should
+ (equal "a b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:fmt (2 " %s")))))
+ (should
+ (equal ">a<"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:fmt (lambda (c) (format ">%s<" c))))))
+ ;; Test :hfmt parameter.
+ (should
+ (equal ">a<\nb"
+ (orgtbl-to-generic (org-table-to-lisp "| a |\n|---|\n| b |")
+ '(:hfmt ">%s<"))))
+ (should
+ (equal ">a<b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:hfmt (1 ">%s<" 2 identity)))))
+ (should
+ (equal "a b"
+ (orgtbl-to-generic (org-table-to-lisp "| a | b |")
+ '(:hfmt (2 " %s")))))
+ (should
+ (equal ">a<"
+ (orgtbl-to-generic (org-table-to-lisp "| a |")
+ '(:hfmt (lambda (c) (format ">%s<" c))))))
+ ;; Test :efmt parameter.
+ (should
+ (equal "2x10^3"
+ (orgtbl-to-generic (org-table-to-lisp "| 2e3 |")
+ '(:efmt "%sx10^%s"))))
+ (should
+ (equal "2x10^3"
+ (orgtbl-to-generic (org-table-to-lisp "| 2e3 |")
+ '(:efmt (lambda (m e) (concat m "x10^" e))))))
+ (should
+ (equal "2x10^3"
+ (orgtbl-to-generic (org-table-to-lisp "| 2e3 |")
+ '(:efmt (1 "%sx10^%s")))))
+ (should
+ (equal "2x10^3"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| 2e3 |")
+ '(:efmt (1 (lambda (m e) (format "%sx10^%s" m e)))))))
+ (should
+ (equal "2e3"
+ (orgtbl-to-generic (org-table-to-lisp "| 2e3 |") '(:efmt nil))))
+ ;; Test :skip parameter.
+ (should
+ (equal "cd"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| \ | <c> |\n| a | b |\n|---+---|\n| c | d |")
+ '(:skip 2))))
+ ;; Test :skipcols parameter.
+ (should
+ (equal "a\nc"
+ (orgtbl-to-generic
+ (org-table-to-lisp "| a | b |\n| c | d |") '(:skipcols (2)))))
+ (should
+ (equal "a\nc"
+ (orgtbl-to-generic
+ (org-table-to-lisp
+ "| / | <c> | <c> |\n| # | a | b |\n|---+---+---|\n| | c | d |")
+ '(:skipcols (2)))))
+ ;; Test :raw parameter.
+ (when (featurep 'ox-latex)
+ (should
+ (org-string-match-p
+ "/a/"
+ (orgtbl-to-generic (org-table-to-lisp "| /a/ | b |")
+ '(:backend latex :raw t))))))
+
+(ert-deftest test-org-table/to-latex ()
+ "Test `orgtbl-to-latex' specifications."
+ (should
+ (equal "\\begin{tabular}{l}\na\\\\\n\\end{tabular}"
+ (orgtbl-to-latex (org-table-to-lisp "| a |") nil)))
+ ;; Test :environment parameter.
+ (should
+ (equal "\\begin{tabularx}{l}\na\\\\\n\\end{tabularx}"
+ (orgtbl-to-latex (org-table-to-lisp "| a |")
+ '(:environment "tabularx"))))
+ ;; Test :booktabs parameter.
+ (should
+ (org-string-match-p
+ "\\toprule" (orgtbl-to-latex (org-table-to-lisp "| a |") '(:booktabs t)))))
+
+(ert-deftest test-org-table/to-html ()
+ "Test `orgtbl-to-html' specifications."
+ (should
+ (equal (orgtbl-to-html (org-table-to-lisp "| a |") nil)
+ "<table border=\"2\" cellspacing=\"0\" cellpadding=\"6\" rules=\"groups\" frame=\"hsides\">
+
+
+<colgroup>
+<col class=\"left\" />
+</colgroup>
+<tbody>
+<tr>
+<td class=\"left\">a</td>
+</tr>
+</tbody>
+</table>"))
+ ;; Test :attributes parameter.
+ (should
+ (org-string-match-p
+ "<table>"
+ (orgtbl-to-html (org-table-to-lisp "| a |") '(:attributes nil))))
+ (should
+ (org-string-match-p
+ "<table border=\"2\">"
+ (orgtbl-to-html (org-table-to-lisp "| a |") '(:attributes (:border "2"))))))
+
+(ert-deftest test-org-table/to-texinfo ()
+ "Test `orgtbl-to-texinfo' specifications."
+ (should
+ (equal "@multitable {a}\n@item a\n@end multitable"
+ (orgtbl-to-texinfo (org-table-to-lisp "| a |") nil)))
+ ;; Test :columns parameter.
+ (should
+ (equal "@multitable @columnfractions .4 .6\n@item a\n@tab b\n@end multitable"
+ (orgtbl-to-texinfo (org-table-to-lisp "| a | b |")
+ '(:columns ".4 .6"))))
+ (should
+ (equal "@multitable @columnfractions .4 .6\n@item a\n@tab b\n@end multitable"
+ (orgtbl-to-texinfo (org-table-to-lisp "| a | b |")
+ '(:columns "@columnfractions .4 .6"))))
+ (should
+ (equal "@multitable {xxx} {xx}\n@item a\n@tab b\n@end multitable"
+ (orgtbl-to-texinfo (org-table-to-lisp "| a | b |")
+ '(:columns "{xxx} {xx}")))))
+
+(ert-deftest test-org-table/to-orgtbl ()
+ "Test `orgtbl-to-orgtbl' specifications."
+ (should
+ (equal "| a | b |\n|---+---|\n| c | d |"
+ (orgtbl-to-orgtbl
+ (org-table-to-lisp "| a | b |\n|---+---|\n| c | d |") nil))))
+
+(ert-deftest test-org-table/to-unicode ()
+ "Test `orgtbl-to-unicode' specifications."
+ (should
+ (equal "━━━\n a \n━━━"
+ (orgtbl-to-unicode (org-table-to-lisp "| a |") nil)))
+ ;; Test :narrow parameter.
+ (should
+ (equal "━━━━\n => \n━━━━"
+ (orgtbl-to-unicode (org-table-to-lisp "| <2> |\n| xxx |")
+ '(:narrow t)))))
+
+(ert-deftest test-org-table/send-region ()
+ "Test `orgtbl-send-table' specifications."
+ ;; Error when not at a table.
+ (should-error
+ (org-test-with-temp-text "Paragraph"
+ (orgtbl-send-table)))
+ ;; Error when destination is missing.
+ (should-error
+ (org-test-with-temp-text "#+ORGTBL: SEND\n<point>| a |"
+ (orgtbl-send-table)))
+ ;; Error when transformation function is not specified.
+ (should-error
+ (org-test-with-temp-text "
+# BEGIN RECEIVE ORGTBL table
+# END RECEIVE ORGTBL table
+#+ORGTBL: SEND table
+<point>| a |"
+ (orgtbl-send-table)))
+ ;; Standard test.
+ (should
+ (equal "| a |\n|---|\n| b |\n"
+ (org-test-with-temp-text "
+# BEGIN RECEIVE ORGTBL table
+# END RECEIVE ORGTBL table
+#+ORGTBL: SEND table orgtbl-to-orgtbl :hlines nil
+<point>| a |\n|---|\n| b |"
+ (orgtbl-send-table)
+ (goto-char (point-min))
+ (buffer-substring-no-properties
+ (search-forward "# BEGIN RECEIVE ORGTBL table\n")
+ (progn (search-forward "# END RECEIVE ORGTBL table")
+ (match-beginning 0)))))))
+
+
(provide 'test-org-table)
;;; test-org-table.el ends here
--
2.1.0
next reply other threads:[~2014-08-24 19:25 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-08-24 19:25 Nicolas Goaziou [this message]
2014-08-24 20:18 ` [RFC] Rewrite radio tables Thorsten Jolitz
2014-08-24 20:51 ` Thorsten Jolitz
2014-08-25 16:08 ` Nick Dokos
2014-08-25 16:11 ` Nick Dokos
2014-08-25 19:20 ` Nicolas Goaziou
2014-09-13 13:23 ` Nicolas Goaziou
2014-08-27 14:50 ` AW
2014-08-27 23:33 ` Nicolas Goaziou
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8761hh6662.fsf@nicolasgoaziou.fr \
--to=mail@nicolasgoaziou.fr \
--cc=emacs-orgmode@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).