summaryrefslogtreecommitdiff
path: root/lisp/org-table.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org-table.el')
-rw-r--r--lisp/org-table.el584
1 files changed, 408 insertions, 176 deletions
diff --git a/lisp/org-table.el b/lisp/org-table.el
index 3eb63b6..c5a3aca 100644
--- a/lisp/org-table.el
+++ b/lisp/org-table.el
@@ -1,6 +1,6 @@
;;; org-table.el --- The table editor for Org-mode
-;; Copyright (C) 2004-2012 Free Software Foundation, Inc.
+;; Copyright (C) 2004-2013 Free Software Foundation, Inc.
;; Author: Carsten Dominik <carsten at orgmode dot org>
;; Keywords: outlines, hypermedia, calendar, wp
@@ -38,13 +38,11 @@
(require 'cl))
(require 'org)
-(declare-function org-table-clean-before-export "org-exp"
- (lines &optional maybe-quoted))
-(declare-function org-format-org-table-html "org-html" (lines &optional splice))
+(declare-function org-export-string-as "ox"
+ (string backend &optional body-only ext-plist))
(declare-function aa2u "ext:ascii-art-to-unicode" ())
(defvar orgtbl-mode) ; defined below
(defvar orgtbl-mode-menu) ; defined when orgtbl mode get initialized
-(defvar org-export-html-table-tag) ; defined in org-exp.el
(defvar constants-unit-system)
(defvar org-table-follow-field-mode)
@@ -54,6 +52,8 @@ This can be used to add additional functionality after the table is sent
to the receiver position, otherwise, if table is not sent, the functions
are not run.")
+(defvar org-table-TBLFM-begin-regexp "|\n[ \t]*#\\+TBLFM: ")
+
(defcustom orgtbl-optimized (eq org-enable-table-editor 'optimized)
"Non-nil means use the optimized table editor version for `orgtbl-mode'.
In the optimized version, the table editor takes over all simple keys that
@@ -112,7 +112,7 @@ table, obtained by prompting the user."
:type 'string)
(defcustom org-table-number-regexp
- "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%:]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$"
+ "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%:]*\\|[<>]?[-+]?0[xX][0-9a-fA-F.]+\\|[<>]?[-+]?[0-9]+#[0-9a-zA-Z.]+\\|nan\\|[-+u]?inf\\)$"
"Regular expression for recognizing numbers in table columns.
If a table column contains mostly numbers, it will be aligned to the
right. If not, it will be aligned to the left.
@@ -136,10 +136,10 @@ Other options offered by the customize interface are more restrictive."
"^[-+]?\\([0-9]*\\.[0-9]+\\|[0-9]+\\.?[0-9]*\\)$")
(const :tag "Exponential, Floating point, Integer"
"^[-+]?[0-9.]+\\([eEdD][-+0-9]+\\)?$")
- (const :tag "Very General Number-Like, including hex"
- "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$")
- (const :tag "Very General Number-Like, including hex, allows comma as decimal mark"
- "^\\([<>]?[-+^.,0-9]*[0-9][-+^.0-9eEdDx()%]*\\|\\(0[xX]\\)[0-9a-fA-F]+\\|nan\\)$")
+ (const :tag "Very General Number-Like, including hex and Calc radix"
+ "^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|[<>]?[-+]?0[xX][0-9a-fA-F.]+\\|[<>]?[-+]?[0-9]+#[0-9a-zA-Z.]+\\|nan\\|[-+u]?inf\\)$")
+ (const :tag "Very General Number-Like, including hex and Calc radix, allows comma as decimal mark"
+ "^\\([<>]?[-+^.,0-9]*[0-9][-+^.0-9eEdDx()%]*\\|[<>]?[-+]?0[xX][0-9a-fA-F.]+\\|[<>]?[-+]?[0-9]+#[0-9a-zA-Z.]+\\|nan\\|[-+u]?inf\\)$")
(string :tag "Regexp:")))
(defcustom org-table-number-fraction 0.5
@@ -419,10 +419,75 @@ available parameters."
(org-split-string (match-string 1 line)
"[ \t]*|[ \t]*")))))))
+(defvar org-table-colgroup-info 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."
+ (setq org-table-colgroup-info nil)
+ (if (memq nil
+ (mapcar
+ (lambda (x) (or (string-match "^[ \t]*|-" x)
+ (string-match
+ (if maybe-quoted
+ "^[ \t]*| *\\\\?\\([\#!$*_^ /]\\) *|"
+ "^[ \t]*| *\\([\#!$*_^ /]\\) *|")
+ x)))
+ lines))
+ ;; No special marking column
+ (progn
+ (setq org-table-clean-did-remove-column nil)
+ (delq nil
+ (mapcar
+ (lambda (x)
+ (cond
+ ((org-table-colgroup-line-p x)
+ ;; This line contains colgroup info, extract it
+ ;; and then discard the line
+ (setq org-table-colgroup-info
+ (mapcar (lambda (x)
+ (cond ((member x '("<" "&lt;")) :start)
+ ((member x '(">" "&gt;")) :end)
+ ((member x '("<>" "&lt;&gt;")) :startend)))
+ (org-split-string x "[ \t]*|[ \t]*")))
+ nil)
+ ((org-table-cookie-line-p x)
+ ;; This line contains formatting cookies, discard it
+ nil)
+ (t x)))
+ lines)))
+ ;; there is a special marking column
+ (setq org-table-clean-did-remove-column t)
+ (delq nil
+ (mapcar
+ (lambda (x)
+ (cond
+ ((org-table-colgroup-line-p x)
+ ;; This line contains colgroup info, extract it
+ ;; and then discard the line
+ (setq org-table-colgroup-info
+ (mapcar (lambda (x)
+ (cond ((member x '("<" "&lt;")) :start)
+ ((member x '(">" "&gt;")) :end)
+ ((member x '("<>" "&lt;&gt;")) :startend)))
+ (cdr (org-split-string x "[ \t]*|[ \t]*"))))
+ nil)
+ ((org-table-cookie-line-p x)
+ ;; This line contains formatting cookies, discard it
+ nil)
+ ((string-match "^[ \t]*| *\\([!_^/$]\\|\\\\\\$\\) *|" x)
+ ;; ignore this line
+ nil)
+ ((or (string-match "^\\([ \t]*\\)|-+\\+" x)
+ (string-match "^\\([ \t]*\\)|[^|]*|" x))
+ ;; remove the first column
+ (replace-match "\\1|" t nil x))))
+ 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.")
+;;;###autoload
(defun org-table-create-with-table.el ()
"Use the table.el package to insert a new table.
If there is already a table at point, convert between Org-mode tables
@@ -439,6 +504,7 @@ and table.el tables."
(org-table-convert)))
(t (call-interactively 'table-insert))))
+;;;###autoload
(defun org-table-create-or-convert-from-region (arg)
"Convert region to table, or create an empty table.
If there is an active region, convert it to a table, using the function
@@ -451,6 +517,7 @@ If there is no such region, create an empty table with `org-table-create'."
(org-table-convert-region (region-beginning) (region-end) arg)
(org-table-create arg)))
+;;;###autoload
(defun org-table-create (&optional size)
"Query for a size and insert a table skeleton.
SIZE is a string Columns x Rows like for example \"3x2\"."
@@ -483,6 +550,7 @@ SIZE is a string Columns x Rows like for example \"3x2\"."
(goto-char pos)))
(org-table-align)))
+;;;###autoload
(defun org-table-convert-region (beg0 end0 &optional separator)
"Convert region to a table.
The region goes from BEG0 to END0, but these borders will be moved
@@ -505,10 +573,10 @@ nil When nil, the command tries to be smart and figure out the
re)
(goto-char beg)
(beginning-of-line 1)
- (setq beg (move-marker (make-marker) (point)))
+ (setq beg (point-marker))
(goto-char end)
(if (bolp) (backward-char 1) (end-of-line 1))
- (setq end (move-marker (make-marker) (point)))
+ (setq end (point-marker))
;; Get the right field separator
(unless separator
(goto-char beg)
@@ -535,7 +603,7 @@ nil When nil, the command tries to be smart and figure out the
((equal separator '(16)) "^\\|\t")
((integerp separator)
(if (< separator 1)
- (error "Number of spaces in separator must be >= 1")
+ (user-error "Number of spaces in separator must be >= 1")
(format "^ *\\| *\t *\\| \\{%d,\\}" separator)))
(t (error "This should not happen"))))
(while (re-search-forward re end t)
@@ -543,6 +611,7 @@ nil When nil, the command tries to be smart and figure out the
(goto-char beg)
(org-table-align)))
+;;;###autoload
(defun org-table-import (file arg)
"Import FILE as a table.
The file is assumed to be tab-separated. Such files can be produced by most
@@ -558,6 +627,7 @@ are found, lines will be split on whitespace into fields."
(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.
Such a file can be imported into usual spreadsheet programs.
@@ -573,9 +643,7 @@ whether it is set locally or up in the hierarchy, then on the
extension of the given file name, and finally on the variable
`org-table-export-default-format'."
(interactive)
- (unless (org-at-table-p)
- (error "No table at point"))
- (require 'org-exp)
+ (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))
@@ -592,13 +660,13 @@ extension of the given file name, and finally on the variable
(setq file (read-file-name "Export table to: "))
(unless (or (not (file-exists-p file))
(y-or-n-p (format "Overwrite file %s? " file)))
- (error "Abort")))
+ (user-error "File not written")))
(if (file-directory-p file)
- (error "This is a directory path, not a 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))))
- (error "Please specify a file name that is different from current"))
+ (user-error "Please specify a file name that is different from current"))
(setq fileext (concat (file-name-extension file) "$"))
(unless format
(setq deffmt-readable
@@ -635,7 +703,7 @@ extension of the given file name, and finally on the variable
skipcols i0)))
(unless (fboundp transform)
- (error "No such transformation function %s" transform))
+ (user-error "No such transformation function %s" transform))
(setq txt (funcall transform table params))
(with-current-buffer (find-file-noselect file)
@@ -646,7 +714,7 @@ extension of the given file name, and finally on the variable
(save-buffer))
(kill-buffer buf)
(message "Export done."))
- (error "TABLE_EXPORT_FORMAT invalid"))))
+ (user-error "TABLE_EXPORT_FORMAT invalid"))))
(defvar org-table-aligned-begin-marker (make-marker)
"Marker at the beginning of the table last aligned.
@@ -673,6 +741,7 @@ When nil, simply write \"#ERROR\" in corrupted fields.")
(defconst org-narrow-column-arrow "=>"
"Used as display property in narrowed table columns.")
+;;;###autoload
(defun org-table-align ()
"Align the table at point by aligning all vertical bars."
(interactive)
@@ -753,7 +822,7 @@ When nil, simply write \"#ERROR\" in corrupted fields.")
(error
(kill-region beg end)
(org-table-create org-table-default-size)
- (error "Empty table - created default table")))
+ (user-error "Empty table - created default table")))
;; A list of empty strings to fill any short rows on output
(setq emptystrings (make-list maxfields ""))
;; Check for special formatting.
@@ -780,7 +849,7 @@ When nil, simply write \"#ERROR\" in corrupted fields.")
(concat "Clipped table field, use C-c ` to edit. Full value is:\n" (org-no-properties (copy-sequence xx))))
(setq f1 (min fmax (or (string-match org-bracket-link-regexp xx) fmax)))
(unless (> f1 1)
- (error "Cannot narrow field starting with wide link \"%s\""
+ (user-error "Cannot narrow field starting with wide link \"%s\""
(match-string 0 xx)))
(add-text-properties f1 (length xx) (list 'org-cwidth t) xx)
(add-text-properties (- f1 2) f1
@@ -853,7 +922,8 @@ When nil, simply write \"#ERROR\" in corrupted fields.")
(org-goto-line winstartline)
(setq winstart (point-at-bol))
(org-goto-line linepos)
- (set-window-start (selected-window) winstart 'noforce)
+ (when (eq (window-buffer (selected-window)) (current-buffer))
+ (set-window-start (selected-window) winstart 'noforce))
(org-table-goto-column colpos)
(and org-table-overlay-coordinates (org-table-overlay-coordinates))
(setq org-table-may-need-update nil)
@@ -884,6 +954,7 @@ With argument TABLE-TYPE, go to the end of a table.el-type table."
(goto-char (match-beginning 0)))
(point-marker)))
+;;;###autoload
(defun org-table-justify-field-maybe (&optional new)
"Justify the current field, text to left, number to right.
Optional argument NEW may specify text to replace the current field content."
@@ -924,6 +995,7 @@ Optional argument NEW may specify text to replace the current field content."
(setq org-table-may-need-update t))
(goto-char pos))))))
+;;;###autoload
(defun org-table-next-field ()
"Go to the next field in the current table, creating new lines as needed.
Before doing so, re-align the table if necessary."
@@ -953,6 +1025,7 @@ Before doing so, re-align the table if necessary."
(error
(org-table-insert-row 'below)))))
+;;;###autoload
(defun org-table-previous-field ()
"Go to the previous field in the table.
Before doing so, re-align the table if necessary."
@@ -968,7 +1041,7 @@ Before doing so, re-align the table if necessary."
(progn
(re-search-backward "|" (org-table-begin))
(re-search-backward "|" (org-table-begin)))
- (error (error "Cannot move to previous table field")))
+ (error (user-error "Cannot move to previous table field")))
(while (looking-at "|\\(-\\|[ \t]*$\\)")
(re-search-backward "|" (org-table-begin)))
(if (looking-at "| ?")
@@ -984,7 +1057,7 @@ With numeric argument N, move N-1 fields forward first."
(setq n (1- n))
(org-table-previous-field))
(if (not (re-search-backward "|" (point-at-bol 0) t))
- (error "No more table fields before the current")
+ (user-error "No more table fields before the current")
(goto-char (match-end 0))
(and (looking-at " ") (forward-char 1)))
(if (>= (point) pos) (org-table-beginning-of-field 2))))
@@ -1006,6 +1079,7 @@ With numeric argument N, move N-1 fields backward first."
(forward-char 1)))
(if (<= (point) pos) (org-table-end-of-field 2))))
+;;;###autoload
(defun org-table-next-row ()
"Go to the next row (same column) in the current table.
Before doing so, re-align the table if necessary."
@@ -1029,6 +1103,7 @@ Before doing so, re-align the table if necessary."
(skip-chars-backward "^|\n\r")
(if (looking-at " ") (forward-char 1)))))
+;;;###autoload
(defun org-table-copy-down (n)
"Copy a field down in the current column.
If the field at the cursor is empty, copy into it the content of
@@ -1043,7 +1118,7 @@ copying. In the case of a timestamp, increment by one day."
(interactive "p")
(let* ((colpos (org-table-current-column))
(col (current-column))
- (field (org-table-get-field))
+ (field (save-excursion (org-table-get-field)))
(non-empty (string-match "[^ \t]" field))
(beg (org-table-begin))
(orig-n n)
@@ -1079,7 +1154,7 @@ copying. In the case of a timestamp, increment by one day."
(org-table-maybe-recalculate-line))
(org-table-align)
(org-move-to-column col))
- (error "No non-empty field found"))))
+ (user-error "No non-empty field found"))))
(defun org-table-check-inside-data-field (&optional noerror)
"Is point inside a table data field?
@@ -1091,7 +1166,7 @@ This actually throws an error, so it aborts the current command."
(looking-at "[ \t]*$"))
(if noerror
nil
- (error "Not in table data field"))
+ (user-error "Not in table data field"))
t))
(defvar org-table-clip nil
@@ -1173,6 +1248,7 @@ is always the old value."
val)
(forward-char 1) ""))
+;;;###autoload
(defun org-table-field-info (arg)
"Show info about the current field, and highlight any reference at point."
(interactive "P")
@@ -1228,6 +1304,7 @@ is always the old value."
(message "In table column %d" cnt))
cnt)))
+;;;###autoload
(defun org-table-current-dline ()
"Find out what table data line we are in.
Only data lines count for this."
@@ -1244,6 +1321,7 @@ Only data lines count for this."
(message "This is table line %d" cnt))
cnt)))
+;;;###autoload
(defun org-table-goto-column (n &optional on-delim force)
"Move the cursor to the Nth column in the current table line.
With optional argument ON-DELIM, stop with point before the left delimiter
@@ -1266,11 +1344,12 @@ However, when FORCE is non-nil, create new columns if necessary."
(backward-char 1)
(if (looking-at " ") (forward-char 1)))))
+;;;###autoload
(defun org-table-insert-column ()
"Insert a new column into the table."
(interactive)
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(org-table-find-dataline)
(let* ((col (max 1 (org-table-current-column)))
(beg (org-table-begin))
@@ -1310,7 +1389,7 @@ However, when FORCE is non-nil, create new columns if necessary."
(if (and (org-at-table-p)
(not (org-at-table-hline-p)))
t
- (error
+ (user-error
"Please position cursor in a data line for column operations")))))
(defun org-table-line-to-dline (line &optional above)
@@ -1335,11 +1414,12 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
(setq i (1+ i)))))
nil))
+;;;###autoload
(defun org-table-delete-column ()
"Delete a column from the table."
(interactive)
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(org-table-find-dataline)
(org-table-check-inside-data-field)
(let* ((col (org-table-current-column))
@@ -1367,20 +1447,23 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
(org-table-fix-formulas "$LR" (list (cons (number-to-string col) "INVALID"))
col -1 col))))
+;;;###autoload
(defun org-table-move-column-right ()
"Move column to the right."
(interactive)
(org-table-move-column nil))
+;;;###autoload
(defun org-table-move-column-left ()
"Move column to the left."
(interactive)
(org-table-move-column 'left))
+;;;###autoload
(defun org-table-move-column (&optional left)
"Move the current column to the right. With arg LEFT, move to the left."
(interactive "P")
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(org-table-find-dataline)
(org-table-check-inside-data-field)
(let* ((col (org-table-current-column))
@@ -1391,9 +1474,9 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
(linepos (org-current-line))
(colpos (if left (1- col) (1+ col))))
(if (and left (= col 1))
- (error "Cannot move column further left"))
+ (user-error "Cannot move column further left"))
(if (and (not left) (looking-at "[^|\n]*|[^|\n]*$"))
- (error "Cannot move column further right"))
+ (user-error "Cannot move column further right"))
(goto-char beg)
(while (< (point) end)
(if (org-at-table-hline-p)
@@ -1415,15 +1498,18 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
"$LR" (list (cons (number-to-string col) (number-to-string colpos))
(cons (number-to-string colpos) (number-to-string col)))))))
+;;;###autoload
(defun org-table-move-row-down ()
"Move table row down."
(interactive)
(org-table-move-row nil))
+;;;###autoload
(defun org-table-move-row-up ()
"Move table row up."
(interactive)
(org-table-move-row 'up))
+;;;###autoload
(defun org-table-move-row (&optional up)
"Move the current table line down. With arg UP, move it up."
(interactive "P")
@@ -1438,7 +1524,7 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
(beginning-of-line tonew)
(unless (org-at-table-p)
(goto-char pos)
- (error "Cannot move row further"))
+ (user-error "Cannot move row further"))
(setq hline2p (looking-at org-table-hline-regexp))
(goto-char pos)
(beginning-of-line 1)
@@ -1457,12 +1543,13 @@ first dline below it is used. When ABOVE is non-nil, the one above is used."
"@" (list (cons (number-to-string dline1) (number-to-string dline2))
(cons (number-to-string dline2) (number-to-string dline1)))))))
+;;;###autoload
(defun org-table-insert-row (&optional arg)
"Insert a new row above the current line into the table.
With prefix ARG, insert below the current line."
(interactive "P")
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(let* ((line (buffer-substring (point-at-bol) (point-at-eol)))
(new (org-table-clean-line line)))
;; Fix the first field if necessary
@@ -1478,12 +1565,13 @@ With prefix ARG, insert below the current line."
(funcall org-table-fix-formulas-confirm "Fix formulas? "))
(org-table-fix-formulas "@" nil (1- (org-table-current-dline)) 1))))
+;;;###autoload
(defun org-table-insert-hline (&optional above)
"Insert a horizontal-line below the current line into the table.
With prefix ABOVE, insert above the current line."
(interactive "P")
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(when (eobp) (insert "\n") (backward-char 1))
(if (not (string-match "|[ \t]*$" (org-current-line-string)))
(org-table-align))
@@ -1501,6 +1589,7 @@ With prefix ABOVE, insert above the current line."
(org-move-to-column col)
(and org-table-overlay-coordinates (org-table-align))))
+;;;###autoload
(defun org-table-hline-and-move (&optional same-column)
"Insert a hline and move to the row below that line."
(interactive "P")
@@ -1527,11 +1616,12 @@ In particular, this does handle wide and invisible characters."
t t s)))
s))
+;;;###autoload
(defun org-table-kill-row ()
"Delete the current row or horizontal line from the table."
(interactive)
(if (not (org-at-table-p))
- (error "Not at a table"))
+ (user-error "Not at a table"))
(let ((col (current-column))
(dline (org-table-current-dline)))
(kill-region (point-at-bol) (min (1+ (point-at-eol)) (point-max)))
@@ -1542,6 +1632,7 @@ In particular, this does handle wide and invisible characters."
(org-table-fix-formulas "@" (list (cons (number-to-string dline) "INVALID"))
dline -1 dline))))
+;;;###autoload
(defun org-table-sort-lines (with-case &optional sorting-type)
"Sort table lines according to the column at point.
@@ -1566,6 +1657,7 @@ should be done in reverse order."
(interactive "P")
(let* ((thisline (org-current-line))
(thiscol (org-table-current-column))
+ (otc org-table-overlay-coordinates)
beg end bcol ecol tend tbeg column lns pos)
(when (equal thiscol 0)
(if (org-called-interactively-p 'any)
@@ -1614,15 +1706,18 @@ should be done in reverse order."
x))
(org-split-string (buffer-substring beg end) "\n")))
(setq lns (org-do-sort lns "Table" with-case sorting-type))
+ (when org-table-overlay-coordinates
+ (org-table-toggle-coordinate-overlays))
(delete-region beg end)
(move-marker beg nil)
(move-marker end nil)
(insert (mapconcat 'cdr lns "\n") "\n")
(org-goto-line thisline)
(org-table-goto-column thiscol)
+ (when otc (org-table-toggle-coordinate-overlays))
(message "%d lines sorted, based on column %d" (length lns) column)))
-
+;;;###autoload
(defun org-table-cut-region (beg end)
"Copy region in table to the clipboard and blank all relevant fields.
If there is no active region, use just the field at point."
@@ -1631,6 +1726,7 @@ If there is no active region, use just the field at point."
(if (org-region-active-p) (region-end) (point))))
(org-table-copy-region beg end 'cut))
+;;;###autoload
(defun org-table-copy-region (beg end &optional cut)
"Copy rectangular region in table to clipboard.
A special clipboard is used which can only be accessed
@@ -1668,6 +1764,7 @@ with `org-table-paste-rectangle'."
(if cut (org-table-align))
org-table-clip))
+;;;###autoload
(defun org-table-paste-rectangle ()
"Paste a rectangular region into a table.
The upper right corner ends up in the current field. All involved fields
@@ -1676,7 +1773,7 @@ the table is enlarged as needed. The process ignores horizontal separator
lines."
(interactive)
(unless (and org-table-clip (listp org-table-clip))
- (error "First cut/copy a region to paste!"))
+ (user-error "First cut/copy a region to paste!"))
(org-table-check-inside-data-field)
(let* ((clip org-table-clip)
(line (org-current-line))
@@ -1698,6 +1795,7 @@ lines."
(org-table-goto-column col)
(org-table-align)))
+;;;###autoload
(defun org-table-convert ()
"Convert from `org-mode' table to table.el and back.
Obviously, this only works within limits. When an Org-mode table is
@@ -1761,16 +1859,22 @@ will be transposed as
Note that horizontal lines disappeared."
(interactive)
- (let ((contents
- (apply #'mapcar* #'list
- ;; remove 'hline from list
- (delq nil (mapcar (lambda (x) (when (listp x) x))
- (org-table-to-lisp))))))
+ (let* ((table (delete 'hline (org-table-to-lisp)))
+ (contents (mapcar (lambda (p)
+ (let ((tp table))
+ (mapcar
+ (lambda (rown)
+ (prog1
+ (pop (car tp))
+ (setq tp (cdr tp))))
+ table)))
+ (car table))))
(delete-region (org-table-begin) (org-table-end))
(insert (mapconcat (lambda(x) (concat "| " (mapconcat 'identity x " | " ) " |\n" ))
contents ""))
(org-table-align)))
+;;;###autoload
(defun org-table-wrap-region (arg)
"Wrap several fields in a column like a paragraph.
This is useful if you'd like to spread the contents of a field over several
@@ -1803,7 +1907,7 @@ blank, and the content is appended to the field above."
nlines)
(org-table-cut-region (region-beginning) (region-end))
(if (> (length (car org-table-clip)) 1)
- (error "Region must be limited to single column"))
+ (user-error "Region must be limited to single column"))
(setq nlines (if arg
(if (< arg 1)
(+ (length org-table-clip) arg)
@@ -1841,6 +1945,7 @@ blank, and the content is appended to the field above."
(defvar org-field-marker nil)
+;;;###autoload
(defun org-table-edit-field (arg)
"Edit table field in a different window.
This is mainly useful for fields that contain hidden parts.
@@ -1858,7 +1963,7 @@ it can be edited in place."
(if (and (boundp 'font-lock-mode) font-lock-mode)
(font-lock-fontify-block))))
(t
- (let ((pos (move-marker (make-marker) (point)))
+ (let ((pos (point-marker))
(coord
(if (eq org-table-use-standard-references t)
(concat (org-number-to-letters (org-table-current-column))
@@ -1944,6 +2049,7 @@ table (but see `org-table-exit-follow-field-mode-when-leaving-table')."
(defvar org-timecnt) ; dynamically scoped parameter
+;;;###autoload
(defun org-table-sum (&optional beg end nlast)
"Sum numbers in region of current table column.
The result will be displayed in the echo area, and will be available
@@ -1970,12 +2076,12 @@ If NLAST is a number, only the NLAST fields will actually be summed."
(setq col (org-table-current-column))
(goto-char (org-table-begin))
(unless (re-search-forward "^[ \t]*|[^-]" nil t)
- (error "No table data"))
+ (user-error "No table data"))
(org-table-goto-column col)
(setq beg (point))
(goto-char (org-table-end))
(unless (re-search-backward "^[ \t]*|[^-]" nil t)
- (error "No table data"))
+ (user-error "No table data"))
(org-table-goto-column col)
(setq end (point))))
(let* ((items (apply 'append (org-table-copy-region beg end)))
@@ -1993,7 +2099,7 @@ If NLAST is a number, only the NLAST fields will actually be summed."
h (floor (/ diff 3600)) diff (mod diff 3600)
m (floor (/ diff 60)) diff (mod diff 60)
s diff)
- (format "%d:%02d:%02d" h m s))))
+ (format "%.0f:%02.0f:%02.0f" h m s))))
(kill-new sres)
(if (org-called-interactively-p 'interactive)
(message "%s"
@@ -2060,7 +2166,7 @@ When NAMED is non-nil, look for a named equation."
(int-to-string (org-table-current-column))))
(dummy (and (or nameass refass) (not named)
(not (y-or-n-p "Replace existing field formula with column formula? " ))
- (error "Abort")))
+ (message "Formula not replaced")))
(name (or name ref))
(org-table-may-need-update nil)
(stored (cdr (assoc scol stored-list)))
@@ -2084,7 +2190,7 @@ When NAMED is non-nil, look for a named equation."
;; remove formula
(setq stored-list (delq (assoc scol stored-list) stored-list))
(org-table-store-formulas stored-list)
- (error "Formula removed"))
+ (user-error "Formula removed"))
(if (string-match "^ *=?" eq) (setq eq (replace-match "" t t eq)))
(if (string-match " *$" eq) (setq eq (replace-match "" t t eq)))
(if (and name (not named))
@@ -2144,9 +2250,10 @@ When NAMED is non-nil, look for a named equation."
(bs (org-table-formula-make-cmp-string (car b))))
(and as bs (string< as bs))))
+;;;###autoload
(defun org-table-get-stored-formulas (&optional noerror)
"Return an alist with the stored formulas directly after current table."
- (interactive)
+ (interactive) ;; FIXME interactive?
(let ((case-fold-search t) scol eq eq-alist strings string seen)
(save-excursion
(goto-char (org-table-end))
@@ -2168,7 +2275,7 @@ When NAMED is non-nil, look for a named equation."
(message "Double definition `$%s=' in TBLFM line, please fix by hand" scol)
(ding)
(sit-for 2))
- (error "Double definition `$%s=' in TBLFM line, please fix by hand" scol))
+ (user-error "Double definition `$%s=' in TBLFM line, please fix by hand" scol))
(push scol seen))))))
(nreverse eq-alist)))
@@ -2192,7 +2299,7 @@ For all numbers larger than LIMIT, shift them by DELTA."
(while (re-search-forward re2 (point-at-eol) t)
(unless (save-match-data (org-in-regexp "remote([^)]+?)"))
(if (equal (char-before (match-beginning 0)) ?.)
- (error "Change makes TBLFM term %s invalid, use undo to recover"
+ (user-error "Change makes TBLFM term %s invalid, use undo to recover"
(match-string 0))
(replace-match "")))))
(while (re-search-forward re (point-at-eol) t)
@@ -2283,6 +2390,7 @@ For all numbers larger than LIMIT, shift them by DELTA."
(setq org-table-local-parameters
(append org-table-local-parameters al2))))))
+;;;###autoload
(defun org-table-maybe-eval-formula ()
"Check if the current field starts with \"=\" or \":=\".
If yes, store the formula and apply it."
@@ -2298,7 +2406,7 @@ If yes, store the formula and apply it."
(equal (substring eq 0 (min 2 (length eq))) "'("))
(org-table-eval-formula (if named '(4) nil)
(org-table-formula-from-user eq))
- (error "Calc does not seem to be installed, and is needed to evaluate the formula"))))))
+ (user-error "Calc does not seem to be installed, and is needed to evaluate the formula"))))))
(defvar org-recalc-commands nil
"List of commands triggering the recalculation of a line.
@@ -2313,6 +2421,7 @@ Will be filled automatically during use.")
("_" . "Names for values in row below this one.")
("^" . "Names for values in row above this one.")))
+;;;###autoload
(defun org-table-rotate-recalc-marks (&optional newchar)
"Rotate the recalculation mark in the first column.
If in any row, the first field is not consistent with a mark,
@@ -2322,7 +2431,7 @@ after prompting for the marking character.
After each change, a message will be displayed indicating the meaning
of the new mark."
(interactive)
- (unless (org-at-table-p) (error "Not at a table"))
+ (unless (org-at-table-p) (user-error "Not at a table"))
(let* ((marks (append (mapcar 'car org-recalc-marks) '(" ")))
(beg (org-table-begin))
(end (org-table-end))
@@ -2341,13 +2450,13 @@ of the new mark."
(setq newchar (char-to-string (read-char-exclusive))
forcenew (car (assoc newchar org-recalc-marks))))
(if (and newchar (not forcenew))
- (error "Invalid NEWCHAR `%s' in `org-table-rotate-recalc-marks'"
+ (user-error "Invalid NEWCHAR `%s' in `org-table-rotate-recalc-marks'"
newchar))
(if l1 (org-goto-line l1))
(save-excursion
(beginning-of-line 1)
(unless (looking-at org-table-dataline-regexp)
- (error "Not at a table data line")))
+ (user-error "Not at a table data line")))
(unless have-col
(org-table-goto-column 1)
(org-table-insert-column)
@@ -2374,6 +2483,7 @@ of the new mark."
(and (org-called-interactively-p 'interactive)
(message "%s" (cdr (assoc new org-recalc-marks))))))
+;;;###autoload
(defun org-table-maybe-recalculate-line ()
"Recompute the current line if marked for it, and if we haven't just done it."
(interactive)
@@ -2397,6 +2507,7 @@ of the new mark."
(cons var (cons value org-tbl-calc-modes)))
org-tbl-calc-modes)
+;;;###autoload
(defun org-table-eval-formula (&optional arg equation
suppress-align suppress-const
suppress-store suppress-analysis)
@@ -2440,7 +2551,7 @@ not overwrite the stored one."
(or suppress-analysis (org-table-get-specials))
(if (equal arg '(16))
(let ((eq (org-table-current-field-formula)))
- (or eq (error "No equation active for current field"))
+ (or eq (user-error "No equation active for current field"))
(org-table-get-field nil eq)
(org-table-align)
(setq org-table-may-need-update t))
@@ -2514,7 +2625,10 @@ not overwrite the stored one."
fields)))
(if (eq numbers t)
(setq fields (mapcar
- (lambda (x) (number-to-string (string-to-number x)))
+ (lambda (x)
+ (if (string-match "\\S-" x)
+ (number-to-string (string-to-number x))
+ x))
fields)))
(setq ndown (1- ndown))
(setq form (copy-sequence formula)
@@ -2569,7 +2683,7 @@ not overwrite the stored one."
(if (not (save-match-data
(string-match (regexp-quote form) formrpl)))
(setq form (replace-match formrpl t t form))
- (error "Spreadsheet error: invalid reference \"%s\"" form)))
+ (user-error "Spreadsheet error: invalid reference \"%s\"" form)))
;; Insert simple ranges
(while (string-match "\\$\\([0-9]+\\)\\.\\.\\$\\([0-9]+\\)" form)
(setq form
@@ -2587,11 +2701,12 @@ not overwrite the stored one."
(setq n (+ (string-to-number (match-string 1 form))
(if (match-end 2) n0 0))
x (nth (1- (if (= n 0) n0 (max n 1))) fields))
- (unless x (error "Invalid field specifier \"%s\""
+ (unless x (user-error "Invalid field specifier \"%s\""
(match-string 0 form)))
(setq form (replace-match
(save-match-data
- (org-table-make-reference x nil numbers lispp))
+ (org-table-make-reference
+ x keep-empty numbers lispp))
t t form)))
(if lispp
@@ -2603,12 +2718,23 @@ not overwrite the stored one."
(string-to-number ev)
duration-output-format) ev))
(or (fboundp 'calc-eval)
- (error "Calc does not seem to be installed, and is needed to evaluate the formula"))
- ;; "Inactivate" time-stamps so that Calc can handle them
+ (user-error "Calc does not seem to be installed, and is needed to evaluate the formula"))
+ ;; Use <...> time-stamps so that Calc can handle them
(setq form (replace-regexp-in-string org-ts-regexp3 "<\\1>" form))
+ ;; I18n-ize local time-stamps by setting (system-time-locale "C")
+ (when (string-match org-ts-regexp2 form)
+ (let* ((ts (match-string 0 form))
+ (tsp (apply 'encode-time (save-match-data (org-parse-time-string ts))))
+ (system-time-locale "C")
+ (tf (or (and (save-match-data (string-match "[0-9]\\{1,2\\}:[0-9]\\{2\\}" ts))
+ (cdr org-time-stamp-formats))
+ (car org-time-stamp-formats))))
+ (setq form (replace-match (format-time-string tf tsp) t t form))))
+
(setq ev (if (and duration (string-match "^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" form))
form
- (calc-eval (cons form org-tbl-calc-modes) (if numbers 'num)))
+ (calc-eval (cons form org-tbl-calc-modes)
+ (when (and (not keep-empty) numbers) 'num)))
ev (if duration (org-table-time-seconds-to-string
(if (string-match "^[0-9]+:[0-9]+\\(?::[0-9]+\\)?$" ev)
(string-to-number (org-table-time-string-to-seconds ev))
@@ -2635,7 +2761,7 @@ $1-> %s\n" orig formula form0 form))
(unless (let (inhibit-redisplay)
(y-or-n-p "Debugging Formula. Continue to next? "))
(org-table-align)
- (error "Abort"))
+ (user-error "Abort"))
(delete-window bw)
(message "")))
(if (listp ev) (setq fmt nil ev "#ERROR"))
@@ -2673,7 +2799,7 @@ in the buffer and column1 and column2 are table column numbers."
(let ((thisline (org-current-line))
beg end c1 c2 r1 r2 rangep tmp)
(unless (string-match org-table-range-regexp desc)
- (error "Invalid table range specifier `%s'" desc))
+ (user-error "Invalid table range specifier `%s'" desc))
(setq rangep (match-end 3)
r1 (and (match-end 1) (match-string 1 desc))
r2 (and (match-end 4) (match-string 4 desc))
@@ -2741,7 +2867,7 @@ and TABLE is a vector with line types."
;; 1 2 3 4 5 6
(and (not (match-end 3)) (not (match-end 6)))
(and (match-end 3) (match-end 6) (not (match-end 5))))
- (error "Invalid row descriptor `%s'" desc))
+ (user-error "Invalid row descriptor `%s'" desc))
(let* ((hdir (and (match-end 2) (match-string 2 desc)))
(hn (if (match-end 3) (- (match-end 3) (match-beginning 3)) nil))
(odir (and (match-end 5) (match-string 5 desc)))
@@ -2755,7 +2881,7 @@ and TABLE is a vector with line types."
(setq i 0 hdir "+")
(if (eq (aref table 0) 'hline) (setq hn (1- hn)))))
(if (and (not hn) on (not odir))
- (error "Should never happen");;(aref org-table-dlines on)
+ (user-error "Should never happen");;(aref org-table-dlines on)
(if (and hn (> hn 0))
(setq i (org-table-find-row-type table i 'hline (equal hdir "-")
nil hn cline desc)))
@@ -2775,41 +2901,56 @@ and TABLE is a vector with line types."
(cond
((eq org-table-relative-ref-may-cross-hline t) t)
((eq org-table-relative-ref-may-cross-hline 'error)
- (error "Row descriptor %s used in line %d crosses hline" desc cline))
+ (user-error "Row descriptor %s used in line %d crosses hline" desc cline))
(t (setq i (- i (if backwards -1 1))
n 1)
nil))
t)))
(setq n (1- n)))
(if (or (< i 0) (>= i l))
- (error "Row descriptor %s used in line %d leads outside table"
+ (user-error "Row descriptor %s used in line %d leads outside table"
desc cline)
i)))
(defun org-table-rewrite-old-row-references (s)
(if (string-match "&[-+0-9I]" s)
- (error "Formula contains old &row reference, please rewrite using @-syntax")
+ (user-error "Formula contains old &row reference, please rewrite using @-syntax")
s))
(defun org-table-make-reference (elements keep-empty numbers lispp)
"Convert list ELEMENTS to something appropriate to insert into formula.
KEEP-EMPTY indicated to keep empty fields, default is to skip them.
NUMBERS indicates that everything should be converted to numbers.
-LISPP means to return something appropriate for a Lisp list."
- (if (stringp elements) ; just a single val
+LISPP non-nil means to return something appropriate for a Lisp
+list, 'literal is for the format specifier L."
+ ;; Calc nan (not a number) is used for the conversion of the empty
+ ;; field to a reference for several reasons: (i) It is accepted in a
+ ;; Calc formula (e. g. "" or "()" would result in a Calc error).
+ ;; (ii) In a single field (not in range) it can be distinguished
+ ;; from "(nan)" which is the reference made from a single field
+ ;; containing "nan".
+ (if (stringp elements)
+ ;; field reference
(if lispp
(if (eq lispp 'literal)
elements
- (prin1-to-string (if numbers (string-to-number elements) elements)))
- (if (equal elements "") (setq elements "0"))
- (if numbers (setq elements (number-to-string (string-to-number elements))))
- (concat "(" elements ")"))
+ (if (and (eq elements "") (not keep-empty))
+ ""
+ (prin1-to-string
+ (if numbers (string-to-number elements) elements))))
+ (if (string-match "\\S-" elements)
+ (progn
+ (when numbers (setq elements (number-to-string
+ (string-to-number elements))))
+ (concat "(" elements ")"))
+ (if (or (not keep-empty) numbers) "(0)" "nan")))
+ ;; range reference
(unless keep-empty
(setq elements
(delq nil
(mapcar (lambda (x) (if (string-match "\\S-" x) x nil))
elements))))
- (setq elements (or elements '("0")))
+ (setq elements (or elements '())) ; if delq returns nil then we need '()
(if lispp
(mapconcat
(lambda (x)
@@ -2819,10 +2960,33 @@ LISPP means to return something appropriate for a Lisp list."
elements " ")
(concat "[" (mapconcat
(lambda (x)
- (if numbers (number-to-string (string-to-number x)) x))
+ (if (string-match "\\S-" x)
+ (if numbers
+ (number-to-string (string-to-number x))
+ x)
+ (if (or (not keep-empty) numbers) "0" "nan")))
elements
",") "]"))))
+;;;###autoload
+(defun org-table-set-constants ()
+ "Set `org-table-formula-constants-local' in the current buffer."
+ (let (cst consts const-str)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^[ \t]*#\\+CONSTANTS: \\(.*\\)" nil t)
+ (setq const-str (substring-no-properties (match-string 1)))
+ (setq consts (append consts (org-split-string const-str "[ \t]+")))
+ (when consts
+ (let (e)
+ (while (setq e (pop consts))
+ (when (string-match "^\\([a-zA-Z0][_a-zA-Z0-9]*\\)=\\(.*\\)" e)
+ (if (assoc-string (match-string 1 e) cst)
+ (setq cst (delete (assoc-string (match-string 1 e) cst) cst)))
+ (push (cons (match-string 1 e) (match-string 2 e)) cst)))
+ (setq org-table-formula-constants-local cst)))))))
+
+;;;###autoload
(defun org-table-recalculate (&optional all noalign)
"Recalculate the current table line by applying all stored formulas.
With prefix arg ALL, do this for all lines in the table.
@@ -2835,7 +2999,7 @@ known that the table will be realigned a little later anyway."
(interactive "P")
(or (memq this-command org-recalc-commands)
(setq org-recalc-commands (cons this-command org-recalc-commands)))
- (unless (org-at-table-p) (error "Not at a table"))
+ (unless (org-at-table-p) (user-error "Not at a table"))
(if (or (eq all 'iterate) (equal all '(16)))
(org-table-iterate)
(org-table-get-specials)
@@ -2858,7 +3022,7 @@ known that the table will be realigned a little later anyway."
(car x)) 1)
(cdr x)))
(if (assoc (car x) eqlist1)
- (error "\"%s=\" formula tries to overwrite existing formula for column %s"
+ (user-error "\"%s=\" formula tries to overwrite existing formula for column %s"
lhs1 (car x))))
(cons
(org-table-formula-handle-first/last-rc (car x))
@@ -2903,7 +3067,7 @@ known that the table will be realigned a little later anyway."
(if a (setq name1 (format "@%d$%d" (org-table-line-to-dline (nth 1 a))
(nth 2 a))))
(when (member name1 seen-fields)
- (error "Several field/range formulas try to set %s" name1))
+ (user-error "Several field/range formulas try to set %s" name1))
(push name1 seen-fields)
(and (not a)
@@ -2912,7 +3076,7 @@ known that the table will be realigned a little later anyway."
(condition-case nil
(aref org-table-dlines
(string-to-number (match-string 1 name)))
- (error (error "Invalid row number in %s"
+ (error (user-error "Invalid row number in %s"
name)))
(string-to-number (match-string 2 name)))))
(when (and a (or all (equal (nth 1 a) thisline)))
@@ -2961,6 +3125,7 @@ known that the table will be realigned a little later anyway."
(or noalign (and org-table-may-need-update (org-table-align))
(and all (message "Re-applying formulas...done"))))))
+;;;###autoload
(defun org-table-iterate (&optional arg)
"Recalculate the table until it does not change anymore.
The maximum number of iterations is 10, but you can choose a different value
@@ -2981,7 +3146,7 @@ with the prefix ARG."
(message "Convergence after %d iterations" i)
(message "Table was already stable"))
(throw 'exit t)))
- (error "No convergence after %d iterations" i))))
+ (user-error "No convergence after %d iterations" i))))
;;;###autoload
(defun org-table-recalculate-buffer-tables ()
@@ -2997,10 +3162,9 @@ with the prefix ARG."
"Iterate all tables in the buffer, to converge inter-table dependencies."
(interactive)
(let* ((imax 10)
+ (i imax)
(checksum (md5 (buffer-string)))
-
- c1
- (i imax))
+ c1)
(save-excursion
(save-restriction
(widen)
@@ -3013,7 +3177,40 @@ with the prefix ARG."
(message "Convergence after %d iterations" (- imax i))
(throw 'exit t))
(setq checksum c1)))
- (error "No convergence after %d iterations" imax))))))
+ (user-error "No convergence after %d iterations" imax))))))
+
+(defun org-table-calc-current-TBLFM (&optional arg)
+ "Apply the #+TBLFM in the line at point to the table."
+ (interactive "P")
+ (unless (org-at-TBLFM-p) (user-error "Not at a #+TBLFM line"))
+ (let ((formula (buffer-substring
+ (point-at-bol)
+ (point-at-eol)))
+ s e)
+ (save-excursion
+ ;; Insert a temporary formula at right after the table
+ (goto-char (org-table-TBLFM-begin))
+ (setq s (set-marker (make-marker) (point)))
+ (insert (concat formula "\n"))
+ (setq e (set-marker (make-marker) (point)))
+ ;; Recalculate the table
+ (beginning-of-line 0) ; move to the inserted line
+ (skip-chars-backward " \r\n\t")
+ (if (org-at-table-p)
+ (unwind-protect
+ (org-call-with-arg 'org-table-recalculate (or arg t))
+ ;; delete the formula inserted temporarily
+ (delete-region s e))))))
+
+(defun org-table-TBLFM-begin ()
+ "Find the beginning of the TBLFM lines and return its position.
+Return nil when the beginning of TBLFM line was not found."
+ (save-excursion
+ (when (progn (forward-line 1)
+ (re-search-backward
+ org-table-TBLFM-begin-regexp
+ nil t))
+ (point-at-bol 2))))
(defun org-table-expand-lhs-ranges (equations)
"Expand list of formulas.
@@ -3071,7 +3268,7 @@ borders of the table using the @< @> $< $> makers."
len
(- nmax len -1)))
(if (or (< n 1) (> n nmax))
- (error "Reference \"%s\" in expression \"%s\" points outside table"
+ (user-error "Reference \"%s\" in expression \"%s\" points outside table"
(match-string 0 s) s))
(setq start (match-beginning 0))
(setq s (replace-match (format "%s%d" (match-string 1 s) n) t t s)))))
@@ -3164,17 +3361,18 @@ Parameters get priority."
(defvar org-pos)
+;;;###autoload
(defun org-table-edit-formulas ()
"Edit the formulas of the current table in a separate buffer."
(interactive)
(when (save-excursion (beginning-of-line 1) (let ((case-fold-search t)) (looking-at "[ \t]*#\\+TBLFM")))
(beginning-of-line 0))
- (unless (org-at-table-p) (error "Not at a table"))
+ (unless (org-at-table-p) (user-error "Not at a table"))
(org-table-get-specials)
(let ((key (org-table-current-field-formula 'key 'noerror))
(eql (sort (org-table-get-stored-formulas 'noerror)
'org-table-formula-less-p))
- (pos (move-marker (make-marker) (point)))
+ (pos (point-marker))
(startline 1)
(wc (current-window-configuration))
(sel-win (selected-window))
@@ -3391,7 +3589,7 @@ minutes or seconds."
((org-at-regexp-p "\\(\\<[a-zA-Z]\\)&")
(if (memq dir '(left right))
(org-rematch-and-replace 1 (eq dir 'left))
- (error "Cannot shift reference in this direction")))
+ (user-error "Cannot shift reference in this direction")))
((org-at-regexp-p "\\(\\<[a-zA-Z]\\{1,2\\}\\)\\([0-9]+\\)")
;; A B3-like reference
(if (memq dir '(up down))
@@ -3406,7 +3604,7 @@ minutes or seconds."
(defun org-rematch-and-replace (n &optional decr hline)
"Re-match the group N, and replace it with the shifted reference."
- (or (match-end n) (error "Cannot shift reference in this direction"))
+ (or (match-end n) (user-error "Cannot shift reference in this direction"))
(goto-char (match-beginning n))
(and (looking-at (regexp-quote (match-string n)))
(replace-match (org-table-shift-refpart (match-string 0) decr hline)
@@ -3442,7 +3640,7 @@ a translation reference."
(org-number-to-letters
(max 1 (+ (org-letters-to-number ref) (if decr -1 1)))))
- (t (error "Cannot shift reference"))))))
+ (t (user-error "Cannot shift reference"))))))
(defun org-table-fedit-toggle-coordinates ()
"Toggle the display of coordinates in the referenced table."
@@ -3474,14 +3672,14 @@ With prefix ARG, apply the new formulas to the table."
(while (string-match "[ \t]*\n[ \t]*" form)
(setq form (replace-match " " t t form)))
(when (assoc var eql)
- (error "Double formulas for %s" var))
+ (user-error "Double formulas for %s" var))
(push (cons var form) eql)))
(setq org-pos nil)
(set-window-configuration org-window-configuration)
(select-window sel-win)
(goto-char pos)
(unless (org-at-table-p)
- (error "Lost table position - cannot install formulas"))
+ (user-error "Lost table position - cannot install formulas"))
(org-table-store-formulas eql)
(move-marker pos nil)
(kill-buffer "*Edit Formulas*")
@@ -3511,14 +3709,14 @@ With prefix ARG, apply the new formulas to the table."
(call-interactively 'lisp-indent-line))
((looking-at "[$&@0-9a-zA-Z]+ *= *[^ \t\n']") (goto-char pos))
((not (fboundp 'pp-buffer))
- (error "Cannot pretty-print. Command `pp-buffer' is not available"))
+ (user-error "Cannot pretty-print. Command `pp-buffer' is not available"))
((looking-at "[$&@0-9a-zA-Z]+ *= *'(")
(goto-char (- (match-end 0) 2))
(setq beg (point))
(setq ind (make-string (current-column) ?\ ))
(condition-case nil (forward-sexp 1)
(error
- (error "Cannot pretty-print Lisp expression: Unbalanced parenthesis")))
+ (user-error "Cannot pretty-print Lisp expression: Unbalanced parenthesis")))
(setq end (point))
(save-restriction
(narrow-to-region beg end)
@@ -3535,7 +3733,7 @@ With prefix ARG, apply the new formulas to the table."
(beginning-of-line 1)
(insert ind))
(goto-char (point-max))
- (backward-delete-char 1)))
+ (org-delete-backward-char 1)))
(goto-char beg))
(t nil))))
@@ -3570,7 +3768,7 @@ With prefix ARG, apply the new formulas to the table."
((org-at-regexp-p "\\$[a-zA-Z][a-zA-Z0-9]*") 'name)
((org-at-regexp-p "\\$[0-9]+") 'column)
((not local) nil)
- (t (error "No reference at point")))
+ (t (user-error "No reference at point")))
match (and what (or match (match-string 0))))
(when (and match (not (equal (match-beginning 0) (point-at-bol))))
(org-table-add-rectangle-overlay (match-beginning 0) (match-end 0)
@@ -3637,7 +3835,7 @@ With prefix ARG, apply the new formulas to the table."
(goto-char (match-beginning 1))
(org-table-highlight-rectangle)
(message "Named column (column %s)" (cdr e)))
- (error "Column name not found")))
+ (user-error "Column name not found")))
((eq what 'column)
;; column number
(org-table-goto-column (string-to-number (substring match 1)))
@@ -3650,10 +3848,10 @@ With prefix ARG, apply the new formulas to the table."
(goto-char (match-beginning 1))
(org-table-highlight-rectangle)
(message "Local parameter."))
- (error "Parameter not found")))
+ (user-error "Parameter not found")))
(t
(cond
- ((not var) (error "No reference at point"))
+ ((not var) (user-error "No reference at point"))
((setq e (assoc var org-table-formula-constants-local))
(message "Local Constant: $%s=%s in #+CONSTANTS line."
var (cdr e)))
@@ -3663,7 +3861,7 @@ With prefix ARG, apply the new formulas to the table."
((setq e (and (fboundp 'constants-get) (constants-get var)))
(message "Constant: $%s=%s, from `constants.el'%s."
var e (format " (%s units)" constants-unit-system)))
- (t (error "Undefined name $%s" var)))))
+ (t (user-error "Undefined name $%s" var)))))
(goto-char pos)
(when (and org-show-positions
(not (memq this-command '(org-table-fedit-scroll
@@ -3689,7 +3887,7 @@ With prefix ARG, apply the new formulas to the table."
(goto-char (if (< (abs (- p1 (point))) (abs (- p2 (point))))
p1 p2)))
((or p1 p2) (goto-char (or p1 p2)))
- (t (error "No table dataline around here"))))))
+ (t (user-error "No table dataline around here"))))))
(defun org-table-fedit-line-up ()
"Move cursor one line up in the window showing the table."
@@ -3801,6 +3999,7 @@ Use COMMAND to do the motion, repeat if necessary to end up in a data line."
(org-overlay-display ov str 'org-special-keyword 'evaporate)))
(beginning-of-line 2)))))
+;;;###autoload
(defun org-table-toggle-coordinate-overlays ()
"Toggle the display of Row/Column numbers in tables."
(interactive)
@@ -3813,6 +4012,7 @@ Use COMMAND to do the motion, repeat if necessary to end up in a data line."
(mapc 'delete-overlay org-table-coordinate-overlays)
(setq org-table-coordinate-overlays nil)))
+;;;###autoload
(defun org-table-toggle-formula-debugger ()
"Toggle the formula debugger in tables."
(interactive)
@@ -3852,11 +4052,6 @@ Use COMMAND to do the motion, repeat if necessary to end up in a data line."
(defvar orgtbl-mode-map (make-keymap)
"Keymap for `orgtbl-mode'.")
-;;;###autoload
-(defun turn-on-orgtbl ()
- "Unconditionally turn on `orgtbl-mode'."
- (orgtbl-mode 1))
-
(defvar org-old-auto-fill-inhibit-regexp nil
"Local variable used by `orgtbl-mode'.")
@@ -3957,7 +4152,7 @@ to execute outside of tables."
(defun orgtbl-error ()
"Error when there is no default binding for a table key."
(interactive)
- (error "This key has no function outside tables"))
+ (user-error "This key has no function outside tables"))
(defun orgtbl-setup ()
"Setup orgtbl keymaps."
@@ -4109,7 +4304,7 @@ to execute outside of tables."
If it is a table to be sent away to a receiver, do it.
With prefix arg, also recompute table."
(interactive "P")
- (let ((case-fold-search t) (pos (point)) action consts-str consts cst const-str)
+ (let ((case-fold-search t) (pos (point)) action)
(save-excursion
(beginning-of-line 1)
(setq action (cond
@@ -4127,17 +4322,7 @@ With prefix arg, also recompute table."
(when (orgtbl-send-table 'maybe)
(run-hooks 'orgtbl-after-send-table-hook)))
((eq action 'recalc)
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^[ \t]*#\\+CONSTANTS: \\(.*\\)" nil t)
- (setq const-str (substring-no-properties (match-string 1)))
- (setq consts (append consts (org-split-string const-str "[ \t]+")))
- (when consts
- (let (e)
- (while (setq e (pop consts))
- (if (string-match "^\\([a-zA-Z0][_a-zA-Z0-9]*\\)=\\(.*\\)" e)
- (push (cons (match-string 1 e) (match-string 2 e)) cst)))
- (setq org-table-formula-constants-local cst)))))
+ (org-table-set-constants)
(save-excursion
(beginning-of-line 1)
(skip-chars-backward " \r\n\t")
@@ -4193,7 +4378,7 @@ overwritten, and the table is not marked as requiring realignment."
(looking-at "[^|\n]* +|"))
(let (org-table-may-need-update)
(goto-char (1- (match-end 0)))
- (backward-delete-char 1)
+ (org-delete-backward-char 1)
(goto-char (match-beginning 0))
(self-insert-command N))
(setq org-table-may-need-update t)
@@ -4223,13 +4408,12 @@ overwritten, and the table is not marked as requiring realignment."
"Regular expression matching exponentials as produced by calc.")
(defun orgtbl-export (table target)
- (require 'org-exp)
(let ((func (intern (concat "orgtbl-to-" (symbol-name target))))
(lines (org-split-string table "[ \t]*\n[ \t]*"))
org-table-last-alignment org-table-last-column-widths
maxcol column)
(if (not (fboundp func))
- (error "Cannot export orgtbl table to %s" target))
+ (user-error "Cannot export orgtbl table to %s" target))
(setq lines (org-table-clean-before-export lines))
(setq table
(mapcar
@@ -4270,14 +4454,14 @@ a radio table."
(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"))
+ (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)
- (error "Cannot find end of insertion region"))
+ (user-error "Cannot find end of insertion region"))
(beginning-of-line 1)
(delete-region beg (point))))
(insert txt "\n")))
@@ -4290,7 +4474,7 @@ 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)
- (error "No table at point")))
+ (user-error "No table at point")))
(let* ((txt (or txt
(buffer-substring-no-properties (org-table-begin)
(org-table-end))))
@@ -4309,7 +4493,7 @@ With argument MAYBE, fail quietly if no transformation is defined for
this table."
(interactive)
(catch 'exit
- (unless (org-at-table-p) (error "Not at a table"))
+ (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))
@@ -4317,7 +4501,7 @@ this table."
(org-table-end)))
(ntbl 0))
(unless dests (if maybe (throw 'exit nil)
- (error "Don't know how to transform this table")))
+ (user-error "Don't know how to transform this table")))
(dolist (dest dests)
(let* ((name (plist-get dest :name))
(transform (plist-get dest :transform))
@@ -4350,7 +4534,7 @@ this table."
skipcols i0))
(txt (if (fboundp transform)
(funcall transform table params)
- (error "No such transformation function %s" transform))))
+ (user-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"
@@ -4380,7 +4564,7 @@ First element has index 0, or I0 if given."
(commented (save-excursion (beginning-of-line 1)
(cond ((looking-at re1) t)
((looking-at re2) nil)
- (t (error "Not at an org table")))))
+ (t (user-error "Not at an org table")))))
(re (if commented re1 re2))
beg end)
(save-excursion
@@ -4398,7 +4582,7 @@ First element has index 0, or I0 if given."
(let* ((e (assq major-mode orgtbl-radio-table-templates))
(txt (nth 1 e))
name pos)
- (unless e (error "No radio table setup defined for %s" major-mode))
+ (unless e (user-error "No radio table setup defined for %s" major-mode))
(setq name (read-string "Table name: "))
(while (string-match "%n" txt)
(setq txt (replace-match name t t txt)))
@@ -4432,7 +4616,8 @@ First element has index 0, or I0 if given."
fmt))
(defsubst orgtbl-apply-fmt (fmt &rest args)
- "Apply format FMT to the arguments. NIL FMTs return the first argument."
+ "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))
@@ -4462,7 +4647,7 @@ First element has index 0, or I0 if given."
f)))
line)))
(push (if *orgtbl-lfmt*
- (orgtbl-apply-fmt *orgtbl-lfmt* line)
+ (apply #'orgtbl-apply-fmt *orgtbl-lfmt* line)
(concat (orgtbl-eval-str *orgtbl-lstart*)
(mapconcat 'identity line *orgtbl-sep*)
(orgtbl-eval-str *orgtbl-lend*)))
@@ -4480,12 +4665,16 @@ First element has index 0, or I0 if given."
(*orgtbl-lfmt* *orgtbl-llfmt*))
(orgtbl-format-line prevline))))))
-(defun orgtbl-to-generic (table params)
+;;;###autoload
+(defun orgtbl-to-generic (table params &optional backend)
"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).
@@ -4556,22 +4745,31 @@ directly by `orgtbl-send-table'. See manual."
(*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*)))))
-
- ;; Do we have a heading section? If so, format it and handle the
- ;; trailing hline.
+ ;; 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
+ ;; 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)
@@ -4589,15 +4787,12 @@ directly by `orgtbl-send-table'. See manual."
(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))
@@ -4606,9 +4801,11 @@ directly by `orgtbl-send-table'. See manual."
(remq nil *orgtbl-rtn*)
*orgtbl-rtn*)) "\n")))
+;;;###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."
@@ -4616,6 +4813,7 @@ This does take care of the proper quoting of fields with comma or quotes."
'(: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
@@ -4652,8 +4850,10 @@ this function is called."
:tend "\\end{tabular}"
:lstart "" :lend " \\\\" :sep " & "
:efmt "%s\\,(%s)" :hline "\\hline")))
- (orgtbl-to-generic table (org-combine-plists params2 params))))
+ (require 'ox-latex)
+ (orgtbl-to-generic table (org-combine-plists params2 params) 'latex)))
+;;;###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
@@ -4667,23 +4867,16 @@ Currently this function recognizes the following parameters:
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."
- (let* ((splicep (plist-get params :splice))
- (html-table-tag org-export-html-table-tag)
- html)
- ;; Just call the formatter we already have
- ;; We need to make text lines for it, so put the fields back together.
- (setq html (org-format-org-table-html
- (mapcar
- (lambda (x)
- (if (eq x 'hline)
- "|----+----|"
- (concat "| " (mapconcat 'org-html-expand x " | ") " |")))
- table)
- splicep))
- (if (string-match "\n+\\'" html)
- (setq html (replace-match "" t t html)))
- html))
+ (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))))))
+;;;###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
@@ -4720,8 +4913,10 @@ this function is called."
:tend "@end multitable"
:lstart "@item " :lend "" :sep " @tab "
:hlstart "@headitem ")))
- (orgtbl-to-generic table (org-combine-plists params2 params))))
+ (require 'ox-texinfo)
+ (orgtbl-to-generic table (org-combine-plists params2 params) 'texinfo)))
+;;;###autoload
(defun orgtbl-to-orgtbl (table params)
"Convert the orgtbl-mode TABLE into another orgtbl-mode table.
Useful when slicing one table into many. The :hline, :sep,
@@ -4766,22 +4961,22 @@ it here: http://gnuvola.org/software/j/aa2u/ascii-art-to-unicode.el."
(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))
- (error "Please download ascii-art-to-unicode.el (use C-c C-l to insert the link to it)"))
+ (user-error "Please download ascii-art-to-unicode.el (use C-c C-l to insert the link to it)"))
(buffer-string)))
(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.
-NAME-OR-ID may be the name of a table in the current file as set by
-a \"#+TBLNAME:\" directive. The first table following this line
+NAME-OR-ID may be the name of a table in the current file as set
+by a \"#+NAME:\" directive. The first table following this line
will then be used. Alternatively, it may be an ID referring to
-any entry, also in a different file. In this case, the first table
-in that entry will be referenced.
+any entry, also in a different file. In this case, the first
+table in that entry will be referenced.
FORM is a field or range descriptor like \"@2$3\" or \"B3\" or
\"@I$2..@II$2\". All the references must be absolute, not relative.
The return value is either a single string for a single field, or a
-list of the fields in the rectangle ."
+list of the fields in the rectangle."
(save-match-data
(let ((case-fold-search t) (id-loc nil)
;; Protect a bunch of variables from being overwritten
@@ -4802,12 +4997,13 @@ list of the fields in the rectangle ."
(save-excursion
(goto-char (point-min))
(if (re-search-forward
- (concat "^[ \t]*#\\+tblname:[ \t]*" (regexp-quote name-or-id) "[ \t]*$")
+ (concat "^[ \t]*#\\+\\(tbl\\)?name:[ \t]*"
+ (regexp-quote name-or-id) "[ \t]*$")
nil t)
(setq buffer (current-buffer) loc (match-beginning 0))
(setq id-loc (org-id-find name-or-id 'marker))
(unless (and id-loc (markerp id-loc))
- (error "Can't find remote table \"%s\"" name-or-id))
+ (user-error "Can't find remote table \"%s\"" name-or-id))
(setq buffer (marker-buffer id-loc)
loc (marker-position id-loc))
(move-marker id-loc nil)))
@@ -4819,7 +5015,7 @@ list of the fields in the rectangle ."
(forward-char 1)
(unless (and (re-search-forward "^\\(\\*+ \\)\\|[ \t]*|" nil t)
(not (match-beginning 1)))
- (error "Cannot find a table at NAME or ID %s" name-or-id))
+ (user-error "Cannot find a table at NAME or ID %s" name-or-id))
(setq tbeg (point-at-bol))
(org-table-get-specials)
(setq form (org-table-formula-substitute-names
@@ -4830,6 +5026,42 @@ list of the fields in the rectangle ."
(org-table-get-range (match-string 0 form) tbeg 1))
form)))))))))
+(defmacro org-define-lookup-function (mode)
+ (let ((mode-str (symbol-name mode))
+ (first-p (equal mode 'first))
+ (all-p (equal mode 'all)))
+ (let ((plural-str (if all-p "s" "")))
+ `(defun ,(intern (format "org-lookup-%s" mode-str)) (val s-list r-list &optional predicate)
+ ,(format "Find %s occurrence%s of VAL in S-LIST; return corresponding element%s of R-LIST.
+If R-LIST is nil, return matching element%s of S-LIST.
+If PREDICATE is not nil, use it instead of `equal' to match VAL.
+Matching is done by (PREDICATE VAL S), where S is an element of S-LIST.
+This function is generated by a call to the macro `org-define-lookup-function'."
+ mode-str plural-str plural-str plural-str)
+ (let ,(let ((lvars '((p (or predicate 'equal))
+ (sl s-list)
+ (rl (or r-list s-list))
+ (ret nil))))
+ (if first-p (add-to-list 'lvars '(match-p nil)))
+ lvars)
+ (while ,(if first-p '(and (not match-p) sl) 'sl)
+ (progn
+ (if (funcall p val (car sl))
+ (progn
+ ,(if first-p '(setq match-p t))
+ (let ((rval (car rl)))
+ (setq ret ,(if all-p '(append ret (list rval)) 'rval)))))
+ (setq sl (cdr sl) rl (cdr rl))))
+ ret)))))
+
+(org-define-lookup-function first)
+(org-define-lookup-function last)
+(org-define-lookup-function all)
+
(provide 'org-table)
+;; Local variables:
+;; generated-autoload-file: "org-loaddefs.el"
+;; End:
+
;;; org-table.el ends here