Invisible text in emacs

| categories: emacs | tags:

Emacs supports invisible text . In other words, you can use code to set properties on text in a buffer that make it visible, or invisible. You can use code to change the invisibility properties of text.

I have been exploring ways to conditionally navigate in org documents using links. These links may validate that some property has been set in a heading, for example. An alternative approach is to make regions visible, depending on some criteria. That is what we do today. You will probably want to see this video , since what happens in this post is dynamic, and you will not see visible and invisible text.

What I have below here are a set of headings with properties that indicate what "level" they are at: beginner, medium and advanced. First, we mark each org subtree with an overlay that has an 'invisible property that contains the "level". Then, we add the "level" to the list of symbols that marks invisible sections. If you run this block, the headings all disappear.

(org-map-entries (lambda () 
                   (let ((level (org-entry-get (point) "level"))
                          (symbol-level))
                     (when level
                       (setq symbol-level (intern level))
                       (org-mark-subtree)                 
                       (overlay-put (make-overlay (point) (mark))
                                    'invisible 
                                    symbol-level)
                       ;; make regions with symbol-level invisible
                       (add-to-invisibility-spec `(,symbol-level))))))

Now, we can selectively make them appear with these links.

elisp:(remove-from-invisibility-spec '(beginner))

elisp:(remove-from-invisibility-spec '(medium))

elisp:(remove-from-invisibility-spec '(advanced))

I imagine this could be useful to show selective content based on user choices. I am not sure it is better than links to external files. I imagine you would have to open this org file by some elisp command that would run the block at the top to make everything invisible, and then show it to the user. You could definitely build in more complex code to determine if a user was allowed to open a section.

(defun level2-p ()
  "return if user is ready for level 2 based on value of property named correct"
  (interactive)
  (save-excursion
    (org-open-link-from-string "[[#beginner]]")
    (let ((val (org-entry-get (point) "correct")))
      (if (and val (string= val "true"))
          t
        nil))))
level2-p

Now, we can build this link:

elisp:(when (level2-p) (remove-from-invisibility-spec '(medium)))

This will show the medium level, provided we have already opened the beginner level and set the property value correctly.

1 subsection 1

some text in 1

2 subsection 2

more text in 2

3 subsection 3

last section 3

Copyright (C) 2014 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.5h

Discuss on Twitter