(get_boot_time): Don't use BUFSIZ.
[bpt/emacs.git] / lisp / midnight.el
CommitLineData
ac06bd0f
RS
1;;; midnight.el --- run something every midnight, e.g., kill old buffers.
2
3;;; Copyright (C) 1998 Free Software Foundation, Inc.
4
5;;; Author: Sam Steingold <sds@usa.net>
6;;; Maintainer: Sam Steingold <sds@usa.net>
7;;; Created: 1998-05-18
8;;; Keywords: utilities
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
6d9d01a9 51(defcustom midnight-mode nil
e9d7cff0
RS
52 "*Non-nil means run `midnight-hook' at midnight.
53Setting this variable outside customize has no effect;
54call `cancel-timer' or `timer-activate' on `midnight-timer' instead."
55 :type 'boolean
56 :group 'midnight
57 :require 'midnight
6d9d01a9 58 :initialize 'custom-initialize-default
e9d7cff0
RS
59 :set (lambda (symb val)
60 (set symb val) (require 'midnight)
61 (if val (timer-activate midnight-timer)
62 (cancel-timer midnight-timer))))
63
ac06bd0f
RS
64;;; time conversion
65
6d9d01a9 66(defun midnight-float-time (&optional tm)
ac06bd0f
RS
67 "Convert `current-time' to a float number of seconds."
68 (multiple-value-bind (s0 s1 s2) (or tm (current-time))
69 (+ (* (float (ash 1 16)) s0) (float s1) (* 0.0000001 s2))))
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
RS
78 "Return the time-stamp of the given buffer, or current buffer, as float."
79 (save-excursion
80 (set-buffer (or buf (current-buffer)))
6d9d01a9 81 (when buffer-display-time (midnight-float-time buffer-display-time))))
ac06bd0f
RS
82
83;;; clean-buffer-list stuff
84
85(defcustom clean-buffer-list-delay-general 3
86 "*The number of days before any buffer becomes eligible for autokilling.
87The autokilling is done by `clean-buffer-list' when is it in `midnight-hook'.
88Currently displayed and/or modified (unsaved) buffers, as well as buffers
89matching `clean-buffer-list-kill-never-buffer-names' and
90`clean-buffer-list-kill-never-regexps' are excluded."
91 :type 'integer
1e484d64 92 :group 'midnight)
ac06bd0f
RS
93
94(defcustom clean-buffer-list-delay-special 3600
95 "*The number of seconds before some buffers become eligible for autokilling.
96Buffers matched by `clean-buffer-list-kill-regexps' and
97`clean-buffer-list-kill-buffer-names' are killed if they were last
98displayed more than this many seconds ago."
99 :type 'integer
1e484d64 100 :group 'midnight)
ac06bd0f 101
b2f9ab3c 102(defcustom clean-buffer-list-kill-regexps nil
ac06bd0f
RS
103 "*List of regexps saying which buffers will be killed at midnight.
104If buffer name matches a regexp in the list and the buffer was not displayed
105in the last `clean-buffer-list-delay-special' seconds, it is killed by
106`clean-buffer-list' when is it in `midnight-hook'.
107If a member of the list is a cons, it's `car' is the regexp and its `cdr' is
108the number of seconds to use instead of `clean-buffer-list-delay-special'.
109See also `clean-buffer-list-kill-buffer-names',
110`clean-buffer-list-kill-never-regexps' and
111`clean-buffer-list-kill-never-buffer-names'."
1e5a4438 112 :type '(repeat (regexp :tag "Regexp matching Buffer Name"))
1e484d64 113 :group 'midnight)
ac06bd0f
RS
114
115(defcustom clean-buffer-list-kill-buffer-names
b2f9ab3c 116 '("*Help*" "*Apropos*" "*Man " "*Buffer List*" "*Compile-Log*" "*info*"
9cc077f6 117 "*vc*" "*vc-diff*" "*diff*")
ac06bd0f
RS
118 "*List of strings saying which buffers will be killed at midnight.
119Buffers with names in this list, which were not displayed in the last
120`clean-buffer-list-delay-special' seconds, are killed by `clean-buffer-list'
121when is it in `midnight-hook'.
122If a member of the list is a cons, it's `car' is the name and its `cdr' is
123the number of seconds to use instead of `clean-buffer-list-delay-special'.
124See also `clean-buffer-list-kill-regexps',
125`clean-buffer-list-kill-never-regexps' and
126`clean-buffer-list-kill-never-buffer-names'."
1e5a4438 127 :type '(repeat (string :tag "Buffer Name"))
1e484d64 128 :group 'midnight)
ac06bd0f
RS
129
130(defcustom clean-buffer-list-kill-never-buffer-names
131 '("*scratch*" "*Messages*")
132 "*List of buffer names which will never be killed by `clean-buffer-list'.
133See also `clean-buffer-list-kill-never-regexps'.
134Note that this does override `clean-buffer-list-kill-regexps' and
135`clean-buffer-list-kill-buffer-names' so a buffer matching any of these
136two lists will NOT be killed if it is also present in this list."
1e5a4438 137 :type '(repeat (string :tag "Buffer Name"))
1e484d64
DN
138 :group 'midnight)
139
ac06bd0f
RS
140
141(defcustom clean-buffer-list-kill-never-regexps '("^ \*Minibuf-.*\*$")
142 "*List of regexp saying which buffers will never be killed at midnight.
143See also `clean-buffer-list-kill-never-buffer-names'.
144Killing is done by `clean-buffer-list'.
145Note that this does override `clean-buffer-list-kill-regexps' and
146`clean-buffer-list-kill-buffer-names' so a buffer matching any of these
147two lists will NOT be killed if it also matches anything in this list."
1e5a4438 148 :type '(repeat (regexp :tag "Regexp matching Buffer Name"))
1e484d64 149 :group 'midnight)
ac06bd0f
RS
150
151(defun midnight-find (el ls test &optional key)
152 "A stopgap solution to the absence of `find' in ELisp."
9cc077f6
RS
153 (dolist (rr ls)
154 (when (funcall test el (if key (funcall key rr) rr))
155 (return rr))))
849ac835 156
b2f9ab3c
RS
157(defun clean-buffer-list-delay (name)
158 "Return the delay, in seconds, before killing a buffer named NAME.
ac06bd0f
RS
159Uses `clean-buffer-list-kill-buffer-names', `clean-buffer-list-kill-regexps'
160`clean-buffer-list-delay-general' and `clean-buffer-list-delay-special'.
161Autokilling is done by `clean-buffer-list'."
b2f9ab3c 162 (or (assoc-default name clean-buffer-list-kill-buffer-names 'string=
849ac835 163 clean-buffer-list-delay-special)
b2f9ab3c 164 (assoc-default name clean-buffer-list-kill-regexps 'string-match
849ac835
RS
165 clean-buffer-list-delay-special)
166 (* clean-buffer-list-delay-general 24 60 60)))
ac06bd0f 167
80252f73 168;;;###autoload
ac06bd0f 169(defun clean-buffer-list ()
b2f9ab3c 170 "Kill old buffers that have not been displayed recently.
9cc077f6 171The relevant variables are `clean-buffer-list-delay-general',
ac06bd0f
RS
172`clean-buffer-list-delay-special', `clean-buffer-list-kill-buffer-names',
173`clean-buffer-list-kill-never-buffer-names',
9cc077f6
RS
174`clean-buffer-list-kill-regexps' and
175`clean-buffer-list-kill-never-regexps'.
176While processing buffers, this procedure displays messages containing
177the current date/time, buffer name, how many seconds ago it was
82f08756
RS
178displayed (can be nil if the buffer was never displayed) and its
179lifetime, i.e., its \"age\" when it will be purged."
ac06bd0f 180 (interactive)
83bc1919
KH
181 (let ((tm (midnight-float-time)) bts (ts (format-time-string "%Y-%m-%d %T"))
182 (bufs (buffer-list)) buf delay cbld bn)
9cc077f6 183 (while (setq buf (pop bufs))
6d9d01a9 184 (setq bts (midnight-buffer-display-time buf) bn (buffer-name buf)
9cc077f6
RS
185 delay (if bts (- tm bts) 0) cbld (clean-buffer-list-delay bn))
186 (message "[%s] `%s' [%s %d]" ts bn (if bts (round delay)) cbld)
849ac835 187 (unless (or (midnight-find bn clean-buffer-list-kill-never-regexps
ac06bd0f
RS
188 'string-match)
189 (midnight-find bn clean-buffer-list-kill-never-buffer-names
190 'string-equal)
83bc1919 191 (get-buffer-process buf)
9cc077f6
RS
192 (and (buffer-file-name buf) (buffer-modified-p buf))
193 (get-buffer-window buf 'visible) (< delay cbld))
ac06bd0f
RS
194 (message "[%s] killing `%s'" ts bn)
195 (kill-buffer buf)))))
196
197;;; midnight hook
198
199(defvar midnight-period (* 24 60 60)
b2f9ab3c 200 "The number of seconds in a day--the delta for `midnight-timer'.")
ac06bd0f 201
82f08756 202(defcustom midnight-hook '(clean-buffer-list)
ac06bd0f
RS
203 "The hook run `midnight-delay' seconds after midnight every day.
204The default value is `clean-buffer-list'."
205 :type 'hook
1e484d64 206 :group 'midnight)
ac06bd0f
RS
207
208(defun midnight-next ()
209 "Return the number of seconds till the next midnight."
210 (multiple-value-bind (sec min hrs) (decode-time)
211 (- (* 24 60 60) (* 60 60 hrs) (* 60 min) sec)))
212
213(defvar midnight-timer nil
214 "Timer running the `midnight-hook' `midnight-delay' seconds after midnight.
215Use `cancel-timer' to stop it and `midnight-delay-set' to change
216the time when it is run.")
217
218;;;###autoload
219(defun midnight-delay-set (symb tm)
220 "Modify `midnight-timer' according to `midnight-delay'.
9cc077f6
RS
221Sets the first argument SYMB (which must be symbol `midnight-delay')
222to its second argument TM."
223 (assert (eq symb 'midnight-delay) t
224 "Illegal argument to `midnight-delay-set': `%s'" symb)
ac06bd0f
RS
225 (set symb tm)
226 (when (timerp midnight-timer) (cancel-timer midnight-timer))
227 (setq midnight-timer
228 (run-at-time (if (numberp tm) (+ (midnight-next) tm) tm)
cef7e1da 229 midnight-period 'run-hooks 'midnight-hook)))
ac06bd0f
RS
230
231(defcustom midnight-delay 3600
232 "*The number of seconds after the midnight when the `midnight-timer' is run.
233You should set this variable before loading midnight.el, or
234set it by calling `midnight-delay-set', or use `custom'.
235If you wish, you can use a string instead, it will be passed as the
236first argument to `run-at-time'."
237 :type 'sexp
238 :set 'midnight-delay-set
1e484d64 239 :group 'midnight)
ac06bd0f
RS
240
241(provide 'midnight)
242
243;;; midnight.el ends here