Update FSF's address.
[bpt/emacs.git] / lisp / midnight.el
CommitLineData
60370d40 1;;; midnight.el --- run something every midnight, e.g., kill old buffers
ac06bd0f 2
320cb80d 3;;; Copyright (C) 1998, 2004, 2005 Free Software Foundation, Inc.
ac06bd0f 4
60370d40
PJ
5;; Author: Sam Steingold <sds@usa.net>
6;; Maintainer: Sam Steingold <sds@usa.net>
7;; Created: 1998-05-18
8;; Keywords: utilities
ac06bd0f
RS
9
10;; This file is part of GNU Emacs.
11
12;; GNU Emacs is free software; you can redistribute it and/or modify
13;; it under the terms of the GNU General Public License as published by
14;; the Free Software Foundation; either version 2, or (at your option)
15;; any later version.
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
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
26
27;;; Commentary:
28
29;; To use the file, put (require 'midnight) into your .emacs. Then, at
30;; midnight, Emacs will run the normal hook `midnight-hook'. You can
31;; put whatever you like there, say, `calendar'; by default there is
32;; only one function there - `clean-buffer-list'. It will kill the
33;; buffers matching `clean-buffer-list-kill-buffer-names' and
34;; `clean-buffer-list-kill-regexps' and the buffers which where last
35;; displayed more than `clean-buffer-list-delay-general' days ago,
36;; keeping `clean-buffer-list-kill-never-buffer-names' and
37;; `clean-buffer-list-kill-never-regexps'.
38
9cc077f6
RS
39;;; Code:
40
849ac835 41(eval-when-compile
51eb1909
KH
42 (require 'cl))
43
44(require 'timer)
ac06bd0f
RS
45
46(defgroup midnight nil
47 "Run something every day at midnight."
1e484d64
DN
48 :group 'calendar
49 :version "20.3")
ac06bd0f 50
ed4761a9
RS
51(defvar midnight-timer nil
52 "Timer running the `midnight-hook' `midnight-delay' seconds after midnight.
53Use `cancel-timer' to stop it and `midnight-delay-set' to change
54the time when it is run.")
55
6d9d01a9 56(defcustom midnight-mode nil
e9d7cff0
RS
57 "*Non-nil means run `midnight-hook' at midnight.
58Setting this variable outside customize has no effect;
59call `cancel-timer' or `timer-activate' on `midnight-timer' instead."
60 :type 'boolean
61 :group 'midnight
62 :require 'midnight
6d9d01a9 63 :initialize 'custom-initialize-default
e9d7cff0
RS
64 :set (lambda (symb val)
65 (set symb val) (require 'midnight)
66 (if val (timer-activate midnight-timer)
67 (cancel-timer midnight-timer))))
68
ac06bd0f
RS
69;;; time conversion
70
6d9d01a9 71(defun midnight-time-float (num)
ac06bd0f
RS
72 "Convert the float number of seconds since epoch to the list of 3 integers."
73 (let* ((div (ash 1 16)) (1st (floor num div)))
74 (list 1st (floor (- num (* (float div) 1st)))
75 (round (* 10000000 (mod num 1))))))
76
6d9d01a9 77(defun midnight-buffer-display-time (&optional buf)
ac06bd0f 78 "Return the time-stamp of the given buffer, or current buffer, as float."
5044b74a 79 (with-current-buffer (or buf (current-buffer))
a1f84f6d 80 (when buffer-display-time (float-time buffer-display-time))))
ac06bd0f
RS
81
82;;; clean-buffer-list stuff
83
84(defcustom clean-buffer-list-delay-general 3
85 "*The number of days before any buffer becomes eligible for autokilling.
86The autokilling is done by `clean-buffer-list' when is it in `midnight-hook'.
87Currently displayed and/or modified (unsaved) buffers, as well as buffers
88matching `clean-buffer-list-kill-never-buffer-names' and
89`clean-buffer-list-kill-never-regexps' are excluded."
90 :type 'integer
1e484d64 91 :group 'midnight)
ac06bd0f
RS
92
93(defcustom clean-buffer-list-delay-special 3600
94 "*The number of seconds before some buffers become eligible for autokilling.
95Buffers matched by `clean-buffer-list-kill-regexps' and
96`clean-buffer-list-kill-buffer-names' are killed if they were last
97displayed more than this many seconds ago."
98 :type 'integer
1e484d64 99 :group 'midnight)
ac06bd0f 100
b2f9ab3c 101(defcustom clean-buffer-list-kill-regexps nil
ac06bd0f
RS
102 "*List of regexps saying which buffers will be killed at midnight.
103If buffer name matches a regexp in the list and the buffer was not displayed
104in the last `clean-buffer-list-delay-special' seconds, it is killed by
105`clean-buffer-list' when is it in `midnight-hook'.
f40c9c7b 106If a member of the list is a cons, its `car' is the regexp and its `cdr' is
ac06bd0f
RS
107the number of seconds to use instead of `clean-buffer-list-delay-special'.
108See also `clean-buffer-list-kill-buffer-names',
109`clean-buffer-list-kill-never-regexps' and
110`clean-buffer-list-kill-never-buffer-names'."
1e5a4438 111 :type '(repeat (regexp :tag "Regexp matching Buffer Name"))
1e484d64 112 :group 'midnight)
ac06bd0f
RS
113
114(defcustom clean-buffer-list-kill-buffer-names
b2f9ab3c 115 '("*Help*" "*Apropos*" "*Man " "*Buffer List*" "*Compile-Log*" "*info*"
9cc077f6 116 "*vc*" "*vc-diff*" "*diff*")
ac06bd0f
RS
117 "*List of strings saying which buffers will be killed at midnight.
118Buffers with names in this list, which were not displayed in the last
119`clean-buffer-list-delay-special' seconds, are killed by `clean-buffer-list'
120when is it in `midnight-hook'.
f40c9c7b 121If a member of the list is a cons, its `car' is the name and its `cdr' is
ac06bd0f
RS
122the number of seconds to use instead of `clean-buffer-list-delay-special'.
123See also `clean-buffer-list-kill-regexps',
124`clean-buffer-list-kill-never-regexps' and
125`clean-buffer-list-kill-never-buffer-names'."
1e5a4438 126 :type '(repeat (string :tag "Buffer Name"))
1e484d64 127 :group 'midnight)
ac06bd0f
RS
128
129(defcustom clean-buffer-list-kill-never-buffer-names
130 '("*scratch*" "*Messages*")
131 "*List of buffer names which will never be killed by `clean-buffer-list'.
132See also `clean-buffer-list-kill-never-regexps'.
133Note that this does override `clean-buffer-list-kill-regexps' and
134`clean-buffer-list-kill-buffer-names' so a buffer matching any of these
135two lists will NOT be killed if it is also present in this list."
1e5a4438 136 :type '(repeat (string :tag "Buffer Name"))
1e484d64
DN
137 :group 'midnight)
138
ac06bd0f 139
b3275b47 140(defcustom clean-buffer-list-kill-never-regexps '("^ \\*Minibuf-.*\\*$")
ac06bd0f
RS
141 "*List of regexp saying which buffers will never be killed at midnight.
142See also `clean-buffer-list-kill-never-buffer-names'.
143Killing is done by `clean-buffer-list'.
144Note that this does override `clean-buffer-list-kill-regexps' and
145`clean-buffer-list-kill-buffer-names' so a buffer matching any of these
146two lists will NOT be killed if it also matches anything in this list."
1e5a4438 147 :type '(repeat (regexp :tag "Regexp matching Buffer Name"))
1e484d64 148 :group 'midnight)
ac06bd0f
RS
149
150(defun midnight-find (el ls test &optional key)
151 "A stopgap solution to the absence of `find' in ELisp."
9cc077f6 152 (dolist (rr ls)
b3275b47 153 (when (funcall test (if key (funcall key rr) rr) el)
9cc077f6 154 (return rr))))
849ac835 155
b2f9ab3c
RS
156(defun clean-buffer-list-delay (name)
157 "Return the delay, in seconds, before killing a buffer named NAME.
ac06bd0f
RS
158Uses `clean-buffer-list-kill-buffer-names', `clean-buffer-list-kill-regexps'
159`clean-buffer-list-delay-general' and `clean-buffer-list-delay-special'.
160Autokilling is done by `clean-buffer-list'."
b2f9ab3c 161 (or (assoc-default name clean-buffer-list-kill-buffer-names 'string=
849ac835 162 clean-buffer-list-delay-special)
b2f9ab3c 163 (assoc-default name clean-buffer-list-kill-regexps 'string-match
849ac835
RS
164 clean-buffer-list-delay-special)
165 (* clean-buffer-list-delay-general 24 60 60)))
ac06bd0f 166
80252f73 167;;;###autoload
ac06bd0f 168(defun clean-buffer-list ()
b2f9ab3c 169 "Kill old buffers that have not been displayed recently.
9cc077f6 170The relevant variables are `clean-buffer-list-delay-general',
ac06bd0f
RS
171`clean-buffer-list-delay-special', `clean-buffer-list-kill-buffer-names',
172`clean-buffer-list-kill-never-buffer-names',
9cc077f6
RS
173`clean-buffer-list-kill-regexps' and
174`clean-buffer-list-kill-never-regexps'.
175While processing buffers, this procedure displays messages containing
176the current date/time, buffer name, how many seconds ago it was
82f08756
RS
177displayed (can be nil if the buffer was never displayed) and its
178lifetime, i.e., its \"age\" when it will be purged."
ac06bd0f 179 (interactive)
a1f84f6d 180 (let ((tm (float-time)) bts (ts (format-time-string "%Y-%m-%d %T"))
83bc1919 181 (bufs (buffer-list)) buf delay cbld bn)
9cc077f6 182 (while (setq buf (pop bufs))
6d9d01a9 183 (setq bts (midnight-buffer-display-time buf) bn (buffer-name buf)
9cc077f6
RS
184 delay (if bts (- tm bts) 0) cbld (clean-buffer-list-delay bn))
185 (message "[%s] `%s' [%s %d]" ts bn (if bts (round delay)) cbld)
849ac835 186 (unless (or (midnight-find bn clean-buffer-list-kill-never-regexps
ac06bd0f
RS
187 'string-match)
188 (midnight-find bn clean-buffer-list-kill-never-buffer-names
189 'string-equal)
83bc1919 190 (get-buffer-process buf)
9cc077f6
RS
191 (and (buffer-file-name buf) (buffer-modified-p buf))
192 (get-buffer-window buf 'visible) (< delay cbld))
ac06bd0f
RS
193 (message "[%s] killing `%s'" ts bn)
194 (kill-buffer buf)))))
195
196;;; midnight hook
197
198(defvar midnight-period (* 24 60 60)
b2f9ab3c 199 "The number of seconds in a day--the delta for `midnight-timer'.")
ac06bd0f 200
82f08756 201(defcustom midnight-hook '(clean-buffer-list)
ac06bd0f
RS
202 "The hook run `midnight-delay' seconds after midnight every day.
203The default value is `clean-buffer-list'."
204 :type 'hook
1e484d64 205 :group 'midnight)
ac06bd0f
RS
206
207(defun midnight-next ()
208 "Return the number of seconds till the next midnight."
209 (multiple-value-bind (sec min hrs) (decode-time)
210 (- (* 24 60 60) (* 60 60 hrs) (* 60 min) sec)))
211
ac06bd0f
RS
212;;;###autoload
213(defun midnight-delay-set (symb tm)
214 "Modify `midnight-timer' according to `midnight-delay'.
9cc077f6
RS
215Sets the first argument SYMB (which must be symbol `midnight-delay')
216to its second argument TM."
217 (assert (eq symb 'midnight-delay) t
320cb80d 218 "Invalid argument to `midnight-delay-set': `%s'")
ac06bd0f
RS
219 (set symb tm)
220 (when (timerp midnight-timer) (cancel-timer midnight-timer))
221 (setq midnight-timer
222 (run-at-time (if (numberp tm) (+ (midnight-next) tm) tm)
cef7e1da 223 midnight-period 'run-hooks 'midnight-hook)))
ac06bd0f
RS
224
225(defcustom midnight-delay 3600
226 "*The number of seconds after the midnight when the `midnight-timer' is run.
227You should set this variable before loading midnight.el, or
228set it by calling `midnight-delay-set', or use `custom'.
229If you wish, you can use a string instead, it will be passed as the
230first argument to `run-at-time'."
231 :type 'sexp
232 :set 'midnight-delay-set
1e484d64 233 :group 'midnight)
ac06bd0f
RS
234
235(provide 'midnight)
236
ab5796a9 237;;; arch-tag: a5979be9-2890-46a3-ba84-791f0a4a6e80
ac06bd0f 238;;; midnight.el ends here