Function: format-annotate-region

format-annotate-region is a byte-compiled function defined in format.el.gz.

Signature

(format-annotate-region FROM TO TRANSLATIONS FORMAT-FN IGNORE)

Documentation

Generate annotations for text properties in the region.

Search for changes between FROM and TO, and describe them with a list of annotations as defined by alist TRANSLATIONS and FORMAT-FN. IGNORE lists text properties not to consider; any text properties that are neither ignored nor listed in TRANSLATIONS are warned about. If you actually want to modify the region, give the return value of this function to format-insert-annotations.

Format of the TRANSLATIONS argument:

Each element is a list whose car is a PROPERTY, and the following elements have the form (VALUE ANNOTATIONS...). Whenever the property takes on the value VALUE, the annotations
(as formatted by FORMAT-FN) are inserted into the file.
When the property stops having that value, the matching negated annotation will be inserted (it may actually be closed earlier and reopened, if necessary, to keep proper nesting).

If VALUE is a list, then each element of the list is dealt with separately.

If a VALUE is numeric, then it is assumed that there is a single annotation and each occurrence of it increments the value of the property by that number. Thus, given the entry (left-margin (4 "indent")), if the left margin changes from 4 to 12, two <indent> annotations will be generated.

If the VALUE is nil, then instead of annotations, a function should be specified. This function is used as a default: it is called for all transitions not explicitly listed in the table. The function is called with two arguments, the OLD and NEW values of the property. It should return a cons cell (CLOSE . OPEN) as format-annotate-single-property-change does.

The same TRANSLATIONS structure can be used in reverse for reading files.

Source Code

;; Defined in /usr/src/emacs/lisp/format.el.gz
(defun format-annotate-region (from to translations format-fn ignore)
  "Generate annotations for text properties in the region.
Search for changes between FROM and TO, and describe them with a list of
annotations as defined by alist TRANSLATIONS and FORMAT-FN.  IGNORE lists text
properties not to consider; any text properties that are neither ignored nor
listed in TRANSLATIONS are warned about.
If you actually want to modify the region, give the return value of this
function to `format-insert-annotations'.

Format of the TRANSLATIONS argument:

Each element is a list whose car is a PROPERTY, and the following
elements have the form (VALUE ANNOTATIONS...).
Whenever the property takes on the value VALUE, the annotations
\(as formatted by FORMAT-FN) are inserted into the file.
When the property stops having that value, the matching negated annotation
will be inserted \(it may actually be closed earlier and reopened, if
necessary, to keep proper nesting).

If VALUE is a list, then each element of the list is dealt with
separately.

If a VALUE is numeric, then it is assumed that there is a single annotation
and each occurrence of it increments the value of the property by that number.
Thus, given the entry \(left-margin \(4 \"indent\")), if the left margin
changes from 4 to 12, two <indent> annotations will be generated.

If the VALUE is nil, then instead of annotations, a function should be
specified.  This function is used as a default: it is called for all
transitions not explicitly listed in the table.  The function is called with
two arguments, the OLD and NEW values of the property.  It should return
a cons cell (CLOSE . OPEN) as `format-annotate-single-property-change' does.

The same TRANSLATIONS structure can be used in reverse for reading files."
  (let ((all-ans nil)    ; All annotations - becomes return value
	(open-ans nil)   ; Annotations not yet closed
	(loc nil)	 ; Current location
	(not-found nil)) ; Properties that couldn't be saved
    (while (or (null loc)
	       (and (setq loc (next-property-change loc nil to))
		    (< loc to)))
      (or loc (setq loc from))
      (let* ((ans (format-annotate-location loc (= loc from) ignore translations))
	     (neg-ans (format-reorder (aref ans 0) open-ans))
	     (pos-ans (aref ans 1))
	     (ignored (aref ans 2)))
	(setq not-found (append ignored not-found)
	      ignore    (append ignored ignore))
	;; First do the negative (closing) annotations
	(while neg-ans
	  ;; Check if it's missing.  This can happen (eg, a numeric property
	  ;; going negative can generate closing annotations before there are
	  ;; any open).  Warn user & ignore.
	  (if (not (member (car neg-ans) open-ans))
	      (message "Can't close %s: not open." (car neg-ans))
	    (while (not (equal (car neg-ans) (car open-ans)))
	      ;; To close anno. N, need to first close ans 1 to N-1,
	      ;; remembering to re-open them later.
	      (push (car open-ans) pos-ans)
	      (setq all-ans
		    (cons (cons loc (funcall format-fn (car open-ans) nil))
			  all-ans))
	      (setq open-ans (cdr open-ans)))
	    ;; Now remove the one we're really interested in from open list.
	    (setq open-ans (cdr open-ans))
	    ;; And put the closing annotation here.
	    (push (cons loc (funcall format-fn (car neg-ans) nil))
		  all-ans))
	  (setq neg-ans (cdr neg-ans)))
	;; Now deal with positive (opening) annotations
        (while pos-ans
          (push (car pos-ans) open-ans)
          (push (cons loc (funcall format-fn (car pos-ans) t))
                all-ans)
          (setq pos-ans (cdr pos-ans)))))

    ;; Close any annotations still open
    (while open-ans
      (setq all-ans
	    (cons (cons to (funcall format-fn (car open-ans) nil))
		  all-ans))
      (setq open-ans (cdr open-ans)))
    (if not-found
	(message "These text properties could not be saved:\n    %s"
		 not-found))
    (nreverse all-ans)))