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