;;; format.el --- read and save files in multiple formats
-;; Copyright (c) 1994, 1995, 1997, 1999 Free Software Foundation
+;; Copyright (C) 1994, 1995, 1997, 1999, 2002, 2003, 2004,
+;; 2005, 2006 Free Software Foundation, Inc.
;; Author: Boris Goldowsky <boris@gnu.org>
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; change this variable, or use `format-write-file'.
;;
;; Auto-save files are normally created in the same format as the visited
-;; file, but the variable `auto-save-file-format' can be set to a
+;; file, but the variable `buffer-auto-save-file-format' can be set to a
;; particularly fast or otherwise preferred format to be used for
;; auto-saving (or nil to do no encoding on auto-save files, but then you
;; risk losing any text-properties in the buffer).
;;; Code:
(put 'buffer-file-format 'permanent-local t)
+(put 'buffer-auto-save-file-format 'permanent-local t)
(defvar format-alist
'((text/enriched "Extended MIME text/enriched format."
MODE-FN, if specified, is called when visiting a file with that format.
It is called with a single positive argument, on the assumption
- that it turns on some Emacs mode.")
+ that it turns on some Emacs mode.
+
+PRESERVE, if non-nil, means that `format-write-file' should not remove
+ this format from `buffer-file-formats'.")
;;; Basic Functions (called from Lisp)
(if modify
;; To-function wants to modify region. Copy to safe place.
(let ((copy-buf (get-buffer-create (format " *Format Temp %d*"
- format-count))))
+ format-count)))
+ (sel-disp selective-display)
+ (multibyte enable-multibyte-characters)
+ (coding-system buffer-file-coding-system))
+ (with-current-buffer copy-buf
+ (setq selective-display sel-disp)
+ (set-buffer-multibyte multibyte)
+ (setq buffer-file-coding-system coding-system))
(copy-to-buffer copy-buf from to)
(set-buffer copy-buf)
(format-insert-annotations write-region-annotations-so-far from)
Second arg LENGTH is the number of characters following point to operate on.
If optional third arg VISIT-FLAG is true, set `buffer-file-format'
-to the list of formats used, and call any mode functions defined for those
-formats.
+to the reverted list of formats used, and call any mode functions defined
+for those formats.
Returns the new length of the decoded region.
(unwind-protect
(progn
;; Don't record undo information for the decoding.
-
+
(if (null format)
;; Figure out which format it is in, remember list in `format'.
(let ((try format-alist))
(if (and regexp (looking-at regexp)
(< (match-end 0) (+ begin length)))
(progn
- (setq format (cons (car f) format))
+ (push (car f) format)
;; Decode it
(if (nth 3 f)
(setq end (format-decode-run-method (nth 3 f) begin end)))
(let ((do format) f)
(while do
(or (setq f (assq (car do) format-alist))
- (error "Unknown format" (car do)))
+ (error "Unknown format %s" (car do)))
;; Decode:
(if (nth 3 f)
(setq end (format-decode-run-method (nth 3 f) begin end)))
;; Call visit function if required
(if (and visit-flag (nth 6 f)) (funcall (nth 6 f) 1))
- (setq do (cdr do)))))
+ (setq do (cdr do))))
+ ;; Encode in the opposite order.
+ (setq format (reverse format)))
(if visit-flag
(setq buffer-file-format format)))
-
+
(set-buffer-modified-p mod))
;; Return new length of region
`buffer-file-format' is set to the format used, and any mode-functions
for the format are called."
(interactive
- (list (format-read "Translate buffer from format (default: guess): ")))
+ (list (format-read "Translate buffer from format (default guess): ")))
(save-excursion
(goto-char (point-min))
(format-decode format (buffer-size) t)))
for identifying regular expressions at the beginning of the region."
(interactive
(list (region-beginning) (region-end)
- (format-read "Translate region from format (default: guess): ")))
+ (format-read "Translate region from format (default guess): ")))
(save-excursion
(goto-char from)
(format-decode format (- to from) nil)))
(funcall to-fn beg end (current-buffer)))))
(setq format (cdr format)))))))
-(defun format-write-file (filename format)
+(defun format-write-file (filename format &optional confirm)
"Write current buffer into file FILENAME using some FORMAT.
-Makes buffer visit that file and sets the format as the default for future
+Make buffer visit that file and set the format as the default for future
saves. If the buffer is already visiting a file, you can specify a directory
-name as FILENAME, to write a file of the same old name in that directory."
+name as FILENAME, to write a file of the same old name in that directory.
+
+If optional third arg CONFIRM is non-nil, this function asks for
+confirmation before overwriting an existing file. Interactively,
+confirmation is required unless you supply a prefix argument."
(interactive
;; Same interactive spec as write-file, plus format question.
(let* ((file (if buffer-file-name
nil nil (buffer-name))))
(fmt (format-read (format "Write file `%s' in format: "
(file-name-nondirectory file)))))
- (list file fmt)))
- (setq buffer-file-format format)
- (write-file filename))
+ (list file fmt (not current-prefix-arg))))
+ (let ((old-formats buffer-file-format)
+ preserve-formats)
+ (dolist (fmt old-formats)
+ (let ((aelt (assq fmt format-alist)))
+ (if (nth 7 aelt)
+ (push fmt preserve-formats))))
+ (setq buffer-file-format format)
+ (dolist (fmt preserve-formats)
+ (unless (memq fmt buffer-file-format)
+ (setq buffer-file-format (append buffer-file-format (list fmt))))))
+ (write-file filename confirm))
(defun format-find-file (filename format)
"Find the file FILENAME using data format FORMAT.
the part of the file to read.
The return value is like the value of `insert-file-contents':
-a list (ABSOLUTE-FILE-NAME . SIZE)."
+a list (ABSOLUTE-FILE-NAME SIZE)."
(interactive
;; Same interactive spec as write-file, plus format question.
(let* ((file (read-file-name "Find file: "))
(setq size (nth 1 value)))
(if format
(setq size (format-decode format size)
- value (cons (car value) size)))
+ value (list (car value) size)))
value))
(defun format-read (&optional prompt)
;; Now (cdr p) is the cons to delete
(setcdr p (cdr cons))
list)))
-
+
(defun format-make-relatively-unique (a b)
"Delete common elements of lists A and B, return as pair.
Compares using `equal'."
(delete-region loc end)
(cond
;; Positive annotations are stacked, remembering location
- (positive (setq open-ans (cons `(,name ((,loc . nil))) open-ans)))
+ (positive (push `(,name ((,loc . nil))) open-ans))
;; It is a negative annotation:
;; Close the top annotation & add its text property.
;; If the file's nesting is messed up, the close might not match
;; Not a property, but a function.
(let ((rtn
(apply value start loc params)))
- (if rtn (setq todo (cons rtn todo)))))
+ (if rtn (push rtn todo))))
(t
;; Normal property/value pair
(setq todo
(message "Unknown annotations: %s" unknown-ans))))))
(defun format-subtract-regions (minu subtra)
- "Remove from the regions in MINUend the regions in SUBTRAhend.
+ "Remove from the regions in MINUEND the regions in SUBTRAHEND.
A region is a dotted pair (FROM . TO). Both parameters are lists of
regions. Each list must contain nonoverlapping, noncontiguous
regions, in descending order. The result is also nonoverlapping,
noncontiguous, and in descending order. The first element of MINUEND
can have a cdr of nil, indicating that the end of that region is not
-yet known."
+yet known.
+
+\(fn MINUEND SUBTRAHEND)"
(let* ((minuend (copy-alist minu))
(subtrahend (copy-alist subtra))
(m (car minuend))
(cond
;; The minuend starts after the subtrahend ends; keep it.
((> (car m) (cdr s))
- (setq results (cons m results)
- minuend (cdr minuend)
+ (push m results)
+ (setq minuend (cdr minuend)
m (car minuend)))
;; The minuend extends beyond the end of the subtrahend. Chop it off.
((or (null (cdr m)) (> (cdr m) (cdr s)))
- (setq results (cons (cons (1+ (cdr s)) (cdr m)) results))
+ (push (cons (1+ (cdr s)) (cdr m)) results)
(setcdr m (cdr s)))
;; The subtrahend starts after the minuend ends; throw it away.
((< (cdr m) (car s))
Inserts each element of the given LIST of buffer annotations at its
appropriate place. Use second arg OFFSET if the annotations' locations are
not relative to the beginning of the buffer: annotations will be inserted
-at their location-OFFSET+1 \(ie, the offset is treated as the character number
-of the first character in the buffer)."
+at their location-OFFSET+1 \(ie, the offset is treated as the position of
+the first character in the buffer)."
(if (not offset)
(setq offset 0)
(setq offset (1- offset)))
(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.
- (setq pos-ans (cons (car open-ans) pos-ans))
+ (push (car open-ans) pos-ans)
(setq all-ans
(cons (cons loc (funcall format-fn (car open-ans) nil))
all-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.
- (setq all-ans
- (cons (cons loc (funcall format-fn (car neg-ans) nil))
- all-ans)))
+ (push (cons loc (funcall format-fn (car neg-ans) nil))
+ all-ans))
(setq neg-ans (cdr neg-ans)))
;; Now deal with positive (opening) annotations
(let ((p pos-ans))
(while pos-ans
- (setq open-ans (cons (car pos-ans) open-ans))
- (setq all-ans
- (cons (cons loc (funcall format-fn (car pos-ans) t))
- all-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
(defun format-annotate-location (loc all ignore translations)
"Return annotation(s) needed at location LOC.
-This includes any properties that change between LOC-1 and LOC.
+This includes any properties that change between LOC - 1 and LOC.
If ALL is true, don't look at previous location, but generate annotations for
all non-nil properties.
Third argument IGNORE is a list of text-properties not to consider.
(setq p before-plist)
(while p
(if (not (memq (car p) props))
- (setq props (cons (car p) props)))
+ (push (car p) props))
(setq p (cdr (cdr p))))
(setq p after-plist)
(while p
(if (not (memq (car p) props))
- (setq props (cons (car p) props)))
+ (push (car p) props))
(setq p (cdr (cdr p))))
(while props
- (setq prop (car props)
- props (cdr props))
+ (setq prop (pop props))
(if (memq prop ignore)
nil ; If it's been ignored before, ignore it now.
(let ((before (if all nil (car (cdr (memq prop before-plist)))))
(let ((result (format-annotate-single-property-change
prop before after translations)))
(if (not result)
- (setq not-found (cons prop not-found))
+ (push prop not-found)
(setq negatives (nconc negatives (car result))
positives (nconc positives (cdr result)))))))))
(vector negatives positives not-found)))
(provide 'format)
+;;; arch-tag: c387e9c7-a93d-47bf-89bc-8ca67e96755a
;;; format.el ends here