Commit | Line | Data |
---|---|---|
06b60517 | 1 | ;;; savehist.el --- Save minibuffer history |
cb23c7c1 | 2 | |
ba318903 | 3 | ;; Copyright (C) 1997, 2005-2014 Free Software Foundation, Inc. |
cb23c7c1 RS |
4 | |
5 | ;; Author: Hrvoje Niksic <hniksic@xemacs.org> | |
34dc21db | 6 | ;; Maintainer: emacs-devel@gnu.org |
cb23c7c1 | 7 | ;; Keywords: minibuffer |
ed5a258a | 8 | ;; Version: 24 |
cb23c7c1 RS |
9 | |
10 | ;; This file is part of GNU Emacs. | |
11 | ||
eb3fa2cf | 12 | ;; GNU Emacs is free software: you can redistribute it and/or modify |
cb23c7c1 | 13 | ;; it under the terms of the GNU General Public License as published by |
eb3fa2cf GM |
14 | ;; the Free Software Foundation, either version 3 of the License, or |
15 | ;; (at your option) any later version. | |
cb23c7c1 RS |
16 | |
17 | ;; GNU Emacs is distributed in the hope that it will be useful, | |
18 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | ;; GNU General Public License for more details. | |
21 | ||
22 | ;; You should have received a copy of the GNU General Public License | |
eb3fa2cf | 23 | ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. |
cb23c7c1 RS |
24 | |
25 | ;;; Commentary: | |
26 | ||
216ee1a4 SM |
27 | ;; Many editors (e.g. Vim) have the feature of saving minibuffer |
28 | ;; history to an external file after exit. This package provides the | |
2a2b5b29 SM |
29 | ;; same feature in Emacs. When set up, it saves recorded minibuffer |
30 | ;; histories to a file (`~/.emacs-history' by default). Additional | |
31 | ;; variables may be specified by customizing | |
32 | ;; `savehist-additional-variables'. | |
cb23c7c1 | 33 | |
b91f17dc SM |
34 | ;; To use savehist, turn on savehist-mode by putting the following in |
35 | ;; `~/.emacs': | |
cb23c7c1 | 36 | ;; |
b91f17dc SM |
37 | ;; (savehist-mode 1) |
38 | ;; | |
39 | ;; or with customize: `M-x customize-option RET savehist-mode RET'. | |
40 | ;; | |
41 | ;; You can also explicitly save history with `M-x savehist-save' and | |
b13e8fb3 | 42 | ;; load it by loading the `savehist-file' with `M-x load-file'. |
cb23c7c1 | 43 | |
2a2b5b29 SM |
44 | ;; If you are using a version of Emacs that does not ship with this |
45 | ;; package, be sure to have `savehist.el' in a directory that is in | |
46 | ;; your load-path, and to byte-compile it. | |
216ee1a4 | 47 | |
cb23c7c1 RS |
48 | ;;; Code: |
49 | ||
216ee1a4 | 50 | (require 'custom) |
2a2b5b29 | 51 | (eval-when-compile |
5c91a2b8 | 52 | (if (featurep 'xemacs) (require 'cl))) |
216ee1a4 | 53 | |
cb23c7c1 RS |
54 | ;; User variables |
55 | ||
56 | (defgroup savehist nil | |
57 | "Save minibuffer history." | |
cd4160e6 | 58 | :version "22.1" |
cb23c7c1 RS |
59 | :group 'minibuffer) |
60 | ||
2a2b5b29 | 61 | (defcustom savehist-save-minibuffer-history t |
ea6c930a | 62 | "If non-nil, save all recorded minibuffer histories. |
fdcfd745 JB |
63 | If you want to save only specific histories, use `savehist-save-hook' |
64 | to modify the value of `savehist-minibuffer-history-variables'." | |
2a2b5b29 SM |
65 | :type 'boolean |
66 | :group 'savehist) | |
67 | ||
68 | (defcustom savehist-additional-variables () | |
ea6c930a | 69 | "List of additional variables to save. |
2a2b5b29 | 70 | Each element is a symbol whose value will be persisted across Emacs |
fdcfd745 | 71 | sessions that use Savehist. The contents of variables should be |
b91f17dc SM |
72 | printable with the Lisp printer. You don't need to add minibuffer |
73 | history variables to this list, all minibuffer histories will be | |
74 | saved automatically as long as `savehist-save-minibuffer-history' is | |
75 | non-nil. | |
76 | ||
fdcfd745 | 77 | User options should be saved with the Customize interface. This |
b91f17dc SM |
78 | list is useful for saving automatically updated variables that are not |
79 | minibuffer histories, such as `compile-command' or `kill-ring'." | |
80 | :type '(repeat variable) | |
cb23c7c1 RS |
81 | :group 'savehist) |
82 | ||
cd4160e6 | 83 | (defcustom savehist-ignored-variables nil ;; '(command-history) |
ea6c930a | 84 | "List of additional variables not to save." |
cd4160e6 RS |
85 | :type '(repeat variable) |
86 | :group 'savehist) | |
87 | ||
b91f17dc | 88 | (defcustom savehist-file |
d6c180c4 | 89 | (locate-user-emacs-file "history" ".emacs-history") |
ea6c930a | 90 | "File name where minibuffer history is saved to and loaded from. |
b91f17dc | 91 | The minibuffer history is a series of Lisp expressions loaded |
fdcfd745 | 92 | automatically when Savehist mode is turned on. See `savehist-mode' |
b91f17dc SM |
93 | for more details. |
94 | ||
95 | If you want your minibuffer history shared between Emacs and XEmacs, | |
96 | customize this value and make sure that `savehist-coding-system' is | |
97 | set to a coding system that exists in both emacsen." | |
cb23c7c1 RS |
98 | :type 'file |
99 | :group 'savehist) | |
100 | ||
b91f17dc | 101 | (defcustom savehist-file-modes #o600 |
ea6c930a | 102 | "Default permissions of the history file. |
216ee1a4 SM |
103 | This is decimal, not octal. The default is 384 (0600 in octal). |
104 | Set to nil to use the default permissions that Emacs uses, typically | |
105 | mandated by umask. The default is a bit more restrictive to protect | |
106 | the user's privacy." | |
cb23c7c1 RS |
107 | :type 'integer |
108 | :group 'savehist) | |
109 | ||
216ee1a4 | 110 | (defcustom savehist-autosave-interval (* 5 60) |
ea6c930a | 111 | "The interval between autosaves of minibuffer history. |
b91f17dc | 112 | If set to nil, disables timer-based autosaving." |
2ac7e73e JB |
113 | :type '(choice (const :tag "Disabled" nil) |
114 | (integer :tag "Seconds")) | |
216ee1a4 SM |
115 | :group 'savehist) |
116 | ||
ed5a258a | 117 | (defcustom savehist-mode-hook nil |
fdcfd745 | 118 | "Hook called when Savehist mode is turned on." |
105744a3 JL |
119 | :type 'hook |
120 | :group 'savehist) | |
ed5a258a | 121 | |
b91f17dc | 122 | (defcustom savehist-save-hook nil |
b13e8fb3 | 123 | "Hook called by `savehist-save' before saving the variables. |
fdcfd745 JB |
124 | You can use this hook to influence choice and content of variables |
125 | to save." | |
f6fbc344 RS |
126 | :type 'hook |
127 | :group 'savehist) | |
b91f17dc | 128 | |
2d10b62b SM |
129 | ;; This should be capable of representing characters used by Emacs. |
130 | ;; We prefer UTF-8 over ISO 2022 because it is well-known outside | |
83d67b56 | 131 | ;; Mule. XEmacs prior to 21.5 had UTF-8 provided by an external |
2d10b62b SM |
132 | ;; package which may not be loaded, which is why we check for version. |
133 | (defvar savehist-coding-system (if (and (featurep 'xemacs) | |
134 | (<= emacs-major-version 21) | |
135 | (< emacs-minor-version 5)) | |
7619d43b | 136 | 'iso-2022-8 'utf-8-unix) |
fdcfd745 | 137 | "The coding system Savehist uses for saving the minibuffer history. |
216ee1a4 SM |
138 | Changing this value while Emacs is running is supported, but considered |
139 | unwise, unless you know what you are doing.") | |
140 | ||
141 | ;; Internal variables. | |
142 | ||
143 | (defvar savehist-timer nil) | |
144 | ||
145 | (defvar savehist-last-checksum nil) | |
146 | ||
b91f17dc SM |
147 | (defvar savehist-minibuffer-history-variables nil |
148 | "List of minibuffer histories. | |
149 | The contents of this variable is built while Emacs is running, and saved | |
150 | along with minibuffer history. You can change its value off | |
151 | `savehist-save-hook' to influence which variables are saved.") | |
2a2b5b29 | 152 | |
ed5a258a SM |
153 | (defconst savehist-no-conversion (if (featurep 'xemacs) 'binary 'no-conversion) |
154 | "Coding system without any conversion. | |
155 | This is used for calculating an internal checksum. Should be as fast | |
156 | as possible, ideally simply exposing the internal representation of | |
157 | buffer text.") | |
b91f17dc | 158 | |
ed5a258a SM |
159 | (defvar savehist-loaded nil |
160 | "Whether the history has already been loaded. | |
fdcfd745 | 161 | This prevents toggling Savehist mode from destroying existing |
ed5a258a | 162 | minibuffer history.") |
b91f17dc | 163 | |
2d10b62b SM |
164 | (when (featurep 'xemacs) |
165 | ;; Must declare this under XEmacs, which doesn't have built-in | |
166 | ;; minibuffer history truncation. | |
167 | (defvar history-length 100)) | |
cb23c7c1 | 168 | \f |
2a2b5b29 SM |
169 | ;; Functions. |
170 | ||
b91f17dc | 171 | ;;;###autoload |
56eb0904 | 172 | (define-minor-mode savehist-mode |
06e21633 CY |
173 | "Toggle saving of minibuffer history (Savehist mode). |
174 | With a prefix argument ARG, enable Savehist mode if ARG is | |
175 | positive, and disable it otherwise. If called from Lisp, enable | |
176 | the mode if ARG is omitted or nil. | |
177 | ||
178 | When Savehist mode is enabled, minibuffer history is saved | |
179 | periodically and when exiting Emacs. When Savehist mode is | |
180 | enabled for the first time in an Emacs session, it loads the | |
181 | previous minibuffer history from `savehist-file'. | |
b91f17dc SM |
182 | |
183 | This mode should normally be turned on from your Emacs init file. | |
06e21633 CY |
184 | Calling it at any other time replaces your current minibuffer |
185 | histories, which is probably undesirable." | |
56eb0904 | 186 | :global t |
b91f17dc SM |
187 | (if (not savehist-mode) |
188 | (savehist-uninstall) | |
189 | (when (and (not savehist-loaded) | |
190 | (file-exists-p savehist-file)) | |
191 | (condition-case errvar | |
192 | (progn | |
193 | ;; Don't set coding-system-for-read -- we rely on the | |
194 | ;; coding cookie to convey that information. That way, if | |
195 | ;; the user changes the value of savehist-coding-system, | |
196 | ;; we can still correctly load the old file. | |
32226619 | 197 | (load savehist-file nil (not (called-interactively-p 'interactive))) |
b91f17dc SM |
198 | (setq savehist-loaded t)) |
199 | (error | |
200 | ;; Don't install the mode if reading failed. Doing so would | |
201 | ;; effectively destroy the user's data at the next save. | |
202 | (setq savehist-mode nil) | |
203 | (savehist-uninstall) | |
204 | (signal (car errvar) (cdr errvar))))) | |
56eb0904 | 205 | (savehist-install))) |
b91f17dc SM |
206 | |
207 | (defun savehist-load () | |
fdcfd745 | 208 | "Load the variables stored in `savehist-file' and turn on Savehist mode. |
b59d7b84 JB |
209 | If `savehist-file' is in the old format that doesn't record |
210 | the value of `savehist-minibuffer-history-variables', that | |
211 | value is deducted from the contents of the file." | |
59f7af81 | 212 | (declare (obsolete savehist-mode "22.1")) |
b91f17dc SM |
213 | (savehist-mode 1) |
214 | ;; Old versions of savehist distributed with XEmacs didn't save | |
215 | ;; savehist-minibuffer-history-variables. If that variable is nil | |
216 | ;; after loading the file, try to intuit the intended value. | |
217 | (when (null savehist-minibuffer-history-variables) | |
218 | (setq savehist-minibuffer-history-variables | |
219 | (with-temp-buffer | |
220 | (ignore-errors | |
221 | (insert-file-contents savehist-file)) | |
222 | (let ((vars ()) form) | |
223 | (while (setq form (condition-case nil | |
224 | (read (current-buffer)) (error nil))) | |
225 | ;; Each form read is of the form (setq VAR VALUE). | |
226 | ;; Collect VAR, i.e. (nth form 1). | |
227 | (push (nth 1 form) vars)) | |
228 | vars))))) | |
b91f17dc | 229 | |
2a2b5b29 | 230 | (defun savehist-install () |
fdcfd745 | 231 | "Hook Savehist into Emacs. |
b91f17dc | 232 | Normally invoked by calling `savehist-mode' to set the minor mode. |
d33544d3 JB |
233 | Installs `savehist-autosave' in `kill-emacs-hook' and on a timer. |
234 | To undo this, call `savehist-uninstall'." | |
2a2b5b29 SM |
235 | (add-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook) |
236 | (add-hook 'kill-emacs-hook 'savehist-autosave) | |
237 | ;; Install an invocation of savehist-autosave on a timer. This | |
238 | ;; should not cause noticeable delays for users -- savehist-autosave | |
239 | ;; executes in under 5 ms on my system. | |
b91f17dc SM |
240 | (when (and savehist-autosave-interval |
241 | (null savehist-timer)) | |
2a2b5b29 SM |
242 | (setq savehist-timer |
243 | (if (featurep 'xemacs) | |
244 | (start-itimer | |
245 | "savehist" 'savehist-autosave savehist-autosave-interval | |
246 | savehist-autosave-interval) | |
b91f17dc SM |
247 | (run-with-timer savehist-autosave-interval |
248 | savehist-autosave-interval 'savehist-autosave))))) | |
2a2b5b29 SM |
249 | |
250 | (defun savehist-uninstall () | |
b91f17dc SM |
251 | "Undo installing savehist. |
252 | Normally invoked by calling `savehist-mode' to unset the minor mode." | |
2a2b5b29 SM |
253 | (remove-hook 'minibuffer-setup-hook 'savehist-minibuffer-hook) |
254 | (remove-hook 'kill-emacs-hook 'savehist-autosave) | |
255 | (when savehist-timer | |
256 | (if (featurep 'xemacs) | |
257 | (delete-itimer savehist-timer) | |
258 | (cancel-timer savehist-timer)) | |
259 | (setq savehist-timer nil))) | |
cb23c7c1 | 260 | |
06b60517 JB |
261 | ;; From XEmacs? |
262 | (defvar print-readably) | |
263 | (defvar print-string-length) | |
264 | ||
216ee1a4 | 265 | (defun savehist-save (&optional auto-save) |
2a2b5b29 SM |
266 | "Save the values of minibuffer history variables. |
267 | Unbound symbols referenced in `savehist-additional-variables' are ignored. | |
216ee1a4 SM |
268 | If AUTO-SAVE is non-nil, compare the saved contents to the one last saved, |
269 | and don't save the buffer if they are the same." | |
cb23c7c1 | 270 | (interactive) |
216ee1a4 SM |
271 | (with-temp-buffer |
272 | (insert | |
273 | (format ";; -*- mode: emacs-lisp; coding: %s -*-\n" savehist-coding-system) | |
274 | ";; Minibuffer history file, automatically generated by `savehist'.\n\n") | |
b91f17dc | 275 | (run-hooks 'savehist-save-hook) |
216ee1a4 SM |
276 | (let ((print-length nil) |
277 | (print-string-length nil) | |
278 | (print-level nil) | |
279 | (print-readably t) | |
b91f17dc SM |
280 | (print-quoted t)) |
281 | ;; Save the minibuffer histories, along with the value of | |
282 | ;; savehist-minibuffer-history-variables itself. | |
283 | (when savehist-save-minibuffer-history | |
284 | (prin1 `(setq savehist-minibuffer-history-variables | |
285 | ',savehist-minibuffer-history-variables) | |
286 | (current-buffer)) | |
287 | (insert ?\n) | |
288 | (dolist (symbol savehist-minibuffer-history-variables) | |
e2295672 RS |
289 | (when (and (boundp symbol) |
290 | (not (memq symbol savehist-ignored-variables))) | |
648db50d RS |
291 | (let ((value (savehist-trim-history (symbol-value symbol))) |
292 | excess-space) | |
293 | (when value ; Don't save empty histories. | |
294 | (insert "(setq ") | |
295 | (prin1 symbol (current-buffer)) | |
296 | (insert " '(") | |
297 | ;; We will print an extra space before the first element. | |
298 | ;; Record where that is. | |
299 | (setq excess-space (point)) | |
300 | ;; Print elements of VALUE one by one, carefully. | |
301 | (dolist (elt value) | |
302 | (let ((start (point))) | |
303 | (insert " ") | |
14c8159c | 304 | ;; Try to print and then to read an element. |
648db50d | 305 | (condition-case nil |
926558fb GM |
306 | (progn |
307 | (prin1 elt (current-buffer)) | |
308 | (save-excursion | |
309 | (goto-char start) | |
310 | (read (current-buffer)))) | |
648db50d | 311 | (error |
14c8159c | 312 | ;; If writing or reading gave an error, comment it out. |
648db50d RS |
313 | (goto-char start) |
314 | (insert "\n") | |
315 | (while (not (eobp)) | |
316 | (insert ";;; ") | |
317 | (forward-line 1)) | |
318 | (insert "\n"))) | |
319 | (goto-char (point-max)))) | |
320 | ;; Delete the extra space before the first element. | |
321 | (save-excursion | |
322 | (goto-char excess-space) | |
323 | (if (eq (following-char) ?\s) | |
324 | (delete-region (point) (1+ (point))))) | |
325 | (insert "))\n")))))) | |
b91f17dc SM |
326 | ;; Save the additional variables. |
327 | (dolist (symbol savehist-additional-variables) | |
328 | (when (boundp symbol) | |
329 | (let ((value (symbol-value symbol))) | |
330 | (when (savehist-printable value) | |
331 | (prin1 `(setq ,symbol ',value) (current-buffer)) | |
332 | (insert ?\n)))))) | |
216ee1a4 SM |
333 | ;; If autosaving, avoid writing if nothing has changed since the |
334 | ;; last write. | |
335 | (let ((checksum (md5 (current-buffer) nil nil savehist-no-conversion))) | |
336 | (unless (and auto-save (equal checksum savehist-last-checksum)) | |
337 | ;; Set file-precious-flag when saving the buffer because we | |
338 | ;; don't want a half-finished write ruining the entire | |
2a2b5b29 SM |
339 | ;; history. Remember that this is run from a timer and from |
340 | ;; kill-emacs-hook, and also that multiple Emacs instances | |
341 | ;; could write to this file at once. | |
216ee1a4 SM |
342 | (let ((file-precious-flag t) |
343 | (coding-system-for-write savehist-coding-system)) | |
344 | (write-region (point-min) (point-max) savehist-file nil | |
32226619 | 345 | (unless (called-interactively-p 'interactive) 'quiet))) |
b91f17dc SM |
346 | (when savehist-file-modes |
347 | (set-file-modes savehist-file savehist-file-modes)) | |
216ee1a4 SM |
348 | (setq savehist-last-checksum checksum))))) |
349 | ||
350 | (defun savehist-autosave () | |
b91f17dc | 351 | "Save the minibuffer history if it has been modified since the last save. |
fdcfd745 | 352 | Does nothing if Savehist mode is off." |
b91f17dc SM |
353 | (when savehist-mode |
354 | (savehist-save t))) | |
355 | ||
356 | (defun savehist-trim-history (value) | |
d33544d3 | 357 | "Retain only the first `history-length' items in VALUE. |
ed5a258a | 358 | Only used under XEmacs, which doesn't (yet) implement automatic |
d33544d3 | 359 | trimming of history lists to `history-length' items." |
b91f17dc SM |
360 | (if (and (featurep 'xemacs) |
361 | (natnump history-length) | |
362 | (> (length value) history-length)) | |
363 | ;; Equivalent to `(subseq value 0 history-length)', but doesn't | |
364 | ;; need cl-extra at run-time. | |
365 | (loop repeat history-length collect (pop value)) | |
366 | value)) | |
216ee1a4 SM |
367 | |
368 | (defun savehist-printable (value) | |
3930b7e4 | 369 | "Return non-nil if VALUE is printable." |
216ee1a4 | 370 | (cond |
b91f17dc | 371 | ;; Quick response for oft-encountered types known to be printable. |
216ee1a4 SM |
372 | ((numberp value)) |
373 | ((symbolp value)) | |
95d5e396 LL |
374 | ;; String without properties |
375 | ((and (stringp value) | |
376 | (equal-including-properties value (substring-no-properties value)))) | |
216ee1a4 SM |
377 | (t |
378 | ;; For others, check explicitly. | |
b91f17dc SM |
379 | (with-temp-buffer |
380 | (condition-case nil | |
381 | (let ((print-readably t) (print-level nil)) | |
382 | ;; Print the value into a buffer... | |
383 | (prin1 value (current-buffer)) | |
216ee1a4 | 384 | ;; ...and attempt to read it. |
b91f17dc | 385 | (read (point-min-marker)) |
216ee1a4 SM |
386 | ;; The attempt worked: the object is printable. |
387 | t) | |
b91f17dc SM |
388 | ;; The attempt failed: the object is not printable. |
389 | (error nil)))))) | |
cb23c7c1 | 390 | |
2a2b5b29 | 391 | (defun savehist-minibuffer-hook () |
cd4160e6 RS |
392 | (unless (or (eq minibuffer-history-variable t) |
393 | ;; XEmacs sets minibuffer-history-variable to t to mean "no | |
394 | ;; history is being recorded". | |
395 | (memq minibuffer-history-variable savehist-ignored-variables)) | |
2d10b62b SM |
396 | (add-to-list 'savehist-minibuffer-history-variables |
397 | minibuffer-history-variable))) | |
2a2b5b29 | 398 | |
cb23c7c1 | 399 | (provide 'savehist) |
b91f17dc | 400 | \f |
b91f17dc | 401 | |
cb23c7c1 | 402 | ;;; savehist.el ends here |