1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-11-23 07:19:15 +00:00

Sync up to version 19.

(savehist-mode): New minor mode.
(savehist-file): Use ~/.emacs.d or ~/.xemacs if available.
(savehist-length): Remove (use history-length instead).
(savehist-file-modes): Rename from savehist-modes.
(savehist-save-hook, savehist-loaded): New vars.
(savehist-load): Use savehist-mode.  Try to smooth up transition from
old format to new format.
(savehist-install): Allow savehist-autosave-interval to be nil.
(savehist-save): Run the new hook.  Be more careful to only trim the
history variables.
(savehist-trim-history): New fun.  Replaces savehist-process-for-saving.
(savehist-printable): Print into a buffer rather than char-by-char.
This commit is contained in:
Stefan Monnier 2005-11-01 05:49:46 +00:00
parent d08a1c88d6
commit b91f17dcc6

View File

@ -4,7 +4,7 @@
;; Author: Hrvoje Niksic <hniksic@xemacs.org> ;; Author: Hrvoje Niksic <hniksic@xemacs.org>
;; Keywords: minibuffer ;; Keywords: minibuffer
;; Version: 9 ;; Version: 19
;; This file is part of GNU Emacs. ;; This file is part of GNU Emacs.
@ -32,10 +32,15 @@
;; variables may be specified by customizing ;; variables may be specified by customizing
;; `savehist-additional-variables'. ;; `savehist-additional-variables'.
;; To use savehist, put the following to `~/.emacs': ;; To use savehist, turn on savehist-mode by putting the following in
;; `~/.emacs':
;; ;;
;; (require 'savehist) ;; (savehist-mode 1)
;; (savehist-load) ;;
;; or with customize: `M-x customize-option RET savehist-mode RET'.
;;
;; You can also explicitly save history with `M-x savehist-save' and
;; load it by loading the `savehist-file' with `M-x load'.
;; If you are using a version of Emacs that does not ship with this ;; If you are using a version of Emacs that does not ship with this
;; package, be sure to have `savehist.el' in a directory that is in ;; package, be sure to have `savehist.el' in a directory that is in
@ -53,41 +58,62 @@
"Save minibuffer history." "Save minibuffer history."
:group 'minibuffer) :group 'minibuffer)
;;;###autoload
(defcustom savehist-mode nil
"Mode for automatic saving of minibuffer history.
Set this by calling the `savehist-mode' function or using the customize
interface."
:type 'boolean
:set (lambda (symbol value) (savehist-mode (or value 0)))
:initialize 'custom-initialize-default
:require 'savehist
:group 'savehist)
(defcustom savehist-save-minibuffer-history t (defcustom savehist-save-minibuffer-history t
"If non-nil, save all recorded minibuffer histories." "*If non-nil, save all recorded minibuffer histories.
If you want to save only specific histories, use `savehist-save-hook' to
modify the value of `savehist-minibuffer-history-variables'."
:type 'boolean :type 'boolean
:group 'savehist) :group 'savehist)
(defcustom savehist-additional-variables () (defcustom savehist-additional-variables ()
"List of additional variables to save. "*List of additional variables to save.
Each element is a symbol whose value will be persisted across Emacs Each element is a symbol whose value will be persisted across Emacs
sessions that use savehist. The contents of variables should be sessions that use savehist. The contents of variables should be
printable with the Lisp printer. If the variable's value is a list, printable with the Lisp printer. You don't need to add minibuffer
it will be trimmed to `savehist-length' elements. history variables to this list, all minibuffer histories will be
saved automatically as long as `savehist-save-minibuffer-history' is
non-nil.
You don't need to add minibuffer history variables to this list. All User options should be saved with the customize interface. This
minibuffer histories will be saved automatically." list is useful for saving automatically updated variables that are not
:type '(repeat (symbol :tag "Variable")) minibuffer histories, such as `compile-command' or `kill-ring'."
:type '(repeat variable)
:group 'savehist) :group 'savehist)
(defcustom savehist-file "~/.emacs-history" (defcustom savehist-file
"File name to save minibuffer history to. (cond
The minibuffer history is a series of Lisp expressions, which should be ;; Backward compatibility with previous versions of savehist.
loaded using `savehist-load' from your .emacs. See `savehist-load' for ((file-exists-p "~/.emacs-history") "~/.emacs-history")
more details." ((and (not (featurep 'xemacs)) (file-directory-p "~/.emacs.d/"))
"~/.emacs.d/history")
((and (featurep 'xemacs) (file-directory-p "~/.xemacs/"))
"~/.xemacs/history")
;; For users without `~/.emacs.d/' or `~/.xemacs/'.
(t "~/.emacs-history"))
"*File name where minibuffer history is saved to and loaded from.
The minibuffer history is a series of Lisp expressions loaded
automatically when `savehist-mode' is turned on. See `savehist-mode'
for more details.
If you want your minibuffer history shared between Emacs and XEmacs,
customize this value and make sure that `savehist-coding-system' is
set to a coding system that exists in both emacsen."
:type 'file :type 'file
:group 'savehist) :group 'savehist)
(defcustom savehist-length 100 (defcustom savehist-file-modes #o600
"Maximum length of a minibuffer list. "*Default permissions of the history file.
Minibuffer histories with more entries are trimmed when saved, the older
entries being removed first. If set to nil, the length is unlimited."
:type '(choice integer
(const :tag "Unlimited" nil))
:group 'savehist)
(defcustom savehist-modes #o600
"Default permissions of the history file.
This is decimal, not octal. The default is 384 (0600 in octal). This is decimal, not octal. The default is 384 (0600 in octal).
Set to nil to use the default permissions that Emacs uses, typically Set to nil to use the default permissions that Emacs uses, typically
mandated by umask. The default is a bit more restrictive to protect mandated by umask. The default is a bit more restrictive to protect
@ -96,16 +122,18 @@ the user's privacy."
:group 'savehist) :group 'savehist)
(defcustom savehist-autosave-interval (* 5 60) (defcustom savehist-autosave-interval (* 5 60)
"The interval during which savehist should autosave the history buffer." "*The interval between autosaves of minibuffer history.
If set to nil, disables timer-based autosaving."
:type 'integer :type 'integer
:group 'savehist) :group 'savehist)
(defvar savehist-coding-system (defcustom savehist-save-hook nil
;; UTF-8 is usually preferable to ISO-2022-8 when available, but under "Hook called by savehist-save before saving the variables.
;; XEmacs, UTF-8 is provided by external packages, and may not always be You can use this hook to influence choice and content of variables to
;; available, so even if it currently is available, we prefer not to save."
;; use is. :type 'hook)
(if (featurep 'xemacs) 'iso-2022-8 'utf-8)
(defvar savehist-coding-system (if (featurep 'xemacs) 'iso-2022-8 'utf-8)
"The coding system savehist uses for saving the minibuffer history. "The coding system savehist uses for saving the minibuffer history.
Changing this value while Emacs is running is supported, but considered Changing this value while Emacs is running is supported, but considered
unwise, unless you know what you are doing.") unwise, unless you know what you are doing.")
@ -116,34 +144,115 @@ unwise, unless you know what you are doing.")
(defvar savehist-last-checksum nil) (defvar savehist-last-checksum nil)
(defvar savehist-minibuffer-history-variables nil) (defvar savehist-minibuffer-history-variables nil
"List of minibuffer histories.
The contents of this variable is built while Emacs is running, and saved
along with minibuffer history. You can change its value off
`savehist-save-hook' to influence which variables are saved.")
(defconst savehist-no-conversion (if (featurep 'xemacs) 'binary 'no-conversion) ;; Coding system without any conversion, used for calculating an
"Coding system without conversion, only used for calculating checksums. ;; internal checksum. Should be as fast as possible, ideally simply
It should be as discriminating as `savehist-coding-system' but faster.") ;; exposing the internal representation of buffer text.
(defconst savehist-no-conversion (if (featurep 'xemacs) 'binary 'no-conversion))
;; Whether the history has already been loaded. This prevents
;; toggling savehist-mode from destroying existing minibuffer history.
(defvar savehist-loaded nil)
(eval-when-compile
(when (featurep 'xemacs)
;; Must declare this under XEmacs, which doesn't have built-in
;; minibuffer history truncation.
(defvar history-length 100)))
;; Functions. ;; Functions.
;;;###autoload
(defun savehist-mode (arg)
"Toggle savehist-mode.
Positive ARG turns on `savehist-mode'. When on, savehist-mode causes
minibuffer history to be saved periodically and when exiting Emacs.
When turned on for the first time in an Emacs session, it causes the
previous minibuffer history to be loaded from `savehist-file'.
This mode should normally be turned on from your Emacs init file.
Calling it at any other time replaces your current minibuffer histories,
which is probably undesirable."
(interactive "P")
(setq savehist-mode
(if (null arg)
(not savehist-mode)
(> (prefix-numeric-value arg) 0)))
(if (not savehist-mode)
(savehist-uninstall)
(when (and (not savehist-loaded)
(file-exists-p savehist-file))
(condition-case errvar
(progn
;; Don't set coding-system-for-read -- we rely on the
;; coding cookie to convey that information. That way, if
;; the user changes the value of savehist-coding-system,
;; we can still correctly load the old file.
(load savehist-file nil (not (interactive-p)))
(setq savehist-loaded t))
(error
;; Don't install the mode if reading failed. Doing so would
;; effectively destroy the user's data at the next save.
(setq savehist-mode nil)
(savehist-uninstall)
(signal (car errvar) (cdr errvar)))))
(savehist-install)))
(add-minor-mode 'savehist-mode "")
(defun savehist-load ()
"Obsolete function provided for transition from old versions of savehist.
Don't call this from new code, use (savehist-mode 1) instead.
This function loads the variables stored in `savehist-file' and turns on
savehist-mode. If savehist-file is in the old format that doesn't record
the value of `savehist-minibuffer-history-variables', that value is
deducted from the contents of the file."
(savehist-mode 1)
;; Old versions of savehist distributed with XEmacs didn't save
;; savehist-minibuffer-history-variables. If that variable is nil
;; after loading the file, try to intuit the intended value.
(when (null savehist-minibuffer-history-variables)
(setq savehist-minibuffer-history-variables
(with-temp-buffer
(ignore-errors
(insert-file-contents savehist-file))
(let ((vars ()) form)
(while (setq form (condition-case nil
(read (current-buffer)) (error nil)))
;; Each form read is of the form (setq VAR VALUE).
;; Collect VAR, i.e. (nth form 1).
(push (nth 1 form) vars))
vars)))))
(make-obsolete 'savehist-load 'savehist-mode)
(defun savehist-install () (defun savehist-install ()
"Hook savehist into Emacs. "Hook savehist into Emacs.
This will install `savehist-autosave' in `kill-emacs-hook' and on a timer. Normally invoked by calling `savehist-mode' to set the minor mode.
To undo this, call `savehist-uninstall'." Installs `savehist-autosave' in `kill-emacs-hook' and on a timer. To
undo this, call `savehist-uninstall'."
(add-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook) (add-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook)
(add-hook 'kill-emacs-hook 'savehist-autosave) (add-hook 'kill-emacs-hook 'savehist-autosave)
;; Install an invocation of savehist-autosave on a timer. This ;; Install an invocation of savehist-autosave on a timer. This
;; should not cause noticeable delays for users -- savehist-autosave ;; should not cause noticeable delays for users -- savehist-autosave
;; executes in under 5 ms on my system. ;; executes in under 5 ms on my system.
(unless savehist-timer (when (and savehist-autosave-interval
(null savehist-timer))
(setq savehist-timer (setq savehist-timer
(if (featurep 'xemacs) (if (featurep 'xemacs)
(start-itimer (start-itimer
"savehist" 'savehist-autosave savehist-autosave-interval "savehist" 'savehist-autosave savehist-autosave-interval
savehist-autosave-interval) savehist-autosave-interval)
(run-with-timer savehist-autosave-interval savehist-autosave-interval (run-with-timer savehist-autosave-interval
'savehist-autosave))))) savehist-autosave-interval 'savehist-autosave)))))
(defun savehist-uninstall () (defun savehist-uninstall ()
"Undo installing savehist." "Undo installing savehist.
Normally invoked by calling `savehist-mode' to unset the minor mode."
(remove-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook) (remove-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook)
(remove-hook 'kill-emacs-hook 'savehist-autosave) (remove-hook 'kill-emacs-hook 'savehist-autosave)
(when savehist-timer (when savehist-timer
@ -152,26 +261,6 @@ To undo this, call `savehist-uninstall'."
(cancel-timer savehist-timer)) (cancel-timer savehist-timer))
(setq savehist-timer nil))) (setq savehist-timer nil)))
;;;###autoload
(defun savehist-load (&optional no-install)
"Load the minibuffer histories from `savehist-file'.
Unless NO-INSTALL is present and non-nil, the function will also install
`savehist-autosave' in `kill-emacs-hook' and on a timer, ensuring that
history is saved before leaving Emacs.
This function should be normally used from your Emacs init file. Since
it removes your current minibuffer histories, it is unwise to call it at
any other time."
(interactive "P")
;; Don't set coding-system-for-read here. We rely on autodetection
;; and the coding cookie to convey that information. That way, if
;; the user changes the value of savehist-coding-system, we can
;; still correctly load the old file.
(load savehist-file t (not (interactive-p)))
(unless no-install
(savehist-install)))
;;;###autoload
(defun savehist-save (&optional auto-save) (defun savehist-save (&optional auto-save)
"Save the values of minibuffer history variables. "Save the values of minibuffer history variables.
Unbound symbols referenced in `savehist-additional-variables' are ignored. Unbound symbols referenced in `savehist-additional-variables' are ignored.
@ -182,21 +271,32 @@ If AUTO-SAVE is non-nil, compare the saved contents to the one last saved,
(insert (insert
(format ";; -*- mode: emacs-lisp; coding: %s -*-\n" savehist-coding-system) (format ";; -*- mode: emacs-lisp; coding: %s -*-\n" savehist-coding-system)
";; Minibuffer history file, automatically generated by `savehist'.\n\n") ";; Minibuffer history file, automatically generated by `savehist'.\n\n")
(run-hooks 'savehist-save-hook)
(let ((print-length nil) (let ((print-length nil)
(print-string-length nil) (print-string-length nil)
(print-level nil) (print-level nil)
(print-readably t) (print-readably t)
(print-quoted t) (print-quoted t))
(symbol-list (append ;; Save the minibuffer histories, along with the value of
(and savehist-save-minibuffer-history ;; savehist-minibuffer-history-variables itself.
(cons 'savehist-minibuffer-history-variables (when savehist-save-minibuffer-history
savehist-minibuffer-history-variables)) (prin1 `(setq savehist-minibuffer-history-variables
savehist-additional-variables))) ',savehist-minibuffer-history-variables)
(dolist (sym symbol-list) (current-buffer))
(when (boundp sym) (insert ?\n)
(let ((value (savehist-process-for-saving (symbol-value sym)))) (dolist (symbol savehist-minibuffer-history-variables)
(prin1 `(setq ,sym ',value) (current-buffer)) (when (boundp symbol)
(insert ?\n))))) (let ((value (savehist-trim-history (symbol-value symbol))))
(when value ; don't save empty histories
(prin1 `(setq ,symbol ',value) (current-buffer))
(insert ?\n))))))
;; Save the additional variables.
(dolist (symbol savehist-additional-variables)
(when (boundp symbol)
(let ((value (symbol-value symbol)))
(when (savehist-printable value)
(prin1 `(setq ,symbol ',value) (current-buffer))
(insert ?\n))))))
;; If autosaving, avoid writing if nothing has changed since the ;; If autosaving, avoid writing if nothing has changed since the
;; last write. ;; last write.
(let ((checksum (md5 (current-buffer) nil nil savehist-no-conversion))) (let ((checksum (md5 (current-buffer) nil nil savehist-no-conversion)))
@ -210,57 +310,55 @@ If AUTO-SAVE is non-nil, compare the saved contents to the one last saved,
(coding-system-for-write savehist-coding-system)) (coding-system-for-write savehist-coding-system))
(write-region (point-min) (point-max) savehist-file nil (write-region (point-min) (point-max) savehist-file nil
(unless (interactive-p) 'quiet))) (unless (interactive-p) 'quiet)))
(when savehist-modes (when savehist-file-modes
(set-file-modes savehist-file savehist-modes)) (set-file-modes savehist-file savehist-file-modes))
(setq savehist-last-checksum checksum))))) (setq savehist-last-checksum checksum)))))
(defun savehist-autosave () (defun savehist-autosave ()
"Save the minibuffer history if it has been modified since the last save." "Save the minibuffer history if it has been modified since the last save.
(savehist-save t)) Does nothing if savehist-mode is off."
(when savehist-mode
(savehist-save t)))
(defun savehist-process-for-saving (value) (defun savehist-trim-history (value)
;; Process VALUE for saving to file. If it is a list, retain only ;; Retain only the first history-length items in VALUE. Only used
;; the first `savehist-length' values and prune non-printable ones. ;; under XEmacs, which doesn't (yet) implement automatic trimming of
;; If VALUE is not a list, return it as-is if it is printable and ;; history lists to history-length items.
;; nil otherwise. (if (and (featurep 'xemacs)
(cond (natnump history-length)
((listp value) (> (length value) history-length))
(when (and savehist-length (> (length value) savehist-length)) ;; Equivalent to `(subseq value 0 history-length)', but doesn't
;; This should be: (setq value (subseq value 0 savehist-length)) ;; need cl-extra at run-time.
(setq value (copy-sequence value)) (loop repeat history-length collect (pop value))
(setcdr (nthcdr savehist-length value) nil)) value))
;; And this should be (remove-if-not #'savehist-printable value)
(delq nil (mapcar (lambda (x) (if (savehist-printable x) x)) value)))
((savehist-printable value) value)
(t nil)))
(defun savehist-printable (value) (defun savehist-printable (value)
"Return non-nil if VALUE is printable." "Return non-nil if VALUE is printable."
;; Quick response for oft-encountered types known to be printable.
(cond (cond
;; Quick response for oft-encountered types known to be printable.
((stringp value)) ((stringp value))
((numberp value)) ((numberp value))
((symbolp value)) ((symbolp value))
(t (t
;; For others, check explicitly. ;; For others, check explicitly.
(condition-case nil (with-temp-buffer
(let ((print-readably t) (condition-case nil
(print-level nil) (let ((print-readably t) (print-level nil))
(chars ())) ;; Print the value into a buffer...
;; Print the value into a string... (prin1 value (current-buffer))
(prin1 value (lambda (char) (push char chars)))
;; ...and attempt to read it. ;; ...and attempt to read it.
(read (apply #'string (nreverse chars))) (read (point-min-marker))
;; The attempt worked: the object is printable. ;; The attempt worked: the object is printable.
t) t)
;; The attempt failed: the object is not printable. ;; The attempt failed: the object is not printable.
(error nil))))) (error nil))))))
(defun savehist-minibuffer-hook () (defun savehist-minibuffer-hook ()
(add-to-list 'savehist-minibuffer-history-variables (add-to-list 'savehist-minibuffer-history-variables
minibuffer-history-variable)) minibuffer-history-variable))
(provide 'savehist) (provide 'savehist)
;; arch-tag: b3ce47f4-c5ad-4ebc-ad02-73aba705cf9f ;; arch-tag: b3ce47f4-c5ad-4ebc-ad02-73aba705cf9f
;;; savehist.el ends here ;;; savehist.el ends here