summaryrefslogtreecommitdiff
path: root/lisp/org/org-table.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/org/org-table.el')
-rw-r--r--lisp/org/org-table.el546
1 files changed, 312 insertions, 234 deletions
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index 49765472558..8dd3f392d2d 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -40,6 +40,8 @@
(require 'org-keys)
(declare-function calc-eval "calc" (str &optional separator &rest args))
+(declare-function face-remap-remove-relative "face-remap" (cookie))
+(declare-function face-remap-add-relative "face-remap" (face &rest specs))
(declare-function org-at-timestamp-p "org" (&optional extended))
(declare-function org-delete-backward-char "org" (N))
(declare-function org-element-at-point "org-element" ())
@@ -164,6 +166,12 @@ table, obtained by prompting the user."
:tag "Org Table Settings"
:group 'org-table)
+(defcustom org-table-header-line-p nil
+ "Activate `org-table-header-line-mode' by default?"
+ :type 'boolean
+ :package-version '(Org . "9.4")
+ :group 'org-table)
+
(defcustom org-table-default-size "5x2"
"The default size for newly created tables, Columns x Rows."
:group 'org-table-settings
@@ -198,7 +206,7 @@ Other options offered by the customize interface are more restrictive."
"^\\([<>]?[-+^.0-9]*[0-9][-+^.0-9eEdDx()%]*\\|[<>]?[-+]?0[xX][[:xdigit:].]+\\|[<>]?[-+]?[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][[:xdigit:].]+\\|[<>]?[-+]?[0-9]+#[0-9a-zA-Z.]+\\|nan\\|[-+u]?inf\\)$")
- (string :tag "Regexp:")))
+ (regexp :tag "Regexp:")))
(defcustom org-table-number-fraction 0.5
"Fraction of numbers in a column required to make the column align right.
@@ -442,6 +450,59 @@ prevents it from hanging Emacs."
:package-version '(Org . "8.3"))
+;;; Org table header minor mode
+(defun org-table-row-get-visible-string (&optional pos)
+ "Get the visible string of a table row.
+This may be useful when columns have been shrunk."
+ (save-excursion
+ (when pos (goto-char pos))
+ (goto-char (line-beginning-position))
+ (let ((end (line-end-position)) str)
+ (while (progn (forward-char 1) (< (point) end))
+ (let ((ov (car (overlays-at (point)))))
+ (if (not ov)
+ (push (char-to-string (char-after)) str)
+ (push (overlay-get ov 'display) str)
+ (goto-char (1- (overlay-end ov))))))
+ (format "|%s" (mapconcat #'identity (reverse str) "")))))
+
+(defvar-local org-table-header-overlay nil)
+(defun org-table-header-set-header ()
+ "Display the header of the table at point."
+ (when (overlayp org-table-header-overlay)
+ (delete-overlay org-table-header-overlay))
+ (let* ((ws (window-start))
+ (beg (save-excursion
+ (goto-char (org-table-begin))
+ (while (or (org-at-table-hline-p)
+ (looking-at-p ".*|\\s-+<[rcl]?\\([0-9]+\\)?>"))
+ (move-beginning-of-line 2))
+ (point)))
+ (end (save-excursion (goto-char beg) (point-at-eol))))
+ (if (pos-visible-in-window-p beg)
+ (when (overlayp org-table-header-overlay)
+ (delete-overlay org-table-header-overlay))
+ (setq org-table-header-overlay
+ (make-overlay ws (+ ws (- end beg))))
+ (org-overlay-display
+ org-table-header-overlay
+ (org-table-row-get-visible-string beg)
+ 'org-table-header))))
+
+;;;###autoload
+(define-minor-mode org-table-header-line-mode
+ "Display the first row of the table at point in the header line."
+ nil " TblHeader" nil
+ (unless (eq major-mode 'org-mode)
+ (user-error "Cannot turn org table header mode outside org-mode buffers"))
+ (if org-table-header-line-mode
+ (add-hook 'post-command-hook #'org-table-header-set-header nil t)
+ (when (overlayp org-table-header-overlay)
+ (delete-overlay org-table-header-overlay)
+ (setq org-table-header-overlay nil))
+ (remove-hook 'post-command-hook #'org-table-header-set-header t)))
+
+
;;; Regexps Constants
(defconst org-table-any-line-regexp "^[ \t]*\\(|\\|\\+-[-+]\\)"
@@ -860,19 +921,22 @@ nil When nil, the command tries to be smart and figure out the
The command tries to be smart and figure out the separator in the
following way:
- - when each line contains a TAB, assume TAB-separated material
- - when each line contains a comma, assume CSV material
- - else, assume one or more SPACE characters as separator.
+- when each line contains a TAB, assume TAB-separated material;
+- when each line contains a comma, assume CSV material;
+- else, assume one or more SPACE characters as separator.
When non-nil, SEPARATOR specifies the field separator in the
lines. It can have the following values:
-(4) Use the comma as a field separator
-(16) Use a TAB as field separator
-(64) Prompt for a regular expression as field separator
-integer When a number, use that many spaces, or a TAB, as field separator
-regexp When a regular expression, use it to match the separator."
+- (4) Use the comma as a field separator.
+- (16) Use a TAB as field separator.
+- (64) Prompt for a regular expression as field separator.
+- integer When a number, use that many spaces, or a TAB, as field separator.
+- regexp When a regular expression, use it to match the separator."
(interactive "f\nP")
+ (when (and (called-interactively-p 'any)
+ (not (string-match-p (rx "." (or "txt" "tsv" "csv") eos) file)))
+ (user-error "Cannot import such file"))
(unless (bolp) (insert "\n"))
(let ((beg (point))
(pm (point-max)))
@@ -1181,7 +1245,7 @@ value."
(save-excursion
(let* ((pos (point))
(col (org-table-current-column))
- (cname (car (rassoc (int-to-string col) org-table-column-names)))
+ (cname (car (rassoc (number-to-string col) org-table-column-names)))
(name (car (rassoc (list (count-lines org-table-current-begin-pos
(line-beginning-position))
col)
@@ -1290,25 +1354,20 @@ However, when FORCE is non-nil, create new columns if necessary."
(while (< (point) end)
(unless (org-at-table-hline-p)
(org-table-goto-column col t)
- (unless (search-forward "|" (line-end-position) t 2)
- ;; Add missing vertical bar at the end of the row.
- (end-of-line)
- (insert "|"))
- (insert " |"))
+ (insert "|"))
(forward-line)))
- (org-table-goto-column (1+ col))
+ (org-table-goto-column col)
(org-table-align)
;; Shift appropriately stored shrunk column numbers, then hide the
;; columns again.
- (org-table--shrink-columns (mapcar (lambda (c) (if (<= c col) c (1+ c)))
+ (org-table--shrink-columns (mapcar (lambda (c) (if (< c col) c (1+ c)))
shrunk-columns)
beg end)
(set-marker end nil)
;; Fix TBLFM formulas, if desirable.
(when (or (not org-table-fix-formulas-confirm)
(funcall org-table-fix-formulas-confirm "Fix formulas? "))
- (org-table-fix-formulas "$" nil (1- col) 1)
- (org-table-fix-formulas "$LR" nil (1- col) 1))))
+ (org-table-fix-formulas "$" nil (1- col) 1))))
(defun org-table-find-dataline ()
"Find a data line in the current table, which is needed for column commands.
@@ -1431,6 +1490,8 @@ Swap with anything in target cell."
(interactive)
(unless (org-at-table-p) (user-error "Not at a table"))
(org-table-find-dataline)
+ (when (save-excursion (skip-chars-forward " \t") (eolp))
+ (search-backward "|")) ;snap into last column
(org-table-check-inside-data-field nil t)
(let* ((col (org-table-current-column))
(beg (org-table-begin))
@@ -1446,7 +1507,6 @@ Swap with anything in target cell."
(and (looking-at "|[^|\n]+|")
(replace-match "|")))
(forward-line)))
- (org-table-goto-column (max 1 (1- col)))
(org-table-align)
;; Shift appropriately stored shrunk column numbers, then hide the
;; columns again.
@@ -1458,9 +1518,7 @@ Swap with anything in target cell."
(when (or (not org-table-fix-formulas-confirm)
(funcall org-table-fix-formulas-confirm "Fix formulas? "))
(org-table-fix-formulas
- "$" (list (cons (number-to-string col) "INVALID")) col -1 col)
- (org-table-fix-formulas
- "$LR" (list (cons (number-to-string col) "INVALID")) col -1 col))))
+ "$" (list (cons (number-to-string col) "INVALID")) col -1 col))))
;;;###autoload
(defun org-table-move-column-right ()
@@ -1521,11 +1579,7 @@ Swap with anything in target cell."
(funcall org-table-fix-formulas-confirm "Fix formulas? "))
(org-table-fix-formulas
"$" (list (cons (number-to-string col) (number-to-string colpos))
- (cons (number-to-string colpos) (number-to-string col))))
- (org-table-fix-formulas
- "$LR" (list
- (cons (number-to-string col) (number-to-string colpos))
- (cons (number-to-string colpos) (number-to-string col))))))))
+ (cons (number-to-string colpos) (number-to-string col))))))))
;;;###autoload
(defun org-table-move-row-down ()
@@ -1958,9 +2012,9 @@ toggle `org-table-follow-field-mode'."
(coord
(if (eq org-table-use-standard-references t)
(concat (org-number-to-letters (org-table-current-column))
- (int-to-string (org-table-current-dline)))
- (concat "@" (int-to-string (org-table-current-dline))
- "$" (int-to-string (org-table-current-column)))))
+ (number-to-string (org-table-current-dline)))
+ (concat "@" (number-to-string (org-table-current-dline))
+ "$" (number-to-string (org-table-current-column)))))
(field (org-table-get-field))
(cw (current-window-configuration))
p)
@@ -2005,7 +2059,7 @@ the table and kill the editing buffer."
text)
(goto-char (point-min))
(while (re-search-forward "^#.*\n?" nil t) (replace-match ""))
- (while (re-search-forward "\\([ \t]*\n[ \t]*\\)+" nil t)
+ (while (re-search-forward "[ \t]*\n[ \t\n]*" nil t)
(replace-match " "))
(setq text (org-trim (buffer-string)))
(set-window-configuration cw)
@@ -2060,7 +2114,7 @@ When NAMED is non-nil, look for a named equation."
(org-table-current-column)))
(scol (cond
((not named) (format "$%d" (org-table-current-column)))
- ((and name (not (string-match "\\`LR[0-9]+\\'" name))) name)
+ (name)
(t ref)))
(name (or name ref))
(org-table-may-need-update nil)
@@ -2193,11 +2247,10 @@ For all numbers larger than LIMIT, shift them by DELTA."
(save-excursion
(goto-char (org-table-end))
(while (let ((case-fold-search t)) (looking-at "[ \t]*#\\+tblfm:"))
- (let ((msg "The formulas in #+TBLFM have been updated")
- (re (concat key "\\([0-9]+\\)"))
+ (let ((re (concat key "\\([0-9]+\\)"))
(re2
(when remove
- (if (or (equal key "$") (equal key "$LR"))
+ (if (equal key "$")
(format "\\(@[0-9]+\\)?%s%d=.*?\\(::\\|$\\)"
(regexp-quote key) remove)
(format "@%d\\$[0-9]+=.*?\\(::\\|$\\)" remove))))
@@ -2215,11 +2268,10 @@ For all numbers larger than LIMIT, shift them by DELTA."
(setq s (match-string 1) n (string-to-number s))
(cond
((setq a (assoc s replace))
- (replace-match (concat key (cdr a)) t t)
- (message msg))
+ (replace-match (concat key (cdr a)) t t))
((and limit (> n limit))
- (replace-match (concat key (int-to-string (+ n delta))) t t)
- (message msg))))))
+ (replace-match (concat key (number-to-string (+ n delta))) t t)))))
+ (message "The formulas in #+TBLFM have been updated"))
(forward-line))))
;;;###autoload
@@ -2547,7 +2599,8 @@ location of point."
ev (if (numberp ev) (number-to-string ev) ev)
ev (if duration (org-table-time-seconds-to-string
(string-to-number ev)
- duration-output-format) ev))
+ duration-output-format)
+ ev))
;; Use <...> time-stamps so that Calc can handle them.
(setq form
@@ -2578,27 +2631,29 @@ location of point."
ev)))
(when org-table-formula-debug
- (with-output-to-temp-buffer "*Substitution History*"
- (princ (format "Substitution history of formula
+ (let ((wcf (current-window-configuration)))
+ (with-output-to-temp-buffer "*Substitution History*"
+ (princ (format "Substitution history of formula
Orig: %s
$xyz-> %s
@r$c-> %s
$1-> %s\n" orig formula form0 form))
- (if (consp ev)
- (princ (format " %s^\nError: %s"
- (make-string (car ev) ?\-) (nth 1 ev)))
- (princ (format "Result: %s\nFormat: %s\nFinal: %s"
- ev (or fmt "NONE")
- (if fmt (format fmt (string-to-number ev)) ev)))))
- (setq bw (get-buffer-window "*Substitution History*"))
- (org-fit-window-to-buffer bw)
- (unless (and (called-interactively-p 'any) (not ndown))
- (unless (let (inhibit-redisplay)
- (y-or-n-p "Debugging Formula. Continue to next? "))
- (org-table-align)
- (user-error "Abort"))
- (delete-window bw)
- (message "")))
+ (if (consp ev)
+ (princ (format " %s^\nError: %s"
+ (make-string (car ev) ?\-) (nth 1 ev)))
+ (princ (format "Result: %s\nFormat: %s\nFinal: %s"
+ ev (or fmt "NONE")
+ (if fmt (format fmt (string-to-number ev)) ev)))))
+ (setq bw (get-buffer-window "*Substitution History*"))
+ (org-fit-window-to-buffer bw)
+ (unless (and (called-interactively-p 'any) (not ndown))
+ (unless (let (inhibit-redisplay)
+ (y-or-n-p "Debugging Formula. Continue to next? "))
+ (org-table-align)
+ (user-error "Abort"))
+ (delete-window bw)
+ (message "")
+ (set-window-configuration wcf))))
(when (consp ev) (setq fmt nil ev "#ERROR"))
(org-table-justify-field-maybe
(format org-table-formula-field-format
@@ -3099,7 +3154,7 @@ function assumes the table is already analyzed (i.e., using
(let ((lhs (car e))
(rhs (cdr e)))
(cond
- ((string-match-p "\\`@-?[-+0-9]+\\$-?[0-9]+\\'" lhs)
+ ((string-match-p "\\`@[-+0-9]+\\$-?[0-9]+\\'" lhs)
;; This just refers to one fixed field.
(push e res))
((string-match-p "\\`[a-zA-Z][_a-zA-Z0-9]*\\'" lhs)
@@ -3287,7 +3342,6 @@ Parameters get priority."
(setq-local org-selected-window sel-win)
(use-local-map org-table-fedit-map)
(add-hook 'post-command-hook #'org-table-fedit-post-command t t)
- (easy-menu-add org-table-fedit-menu)
(setq startline (org-current-line))
(dolist (entry eql)
(let* ((type (cond
@@ -3768,14 +3822,16 @@ FACE, when non-nil, for the highlight."
(defun org-table-toggle-coordinate-overlays ()
"Toggle the display of Row/Column numbers in tables."
(interactive)
- (setq org-table-overlay-coordinates (not org-table-overlay-coordinates))
- (message "Tables Row/Column numbers display turned %s"
- (if org-table-overlay-coordinates "on" "off"))
- (when (and (org-at-table-p) org-table-overlay-coordinates)
- (org-table-align))
- (unless org-table-overlay-coordinates
- (mapc 'delete-overlay org-table-coordinate-overlays)
- (setq org-table-coordinate-overlays nil)))
+ (if (not (org-at-table-p))
+ (user-error "Not on a table")
+ (setq org-table-overlay-coordinates (not org-table-overlay-coordinates))
+ (when (and (org-at-table-p) org-table-overlay-coordinates)
+ (org-table-align))
+ (unless org-table-overlay-coordinates
+ (mapc 'delete-overlay org-table-coordinate-overlays)
+ (setq org-table-coordinate-overlays nil))
+ (message "Tables Row/Column numbers display turned %s"
+ (if org-table-overlay-coordinates "on" "off"))))
;;;###autoload
(defun org-table-toggle-formula-debugger ()
@@ -4239,7 +4295,8 @@ extension of the given file name, and finally on the variable
(and (string-match-p fileext f) f))
formats)))
org-table-export-default-format)
- t t) t t)))
+ t t)
+ t t)))
(setq format
(org-completing-read
"Format: " formats nil nil deffmt-readable))))
@@ -4247,9 +4304,7 @@ extension of the given file name, and finally on the variable
(let ((transform (intern (match-string 1 format)))
(params (and (match-end 2)
(read (concat "(" (match-string 2 format) ")"))))
- (table (org-table-to-lisp
- (buffer-substring-no-properties
- (org-table-begin) (org-table-end)))))
+ (table (org-table-to-lisp)))
(unless (fboundp transform)
(user-error "No such transformation function %s" transform))
(let (buf)
@@ -4293,78 +4348,79 @@ FIELD is a string. WIDTH is a number. ALIGN is either \"c\",
(move-marker org-table-aligned-end-marker end)
(goto-char beg)
(org-table-with-shrunk-columns
- (let* ((indent (progn (looking-at "[ \t]*") (match-string 0)))
- ;; Table's rows as lists of fields. Rules are replaced
- ;; by nil. Trailing spaces are removed.
- (fields (mapcar
- (lambda (l)
- (and (not (string-match-p org-table-hline-regexp l))
- (org-split-string l "[ \t]*|[ \t]*")))
- (split-string (buffer-substring beg end) "\n" t)))
- ;; Compute number of columns. If the table contains no
- ;; field, create a default table and bail out.
- (columns-number
- (if fields (apply #'max (mapcar #'length fields))
- (kill-region beg end)
- (org-table-create org-table-default-size)
- (user-error "Empty table - created default table")))
+ (let* ((table (org-table-to-lisp))
+ (rows (remq 'hline table))
(widths nil)
- (alignments nil))
- ;; Compute alignment and width for each column.
- (dotimes (i columns-number)
- (let* ((max-width 1)
- (fixed-align? nil)
- (numbers 0)
- (non-empty 0))
- (dolist (row fields)
- (let ((cell (or (nth i row) "")))
- (setq max-width (max max-width (org-string-width cell)))
- (cond (fixed-align? nil)
- ((equal cell "") nil)
- ((string-match "\\`<\\([lrc]\\)[0-9]*>\\'" cell)
- (setq fixed-align? (match-string 1 cell)))
- (t
- (cl-incf non-empty)
- (when (string-match-p org-table-number-regexp cell)
- (cl-incf numbers))))))
- (push max-width widths)
- (push (cond
- (fixed-align?)
- ((>= numbers (* org-table-number-fraction non-empty)) "r")
- (t "l"))
- alignments)))
- (setq widths (nreverse widths))
- (setq alignments (nreverse alignments))
+ (alignments nil)
+ (columns-number 1))
+ (if (null rows)
+ ;; Table contains only horizontal rules. Compute the
+ ;; number of columns anyway, and choose an arbitrary width
+ ;; and alignment.
+ (let ((end (line-end-position)))
+ (save-excursion
+ (while (search-forward "+" end t)
+ (cl-incf columns-number)))
+ (setq widths (make-list columns-number 1))
+ (setq alignments (make-list columns-number "l")))
+ ;; Compute alignment and width for each column.
+ (setq columns-number (apply #'max (mapcar #'length rows)))
+ (dotimes (i columns-number)
+ (let ((max-width 1)
+ (fixed-align? nil)
+ (numbers 0)
+ (non-empty 0))
+ (dolist (row rows)
+ (let ((cell (or (nth i row) "")))
+ (setq max-width (max max-width (org-string-width cell)))
+ (cond (fixed-align? nil)
+ ((equal cell "") nil)
+ ((string-match "\\`<\\([lrc]\\)[0-9]*>\\'" cell)
+ (setq fixed-align? (match-string 1 cell)))
+ (t
+ (cl-incf non-empty)
+ (when (string-match-p org-table-number-regexp cell)
+ (cl-incf numbers))))))
+ (push max-width widths)
+ (push (cond
+ (fixed-align?)
+ ((>= numbers (* org-table-number-fraction non-empty)) "r")
+ (t "l"))
+ alignments)))
+ (setq widths (nreverse widths))
+ (setq alignments (nreverse alignments)))
;; Store alignment of this table, for later editing of single
;; fields.
(setq org-table-last-alignment alignments)
(setq org-table-last-column-widths widths)
;; Build new table rows. Only replace rows that actually
;; changed.
- (dolist (row fields)
- (let ((previous (buffer-substring (point) (line-end-position)))
- (new
- (format "%s|%s|"
- indent
- (if (null row) ;horizontal rule
- (mapconcat (lambda (w) (make-string (+ 2 w) ?-))
- widths
- "+")
- (let ((cells ;add missing fields
- (append row
- (make-list (- columns-number
- (length row))
- ""))))
- (mapconcat #'identity
- (cl-mapcar #'org-table--align-field
- cells
- widths
- alignments)
- "|"))))))
- (if (equal new previous)
- (forward-line)
- (insert new "\n")
- (delete-region (point) (line-beginning-position 2)))))
+ (let ((rule (and (memq 'hline table)
+ (mapconcat (lambda (w) (make-string (+ 2 w) ?-))
+ widths
+ "+")))
+ (indent (progn (looking-at "[ \t]*|") (match-string 0))))
+ (dolist (row table)
+ (let ((previous (buffer-substring (point) (line-end-position)))
+ (new
+ (concat indent
+ (if (eq row 'hline) rule
+ (let* ((offset (- columns-number (length row)))
+ (fields (if (= 0 offset) row
+ ;; Add missing fields.
+ (append row
+ (make-list offset "")))))
+ (mapconcat #'identity
+ (cl-mapcar #'org-table--align-field
+ fields
+ widths
+ alignments)
+ "|")))
+ "|")))
+ (if (equal new previous)
+ (forward-line)
+ (insert new "\n")
+ (delete-region (point) (line-beginning-position 2))))))
(set-marker end nil)
(when org-table-overlay-coordinates (org-table-overlay-coordinates))
(setq org-table-may-need-update nil))))))
@@ -4406,7 +4462,7 @@ Optional argument NEW may specify text to replace the current field content."
((not new)
(concat (org-table--align-field field width align)
"|"))
- ((<= (org-string-width new) width)
+ ((and width (<= (org-string-width new) width))
(concat (org-table--align-field new width align)
"|"))
(t
@@ -4758,7 +4814,7 @@ This function sets up the following dynamically scoped variables:
(dolist (name (org-split-string (match-string 1) " *| *"))
(cl-incf c)
(when (string-match "\\`[a-zA-Z][_a-zA-Z0-9]*\\'" name)
- (push (cons name (int-to-string c)) org-table-column-names)))))
+ (push (cons name (number-to-string c)) org-table-column-names)))))
(setq org-table-column-names (nreverse org-table-column-names))
(setq org-table-column-name-regexp
(format "\\$\\(%s\\)\\>"
@@ -4817,23 +4873,10 @@ This function sets up the following dynamically scoped variables:
;; Get the number of columns from the first data line in table.
(goto-char beg)
(forward-line (aref org-table-dlines 1))
- (let* ((fields
- (org-split-string
- (buffer-substring (line-beginning-position) (line-end-position))
- "[ \t]*|[ \t]*"))
- (nfields (length fields))
- al al2)
- (setq org-table-current-ncol nfields)
- (let ((last-dline
- (aref org-table-dlines (1- (length org-table-dlines)))))
- (dotimes (i nfields)
- (let ((column (1+ i)))
- (push (list (format "LR%d" column) last-dline column) al)
- (push (cons (format "LR%d" column) (nth i fields)) al2))))
- (setq org-table-named-field-locations
- (append org-table-named-field-locations al))
- (setq org-table-local-parameters
- (append org-table-local-parameters al2))))))
+ (setq org-table-current-ncol
+ (length (org-split-string
+ (buffer-substring (line-beginning-position) (line-end-position))
+ "[ \t]*|[ \t]*"))))))
(defun org-table--force-dataline ()
"Move point to the closest data line in a table.
@@ -5039,66 +5082,66 @@ When LOCAL is non-nil, show references for the table at point."
(put 'orgtbl-mode :menu-tag "Org Table Mode")
(easy-menu-define orgtbl-mode-menu orgtbl-mode-map "OrgTbl menu"
- '("OrgTbl"
- ["Create or convert" org-table-create-or-convert-from-region
- :active (not (org-at-table-p)) :keys "C-c |" ]
- "--"
- ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p) :keys "C-c C-c"]
- ["Next Field" org-cycle :active (org-at-table-p) :keys "TAB"]
- ["Previous Field" org-shifttab :active (org-at-table-p) :keys "S-TAB"]
- ["Next Row" org-return :active (org-at-table-p) :keys "RET"]
- "--"
- ["Blank Field" org-table-blank-field :active (org-at-table-p) :keys "C-c SPC"]
- ["Edit Field" org-table-edit-field :active (org-at-table-p) :keys "C-c ` "]
- ["Copy Field from Above"
- org-table-copy-down :active (org-at-table-p) :keys "S-RET"]
- "--"
- ("Column"
- ["Move Column Left" org-metaleft :active (org-at-table-p) :keys "M-<left>"]
- ["Move Column Right" org-metaright :active (org-at-table-p) :keys "M-<right>"]
- ["Delete Column" org-shiftmetaleft :active (org-at-table-p) :keys "M-S-<left>"]
- ["Insert Column" org-shiftmetaright :active (org-at-table-p) :keys "M-S-<right>"])
- ("Row"
- ["Move Row Up" org-metaup :active (org-at-table-p) :keys "M-<up>"]
- ["Move Row Down" org-metadown :active (org-at-table-p) :keys "M-<down>"]
- ["Delete Row" org-shiftmetaup :active (org-at-table-p) :keys "M-S-<up>"]
- ["Insert Row" org-shiftmetadown :active (org-at-table-p) :keys "M-S-<down>"]
- ["Sort lines in region" org-table-sort-lines :active (org-at-table-p) :keys "C-c ^"]
- "--"
- ["Insert Hline" org-table-insert-hline :active (org-at-table-p) :keys "C-c -"])
- ("Rectangle"
- ["Copy Rectangle" org-copy-special :active (org-at-table-p)]
- ["Cut Rectangle" org-cut-special :active (org-at-table-p)]
- ["Paste Rectangle" org-paste-special :active (org-at-table-p)]
- ["Fill Rectangle" org-table-wrap-region :active (org-at-table-p)])
- "--"
- ("Radio tables"
- ["Insert table template" orgtbl-insert-radio-table
- (cl-assoc-if #'derived-mode-p orgtbl-radio-table-templates)]
- ["Comment/uncomment table" orgtbl-toggle-comment t])
- "--"
- ["Set Column Formula" org-table-eval-formula :active (org-at-table-p) :keys "C-c ="]
- ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="]
- ["Edit Formulas" org-table-edit-formulas :active (org-at-table-p) :keys "C-c '"]
- ["Recalculate line" org-table-recalculate :active (org-at-table-p) :keys "C-c *"]
- ["Recalculate all" (org-table-recalculate '(4)) :active (org-at-table-p) :keys "C-u C-c *"]
- ["Iterate all" (org-table-recalculate '(16)) :active (org-at-table-p) :keys "C-u C-u C-c *"]
- ["Toggle Recalculate Mark" org-table-rotate-recalc-marks :active (org-at-table-p) :keys "C-c #"]
- ["Sum Column/Rectangle" org-table-sum
- :active (or (org-at-table-p) (org-region-active-p)) :keys "C-c +"]
- ["Which Column?" org-table-current-column :active (org-at-table-p) :keys "C-c ?"]
- ["Debug Formulas"
- org-table-toggle-formula-debugger :active (org-at-table-p)
- :keys "C-c {"
- :style toggle :selected org-table-formula-debug]
- ["Show Col/Row Numbers"
- org-table-toggle-coordinate-overlays :active (org-at-table-p)
- :keys "C-c }"
- :style toggle :selected org-table-overlay-coordinates]
- "--"
- ("Plot"
- ["Ascii plot" orgtbl-ascii-plot :active (org-at-table-p) :keys "C-c \" a"]
- ["Gnuplot" org-plot/gnuplot :active (org-at-table-p) :keys "C-c \" g"])))
+ '("OrgTbl"
+ ["Create or convert" org-table-create-or-convert-from-region
+ :active (not (org-at-table-p)) :keys "C-c |" ]
+ "--"
+ ["Align" org-ctrl-c-ctrl-c :active (org-at-table-p) :keys "C-c C-c"]
+ ["Next Field" org-cycle :active (org-at-table-p) :keys "TAB"]
+ ["Previous Field" org-shifttab :active (org-at-table-p) :keys "S-TAB"]
+ ["Next Row" org-return :active (org-at-table-p) :keys "RET"]
+ "--"
+ ["Blank Field" org-table-blank-field :active (org-at-table-p) :keys "C-c SPC"]
+ ["Edit Field" org-table-edit-field :active (org-at-table-p) :keys "C-c ` "]
+ ["Copy Field from Above"
+ org-table-copy-down :active (org-at-table-p) :keys "S-RET"]
+ "--"
+ ("Column"
+ ["Move Column Left" org-metaleft :active (org-at-table-p) :keys "M-<left>"]
+ ["Move Column Right" org-metaright :active (org-at-table-p) :keys "M-<right>"]
+ ["Delete Column" org-shiftmetaleft :active (org-at-table-p) :keys "M-S-<left>"]
+ ["Insert Column" org-shiftmetaright :active (org-at-table-p) :keys "M-S-<right>"])
+ ("Row"
+ ["Move Row Up" org-metaup :active (org-at-table-p) :keys "M-<up>"]
+ ["Move Row Down" org-metadown :active (org-at-table-p) :keys "M-<down>"]
+ ["Delete Row" org-shiftmetaup :active (org-at-table-p) :keys "M-S-<up>"]
+ ["Insert Row" org-shiftmetadown :active (org-at-table-p) :keys "M-S-<down>"]
+ ["Sort lines in region" org-table-sort-lines :active (org-at-table-p) :keys "C-c ^"]
+ "--"
+ ["Insert Hline" org-table-insert-hline :active (org-at-table-p) :keys "C-c -"])
+ ("Rectangle"
+ ["Copy Rectangle" org-copy-special :active (org-at-table-p)]
+ ["Cut Rectangle" org-cut-special :active (org-at-table-p)]
+ ["Paste Rectangle" org-paste-special :active (org-at-table-p)]
+ ["Fill Rectangle" org-table-wrap-region :active (org-at-table-p)])
+ "--"
+ ("Radio tables"
+ ["Insert table template" orgtbl-insert-radio-table
+ (cl-assoc-if #'derived-mode-p orgtbl-radio-table-templates)]
+ ["Comment/uncomment table" orgtbl-toggle-comment t])
+ "--"
+ ["Set Column Formula" org-table-eval-formula :active (org-at-table-p) :keys "C-c ="]
+ ["Set Field Formula" (org-table-eval-formula '(4)) :active (org-at-table-p) :keys "C-u C-c ="]
+ ["Edit Formulas" org-table-edit-formulas :active (org-at-table-p) :keys "C-c '"]
+ ["Recalculate line" org-table-recalculate :active (org-at-table-p) :keys "C-c *"]
+ ["Recalculate all" (org-table-recalculate '(4)) :active (org-at-table-p) :keys "C-u C-c *"]
+ ["Iterate all" (org-table-recalculate '(16)) :active (org-at-table-p) :keys "C-u C-u C-c *"]
+ ["Toggle Recalculate Mark" org-table-rotate-recalc-marks :active (org-at-table-p) :keys "C-c #"]
+ ["Sum Column/Rectangle" org-table-sum
+ :active (or (org-at-table-p) (org-region-active-p)) :keys "C-c +"]
+ ["Which Column?" org-table-current-column :active (org-at-table-p) :keys "C-c ?"]
+ ["Debug Formulas"
+ org-table-toggle-formula-debugger :active (org-at-table-p)
+ :keys "C-c {"
+ :style toggle :selected org-table-formula-debug]
+ ["Show Col/Row Numbers"
+ org-table-toggle-coordinate-overlays :active (org-at-table-p)
+ :keys "C-c }"
+ :style toggle :selected org-table-overlay-coordinates]
+ "--"
+ ("Plot"
+ ["Ascii plot" orgtbl-ascii-plot :active (org-at-table-p) :keys "C-c \" a"]
+ ["Gnuplot" org-plot/gnuplot :active (org-at-table-p) :keys "C-c \" g"])))
;;;###autoload
(define-minor-mode orgtbl-mode
@@ -5129,15 +5172,13 @@ When LOCAL is non-nil, show references for the table at point."
orgtbl-line-start-regexp))
(when (fboundp 'font-lock-add-keywords)
(font-lock-add-keywords nil orgtbl-extra-font-lock-keywords)
- (org-restart-font-lock))
- (easy-menu-add orgtbl-mode-menu))
+ (org-restart-font-lock)))
(t
(setq auto-fill-inhibit-regexp org-old-auto-fill-inhibit-regexp)
(remove-hook 'before-change-functions 'org-before-change-function t)
(when (fboundp 'font-lock-remove-keywords)
(font-lock-remove-keywords nil orgtbl-extra-font-lock-keywords)
(org-restart-font-lock))
- (easy-menu-remove orgtbl-mode-menu)
(force-mode-line-update 'all))))
(defun orgtbl-make-binding (fun n &rest keys)
@@ -5147,7 +5188,7 @@ command name. KEYS are keys that should be checked in for a command
to execute outside of tables."
(eval
(list 'defun
- (intern (concat "orgtbl-hijacker-command-" (int-to-string n)))
+ (intern (concat "orgtbl-hijacker-command-" (number-to-string n)))
'(arg)
(concat "In tables, run `" (symbol-name fun) "'.\n"
"Outside of tables, run the binding of `"
@@ -5401,17 +5442,56 @@ a radio table."
;;;###autoload
(defun org-table-to-lisp (&optional txt)
"Convert the table at point to a Lisp structure.
+
The structure will be a list. Each item is either the symbol `hline'
for a horizontal separator line, or a list of field values as strings.
The table is taken from the parameter TXT, or from the buffer at point."
- (unless (or txt (org-at-table-p)) (user-error "No table at point"))
- (let ((txt (or txt
- (buffer-substring-no-properties (org-table-begin)
- (org-table-end)))))
- (mapcar (lambda (x)
- (if (string-match org-table-hline-regexp x) 'hline
- (org-split-string (org-trim x) "\\s-*|\\s-*")))
- (org-split-string txt "[ \t]*\n[ \t]*"))))
+ (if txt
+ (with-temp-buffer
+ (insert txt)
+ (goto-char (point-min))
+ (org-table-to-lisp))
+ (save-excursion
+ (goto-char (org-table-begin))
+ (let ((table nil))
+ (while (re-search-forward "\\=[ \t]*|" nil t)
+ (let ((row nil))
+ (if (looking-at "-")
+ (push 'hline table)
+ (while (not (progn (skip-chars-forward " \t") (eolp)))
+ (push (buffer-substring
+ (point)
+ (progn (re-search-forward "[ \t]*\\(|\\|$\\)")
+ (match-beginning 0)))
+ row))
+ (push (nreverse row) table)))
+ (forward-line))
+ (nreverse table)))))
+
+(defun org-table-collapse-header (table &optional separator max-header-lines)
+ "Collapse the lines before 'hline into a single header.
+
+The given TABLE is a list of lists as returned by `org-table-to-lisp'.
+The leading lines before the first `hline' symbol are considered
+forming the table header. This function collapses all leading header
+lines into a single header line, followed by the `hline' symbol, and
+the rest of the TABLE. Header cells are glued together with a space,
+or the given SEPARATOR."
+ (while (eq (car table) 'hline) (pop table))
+ (let* ((separator (or separator " "))
+ (max-header-lines (or max-header-lines 4))
+ (trailer table)
+ (header-lines (cl-loop for line in table
+ until (eq 'hline line)
+ collect (pop trailer))))
+ (if (and trailer (<= (length header-lines) max-header-lines))
+ (cons (apply #'cl-mapcar
+ (lambda (&rest x)
+ (org-trim
+ (mapconcat #'identity x separator)))
+ header-lines)
+ trailer)
+ table)))
(defun orgtbl-send-table (&optional maybe)
"Send a transformed version of table at point to the receiver position.
@@ -5423,9 +5503,7 @@ for this table."
;; when non-interactive, we assume align has just happened.
(when (called-interactively-p 'any) (org-table-align))
(let ((dests (orgtbl-gather-send-defs))
- (table (org-table-to-lisp
- (buffer-substring-no-properties (org-table-begin)
- (org-table-end))))
+ (table (org-table-to-lisp))
(ntbl 0))
(unless dests
(if maybe (throw 'exit nil)
@@ -6096,7 +6174,7 @@ which will prompt for the width."
((numberp ask) ask)
(t 12))))
;; Skip any hline a the top of table.
- (while (eq (car table) 'hline) (setq table (cdr table)))
+ (while (eq (car table) 'hline) (pop table))
;; Skip table header if any.
(dolist (x (or (cdr (memq 'hline table)) table))
(when (consp x)
@@ -6122,7 +6200,7 @@ which will prompt for the width."
;; Here are two examples of different styles.
;; Unicode block characters are used to give a smooth effect.
-;; See http://en.wikipedia.org/wiki/Block_Elements
+;; See https://en.wikipedia.org/wiki/Block_Elements
;; Use one of those drawing functions
;; - orgtbl-ascii-draw (the default ascii)
;; - orgtbl-uc-draw-grid (unicode with a grid effect)
@@ -6136,7 +6214,7 @@ which will prompt for the width."
It is a variant of orgtbl-ascii-draw with Unicode block
characters, for a smooth display. Bars appear as grids (to the
extent the font allows)."
- ;; http://en.wikipedia.org/wiki/Block_Elements
+ ;; https://en.wikipedia.org/wiki/Block_Elements
;; best viewed with the "DejaVu Sans Mono" font.
(orgtbl-ascii-draw value min max width
" \u258F\u258E\u258D\u258C\u258B\u258A\u2589"))