aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisp/savehist.el192
1 files changed, 133 insertions, 59 deletions
diff --git a/lisp/savehist.el b/lisp/savehist.el
index 395bdf7a39b..67c7a576b83 100644
--- a/lisp/savehist.el
+++ b/lisp/savehist.el
@@ -1,10 +1,10 @@
1;;; savehist.el --- Save minibuffer history 1;;; savehist.el --- Save minibuffer history.
2 2
3;; Copyright (c) 1997 Free Software Foundation 3;; Copyright (C) 1997, 2005 Free Software Foundation
4 4
5;; Author: Hrvoje Niksic <hniksic@xemacs.org> 5;; Author: Hrvoje Niksic <hniksic@xemacs.org>
6;; Keywords: minibuffer 6;; Keywords: minibuffer
7;; Version: 0.4 7;; Version: 7
8 8
9;; This file is part of GNU Emacs. 9;; This file is part of GNU Emacs.
10 10
@@ -25,8 +25,9 @@
25 25
26;;; Commentary: 26;;; Commentary:
27 27
28;; This package provides the feature of saving minibuffer 28;; Many editors (e.g. Vim) have the feature of saving minibuffer
29;; history to an external file after exit. When Emacs is about the exit, 29;; history to an external file after exit. This package provides the
30;; same feature in Emacs. When Emacs is about the exit,
30;; `savehist-save' will dump the contents of various minibuffer 31;; `savehist-save' will dump the contents of various minibuffer
31;; histories (as determined by `savehist-history-variables') to a save 32;; histories (as determined by `savehist-history-variables') to a save
32;; file (`~/.emacs-history' by default). Although the package was 33;; file (`~/.emacs-history' by default). Although the package was
@@ -40,16 +41,18 @@
40 41
41;; Be sure to have `savehist.el' in a directory that is in your 42;; Be sure to have `savehist.el' in a directory that is in your
42;; load-path, and byte-compile it. 43;; load-path, and byte-compile it.
43 44
44;;; Code: 45;;; Code:
45 46
47(require 'custom)
48(require 'cl)
49
46;; User variables 50;; User variables
47 51
48(defgroup savehist nil 52(defgroup savehist nil
49 "Save minibuffer history." 53 "Save minibuffer history."
50 :group 'minibuffer) 54 :group 'minibuffer)
51 55
52
53(defcustom savehist-history-variables 56(defcustom savehist-history-variables
54 '( 57 '(
55 ;; Catch-all minibuffer history 58 ;; Catch-all minibuffer history
@@ -87,6 +90,7 @@
87 90
88 ;; Info, lookup, and bookmark historys 91 ;; Info, lookup, and bookmark historys
89 Info-minibuffer-history 92 Info-minibuffer-history
93 Info-search-history
90 Manual-page-minibuffer-history 94 Manual-page-minibuffer-history
91 95
92 ;; Emacs-specific: 96 ;; Emacs-specific:
@@ -98,8 +102,11 @@ only if it is bound and has a non-nil value. Thus it is safe to
98specify a superset of the variables a user is expected to want to 102specify a superset of the variables a user is expected to want to
99save. 103save.
100 104
101Default value contains minibuffer history variables used by Emacs, XEmacs, 105Default value contains minibuffer history variables used by Emacs, XEmacs,
102and Viper (uh-oh)." 106and Viper (uh-oh). Note that, if you customize this variable, you
107can lose the benefit of future versions of Emacs adding new values to
108the list. Because of that it might be more useful to add values using
109`add-to-list'."
103 :type '(repeat (symbol :tag "Variable")) 110 :type '(repeat (symbol :tag "Variable"))
104 :group 'savehist) 111 :group 'savehist)
105 112
@@ -118,12 +125,36 @@ If set to nil, the length is unlimited."
118 (const :tag "Unlimited" nil)) 125 (const :tag "Unlimited" nil))
119 :group 'savehist) 126 :group 'savehist)
120 127
121(defcustom savehist-modes 384 128(defcustom savehist-modes #o600
122 "*Default permissions of the history file. 129 "*Default permissions of the history file.
123This is decimal, not octal. The default is 384 (0600 in octal)." 130This is decimal, not octal. The default is 384 (0600 in octal).
131Set to nil to use the default permissions that Emacs uses, typically
132mandated by umask. The default is a bit more restrictive to protect
133the user's privacy."
124 :type 'integer 134 :type 'integer
125 :group 'savehist) 135 :group 'savehist)
126 136
137(defcustom savehist-autosave-interval (* 5 60)
138 "*The interval during which savehist should autosave the history buffer."
139 :type 'integer
140 :group 'savehist)
141
142(defconst savehist-xemacs (string-match "XEmacs" emacs-version))
143
144(defvar savehist-coding-system (if savehist-xemacs 'iso-2022-8 'utf-8)
145 "The coding system savehist uses for saving the minibuffer history.
146Changing this value while Emacs is running is supported, but considered
147unwise, unless you know what you are doing.")
148
149;; Internal variables.
150
151(defvar savehist-timer nil)
152
153(defvar savehist-last-checksum nil)
154
155;; Coding system without conversion, only used for calculating and
156;; comparing checksums.
157(defconst savehist-no-conversion (if savehist-xemacs 'binary 'no-conversion))
127 158
128;; Functions 159;; Functions
129 160
@@ -131,64 +162,107 @@ This is decimal, not octal. The default is 384 (0600 in octal)."
131(defun savehist-load (&optional no-hook) 162(defun savehist-load (&optional no-hook)
132 "Load the minibuffer histories from `savehist-file'. 163 "Load the minibuffer histories from `savehist-file'.
133Unless NO-HOOK is specified, the function will also add the save function 164Unless NO-HOOK is specified, the function will also add the save function
134to `kill-emacs-hook', thus ensuring that the minibuffer contents will be 165to `kill-emacs-hook' and on a timer, ensuring that the minibuffer contents
135saved before leaving Emacs. 166will be saved before leaving Emacs.
136 167
137This function should be normally used from your Emacs init file. Since it 168This function should be normally used from your Emacs init file. Since it
138removes your current minibuffer histories, it is unwise to call it at any 169removes your current minibuffer histories, it is unwise to call it at any
139other time." 170other time."
140 (interactive "P") 171 (interactive "P")
141 (unless no-hook 172 (unless no-hook
142 (add-hook 'kill-emacs-hook 'savehist-save)) 173 (add-hook 'kill-emacs-hook 'savehist-autosave)
143 (load savehist-file t)) 174 ;; Install an invocation of savehist-autosave on a timer. This
175 ;; should not cause a noticeable delay -- savehist-autosave
176 ;; executes in under 5 ms on my system.
177 (unless savehist-timer
178 (setq savehist-timer
179 (if savehist-xemacs
180 (start-itimer
181 "savehist" 'savehist-autosave savehist-autosave-interval
182 savehist-autosave-interval)
183 (run-with-timer savehist-autosave-interval savehist-autosave-interval
184 'savehist-autosave)))))
185 ;; Don't set coding-system-for-read here. We rely on autodetection
186 ;; and the coding cookie to convey that information. That way, if
187 ;; the user changes the value of savehist-coding-system, we can
188 ;; still correctly load the old file.
189 (load savehist-file t (not (interactive-p))))
144 190
145;;;###autoload 191;;;###autoload
146(defun savehist-save () 192(defun savehist-save (&optional auto-save)
147 "Save the histories from `savehist-history-variables' to `savehist-file'. 193 "Save the histories from `savehist-history-variables' to `savehist-file'.
148A variable will be saved if it is bound and non-nil." 194Unbound symbols referenced in `savehist-history-variables' are ignored.
195If AUTO-SAVE is non-nil, compare the saved contents to the one last saved,
196 and don't save the buffer if they are the same."
149 (interactive) 197 (interactive)
150 (save-excursion 198 (with-temp-buffer
151 ;; Is it wise to junk `find-file-hooks' just like that? How else 199 (insert
152 ;; should I avoid font-lock et al.? 200 (format ";; -*- mode: emacs-lisp; coding: %s -*-\n" savehist-coding-system)
153 (let ((find-file-hooks nil) 201 ";; Minibuffer history file, automatically generated by `savehist'.\n\n")
154 (buffer-exists-p (get-file-buffer savehist-file))) 202 (let ((print-length nil)
155 (set-buffer (find-file-noselect savehist-file)) 203 (print-string-length nil)
156 (unwind-protect 204 (print-level nil)
157 (progn 205 (print-readably t)
158 (erase-buffer) 206 (print-quoted t))
159 (insert 207 (dolist (sym savehist-history-variables)
160 ";; -*- emacs-lisp -*-\n" 208 (when (boundp sym)
161 ";; Minibuffer history file.\n\n" 209 (let ((value (savehist-process-for-saving (symbol-value sym))))
162 ";; This file is automatically generated by `savehist-save'" 210 (prin1 `(setq ,sym ',value) (current-buffer))
163 " or when\n" 211 (insert ?\n)))))
164 ";; exiting Emacs.\n" 212 ;; If autosaving, avoid writing if nothing has changed since the
165 ";; Do not edit. Unless you really want to, that is.\n\n") 213 ;; last write.
166 (let ((print-length nil) 214 (let ((checksum (md5 (current-buffer) nil nil savehist-no-conversion)))
167 (print-string-length nil) 215 (unless (and auto-save (equal checksum savehist-last-checksum))
168 (print-level nil) 216 ;; Set file-precious-flag when saving the buffer because we
169 (print-readably t)) 217 ;; don't want a half-finished write ruining the entire
170 (dolist (sym savehist-history-variables) 218 ;; history. (Remember that this is run from a timer and from
171 (when (and (boundp sym) 219 ;; kill-emacs-hook.)
172 (symbol-value sym)) 220 (let ((file-precious-flag t)
173 (prin1 221 (coding-system-for-write savehist-coding-system))
174 `(setq ,sym (quote ,(savehist-delimit (symbol-value sym) 222 (write-region (point-min) (point-max) savehist-file nil
175 savehist-length))) 223 (unless (interactive-p) 'quiet)))
176 (current-buffer)) 224 (when savehist-modes
177 (insert ?\n)))) 225 (set-file-modes savehist-file savehist-modes))
178 (save-buffer) 226 (setq savehist-last-checksum checksum)))))
179 (set-file-modes savehist-file savehist-modes)) 227
180 (or buffer-exists-p 228(defun savehist-autosave ()
181 (kill-buffer (current-buffer))))))) 229 "Save the minibuffer history if it has been modified since the last save."
182 230 (savehist-save t))
183;; If ARG is a list with less than N elements, return it, else return 231
184;; its subsequence of N elements. If N is nil or ARG is not a list, 232(defun savehist-process-for-saving (value)
185;; always return ARG. 233 ;; Process VALUE for saving to file. If it is a list, retain only
186(defun savehist-delimit (arg n) 234 ;; the first `savehist-length' values and prune non-printable ones.
187 (if (and n 235 ;; If VALUE is not a list, return it as-is if it is printable and
188 (listp arg) 236 ;; nil otherwise.
189 (> (length arg) n)) 237 (cond
190 (subseq arg 0 n) 238 ((listp value)
191 arg)) 239 (when (and savehist-length (> (length value) savehist-length))
240 (setq value (subseq value 0 savehist-length)))
241 (delete-if-not #'savehist-printable value))
242 ((savehist-printable value) value)
243 (t nil)))
244
245(defun savehist-printable (value)
246 "Returns non-nil if VALUE is printable."
247 ;; Quick response for oft-encountered types known to be printable.
248 (cond
249 ((stringp value))
250 ((numberp value))
251 ((symbolp value))
252 (t
253 ;; For others, check explicitly.
254 (condition-case nil
255 (let ((print-readably t)
256 (print-level nil)
257 (chars ()))
258 ;; Print the value into a string...
259 (prin1 value (lambda (char) (push char chars)))
260 ;; ...and attempt to read it.
261 (read (apply #'string (nreverse chars)))
262 ;; The attempt worked: the object is printable.
263 t)
264 ;; The attempt failed: the object is not printable.
265 (error nil)))))
192 266
193(provide 'savehist) 267(provide 'savehist)
194 268