]> code.delx.au - gnu-emacs/blobdiff - lisp/saveplace.el
* emacs-lisp/easy-mmode.el (define-minor-mode): Doc fix re setf.
[gnu-emacs] / lisp / saveplace.el
index 3211a055335c3cb662f9ab08ec58909877135e25..baa6b794fc4d3643f3b136cfc8a4e499a4275bb7 100644 (file)
@@ -1,6 +1,6 @@
 ;;; saveplace.el --- automatically save place in files
 
-;; Copyright (C) 1993, 1994, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1993-1994, 2001-2013 Free Software Foundation, Inc.
 
 ;; Author: Karl Fogel <kfogel@red-bean.com>
 ;; Maintainer: FSF
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -38,7 +36,7 @@
 ;;; Code:
 
 ;; this is what I was using during testing:
-;; (define-key ctl-x-map "p" 'toggle-save-place)
+;; (define-key ctl-x-map "p" 'toggle-save-place-globally)
 
 (defgroup save-place nil
   "Automatically save place in files."
@@ -53,15 +51,17 @@ rather than the beginning of the buffer.
 This alist is saved between Emacs sessions.")
 
 (defcustom save-place nil
-  "*Non-nil means automatically save place in each file.
+  "Non-nil means automatically save place in each file.
 This means when you visit a file, point goes to the last place
 where it was when you previously visited the same file.
 This variable is automatically buffer-local.
 
-If you wish your place in any file to always be automatically saved,
-simply put this in your `~/.emacs' file:
+If you wish your place in any file to always be automatically
+saved, set this to t using the Customize facility, or put the
+following code in your init file:
 
-\(setq-default save-place t\)"
+\(setq-default save-place t)
+\(require 'saveplace)"
   :type 'boolean
   :require 'saveplace
   :group 'save-place)
@@ -69,12 +69,12 @@ simply put this in your `~/.emacs' file:
 (make-variable-buffer-local 'save-place)
 
 (defcustom save-place-file (convert-standard-filename "~/.emacs-places")
-  "*Name of the file that records `save-place-alist' value."
+  "Name of the file that records `save-place-alist' value."
   :type 'file
   :group 'save-place)
 
 (defcustom save-place-version-control nil
-  "*Controls whether to make numbered backups of master save-place file.
+  "Controls whether to make numbered backups of master save-place file.
 It can have four values: t, nil, `never', and `nospecial'.  The first
 three have the same meaning that they do for the variable
 `version-control', and the final value `nospecial' means just use the
@@ -88,12 +88,56 @@ value of `version-control'."
 (defvar save-place-loaded nil
   "Non-nil means that the `save-place-file' has been loaded.")
 
-(defcustom save-place-limit nil
+(defcustom save-place-limit 400
   "Maximum number of entries to retain in the list; nil means no limit."
+  :version "24.1"                       ; nil -> 400
   :type '(choice (integer :tag "Entries" :value 1)
                 (const :tag "No Limit" nil))
   :group 'save-place)
 
+(defcustom save-place-forget-unreadable-files t
+  "Non-nil means forget place in unreadable files.
+
+The filenames in `save-place-alist' that do not match
+`save-place-skip-check-regexp' are filtered through
+`file-readable-p'. if nil, their alist entries are removed.
+
+You may do this anytime by calling the complementary function,
+`save-place-forget-unreadable-files'.  When this option is turned on,
+this happens automatically before saving `save-place-alist' to
+`save-place-file'."
+  :type 'boolean :group 'save-place)
+
+(defcustom save-place-save-skipped t
+  "If non-nil, remember files matching `save-place-skip-check-regexp'.
+
+When filtering `save-place-alist' for unreadable files, some will not
+be checked, based on said regexp, and instead saved or forgotten based
+on this flag."
+  :type 'boolean :group 'save-place)
+
+(defcustom save-place-skip-check-regexp
+  ;; thanks to ange-ftp-name-format
+  "\\`/\\(?:cdrom\\|floppy\\|mnt\\|\\(?:[^@/:]*@\\)?[^@/:]*[^@/:.]:\\)"
+  "Regexp whose file names shall not be checked for readability.
+
+When forgetting unreadable files, file names matching this regular
+expression shall not be checked for readability, but instead be
+subject to `save-place-save-skipped'.
+
+Files for which such a check may be inconvenient include those on
+removable and network volumes."
+  :type 'regexp :group 'save-place)
+
+(defcustom save-place-ignore-files-regexp
+  "\\(?:COMMIT_EDITMSG\\|hg-editor-[[:alnum:]]+\\.txt\\|svn-commit\\.tmp\\|bzr_log\\.[[:alnum:]]+\\)$"
+  "Regexp matching files for which no position should be recorded.
+Useful for temporary file such as commit message files that are
+automatically created by the VCS.  If set to nil, this feature is
+disabled, i.e., the position is recorded for all files."
+  :version "24.1"
+  :type 'regexp :group 'save-place)
+
 (defun toggle-save-place (&optional parg)
   "Toggle whether to save your place in this file between sessions.
 If this mode is enabled, point is recorded when you kill the buffer
@@ -103,7 +147,8 @@ even in a later Emacs session.
 If called with a prefix arg, the mode is enabled if and only if
 the argument is positive.
 
-To save places automatically in all files, put this in your `.emacs' file:
+To save places automatically in all files, put this in your init
+file:
 
 \(setq-default save-place t\)"
   (interactive "P")
@@ -124,27 +169,64 @@ To save places automatically in all files, put this in your `.emacs' file:
   ;; file.  If not, do so, then feel free to modify the alist.  It
   ;; will be saved again when Emacs is killed.
   (or save-place-loaded (load-save-place-alist-from-file))
-  (if buffer-file-name
-      (progn
-        (let ((cell (assoc buffer-file-name save-place-alist))
-             (position (if (not (eq major-mode 'hexl-mode))
-                           (point)
-                         (1+ (hexl-current-address)))))
-          (if cell
-              (setq save-place-alist (delq cell save-place-alist)))
-         (if (and save-place
-                  (not (= position 1)))  ;; Optimize out the degenerate case.
-             (setq save-place-alist
-                   (cons (cons buffer-file-name position)
-                         save-place-alist)))))))
+  (when (and buffer-file-name
+            (or (not save-place-ignore-files-regexp)
+                (not (string-match save-place-ignore-files-regexp
+                                   buffer-file-name))))
+    (let ((cell (assoc buffer-file-name save-place-alist))
+         (position (if (not (eq major-mode 'hexl-mode))
+                       (point)
+                     (with-no-warnings
+                       (1+ (hexl-current-address))))))
+      (if cell
+         (setq save-place-alist (delq cell save-place-alist)))
+      (if (and save-place
+              (not (= position 1)))  ;; Optimize out the degenerate case.
+         (setq save-place-alist
+               (cons (cons buffer-file-name position)
+                     save-place-alist))))))
+
+(defun save-place-forget-unreadable-files ()
+  "Remove unreadable files from `save-place-alist'.
+For each entry in the alist, if `file-readable-p' returns nil for the
+filename, remove the entry.  Save the new alist \(as the first pair
+may have changed\) back to `save-place-alist'."
+  (interactive)
+  ;; the following was adapted from an in-place filtering function,
+  ;; `filter-mod', used in the original.
+  (unless (null save-place-alist)      ;says it better than `when'
+    ;; first, check all except first
+    (let ((fmprev save-place-alist) (fmcur (cdr save-place-alist)))
+      (while fmcur                     ;not null
+       ;; a value is only saved when it becomes FMPREV.
+       (if (if (string-match save-place-skip-check-regexp (caar fmcur))
+               save-place-save-skipped
+             (file-readable-p (caar fmcur)))
+           (setq fmprev fmcur)
+         (setcdr fmprev (cdr fmcur)))
+       (setq fmcur (cdr fmcur))))
+    ;; test first pair, keep it if OK, otherwise 2nd element, which
+    ;; may be '()
+    (unless (if (string-match save-place-skip-check-regexp
+                             (caar save-place-alist))
+               save-place-save-skipped
+             (file-readable-p (caar save-place-alist)))
+      (setq save-place-alist (cdr save-place-alist)))))
 
 (defun save-place-alist-to-file ()
-  (let ((file (expand-file-name save-place-file)))
-    (save-excursion
-      (message "Saving places to %s..." file)
-      (set-buffer (get-buffer-create " *Saved Places*"))
+  (let ((file (expand-file-name save-place-file))
+        (coding-system-for-write 'utf-8))
+    (with-current-buffer (get-buffer-create " *Saved Places*")
       (delete-region (point-min) (point-max))
-      (print save-place-alist (current-buffer))
+      (when save-place-forget-unreadable-files
+       (save-place-forget-unreadable-files))
+      (insert (format ";;; -*- coding: %s -*-\n"
+                      (symbol-name coding-system-for-write)))
+      (let ((print-length nil)
+            (print-level nil))
+        (pp (sort save-place-alist
+                  (lambda (a b) (string< (car a) (car b))))
+            (current-buffer)))
       (let ((version-control
              (cond
               ((null save-place-version-control) nil)
@@ -152,9 +234,11 @@ To save places automatically in all files, put this in your `.emacs' file:
               ((eq 'nospecial save-place-version-control) version-control)
               (t
                t))))
-        (write-file file)
-        (kill-buffer (current-buffer))
-        (message "Saving places to %s...done" file)))))
+       (condition-case nil
+           ;; Don't use write-file; we don't want this buffer to visit it.
+            (write-region (point-min) (point-max) file)
+         (file-error (message "Saving places: can't write %s" file)))
+        (kill-buffer (current-buffer))))))
 
 (defun load-save-place-alist-from-file ()
   (if (not save-place-loaded)
@@ -164,11 +248,9 @@ To save places automatically in all files, put this in your `.emacs' file:
           ;; make sure that the alist does not get overwritten, and then
           ;; load it if it exists:
           (if (file-readable-p file)
-              (save-excursion
-                (message "Loading places from %s..." save-place-file)
-                ;; don't want to use find-file because we have been
-                ;; adding hooks to it.
-                (set-buffer (get-buffer-create " *Saved Places*"))
+              ;; don't want to use find-file because we have been
+              ;; adding hooks to it.
+              (with-current-buffer (get-buffer-create " *Saved Places*")
                 (delete-region (point-min) (point-max))
                 (insert-file-contents file)
                 (goto-char (point-min))
@@ -193,8 +275,7 @@ To save places automatically in all files, put this in your `.emacs' file:
                             (setq count (1+ count)))
                           (setq s (cdr s))))))
 
-                (kill-buffer (current-buffer))
-                (message "Loading places from %s...done" file)))
+                (kill-buffer (current-buffer))))
           nil))))
 
 (defun save-places-to-alist ()
@@ -205,8 +286,7 @@ To save places automatically in all files, put this in your `.emacs' file:
       ;; put this into a save-excursion in case someone is counting on
       ;; another function in kill-emacs-hook to act on the last buffer
       ;; they were in:
-      (save-excursion
-       (set-buffer (car buf-list))
+      (with-current-buffer (car buf-list)
        ;; save-place checks buffer-file-name too, but we can avoid
        ;; overhead of function call by checking here too.
        (and buffer-file-name (save-place-to-alist))
@@ -217,7 +297,7 @@ To save places automatically in all files, put this in your `.emacs' file:
   (let ((cell (assoc buffer-file-name save-place-alist)))
     (if cell
        (progn
-         (or after-find-file-from-revert-buffer
+         (or revert-buffer-in-progress-p
              (goto-char (cdr cell)))
           ;; and make sure it will be saved again for later
           (setq save-place t)))))
@@ -232,7 +312,8 @@ To save places automatically in all files, put this in your `.emacs' file:
 
 (add-hook 'find-file-hook 'save-place-find-file-hook t)
 
-(add-hook 'kill-emacs-hook 'save-place-kill-emacs-hook)
+(unless noninteractive
+  (add-hook 'kill-emacs-hook 'save-place-kill-emacs-hook))
 
 (add-hook 'kill-buffer-hook 'save-place-to-alist)