1

I'd like C-c ? to happen automatically when I focus on a table cell, is there something built-in to do this?

(Or is there some other way to quickly show which cells are "input" vs "output"?)

2
  • There are multiple questions bundled in to a single question ... and I have addressed each component of the question. As the screenshots show, the snippets work reasonably well. It is possible that are slow on large tables with too many formulae etc. The snippets show good starting points and the mechanics involved to dig deeper
    – mxnt
    Commented Mar 26 at 4:34
  • The final solution that consolidates all the approaches is here emacs.stackexchange.com/a/80851/42623. This solution has too many moving parts. The other solutions are also solutions, in the sense that they are fairly easy to understand (= less bugs). IOW, different solutions for different needs. Leave the other answers intact ...
    – mxnt
    Commented Mar 26 at 9:11

4 Answers 4

3

I'd like C-c ? to happen automatically when I focus on a table cell, is there something built-in to do this?

To get this

Display Table Cell info as eldoc string

Table Cell info as eldoc string

on this

#+NAME: table1
#+CAPTION: Table 1
| Student  | Mark1 | Mark2 | Mark3 | Result | Result-simple | ResultSkaled |
|----------+-------+-------+-------+--------+---------------+--------------|
| Student1 |     2 |     3 |     4 |      9 |             9 |          900 |
| Student2 |     4 |     2 |     1 |      7 |             7 |          700 |
#+TBLFM: $5=vsum($2..$4)::$6=$2+$3+$4::$7=vsum($2..$4)*100



this seems like a good starting point

(defun my-tblcell-info ()
  (cl-letf (((symbol-function 'message) 'format))
    (cond
     ((and (eq 'table-cell (org-element-type (org-element-context))))
      (unless org-table-overlay-coordinates
        (org-table-toggle-coordinate-overlays))
      (org-table-toggle-coordinate-overlays)
      (org-table-toggle-coordinate-overlays)
      (org-table-field-info nil)))))

(defun my-install-tblcell-info-as-eldoc-string ()
  (add-function :before-until (local 'eldoc-documentation-function)
                #'my-tblcell-info)
  (eldoc-add-command 'org-cycle 'org-shifttab)
  (turn-on-eldoc-mode))

(add-hook 'org-mode-hook 'my-install-tblcell-info-as-eldoc-string)

If org table is a too big to analyze, you may have to build the docstring in a callback.

For quick results, the above snippet works reasonably well.

1

I'd like C-c ? to happen automatically when I focus on a table cell, i

To get this

mouse-1 or left click shows table cell info at point

mouse-1 shows info about cell at point

do this

(defun my-org-table-info (&optional event promote-to-region)
  (interactive "e\np")
  (mouse-set-point event promote-to-region)
  (pcase (org-element-type (org-element-context))
    (`table-cell
     (unless org-table-overlay-coordinates
       (org-table-toggle-coordinate-overlays))
     (org-table-toggle-coordinate-overlays)
     (org-table-toggle-coordinate-overlays)
     (call-interactively 'org-table-field-info))))

(define-key org-mode-map (kbd "<mouse-1>") 'my-org-table-info)

1

(Or is there some other way to quickly show which cells are "input" vs "output"?)

The snippet gives the contour of possible solution and is NOT production ready. Right now, it doesn't overlays used for highlighting etc.

TODO: Destructure the message emitted by stock org-table-field-info with pcase rx pattern may be.

To get this

Highight dependent cells of a table with M-x my-org-table-highlight-dependent-cells

Highight dependent cells of a table

on this

#+begin_src emacs-lisp
  (defun my-org-table-field-info ()
    (cl-letf (((symbol-function 'message)
               (lambda (fmt-string &rest args)
                 args)))
      (cond
       ((and (eq 'table-cell (org-element-type (org-element-context))))
        (unless org-table-overlay-coordinates
          (org-table-toggle-coordinate-overlays))
        (org-table-toggle-coordinate-overlays)
        (org-table-toggle-coordinate-overlays)
        (org-table-field-info nil)))))

  (defun my-org-table-field-is-a-formula-p (table-field-info)
    ;; Poor man's destructuring of message emitted by stock
    ;; `org-table-field-info'
    (when (org-string-nw-p (nth 7 table-field-info))
      (nth 7 table-field-info)))

  (defun my-org-table-highlight-dependent-cells ()
    (interactive)
    (when (org-at-table-p)
      (goto-char (org-table-end))
      (ignore-errors
        (while t
          (org-table-previous-field)
          (when (my-org-table-field-is-a-formula-p
                 (my-org-table-field-info))
            (pcase-let* ((`(,type ,(map :begin :end) ,contents) (org-element-context)))
              (thread-first (thread-last (list begin (1- end))
                                         (apply #'make-overlay))
                            (overlay-put 'face 'secondary-selection))))))))
#+end_src

#+RESULTS:
: my-org-table-highlight-dependent-cells

#+NAME: table1
#+CAPTION: Table 1
| Student  | Mark1 | Mark2 | Mark3 | Result | Result-simple | ResultSkaled |
|----------+-------+-------+-------+--------+---------------+--------------|
| Student1 |     2 |     3 |     4 |      9 |             9 |          900 |
| Student2 |     4 |     2 |     1 |      7 |             7 |          700 |
#+TBLFM: $5=vsum($2..$4)::$6=$2+$3+$4::$7=vsum($2..$4)*100


do this

(defun my-org-table-field-info ()
  (cl-letf (((symbol-function 'message)
             (lambda (fmt-string &rest args)
               args)))
    (cond
     ((and (eq 'table-cell (org-element-type (org-element-context))))
      (unless org-table-overlay-coordinates
        (org-table-toggle-coordinate-overlays))
      (org-table-toggle-coordinate-overlays)
      (org-table-toggle-coordinate-overlays)
      (org-table-field-info nil)))))

(defun my-org-table-field-is-a-formula-p (table-field-info)
  ;; Poor man's destructuring of message emitted by stock
  ;; `org-table-field-info'
  (when (org-string-nw-p (nth 7 table-field-info))
    (nth 7 table-field-info)))

(defun my-org-table-highlight-dependent-cells ()
  (interactive)
  (when (org-at-table-p)
    (goto-char (org-table-end))
    (ignore-errors
      (while t
        (org-table-previous-field)
        (when (my-org-table-field-is-a-formula-p
               (my-org-table-field-info))
          (pcase-let* ((`(,type ,(map :begin :end) ,contents) (org-element-context)))
            (thread-first (thread-last (list begin (1- end))
                                       (apply #'make-overlay))
                          (overlay-put 'face 'secondary-selection))))))))

1

Destructure the message emitted by stock org-table-field-info with pcase rx pattern may be

Done.

What does the Elisp Recipe do?

Recipe

This recipe does the following

  • mouse-1 on a table cell highlight the table, it also prints table cell info as eldoc string

  • When on a table, if use <tab>, <backtab> (translated from S-<iso-lefttab>), C-f, C-b, C-n, C-p to navigate around the table, it prints the table cell info as eldoc string. (In this case, no highlighting of dependent cell would happen.)

Screenshots of recipe in action

Demo-1: What happens when mouse-1 on a Table cell

(Note that this table is a fairly complex, and names some fields, and columns)

mouse-1 on a Table Cell

Demo-2: What happens when mouse-1 on a different Table

mouse-1 on another Table

Org file used for Demo

#+NAME: revenue
#+CAPTION: Quarterly Revenue
#+ATTR_ODT: :style "Academic"
|       | Jan | Feb | Mar | Sum |
|-------+-----+-----+-----+-----|
| North | 5.1 | 1.7 | 5.6 |     |
| South | 7.6 | 3.7 | 0.4 |     |
| East  | 9.5 | 0.4 | 9.6 |     |
| West  | 4.8 | 5.7 | 5.9 |     |
|-------+-----+-----+-----+-----|
| Sum   |     |     |     |     |
#+TBLFM: $5=vsum($2..$4)::@6$2..@6$4=vsum(@I..@II)::@>$>=vsum(@I..@II)

#+NAME: table4
#+CAPTION: Table 4
|---+---------+--------+--------+--------+-------+------+----------------|
|   | Student | Prob 1 | Prob 2 | Prob 3 | Total | Note | Copy of Prob 1 |
|---+---------+--------+--------+--------+-------+------+----------------|
| ! |         |     P1 |     P2 |     P3 |   Tot |      |                |
| # | Maximum |     10 |     15 |     25 |    50 | 10.0 |             10 |
| ^ |         |     m1 |     m2 |     m3 |    mt |      |                |
|---+---------+--------+--------+--------+-------+------+----------------|
| # | Peter   |     10 |      8 |     23 |    41 |  8.2 |             10 |
| # | Sam     |      2 |      4 |      3 |     9 |  1.8 |              2 |
|---+---------+--------+--------+--------+-------+------+----------------|
|   | Average |        |        |        |  25.0 |      |                |
| ^ |         |        |        |        |    at |      |                |
| $ | max=50  |        |        |        |       |      |                |
|---+---------+--------+--------+--------+-------+------+----------------|
#+TBLFM: $6=vsum($P1..$P3)::$7=10*$Tot/$max;%.1f::$8=$3

Elisp Recipe

This recipe does the following

  • mouse-1 on a table cell highlight the table, it also prints table cell info as eldoc string

  • When on a table, if use <tab>, <backtab> (translated from S-<iso-lefttab>), C-f, C-b, C-n, C-p to navigate around the table, it prints the table cell info as eldoc string. (In this case, no highlighting of dependent cell would happen.)


(defun my-tblcell-info ()
  (cl-letf (((symbol-function 'message) 'format))
    (when (and (org-at-table-p)
               (eq 'table-cell (org-element-type (org-element-context))))
      (unless org-table-overlay-coordinates
        (org-table-toggle-coordinate-overlays))
      (org-table-toggle-coordinate-overlays)
      (org-table-toggle-coordinate-overlays)
      (substring-no-properties (org-table-field-info nil)))))

(defun my-tblcell-info-as-plist (field-info)
  (when (stringp field-info)
    (pcase-let* (;; (field-info
                 ;;  "line @3, col $6 or $Tot, ref @3$6 or F3 or $mt, formula: $6=vsum($P1..$P3)")
                 ((rx
                   "line " (let line (one-or-more any))
                   ", col " (let col (let col-1 (minimal-match (one-or-more any))) (opt " or " (let col-2 (one-or-more any))))
                   ", ref " (let ref (minimal-match (one-or-more any)))
                   " or " (and
                           (let rest-1 (minimal-match (one-or-more any)))
                           (opt " or " (let rest-2 (minimal-match (one-or-more any))))
                           (opt ", formula: " (let rest-3 (minimal-match (one-or-more any)))))
                   eos)
                  field-info))
      (list :line line
            :cols (list col-1 col-2)
            :refs (list ref rest-1 rest-2)
            :formula rest-3))))

(defun my-tblcell-info-as-string ()
  (when-let ((plist (my-tblcell-info-as-plist (my-tblcell-info))))
    (format "%S" plist)
    ;; (plist-get plist :formula)
    ))

(defun my-tblcell-is-a-formula-p (plist)
  (plist-get plist :formula))

(defun my-install-tblcell-info-as-eldoc-string ()
  (add-function :before-until (local 'eldoc-documentation-function)
                #'my-tblcell-info-as-string)
  (eldoc-add-command 'org-cycle 'org-shifttab 'my-tblcell-highlight-dependent-cells)
  (turn-on-eldoc-mode))

(defun my-tblcell-highlight-dependent-cells ()
  (interactive)
  (save-excursion
    (when (org-at-table-p)
      (goto-char (org-table-end))
      (ignore-errors
        (while t
          (org-table-previous-field)
          (when (my-tblcell-is-a-formula-p
                 (my-tblcell-info-as-plist
                  (my-tblcell-info)))
            (pcase-let* ((`(,type ,(map :begin :end) ,contents) (org-element-context)))
              (thread-first (thread-last (list begin (1- end))
                                         (apply #'make-overlay))
                            (overlay-put 'face 'secondary-selection)))))))))

(add-hook 'org-mode-hook 'my-install-tblcell-info-as-eldoc-string)

(define-key org-mode-map (kbd "<mouse-1>") 'my-tblcell-highlight-dependent-cells)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.