Is there a default way to make tables in org mode foldable? Obviously, I can just advise org-table-create
to wrap the new table inside a drawer, but I was wondering whether this is overdesigned and there is some built-in way that I have just not been able to find in the manual.
2 Answers
To get this
Use this snippet ...
(defun my-table-hide-spec ()
"Hide portions of table content.
Add `my-table-hide-table' as an invisibility spec for hiding
portions of tables content."
(add-to-invisibility-spec '(my-table-hide-table . t)))
(add-hook 'org-mode-hook #'my-table-hide-spec)
(defvar-local my-table-hide-overlays nil
"Overlays hiding tables.")
(defun my-table-fold-all ()
"Fold all tables in the current buffer."
(interactive)
(my-table-unfold-all)
(save-excursion
(org-table-map-tables
#'my-table-toggle-folds-maybe)))
(defun my-table-unfold-all ()
"Unfold all tables in the current buffer."
(interactive)
(mapc 'delete-overlay my-table-hide-overlays)
(setq my-table-hide-overlays nil))
;;;###autoload
(defun my-table-toggle-folds-maybe ()
"Toggle visibility of table at point."
(interactive)
(my-table-toggle-fold))
(defun my-table-toggle-fold ()
"Toggle the visibility of the current table."
(interactive)
(save-excursion
(beginning-of-line)
(unless (org-at-table-p)
(error "Not looking at a table"))
(let ((start (progn
(goto-char (org-table-begin))
(re-search-forward "|")
(point)))
(end (progn
(goto-char (org-table-end))
(re-search-backward "|")
(point)))
ov)
(cond
((memq t (mapcar (lambda (overlay)
(eq (overlay-get overlay 'invisible)
'my-table-hide-table))
(overlays-at start)))
(mapc (lambda (ov)
(when (member ov my-table-hide-overlays)
(setq my-table-hide-overlays
(delq ov my-table-hide-overlays)))
(when (eq (overlay-get ov 'invisible)
'my-table-hide-table)
(delete-overlay ov)))
(overlays-at start)))
(t
(setq ov (make-overlay start end))
(overlay-put ov 'invisible 'my-table-hide-table)
;; make the block accessible to isearch
(overlay-put
ov 'isearch-open-invisible
(lambda (ov)
(when (member ov my-table-hide-overlays)
(setq my-table-hide-overlays
(delq ov my-table-hide-overlays)))
(when (eq (overlay-get ov 'invisible)
'my-table-hide-table)
(delete-overlay ov))))
(push ov my-table-hide-overlays))))))
;; org-tab-after-check-for-cycling-hook
(add-hook 'org-tab-first-hook #'my-table-toggle-folds-maybe)
;; Remove overlays when changing major mode
(add-hook 'org-mode-hook
(lambda () (add-hook 'change-major-mode-hook
#'my-table-unfold-all 'append 'local)))
Here is a sample org
file for you to try ...
#+name: colgroups
| N | N^2 | N^3 | N^4 | sqrt(n) | sqrt[4](N) |
|---+-----+-----+-----+---------+------------|
| / | < | | > | < | > |
| 1 | 1 | 1 | 1 | 1 | 1 |
| 2 | 4 | 8 | 16 | 1.4142 | 1.1892 |
| 3 | 9 | 27 | 81 | 1.7321 | 1.3161 |
|---+-----+-----+-----+---------+------------|
#+TBLFM: $2=$1^2::$3=$1^3::$4=$1^4::$5=sqrt($1)::$6=sqrt(sqrt(($1)))
#+name: Duration and Time Values
| Task 1 | Task 2 | Total |
|---------+----------+----------|
| 2:12 | 1:47 | 03:59:00 |
| 2:12 | 1:47 | 03:59 |
| 3:02:20 | -2:07:00 | 0.92 |
#+TBLFM: @2$3=$1+$2;T::@3$3=$1+$2;U::@4$3=$1+$2;t
Some text
#+name: test
| a | b | b | c |
| d | e | f | g |
|---+---+---+---|
| h | i | j | k |
#+TBLFM:
| a | b | b | c |
| d | e | f | g |
| h | i | j | k |
The following function hides the text snippet identified by org-element
as element at point.
Tables are such elements.
This works only on the #+NAME:
-line or the #+TBLFM:
-line since otherwise org-table-next-field
interferes.
(defun org+-hide-element-at-point-toggle (&optional force)
"Toggle the visibility of named paragraphs.
If FORCE is 'off make paragraph visible.
If FORCE is otherwise non-nil make paragraph invisible.
Otherwise toggle the visibility."
(interactive "P")
(let* ((par (org-element-at-point))
(start (org-element-property :contents-begin par))
(end (org-element-property :contents-end par))
(post (org-element-property :post-affiliated par)))
(when (and start end post)
(cond ((eq force 'off)
(org-flag-region start end nil 'org-hide-block))
(force
(org-flag-region start end t 'org-hide-block))
((eq (get-char-property start 'invisible) 'org-hide-block)
(org-flag-region start end nil 'org-hide-block))
(t
(org-flag-region start end t 'org-hide-block)))
;; When the block is hidden away, make sure point is left in
;; a visible part of the buffer.
(when (and post (invisible-p (max (1- (point)) (point-min))))
(goto-char post))
;; Signal success.
t)))
(add-hook 'org-tab-after-check-for-cycling-hook #'org+-hide-element-at-point-toggle)
Note, that this makes also paragraphs foldable.