;;; files.el --- file input and output commands for Emacs
-;; Copyright (C) 1985,86,87,92,93,94,95,96,97,98,99,2000,01,02,03,2004
-;;; Free Software Foundation, Inc.
+;; Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+;; 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
;; Maintainer: FSF
:group 'backup)
(defcustom require-final-newline nil
- "*Value of t says silently ensure a file ends in a newline when it is saved.
-Non-nil but not t says ask user whether to add a newline when there isn't one.
-nil means don't add newlines."
- :type '(choice (const :tag "Off" nil)
- (const :tag "Add" t)
+ "*Whether to add a newline automatically at the end of the file.
+
+A value of t means do this only when the file is about to be saved.
+A value of `visit' means do this right after the file is visited.
+A value of `visit-save' means do it at both of those times.
+Any other non-nil value means ask user whether to add a newline, when saving.
+nil means don't add newlines.
+
+Certain major modes set this locally to the value obtained
+from `mode-require-final-newline'."
+ :type '(choice (const :tag "When visiting" visit)
+ (const :tag "When saving" t)
+ (const :tag "When visiting or saving" visit-save)
+ (const :tag "Never" nil)
(other :tag "Ask" ask))
:group 'editing-basics)
+(defcustom mode-require-final-newline t
+ "*Whether to add a newline at the end of the file, in certain major modes.
+Those modes set `require-final-newline' to this value when you enable them.
+They do so because they are used for files that are supposed
+to end in newlines, and the question is how to arrange that.
+
+A value of t means do this only when the file is about to be saved.
+A value of `visit' means do this right after the file is visited.
+A value of `visit-save' means do it at both of those times.
+Any other non-nil value means ask user whether to add a newline, when saving."
+ :type '(choice (const :tag "When visiting" visit)
+ (const :tag "When saving" t)
+ (const :tag "When visiting or saving" visit-save)
+ (other :tag "Ask" ask))
+ :group 'editing-basics
+ :version "22.1")
+
(defcustom auto-save-default t
"*Non-nil says by default do auto-saving of every file-visiting buffer."
:type 'boolean
The functions are called in the order given until one of them returns non-nil.")
(defvaralias 'find-file-not-found-hooks 'find-file-not-found-functions)
(make-obsolete-variable
- 'find-file-not-found-hooks 'find-file-not-found-functions "21.4")
+ 'find-file-not-found-hooks 'find-file-not-found-functions "22.1")
;;;It is not useful to make this a local variable.
;;;(put 'find-file-hooks 'permanent-local t)
:group 'find-file
:type 'hook
:options '(auto-insert)
- :version "21.4")
+ :version "22.1")
(defvaralias 'find-file-hooks 'find-file-hook)
-(make-obsolete-variable 'find-file-hooks 'find-file-hook "21.4")
+(make-obsolete-variable 'find-file-hooks 'find-file-hook "22.1")
(defvar write-file-functions nil
"List of functions to be called before writing out a buffer to a file.
updates before the buffer is saved, use `before-save-hook' .")
(put 'write-file-functions 'permanent-local t)
(defvaralias 'write-file-hooks 'write-file-functions)
-(make-obsolete-variable 'write-file-hooks 'write-file-functions "21.4")
+(make-obsolete-variable 'write-file-hooks 'write-file-functions "22.1")
(defvar local-write-file-hooks nil)
(make-variable-buffer-local 'local-write-file-hooks)
(put 'local-write-file-hooks 'permanent-local t)
-(make-obsolete-variable 'local-write-file-hooks 'write-file-functions "21.4")
+(make-obsolete-variable 'local-write-file-hooks 'write-file-functions "22.1")
(defvar write-contents-functions nil
"List of functions to be called before writing out a buffer to a file.
If one of them returns non-nil, the file is considered already written
-and the rest are not called.
+and the rest are not called and neither are the functions in
+`write-file-functions'.
This variable is meant to be used for hooks that pertain to the
buffer's contents, not to the particular visited file; thus,
use `before-save-hook'.")
(make-variable-buffer-local 'write-contents-functions)
(defvaralias 'write-contents-hooks 'write-contents-functions)
-(make-obsolete-variable 'write-contents-hooks 'write-contents-functions "21.4")
+(make-obsolete-variable 'write-contents-hooks 'write-contents-functions "22.1")
(defcustom enable-local-variables t
"*Control use of local variables in files you visit.
"*Control processing of the \"variable\" `eval' in a file's local variables.
The value can be t, nil or something else.
A value of t means obey `eval' variables;
-nil means ignore them; anything else means query.
-
-The command \\[normal-mode] always obeys local-variables lists
-and ignores this variable."
+nil means ignore them; anything else means query."
:type '(choice (const :tag "Obey" t)
(const :tag "Ignore" nil)
(other :tag "Query" other))
(apply op args))))
(defun convert-standard-filename (filename)
- "Convert a standard file's name to something suitable for the current OS.
-This function's standard definition is trivial; it just returns the argument.
-However, on some systems, the function is redefined with a definition
-that really does change some file names to canonicalize certain
-patterns and to guarantee valid names."
+ "Convert a standard file's name to something suitable for the OS.
+This means to guarantee valid names and perhaps to canonicalize
+certain patterns.
+
+This function's standard definition is trivial; it just returns
+the argument. However, on Windows and DOS, replace invalid
+characters. On DOS, make sure to obey the 8.3 limitations. On
+Windows, turn Cygwin names into native names, and also turn
+slashes into backslashes if the shell requires it (see
+`w32-shell-dos-semantics').
+
+See Info node `(elisp)Standard File Names' for more details."
filename)
(defun read-directory-name (prompt &optional dir default-dirname mustmatch initial)
Not actually set up until the first time you use it.")
(defun parse-colon-path (cd-path)
- "Explode a colon-separated search path into a list of directory names.
-\(For values of `colon' equal to `path-separator'.)"
+ "Explode a search path into a list of directory names.
+Directories are separated by occurrences of `path-separator'
+\(which is colon in GNU and GNU-like systems)."
;; We could use split-string here.
(and cd-path
(let (cd-list (cd-start 0) cd-colon)
(defun cd (dir)
"Make DIR become the current buffer's default directory.
-If your environment includes a `CDPATH' variable, try each one of that
-colon-separated list of directories when resolving a relative directory name."
+If your environment includes a `CDPATH' variable, try each one of
+that list of directories (separated by occurrences of
+`path-separator') when resolving a relative directory name.
+The path separator is colon in GNU and GNU-like systems."
(interactive
(list (read-directory-name "Change default directory: "
default-directory default-directory
(load library))
(defun file-remote-p (file)
- "Test whether FILE specifies a location on a remote system."
- (let ((handler (find-file-name-handler file 'file-local-copy)))
+ "Test whether FILE specifies a location on a remote system.
+Return an identification of the system if the location is indeed
+remote. The identification of the system may comprise a method
+to access the system and its hostname, amongst other things.
+
+For example, the filename \"/user@host:/foo\" specifies a location
+on the system \"/user@host:\"."
+ (let ((handler (find-file-name-handler file 'file-remote-p)))
(if handler
- (get handler 'file-remote-p))))
+ (funcall handler 'file-remote-p file)
+ nil)))
(defun file-local-copy (file)
"Copy the file FILE into a temporary file on this machine.
both at the level of the file and at the level of the directories
containing it, until no links are left at any level.
-\(fn FILENAME)"
+\(fn FILENAME)" ;; Don't document the optional arguments.
;; COUNTER and PREV-DIRS are only used in recursive calls.
;; COUNTER can be a cons cell whose car is the count of how many
;; more links to chase before getting an error.
\f
(defun switch-to-buffer-other-window (buffer &optional norecord)
"Select buffer BUFFER in another window.
+If BUFFER does not identify an existing buffer, then this function
+creates a buffer with that name.
+
+When called from Lisp, BUFFER can be a buffer, a string \(a buffer name),
+or nil. If BUFFER is nil, then this function chooses a buffer
+using `other-buffer'.
Optional second arg NORECORD non-nil means
do not put this buffer at the front of the list of recently selected ones.
+This function returns the buffer it switched to.
This uses the function `display-buffer' as a subroutine; see its
documentation for additional customization information."
type M-n to pull it into the minibuffer.
Interactively, or if WILDCARDS is non-nil in a call from Lisp,
-expand wildcards (if any) and visit multiple files. Wildcard expansion
-can be suppressed by setting `find-file-wildcards'."
- (interactive
- (find-file-read-args "Find file: " nil))
+expand wildcards (if any) and visit multiple files. You can
+suppress wildcard expansion by setting `find-file-wildcards'.
+
+To visit a file without any kind of conversion and without
+automatically choosing a major mode, use \\[find-file-literally]."
+ (interactive (find-file-read-args "Find file: " nil))
(let ((value (find-file-noselect filename nil nil wildcards)))
(if (listp value)
(mapcar 'switch-to-buffer (nreverse value))
(if (listp value)
(progn
(setq value (nreverse value))
- (switch-to-buffer-other-window (car value))
- (mapcar 'switch-to-buffer (cdr value)))
+ (cons (switch-to-buffer-other-window (car value))
+ (mapcar 'switch-to-buffer (cdr value))))
(switch-to-buffer-other-window value))))
(defun find-file-other-frame (filename &optional wildcards)
(if (listp value)
(progn
(setq value (nreverse value))
- (switch-to-buffer-other-frame (car value))
- (mapcar 'switch-to-buffer (cdr value)))
+ (cons (switch-to-buffer-other-frame (car value))
+ (mapcar 'switch-to-buffer (cdr value))))
(switch-to-buffer-other-frame value))))
+(defun find-file-existing (filename &optional wildcards)
+ "Edit the existing file FILENAME.
+Like \\[find-file] but only allow files that exists."
+ (interactive (find-file-read-args "Find existing file: " t))
+ (unless (file-exists-p filename) (error "%s does not exist" filename))
+ (find-file filename wildcards)
+ (current-buffer))
+
(defun find-file-read-only (filename &optional wildcards)
"Edit file FILENAME but don't allow changes.
Like \\[find-file] but marks buffer as read-only.
Use \\[toggle-read-only] to permit editing."
- (interactive (find-file-read-args "Find file read-only: " t))
- (unless (file-exists-p filename) (error "%s does not exist" filename))
- (find-file filename wildcards)
- (toggle-read-only 1)
- (current-buffer))
+ (interactive (find-file-read-args "Find file read-only: " nil))
+ (unless (or (and wildcards find-file-wildcards
+ (not (string-match "\\`/:" filename))
+ (string-match "[[*?]" filename))
+ (file-exists-p filename))
+ (error "%s does not exist" filename))
+ (let ((value (find-file filename wildcards)))
+ (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+ (if (listp value) value (list value)))
+ value))
(defun find-file-read-only-other-window (filename &optional wildcards)
"Edit file FILENAME in another window but don't allow changes.
Like \\[find-file-other-window] but marks buffer as read-only.
Use \\[toggle-read-only] to permit editing."
- (interactive (find-file-read-args "Find file read-only other window: " t))
- (unless (file-exists-p filename) (error "%s does not exist" filename))
- (find-file-other-window filename wildcards)
- (toggle-read-only 1)
- (current-buffer))
+ (interactive (find-file-read-args "Find file read-only other window: " nil))
+ (unless (or (and wildcards find-file-wildcards
+ (not (string-match "\\`/:" filename))
+ (string-match "[[*?]" filename))
+ (file-exists-p filename))
+ (error "%s does not exist" filename))
+ (let ((value (find-file-other-window filename wildcards)))
+ (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+ (if (listp value) value (list value)))
+ value))
(defun find-file-read-only-other-frame (filename &optional wildcards)
"Edit file FILENAME in another frame but don't allow changes.
Like \\[find-file-other-frame] but marks buffer as read-only.
Use \\[toggle-read-only] to permit editing."
- (interactive (find-file-read-args "Find file read-only other frame: " t))
- (unless (file-exists-p filename) (error "%s does not exist" filename))
- (find-file-other-frame filename wildcards)
- (toggle-read-only 1)
- (current-buffer))
-
-(defun find-alternate-file-other-window (filename)
+ (interactive (find-file-read-args "Find file read-only other frame: " nil))
+ (unless (or (and wildcards find-file-wildcards
+ (not (string-match "\\`/:" filename))
+ (string-match "[[*?]" filename))
+ (file-exists-p filename))
+ (error "%s does not exist" filename))
+ (let ((value (find-file-other-frame filename wildcards)))
+ (mapc (lambda (b) (with-current-buffer b (toggle-read-only 1)))
+ (if (listp value) value (list value)))
+ value))
+
+(defun find-alternate-file-other-window (filename &optional wildcards)
"Find file FILENAME as a replacement for the file in the next window.
-This command does not select that window."
+This command does not select that window.
+
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and replace the file with multiple files."
(interactive
(save-selected-window
(other-window 1)
(setq file-name (file-name-nondirectory file)
file-dir (file-name-directory file)))
(list (read-file-name
- "Find alternate file: " file-dir nil nil file-name)))))
+ "Find alternate file: " file-dir nil nil file-name)
+ t))))
(if (one-window-p)
- (find-file-other-window filename)
+ (find-file-other-window filename wildcards)
(save-selected-window
(other-window 1)
- (find-alternate-file filename))))
+ (find-alternate-file filename wildcards))))
-(defun find-alternate-file (filename)
+(defun find-alternate-file (filename &optional wildcards)
"Find file FILENAME, select its buffer, kill previous buffer.
If the current buffer now contains an empty file that you just visited
-\(presumably by mistake), use this command to visit the file you really want."
+\(presumably by mistake), use this command to visit the file you really want.
+
+Interactively, or if WILDCARDS is non-nil in a call from Lisp,
+expand wildcards (if any) and replace the file with multiple files."
(interactive
(let ((file buffer-file-name)
(file-name nil)
(setq file-name (file-name-nondirectory file)
file-dir (file-name-directory file)))
(list (read-file-name
- "Find alternate file: " file-dir nil nil file-name))))
+ "Find alternate file: " file-dir nil nil file-name)
+ t)))
(unless (run-hook-with-args-until-failure 'kill-buffer-query-functions)
(error "Aborted"))
(when (and (buffer-modified-p) (buffer-file-name))
(setq buffer-file-truename nil)
;; Likewise for dired buffers.
(setq dired-directory nil)
- (find-file filename))
+ (find-file filename wildcards))
(when (eq obuf (current-buffer))
;; This executes if find-file gets an error
;; and does not really find anything.
"Return the buffer visiting file FILENAME (a string).
This is like `get-file-buffer', except that it checks for any buffer
visiting the same file, possibly under a different name.
-If PREDICATE is non-nil, only a buffer satisfying it can be returned.
+If PREDICATE is non-nil, only buffers satisfying it are eligible,
+and others are ignored.
If there is no such live buffer, return nil."
(let ((predicate (or predicate #'identity))
(truename (abbreviate-file-name (file-truename filename))))
When nil, never request confirmation."
:group 'files
:group 'find-file
+ :version "22.1"
:type '(choice integer (const :tag "Never request confirmation" nil)))
(defun find-file-noselect (filename &optional nowarn rawfile wildcards)
Optional second arg RAWFILE non-nil means the file is read literally.
Optional third arg WILDCARDS non-nil means do wildcard processing
and visit all the matching files. When wildcards are actually
-used and expanded, the value is a list of buffers
-that are visiting the various files."
+used and expanded, return a list of buffers that are visiting
+the various files."
(setq filename
(abbreviate-file-name
(expand-file-name filename)))
(kill-local-variable 'buffer-file-coding-system)
(kill-local-variable 'cursor-type)
(let ((inhibit-read-only t))
- (erase-buffer)
- (and (default-value 'enable-multibyte-characters)
- (not rawfile)
- (set-buffer-multibyte t))
- (if rawfile
- (condition-case ()
- (insert-file-contents-literally filename t)
- (file-error
- (when (and (file-exists-p filename)
- (not (file-readable-p filename)))
- (kill-buffer buf)
- (signal 'file-error (list "File is not readable"
- filename)))
- ;; Unconditionally set error
+ (erase-buffer))
+ (and (default-value 'enable-multibyte-characters)
+ (not rawfile)
+ (set-buffer-multibyte t))
+ (if rawfile
+ (condition-case ()
+ (let ((inhibit-read-only t))
+ (insert-file-contents-literally filename t))
+ (file-error
+ (when (and (file-exists-p filename)
+ (not (file-readable-p filename)))
+ (kill-buffer buf)
+ (signal 'file-error (list "File is not readable"
+ filename)))
+ ;; Unconditionally set error
+ (setq error t)))
+ (condition-case ()
+ (let ((inhibit-read-only t))
+ (insert-file-contents filename t))
+ (file-error
+ (when (and (file-exists-p filename)
+ (not (file-readable-p filename)))
+ (kill-buffer buf)
+ (signal 'file-error (list "File is not readable"
+ filename)))
+ ;; Run find-file-not-found-hooks until one returns non-nil.
+ (or (run-hook-with-args-until-success 'find-file-not-found-functions)
+ ;; If they fail too, set error.
(setq error t)))))
- (condition-case ()
- (let ((inhibit-read-only t))
- (insert-file-contents filename t))
- (file-error
- (when (and (file-exists-p filename)
- (not (file-readable-p filename)))
- (kill-buffer buf)
- (signal 'file-error (list "File is not readable"
- filename)))
- ;; Run find-file-not-found-hooks until one returns non-nil.
- (or (run-hook-with-args-until-success 'find-file-not-found-functions)
- ;; If they fail too, set error.
- (setq error t))))
;; Record the file's truename, and maybe use that as visited name.
(if (equal filename buffer-file-name)
(setq buffer-file-truename truename)
(when (and view-read-only view-mode)
(view-mode-disable))
(normal-mode t)
+ ;; If requested, add a newline at the end of the file.
+ (and (memq require-final-newline '(visit visit-save))
+ (> (point-max) (point-min))
+ (/= (char-after (1- (point-max))) ?\n)
+ (not (and (eq selective-display t)
+ (= (char-after (1- (point-max))) ?\r)))
+ (save-excursion
+ (goto-char (point-max))
+ (insert "\n")))
(when (and buffer-read-only
view-read-only
(not (eq (get major-mode 'mode-class) 'special)))
(mapc
(lambda (elt)
(cons (purecopy (car elt)) (cdr elt)))
- '(("\\.te?xt\\'" . text-mode)
- ("\\.tex\\'" . tex-mode)
+ '(;; do this first, so that .html.pl is Polish html, not Perl
+ ("\\.s?html?\\(\\.[a-zA-Z_]+\\)?\\'" . html-mode)
+ ("\\.te?xt\\'" . text-mode)
+ ("\\.[tT]e[xX]\\'" . tex-mode)
("\\.ins\\'" . tex-mode) ;Installation files for TeX packages.
("\\.ltx\\'" . latex-mode)
("\\.dtx\\'" . doctex-mode)
("\\.el\\'" . emacs-lisp-mode)
("\\.\\(scm\\|stk\\|ss\\|sch\\)\\'" . scheme-mode)
("\\.l\\'" . lisp-mode)
- ("\\.lisp\\'" . lisp-mode)
- ("\\.f\\'" . fortran-mode)
- ("\\.F\\'" . fortran-mode)
+ ("\\.li?sp\\'" . lisp-mode)
+ ("\\.[fF]\\'" . fortran-mode)
("\\.for\\'" . fortran-mode)
("\\.p\\'" . pascal-mode)
("\\.pas\\'" . pascal-mode)
("\\.ad[abs]\\'" . ada-mode)
("\\.ad[bs].dg\\'" . ada-mode)
- ("\\.\\([pP]\\([Llm]\\|erl\\)\\|al\\)\\'" . perl-mode)
- ("\\.s?html?\\'" . html-mode)
+ ("\\.\\([pP]\\([Llm]\\|erl\\|od\\)\\|al\\)\\'" . perl-mode)
("\\.mk\\'" . makefile-mode)
- ("\\(M\\|m\\|GNUm\\)akefile\\'" . makefile-mode)
+ ("\\([Mm]\\|GNUm\\)akep*file\\'" . makefile-mode)
("\\.am\\'" . makefile-mode) ;For Automake.
;; Less common extensions come here
;; so more common ones above are found faster.
("\\.texinfo\\'" . texinfo-mode)
("\\.te?xi\\'" . texinfo-mode)
- ("\\.s\\'" . asm-mode)
- ("\\.S\\'" . asm-mode)
+ ("\\.[sS]\\'" . asm-mode)
("\\.asm\\'" . asm-mode)
- ("ChangeLog\\'" . change-log-mode)
- ("change\\.log\\'" . change-log-mode)
- ("changelo\\'" . change-log-mode)
- ("ChangeLog\\.[0-9]+\\'" . change-log-mode)
- ;; for MSDOS and MS-Windows (which are case-insensitive)
- ("changelog\\'" . change-log-mode)
- ("changelog\\.[0-9]+\\'" . change-log-mode)
+ ("[cC]hange\\.?[lL]og?\\'" . change-log-mode)
+ ("[cC]hange[lL]og\\.[0-9]+\\'" . change-log-mode)
("\\$CHANGE_LOG\\$\\.TXT" . change-log-mode)
("\\.scm\\.[0-9]*\\'" . scheme-mode)
("\\.[ck]?sh\\'\\|\\.shar\\'\\|/\\.z?profile\\'" . sh-mode)
("\\(/\\|\\`\\)\\.\\(bash_logout\\|shrc\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
("\\.m?spec\\'" . sh-mode)
- ("\\.mm\\'" . nroff-mode)
- ("\\.me\\'" . nroff-mode)
- ("\\.ms\\'" . nroff-mode)
+ ("\\.m[mes]\\'" . nroff-mode)
("\\.man\\'" . nroff-mode)
- ("\\.TeX\\'" . tex-mode)
("\\.sty\\'" . latex-mode)
- ("\\.cls\\'" . latex-mode) ;LaTeX 2e class
- ("\\.clo\\'" . latex-mode) ;LaTeX 2e class option
+ ("\\.cl[so]\\'" . latex-mode) ;LaTeX 2e class option
("\\.bbl\\'" . latex-mode)
("\\.bib\\'" . bibtex-mode)
("\\.sql\\'" . sql-mode)
- ("\\.m4\\'" . m4-mode)
- ("\\.mc\\'" . m4-mode)
+ ("\\.m[4c]\\'" . m4-mode)
("\\.mf\\'" . metafont-mode)
("\\.mp\\'" . metapost-mode)
("\\.vhdl?\\'" . vhdl-mode)
("\\.article\\'" . text-mode)
("\\.letter\\'" . text-mode)
- ("\\.tcl\\'" . tcl-mode)
+ ("\\.i?tcl\\'" . tcl-mode)
("\\.exp\\'" . tcl-mode)
- ("\\.itcl\\'" . tcl-mode)
("\\.itk\\'" . tcl-mode)
("\\.icn\\'" . icon-mode)
("\\.sim\\'" . simula-mode)
("\\.mss\\'" . scribe-mode)
- ("\\.f90\\'" . f90-mode)
- ("\\.f95\\'" . f90-mode)
+ ("\\.f9[05]\\'" . f90-mode)
("\\.indent\\.pro\\'" . fundamental-mode) ; to avoid idlwave-mode
("\\.pro\\'" . idlwave-mode)
- ("\\.lsp\\'" . lisp-mode)
("\\.prolog\\'" . prolog-mode)
("\\.tar\\'" . tar-mode)
("\\.\\(arc\\|zip\\|lzh\\|zoo\\|ear\\|jar\\|war\\)\\'" . archive-mode)
("\\`/tmp/fol/" . text-mode)
("\\.oak\\'" . scheme-mode)
("\\.sgml?\\'" . sgml-mode)
- ("\\.xml\\'" . sgml-mode)
- ("\\.xsl\\'" . sgml-mode)
+ ("\\.x[ms]l\\'" . xml-mode)
("\\.dtd\\'" . sgml-mode)
("\\.ds\\(ss\\)?l\\'" . dsssl-mode)
+ ("\\.js\\'" . java-mode) ; javascript-mode would be better
+ ("\\.x[bp]m\\'" . c-mode)
;; .emacs or .gnus or .viper following a directory delimiter in
;; Unix, MSDOG or VMS syntax.
("[]>:/\\]\\..*\\(emacs\\|gnus\\|viper\\)\\'" . emacs-lisp-mode)
("BROWSE\\'" . ebrowse-tree-mode)
("\\.ebrowse\\'" . ebrowse-tree-mode)
("#\\*mail\\*" . mail-mode)
+ ("\\.g\\'" . antlr-mode)
+ ("\\.ses\\'" . ses-mode)
+ ("\\.\\(soa\\|zone\\)\\'" . dns-mode)
+ ("\\.docbook\\'" . sgml-mode)
+ ("\\.com\\'" . dcl-mode)
+ ("/config\\.\\(?:bat\\|log\\)\\'" . fundamental-mode)
+ ;; Windows candidates may be opened case sensitively on Unix
+ ("\\.\\(?:[iI][nN][iI]\\|[lL][sS][tT]\\|[rR][eE][gG]\\|[sS][yY][sS]\\)\\'" . conf-mode)
+ ("\\.\\(?:desktop\\|la\\)\\'" . conf-unix-mode)
+ ("\\.ppd\\'" . conf-ppd-mode)
+ ("java.+\\.conf\\'" . conf-javaprop-mode)
+ ("\\.properties\\(?:\\.[a-zA-Z0-9._-]+\\)?\\'" . conf-javaprop-mode)
+ ;; *.cf, *.cfg, *.conf, *.config[.local|.de_DE.UTF8|...], */config
+ ("[/.]c\\(?:on\\)?f\\(?:i?g\\)?\\(?:\\.[a-zA-Z0-9._-]+\\)?\\'" . conf-mode)
+ ("\\`/etc/\\(?:DIR_COLORS\\|ethers\\|.?fstab\\|.*hosts\\|lesskey\\|login\\.?de\\(?:fs\\|vperm\\)\\|magic\\|mtab\\|pam\\.d/.*\\|permissions\\|protocols\\|rpc\\|services\\)\\'" . conf-space-mode)
+ ("\\`/etc/\\(?:acpid?/.+\\|aliases\\|default/.+\\|group-?\\|hosts\\..+\\|inittab\\|ksysguarddrc\\|opera6rc\\|passwd-?\\|shadow-?\\)\\'" . conf-mode)
+ ;; either user's dot-files or under /etc or some such
+ ("/\\.?\\(?:gnokiirc\\|kde.*rc\\|mime\\.types\\|wgetrc\\)\\'" . conf-mode)
+ ;; alas not all ~/.*rc files are like this
+ ("/\\.\\(?:enigma\\|gltron\\|gtk\\|hxplayer\\|net\\|neverball\\|qt/.+\\|realplayer\\|scummvm\\|sversion\\|sylpheed/.+\\|xmp\\)rc\\'" . conf-mode)
+ ("/\\.\\(?:gdbtkinit\\|grip\\|orbital/.+txt\\|rhosts\\|tuxracer/options\\)\\'" . conf-mode)
+ ("/\\.?X\\(?:default\\|resource\\|re\\)s\\>" . conf-xdefaults-mode)
+ ("/X11.+app-defaults/" . conf-xdefaults-mode)
+ ("/X11.+locale/.+/Compose\\'" . conf-colon-mode)
+ ;; this contains everything twice, with space and with colon :-(
+ ("/X11.+locale/compose\\.dir\\'" . conf-javaprop-mode)
;; Get rid of any trailing .n.m and try again.
;; This is for files saved by cvs-merge that look like .#<file>.<rev>
;; or .#<file>.<rev>-<rev> or VC's <file>.~<rev>~.
;; Using mode nil rather than `ignore' would let the search continue
;; through this list (with the shortened name) rather than start over.
- ("\\.~?[0-9]+\\.[0-9][-.0-9]*~?\\'" ignore t)
+ ("\\.~?[0-9]+\\.[0-9][-.0-9]*~?\\'" nil t)
;; The following should come after the ChangeLog pattern
;; for the sake of ChangeLog.1, etc.
;; and after the .scm.[0-9] and CVS' <file>.<rev> patterns too.
("\\.[1-9]\\'" . nroff-mode)
- ("\\.g\\'" . antlr-mode)
- ("\\.ses\\'" . ses-mode)
- ("\\.orig\\'" nil t) ; from patch
- ("\\.in\\'" nil t)))
+ ("\\.\\(?:orig\\|in\\|[bB][aA][kK]\\)\\'" nil t)))
"Alist of filename patterns vs corresponding major mode functions.
Each element looks like (REGEXP . FUNCTION) or (REGEXP FUNCTION NON-NIL).
\(NON-NIL stands for anything that is not nil; the value does not matter.)
If the element has the form (REGEXP FUNCTION NON-NIL), then after
calling FUNCTION (if it's not nil), we delete the suffix that matched
-REGEXP and search the list again for another match.")
+REGEXP and search the list again for another match.
+If the file name matches `inhibit-first-line-modes-regexps',
+then `auto-mode-alist' is not processed.
+
+See also `interpreter-mode-alist', which detects executable script modes
+based on the interpreters they specify to run,
+and `magic-mode-alist', which determines modes based on file contents.")
(defvar interpreter-mode-alist
;; Note: The entries for the modes defined in cc-mode.el (awk-mode
("guile" . scheme-mode)
("clisp" . lisp-mode)))
"Alist mapping interpreter names to major modes.
-This alist applies to files whose first line starts with `#!'.
+This is used for files whose first lines match `auto-mode-interpreter-regexp'.
Each element looks like (INTERPRETER . MODE).
The car of each element is compared with
the name of the interpreter specified in the first line.
-If it matches, mode MODE is selected.")
+If it matches, mode MODE is selected.
+
+See also `auto-mode-alist'.")
(defvar inhibit-first-line-modes-regexps '("\\.tar\\'" "\\.tgz\\'")
"List of regexps; if one matches a file name, don't look for `-*-'.")
regular expression. The mode is then determined as the mode associated
with that interpreter in `interpreter-mode-alist'.")
-(defun set-auto-mode (&optional just-from-file-name)
+(defvar magic-mode-alist
+ `(;; The < comes before the groups (but the first) to reduce backtracking.
+ ;; TODO: UTF-16 <?xml may be preceded by a BOM 0xff 0xfe or 0xfe 0xff.
+ (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
+ (comment-re (concat "\\(?:!--" incomment-re "*-->\\s *<\\)")))
+ (concat "\\(?:<\\?xml\\s +[^>]*>\\)?\\s *<"
+ comment-re "*"
+ "\\(?:!DOCTYPE\\s +[^>]*>\\s *<\\s *" comment-re "*\\)?"
+ "[Hh][Tt][Mm][Ll]"))
+ . html-mode)
+ ;; These two must come after html, because they are more general:
+ ("<\\?xml " . xml-mode)
+ (,(let* ((incomment-re "\\(?:[^-]\\|-[^-]\\)")
+ (comment-re (concat "\\(?:!--" incomment-re "*-->\\s *<\\)")))
+ (concat "\\s *<" comment-re "*!DOCTYPE "))
+ . sgml-mode)
+ ("%![^V]" . ps-mode)
+ ("# xmcd " . conf-unix-mode))
+ "Alist of buffer beginnings vs. corresponding major mode functions.
+Each element looks like (REGEXP . FUNCTION). FUNCTION will be
+called, unless it is nil (to allow `auto-mode-alist' to override).")
+
+(defun set-auto-mode (&optional keep-mode-if-same)
"Select major mode appropriate for current buffer.
-This checks for a -*- mode tag in the buffer's text,
-compares the filename against the entries in `auto-mode-alist',
-or checks the interpreter that runs this file against
-`interpreter-mode-alist'.
+
+This checks for a -*- mode tag in the buffer's text, checks the
+interpreter that runs this file against `interpreter-mode-alist',
+compares the buffer beginning against `magic-mode-alist', or
+compares the filename against the entries in `auto-mode-alist'.
It does not check for the `mode:' local variable in the
Local Variables section of the file; for that, use `hack-local-variables'.
If `enable-local-variables' is nil, this function does not check for a
-*- mode tag.
-If the optional argument JUST-FROM-FILE-NAME is non-nil,
-then we do not set anything but the major mode,
-and we don't even do that unless it would come from the file name."
+If the optional argument KEEP-MODE-IF-SAME is non-nil, then we
+only set the major mode, if that would change it."
;; Look for -*-MODENAME-*- or -*- ... mode: MODENAME; ... -*-
- (let (end done modes)
+ (let (end done mode modes)
+ ;; Find a -*- mode tag
(save-excursion
(goto-char (point-min))
(skip-chars-forward " \t\n")
(push (intern (concat (downcase (buffer-substring (point) end))
"-mode"))
modes))))
- ;; If we found modes to use, invoke them now,
- ;; outside the save-excursion.
- (unless just-from-file-name
- (dolist (mode (nreverse modes))
- (if (not (functionp mode))
- (message "Ignoring unknown mode `%s'" mode)
- (setq done t)
- (funcall mode))))
- ;; If we didn't find a mode from a -*- line, try using the file name.
- (if (and (not done) buffer-file-name)
- (let ((name buffer-file-name)
- (keep-going t))
- ;; Remove backup-suffixes from file name.
- (setq name (file-name-sans-versions name))
- (while keep-going
- (setq keep-going nil)
- (let ((alist auto-mode-alist)
- (mode nil))
- ;; Find first matching alist entry.
- (let ((case-fold-search
- (memq system-type '(vax-vms windows-nt cygwin))))
- (while (and (not mode) alist)
- (if (string-match (car (car alist)) name)
- (if (and (consp (cdr (car alist)))
- (nth 2 (car alist)))
- (setq mode (car (cdr (car alist)))
- name (substring name 0 (match-beginning 0))
- keep-going t)
- (setq mode (cdr (car alist))
- keep-going nil)))
- (setq alist (cdr alist))))
- (if mode
- ;; When JUST-FROM-FILE-NAME is set,
- ;; we are working on behalf of set-visited-file-name.
- ;; In that case, if the major mode specified is the
- ;; same one we already have, don't actually reset it.
- ;; We don't want to lose minor modes such as Font Lock.
- (unless (and just-from-file-name (eq mode major-mode))
- (funcall mode))
- ;; If we can't deduce a mode from the file name,
- ;; look for an interpreter specified in the first line.
- ;; As a special case, allow for things like "#!/bin/env perl",
- ;; which finds the interpreter anywhere in $PATH.
- (let ((interpreter
- (save-excursion
- (goto-char (point-min))
- (if (looking-at auto-mode-interpreter-regexp)
- (match-string 2)
- "")))
- elt)
- ;; Map interpreter name to a mode.
- (setq elt (assoc (file-name-nondirectory interpreter)
- interpreter-mode-alist))
- (unless just-from-file-name
- (if elt
- (funcall (cdr elt))))))))))))
-
+ ;; If we found modes to use, invoke them now, outside the save-excursion.
+ (if modes
+ (catch 'nop
+ (dolist (mode (nreverse modes))
+ (if (not (functionp mode))
+ (message "Ignoring unknown mode `%s'" mode)
+ (setq done t)
+ (or (set-auto-mode-0 mode keep-mode-if-same)
+ ;; continuing would call minor modes again, toggling them off
+ (throw 'nop nil)))))
+ ;; If we didn't, look for an interpreter specified in the first line.
+ ;; As a special case, allow for things like "#!/bin/env perl", which
+ ;; finds the interpreter anywhere in $PATH.
+ (setq mode (save-excursion
+ (goto-char (point-min))
+ (if (looking-at auto-mode-interpreter-regexp)
+ (match-string 2)
+ ""))
+ ;; Map interpreter name to a mode, signalling we're done at the
+ ;; same time.
+ done (assoc (file-name-nondirectory mode)
+ interpreter-mode-alist))
+ ;; If we found an interpreter mode to use, invoke it now.
+ (if done
+ (set-auto-mode-0 (cdr done) keep-mode-if-same)))
+ ;; If we didn't, match the buffer beginning against magic-mode-alist.
+ (unless done
+ (if (setq done (save-excursion
+ (goto-char (point-min))
+ (assoc-default nil magic-mode-alist
+ (lambda (re dummy)
+ (looking-at re)))))
+ (set-auto-mode-0 done keep-mode-if-same)
+ ;; Compare the filename against the entries in auto-mode-alist.
+ (if buffer-file-name
+ (let ((name buffer-file-name))
+ ;; Remove backup-suffixes from file name.
+ (setq name (file-name-sans-versions name))
+ (while name
+ ;; Find first matching alist entry.
+ (let ((case-fold-search
+ (memq system-type '(vax-vms windows-nt cygwin))))
+ (if (and (setq mode (assoc-default name auto-mode-alist
+ 'string-match))
+ (consp mode)
+ (cadr mode))
+ (setq mode (car mode)
+ name (substring name 0 (match-beginning 0)))
+ (setq name)))
+ (when mode
+ (set-auto-mode-0 mode keep-mode-if-same)))))))))
+
+;; When `keep-mode-if-same' is set, we are working on behalf of
+;; set-visited-file-name. In that case, if the major mode specified is the
+;; same one we already have, don't actually reset it. We don't want to lose
+;; minor modes such as Font Lock.
+(defun set-auto-mode-0 (mode &optional keep-mode-if-same)
+ "Apply MODE and return it.
+If optional arg KEEP-MODE-IF-SAME is non-nil, MODE is chased of
+any aliases and compared to current major mode. If they are the
+same, do nothing and return nil."
+ (when keep-mode-if-same
+ (while (symbolp (symbol-function mode))
+ (setq mode (symbol-function mode)))
+ (if (eq mode major-mode)
+ (setq mode nil)))
+ (when mode
+ (funcall mode)
+ mode))
(defun set-auto-mode-1 ()
"Find the -*- spec in the buffer.
(save-excursion
(goto-char (point-max))
(search-backward "\n\^L" (max (- (point-max) 3000) (point-min)) 'move)
- (if (let ((case-fold-search t))
- (and (search-forward "Local Variables:" nil t)
- (or (eq enable-local-variables t)
- mode-only
- (and enable-local-variables
- (save-window-excursion
- (switch-to-buffer (current-buffer))
- (save-excursion
- (beginning-of-line)
- (set-window-start (selected-window) (point)))
- (y-or-n-p (format "Set local variables as specified at end of %s? "
- (if buffer-file-name
- (file-name-nondirectory
- buffer-file-name)
- (concat "buffer "
- (buffer-name))))))))))
- (let ((continue t)
- prefix prefixlen suffix beg
- mode-specified
- (enable-local-eval enable-local-eval))
- ;; The prefix is what comes before "local variables:" in its line.
- ;; The suffix is what comes after "local variables:" in its line.
- (skip-chars-forward " \t")
- (or (eolp)
- (setq suffix (buffer-substring (point)
- (progn (end-of-line) (point)))))
- (goto-char (match-beginning 0))
- (or (bolp)
- (setq prefix
- (buffer-substring (point)
- (progn (beginning-of-line) (point)))))
-
- (if prefix (setq prefixlen (length prefix)
- prefix (regexp-quote prefix)))
- (if suffix (setq suffix (concat (regexp-quote suffix) "$")))
- (while continue
- ;; Look at next local variable spec.
- (if selective-display (re-search-forward "[\n\C-m]")
+ (when (let ((case-fold-search t))
+ (and (search-forward "Local Variables:" nil t)
+ (or (eq enable-local-variables t)
+ mode-only
+ (and enable-local-variables
+ (save-window-excursion
+ (switch-to-buffer (current-buffer))
+ (save-excursion
+ (beginning-of-line)
+ (set-window-start (selected-window) (point)))
+ (y-or-n-p (format "Set local variables as specified at end of %s? "
+ (if buffer-file-name
+ (file-name-nondirectory
+ buffer-file-name)
+ (concat "buffer "
+ (buffer-name))))))))))
+ (skip-chars-forward " \t")
+ (let ((enable-local-eval enable-local-eval)
+ ;; suffix is what comes after "local variables:" in its line.
+ (suffix
+ (concat
+ (regexp-quote (buffer-substring (point) (line-end-position)))
+ "$"))
+ ;; prefix is what comes before "local variables:" in its line.
+ (prefix
+ (concat "^" (regexp-quote
+ (buffer-substring (line-beginning-position)
+ (match-beginning 0)))))
+ beg)
+
+ (forward-line 1)
+ (let ((startpos (point))
+ endpos
+ (thisbuf (current-buffer)))
+ (save-excursion
+ (if (not (re-search-forward
+ (concat prefix "[ \t]*End:[ \t]*" suffix)
+ nil t))
+ (error "Local variables list is not properly terminated"))
+ (beginning-of-line)
+ (setq endpos (point)))
+
+ (with-temp-buffer
+ (insert-buffer-substring thisbuf startpos endpos)
+ (goto-char (point-min))
+ (subst-char-in-region (point) (point-max) ?\^m ?\n)
+ (while (not (eobp))
+ ;; Discard the prefix.
+ (if (looking-at prefix)
+ (delete-region (point) (match-end 0))
+ (error "Local variables entry is missing the prefix"))
+ (end-of-line)
+ ;; Discard the suffix.
+ (if (looking-back suffix)
+ (delete-region (match-beginning 0) (point))
+ (error "Local variables entry is missing the suffix"))
(forward-line 1))
- ;; Skip the prefix, if any.
- (if prefix
- (if (looking-at prefix)
- (forward-char prefixlen)
- (error "Local variables entry is missing the prefix")))
- ;; Find the variable name; strip whitespace.
- (skip-chars-forward " \t")
- (setq beg (point))
- (skip-chars-forward "^:\n")
- (if (eolp) (error "Missing colon in local variables entry"))
- (skip-chars-backward " \t")
- (let* ((str (buffer-substring beg (point)))
- (var (read str))
- val)
- ;; Setting variable named "end" means end of list.
- (if (string-equal (downcase str) "end")
- (setq continue nil)
- ;; Otherwise read the variable value.
+ (goto-char (point-min))
+
+ (while (not (eobp))
+ ;; Find the variable name; strip whitespace.
+ (skip-chars-forward " \t")
+ (setq beg (point))
+ (skip-chars-forward "^:\n")
+ (if (eolp) (error "Missing colon in local variables entry"))
+ (skip-chars-backward " \t")
+ (let* ((str (buffer-substring beg (point)))
+ (var (read str))
+ val)
+ ;; Read the variable value.
(skip-chars-forward "^:")
(forward-char 1)
(setq val (read (current-buffer)))
- (skip-chars-backward "\n")
- (skip-chars-forward " \t")
- (or (if suffix (looking-at suffix) (eolp))
- (error "Local variables entry is terminated incorrectly"))
(if mode-only
(if (eq var 'mode)
(setq mode-specified t))
;; Set the variable. "Variables" mode and eval are funny.
- (hack-one-local-variable var val))))))))
+ (with-current-buffer thisbuf
+ (hack-one-local-variable var val))))
+ (forward-line 1)))))))
(unless mode-only
(run-hooks 'hack-local-variables-hook))
mode-specified))
-(defvar ignored-local-variables
- '(enable-local-eval)
+(defvar ignored-local-variables ()
"Variables to be ignored in a file's local variable spec.")
;; Get confirmation before setting these variables as locals in a file.
If VAL is nil or omitted, the question is whether any value might be
dangerous."
(let ((safep (get sym 'safe-local-variable)))
- (or (memq sym ignored-local-variables)
- (get sym 'risky-local-variable)
+ (or (get sym 'risky-local-variable)
(and (string-match "-hooks?$\\|-functions?$\\|-forms?$\\|-program$\\|-command$\\|-predicate$\\|font-lock-keywords$\\|font-lock-keywords-[0-9]+$\\|font-lock-syntactic-keywords$\\|-frame-alist$\\|-mode-alist$\\|-map$\\|-map-alist$"
(symbol-name sym))
(not safep))
they appear in an `eval' local variable specification, without first
asking you for confirmation."
:group 'find-file
- :version "21.4"
+ :version "22.1"
:type '(repeat sexp))
(put 'c-set-style 'safe-local-eval-function t)
((eq var 'coding)
;; We have already handled coding: tag in set-auto-coding.
nil)
+ ((memq var ignored-local-variables)
+ nil)
;; "Setting" eval means either eval it or do nothing.
;; Likewise for setting hook variables.
((risky-local-variable-p var val)
(defun normal-backup-enable-predicate (name)
"Default `backup-enable-predicate' function.
-Checks for files in `temporary-file-directory' or
-`small-temporary-file-directory'."
+Checks for files in `temporary-file-directory',
+`small-temporary-file-directory', and /tmp."
(not (or (let ((comp (compare-strings temporary-file-directory 0 nil
name 0 nil)))
;; Directory is under temporary-file-directory.
(and (not (eq comp t))
(< comp (- (length temporary-file-directory)))))
+ (let ((comp (compare-strings "/tmp" 0 nil
+ name 0 nil)))
+ ;; Directory is under /tmp.
+ (and (not (eq comp t))
+ (< comp (- (length "/tmp")))))
(if small-temporary-file-directory
(let ((comp (compare-strings small-temporary-file-directory
0 nil
(file-name-as-directory (expand-file-name (or directory
default-directory))))
(setq filename (expand-file-name filename))
- (let ((hf (find-file-name-handler filename 'file-local-copy))
- (hd (find-file-name-handler directory 'file-local-copy)))
- (when (and hf (not (get hf 'file-remote-p))) (setq hf nil))
- (when (and hd (not (get hd 'file-remote-p))) (setq hd nil))
+ (let ((fremote (file-remote-p filename))
+ (dremote (file-remote-p directory)))
(if ;; Conditions for separate trees
(or
;; Test for different drives on DOS/Windows
;; 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))))
- ;; Test for different remote file handlers
- (not (eq hf hd))
;; Test for different remote file system identification
- (and
- hf
- (let ((re (car (rassq hf file-name-handler-alist))))
- (not
- (equal
- (and
- (string-match re filename)
- (substring filename 0 (match-end 0)))
- (and
- (string-match re directory)
- (substring directory 0 (match-end 0))))))))
+ (not (equal fremote dremote)))
filename
(let ((ancestor ".")
(filename-dir (file-name-as-directory filename)))
(defcustom before-save-hook nil
"Normal hook that is run before a buffer is saved to its file."
- :options '(copyright-update)
+ :options '(copyright-update time-stamp)
:type 'hook
:group 'files)
(not (and (eq selective-display t)
(= (char-after (1- (point-max))) ?\r)))
(or (eq require-final-newline t)
+ (eq require-final-newline 'visit-save)
(and require-final-newline
(y-or-n-p
(format "Buffer %s does not end in newline. Add one? "
;; but inhibited if one of write-file-functions returns non-nil.
;; It returns a value (MODES . BACKUPNAME), like backup-buffer.
(defun basic-save-buffer-1 ()
- (if save-buffer-coding-system
- (let ((coding-system-for-write save-buffer-coding-system))
+ (prog1
+ (if save-buffer-coding-system
+ (let ((coding-system-for-write save-buffer-coding-system))
+ (basic-save-buffer-2))
(basic-save-buffer-2))
- (basic-save-buffer-2)))
+ (setq buffer-file-coding-system-explicit last-coding-system-used)))
;; This returns a value (MODES . BACKUPNAME), like backup-buffer.
(defun basic-save-buffer-2 ()
"ACTION-ALIST argument used in call to `map-y-or-n-p'.")
(put 'save-some-buffers-action-alist 'risky-local-variable t)
+(defvar buffer-save-without-query nil
+ "Non-nil means `save-some-buffers' should save this buffer without asking.")
+(make-variable-buffer-local 'buffer-save-without-query)
+
(defun save-some-buffers (&optional arg pred)
"Save some modified file-visiting buffers. Asks user about each one.
You can answer `y' to save, `n' not to save, `C-r' to look at the
change the additional actions you can take on files."
(interactive "P")
(save-window-excursion
- (let* ((queried nil)
- (files-done
+ (let* (queried some-automatic
+ files-done abbrevs-done)
+ (dolist (buffer (buffer-list))
+ ;; First save any buffers that we're supposed to save unconditionally.
+ ;; That way the following code won't ask about them.
+ (with-current-buffer buffer
+ (when (and buffer-save-without-query (buffer-modified-p))
+ (setq some-automatic t)
+ (save-buffer))))
+ ;; Ask about those buffers that merit it,
+ ;; and record the number thus saved.
+ (setq files-done
(map-y-or-n-p
(function
(lambda (buffer)
(buffer-list)
'("buffer" "buffers" "save")
save-some-buffers-action-alist))
- (abbrevs-done
- (and save-abbrevs abbrevs-changed
- (progn
- (if (or arg
- (eq save-abbrevs 'silently)
- (y-or-n-p (format "Save abbrevs in %s? "
- abbrev-file-name)))
- (write-abbrev-file nil))
- ;; Don't keep bothering user if he says no.
- (setq abbrevs-changed nil)
- t))))
+ ;; Maybe to save abbrevs, and record whether
+ ;; we either saved them or asked to.
+ (and save-abbrevs abbrevs-changed
+ (progn
+ (if (or arg
+ (eq save-abbrevs 'silently)
+ (y-or-n-p (format "Save abbrevs in %s? "
+ abbrev-file-name)))
+ (write-abbrev-file nil))
+ ;; Don't keep bothering user if he says no.
+ (setq abbrevs-changed nil)
+ (setq abbrevs-done t)))
(or queried (> files-done 0) abbrevs-done
- (message "(No files need saving)")))))
+ (message (if some-automatic
+ "(Some special files were saved without asking)"
+ "(No files need saving)"))))))
\f
(defun not-modified (&optional arg)
"Mark current buffer as unmodified, not needing to be saved.
The idea behind the NOCONFIRM argument is that it should be
non-nil if the buffer is going to be reverted without asking the
user. In such situations, one has to be careful with potentially
-time consuming operations.")
+time consuming operations.
+
+For more information on how this variable is used by Auto Revert mode,
+see Info node `(emacs-xtra)Supporting additional buffers'.")
(defvar before-revert-hook nil
"Normal hook for `revert-buffer' to run before reverting.
(unlock-buffer)))
(widen)
(let ((coding-system-for-read
- ;; Auto-saved file shoule be read without
- ;; any code conversion.
- (if auto-save-p 'emacs-mule-unix
+ ;; Auto-saved file shoule be read by Emacs'
+ ;; internal coding.
+ (if auto-save-p 'auto-save-coding
(or coding-system-for-read
- buffer-file-coding-system))))
+ buffer-file-coding-system-explicit))))
;; This force after-insert-file-set-coding
;; (called from insert-file-contents) to set
;; buffer-file-coding-system to a proper value.
(defun kill-some-buffers (&optional list)
"Kill some buffers. Asks the user whether to kill each one of them.
-Non-interactively, if optional argument LIST is non-`nil', it
+Non-interactively, if optional argument LIST is non-nil, it
specifies the list of buffers to kill, asking for approval for each one."
(interactive)
(if (null list)
(buffer-substring (point) end)))))))))
+(defvar insert-directory-ls-version 'unknown)
+
;; insert-directory
;; - must insert _exactly_one_line_ describing FILE if WILDCARD and
;; FULL-DIRECTORY-P is nil.
(concat (file-name-as-directory file) ".")
file))))))))
+ ;; If we got "//DIRED//" in the output, it means we got a real
+ ;; directory listing, even if `ls' returned nonzero.
+ ;; So ignore any errors.
+ (when (if (stringp switches)
+ (string-match "--dired\\>" switches)
+ (member "--dired" switches))
+ (save-excursion
+ (forward-line -2)
+ (when (looking-at "//SUBDIRED//")
+ (forward-line -1))
+ (if (looking-at "//DIRED//")
+ (setq result 0))))
+
+ (when (and (not (eq 0 result))
+ (eq insert-directory-ls-version 'unknown))
+ ;; The first time ls returns an error,
+ ;; find the version numbers of ls,
+ ;; and set insert-directory-ls-version
+ ;; to > if it is more than 5.2.1, < if it is less, nil if it
+ ;; is equal or if the info cannot be obtained.
+ ;; (That can mean it isn't GNU ls.)
+ (let ((version-out
+ (with-temp-buffer
+ (call-process "ls" nil t nil "--version")
+ (buffer-string))))
+ (if (string-match "ls (.*utils) \\([0-9.]*\\)$" version-out)
+ (let* ((version (match-string 1 version-out))
+ (split (split-string version "[.]"))
+ (numbers (mapcar 'string-to-int split))
+ (min '(5 2 1))
+ comparison)
+ (while (and (not comparison) (or numbers min))
+ (cond ((null min)
+ (setq comparison '>))
+ ((null numbers)
+ (setq comparison '<))
+ ((> (car numbers) (car min))
+ (setq comparison '>))
+ ((< (car numbers) (car min))
+ (setq comparison '<))
+ (t
+ (setq numbers (cdr numbers)
+ min (cdr min)))))
+ (setq insert-directory-ls-version (or comparison '=)))
+ (setq insert-directory-ls-version nil))))
+
+ ;; For GNU ls versions 5.2.2 and up, ignore minor errors.
+ (when (and (eq 1 result) (eq insert-directory-ls-version '>))
+ (setq result 0))
+
;; If `insert-directory-program' failed, signal an error.
(unless (eq 0 result)
;; Delete the error message it may have output.
(when (if (stringp switches)
(string-match "--dired\\>" switches)
(member "--dired" switches))
+ ;; The following overshoots by one line for an empty
+ ;; directory listed with "--dired", but without "-a"
+ ;; switch, where the ls output contains a
+ ;; "//DIRED-OPTIONS//" line, but no "//DIRED//" line.
+ ;; We take care of that case later.
(forward-line -2)
(when (looking-at "//SUBDIRED//")
(delete-region (point) (progn (forward-line 1) (point)))
(forward-line -1))
- (let ((end (line-end-position)))
- (forward-word 1)
- (forward-char 3)
- (while (< (point) end)
- (let ((start (+ beg (read (current-buffer))))
- (end (+ beg (read (current-buffer)))))
- (if (= (char-after end) ?\n)
- (put-text-property start end 'dired-filename t)
- ;; It seems that we can't trust ls's output as to
- ;; byte positions of filenames.
- (put-text-property beg (point) 'dired-filename nil)
- (end-of-line))))
- (goto-char end)
- (beginning-of-line)
- (delete-region (point) (progn (forward-line 2) (point)))))
+ (if (looking-at "//DIRED//")
+ (let ((end (line-end-position))
+ (linebeg (point))
+ error-lines)
+ ;; Find all the lines that are error messages,
+ ;; and record the bounds of each one.
+ (goto-char beg)
+ (while (< (point) linebeg)
+ (or (eql (following-char) ?\s)
+ (push (list (point) (line-end-position)) error-lines))
+ (forward-line 1))
+ (setq error-lines (nreverse error-lines))
+ ;; Now read the numeric positions of file names.
+ (goto-char linebeg)
+ (forward-word 1)
+ (forward-char 3)
+ (while (< (point) end)
+ (let ((start (insert-directory-adj-pos
+ (+ beg (read (current-buffer)))
+ error-lines))
+ (end (insert-directory-adj-pos
+ (+ beg (read (current-buffer)))
+ error-lines)))
+ (if (memq (char-after end) '(?\n ?\ ))
+ ;; End is followed by \n or by " -> ".
+ (put-text-property start end 'dired-filename t)
+ ;; It seems that we can't trust ls's output as to
+ ;; byte positions of filenames.
+ (put-text-property beg (point) 'dired-filename nil)
+ (end-of-line))))
+ (goto-char end)
+ (beginning-of-line)
+ (delete-region (point) (progn (forward-line 1) (point))))
+ ;; Take care of the case where the ls output contains a
+ ;; "//DIRED-OPTIONS//"-line, but no "//DIRED//"-line
+ ;; and we went one line too far back (see above).
+ (forward-line 1))
+ (if (looking-at "//DIRED-OPTIONS//")
+ (delete-region (point) (progn (forward-line 1) (point)))))
;; Now decode what read if necessary.
(let ((coding (or coding-system-for-read
(end-of-line)
(insert " available " available)))))))))))
+(defun insert-directory-adj-pos (pos error-lines)
+ "Convert `ls --dired' file name position value POS to a buffer position.
+File name position values returned in ls --dired output
+count only stdout; they don't count the error messages sent to stderr.
+So this function converts to them to real buffer positions.
+ERROR-LINES is a list of buffer positions of error message lines,
+of the form (START END)."
+ (while (and error-lines (< (caar error-lines) pos))
+ (setq pos (+ pos (- (nth 1 (car error-lines)) (nth 0 (car error-lines)))))
+ (pop error-lines))
+ pos)
+
(defun insert-directory-safely (file switches
&optional wildcard full-directory-p)
"Insert directory listing for FILE, formatted according to SWITCHES.
;; Get a list of the indices of the args which are file names.
(file-arg-indices
(cdr (or (assq operation
- ;; The first five are special because they
+ ;; The first six are special because they
;; return a file name. We want to include the /:
;; in the return value.
;; So just avoid stripping it in the first place.
(file-name-as-directory . nil)
(directory-file-name . nil)
(file-name-sans-versions . nil)
+ (find-backup-file-name . nil)
;; `identity' means just return the first arg
;; not stripped of its quoting.
(substitute-in-file-name identity)
+ ;; `add' means add "/:" to the result.
+ (file-truename add 0)
+ ;; `quote' means add "/:" to buffer-file-name.
+ (insert-file-contents quote 0)
+ ;; `unquote-then-quote' means set buffer-file-name
+ ;; temporarily to unquoted filename.
+ (verify-visited-file-modtime unquote-then-quote)
+ ;; List the arguments which are filenames.
(file-name-completion 1)
(file-name-all-completions 1)
- ;; t means add "/:" to the result.
- (file-truename t 0)
+ (write-region 2 5)
(rename-file 0 1)
(copy-file 0 1)
(make-symbolic-link 0 1)
(setq file-arg-indices (cdr file-arg-indices))))
(cond ((eq method 'identity)
(car arguments))
- (method
+ ((eq method 'add)
(concat "/:" (apply operation arguments)))
+ ((eq method 'quote)
+ (prog1 (apply operation arguments)
+ (setq buffer-file-name (concat "/:" buffer-file-name))))
+ ((eq method 'unquote-then-quote)
+ (let (res)
+ (setq buffer-file-name (substring buffer-file-name 2))
+ (setq res (apply operation arguments))
+ (setq buffer-file-name (concat "/:" buffer-file-name))
+ res))
(t
(apply operation arguments)))))
\f