|
|
1.1 root 1: ;; Record version number of Emacs.
2: ;; Copyright (C) 1988 Free Software Foundation, Inc.
3:
4: ;; This file is part of GNU Emacs.
5:
6: ;; GNU Emacs is distributed in the hope that it will be useful,
7: ;; but WITHOUT ANY WARRANTY. No author or distributor
8: ;; accepts responsibility to anyone for the consequences of using it
9: ;; or for whether it serves any particular purpose or works at all,
10: ;; unless he says so in writing. Refer to the GNU Emacs General Public
11: ;; License for full details.
12:
13: ;; Everyone is granted permission to copy, modify and redistribute
14: ;; GNU Emacs, but only under the conditions described in the
15: ;; GNU Emacs General Public License. A copy of this license is
16: ;; supposed to have been given to you along with GNU Emacs so you
17: ;; can know your rights and responsibilities. It should be in a
18: ;; file named COPYING. Among other things, the copyright notice
19: ;; and this notice must be preserved on all copies.
20: ;;
21: ;; Comments, corrections, and improvements should be sent to
22: ;; Edward M. Reingold Department of Computer Science
23: ;; (217) 333-6733 University of Illinois at Urbana-Champaign
24: ;; [email protected] 1304 West Springfield Avenue
25: ;; Urbana, Illinois 61801
26: ;;
27: ;; The author gratefully acknowledges the patient help of Richard Stallman
28: ;; in making this function into a reasonable piece of code!
29: ;;
30: ;; Modification for month-offset arguments suggested and implemented by
31: ;; Constantine Rasmussen Sun Microsystems, East Coast Division
32: ;; (617) 671-0404 2 Federal Street; Billerica, Ma. 01824
33: ;; ARPA: [email protected] USENET: {cbosgd,decvax,hplabs,seismo}!sun!suneast!cdr
34: ;;
35: ;; Modification to mark current day with stars suggested by
36: ;; Franklin Davis Thinking Machines Corp
37: ;; (617) 876-1111 245 First Street, Cambridge, MA 02142
38: ;; [email protected]
39:
40: (defvar calendar-hook nil
41: "List of functions called after the calendar buffer has been prepared with
42: the calendar of the current month. This can be used, for example, to highlight
43: today's date with asterisks--a function star-date is included for this purpose.
44: The variable offset-calendar-hook is the list of functions called when the
45: calendar function was called for a past or future month.")
46:
47: (defvar offset-calendar-hook nil
48: "List of functions called after the calendar buffer has been prepared with
49: the calendar of a past or future month. The variable calendar-hook is the
50: list of functions called when the calendar function was called for the
51: current month.")
52:
53: (defun calendar (&optional month-offset)
54: "Display three-month calendar in another window.
55: The three months appear side by side, with the current month in the middle
56: surrounded by the previous and next months. The cursor is put on today's date.
57:
58: An optional prefix argument ARG causes the calendar displayed to be
59: ARG months in the future if ARG is positive or in the past if ARG is
60: negative; in this case the cursor goes on the first day of the month.
61:
62: The Gregorian calendar is assumed.
63:
64: After preparing the calendar window, the hooks calendar-hook are run
65: when the calendar is for the current month--that is, the was no prefix
66: argument. If the calendar is for a future or past month--that is, there
67: was a prefix argument--the hooks offset-calendar-hook are run. Thus, for
68: example, setting calendar-hooks to 'star-date will cause today's date to be
69: replaced by asterisks to highlight it in the window."
70: (interactive "P")
71: (if month-offset (setq month-offset (prefix-numeric-value month-offset)))
72: (let ((today (make-marker)))
73: (save-excursion
74: (set-buffer (get-buffer-create "*Calendar*"))
75: (setq buffer-read-only t)
76: (let*
77: ((buffer-read-only nil)
78: ;; Get today's date and extract the day, month and year.
79: (date (current-time-string))
80: (garbage (string-match
81: " \\([A-Z][a-z][a-z]\\) *\\([0-9]*\\) .* \\([0-9]*\\)$"
82: date))
83: (day (or (and month-offset 1)
84: (string-to-int
85: (substring date (match-beginning 2) (match-end 2)))))
86: (month
87: (cdr (assoc
88: (substring date (match-beginning 1) (match-end 1))
89: '(("Jan" . 1) ("Feb" . 2) ("Mar" . 3) ("Apr" . 4)
90: ("May" . 5) ("Jun" . 6) ("Jul" . 7) ("Aug" . 8)
91: ("Sep" . 9) ("Oct" . 10) ("Nov" . 11) ("Dec" . 12)))))
92: (year (string-to-int
93: (substring date (match-beginning 3) (match-end 3)))))
94: (erase-buffer)
95: ;; If user requested a month in the future or the past,
96: ;; advance the variables MONTH and YEAR to describe that one.
97: (cond
98: (month-offset
99: (let ((year-month (+ (+ (* year 12) (- month 1)) month-offset)))
100: (setq month (+ (% year-month 12) 1))
101: (setq year (/ year-month 12)))))
102: ;; Generate previous month, starting at left margin.
103: (generate-month;; previous month
104: (if (= month 1) 12 (1- month))
105: (if (= month 1) (1- year) year)
106: 0)
107: ;; Generate this month, starting at column 24,
108: ;; and record where today's date appears, in the marker TODAY.
109: (goto-char (point-min))
110: (set-marker today (generate-month month year 24 day))
111: ;; Generate the following month, starting at column 48.
112: (goto-char (point-min))
113: (generate-month
114: (if (= month 12) 1 (1+ month))
115: (if (= month 12) (1+ year) year)
116: 48)))
117: ;; Display the buffer and put cursor on today's date.
118: ;; Do it in another window, but if this buffer is already visible,
119: ;; just select its window.
120: (pop-to-buffer "*Calendar*")
121: (goto-char (marker-position today))
122: ;; Make TODAY point nowhere so it won't slow down buffer editing until GC.
123: (set-marker today nil))
124: ;; Make the window just tall enough for its contents.
125: (let ((h (1- (window-height)))
126: (l (count-lines (point-min) (point-max))))
127: (or (one-window-p t)
128: (<= h l)
129: (shrink-window (- h l))))
130: (if month-offset
131: (run-hooks 'offset-calendar-hook)
132: (run-hooks 'calendar-hook)))
133:
134: (defun leap-year-p (year)
135: "Returns true if YEAR is a Gregorian leap year, and false if not."
136: (or
137: (and (= (% year 4) 0)
138: (/= (% year 100) 0))
139: (= (% year 400) 0)))
140:
141: (defun day-number (month day year)
142: "Return day-number within year (origin-1) of the date MONTH DAY YEAR.
143: For example, (day-number 1 1 1987) returns the value 1,
144: while (day-number 12 31 1980) returns 366."
145: ;;
146: ;; an explanation of the calculation can be found in PascAlgorithms by
147: ;; Edward and Ruth Reingold, Scott-foresman/Little, Brown, 1988.
148: ;;
149: (let ((day-of-year (+ day (* 31 (1- month)))))
150: (if (> month 2)
151: (progn
152: (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10)))
153: (if (leap-year-p year)
154: (setq day-of-year (1+ day-of-year)))))
155: day-of-year))
156:
157: (defun day-of-week (month day year)
158: "Returns the day-of-the-week index of MONTH DAY, YEAR.
159: Value is 0 for Sunday, 1 for Monday, etc."
160: ;;
161: ;; Done by calculating the number of days elapsed since the (imaginary)
162: ;; Gregorian date Sunday, December 31, 1 BC and taking that number mod 7.
163: ;;
164: (%
165: (-
166: (+ (day-number month day year)
167: (* 365 (1- year))
168: (/ (1- year) 4))
169: (let ((correction (* (/ (1- year) 100) 3)))
170: (if (= (% correction 4) 0)
171: (/ correction 4)
172: (1+ (/ correction 4)))))
173: 7))
174:
175: (defun generate-month (month year indent &optional day)
176: "Produce a calendar for MONTH, YEAR on the Gregorian calendar, inserted
177: in the buffer starting at the line on which point is currently located, but
178: indented INDENT spaces. The position in the buffer of the optional
179: parameter DAY is returned. The indentation is done from the first
180: character on the line and does not disturb the first INDENT characters on
181: the line."
182: (let* ((first-day-of-month (day-of-week month 1 year) 7)
183: (first-saturday (- 7 first-day-of-month))
184: (last-of-month
185: (if (and (leap-year-p year) (= month 2))
186: 29
187: (aref [31 28 31 30 31 30 31 31 30 31 30 31] (1- month))))
188: (month-name
189: (aref ["January" "February" "March" "April" "May" "June"
190: "July" "August" "September" "October" "November" "December"]
191: (1- month))))
192: (insert-indented (format " %s %d" month-name year) indent t)
193: (insert-indented " S M Tu W Th F S" indent t)
194: (insert-indented "" indent);; move point to appropriate spot on line
195: (let ((i 0)) ;; add blank days before the first of the month
196: (while (<= (setq i (1+ i)) first-day-of-month)
197: (insert " ")))
198: (let ((i 0)
199: (day-marker)) ;; put in the days of the month
200: (while (<= (setq i (1+ i)) last-of-month)
201: (insert (format "%2d " i))
202: (and
203: day
204: (= i day) ;; save the location of the specified day
205: (setq day-marker (- (point) 2)))
206: (and (= (% i 7) (% first-saturday 7))
207: (/= i last-of-month)
208: (insert-indented "" 0 t) ;; force onto following line
209: (insert-indented "" indent))) ;; go to proper spot on line
210: day-marker)))
211:
212: (defun insert-indented (string indent &optional newline)
213: "Insert STRING at column INDENT.
214: If the optional parameter NEWLINE is true, leave point at start of next
215: line, inserting a newline if there was no next line; otherwise, leave point
216: after the inserted text. Value is always `t'."
217: ;; Try to move to that column.
218: (move-to-column indent)
219: ;; If line is too short, indent out to that column.
220: (if (< (current-column) indent)
221: (indent-to indent))
222: (insert string)
223: ;; Advance to next line, if requested.
224: (if newline
225: (progn
226: (end-of-line)
227: (if (eobp)
228: (newline)
229: (forward-line 1))))
230: t)
231:
232: (defun star-date ()
233: "Replace today's date with asterisks in the calendar window.
234: This function can be used with the calendar-hook run after the
235: calendar window has been prepared."
236: (let ((buffer-read-only nil))
237: (forward-char 1)
238: (delete-backward-char 2)
239: (insert "**")
240: (backward-char 1)))
241:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.