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.
(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.
When nil, never request confirmation."
:group 'files
:group 'find-file
+ :version "21.4"
:type '(choice integer (const :tag "Never request confirmation" nil)))
(defun find-file-noselect (filename &optional nowarn rawfile wildcards)
(mapc
(lambda (elt)
(cons (purecopy (car elt)) (cdr elt)))
- '(("\\.te?xt\\'" . text-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)
("\\.ad[abs]\\'" . ada-mode)
("\\.ad[bs].dg\\'" . ada-mode)
("\\.\\([pP]\\([Llm]\\|erl\\|od\\)\\|al\\)\\'" . perl-mode)
- ("\\.s?html?\\'" . html-mode)
("\\.mk\\'" . makefile-mode)
("\\([Mm]\\|GNUm\\)akep*file\\'" . makefile-mode)
("\\.am\\'" . makefile-mode) ;For Automake.
("\\.bib\\'" . bibtex-mode)
("\\.sql\\'" . sql-mode)
("\\.m[4c]\\'" . m4-mode)
- ("\\.m[fp]\\'" . metapost-mode)
+ ("\\.mf\\'" . metafont-mode)
+ ("\\.mp\\'" . metapost-mode)
("\\.vhdl?\\'" . vhdl-mode)
("\\.article\\'" . text-mode)
("\\.letter\\'" . text-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)
+ ("/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)
+ ("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\\|permissions\\|protocols\\|rpc\\|services\\)\\'" . conf-space-mode)
+ ("\\`/etc/\\(?:aliases\\|hosts\\..+\\|ksysguarddrc\\|opera6rc\\)\\'" . 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\\|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>~.
;; 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
- ("\\.\\(soa\\|zone\\)\\'" . dns-mode)
- ("\\.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.)
regular expression. The mode is then determined as the mode associated
with that interpreter in `interpreter-mode-alist'.")
-(defvar xml-based-modes '(html-mode)
- "Modes that override an XML declaration.
-When `set-auto-mode' sees an <?xml or <!DOCTYPE declaration, that
-buffer will be in some XML mode. If `auto-mode-alist' associates
-the file with one of the modes in this list, that mode will be
-used. Else `xml-mode' or `sgml-mode' is used.")
-
-(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, checks the
interpreter that runs this file against `interpreter-mode-alist',
-looks for an <?xml or <!DOCTYPE declaration (see
-`xml-based-modes'), or compares the filename against the entries
-in `auto-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 mode modes xml)
- (unless just-from-file-name
- ;; Find a -*- mode tag
- (save-excursion
- (goto-char (point-min))
- (skip-chars-forward " \t\n")
- ;; While we're at this point, check xml for later.
- (setq xml (looking-at "<\\?xml \\|<!DOCTYPE"))
- (and enable-local-variables
- (setq end (set-auto-mode-1))
- (if (save-excursion (search-forward ":" end t))
- ;; Find all specifications for the `mode:' variable
- ;; and execute them left to right.
- (while (let ((case-fold-search t))
- (or (and (looking-at "mode:")
- (goto-char (match-end 0)))
- (re-search-forward "[ \t;]mode:" end t)))
- (skip-chars-forward " \t")
- (let ((beg (point)))
- (if (search-forward ";" end t)
- (forward-char -1)
- (goto-char end))
- (skip-chars-backward " \t")
- (push (intern (concat (downcase (buffer-substring beg (point))) "-mode"))
- modes)))
- ;; Simple -*-MODE-*- case.
- (push (intern (concat (downcase (buffer-substring (point) end))
- "-mode"))
- modes))))
- ;; If we found modes to use, invoke them now, outside the save-excursion.
- (if modes
+ (let (end done mode modes)
+ ;; Find a -*- mode tag
+ (save-excursion
+ (goto-char (point-min))
+ (skip-chars-forward " \t\n")
+ (and enable-local-variables
+ (setq end (set-auto-mode-1))
+ (if (save-excursion (search-forward ":" end t))
+ ;; Find all specifications for the `mode:' variable
+ ;; and execute them left to right.
+ (while (let ((case-fold-search t))
+ (or (and (looking-at "mode:")
+ (goto-char (match-end 0)))
+ (re-search-forward "[ \t;]mode:" end t)))
+ (skip-chars-forward " \t")
+ (let ((beg (point)))
+ (if (search-forward ";" end t)
+ (forward-char -1)
+ (goto-char end))
+ (skip-chars-backward " \t")
+ (push (intern (concat (downcase (buffer-substring beg (point))) "-mode"))
+ modes)))
+ ;; Simple -*-MODE-*- case.
+ (push (intern (concat (downcase (buffer-substring (point) end))
+ "-mode"))
+ modes))))
+ ;; 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)
- (funcall mode)))
- ;; 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 (funcall (cdr done)))))
- (if (and (not done) buffer-file-name)
- (let ((name buffer-file-name))
- ;; Remove backup-suffixes from file name.
- (setq name (file-name-sans-versions name))
- (while (not done)
- ;; 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 done t)))
- (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))
- (if (if xml (memq mode xml-based-modes) t)
- (funcall mode)
- (xml-mode)))))))
- (and (not done)
- xml
- (xml-mode))))
-
+ (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.
(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)