Mercurial > emacs
comparison lisp/calendar/appt.el @ 89909:68c22ea6027c
Sync to HEAD
author | Kenichi Handa <handa@m17n.org> |
---|---|
date | Fri, 16 Apr 2004 12:51:06 +0000 |
parents | 375f2633d815 |
children | 4c90ffeb71c5 |
comparison
equal
deleted
inserted
replaced
89908:ee1402f7b568 | 89909:68c22ea6027c |
---|---|
1 ;;; appt.el --- appointment notification functions | 1 ;;; appt.el --- appointment notification functions |
2 | 2 |
3 ;; Copyright (C) 1989, 1990, 1994, 1998 Free Software Foundation, Inc. | 3 ;; Copyright (C) 1989, 1990, 1994, 1998, 2004 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Neil Mager <neilm@juliet.ll.mit.edu> | 5 ;; Author: Neil Mager <neilm@juliet.ll.mit.edu> |
6 ;; Maintainer: FSF | 6 ;; Maintainer: FSF |
7 ;; Keywords: calendar | 7 ;; Keywords: calendar |
8 | 8 |
25 | 25 |
26 ;;; Commentary: | 26 ;;; Commentary: |
27 | 27 |
28 ;; | 28 ;; |
29 ;; appt.el - visible and/or audible notification of | 29 ;; appt.el - visible and/or audible notification of |
30 ;; appointments from ~/diary file. | 30 ;; appointments from diary file. |
31 ;; | 31 ;; |
32 ;;; | 32 ;;; |
33 ;;; Thanks to Edward M. Reingold for much help and many suggestions, | 33 ;;; Thanks to Edward M. Reingold for much help and many suggestions, |
34 ;;; And to many others for bug fixes and suggestions. | 34 ;;; And to many others for bug fixes and suggestions. |
35 ;;; | 35 ;;; |
36 ;;; | 36 ;;; |
37 ;;; This functions in this file will alert the user of a | 37 ;;; This functions in this file will alert the user of a |
38 ;;; pending appointment based on their diary file. | 38 ;;; pending appointment based on his/her diary file. This package |
39 ;;; | 39 ;;; is documented in the Emacs manual. |
40 ;;; A message will be displayed in the mode line of the Emacs buffer | 40 ;;; |
41 ;;; and (if you request) the terminal will beep and display a message | 41 ;;; To activate this package, simply use (appt-activate 1). |
42 ;;; from the diary in the mini-buffer, or you can choose to | 42 ;;; A `diary-file' with appointments of the format described in the |
43 ;;; have a message displayed in a new buffer. | 43 ;;; documentation of the function `appt-check' is required. |
44 ;;; | 44 ;;; Relevant customizable variables are also listed in the |
45 ;;; The variable `appt-message-warning-time' allows the | 45 ;;; documentation of that function. |
46 ;;; user to specify how much notice they want before the appointment. The | 46 ;;; |
47 ;;; variable `appt-issue-message' specifies whether the user wants | 47 ;;; Today's appointment list is initialized from the diary when this |
48 ;;; to be notified of a pending appointment. | 48 ;;; package is activated. Additionally, the appointments list is |
49 ;;; | 49 ;;; recreated automatically at 12:01am for those who do not logout |
50 ;;; In order to use the appt package, you only need | 50 ;;; every day or are programming late. It is also updated when the |
51 ;;; to load it---provided you have appointments. | 51 ;;; `diary-file' is saved. Calling `appt-check' with an argument forces |
52 ;;; | 52 ;;; a re-initialization at any time. |
53 ;;; Before that, you can also set some options if you want | 53 ;;; |
54 ;;; (setq view-diary-entries-initially t) | 54 ;;; In order to add or delete items from today's list, without |
55 ;;; (setq appt-issue-message t) | 55 ;;; changing the diary file, use `appt-add' and `appt-delete'. |
56 ;;; | 56 ;;; |
57 ;;; This is an example of what can be in your diary file: | 57 |
58 ;;; Monday | |
59 ;;; 9:30am Coffee break | |
60 ;;; 12:00pm Lunch | |
61 ;;; | |
62 ;;; Based upon the above lines in your .emacs and diary files, | |
63 ;;; the calendar and diary will be displayed when you enter | |
64 ;;; Emacs and your appointments list will automatically be created. | |
65 ;;; You will then be reminded at 9:20am about your coffee break | |
66 ;;; and at 11:50am to go to lunch. | |
67 ;;; | |
68 ;;; Use describe-function on appt-check for a description of other variables | |
69 ;;; that can be used to personalize the notification system. | |
70 ;;; | |
71 ;;; In order to add or delete items from todays list, use appt-add | |
72 ;;; and appt-delete. | |
73 ;;; | |
74 ;;; Additionally, the appointments list is recreated automatically | |
75 ;;; at 12:01am for those who do not logout every day or are programming | |
76 ;;; late. | |
77 ;;; | |
78 ;;; Brief internal description - Skip this if you are not interested! | 58 ;;; Brief internal description - Skip this if you are not interested! |
79 ;;; | 59 ;;; |
80 ;;; The function appt-make-list creates the appointments list which appt-check | 60 ;;; The function `appt-make-list' creates the appointments list which |
81 ;;; reads. This is all done automatically. | 61 ;;; `appt-check' reads. |
82 ;;; It is invoked from the function list-diary-entries. | |
83 ;;; | 62 ;;; |
84 ;;; You can change the way the appointment window is created/deleted by | 63 ;;; You can change the way the appointment window is created/deleted by |
85 ;;; setting the variables | 64 ;;; setting the variables |
86 ;;; | 65 ;;; |
87 ;;; appt-disp-window-function | 66 ;;; appt-disp-window-function |
88 ;;; and | 67 ;;; and |
89 ;;; appt-delete-window-function | 68 ;;; appt-delete-window-function |
90 ;;; | 69 ;;; |
91 ;;; For instance, these variables can be set to functions that display | 70 ;;; For instance, these variables could be set to functions that display |
92 ;;; appointments in pop-up frames, which are lowered or iconified after | 71 ;;; appointments in pop-up frames, which are lowered or iconified after |
93 ;;; appt-display-interval minutes. | 72 ;;; `appt-display-interval' minutes. |
94 ;;; | 73 ;;; |
95 | 74 |
96 ;;; Code: | 75 ;;; Code: |
97 | 76 |
98 ;; Make sure calendar is loaded when we compile this. | 77 ;; Make sure calendar is loaded when we compile this. |
99 (require 'calendar) | 78 (require 'calendar) |
100 | 79 |
101 (provide 'appt) | |
102 | 80 |
103 ;;;###autoload | 81 ;;;###autoload |
104 (defcustom appt-issue-message t | 82 (defcustom appt-issue-message t |
105 "*Non-nil means check for appointments in the diary buffer. | 83 "*Non-nil means check for appointments in the diary buffer. |
106 To be detected, the diary entry must have the time | 84 To be detected, the diary entry must have the format described in the |
107 as the first thing on a line." | 85 documentation of the function `appt-check'." |
108 :type 'boolean | 86 :type 'boolean |
109 :group 'appt) | 87 :group 'appt) |
88 | |
89 (make-obsolete-variable 'appt-issue-message | |
90 "use the function `appt-activate', and the \ | |
91 variable `appt-display-format' instead." "21.4") | |
110 | 92 |
111 ;;;###autoload | 93 ;;;###autoload |
112 (defcustom appt-message-warning-time 12 | 94 (defcustom appt-message-warning-time 12 |
113 "*Time in minutes before an appointment that the warning begins." | 95 "*Time in minutes before an appointment that the warning begins." |
114 :type 'integer | 96 :type 'integer |
120 :type 'boolean | 102 :type 'boolean |
121 :group 'appt) | 103 :group 'appt) |
122 | 104 |
123 ;;;###autoload | 105 ;;;###autoload |
124 (defcustom appt-visible t | 106 (defcustom appt-visible t |
125 "*Non-nil means display appointment message in echo area." | 107 "*Non-nil means display appointment message in echo area. |
108 This variable is only relevant if `appt-msg-window' is nil." | |
126 :type 'boolean | 109 :type 'boolean |
127 :group 'appt) | 110 :group 'appt) |
128 | 111 |
112 (make-obsolete-variable 'appt-visible 'appt-display-format "21.4") | |
113 | |
114 ;;;###autoload | |
115 (defcustom appt-msg-window t | |
116 "*Non-nil means display appointment message in another window. | |
117 If non-nil, this variable overrides `appt-visible'." | |
118 :type 'boolean | |
119 :group 'appt) | |
120 | |
121 (make-obsolete-variable 'appt-msg-window 'appt-display-format "21.4") | |
122 | |
123 ;; TODO - add popup. | |
124 (defcustom appt-display-format 'ignore | |
125 "How appointment reminders should be displayed. | |
126 The options are: | |
127 window - use a separate window | |
128 echo - use the echo area | |
129 nil - no visible reminder. | |
130 See also `appt-audible' and `appt-display-mode-line'. | |
131 | |
132 The default value is 'ignore, which means to fall back on the value | |
133 of the (obsolete) variables `appt-msg-window' and `appt-visible'." | |
134 :type '(choice | |
135 (const :tag "Separate window" window) | |
136 (const :tag "Echo-area" echo) | |
137 (const :tag "No visible display" nil)) | |
138 :group 'appt | |
139 :version "21.4") | |
140 | |
129 ;;;###autoload | 141 ;;;###autoload |
130 (defcustom appt-display-mode-line t | 142 (defcustom appt-display-mode-line t |
131 "*Non-nil means display minutes to appointment and time on the mode line." | 143 "*Non-nil means display minutes to appointment and time on the mode line. |
144 This is in addition to any other display of appointment messages." | |
132 :type 'boolean | 145 :type 'boolean |
133 :group 'appt) | 146 :group 'appt) |
134 | 147 |
135 ;;;###autoload | 148 ;;;###autoload |
136 (defcustom appt-msg-window t | |
137 "*Non-nil means display appointment message in another window." | |
138 :type 'boolean | |
139 :group 'appt) | |
140 | |
141 ;;;###autoload | |
142 (defcustom appt-display-duration 10 | 149 (defcustom appt-display-duration 10 |
143 "*The number of seconds an appointment message is displayed." | 150 "*The number of seconds an appointment message is displayed. |
151 Only relevant if reminders are to be displayed in their own window." | |
144 :type 'integer | 152 :type 'integer |
145 :group 'appt) | 153 :group 'appt) |
146 | 154 |
147 ;;;###autoload | 155 ;;;###autoload |
148 (defcustom appt-display-diary t | 156 (defcustom appt-display-diary t |
149 "*Non-nil means to display the next days diary on the screen. | 157 "*Non-nil displays the diary when the appointment list is first initialized. |
150 This will occur at midnight when the appointment list is updated." | 158 This will occur at midnight when the appointment list is updated." |
151 :type 'boolean | 159 :type 'boolean |
152 :group 'appt) | 160 :group 'appt) |
153 | |
154 (defvar appt-time-msg-list nil | |
155 "The list of appointments for today. | |
156 Use `appt-add' and `appt-delete' to add and delete appointments from list. | |
157 The original list is generated from the today's `diary-entries-list'. | |
158 The number before each time/message is the time in minutes from midnight.") | |
159 | |
160 (defconst appt-max-time 1439 | |
161 "11:59pm in minutes - number of minutes in a day minus 1.") | |
162 | 161 |
163 (defcustom appt-display-interval 3 | 162 (defcustom appt-display-interval 3 |
164 "*Number of minutes to wait between checking the appointment list." | 163 "*Number of minutes to wait between checking the appointment list." |
165 :type 'integer | 164 :type 'integer |
166 :group 'appt) | 165 :group 'appt) |
167 | 166 |
167 (defcustom appt-disp-window-function 'appt-disp-window | |
168 "Function called to display appointment window. | |
169 Only relevant if reminders are being displayed in a window." | |
170 :type '(choice (const appt-disp-window) | |
171 function) | |
172 :group 'appt) | |
173 | |
174 (defcustom appt-delete-window-function 'appt-delete-window | |
175 "Function called to remove appointment window and buffer. | |
176 Only relevant if reminders are being displayed in a window." | |
177 :type '(choice (const appt-delete-window) | |
178 function) | |
179 :group 'appt) | |
180 | |
181 | |
182 ;;; Internal variables below this point. | |
183 | |
168 (defvar appt-buffer-name " *appt-buf*" | 184 (defvar appt-buffer-name " *appt-buf*" |
169 "Name of the appointments buffer.") | 185 "Name of the appointments buffer.") |
170 | 186 |
171 (defvar appt-disp-window-function 'appt-disp-window | 187 (defvar appt-time-msg-list nil |
172 "Function called to display appointment window.") | 188 "The list of appointments for today. |
173 | 189 Use `appt-add' and `appt-delete' to add and delete appointments. |
174 (defvar appt-delete-window-function 'appt-delete-window | 190 The original list is generated from today's `diary-entries-list', and |
175 "Function called to remove appointment window and buffer.") | 191 can be regenerated using the function `appt-check'. |
192 Each element of the generated list has the form (MINUTES) STRING; where | |
193 MINUTES is the time in minutes of the appointment after midnight, and | |
194 STRING is the description of the appointment.") | |
195 | |
196 (defconst appt-max-time 1439 | |
197 "11:59pm in minutes - number of minutes in a day minus 1.") | |
176 | 198 |
177 (defvar appt-mode-string nil | 199 (defvar appt-mode-string nil |
178 "String being displayed in the mode line saying you have an appointment. | 200 "String being displayed in the mode line saying you have an appointment. |
179 The actual string includes the amount of time till the appointment.") | 201 The actual string includes the amount of time till the appointment. |
202 Only used if `appt-display-mode-line' is non-nil.") | |
180 | 203 |
181 (defvar appt-prev-comp-time nil | 204 (defvar appt-prev-comp-time nil |
182 "Time of day (mins since midnight) at which we last checked appointments.") | 205 "Time of day (mins since midnight) at which we last checked appointments. |
206 A nil value forces the diary file to be (re-)checked for appointments.") | |
183 | 207 |
184 (defvar appt-now-displayed nil | 208 (defvar appt-now-displayed nil |
185 "Non-nil when we have started notifying about a appointment that is near.") | 209 "Non-nil when we have started notifying about a appointment that is near.") |
186 | 210 |
187 (defvar appt-display-count nil) | 211 (defvar appt-display-count nil |
188 | 212 "Internal variable used to count number of consecutive reminders.") |
189 (defun appt-check () | 213 |
190 "Check for an appointment and update the mode line. | 214 (defvar appt-timer nil |
215 "Timer used for diary appointment notifications (`appt-check'). | |
216 If this is non-nil, appointment checking is active.") | |
217 | |
218 | |
219 ;;; Functions. | |
220 | |
221 (defun appt-display-message (string mins) | |
222 "Display a reminder about an appointment. | |
223 The string STRING describes the appointment, due in integer MINS minutes. | |
224 The format of the visible reminder is controlled by `appt-display-format'. | |
225 The variable `appt-audible' controls the audible reminder." | |
226 ;; let binding for backwards compatability. Remove when obsolete | |
227 ;; vars appt-msg-window and appt-visible are dropped. | |
228 (let ((appt-display-format | |
229 (if (eq appt-display-format 'ignore) | |
230 (cond (appt-msg-window 'window) | |
231 (appt-visible 'echo)) | |
232 appt-display-format))) | |
233 (cond ((eq appt-display-format 'window) | |
234 (funcall appt-disp-window-function | |
235 (number-to-string mins) | |
236 (format-time-string "%a %b %e " (current-time)) | |
237 string) | |
238 (run-at-time (format "%d sec" appt-display-duration) | |
239 nil | |
240 appt-delete-window-function)) | |
241 ((eq appt-display-format 'echo) | |
242 (message "%s" string))) | |
243 (if appt-audible (beep 1)))) | |
244 | |
245 | |
246 (defun appt-check (&optional force) | |
247 "Check for an appointment and update any reminder display. | |
248 If optional argument FORCE is non-nil, reparse the diary file for | |
249 appointments. Otherwise the diary file is only parsed once per day, | |
250 and when saved. | |
251 | |
191 Note: the time must be the first thing in the line in the diary | 252 Note: the time must be the first thing in the line in the diary |
192 for a warning to be issued. | 253 for a warning to be issued. The format of the time can be either |
193 | 254 24 hour or am/pm. For example: |
194 The format of the time can be either 24 hour or am/pm. | 255 |
195 Example: | 256 02/23/89 |
196 | 257 18:00 Dinner |
197 02/23/89 | |
198 18:00 Dinner | |
199 | 258 |
200 Thursday | 259 Thursday |
201 11:45am Lunch meeting. | 260 11:45am Lunch meeting. |
202 | 261 |
203 Appointments are checked every `appt-display-interval' minutes. | 262 Appointments are checked every `appt-display-interval' minutes. |
204 The following variables control appointment notification: | 263 The following variables control appointment notification: |
205 | 264 |
206 `appt-issue-message' | 265 `appt-display-format' |
207 If t, the diary buffer is checked for appointments. | 266 Controls the format in which reminders are displayed. |
267 | |
268 `appt-audible' | |
269 Variable used to determine if reminder is audible. | |
270 Default is t. | |
208 | 271 |
209 `appt-message-warning-time' | 272 `appt-message-warning-time' |
210 Variable used to determine if appointment message | 273 Variable used to determine when appointment message |
211 should be displayed. | 274 should first be displayed. |
212 | 275 |
213 `appt-audible' | 276 `appt-display-mode-line' |
214 Variable used to determine if appointment is audible. | 277 If non-nil, a generic message giving the time remaining |
215 Default is t. | 278 is shown in the mode-line when an appointment is due. |
216 | 279 |
217 `appt-visible' | 280 `appt-display-interval' |
218 Variable used to determine if appointment message should be | 281 Interval in minutes at which to check for pending appointments. |
219 displayed in the mini-buffer. Default is t. | 282 |
220 | 283 `appt-display-diary' |
221 `appt-msg-window' | 284 Display the diary buffer when the appointment list is |
222 Variable used to determine if appointment message | 285 initialized for the first time in a day. |
223 should temporarily appear in another window. Mutually exclusive | 286 |
224 to `appt-visible'. | 287 The following variables are only relevant if reminders are being |
288 displayed in a window: | |
225 | 289 |
226 `appt-display-duration' | 290 `appt-display-duration' |
227 The number of seconds an appointment message | 291 The number of seconds an appointment message is displayed. |
228 is displayed in another window. | |
229 | 292 |
230 `appt-disp-window-function' | 293 `appt-disp-window-function' |
231 Function called to display appointment window. You can customize | 294 Function called to display appointment window. |
232 appt.el by setting this variable to a function different from the | |
233 one provided with this package. | |
234 | 295 |
235 `appt-delete-window-function' | 296 `appt-delete-window-function' |
236 Function called to remove appointment window and buffer. You can | 297 Function called to remove appointment window and buffer." |
237 customize appt.el by setting this variable to a function different | |
238 from the one provided with this package." | |
239 | 298 |
240 (let* ((min-to-app -1) | 299 (let* ((min-to-app -1) |
241 (new-time "") | |
242 (prev-appt-mode-string appt-mode-string) | 300 (prev-appt-mode-string appt-mode-string) |
243 (prev-appt-display-count (or appt-display-count 0)) | 301 (prev-appt-display-count (or appt-display-count 0)) |
244 ;; Non-nil means do a full check for pending appointments | 302 ;; Non-nil means do a full check for pending appointments |
245 ;; and display in whatever ways the user has selected. | 303 ;; and display in whatever ways the user has selected. |
246 ;; When no appointment is being displayed, | 304 ;; When no appointment is being displayed, |
247 ;; we always do a full check. | 305 ;; we always do a full check. |
248 (full-check | 306 (full-check |
249 (or (not appt-now-displayed) | 307 (or (not appt-now-displayed) |
250 ;; This is true every appt-display-interval minutes. | 308 ;; This is true every appt-display-interval minutes. |
251 (= 0 (mod prev-appt-display-count appt-display-interval)))) | 309 (zerop (mod prev-appt-display-count appt-display-interval)))) |
252 ;; Non-nil means only update the interval displayed in the mode line. | 310 ;; Non-nil means only update the interval displayed in the mode line. |
253 (mode-line-only | 311 (mode-line-only |
254 (and (not full-check) appt-now-displayed))) | 312 (and (not full-check) appt-now-displayed))) |
255 | 313 |
256 (when (or full-check mode-line-only) | 314 (when (or full-check mode-line-only) |
265 (cur-comp-time (+ (* cur-hour 60) cur-min))) | 323 (cur-comp-time (+ (* cur-hour 60) cur-min))) |
266 | 324 |
267 ;; At the first check in any given day, update our | 325 ;; At the first check in any given day, update our |
268 ;; appointments to today's list. | 326 ;; appointments to today's list. |
269 | 327 |
270 (if (or (null appt-prev-comp-time) | 328 (if (or force ; eg initialize, diary save |
271 (< cur-comp-time appt-prev-comp-time)) | 329 (null appt-prev-comp-time) ; first check |
330 (< cur-comp-time appt-prev-comp-time)) ; new day | |
272 (condition-case nil | 331 (condition-case nil |
273 (progn | 332 (if appt-display-diary |
274 (if (and view-diary-entries-initially appt-display-diary) | 333 (let ((diary-hook |
275 (diary) | 334 (if (assoc 'appt-make-list diary-hook) |
276 (let ((diary-display-hook 'appt-make-list)) | 335 diary-hook |
277 (diary)))) | 336 (cons 'appt-make-list diary-hook)))) |
337 (diary)) | |
338 (let ((diary-display-hook 'appt-make-list) | |
339 (d-buff (find-buffer-visiting | |
340 (substitute-in-file-name diary-file))) | |
341 selective) | |
342 (if d-buff ; diary buffer exists | |
343 (with-current-buffer d-buff | |
344 (setq selective selective-display))) | |
345 (diary) | |
346 ;; If the diary buffer existed before this command, | |
347 ;; restore its display state. Otherwise, kill it. | |
348 (if d-buff | |
349 ;; Displays the diary buffer. | |
350 (or selective (show-all-diary-entries)) | |
351 (and | |
352 (setq d-buff (find-buffer-visiting | |
353 (substitute-in-file-name diary-file))) | |
354 (kill-buffer d-buff))))) | |
278 (error nil))) | 355 (error nil))) |
279 (setq appt-prev-comp-time cur-comp-time) | 356 |
280 | 357 (setq appt-prev-comp-time cur-comp-time |
281 (setq appt-mode-string nil) | 358 appt-mode-string nil |
282 (setq appt-display-count nil) | 359 appt-display-count nil) |
283 | 360 |
284 ;; If there are entries in the list, and the | 361 ;; If there are entries in the list, and the |
285 ;; user wants a message issued, | 362 ;; user wants a message issued, |
286 ;; get the first time off of the list | 363 ;; get the first time off of the list |
287 ;; and calculate the number of minutes until the appointment. | 364 ;; and calculate the number of minutes until the appointment. |
315 ;; issue warning if the appointment time is | 392 ;; issue warning if the appointment time is |
316 ;; within appt-message-warning time | 393 ;; within appt-message-warning time |
317 | 394 |
318 (when (and (<= min-to-app appt-message-warning-time) | 395 (when (and (<= min-to-app appt-message-warning-time) |
319 (>= min-to-app 0)) | 396 (>= min-to-app 0)) |
320 (setq appt-now-displayed t) | 397 (setq appt-now-displayed t |
321 (setq appt-display-count | 398 appt-display-count (1+ prev-appt-display-count)) |
322 (1+ prev-appt-display-count)) | |
323 (unless mode-line-only | 399 (unless mode-line-only |
324 (if appt-msg-window | 400 (appt-display-message (cadr (car appt-time-msg-list)) |
325 (progn | 401 min-to-app)) |
326 (setq new-time (format-time-string "%a %b %e " | |
327 (current-time))) | |
328 (funcall | |
329 appt-disp-window-function | |
330 (number-to-string min-to-app) new-time | |
331 (car (cdr (car appt-time-msg-list)))) | |
332 | |
333 (run-at-time | |
334 (format "%d sec" appt-display-duration) | |
335 nil | |
336 appt-delete-window-function)) | |
337 ;;; else | |
338 | |
339 (if appt-visible | |
340 (message "%s" | |
341 (car (cdr (car appt-time-msg-list))))) | |
342 | |
343 (if appt-audible | |
344 (beep 1)))) | |
345 | |
346 (when appt-display-mode-line | 402 (when appt-display-mode-line |
347 (setq appt-mode-string | 403 (setq appt-mode-string |
348 (concat " App't in " | 404 (format " App't in %s min." min-to-app))) |
349 (number-to-string min-to-app) | |
350 " min. "))) | |
351 | 405 |
352 ;; When an appointment is reached, | 406 ;; When an appointment is reached, |
353 ;; delete it from the list. | 407 ;; delete it from the list. |
354 ;; Reset the count to 0 in case we display another | 408 ;; Reset the count to 0 in case we display another |
355 ;; appointment on the next cycle. | 409 ;; appointment on the next cycle. |
356 (if (= min-to-app 0) | 410 (if (zerop min-to-app) |
357 (setq appt-time-msg-list | 411 (setq appt-time-msg-list (cdr appt-time-msg-list) |
358 (cdr appt-time-msg-list) | |
359 appt-display-count nil))))) | 412 appt-display-count nil))))) |
360 | 413 |
361 ;; If we have changed the mode line string, | 414 ;; If we have changed the mode line string, |
362 ;; redisplay all mode lines. | 415 ;; redisplay all mode lines. |
363 (and appt-display-mode-line | 416 (and appt-display-mode-line |
370 (if appt-mode-string | 423 (if appt-mode-string |
371 (sit-for 0))))))))) | 424 (sit-for 0))))))))) |
372 | 425 |
373 | 426 |
374 (defun appt-disp-window (min-to-app new-time appt-msg) | 427 (defun appt-disp-window (min-to-app new-time appt-msg) |
375 "Display appointment message APPT-MSG in a separate buffer." | 428 "Display appointment message APPT-MSG in a separate buffer. |
429 The appointment is due in MIN-TO-APP (a string) minutes. | |
430 NEW-TIME is a string giving the date." | |
376 (require 'electric) | 431 (require 'electric) |
377 | 432 |
378 ;; Make sure we're not in the minibuffer | 433 ;; Make sure we're not in the minibuffer |
379 ;; before splitting the window. | 434 ;; before splitting the window. |
380 | 435 |
382 (if (other-window 1) | 437 (if (other-window 1) |
383 (select-window (other-window 1)) | 438 (select-window (other-window 1)) |
384 (if (display-multi-frame-p) | 439 (if (display-multi-frame-p) |
385 (select-frame (other-frame 1))))) | 440 (select-frame (other-frame 1))))) |
386 | 441 |
387 (let* ((this-buffer (current-buffer)) | 442 (let ((this-window (selected-window)) |
388 (this-window (selected-window)) | 443 (appt-disp-buf (set-buffer (get-buffer-create appt-buffer-name)))) |
389 (appt-disp-buf (set-buffer (get-buffer-create appt-buffer-name)))) | |
390 | 444 |
391 (if (cdr (assq 'unsplittable (frame-parameters))) | 445 (if (cdr (assq 'unsplittable (frame-parameters))) |
392 ;; In an unsplittable frame, use something somewhere else. | 446 ;; In an unsplittable frame, use something somewhere else. |
393 (display-buffer appt-disp-buf) | 447 (display-buffer appt-disp-buf) |
394 (unless (or (special-display-p (buffer-name appt-disp-buf)) | 448 (unless (or (special-display-p (buffer-name appt-disp-buf)) |
403 (erase-buffer) | 457 (erase-buffer) |
404 (insert appt-msg) | 458 (insert appt-msg) |
405 (shrink-window-if-larger-than-buffer (get-buffer-window appt-disp-buf t)) | 459 (shrink-window-if-larger-than-buffer (get-buffer-window appt-disp-buf t)) |
406 (set-buffer-modified-p nil) | 460 (set-buffer-modified-p nil) |
407 (raise-frame (selected-frame)) | 461 (raise-frame (selected-frame)) |
408 (select-window this-window) | 462 (select-window this-window))) |
409 (if appt-audible | |
410 (beep 1)))) | |
411 | 463 |
412 (defun appt-delete-window () | 464 (defun appt-delete-window () |
413 "Function called to undisplay appointment messages. | 465 "Function called to undisplay appointment messages. |
414 Usually just deletes the appointment buffer." | 466 Usually just deletes the appointment buffer." |
415 (let ((window (get-buffer-window appt-buffer-name t))) | 467 (let ((window (get-buffer-window appt-buffer-name t))) |
435 (defun appt-add (new-appt-time new-appt-msg) | 487 (defun appt-add (new-appt-time new-appt-msg) |
436 "Add an appointment for the day at NEW-APPT-TIME and issue message NEW-APPT-MSG. | 488 "Add an appointment for the day at NEW-APPT-TIME and issue message NEW-APPT-MSG. |
437 The time should be in either 24 hour format or am/pm format." | 489 The time should be in either 24 hour format or am/pm format." |
438 | 490 |
439 (interactive "sTime (hh:mm[am/pm]): \nsMessage: ") | 491 (interactive "sTime (hh:mm[am/pm]): \nsMessage: ") |
440 (if (string-match "[0-9]?[0-9]:[0-9][0-9]\\(am\\|pm\\)?" new-appt-time) | 492 (unless (string-match "[0-9]?[0-9][:.][0-9][0-9]\\(am\\|pm\\)?" |
441 nil | 493 new-appt-time) |
442 (error "Unacceptable time-string")) | 494 (error "Unacceptable time-string")) |
443 | |
444 (let* ((appt-time-string (concat new-appt-time " " new-appt-msg)) | 495 (let* ((appt-time-string (concat new-appt-time " " new-appt-msg)) |
445 (appt-time (list (appt-convert-time new-appt-time))) | 496 (appt-time (list (appt-convert-time new-appt-time))) |
446 (time-msg (cons appt-time (list appt-time-string)))) | 497 (time-msg (cons appt-time (list appt-time-string)))) |
447 (setq appt-time-msg-list (nconc appt-time-msg-list (list time-msg))) | 498 (setq appt-time-msg-list (nconc appt-time-msg-list (list time-msg))) |
448 (setq appt-time-msg-list (appt-sort-list appt-time-msg-list)))) | 499 (setq appt-time-msg-list (appt-sort-list appt-time-msg-list)))) |
449 | 500 |
450 ;;;###autoload | 501 ;;;###autoload |
451 (defun appt-delete () | 502 (defun appt-delete () |
452 "Delete an appointment from the list of appointments." | 503 "Delete an appointment from the list of appointments." |
453 (interactive) | 504 (interactive) |
454 (let* ((tmp-msg-list appt-time-msg-list)) | 505 (let ((tmp-msg-list appt-time-msg-list)) |
455 (while tmp-msg-list | 506 (while tmp-msg-list |
456 (let* ((element (car tmp-msg-list)) | 507 (let* ((element (car tmp-msg-list)) |
457 (prompt-string (concat "Delete " | 508 (prompt-string (concat "Delete " |
458 ;; We want to quote any doublequotes | 509 ;; We want to quote any doublequotes |
459 ;; in the string, as well as put | 510 ;; in the string, as well as put |
473 (eval-when-compile (defvar number) | 524 (eval-when-compile (defvar number) |
474 (defvar original-date) | 525 (defvar original-date) |
475 (defvar diary-entries-list)) | 526 (defvar diary-entries-list)) |
476 ;;;###autoload | 527 ;;;###autoload |
477 (defun appt-make-list () | 528 (defun appt-make-list () |
478 "Create the appointments list from todays diary buffer. | 529 "Create the appointments list from today's diary buffer. |
479 The time must be at the beginning of a line for it to be | 530 The time must be at the beginning of a line for it to be |
480 put in the appointments list. | 531 put in the appointments list (see examples in documentation of |
481 02/23/89 | 532 the function `appt-check'). We assume that the variables DATE and |
482 12:00pm lunch | 533 NUMBER hold the arguments that `list-diary-entries' received. |
483 Wednesday | |
484 10:00am group meeting | |
485 We assume that the variables DATE and NUMBER | |
486 hold the arguments that `list-diary-entries' received. | |
487 They specify the range of dates that the diary is being processed for." | 534 They specify the range of dates that the diary is being processed for." |
488 | 535 |
489 ;; We have something to do if the range of dates that the diary is | 536 ;; We have something to do if the range of dates that the diary is |
490 ;; considering includes the current date. | 537 ;; considering includes the current date. |
491 (if (and (not (calendar-date-compare | 538 (if (and (not (calendar-date-compare |
517 (while (and entry-list | 564 (while (and entry-list |
518 (calendar-date-equal | 565 (calendar-date-equal |
519 (calendar-current-date) (car (car entry-list)))) | 566 (calendar-current-date) (car (car entry-list)))) |
520 (let ((time-string (cadr (car entry-list)))) | 567 (let ((time-string (cadr (car entry-list)))) |
521 (while (string-match | 568 (while (string-match |
522 "\\([0-9]?[0-9]:[0-9][0-9]\\(am\\|pm\\)?\\).*" | 569 "\\([0-9]?[0-9][:.][0-9][0-9]\\(am\\|pm\\)?\\).*" |
523 time-string) | 570 time-string) |
524 (let* ((beg (match-beginning 0)) | 571 (let* ((beg (match-beginning 0)) |
525 ;; Get just the time for this appointment. | 572 ;; Get just the time for this appointment. |
526 (only-time (match-string 1 time-string)) | 573 (only-time (match-string 1 time-string)) |
527 ;; Find the end of this appointment | 574 ;; Find the end of this appointment |
528 ;; (the start of the next). | 575 ;; (the start of the next). |
529 (end (string-match | 576 (end (string-match |
530 "^[ \t]*[0-9]?[0-9]:[0-9][0-9]\\(am\\|pm\\)?" | 577 "^[ \t]*[0-9]?[0-9][:.][0-9][0-9]\\(am\\|pm\\)?" |
531 time-string | 578 time-string |
532 (match-end 0))) | 579 (match-end 0))) |
533 ;; Get the whole string for this appointment. | 580 ;; Get the whole string for this appointment. |
534 (appt-time-string | 581 (appt-time-string |
535 (substring time-string beg (if end (1- end))))) | 582 (substring time-string beg (if end (1- end))))) |
554 | 601 |
555 (let* ((now (decode-time)) | 602 (let* ((now (decode-time)) |
556 (cur-hour (nth 2 now)) | 603 (cur-hour (nth 2 now)) |
557 (cur-min (nth 1 now)) | 604 (cur-min (nth 1 now)) |
558 (cur-comp-time (+ (* cur-hour 60) cur-min)) | 605 (cur-comp-time (+ (* cur-hour 60) cur-min)) |
559 (appt-comp-time (car (car (car appt-time-msg-list))))) | 606 (appt-comp-time (car (caar appt-time-msg-list)))) |
560 | 607 |
561 (while (and appt-time-msg-list (< appt-comp-time cur-comp-time)) | 608 (while (and appt-time-msg-list (< appt-comp-time cur-comp-time)) |
562 (setq appt-time-msg-list (cdr appt-time-msg-list)) | 609 (setq appt-time-msg-list (cdr appt-time-msg-list)) |
563 (if appt-time-msg-list | 610 (if appt-time-msg-list |
564 (setq appt-comp-time (car (car (car appt-time-msg-list)))))))))) | 611 (setq appt-comp-time (car (caar appt-time-msg-list))))))))) |
565 | 612 |
566 | 613 |
567 (defun appt-sort-list (appt-list) | 614 (defun appt-sort-list (appt-list) |
568 "Simple sort to put the appointments list APPT-LIST in order. | 615 "Sort an appointment list, putting earlier items at the front. |
569 Scan the list for the smallest element left in the list. | 616 APPT-LIST is a list of the same format as `appt-time-msg-list'." |
570 Append the smallest element left into the new list, and remove | 617 (sort appt-list (lambda (e1 e2) (< (caar e1) (caar e2))))) |
571 it from the original list." | |
572 (let ((order-list nil)) | |
573 (while appt-list | |
574 (let* ((element (car appt-list)) | |
575 (element-time (car (car element))) | |
576 (tmp-list (cdr appt-list))) | |
577 (while tmp-list | |
578 (if (< element-time (car (car (car tmp-list)))) | |
579 nil | |
580 (setq element (car tmp-list)) | |
581 (setq element-time (car (car element)))) | |
582 (setq tmp-list (cdr tmp-list))) | |
583 (setq order-list (nconc order-list (list element))) | |
584 (setq appt-list (delq element appt-list)))) | |
585 order-list)) | |
586 | 618 |
587 | 619 |
588 (defun appt-convert-time (time2conv) | 620 (defun appt-convert-time (time2conv) |
589 "Convert hour:min[am/pm] format to minutes from midnight." | 621 "Convert hour:min[am/pm] format to minutes from midnight. |
590 | 622 A period (.) can be used instead of a colon (:) to separate the |
623 hour and minute parts." | |
591 (let ((conv-time 0) | 624 (let ((conv-time 0) |
592 (hr 0) | 625 (hr 0) |
593 (min 0)) | 626 (min 0)) |
594 | 627 |
595 (string-match ":\\([0-9][0-9]\\)" time2conv) | 628 (string-match "[:.]\\([0-9][0-9]\\)" time2conv) |
596 (setq min (string-to-int | 629 (setq min (string-to-int |
597 (match-string 1 time2conv))) | 630 (match-string 1 time2conv))) |
598 | 631 |
599 (string-match "[0-9]?[0-9]:" time2conv) | 632 (string-match "[0-9]?[0-9][:.]" time2conv) |
600 (setq hr (string-to-int | 633 (setq hr (string-to-int |
601 (match-string 0 time2conv))) | 634 (match-string 0 time2conv))) |
602 | 635 |
603 ;; convert the time appointment time into 24 hour time | 636 ;; convert the time appointment time into 24 hour time |
604 | 637 |
612 ;; against the actual time. | 645 ;; against the actual time. |
613 | 646 |
614 (setq conv-time (+ (* hr 60) min)) | 647 (setq conv-time (+ (* hr 60) min)) |
615 conv-time)) | 648 conv-time)) |
616 | 649 |
617 (defvar appt-timer nil | 650 |
618 "Timer used for diary appointment notifications (`appt-check').") | 651 (defun appt-update-list () |
619 | 652 "If the current buffer is visiting the diary, update appointments. |
620 (unless appt-timer | 653 This function is intended for use with `write-file-functions'." |
621 (setq appt-timer (run-at-time t 60 'appt-check))) | 654 (and (string-equal buffer-file-name (expand-file-name diary-file)) |
622 | 655 appt-timer |
623 (or global-mode-string (setq global-mode-string '(""))) | 656 (let ((appt-display-diary nil)) |
624 (or (memq 'appt-mode-string global-mode-string) | 657 (appt-check t))) |
625 (setq global-mode-string | 658 nil) |
626 (append global-mode-string '(appt-mode-string)))) | 659 |
627 | 660 |
661 ;;;###autoload | |
662 (defun appt-activate (&optional arg) | |
663 "Toggle checking of appointments. | |
664 With optional numeric argument ARG, turn appointment checking on if | |
665 ARG is positive, otherwise off." | |
666 (interactive "P") | |
667 (let ((appt-active appt-timer)) | |
668 (setq appt-active (if arg (> (prefix-numeric-value arg) 0) | |
669 (not appt-active))) | |
670 (remove-hook 'write-file-functions 'appt-update-list) | |
671 (or global-mode-string (setq global-mode-string '(""))) | |
672 (delq 'appt-mode-string global-mode-string) | |
673 (when appt-timer | |
674 (cancel-timer appt-timer) | |
675 (setq appt-timer nil)) | |
676 (when appt-active | |
677 (add-hook 'write-file-functions 'appt-update-list) | |
678 (setq appt-timer (run-at-time t 60 'appt-check) | |
679 global-mode-string | |
680 (append global-mode-string '(appt-mode-string))) | |
681 (appt-check t)))) | |
682 | |
683 | |
684 ;; This is needed for backwards compatibility. Feh. | |
685 (appt-activate 1) | |
686 | |
687 | |
688 (provide 'appt) | |
689 | |
690 ;;; arch-tag: bf5791c4-8921-499e-a26f-772b1788d347 | |
628 ;;; appt.el ends here | 691 ;;; appt.el ends here |