2

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 2

2

To get this

Fold / Unfold Tables at point Fold/Unfold Tables at Point

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 |



1

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.

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.