;;; files.el --- file input and output commands for Emacs
;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996,
-;; 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
-;; 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+;; 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;; 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Package: emacs
A list of elements of the form (FROM . TO), each meaning to replace
FROM with TO when it appears in a directory name. This replacement is
done when setting up the default directory of a newly visited file.
-*Every* FROM string should start with \"\\\\`\".
+
+FROM is matched against directory names anchored at the first
+character, so it should start with a \"\\\\`\", or, if directory
+names cannot have embedded newlines, with a \"^\".
FROM and TO should be equivalent names, which refer to the
same directory. Do not use `~' in the TO strings;
(unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
(error "Aborted"))
(when (and (buffer-modified-p) buffer-file-name)
- (if (yes-or-no-p (format "Buffer %s is modified; save it first? "
- (buffer-name)))
+ (if (yes-or-no-p "Buffer %s is modified; save it first? "
+ (buffer-name))
(save-buffer)
(unless (yes-or-no-p "Kill and replace the buffer without saving it? ")
(error "Aborted"))))
"If file SIZE larger than `large-file-warning-threshold', allow user to abort.
OP-TYPE specifies the file operation being performed (for message to user)."
(when (and large-file-warning-threshold size
- (> size large-file-warning-threshold)
- (not (y-or-n-p
- (format "File %s is large (%dMB), really %s? "
- (file-name-nondirectory filename)
- (/ size 1048576) op-type))))
- (error "Aborted")))
+ (> size large-file-warning-threshold)
+ (not (y-or-n-p "File %s is large (%dMB), really %s? "
+ (file-name-nondirectory filename)
+ (/ size 1048576) op-type)))
+ (error "Aborted")))
(defun find-file-noselect (filename &optional nowarn rawfile wildcards)
"Read file FILENAME into a buffer and return the buffer.
(lambda (elt)
(cons (purecopy (car elt)) (cdr elt)))
`(;; do this first, so that .html.pl is Polish html, not Perl
- ("\\.s?html?\\(\\.[a-zA-Z_]+\\)?\\'" . html-mode)
+ ("\\.[sx]?html?\\(\\.[a-zA-Z_]+\\)?\\'" . html-mode)
("\\.svgz?\\'" . image-mode)
("\\.svgz?\\'" . xml-mode)
("\\.x[bp]m\\'" . image-mode)
("\\.oak\\'" . scheme-mode)
("\\.sgml?\\'" . sgml-mode)
("\\.x[ms]l\\'" . xml-mode)
+ ("\\.dbk\\'" . xml-mode)
("\\.dtd\\'" . sgml-mode)
("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
("\\.js\\'" . js-mode) ; javascript-mode would be better
("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
("\\.\\(dif\\|pat\\)\\'" . diff-mode) ; for MSDOG
("\\.[eE]?[pP][sS]\\'" . ps-mode)
- ("\\.\\(?:PDF\\|DVI\\|pdf\\|dvi\\)\\'" . doc-view-mode)
+ ("\\.\\(?:PDF\\|DVI\\|OD[FGPST]\\|DOCX?\\|XLSX?\\|PPTX?\\|pdf\\|dvi\\|od[fgpst]\\|docx?\\|xlsx?\\|pptx?\\)\\'" . doc-view-mode-maybe)
("configure\\.\\(ac\\|in\\)\\'" . autoconf-mode)
("\\.s\\(v\\|iv\\|ieve\\)\\'" . sieve-mode)
("BROWSE\\'" . ebrowse-tree-mode)
specified. The actual value in the buffer may differ from VALUE,
if it is changed by the major or minor modes, or by the user.")
(make-variable-buffer-local 'file-local-variables-alist)
+(put 'file-local-variables-alist 'permanent-local t)
(defvar dir-local-variables-alist nil
"Alist of directory-local variable settings in the current buffer.
directory-local variables, or nil otherwise."
(if noninteractive
nil
- (let ((name (or dir-name
- (if buffer-file-name
- (file-name-nondirectory buffer-file-name)
- (concat "buffer " (buffer-name)))))
- (offer-save (and (eq enable-local-variables t) unsafe-vars))
- prompt char)
- (save-window-excursion
- (let ((buf (get-buffer-create "*Local Variables*")))
- (pop-to-buffer buf)
- (set (make-local-variable 'cursor-type) nil)
- (erase-buffer)
- (if unsafe-vars
- (insert "The local variables list in " name
- "\ncontains values that may not be safe (*)"
- (if risky-vars
- ", and variables that are risky (**)."
- "."))
- (if risky-vars
- (insert "The local variables list in " name
- "\ncontains variables that are risky (**).")
- (insert "A local variables list is specified in " name ".")))
- (insert "\n\nDo you want to apply it? You can type
+ (save-window-excursion
+ (let* ((name (or dir-name
+ (if buffer-file-name
+ (file-name-nondirectory buffer-file-name)
+ (concat "buffer " (buffer-name)))))
+ (offer-save (and (eq enable-local-variables t)
+ unsafe-vars))
+ (exit-chars
+ (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g)))
+ (buf (pop-to-buffer "*Local Variables*"))
+ prompt char)
+ (set (make-local-variable 'cursor-type) nil)
+ (erase-buffer)
+ (cond
+ (unsafe-vars
+ (insert "The local variables list in " name
+ "\ncontains values that may not be safe (*)"
+ (if risky-vars
+ ", and variables that are risky (**)."
+ ".")))
+ (risky-vars
+ (insert "The local variables list in " name
+ "\ncontains variables that are risky (**)."))
+ (t
+ (insert "A local variables list is specified in " name ".")))
+ (insert "\n\nDo you want to apply it? You can type
y -- to apply the local variables list.
n -- to ignore the local variables list.")
- (if offer-save
- (insert "
+ (if offer-save
+ (insert "
! -- to apply the local variables list, and permanently mark these
values (*) as safe (in the future, they will be set automatically.)\n\n")
- (insert "\n\n"))
- (dolist (elt all-vars)
- (cond ((member elt unsafe-vars)
- (insert " * "))
- ((member elt risky-vars)
- (insert " ** "))
- (t
- (insert " ")))
- (princ (car elt) buf)
- (insert " : ")
- ;; Make strings with embedded whitespace easier to read.
- (let ((print-escape-newlines t))
- (prin1 (cdr elt) buf))
- (insert "\n"))
- (setq prompt
- (format "Please type %s%s: "
- (if offer-save "y, n, or !" "y or n")
- (if (< (line-number-at-pos) (window-body-height))
- ""
- ", or C-v to scroll")))
- (goto-char (point-min))
- (let ((cursor-in-echo-area t)
- (executing-kbd-macro executing-kbd-macro)
- (exit-chars
- (if offer-save '(?! ?y ?n ?\s ?\C-g) '(?y ?n ?\s ?\C-g)))
- done)
- (while (not done)
- (message "%s" prompt)
- (setq char (read-event))
- (if (numberp char)
- (cond ((eq char ?\C-v)
- (condition-case nil
- (scroll-up)
- (error (goto-char (point-min)))))
- ;; read-event returns -1 if we are in a kbd
- ;; macro and there are no more events in the
- ;; macro. In that case, attempt to get an
- ;; event interactively.
- ((and executing-kbd-macro (= char -1))
- (setq executing-kbd-macro nil))
- (t (setq done (memq (downcase char) exit-chars)))))))
- (setq char (downcase char))
- (when (and offer-save (= char ?!) unsafe-vars)
- (dolist (elt unsafe-vars)
- (add-to-list 'safe-local-variable-values elt))
- ;; When this is called from desktop-restore-file-buffer,
- ;; coding-system-for-read may be non-nil. Reset it before
- ;; writing to .emacs.
- (if (or custom-file user-init-file)
- (let ((coding-system-for-read nil))
- (customize-save-variable
- 'safe-local-variable-values
- safe-local-variable-values))))
- (kill-buffer buf)
- (or (= char ?!)
- (= char ?\s)
- (= char ?y)))))))
+ (insert "\n\n"))
+ (dolist (elt all-vars)
+ (cond ((member elt unsafe-vars)
+ (insert " * "))
+ ((member elt risky-vars)
+ (insert " ** "))
+ (t
+ (insert " ")))
+ (princ (car elt) buf)
+ (insert " : ")
+ ;; Make strings with embedded whitespace easier to read.
+ (let ((print-escape-newlines t))
+ (prin1 (cdr elt) buf))
+ (insert "\n"))
+ (setq prompt
+ (format "Please type %s%s: "
+ (if offer-save "y, n, or !" "y or n")
+ (if (< (line-number-at-pos) (window-body-height))
+ ""
+ (push ?\C-v exit-chars)
+ ", or C-v to scroll")))
+ (goto-char (point-min))
+ (while (null char)
+ (setq char (read-char-choice prompt exit-chars t))
+ (when (eq char ?\C-v)
+ (condition-case nil
+ (scroll-up)
+ (error (goto-char (point-min))))
+ (setq char nil)))
+ (kill-buffer buf)
+ (when (and offer-save (= char ?!) unsafe-vars)
+ (dolist (elt unsafe-vars)
+ (add-to-list 'safe-local-variable-values elt))
+ ;; When this is called from desktop-restore-file-buffer,
+ ;; coding-system-for-read may be non-nil. Reset it before
+ ;; writing to .emacs.
+ (if (or custom-file user-init-file)
+ (let ((coding-system-for-read nil))
+ (customize-save-variable
+ 'safe-local-variable-values
+ safe-local-variable-values))))
+ (memq char '(?! ?\s ?y))))))
(defun hack-local-variables-prop-line (&optional mode-only)
"Return local variables specified in the -*- line.
Return the new variables list."
(let* ((file-name (buffer-file-name))
(sub-file-name (if file-name
+ ;; FIXME: Why not use file-relative-name?
(substring file-name (length root)))))
- (dolist (entry class-variables variables)
- (let ((key (car entry)))
- (cond
- ((stringp key)
- ;; Don't include this in the previous condition, because we
- ;; want to filter all strings before the next condition.
- (when (and sub-file-name
- (>= (length sub-file-name) (length key))
- (string= key (substring sub-file-name 0 (length key))))
- (setq variables (dir-locals-collect-variables
- (cdr entry) root variables))))
- ((or (not key)
- (derived-mode-p key))
- (setq variables (dir-locals-collect-mode-variables
- (cdr entry) variables))))))))
+ (condition-case err
+ (dolist (entry class-variables variables)
+ (let ((key (car entry)))
+ (cond
+ ((stringp key)
+ ;; Don't include this in the previous condition, because we
+ ;; want to filter all strings before the next condition.
+ (when (and sub-file-name
+ (>= (length sub-file-name) (length key))
+ (string-prefix-p key sub-file-name))
+ (setq variables (dir-locals-collect-variables
+ (cdr entry) root variables))))
+ ((or (not key)
+ (derived-mode-p key))
+ (setq variables (dir-locals-collect-mode-variables
+ (cdr entry) variables))))))
+ (error
+ ;; The file's content might be invalid (e.g. have a merge conflict), but
+ ;; that shouldn't prevent the user from opening the file.
+ (message ".dir-locals error: %s" (error-message-string err))
+ nil))))
(defun dir-locals-set-directory-class (directory class &optional mtime)
"Declare that the DIRECTORY root is an instance of CLASS.
(dir-name nil))
(cond
((stringp variables-file)
- (setq dir-name (if (buffer-file-name) (file-name-directory (buffer-file-name)) default-directory))
+ (setq dir-name (if (buffer-file-name)
+ (file-name-directory (buffer-file-name))
+ default-directory))
(setq class (dir-locals-read-from-file variables-file)))
((consp variables-file)
(setq dir-name (nth 0 variables-file))
(let ((buffer (and filename (find-buffer-visiting filename))))
(and buffer (not (eq buffer (current-buffer)))
(not no-query)
- (not (y-or-n-p (format "A buffer is visiting %s; proceed? "
- filename)))
+ (not (y-or-n-p "A buffer is visiting %s; proceed? "
+ filename))
(error "Aborted")))
(or (equal filename buffer-file-name)
(progn
(or buffer-file-name (buffer-name))))))
(and confirm
(file-exists-p filename)
- (or (y-or-n-p (format "File `%s' exists; overwrite? " filename))
+ (or (y-or-n-p "File `%s' exists; overwrite? " filename)
(error "Canceled")))
(set-visited-file-name filename (not confirm))))
(set-buffer-modified-p t)
(and targets
(or (eq delete-old-versions t) (eq delete-old-versions nil))
(or delete-old-versions
- (y-or-n-p (format "Delete excess backup versions of %s? "
- real-file-name)))))
+ (y-or-n-p "Delete excess backup versions of %s? "
+ real-file-name))))
(modes (file-modes buffer-file-name))
(context (file-selinux-context buffer-file-name)))
;; Actually write the back up file.
(rename-file real-file-name backupname t)
(setq setmodes (list modes context backupname)))
(file-error
- ;; If trouble writing the backup, write it in ~.
- (setq backupname (expand-file-name
- (convert-standard-filename
- "~/%backup%~")))
+ ;; If trouble writing the backup, write it in
+ ;; .emacs.d/%backup%.
+ (setq backupname (locate-user-emacs-file "%backup%~"))
(message "Cannot write backup file; backing up in %s"
backupname)
(sleep-for 1)
(and context
(set-file-selinux-context to-name context)))
+(defvar file-name-version-regexp
+ "\\(?:~\\|\\.~[-[:alnum:]:#@^._]+~\\)"
+ "Regular expression matching the backup/version part of a file name.
+Used by `file-name-sans-versions'.")
+
(defun file-name-sans-versions (name &optional keep-backup-version)
"Return file NAME sans backup versions or strings.
This is a separate procedure so your site-init or startup file can
redefine it.
If the optional argument KEEP-BACKUP-VERSION is non-nil,
-we do not remove backup version numbers, only true file version numbers."
+we do not remove backup version numbers, only true file version numbers.
+See also `file-name-version-regexp'."
(let ((handler (find-file-name-handler name 'file-name-sans-versions)))
(if handler
(funcall handler 'file-name-sans-versions name keep-backup-version)
(substring name 0
- (if keep-backup-version
- (length name)
- (or (string-match "\\.~[-[:alnum:]:#@^._]+~\\'" name)
- (string-match "~\\'" name)
- (length name)))))))
+ (unless keep-backup-version
+ (string-match (concat file-name-version-regexp "\\'")
+ name))))))
(defun file-ownership-preserved-p (file)
"Return t if deleting FILE and rewriting it would preserve the owner."
(dremote (file-remote-p directory)))
(if ;; Conditions for separate trees
(or
- ;; Test for different drives on DOS/Windows
+ ;; Test for different filesystems on DOS/Windows
(and
;; Should `cygwin' really be included here? --stef
(memq system-type '(ms-dos cygwin windows-nt))
- (not (eq t (compare-strings filename 0 2 directory 0 2))))
+ (or
+ ;; Test for different drive letters
+ (not (eq t (compare-strings filename 0 2 directory 0 2)))
+ ;; Test for UNCs on different servers
+ (not (eq t (compare-strings
+ (progn
+ (if (string-match "\\`//\\([^:/]+\\)/" filename)
+ (match-string 1 filename)
+ ;; Windows file names cannot have ? in
+ ;; them, so use that to detect when
+ ;; neither FILENAME nor DIRECTORY is a
+ ;; UNC.
+ "?"))
+ 0 nil
+ (progn
+ (if (string-match "\\`//\\([^:/]+\\)/" directory)
+ (match-string 1 directory)
+ "?"))
+ 0 nil t)))))
;; Test for different remote file system identification
(not (equal fremote dremote)))
filename
;; Signal an error if the user specified the name of an
;; existing directory.
(error "%s is a directory" filename)
- (unless (y-or-n-p (format "File `%s' exists; overwrite? "
- filename))
+ (unless (y-or-n-p "File `%s' exists; overwrite? "
+ filename)
(error "Canceled")))
;; Signal an error if the specified name refers to a
;; non-existing directory.
(or (verify-visited-file-modtime (current-buffer))
(not (file-exists-p buffer-file-name))
(yes-or-no-p
- (format "%s has changed since visited or saved. Save anyway? "
- (file-name-nondirectory buffer-file-name)))
+ "%s has changed since visited or saved. Save anyway? "
+ (file-name-nondirectory buffer-file-name))
(error "Save not confirmed"))
(save-restriction
(widen)
(eq require-final-newline 'visit-save)
(and require-final-newline
(y-or-n-p
- (format "Buffer %s does not end in newline. Add one? "
- (buffer-name)))))
+ "Buffer %s does not end in newline. Add one? "
+ (buffer-name))))
(save-excursion
(goto-char (point-max))
(insert ?\n))))
(if (not (file-exists-p buffer-file-name))
(error "Directory %s write-protected" dir)
(if (yes-or-no-p
- (format "File %s is write-protected; try to save anyway? "
- (file-name-nondirectory
- buffer-file-name)))
+ "File %s is write-protected; try to save anyway? "
+ (file-name-nondirectory
+ buffer-file-name))
(setq tempsetmodes t)
(error "Attempt to save to a file which you aren't allowed to write"))))))
(or buffer-backed-up
(setq buffer-backed-up nil))))))
setmodes))
+(declare-function diff-no-select "diff"
+ (old new &optional switches no-async buf))
+
(defvar save-some-buffers-action-alist
`((?\C-r
,(lambda (buf)
(progn
(if (or arg
(eq save-abbrevs 'silently)
- (y-or-n-p (format "Save abbrevs in %s? "
- abbrev-file-name)))
+ (y-or-n-p "Save abbrevs in %s? " abbrev-file-name))
(write-abbrev-file nil))
;; Don't keep bothering user if he says no.
(setq abbrevs-changed nil)
(list dir
(if (directory-files dir nil directory-files-no-dot-files-regexp)
(y-or-n-p
- (format "Directory `%s' is not empty, really %s? "
- dir (if trashing "trash" "delete")))
+ "Directory `%s' is not empty, really %s? "
+ dir (if trashing "trash" "delete"))
nil)
(null current-prefix-arg))))
;; If default-directory is a remote directory, make sure we find its
(dolist (regexp revert-without-query)
(when (string-match regexp file-name)
(throw 'found t)))))
- (yes-or-no-p (format "Revert buffer from file %s? "
- file-name)))
+ (yes-or-no-p "Revert buffer from file %s? "
+ file-name))
(run-hooks 'before-revert-hook)
;; If file was backed up but has changed since,
;; we should make another backup.
;; to emulate what `ls' did in that case.
(insert-directory-safely file switches)
(insert-directory-safely file-name switches))))
- (yes-or-no-p (format "Recover auto save file %s? " file-name)))
+ (yes-or-no-p "Recover auto save file %s? " file-name))
(switch-to-buffer (find-file-noselect file t))
(let ((inhibit-read-only t)
;; Keep the current buffer-file-coding-system.
(defun kill-buffer-ask (buffer)
"Kill BUFFER if confirmed."
(when (yes-or-no-p
- (format "Buffer %s %s. Kill? " (buffer-name buffer)
- (if (buffer-modified-p buffer)
- "HAS BEEN EDITED" "is unmodified")))
+ "Buffer %s %s. Kill? " (buffer-name buffer)
+ (if (buffer-modified-p buffer)
+ "HAS BEEN EDITED" "is unmodified"))
(kill-buffer buffer)))
(defun kill-some-buffers (&optional list)