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