]> code.delx.au - gnu-emacs/blobdiff - lisp/files.el
(make-auto-save-file-name): If long file names are not
[gnu-emacs] / lisp / files.el
index b4e30207bfc68766210d97ed062c0d6f76e18ba6..bdd5604417d17551c981e865ff21506892450ea3 100644 (file)
@@ -1,7 +1,7 @@
 ;;; files.el --- file input and output commands for Emacs
 
-;; Copyright (C) 1985, 86, 87, 92, 93,
-;;              94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1985, 86, 87, 92, 93, 94, 95, 96, 97, 98, 99, 2000, 2001
+;;;   Free Software Foundation, Inc.
 
 ;; Maintainer: FSF
 
@@ -68,7 +68,7 @@ the name it is linked to."
   :group 'abbrev
   :group 'find-file)
 
-;;; Turn off backup files on VMS since it has version numbers.
+;; Turn off backup files on VMS since it has version numbers.
 (defcustom make-backup-files (not (eq system-type 'vax-vms))
   "*Non-nil means make a backup of a file the first time it is saved.
 This can be done by renaming the file or by copying.
@@ -535,10 +535,11 @@ colon-separated list of directories when resolving a relative directory name."
 
 (defun load-file (file)
   "Load the Lisp file named FILE."
-  (interactive "fLoad file: ")
-  (let ((completion-ignored-extensions
-        (delete ".elc" completion-ignored-extensions)))
-    (load (expand-file-name file) nil nil t)))
+  ;; This is a case where .elc makes a lot of sense.
+  (interactive (list (let ((completion-ignored-extensions
+                           (remove ".elc" completion-ignored-extensions)))
+                      (read-file-name "Load file: "))))
+  (load (expand-file-name file) nil nil t))
 
 (defun load-library (library)
   "Load the library named LIBRARY.
@@ -699,7 +700,10 @@ unlike `file-truename'."
 (defun switch-to-buffer-other-window (buffer &optional norecord)
   "Select buffer BUFFER in another window.
 Optional second arg NORECORD non-nil means
-do not put this buffer at the front of the list of recently selected ones."
+do not put this buffer at the front of the list of recently selected ones.
+
+This uses the function `display-buffer' as a subroutine; see its
+documentation for additional customization information."
   (interactive "BSwitch to buffer in other window: ")
   (let ((pop-up-windows t))
     (pop-to-buffer buffer t norecord)))
@@ -707,7 +711,10 @@ do not put this buffer at the front of the list of recently selected ones."
 (defun switch-to-buffer-other-frame (buffer &optional norecord)
   "Switch to buffer BUFFER in another frame.
 Optional second arg NORECORD non-nil means
-do not put this buffer at the front of the list of recently selected ones."
+do not put this buffer at the front of the list of recently selected ones.
+
+This uses the function `display-buffer' as a subroutine; see its
+documentation for additional customization information."
   (interactive "BSwitch to buffer in other frame: ")
   (let ((pop-up-frames t))
     (pop-to-buffer buffer t norecord)
@@ -940,20 +947,20 @@ If there is no such live buffer, return nil."
                  (setq found (car list))))
            (setq list (cdr list)))
          found)
-       (let ((number (nthcdr 10 (file-attributes truename)))
-             (list (buffer-list)) found)
+       (let* ((attributes (file-attributes truename))
+              (number (nthcdr 10 attributes))
+              (list (buffer-list)) found)
          (and buffer-file-numbers-unique
               number
               (while (and (not found) list)
-                (save-excursion
-                  (set-buffer (car list))
+                (with-current-buffer (car list)
                   (if (and buffer-file-name
                            (equal buffer-file-number number)
                            ;; Verify this buffer's file number
                            ;; still belongs to its file.
                            (file-exists-p buffer-file-name)
-                           (equal (nthcdr 10 (file-attributes buffer-file-name))
-                                  number))
+                           (equal (file-attributes buffer-file-name)
+                                  attributes))
                       (setq found (car list))))
                 (setq list (cdr list))))
          found))))
@@ -1007,7 +1014,7 @@ that are visiting the various files."
              (find-file-wildcards nil))
          (if (null files)
              (find-file-noselect filename)
-           (car (mapcar #'find-file-noselect files))))
+           (mapcar #'find-file-noselect files)))
       (let* ((buf (get-file-buffer filename))
             (truename (abbreviate-file-name (file-truename filename)))
             (number (nthcdr 10 (file-attributes truename)))
@@ -1170,18 +1177,19 @@ that are visiting the various files."
   "Like `insert-file-contents', but only reads in the file literally.
 A buffer may be modified in several ways after reading into the buffer,
 to Emacs features such as format decoding, character code
-conversion, find-file-hooks, automatic uncompression, etc.
+conversion, `find-file-hooks', automatic uncompression, etc.
 
 This function ensures that none of these modifications will take place."
   (let ((format-alist nil)
        (after-insert-file-functions nil)
        (coding-system-for-read 'no-conversion)
        (coding-system-for-write 'no-conversion)
-       (jka-compr-compression-info-list nil)
        (find-buffer-file-type-function
         (if (fboundp 'find-buffer-file-type)
             (symbol-function 'find-buffer-file-type)
-          nil)))
+          nil))
+       (inhibit-file-name-handlers '(jka-compr-handler image-file-handler))
+       (inhibit-file-name-operation 'insert-file-contents))
     (unwind-protect
        (progn
          (fset 'find-buffer-file-type (lambda (filename) t))
@@ -1214,7 +1222,8 @@ Format conversion and character code conversion are both disabled,
 and multibyte characters are disabled in the resulting buffer.
 The major mode used is Fundamental mode regardless of the file name,
 and local variable specifications in the file are ignored.
-Automatic uncompression is also disabled.
+Automatic uncompression and adding a newline at the end of the
+file due to `require-final-newline' is also disabled.
 
 You cannot absolutely rely on this function to result in
 visiting the file literally.  If Emacs already has a buffer
@@ -1248,52 +1257,53 @@ unless NOMODES is non-nil."
       nil
     (let* (not-serious
           (msg
-           (cond ((and error (file-attributes buffer-file-name))
-                  (setq buffer-read-only t)
-                  "File exists, but cannot be read")
-                 ((not buffer-read-only)
-                  (if (and warn
-                           ;; No need to warn if buffer is auto-saved
-                           ;; under the name of the visited file.
-                           (not (and buffer-file-name
-                                     auto-save-visited-file-name))
-                           (file-newer-than-file-p (or buffer-auto-save-file-name
-                                                       (make-auto-save-file-name))
-                                                   buffer-file-name))
-                      (format "%s has auto save data; consider M-x recover-file"
-                              (file-name-nondirectory buffer-file-name))
-                    (setq not-serious t)
-                    (if (and warn error) "(New file)" nil)))
-                 ((not error)
-                  (setq not-serious t)
-                  "Note: file is write protected")
-                 ((file-attributes (directory-file-name default-directory))
-                  "File not found and directory write-protected")
-                 ((file-exists-p (file-name-directory buffer-file-name))
-                  (setq buffer-read-only nil))
-                 (t
-                  (setq buffer-read-only nil)
-                  (if (file-exists-p (file-name-directory (directory-file-name (file-name-directory buffer-file-name))))
-                      "Use M-x make-directory RET RET to create the directory"
-                    "Use C-u M-x make-directory RET RET to create directory and its parents")))))
-      (if msg
-         (progn
-           (message msg)
-           (or not-serious (sit-for 1 nil t)))))
-    (if (and auto-save-default (not noauto))
-       (auto-save-mode t)))
+           (cond
+            ((not warn) nil)
+            ((and error (file-attributes buffer-file-name))
+             (setq buffer-read-only t)
+             "File exists, but cannot be read")
+            ((not buffer-read-only)
+             (if (and warn
+                      ;; No need to warn if buffer is auto-saved
+                      ;; under the name of the visited file.
+                      (not (and buffer-file-name
+                                auto-save-visited-file-name))
+                      (file-newer-than-file-p (or buffer-auto-save-file-name
+                                                  (make-auto-save-file-name))
+                                              buffer-file-name))
+                 (format "%s has auto save data; consider M-x recover-file"
+                         (file-name-nondirectory buffer-file-name))
+               (setq not-serious t)
+               (if error "(New file)" nil)))
+            ((not error)
+             (setq not-serious t)
+             "Note: file is write protected")
+            ((file-attributes (directory-file-name default-directory))
+             "File not found and directory write-protected")
+            ((file-exists-p (file-name-directory buffer-file-name))
+             (setq buffer-read-only nil))
+            (t
+             (setq buffer-read-only nil)
+             (if (file-exists-p (file-name-directory (directory-file-name (file-name-directory buffer-file-name))))
+                 "Use M-x make-directory RET RET to create the directory"
+               "Use C-u M-x make-directory RET RET to create directory and its parents")))))
+      (when msg
+       (message msg)
+       (or not-serious (sit-for 1 nil t))))
+    (when (and auto-save-default (not noauto))
+      (auto-save-mode t)))
   ;; Make people do a little extra work (C-x C-q)
   ;; before altering a backup file.
-  (if (backup-file-name-p buffer-file-name)
-      (setq buffer-read-only t))
-  (if nomodes
-      nil
-    (and view-read-only view-mode
-        (view-mode-disable))
+  (when (backup-file-name-p buffer-file-name)
+    (setq buffer-read-only t))
+  (unless nomodes
+    (when (and view-read-only view-mode)
+      (view-mode-disable))
     (normal-mode t)
-    (if (and buffer-read-only view-read-only
-            (not (eq (get major-mode 'mode-class) 'special)))
-       (view-mode-enter))
+    (when (and buffer-read-only
+              view-read-only
+              (not (eq (get major-mode 'mode-class) 'special)))
+      (view-mode-enter))
     (run-hooks 'find-file-hooks)))
 
 (defun normal-mode (&optional find-file)
@@ -1343,7 +1353,7 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("\\.p\\'" . pascal-mode)
      ("\\.pas\\'" . pascal-mode)
      ("\\.ad[abs]\\'" . ada-mode)
-     ("\\.\\([pP][Llm]\\|al\\)\\'" . perl-mode)
+     ("\\.\\([pP]\\([Llm]\\|erl\\)\\|al\\)\\'" . perl-mode)
      ("\\.s?html?\\'" . html-mode)
      ("\\.cc\\'" . c++-mode)
      ("\\.hh\\'" . c++-mode)
@@ -1360,8 +1370,8 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("\\.mk\\'" . makefile-mode)
      ("\\(M\\|m\\|GNUm\\)akefile\\(\\.in\\)?\\'" . makefile-mode)
      ("\\.am\\'" . makefile-mode)      ;For Automake.
-;;; Less common extensions come here
-;;; so more common ones above are found faster.
+     ;; Less common extensions come here
+     ;; so more common ones above are found faster.
      ("\\.texinfo\\'" . texinfo-mode)
      ("\\.te?xi\\'" . texinfo-mode)
      ("\\.s\\'" . asm-mode)
@@ -1380,7 +1390,7 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("\\(/\\|\\`\\)\\.\\(bash_profile\\|z?login\\|bash_login\\|z?logout\\)\\'" . sh-mode)
      ("\\(/\\|\\`\\)\\.\\(bash_logout\\|shrc\\|[kz]shrc\\|bashrc\\|t?cshrc\\|esrc\\)\\'" . sh-mode)
      ("\\(/\\|\\`\\)\\.\\([kz]shenv\\|xinitrc\\|startxrc\\|xsession\\)\\'" . sh-mode)
-     ("\\.m?spec$" . sh-mode)
+     ("\\.m?spec\\'" . sh-mode)
      ("\\.mm\\'" . nroff-mode)
      ("\\.me\\'" . nroff-mode)
      ("\\.ms\\'" . nroff-mode)
@@ -1440,27 +1450,26 @@ in that case, this function acts as if `enable-local-variables' were t."
      ("[:/]_emacs\\'" . emacs-lisp-mode)
      ("/crontab\\.X*[0-9]+\\'" . shell-script-mode)
      ("\\.ml\\'" . lisp-mode)
-     ("\\.asn$" . snmp-mode)
-     ("\\.mib$" . snmp-mode)
-     ("\\.smi$" . snmp-mode)
-     ("\\.as2$" . snmpv2-mode)
-     ("\\.mi2$" . snmpv2-mode)
-     ("\\.sm2$" . snmpv2-mode)
+     ("\\.\\(asn\\|mib\\|smi\\)\\'" . snmp-mode)
+     ("\\.\\(as\\|mi\\|sm\\)2\\'" . snmpv2-mode)
      ("\\.\\(diffs?\\|patch\\|rej\\)\\'" . diff-mode)
      ("\\.\\(dif\\|pat\\)\\'" . diff-mode) ; for MSDOG
-     ("\\.[eE]?[pP][sS]$" . ps-mode)
-     ("configure\\.in\\'" . autoconf-mode)
+     ("\\.[eE]?[pP][sS]\\'" . ps-mode)
+     ("configure\\.\\(ac\\|in\\)\\'" . autoconf-mode)
      ("BROWSE\\'" . ebrowse-tree-mode)
      ("\\.ebrowse\\'" . ebrowse-tree-mode)
      ("#\\*mail\\*" . mail-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>~
-     ("\\.~?[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.
-     ("\\.[12345678]\\'" . nroff-mode)))
+     ;; 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)
+     ;; 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)))
   "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.)
@@ -2106,8 +2115,8 @@ no longer accessible under its old name."
        (setq backup-info (find-backup-file-name real-file-name)
              backupname (car backup-info)
              targets (cdr backup-info))
-;;;     (if (file-directory-p buffer-file-name)
-;;;         (error "Cannot save buffer in directory %s" buffer-file-name))
+       ;; (if (file-directory-p buffer-file-name)
+       ;;     (error "Cannot save buffer in directory %s" buffer-file-name))
        (if backup-info
            (condition-case ()
                (let ((delete-old-versions
@@ -2246,7 +2255,7 @@ the value is \"\"."
   "A function to use instead of the default `make-backup-file-name'.
 A value of nil gives the default `make-backup-file-name' behaviour.
 
-This could be buffer-local to do something special for for specific
+This could be buffer-local to do something special for specific
 files.  If you define it, you may need to change `backup-file-name-p'
 and `file-name-sans-versions' too.
 
@@ -2275,7 +2284,7 @@ is made in the original file's directory.
 On MS-DOS filesystems without long names this variable is always
 ignored."
   :group 'backup
-  :type '(repeat (cons (regexp :tag "Regexp macthing filename")
+  :type '(repeat (cons (regexp :tag "Regexp matching filename")
                       (directory :tag "Backup directory name"))))
 
 (defun make-backup-file-name (file)
@@ -2506,7 +2515,8 @@ See the subroutine `basic-save-buffer' for more information."
        (make-backup-files (or (and make-backup-files (not (eq args 0)))
                               (memq args '(16 64)))))
     (and modp (memq args '(16 64)) (setq buffer-backed-up nil))
-    (if (and modp large) (message "Saving file %s..." (buffer-file-name)))
+    (if (and modp large (buffer-file-name))
+       (message "Saving file %s..." (buffer-file-name)))
     (basic-save-buffer)
     (and modp (memq args '(4 64)) (setq buffer-backed-up nil))))
 
@@ -2590,6 +2600,7 @@ After saving the buffer, this function runs `after-save-hook'."
            (widen)
            (save-excursion
              (and (> (point-max) 1)
+                  (not find-file-literally)
                   (/= (char-after (1- (point-max))) ?\n)
                   (not (and (eq selective-display t)
                             (= (char-after (1- (point-max))) ?\r)))
@@ -3014,7 +3025,7 @@ non-nil, it is called instead of rereading visited file contents."
                   (let ((coding-system-for-read
                          ;; Auto-saved file shoule be read without
                          ;; any code conversion.
-                         (if auto-save-p 'no-conversion
+                         (if auto-save-p 'emacs-mule-unix
                            coding-system-for-read)))
                     ;; Note that this preserves point in an intelligent way.
                     (insert-file-contents file-name (not auto-save-p)
@@ -3057,15 +3068,21 @@ non-nil, it is called instead of rereading visited file contents."
                   (if (file-symlink-p file)
                       (setq switches (concat switches "L")))
                   (set-buffer standard-output)
-                  (insert-directory file switches)
-                  (insert-directory file-name switches))))
+                  ;; Use insert-directory-safely, not insert-directory,
+                  ;; because these files might not exist.  In particular,
+                  ;; FILE might not exist if the auto-save file was for
+                  ;; a buffer that didn't visit a file, such as "*mail*".
+                  ;; The code in v20.x called `ls' directly, so we need
+                  ;; 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)))
           (switch-to-buffer (find-file-noselect file t))
           (let ((buffer-read-only nil)
                 ;; Keep the current buffer-file-coding-system.
                 (coding-system buffer-file-coding-system)
                 ;; Auto-saved file shoule be read without any code conversion.
-                (coding-system-for-read 'no-conversion))
+                (coding-system-for-read 'emacs-mule-unix))
             (erase-buffer)
             (insert-file-contents file-name nil)
             (set-buffer-file-coding-system coding-system))
@@ -3247,7 +3264,12 @@ See also `auto-save-file-name-p'."
 
        (if (and (eq system-type 'ms-dos)
                 (not (msdos-long-file-names)))
-           (let ((fn (file-name-nondirectory buffer-file-name)))
+           ;; We truncate the file name to DOS 8+3 limits before
+           ;; doing anything else, because the regexp passed to
+           ;; string-match below cannot handle extensions longer than
+           ;; 3 characters, multiple dots, and other atrocities.
+           (let ((fn (dos-8+3-filename
+                      (file-name-nondirectory buffer-file-name))))
              (string-match "\\`\\([^.]+\\)\\(\\.\\(..?\\)?.?\\|\\)\\'" fn)
              (concat (file-name-directory buffer-file-name)
                      "#" (match-string 1 fn)
@@ -3619,6 +3641,17 @@ If WILDCARD, it also runs the shell specified by `shell-file-name'."
                      (setq available (buffer-substring (point) end))))
                  (insert " available " available))))))))))
 
+(defun insert-directory-safely (file switches
+                                    &optional wildcard full-directory-p)
+  "Insert directory listing for FILE, formatted according to SWITCHES.
+
+Like `insert-directory', but if FILE does not exist, it inserts a
+message to that effect instead of signaling an error."
+  (if (file-exists-p file)
+      (insert-directory file switches wildcard full-directory-p)
+    ;; Simulate the message printed by `ls'.
+    (insert (format "%s: No such file or directory\n" file))))
+
 (defvar kill-emacs-query-functions nil
   "Functions to call with no arguments to query about killing Emacs.
 If any of these functions returns nil, killing Emacs is cancelled.
@@ -3626,6 +3659,16 @@ If any of these functions returns nil, killing Emacs is cancelled.
 but `kill-emacs', the low level primitive, does not.
 See also `kill-emacs-hook'.")
 
+(defcustom confirm-kill-emacs nil
+  "How to ask for confirmation when leaving Emacs.
+If nil, the default, don't ask at all.  If the value is non-nil, it should
+be a predicate function such as `yes-or-no-p'."
+  :type '(choice (const :tag "Ask with yes-or-no-p" yes-or-no-p)
+                (const :tag "Ask with y-or-n-p" y-or-n-p)
+                (const :tag "Don't confirm" nil))
+  :group 'emacs
+  :version "21.1")
+
 (defun save-buffers-kill-emacs (&optional arg)
   "Offer to save each buffer, then kill this Emacs process.
 With prefix arg, silently save all file-visiting buffers, then kill."
@@ -3652,6 +3695,8 @@ With prefix arg, silently save all file-visiting buffers, then kill."
                 (yes-or-no-p "Active processes exist; kill them and exit anyway? "))))
        ;; Query the user for other things, perhaps.
        (run-hook-with-args-until-failure 'kill-emacs-query-functions)
+       (or (null confirm-kill-emacs)
+          (funcall confirm-kill-emacs "Really exit Emacs? "))
        (kill-emacs)))
 \f
 ;; We use /: as a prefix to "quote" a file name