elisp: Invisible Text
37.6 Invisible Text
===================
You can make characters “invisible”, so that they do not appear on the
screen, with the ‘invisible’ property. This can be either a text
DONTPRINTYET property (Text Properties) or an overlay property (*noteDONTPRINTYET property (Text Properties) or an overlay property (
Overlays). Cursor motion also partly ignores these characters; if the
command loop finds that point is inside a range of invisible text after
a command, it relocates point to the other side of the text.
In the simplest case, any non-‘nil’ ‘invisible’ property makes a
character invisible. This is the default case—if you don’t alter the
default value of ‘buffer-invisibility-spec’, this is how the ‘invisible’
property works. You should normally use ‘t’ as the value of the
‘invisible’ property if you don’t plan to set ‘buffer-invisibility-spec’
yourself.
More generally, you can use the variable ‘buffer-invisibility-spec’
to control which values of the ‘invisible’ property make text invisible.
This permits you to classify the text into different subsets in advance,
by giving them different ‘invisible’ values, and subsequently make
various subsets visible or invisible by changing the value of
‘buffer-invisibility-spec’.
Controlling visibility with ‘buffer-invisibility-spec’ is especially
useful in a program to display the list of entries in a database. It
permits the implementation of convenient filtering commands to view just
a part of the entries in the database. Setting this variable is very
fast, much faster than scanning all the text in the buffer looking for
properties to change.
-- Variable: buffer-invisibility-spec
This variable specifies which kinds of ‘invisible’ properties
actually make a character invisible. Setting this variable makes
it buffer-local.
‘t’
A character is invisible if its ‘invisible’ property is
non-‘nil’. This is the default.
a list
Each element of the list specifies a criterion for
invisibility; if a character’s ‘invisible’ property fits any
one of these criteria, the character is invisible. The list
can have two kinds of elements:
‘ATOM’
A character is invisible if its ‘invisible’ property
value is ATOM or if it is a list with ATOM as a member;
comparison is done with ‘eq’.
‘(ATOM . t)’
A character is invisible if its ‘invisible’ property
value is ATOM or if it is a list with ATOM as a member;
comparison is done with ‘eq’. Moreover, a sequence of
such characters displays as an ellipsis.
Two functions are specifically provided for adding elements to
‘buffer-invisibility-spec’ and removing elements from it.
-- Function: add-to-invisibility-spec element
This function adds the element ELEMENT to
‘buffer-invisibility-spec’. If ‘buffer-invisibility-spec’ was ‘t’,
it changes to a list, ‘(t)’, so that text whose ‘invisible’
property is ‘t’ remains invisible.
-- Function: remove-from-invisibility-spec element
This removes the element ELEMENT from ‘buffer-invisibility-spec’.
This does nothing if ELEMENT is not in the list.
A convention for use of ‘buffer-invisibility-spec’ is that a major
mode should use the mode’s own name as an element of
‘buffer-invisibility-spec’ and as the value of the ‘invisible’ property:
;; If you want to display an ellipsis:
(add-to-invisibility-spec '(my-symbol . t))
;; If you don’t want ellipsis:
(add-to-invisibility-spec 'my-symbol)
(overlay-put (make-overlay beginning end)
'invisible 'my-symbol)
;; When done with the invisibility:
(remove-from-invisibility-spec '(my-symbol . t))
;; Or respectively:
(remove-from-invisibility-spec 'my-symbol)
You can check for invisibility using the following function:
-- Function: invisible-p pos-or-prop
If POS-OR-PROP is a marker or number, this function returns a
non-‘nil’ value if the text at that position is invisible.
If POS-OR-PROP is any other kind of Lisp object, that is taken to
mean a possible value of the ‘invisible’ text or overlay property.
In that case, this function returns a non-‘nil’ value if that value
would cause text to become invisible, based on the current value of
‘buffer-invisibility-spec’.
Ordinarily, functions that operate on text or move point do not care
whether the text is invisible, they process invisible characters and
visible characters alike. The user-level line motion commands, such as
‘next-line’, ‘previous-line’, ignore invisible newlines if
‘line-move-ignore-invisible’ is non-‘nil’ (the default), i.e., behave
like these invisible newlines didn’t exist in the buffer, but only
because they are explicitly programmed to do so.
If a command ends with point inside or at the boundary of invisible
text, the main editing loop relocates point to one of the two ends of
the invisible text. Emacs chooses the direction of relocation so that
it is the same as the overall movement direction of the command; if in
doubt, it prefers a position where an inserted char would not inherit
the ‘invisible’ property. Additionally, if the text is not replaced by
an ellipsis and the command only moved within the invisible text, then
point is moved one extra character so as to try and reflect the
command’s movement by a visible movement of the cursor.
Thus, if the command moved point back to an invisible range (with the
usual stickiness), Emacs moves point back to the beginning of that
range. If the command moved point forward into an invisible range,
Emacs moves point forward to the first visible character that follows
the invisible text and then forward one more character.
These “adjustments” of point that ended up in the middle of invisible
text can be disabled by setting ‘disable-point-adjustment’ to a
non-‘nil’ value. Adjusting Point.
Incremental search can make invisible overlays visible temporarily
and/or permanently when a match includes invisible text. To enable
this, the overlay should have a non-‘nil’ ‘isearch-open-invisible’
property. The property value should be a function to be called with the
overlay as an argument. This function should make the overlay visible
permanently; it is used when the match overlaps the overlay on exit from
the search.
During the search, such overlays are made temporarily visible by
temporarily modifying their invisible and intangible properties. If you
want this to be done differently for a certain overlay, give it an
‘isearch-open-invisible-temporary’ property which is a function. The
function is called with two arguments: the first is the overlay, and the
second is ‘nil’ to make the overlay visible, or ‘t’ to make it invisible
again.