comparison lisp/format.el @ 272:c5d627a313b1 r21-0b34

Import from CVS: tag r21-0b34
author cvs
date Mon, 13 Aug 2007 10:28:48 +0200
parents 557eaa0339bf
children 74fd4e045ea6
comparison
equal deleted inserted replaced
271:c7b7086b0a39 272:c5d627a313b1
48 ;; risk losing any text-properties in the buffer). 48 ;; risk losing any text-properties in the buffer).
49 ;; 49 ;;
50 ;; You can manually translate a buffer into or out of a particular format 50 ;; You can manually translate a buffer into or out of a particular format
51 ;; with the functions `format-encode-buffer' and `format-decode-buffer'. 51 ;; with the functions `format-encode-buffer' and `format-decode-buffer'.
52 ;; To translate just the region use the functions `format-encode-region' 52 ;; To translate just the region use the functions `format-encode-region'
53 ;; and `format-decode-region'. 53 ;; and `format-decode-region'.
54 ;; 54 ;;
55 ;; You can define a new format by writing the encoding and decoding 55 ;; You can define a new format by writing the encoding and decoding
56 ;; functions, and adding an entry to `format-alist'. See enriched.el for 56 ;; functions, and adding an entry to `format-alist'. See enriched.el for
57 ;; an example of how to implement a file format. There are various 57 ;; an example of how to implement a file format. There are various
58 ;; functions defined in this file that may be useful for writing the 58 ;; functions defined in this file that may be useful for writing the
92 richtext-decode richtext-encode t enriched-mode) 92 richtext-decode richtext-encode t enriched-mode)
93 (plain "ISO 8859-1 standard format, no text properties." 93 (plain "ISO 8859-1 standard format, no text properties."
94 ;; Plain only exists so that there is an obvious neutral choice in 94 ;; Plain only exists so that there is an obvious neutral choice in
95 ;; the completion list. 95 ;; the completion list.
96 nil nil nil nil nil) 96 nil nil nil nil nil)
97 ;; (ibm "IBM Code Page 850 (DOS)" 97 ;; (ibm "IBM Code Page 850 (DOS)"
98 ;; "1\\(^\\)" 98 ;; "1\\(^\\)"
99 ;; "recode ibm-pc:latin1" "recode latin1:ibm-pc" t nil) 99 ;; "recode ibm-pc:latin1" "recode latin1:ibm-pc" t nil)
100 ;; (mac "Apple Macintosh" 100 ;; (mac "Apple Macintosh"
101 ;; "1\\(^\\)" 101 ;; "1\\(^\\)"
102 ;; "recode mac:latin1" "recode latin1:mac" t nil) 102 ;; "recode mac:latin1" "recode latin1:mac" t nil)
103 ;; (hp "HP Roman8" 103 ;; (hp "HP Roman8"
104 ;; "1\\(^\\)" 104 ;; "1\\(^\\)"
105 ;; "recode roman8:latin1" "recode latin1:roman8" t nil) 105 ;; "recode roman8:latin1" "recode latin1:roman8" t nil)
106 ;; (TeX "TeX (encoding)" 106 ;; (TeX "TeX (encoding)"
107 ;; "1\\(^\\)" 107 ;; "1\\(^\\)"
108 ;; iso-tex2iso iso-iso2tex t nil) 108 ;; iso-tex2iso iso-iso2tex t nil)
109 ;; (gtex "German TeX (encoding)" 109 ;; (gtex "German TeX (encoding)"
110 ;; "1\\(^\\)" 110 ;; "1\\(^\\)"
111 ;; iso-gtex2iso iso-iso2gtex t nil) 111 ;; iso-gtex2iso iso-iso2gtex t nil)
112 ;; (html "HTML (encoding)" 112 ;; (html "HTML (encoding)"
113 ;; "1\\(^\\)" 113 ;; "1\\(^\\)"
114 ;; "recode html:latin1" "recode latin1:html" t nil) 114 ;; "recode html:latin1" "recode latin1:html" t nil)
115 ;; (rot13 "rot13" 115 ;; (rot13 "rot13"
116 ;; "1\\(^\\)" 116 ;; "1\\(^\\)"
117 ;; "tr a-mn-z n-za-m" "tr a-mn-z n-za-m" t nil) 117 ;; "tr a-mn-z n-za-m" "tr a-mn-z n-za-m" t nil)
118 ;; (duden "Duden Ersatzdarstellung" 118 ;; (duden "Duden Ersatzdarstellung"
119 ;; "1\\(^\\)" 119 ;; "1\\(^\\)"
120 ;; "diac" iso-iso2duden t nil) 120 ;; "diac" iso-iso2duden t nil)
121 ;; (de646 "German ASCII (ISO 646)" 121 ;; (de646 "German ASCII (ISO 646)"
122 ;; "1\\(^\\)" 122 ;; "1\\(^\\)"
123 ;; "recode iso646-ge:latin1" "recode latin1:iso646-ge" t nil) 123 ;; "recode iso646-ge:latin1" "recode latin1:iso646-ge" t nil)
124 ;; (denet "net German" 124 ;; (denet "net German"
125 ;; "1\\(^\\)" 125 ;; "1\\(^\\)"
126 ;; iso-german iso-cvt-read-only t nil) 126 ;; iso-german iso-cvt-read-only t nil)
127 ;; (esnet "net Spanish" 127 ;; (esnet "net Spanish"
128 ;; "1\\(^\\)" 128 ;; "1\\(^\\)"
129 ;; iso-spanish iso-cvt-read-only t nil) 129 ;; iso-spanish iso-cvt-read-only t nil)
130 ) 130 )
131 "List of information about understood file formats. 131 "List of information about understood file formats.
132 Elements are of the form \(NAME DOC-STR REGEXP FROM-FN TO-FN MODIFY MODE-FN). 132 Elements are of the form \(NAME DOC-STR REGEXP FROM-FN TO-FN MODIFY MODE-FN).
138 the user if they ask for more information. 138 the user if they ask for more information.
139 139
140 REGEXP is a regular expression to match against the beginning of the file; 140 REGEXP is a regular expression to match against the beginning of the file;
141 it should match only files in that format. 141 it should match only files in that format.
142 142
143 FROM-FN is called to decode files in that format; it gets two args, BEGIN 143 FROM-FN is called to decode files in that format; it gets two args, BEGIN
144 and END, and can make any modifications it likes, returning the new 144 and END, and can make any modifications it likes, returning the new
145 end. It must make sure that the beginning of the file no longer 145 end. It must make sure that the beginning of the file no longer
146 matches REGEXP, or else it will get called again. 146 matches REGEXP, or else it will get called again.
147 Alternatively, FROM-FN can be a string, which specifies a shell command 147 Alternatively, FROM-FN can be a string, which specifies a shell command
148 (including options) to be used as a filter to perform the conversion. 148 (including options) to be used as a filter to perform the conversion.
156 Alternatively, TO-FN can be a string, which specifies a shell command 156 Alternatively, TO-FN can be a string, which specifies a shell command
157 (including options) to be used as a filter to perform the conversion. 157 (including options) to be used as a filter to perform the conversion.
158 158
159 MODIFY, if non-nil, means the TO-FN wants to modify the region. If nil, 159 MODIFY, if non-nil, means the TO-FN wants to modify the region. If nil,
160 TO-FN will not make any changes but will instead return a list of 160 TO-FN will not make any changes but will instead return a list of
161 annotations. 161 annotations.
162 162
163 MODE-FN, if specified, is called when visiting a file with that format.") 163 MODE-FN, if specified, is called when visiting a file with that format.")
164 164
165 ;;; Basic Functions (called from Lisp) 165 ;;; Basic Functions (called from Lisp)
166 166
187 (shell-command-on-region from to method t nil)) 187 (shell-command-on-region from to method t nil))
188 (point)) 188 (point))
189 (funcall method from to))) 189 (funcall method from to)))
190 190
191 (defun format-annotate-function (format from to orig-buf) 191 (defun format-annotate-function (format from to orig-buf)
192 "Returns annotations for writing region as FORMAT. 192 "Return annotations for writing region as FORMAT.
193 FORMAT is a symbol naming one of the formats defined in `format-alist', 193 FORMAT is a symbol naming one of the formats defined in `format-alist',
194 it must be a single symbol, not a list like `buffer-file-format'. 194 it must be a single symbol, not a list like `buffer-file-format'.
195 FROM and TO delimit the region to be operated on in the current buffer. 195 FROM and TO delimit the region to be operated on in the current buffer.
196 ORIG-BUF is the original buffer that the data came from. 196 ORIG-BUF is the original buffer that the data came from.
197 This function works like a function on `write-region-annotate-functions': 197 This function works like a function on `write-region-annotate-functions':
198 it either returns a list of annotations, or returns with a different buffer 198 it either returns a list of annotations, or returns with a different buffer
199 current, which contains the modified text to write. 199 current, which contains the modified text to write.
200 200
201 For most purposes, consider using `format-encode-region' instead." 201 For most purposes, consider using `format-encode-region' instead."
202 ;; This function is called by write-region (actually build-annotations) 202 ;; This function is called by write-region (actually build-annotations)
203 ;; for each element of buffer-file-format. 203 ;; for each element of buffer-file-format.
204 (let* ((info (assq format format-alist)) 204 (let* ((info (assq format format-alist))
205 (to-fn (nth 4 info)) 205 (to-fn (nth 4 info))
206 (modify (nth 5 info))) 206 (modify (nth 5 info)))
207 (if to-fn 207 (if to-fn
216 ;; Otherwise just call function, it will return annotations. 216 ;; Otherwise just call function, it will return annotations.
217 (funcall to-fn from to orig-buf))))) 217 (funcall to-fn from to orig-buf)))))
218 218
219 (defun format-decode (format length &optional visit-flag) 219 (defun format-decode (format length &optional visit-flag)
220 "Decode text from any known FORMAT. 220 "Decode text from any known FORMAT.
221 FORMAT is a symbol appearing in `format-alist' or a list of such symbols, 221 FORMAT is a symbol appearing in `format-alist' or a list of such symbols,
222 or nil, in which case this function tries to guess the format of the data by 222 or nil, in which case this function tries to guess the format of the data by
223 matching against the regular expressions in `format-alist'. After a match is 223 matching against the regular expressions in `format-alist'. After a match is
224 found and the region decoded, the alist is searched again from the beginning 224 found and the region decoded, the alist is searched again from the beginning
225 for another match. 225 for another match.
226 226
281 ;;; 281 ;;;
282 282
283 (defun format-decode-buffer (&optional format) 283 (defun format-decode-buffer (&optional format)
284 "Translate the buffer from some FORMAT. 284 "Translate the buffer from some FORMAT.
285 If the format is not specified, this function attempts to guess. 285 If the format is not specified, this function attempts to guess.
286 `buffer-file-format' is set to the format used, and any mode-functions 286 `buffer-file-format' is set to the format used, and any mode-functions
287 for the format are called." 287 for the format are called."
288 (interactive 288 (interactive
289 (list (format-read "Translate buffer from format (default: guess): "))) 289 (list (format-read "Translate buffer from format (default: guess): ")))
290 (save-excursion 290 (save-excursion
291 (goto-char (point-min)) 291 (goto-char (point-min))
294 (defun format-decode-region (from to &optional format) 294 (defun format-decode-region (from to &optional format)
295 "Decode the region from some format. 295 "Decode the region from some format.
296 Arg FORMAT is optional; if omitted the format will be determined by looking 296 Arg FORMAT is optional; if omitted the format will be determined by looking
297 for identifying regular expressions at the beginning of the region." 297 for identifying regular expressions at the beginning of the region."
298 (interactive 298 (interactive
299 (list (region-beginning) (region-end) 299 (list (region-beginning) (region-end)
300 (format-read "Translate region from format (default: guess): "))) 300 (format-read "Translate region from format (default: guess): ")))
301 (save-excursion 301 (save-excursion
302 (goto-char from) 302 (goto-char from)
303 (format-decode format (- to from) nil))) 303 (format-decode format (- to from) nil)))
304 304
323 (if (symbolp format) (setq format (list format))) 323 (if (symbolp format) (setq format (list format)))
324 (save-excursion 324 (save-excursion
325 (goto-char end) 325 (goto-char end)
326 (let ( ; (cur-buf (current-buffer)) 326 (let ( ; (cur-buf (current-buffer))
327 (end (point-marker))) 327 (end (point-marker)))
328 (while format 328 (while format
329 (let* ((info (assq (car format) format-alist)) 329 (let* ((info (assq (car format) format-alist))
330 (to-fn (nth 4 info)) 330 (to-fn (nth 4 info))
331 (modify (nth 5 info)) 331 (modify (nth 5 info))
332 ;; result 332 ;; result
333 ) 333 )
351 nil nil nil nil) 351 nil nil nil nil)
352 (read-file-name "Write file: " 352 (read-file-name "Write file: "
353 (cdr (assq 'default-directory 353 (cdr (assq 'default-directory
354 (buffer-local-variables))) 354 (buffer-local-variables)))
355 nil nil (buffer-name)))) 355 nil nil (buffer-name))))
356 (fmt (format-read (format "Write file `%s' in format: " 356 (fmt (format-read (format "Write file `%s' in format: "
357 (file-name-nondirectory file))))) 357 (file-name-nondirectory file)))))
358 (list file fmt))) 358 (list file fmt)))
359 (setq buffer-file-format format) 359 (setq buffer-file-format format)
360 (write-file filename)) 360 (write-file filename))
361 361
363 "Find the file FILE using data format FORMAT. 363 "Find the file FILE using data format FORMAT.
364 If FORMAT is nil then do not do any format conversion." 364 If FORMAT is nil then do not do any format conversion."
365 (interactive 365 (interactive
366 ;; Same interactive spec as write-file, plus format question. 366 ;; Same interactive spec as write-file, plus format question.
367 (let* ((file (read-file-name "Find file: ")) 367 (let* ((file (read-file-name "Find file: "))
368 (fmt (format-read (format "Read file `%s' in format: " 368 (fmt (format-read (format "Read file `%s' in format: "
369 (file-name-nondirectory file))))) 369 (file-name-nondirectory file)))))
370 (list file fmt))) 370 (list file fmt)))
371 (let ((format-alist nil)) 371 (let ((format-alist nil))
372 (find-file filename)) 372 (find-file filename))
373 (if format 373 (if format
382 The return value is like the value of `insert-file-contents': 382 The return value is like the value of `insert-file-contents':
383 a list (ABSOLUTE-FILE-NAME . SIZE)." 383 a list (ABSOLUTE-FILE-NAME . SIZE)."
384 (interactive 384 (interactive
385 ;; Same interactive spec as write-file, plus format question. 385 ;; Same interactive spec as write-file, plus format question.
386 (let* ((file (read-file-name "Find file: ")) 386 (let* ((file (read-file-name "Find file: "))
387 (fmt (format-read (format "Read file `%s' in format: " 387 (fmt (format-read (format "Read file `%s' in format: "
388 (file-name-nondirectory file))))) 388 (file-name-nondirectory file)))))
389 (list file fmt))) 389 (list file fmt)))
390 (let (value size) 390 (let (value size)
391 (let ((format-alist nil)) 391 (let ((format-alist nil))
392 (setq value (insert-file-contents filename nil beg end)) 392 (setq value (insert-file-contents filename nil beg end))
415 "Do multiple replacements on the buffer. 415 "Do multiple replacements on the buffer.
416 ALIST is a list of (from . to) pairs, which should be proper arguments to 416 ALIST is a list of (from . to) pairs, which should be proper arguments to
417 `search-forward' and `replace-match' respectively. 417 `search-forward' and `replace-match' respectively.
418 Optional 2nd arg REVERSE, if non-nil, means the pairs are (to . from), so that 418 Optional 2nd arg REVERSE, if non-nil, means the pairs are (to . from), so that
419 you can use the same list in both directions if it contains only literal 419 you can use the same list in both directions if it contains only literal
420 strings. 420 strings.
421 Optional args BEGIN and END specify a region of the buffer to operate on." 421 Optional args BEGIN and END specify a region of the buffer to operate on."
422 (save-excursion 422 (save-excursion
423 (save-restriction 423 (save-restriction
424 (or beg (setq beg (point-min))) 424 (or beg (setq beg (point-min)))
425 (if end (narrow-to-region (point-min) end)) 425 (if end (narrow-to-region (point-min) end))
438 438
439 ;;; Some list-manipulation functions that we need. 439 ;;; Some list-manipulation functions that we need.
440 440
441 (defun format-delq-cons (cons list) 441 (defun format-delq-cons (cons list)
442 "Remove the given CONS from LIST by side effect, 442 "Remove the given CONS from LIST by side effect,
443 and return the new LIST. Since CONS could be the first element 443 and return the new LIST. Since CONS could be the first element
444 of LIST, write `\(setq foo \(format-delq-cons element foo))' to be sure of 444 of LIST, write `\(setq foo \(format-delq-cons element foo))' to be sure of
445 changing the value of `foo'." 445 changing the value of `foo'."
446 (if (eq cons list) 446 (if (eq cons list)
447 (cdr list) 447 (cdr list)
448 (let ((p list)) 448 (let ((p list))
449 (while (not (eq (cdr p) cons)) 449 (while (not (eq (cdr p) cons))
450 (if (null p) (error "format-delq-cons: not an element.")) 450 (if (null p) (error "format-delq-cons: not an element."))
451 (setq p (cdr p))) 451 (setq p (cdr p)))
452 ;; Now (cdr p) is the cons to delete 452 ;; Now (cdr p) is the cons to delete
453 (setcdr p (cdr cons)) 453 (setcdr p (cdr cons))
454 list))) 454 list)))
455 455
456 (defun format-make-relatively-unique (a b) 456 (defun format-make-relatively-unique (a b)
457 "Delete common elements of lists A and B, return as pair. 457 "Delete common elements of lists A and B, return as pair.
458 Compares using `equal'." 458 Compares using `equal'."
459 (let* ((acopy (copy-sequence a)) 459 (let* ((acopy (copy-sequence a))
460 (bcopy (copy-sequence b)) 460 (bcopy (copy-sequence b))
473 equivalent part of B. If even the last items of the two are not equal, 473 equivalent part of B. If even the last items of the two are not equal,
474 returns nil." 474 returns nil."
475 (let ((la (length a)) 475 (let ((la (length a))
476 (lb (length b))) 476 (lb (length b)))
477 ;; Make sure they are the same length 477 ;; Make sure they are the same length
478 (if (> la lb) 478 (if (> la lb)
479 (setq a (nthcdr (- la lb) a)) 479 (setq a (nthcdr (- la lb) a))
480 (setq b (nthcdr (- lb la) b)))) 480 (setq b (nthcdr (- lb la) b))))
481 (while (not (equal a b)) 481 (while (not (equal a b))
482 (setq a (cdr a) 482 (setq a (cdr a)
483 b (cdr b))) 483 b (cdr b)))
488 Elements of ITEMS equal to elements of ORDER will be rearranged to follow the 488 Elements of ITEMS equal to elements of ORDER will be rearranged to follow the
489 ORDER. Unmatched items will go last." 489 ORDER. Unmatched items will go last."
490 (if order 490 (if order
491 (let ((item (member (car order) items))) 491 (let ((item (member (car order) items)))
492 (if item 492 (if item
493 (cons (car item) 493 (cons (car item)
494 (format-reorder (format-delq-cons item items) 494 (format-reorder (format-delq-cons item items)
495 (cdr order))) 495 (cdr order)))
496 (format-reorder items (cdr order)))) 496 (format-reorder items (cdr order))))
497 items)) 497 items))
498 498
506 ;;; Decoding 506 ;;; Decoding
507 ;;; 507 ;;;
508 508
509 (defun format-deannotate-region (from to translations next-fn) 509 (defun format-deannotate-region (from to translations next-fn)
510 "Translate annotations in the region into text properties. 510 "Translate annotations in the region into text properties.
511 This sets text properties between FROM to TO as directed by the 511 This sets text properties between FROM to TO as directed by the
512 TRANSLATIONS and NEXT-FN arguments. 512 TRANSLATIONS and NEXT-FN arguments.
513 513
514 NEXT-FN is a function that searches forward from point for an annotation. 514 NEXT-FN is a function that searches forward from point for an annotation.
515 It should return a list of 4 elements: \(BEGIN END NAME POSITIVE). BEGIN and 515 It should return a list of 4 elements: \(BEGIN END NAME POSITIVE). BEGIN and
516 END are buffer positions bounding the annotation, NAME is the name searched 516 END are buffer positions bounding the annotation, NAME is the name searched
708 (subtrahend (copy-alist subtra)) 708 (subtrahend (copy-alist subtra))
709 (m (car minuend)) 709 (m (car minuend))
710 (s (car subtrahend)) 710 (s (car subtrahend))
711 results) 711 results)
712 (while (and minuend subtrahend) 712 (while (and minuend subtrahend)
713 (cond 713 (cond
714 ;; The minuend starts after the subtrahend ends; keep it. 714 ;; The minuend starts after the subtrahend ends; keep it.
715 ((> (car m) (cdr s)) 715 ((> (car m) (cdr s))
716 (setq results (cons m results) 716 (setq results (cons m results)
717 minuend (cdr minuend) 717 minuend (cdr minuend)
718 m (car minuend))) 718 m (car minuend)))
756 Inserts each element of the given LIST of buffer annotations at its 756 Inserts each element of the given LIST of buffer annotations at its
757 appropriate place. Use second arg OFFSET if the annotations' locations are 757 appropriate place. Use second arg OFFSET if the annotations' locations are
758 not relative to the beginning of the buffer: annotations will be inserted 758 not relative to the beginning of the buffer: annotations will be inserted
759 at their location-OFFSET+1 \(ie, the offset is treated as the character number 759 at their location-OFFSET+1 \(ie, the offset is treated as the character number
760 of the first character in the buffer)." 760 of the first character in the buffer)."
761 (if (not offset) 761 (if (not offset)
762 (setq offset 0) 762 (setq offset 0)
763 (setq offset (1- offset))) 763 (setq offset (1- offset)))
764 (let ((l (reverse list))) 764 (let ((l (reverse list)))
765 (while l 765 (while l
766 (goto-char (- (car (car l)) offset)) 766 (goto-char (- (car (car l)) offset))
790 elements are VALUES of that property followed by the names of zero or more 790 elements are VALUES of that property followed by the names of zero or more
791 ANNOTATIONS. Whenever the property takes on that value, the annotations 791 ANNOTATIONS. Whenever the property takes on that value, the annotations
792 \(as formatted by FORMAT-FN) are inserted into the file. 792 \(as formatted by FORMAT-FN) are inserted into the file.
793 When the property stops having that value, the matching negated annotation 793 When the property stops having that value, the matching negated annotation
794 will be inserted \(it may actually be closed earlier and reopened, if 794 will be inserted \(it may actually be closed earlier and reopened, if
795 necessary, to keep proper nesting). 795 necessary, to keep proper nesting).
796 796
797 If the property's value is a list, then each element of the list is dealt with 797 If the property's value is a list, then each element of the list is dealt with
798 separately. 798 separately.
799 799
800 If a VALUE is numeric, then it is assumed that there is a single annotation 800 If a VALUE is numeric, then it is assumed that there is a single annotation
832 (message "Can't close %s: not open." (car neg-ans)) 832 (message "Can't close %s: not open." (car neg-ans))
833 (while (not (equal (car neg-ans) (car open-ans))) 833 (while (not (equal (car neg-ans) (car open-ans)))
834 ;; To close anno. N, need to first close ans 1 to N-1, 834 ;; To close anno. N, need to first close ans 1 to N-1,
835 ;; remembering to re-open them later. 835 ;; remembering to re-open them later.
836 (setq pos-ans (cons (car open-ans) pos-ans)) 836 (setq pos-ans (cons (car open-ans) pos-ans))
837 (setq all-ans 837 (setq all-ans
838 (cons (cons loc (funcall format-fn (car open-ans) nil)) 838 (cons (cons loc (funcall format-fn (car open-ans) nil))
839 all-ans)) 839 all-ans))
840 (setq open-ans (cdr open-ans))) 840 (setq open-ans (cdr open-ans)))
841 ;; Now remove the one we're really interested in from open list. 841 ;; Now remove the one we're really interested in from open list.
842 (setq open-ans (cdr open-ans)) 842 (setq open-ans (cdr open-ans))
843 ;; And put the closing annotation here. 843 ;; And put the closing annotation here.
844 (setq all-ans 844 (setq all-ans
845 (cons (cons loc (funcall format-fn (car neg-ans) nil)) 845 (cons (cons loc (funcall format-fn (car neg-ans) nil))
846 all-ans))) 846 all-ans)))
847 (setq neg-ans (cdr neg-ans))) 847 (setq neg-ans (cdr neg-ans)))
848 ;; Now deal with positive (opening) annotations 848 ;; Now deal with positive (opening) annotations
849 (let ( ; (p pos-ans) 849 (let ( ; (p pos-ans)
850 ) 850 )
851 (while pos-ans 851 (while pos-ans
852 (setq open-ans (cons (car pos-ans) open-ans)) 852 (setq open-ans (cons (car pos-ans) open-ans))
853 (setq all-ans 853 (setq all-ans
854 (cons (cons loc (funcall format-fn (car pos-ans) t)) 854 (cons (cons loc (funcall format-fn (car pos-ans) t))
855 all-ans)) 855 all-ans))
856 (setq pos-ans (cdr pos-ans)))))) 856 (setq pos-ans (cdr pos-ans))))))
857 857
858 ;; Close any annotations still open 858 ;; Close any annotations still open
859 (while open-ans 859 (while open-ans
860 (setq all-ans 860 (setq all-ans
861 (cons (cons to (funcall format-fn (car open-ans) nil)) 861 (cons (cons to (funcall format-fn (car open-ans) nil))
862 all-ans)) 862 all-ans))
863 (setq open-ans (cdr open-ans))) 863 (setq open-ans (cdr open-ans)))
864 (if not-found 864 (if not-found
865 (message "These text properties could not be saved:\n %s" 865 (message "These text properties could not be saved:\n %s"
928 (let* ((old (if (listp old) old (list old))) 928 (let* ((old (if (listp old) old (list old)))
929 (new (if (listp new) new (list new))) 929 (new (if (listp new) new (list new)))
930 ;; (tail (format-common-tail old new)) 930 ;; (tail (format-common-tail old new))
931 close open) 931 close open)
932 (while old 932 (while old
933 (setq close 933 (setq close
934 (append (car (format-annotate-atomic-property-change 934 (append (car (format-annotate-atomic-property-change
935 prop-alist (car old) nil)) 935 prop-alist (car old) nil))
936 close) 936 close)
937 old (cdr old))) 937 old (cdr old)))
938 (while new 938 (while new
939 (setq open 939 (setq open
940 (append (cdr (format-annotate-atomic-property-change 940 (append (cdr (format-annotate-atomic-property-change
941 prop-alist nil (car new))) 941 prop-alist nil (car new)))
942 open) 942 open)
943 new (cdr new))) 943 new (cdr new)))
944 (format-make-relatively-unique close open)) 944 (format-make-relatively-unique close open))