From e32a45ed36d6000db4b39171149072d11b77af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Delafond?= Date: Sun, 13 Jul 2014 13:35:27 +0200 Subject: Imported Upstream version 8.0.7 --- lisp/org-table.el | 584 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 408 insertions(+), 176 deletions(-) (limited to 'lisp/org-table.el') 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 ;; 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 '("<" "<")) :start) + ((member x '(">" ">")) :end) + ((member x '("<>" "<>")) :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 '("<" "<")) :start) + ((member x '(">" ">")) :end) + ((member x '("<>" "<>")) :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 + "\\`\n" "" + (replace-regexp-in-string "
\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 -- cgit v1.2.3