summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Dominik <carsten.dominik@gmail.com>2008-04-21 07:50:27 +0200
committerCarsten Dominik <carsten.dominik@gmail.com>2008-04-21 07:50:27 +0200
commit1508d31b6ed5238387b6ae64288d5766d30aaa2b (patch)
tree427a38b59568481f1e0f4272d7757bcd8b3f1b15
parent383774f36084b3adf09963c3ae8ad651018cee66 (diff)
downloadorg-mode-1508d31b6ed5238387b6ae64288d5766d30aaa2b.tar.gz
Applied patch series from Jason Riedy.
You can slice a single table full of calculations in different ways into separate destinations. Or you can format the table differently. There are many fun and exciting possible uses. A fancier implementation would scan the document *once* for the set of destinations. That could help implement another function to update all destinations from all sources. Refactor orgtbl-to-generic; explicitly separate heading from body. Support last-line specializers. Allow functions for some orgtbl parameters. Add a :remove-nil-lines parameter to orgtbl-to-generic.
-rw-r--r--ChangeLog55
-rw-r--r--contrib/ChangeLog5
-rw-r--r--contrib/README1
-rw-r--r--contrib/lisp/orgtbl-sqlinsert.el114
-rw-r--r--doc/org.texi5
-rw-r--r--lisp/org-table.el321
-rw-r--r--lisp/org.el1
7 files changed, 394 insertions, 108 deletions
diff --git a/ChangeLog b/ChangeLog
index b869abd..6ca8ac8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2008-04-16 Jason Riedy <jason@acm.org>
+
+ * lisp/org-table.el (orgtbl-to-generic): Add a :remove-nil-lines
+ parameter that supresses lines that evaluate to NIL.
+
+
+2008-04-15 Jason Riedy <jason@acm.org>
+
+ * lisp/org-table.el (orgtbl-get-fmt): New inline function for
+ picking apart formats that may be lists.
+ (orgtbl-apply-fmt): New inline function for applying formats that
+ may be functions.
+ (orgtbl-eval-str): New inline function for strings that may be
+ functions.
+ (orgtbl-format-line, orgtbl-to-generic): Use and document.
+ (orgtbl-to-latex, orgtbl-to-texinfo): Document.
+
+ * doc/org.texi (A LaTeX example): Note that fmt may be a
+ one-argument function, and efmt may be a two-argument function.
+
+2008-04-15 Jason Riedy <jason@acm.org>
+
+ * lisp/org-table.el (*orgtbl-llfmt*, *orgtbl-llstart*)
+ (*orgtbl-llend*): Dynamic variables for last-line formatting.
+ (orgtbl-format-section): Shift formatting to support detecting the
+ last line and formatting it specially.
+ (orgtbl-to-generic): Document :ll* formats. Set to the non-ll
+ formats unless overridden.
+ (orgtbl-to-latex): Suggest using :llend to suppress the final \\.
+
+2008-04-15 Jason Riedy <jason@acm.org>
+
+ * lisp/org-table.el (*orgtbl-table*, *orgtbl-rtn*): Dynamically
+ bound variables to hold the input collection of lines and output
+ formatted text.
+ (*orgtbl-hline*, *orgtbl-sep*, *orgtbl-fmt*, *orgtbl-efmt*,
+ (*orgtbl-lfmt*, *orgtbl-lstart*, *orgtbl-lend*): Dynamically bound
+ format parameters.
+ (orgtbl-format-line): New function encapsulating formatting for a
+ single line.
+ (orgtbl-format-section): Similar for each section. Rebinding the
+ dynamic vars customizes the formatting for each section.
+ (orgtbl-to-generic): Use orgtbl-format-line and
+ orgtbl-format-section.
+ (org-get-param): Now unused, so delete.
+
+ * lisp/org-table.el (orgtbl-gather-send-defs): New function to
+ gather all the SEND definitions before a table.
+ (orgtbl-send-replace-tbl): New function to find the RECEIVE
+ corresponding to the current name.
+ (orgtbl-send-table): Use the previous two functions and implement
+ multiple destinations for each table.
+
+ * doc/org.texi (Radio tables): Document multiple destinations.
+
2008-04-19 Carsten Dominik <dominik@science.uva.nl>
* xemacs/noutline.el (outline-invisible-p): Require that
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index 81c142b..5db4bb3 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,8 @@
+2008-04-15 Jason Riedy <jason@acm.org>
+
+ * lisp/orgtbl-sqlinsert.el: New file.
+ * README: Add to list.
+
2008-04-07 Carsten Dominik <dominik@science.uva.nl>
* lisp/org-iswitchb.el: File removed, because the functionality is
diff --git a/contrib/README b/contrib/README
index e564cf9..6b49863 100644
--- a/contrib/README
+++ b/contrib/README
@@ -24,6 +24,7 @@ org-registry.el --- a registry for Org links
org2rem.el --- Convert org appointments into reminders
org-screen.el --- visit screen sessions through Org-mode links
org-toc.el --- Table of contents for Org-mode buffer
+orgtbl-sqlinsert.el --- Convert Org-mode tables to SQL insertions.
PACKAGES
========
diff --git a/contrib/lisp/orgtbl-sqlinsert.el b/contrib/lisp/orgtbl-sqlinsert.el
new file mode 100644
index 0000000..869f74f
--- /dev/null
+++ b/contrib/lisp/orgtbl-sqlinsert.el
@@ -0,0 +1,114 @@
+;;; orgtbl-sqlinsert.el --- orgtbl to SQL insert statements.
+
+;; Copyright (C) 2008 Free Software Foundation
+
+;; Author: Jason Riedy <jason@acm.org>
+;; Keywords: org, tables, sql
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Converts an orgtbl to a sequence of SQL insertion commands.
+;; Table cells are quoted and escaped very conservatively.
+
+;;; Code:
+
+(defun orgtbl-to-sqlinsert (table params)
+ "Convert the orgtbl-mode TABLE to SQL insert statements.
+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.
+
+Names and strings are modified slightly by default. Single-ticks
+are doubled as per SQL's standard mechanism. Backslashes and
+dollar signs are deleted. And tildes are changed to spaces.
+These modifications were chosed for use with TeX. See
+ORGTBL-SQL-STRIP-AND-QUOTE.
+
+Supports all parameters from ORGTBL-TO-GENERIC. New to this function
+are:
+
+:sqlname The name of the database table; defaults to the name of the
+ target region.
+
+:nowebname If not nil, used as a wrapping noweb fragment name.
+
+The most important parameters of ORGTBL-TO-GENERIC for SQL are:
+
+:splice When set to t, return only insert statements, don't wrap
+ them in a transaction. Default is nil.
+
+:tstart, :tend
+ The strings used to begin and commit the transaction.
+
+:hfmt A function that gathers the quoted header names into a
+ dynamically scoped variable HDRLIST. Probably should
+ not be changed by the user.
+
+The general parameters :skip and :skipcols have already been applied when
+this function is called."
+ (let* (hdrlist
+ (alignment (mapconcat (lambda (x) (if x "r" "l"))
+ org-table-last-alignment ""))
+ (nowebname (plist-get params :nowebname))
+ (breakvals (plist-get params :breakvals))
+ (params2
+ (list
+ :sqlname name
+ :tstart (lambda () (concat (if nowebname
+ (format "<<%s>>= \n" nowebname)
+ "")
+ "BEGIN TRANSACTION;"))
+ :tend (lambda () (concat "COMMIT;" (if nowebname "\n@ " "")))
+ :fmt (lambda (str) (orgtbl-sql-strip-and-quote str))
+; :hfmt (lambda (f) (push (concat "[" f "]") hdrlist) "")
+ :hfmt (lambda (f) (push f hdrlist) "")
+ :hlfmt (lambda (lst) nil)
+ :lstart (lambda () (concat "INSERT INTO "
+ (plist-get params :sqlname) "( "
+ (mapconcat 'identity (reverse hdrlist)
+ ", ")
+ " )" (if breakvals "\n" " ")
+ "VALUES ( "))
+ :lend " );"
+ :sep " , "
+ :hline nil
+ :remove-nil-lines t))
+ (params (org-combine-plists params2 params)))
+ (orgtbl-to-generic table params)))
+
+(defun orgtbl-sql-quote (str)
+ "Convert single ticks to doubled single ticks and wrap in single ticks."
+ (concat "'" (mapconcat 'identity (split-string str "'") "''") "'"))
+
+(defun orgtbl-sql-strip-dollars-escapes-tildes (str)
+ "Strip dollarsigns and backslash escapes, replace tildes with spaces."
+ (mapconcat 'identity
+ (split-string (mapconcat 'identity
+ (split-string str "\\$\\|\\\\")
+ "")
+ "~")
+ " "))
+
+(defun orgtbl-sql-strip-and-quote (str)
+ "Apply ORGBTL-SQL-QUOTE and ORGTBL-SQL-STRIP-DOLLARS-ESCAPES-TILDES
+to sanitize STR for use in SQL statements."
+ (cond ((stringp str)
+ (orgtbl-sql-quote (orgtbl-sql-strip-dollars-escapes-tildes str)))
+ ((sequencep str) (mapcar 'orgtbl-sql-strip-and-quote str))
+ (t nil)))
+
+(provide 'orgtbl-sqlinsert)
+;;; orgtbl-sqlinsert.el ends here
diff --git a/doc/org.texi b/doc/org.texi
index 12c41eb..ae1fdce 100644
--- a/doc/org.texi
+++ b/doc/org.texi
@@ -8583,6 +8583,8 @@ A format to be used to wrap each field, should contain @code{%s} for the
original field value. For example, to wrap each field value in dollars,
you could use @code{:fmt "$%s$"}. This may also be a property list with
column numbers and formats. for example @code{:fmt (2 "$%s$" 4 "%s\\%%")}.
+A function of one argument can be used in place of the strings; the
+function must return a formatted string.
@item :efmt efmt
Use this format to print numbers with exponentials. The format should
@@ -8591,7 +8593,8 @@ have @code{%s} twice for inserting mantissa and exponent, for example
may also be a property list with column numbers and formats, for example
@code{:efmt (2 "$%s\\times10^@{%s@}$" 4 "$%s\\cdot10^@{%s@}$")}. After
@code{efmt} has been applied to a value, @code{fmt} will also be
-applied.
+applied. Similar to @code{fmt}, functions of two arguments can be
+supplied instead of strings.
@end table
@node Translator functions, Radio lists, A LaTeX example, Tables in arbitrary syntax
diff --git a/lisp/org-table.el b/lisp/org-table.el
index 43aaa87..6bcfbff 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -3492,6 +3492,41 @@ overwritten, and the table is not marked as requiring realignment."
(push (> (/ (apply '+ (mapcar (lambda (x) (if (string-match org-table-number-regexp x) 1 0)) column)) maxcol) org-table-number-fraction) org-table-last-alignment))
(funcall func table nil)))
+(defun orgtbl-gather-send-defs ()
+ "Gathers a plist of :name, :transform, :params for each destination before
+a radio table."
+ (save-excursion
+ (goto-char (org-table-begin))
+ (let (rtn)
+ (beginning-of-line 0)
+ (while (looking-at "#\\+ORGTBL: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
+ (let ((name (org-no-properties (match-string 1)))
+ (transform (intern (match-string 2)))
+ (params (if (match-end 3)
+ (read (concat "(" (match-string 3) ")")))))
+ (push (list :name name :transform transform :params params)
+ rtn)
+ (beginning-of-line 0)))
+ rtn)))
+
+(defun orgtbl-send-replace-tbl (name txt)
+ "Find and replace table NAME with TXT."
+ (save-excursion
+ (goto-char (point-min))
+ (unless (re-search-forward
+ (concat "BEGIN RECEIVE ORGTBL +" name "\\([ \t]\\|$\\)") nil t)
+ (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)
+ (error "Cannot find end of insertion region"))
+ (beginning-of-line 1)
+ (delete-region beg (point))))
+ (insert txt "\n")))
+
(defun orgtbl-send-table (&optional maybe)
"Send a tranformed version of this table to the receiver position.
With argument MAYBE, fail quietly if no transformation is defined for
@@ -3501,59 +3536,45 @@ this table."
(unless (org-at-table-p) (error "Not at a table"))
;; when non-interactive, we assume align has just happened.
(when (interactive-p) (org-table-align))
- (save-excursion
- (goto-char (org-table-begin))
- (beginning-of-line 0)
- (unless (looking-at "#\\+ORGTBL: *SEND +\\([a-zA-Z0-9_]+\\) +\\([^ \t\r\n]+\\)\\( +.*\\)?")
- (if maybe
- (throw 'exit nil)
- (error "Don't know how to transform this table."))))
- (let* ((name (match-string 1))
- beg
- (transform (intern (match-string 2)))
- (params (if (match-end 3) (read (concat "(" (match-string 3) ")"))))
- (skip (plist-get params :skip))
- (skipcols (plist-get params :skipcols))
- (txt (buffer-substring-no-properties
- (org-table-begin) (org-table-end)))
- (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)
- (error "No such transformation function %s" transform))
- (setq txt (funcall transform table params))
- ;; Find the insertion place
- (save-excursion
- (goto-char (point-min))
- (unless (re-search-forward
- (concat "BEGIN RECEIVE ORGTBL +" name "\\([ \t]\\|$\\)") nil t)
- (error "Don't know where to insert translated table"))
- (goto-char (match-beginning 0))
- (beginning-of-line 2)
- (setq beg (point))
- (unless (re-search-forward (concat "END RECEIVE ORGTBL +" name) nil t)
- (error "Cannot find end of insertion region"))
- (beginning-of-line 1)
- (delete-region beg (point))
- (goto-char beg)
- (insert txt "\n"))
- (message "Table converted and installed at receiver location"))))
+ (let ((dests (orgtbl-gather-send-defs))
+ (txt (buffer-substring-no-properties (org-table-begin)
+ (org-table-end)))
+ (ntbl 0))
+ (unless dests (if maybe (throw 'exit nil)
+ (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))
+ 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))
+ (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)
+ (error "No such transformation function %s" transform))))
+ (orgtbl-send-replace-tbl name txt))
+ (setq ntbl (1+ ntbl)))
+ (message "Table converted and installed at %d receiver location%s"
+ ntbl (if (> ntbl 1) "s" "")))))
(defun org-remove-by-index (list indices &optional i0)
"Remove the elements in LIST with indices in INDICES.
@@ -3602,15 +3623,75 @@ First element has index 0, or I0 if given."
(insert txt)
(goto-char pos)))
-(defun org-get-param (params header i sym &optional hsym)
- "Get parameter value for symbol SYM.
-If this is a header line, actually get the value for the symbol with an
-additional \"h\" inserted after the colon.
-If the value is a protperty list, get the element for the current column.
-Assumes variables VAL, PARAMS, HEAD and I to be scoped into the function."
- (let ((val (plist-get params sym)))
- (and hsym header (setq val (or (plist-get params hsym) val)))
- (if (consp val) (plist-get val i) val)))
+;; 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-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 the arguments. NIL FMTs return the first argument."
+ (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 (orgtbl-get-fmt *orgtbl-fmt* i) f)))
+ line)))
+ (push (if *orgtbl-lfmt*
+ (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))))))
(defun orgtbl-to-generic (table params)
"Convert the orgtbl-mode TABLE to some other format.
@@ -3624,31 +3705,43 @@ specify either :lfmt, or all of (:lstart :lend :sep). If you do not use
Valid parameters are
-:tstart String to start the table. Ignored when :splice is t.
-:tend String to end the table. Ignored when :splice is t.
-
:splice When set to t, return only table body lines, don't wrap
them into :tstart and :tend. Default is nil.
:hline String to be inserted on horizontal separation lines.
May be nil to ignore hlines.
+:sep Separator between two fields
+:remove-nil-lines Do not include lines that evaluate to nil.
+
+
+ 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
-:sep Separator between two fields
+: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 :hlend :hlsep :hlfmt :hfmt
+: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.
+ 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
@@ -3658,51 +3751,58 @@ Valid parameters are
In addition to this, the parameters :skip and :skipcols are always handled
directly by `orgtbl-send-table'. See manual."
(interactive)
- (let* ((p params)
- (splicep (plist-get p :splice))
- (hline (plist-get p :hline))
- rtn line i fm efm lfmt h)
- ;; Do we have a header?
- (if (and (not splicep) (listp (car table)) (memq 'hline table))
- (setq h t))
+ (let* ((splicep (plist-get params :splice))
+ (hline (plist-get params :hline))
+ (remove-nil-linesp (plist-get params :remove-nil-lines))
+ (*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*)
;; Put header
(unless splicep
- (push (or (plist-get p :tstart) "ERROR: no :tstart") rtn))
-
- ;; Now loop over all lines
- (while (setq line (pop table))
- (if (eq line 'hline)
- ;; A horizontal separator line
- (progn (if hline (push hline rtn))
- (setq h nil)) ; no longer in header
- ;; A normal line. Convert the fields, push line onto the result list
- (setq i 0)
- (setq line
- (mapcar
- (lambda (f)
- (setq i (1+ i)
- fm (org-get-param p h i :fmt :hfmt)
- efm (org-get-param p h i :efmt))
- (if (and efm (string-match orgtbl-exp-regexp f))
- (setq f (format
- efm (match-string 1 f) (match-string 2 f))))
- (if fm (setq f (format fm f)))
- f)
- line))
- (if (setq lfmt (org-get-param p h i :lfmt :hlfmt))
- (push (apply 'format lfmt line) rtn)
- (push (concat
- (org-get-param p h i :lstart :hlstart)
- (mapconcat 'identity line (org-get-param p h i :sep :hsep))
- (org-get-param p h i :lend :hlend))
- rtn))))
+ (push (or (orgtbl-eval-str (plist-get params :tstart))
+ "ERROR: no :tstart") *orgtbl-rtn*))
- (unless splicep
- (push (or (plist-get p :tend) "ERROR: no :tend") rtn))
-
- (mapconcat 'identity (nreverse rtn) "\n")))
+ ;; Do we have a heading section? If so, format it and handle the
+ ;; trailing hline.
+ (if (and (not splicep) (listp (car *orgtbl-table*))
+ (memq 'hline *orgtbl-table*))
+ (progn
+ (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 hline (push hline *orgtbl-rtn*))
+ (pop *orgtbl-table*)))
+
+ ;; Now format the main section.
+ (orgtbl-format-section nil)
+
+ (unless splicep
+ (push (or (orgtbl-eval-str (plist-get params :tend))
+ "ERROR: no :tend") *orgtbl-rtn*))
+
+ (mapconcat 'identity (nreverse (if remove-nil-linesp
+ (remq nil *orgtbl-rtn*)
+ *orgtbl-rtn*)) "\n")))
(defun orgtbl-to-latex (table params)
"Convert the orgtbl-mode TABLE to LaTeX.
@@ -3719,11 +3819,16 @@ LaTeX are:
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."
@@ -3782,6 +3887,8 @@ TeXInfo are:
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
diff --git a/lisp/org.el b/lisp/org.el
index b9b025d..da09c4b 100644
--- a/lisp/org.el
+++ b/lisp/org.el
@@ -185,6 +185,7 @@ to add the symbol `xyz', and the package must have a call to
(const :tag "C org2rem: Convert org appointments into reminders" org2rem)
(const :tag "C screen: Visit screen sessions through Org-mode links" org-screen)
(const :tag "C toc: Table of contents for Org-mode buffer" org-toc)
+ (const :tag "C sqlinsert: Convert Org-mode tables to SQL insertions" orgtbl-sqlinsert)
(repeat :tag "External packages" :inline t (symbol :tag "Package"))))