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