Function: org-table-recalculate

org-table-recalculate is an autoloaded, interactive and byte-compiled function defined in org-table.el.gz.

Signature

(org-table-recalculate &optional ALL NOALIGN)

Documentation

Recalculate the current table line by applying all stored formulas.

With prefix arg ALL, do this for all lines in the table.

When called with a C-u (universal-argument) C-u (universal-argument) prefix, or if ALL is the symbol iterate, recompute the table until it no longer changes.

If NOALIGN is not nil, do not re-align the table after the computations are done. This is typically used internally to save time, if it is known that the table will be realigned a little later anyway.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/org/org-table.el.gz
;;;###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.

When called with a `\\[universal-argument] \\[universal-argument]' prefix, or \
if ALL is the symbol `iterate',
recompute the table until it no longer changes.

If NOALIGN is not nil, do not re-align the table after the computations
are done.  This is typically used internally to save time, if it is
known that the table will be realigned a little later anyway."
  (interactive "P")
  (unless (memq this-command org-recalc-commands)
    (push this-command org-recalc-commands))
  (unless (org-at-table-p) (user-error "Not at a table"))
  (if (or (eq all 'iterate) (equal all '(16)))
      (org-table-iterate)
    (org-table-analyze)
    (let* ((eqlist (sort (org-table-get-stored-formulas)
			 (lambda (a b) (string< (car a) (car b)))))
	   (inhibit-redisplay (not debug-on-error))
	   (line-re org-table-dataline-regexp)
	   (log-first-time (current-time))
	   (log-last-time log-first-time)
	   (cnt 0)
           (table-beg org-table-current-begin-pos)
           (table-end (org-table-end))
	   beg end eqlcol eqlfield)
      ;; Insert constants in all formulas.
      (when eqlist
        (org-fold-core-ignore-modifications
	  (org-table-with-shrunk-columns
	   (org-table-save-field
	    ;; Expand equations, then split the equation list between
	    ;; column formulas and field formulas.
	    (dolist (eq eqlist)
	      (let* ((rhs (org-table-formula-substitute-names
			   (org-table-formula-handle-first/last-rc (cdr eq))))
		     (old-lhs (car eq))
		     (lhs
		      (org-table-formula-handle-first/last-rc
		       (cond
                        ((string-match "\\`@-?I+" old-lhs)
                         (user-error "Can't assign to hline relative reference"))
                        ((string-match "\\`\\$[<>]" old-lhs)
                         (let ((new (org-table-formula-handle-first/last-rc
				     old-lhs)))
			   (when (assoc new eqlist)
			     (user-error "\"%s=\" formula tries to overwrite \
existing formula for column %s"
                                         old-lhs
                                         new))
			   new))
                        (t old-lhs)))))
                (if (string-match-p "\\`\\$[0-9]+\\'" lhs)
		    (push (cons lhs rhs) eqlcol)
		  (push (cons lhs rhs) eqlfield))))
	    (setq eqlcol (nreverse eqlcol))
	    ;; Expand ranges in lhs of formulas
	    (setq eqlfield (org-table-expand-lhs-ranges (nreverse eqlfield)))
	    ;; Get the correct line range to process.
	    (if all
                (progn
		  (setq end (copy-marker table-end))
		  (goto-char (setq beg table-beg))
		  (cond
		   ((re-search-forward org-table-calculate-mark-regexp end t)
		    ;; This is a table with marked lines, compute selected
		    ;; lines.
		    (setq line-re org-table-recalculate-regexp))
		   ;; Move forward to the first non-header line.
		   ((and (re-search-forward org-table-dataline-regexp end t)
                         (re-search-forward org-table-hline-regexp end t)
                         (re-search-forward org-table-dataline-regexp end t))
		    (setq beg (match-beginning 0)))
		   ;; Just leave BEG at the start of the table.
		   (t nil)))
	      (setq beg (line-beginning-position)
		    end (copy-marker (line-beginning-position 2))))
            (org-combine-change-calls table-beg table-end
	      (goto-char beg)
	      ;; Mark named fields untouchable.  Also check if several
	      ;; field/range formulas try to set the same field.
	      (remove-text-properties beg end '(:org-untouchable t))
	      (let ((current-line (count-lines org-table-current-begin-pos
					       (line-beginning-position)))
		    seen-fields)
                (dolist (eq eqlfield)
                  (let* ((name (car eq))
                         (location (assoc name org-table-named-field-locations))
                         (eq-line (or (nth 1 location)
				      (and (string-match "\\`@\\([0-9]+\\)" name)
                                           (aref org-table-dlines
                                                 (string-to-number
                                                  (match-string 1 name))))))
                         (reference
                          (if location
			      ;; Turn field coordinates associated to NAME
			      ;; into an absolute reference.
			      (format "@%d$%d"
				      (org-table-line-to-dline eq-line)
				      (nth 2 location))
			    name)))
		    (when (member reference seen-fields)
		      (user-error "Several field/range formulas try to set %s"
                                  reference))
		    (push reference seen-fields)
		    (when (or all (eq eq-line current-line))
		      (org-table-goto-field name)
		      (org-table-put-field-property :org-untouchable t)))))
	      ;; Evaluate the column formulas, but skip fields covered by
	      ;; field formulas.
	      (goto-char beg)
	      (while (re-search-forward line-re end t)
                (unless (string-match "\\` *[_^!$/] *\\'" (org-table-get-field 1))
                  ;; Unprotected line, recalculate.
                  (cl-incf cnt)
                  (when all
		    (setq log-last-time
                          (org-table-message-once-per-second
                           log-last-time
                           "Re-applying formulas to full table...(line %d)" cnt)))
                  (if (markerp org-last-recalc-line)
		      (move-marker org-last-recalc-line (line-beginning-position))
		    (setq org-last-recalc-line
                          (copy-marker (line-beginning-position))))
                  (dolist (entry eqlcol)
		    (goto-char org-last-recalc-line)
		    (org-table-goto-column
		     (string-to-number (substring (car entry) 1)) nil 'force)
		    (unless (get-text-property (point) :org-untouchable)
		      (org-table-eval-formula
		       nil (cdr entry) 'noalign 'nocst 'nostore 'noanalysis)))))
	      ;; Evaluate the field formulas.
	      (dolist (eq eqlfield)
                (let ((reference (car eq))
		      (formula (cdr eq)))
                  (setq log-last-time
                        (org-table-message-once-per-second
                         (and all log-last-time)
                         "Re-applying formula to field: %s" (car eq)))
                  (org-table-goto-field
                   reference
                   ;; Possibly create a new column, as long as
                   ;; `org-table-formula-create-columns' allows it.
                   (let ((column-count (progn (end-of-line)
					      (1- (org-table-current-column)))))
		     (lambda (column)
		       (when (> column 1000)
                         (user-error "Formula column target too large"))
		       (and (> column column-count)
			    (or (eq org-table-formula-create-columns t)
                                (and (eq org-table-formula-create-columns 'warn)
				     (progn
				       (org-display-warning
                                        "Out-of-bounds formula added columns")
				       t))
                                (and (eq org-table-formula-create-columns 'prompt)
				     (yes-or-no-p
				      "Out-of-bounds formula.  Add columns? "))
                                (user-error
                                 "Missing columns in the table.  Aborting"))))))
                  (org-table-eval-formula nil formula t t t t)))
	      ;; Clean up marker.
	      (set-marker end nil)))))
	(unless noalign
	  (when org-table-may-need-update (org-table-align))
	  (when all
	    (org-table-message-once-per-second
	     log-first-time "Re-applying formulas to %d lines... done" cnt)))
	(org-table-message-once-per-second
	 (and all log-first-time) "Re-applying formulas... done")))))