comparison lisp/calendar/calendar.el @ 92969:bb4fc128d00d

(european-calendar-style, calendar-for-loop) (calendar-sum, calendar-insert-indented, mouse-calendar-other-month) (calendar-cursor-to-date): Doc fix. (hebrew-holidays-1, hebrew-holidays-4): Simplify. (extract-calendar-day, extract-calendar-year): Use cadr, nth. (calendar-day-number): Use when. (generate-calendar-month): Use dotimes. (exit-calendar, calendar-print-other-dates): Use let rather than let*. (calendar-set-mark): Reverse conditional. (calendar-make-alist): Move definition before use.
author Glenn Morris <rgm@gnu.org>
date Sat, 15 Mar 2008 03:00:17 +0000
parents d0fa9dff8d20
children 189ca7ef805d
comparison
equal deleted inserted replaced
92968:e2f0046a8cb4 92969:bb4fc128d00d
89 89
90 ;; Hard copies of these two papers can be obtained by sending email to 90 ;; Hard copies of these two papers can be obtained by sending email to
91 ;; reingold@cs.uiuc.edu with the SUBJECT "send-paper-cal" (no quotes) and 91 ;; reingold@cs.uiuc.edu with the SUBJECT "send-paper-cal" (no quotes) and
92 ;; the message BODY containing your mailing address (snail). 92 ;; the message BODY containing your mailing address (snail).
93 93
94
95 ;; A note on free variables:
96
97 ;; The calendar passes around a few dynamically bound variables, which
98 ;; unfortunately have rather common names. They are meant to be
99 ;; available for external functions, so the names can't be changed.
100
101 ;; displayed-month, displayed-year: bound in generate-calendar, the
102 ;; central month of the 3 month calendar window
103 ;; original-date, number: bound in diary-list-entries, the arguments
104 ;; with which that function was called.
105 ;; date, entry: bound in list-sexp-diary-entries (qv)
106
107 ;; Bound in diary-list-entries:
108 ;; diary-entries-list: use in d-l, appt.el, and by add-to-diary-list
109 ;; diary-saved-point: only used in diary-lib.el, passed to the display func
110 ;; date-string: only used in diary-lib.el FIXME could be removed?
111
94 ;;; Code: 112 ;;; Code:
95 113
96 ;; (elisp) Eval During Compile: "Effectively `require' is 114 ;; (elisp) Eval During Compile: "Effectively `require' is
97 ;; automatically `eval-and-compile'" [but `load' is not] 115 ;; automatically `eval-and-compile'" [but `load' is not]
98 (eval-and-compile 116 (eval-and-compile
455 :group 'diary) 473 :group 'diary)
456 474
457 ;;;###autoload 475 ;;;###autoload
458 (defcustom european-calendar-style nil 476 (defcustom european-calendar-style nil
459 "Use the European style of dates in the diary and in any displays. 477 "Use the European style of dates in the diary and in any displays.
460 If this variable is t, a date 1/2/1990 would be interpreted as February 1, 478 If this variable is non-nil, a date 1/2/1990 would be interpreted as
461 1990. The default European date styles (see `european-date-diary-pattern') 479 February 1, 1990. The default European date styles (see
462 are 480 `european-date-diary-pattern') are
463 481
464 DAY/MONTH 482 DAY/MONTH
465 DAY/MONTH/YEAR 483 DAY/MONTH/YEAR
466 DAY MONTHNAME 484 DAY MONTHNAME
467 DAY MONTHNAME YEAR 485 DAY MONTHNAME YEAR
744 (defvar hebrew-holidays-1 762 (defvar hebrew-holidays-1
745 '((holiday-rosh-hashanah-etc) 763 '((holiday-rosh-hashanah-etc)
746 (if all-hebrew-calendar-holidays 764 (if all-hebrew-calendar-holidays
747 (holiday-julian 765 (holiday-julian
748 11 766 11
749 (let* ((m displayed-month) 767 (let ((m displayed-month)
750 (y displayed-year) 768 (y displayed-year)
751 (year)) 769 year)
752 (increment-calendar-month m y -1) 770 (increment-calendar-month m y -1)
753 (let ((year (extract-calendar-year 771 (setq year (extract-calendar-year
754 (calendar-julian-from-absolute 772 (calendar-julian-from-absolute
755 (calendar-absolute-from-gregorian 773 (calendar-absolute-from-gregorian (list m 1 y)))))
756 (list m 1 y)))))) 774 (if (zerop (% (1+ year) 4))
757 (if (zerop (% (1+ year) 4)) 775 22
758 22 776 21)) "\"Tal Umatar\" (evening)")))
759 21))) "\"Tal Umatar\" (evening)")))
760 "Component of the default value of `hebrew-holidays'.") 777 "Component of the default value of `hebrew-holidays'.")
761 ;;;###autoload 778 ;;;###autoload
762 (put 'hebrew-holidays-1 'risky-local-variable t) 779 (put 'hebrew-holidays-1 'risky-local-variable t)
763 780
764 ;;;###autoload 781 ;;;###autoload
771 10 788 10
772 (let ((h-year (extract-calendar-year 789 (let ((h-year (extract-calendar-year
773 (calendar-hebrew-from-absolute 790 (calendar-hebrew-from-absolute
774 (calendar-absolute-from-gregorian 791 (calendar-absolute-from-gregorian
775 (list displayed-month 28 displayed-year)))))) 792 (list displayed-month 28 displayed-year))))))
776 (if (= (% (calendar-absolute-from-hebrew (list 10 10 h-year)) 793 (if (= 6 (% (calendar-absolute-from-hebrew (list 10 10 h-year))
777 7) 794 7))
778 6)
779 11 10)) 795 11 10))
780 "Tzom Teveth")) 796 "Tzom Teveth"))
781 (if all-hebrew-calendar-holidays 797 (if all-hebrew-calendar-holidays
782 (holiday-hebrew 11 15 "Tu B'Shevat"))) 798 (holiday-hebrew 11 15 "Tu B'Shevat")))
783 "Component of the default value of `hebrew-holidays'.") 799 "Component of the default value of `hebrew-holidays'.")
798 (list m 814 (list m
799 (calendar-last-day-of-month m y) 815 (calendar-last-day-of-month m y)
800 y))))) 816 y)))))
801 (s-s 817 (s-s
802 (calendar-hebrew-from-absolute 818 (calendar-hebrew-from-absolute
803 (if (= 819 (if (= 6
804 (% (calendar-absolute-from-hebrew 820 (% (calendar-absolute-from-hebrew
805 (list 7 1 h-year)) 821 (list 7 1 h-year))
806 7) 822 7))
807 6)
808 (calendar-dayname-on-or-before 823 (calendar-dayname-on-or-before
809 6 (calendar-absolute-from-hebrew 824 6 (calendar-absolute-from-hebrew
810 (list 11 17 h-year))) 825 (list 11 17 h-year)))
811 (calendar-dayname-on-or-before 826 (calendar-dayname-on-or-before
812 6 (calendar-absolute-from-hebrew 827 6 (calendar-absolute-from-hebrew
820 835
821 ;;;###autoload 836 ;;;###autoload
822 (defvar hebrew-holidays-4 837 (defvar hebrew-holidays-4
823 '((holiday-passover-etc) 838 '((holiday-passover-etc)
824 (if (and all-hebrew-calendar-holidays 839 (if (and all-hebrew-calendar-holidays
825 (let* ((m displayed-month) 840 (let ((m displayed-month)
826 (y displayed-year) 841 (y displayed-year)
827 (year)) 842 year)
828 (increment-calendar-month m y -1) 843 (increment-calendar-month m y -1)
829 (let ((year (extract-calendar-year 844 (setq year (extract-calendar-year
830 (calendar-julian-from-absolute 845 (calendar-julian-from-absolute
831 (calendar-absolute-from-gregorian 846 (calendar-absolute-from-gregorian
832 (list m 1 y)))))) 847 (list m 1 y)))))
833 (= 21 (% year 28))))) 848 (= 21 (% year 28))))
834 (holiday-julian 3 26 "Kiddush HaHamah")) 849 (holiday-julian 3 26 "Kiddush HaHamah"))
835 (if all-hebrew-calendar-holidays 850 (if all-hebrew-calendar-holidays
836 (holiday-tisha-b-av-etc))) 851 (holiday-tisha-b-av-etc)))
837 "Component of the default value of `hebrew-holidays'.") 852 "Component of the default value of `hebrew-holidays'.")
838 ;;;###autoload 853 ;;;###autoload
1189 (cons mon yr)) 1204 (cons mon yr))
1190 1205
1191 (defmacro calendar-for-loop (var from init to final do &rest body) 1206 (defmacro calendar-for-loop (var from init to final do &rest body)
1192 "Execute a for loop. 1207 "Execute a for loop.
1193 Evaluate BODY with VAR bound to successive integers from INIT to FINAL, 1208 Evaluate BODY with VAR bound to successive integers from INIT to FINAL,
1194 inclusive." 1209 inclusive. The standard macro `dotimes' is preferable in most cases."
1195 (declare (debug (symbolp "from" form "to" form "do" body))) 1210 (declare (debug (symbolp "from" form "to" form "do" body)))
1196 `(let ((,var (1- ,init))) 1211 `(let ((,var (1- ,init)))
1197 (while (>= ,final (setq ,var (1+ ,var))) 1212 (while (>= ,final (setq ,var (1+ ,var)))
1198 ,@body))) 1213 ,@body)))
1199 1214
1200 (defmacro calendar-sum (index initial condition expression) 1215 (defmacro calendar-sum (index initial condition expression)
1201 "For INDEX = INITIAL et seq, as long as CONDITION holds, sum EXPRESSION." 1216 "For INDEX = INITIAL, +1, ... (as long as CONDITION holds), sum EXPRESSION."
1202 (declare (debug (symbolp form form form))) 1217 (declare (debug (symbolp form form form)))
1203 `(let ((,index ,initial) 1218 `(let ((,index ,initial)
1204 (sum 0)) 1219 (sum 0))
1205 (while ,condition 1220 (while ,condition
1206 (setq sum (+ sum ,expression)) 1221 (setq sum (+ sum ,expression)
1207 (setq ,index (1+ ,index))) 1222 ,index (1+ ,index)))
1208 sum)) 1223 sum))
1209 1224
1210 ;; The following are in-line for speed; they can be called thousands of times 1225 ;; The following are in-line for speed; they can be called thousands of times
1211 ;; when looking up holidays or processing the diary. Here, for example, are 1226 ;; when looking up holidays or processing the diary. Here, for example, are
1212 ;; the numbers of calls to calendar/diary/holiday functions in preparing the 1227 ;; the numbers of calls to calendar/diary/holiday functions in preparing the
1240 (car date)) 1255 (car date))
1241 1256
1242 ;; Note gives wrong answer for result of (calendar-read-date 'noday). 1257 ;; Note gives wrong answer for result of (calendar-read-date 'noday).
1243 (defsubst extract-calendar-day (date) 1258 (defsubst extract-calendar-day (date)
1244 "Extract the day part of DATE which has the form (month day year)." 1259 "Extract the day part of DATE which has the form (month day year)."
1245 (car (cdr date))) 1260 (cadr date))
1246 1261
1247 (defsubst extract-calendar-year (date) 1262 (defsubst extract-calendar-year (date)
1248 "Extract the year part of DATE which has the form (month day year)." 1263 "Extract the year part of DATE which has the form (month day year)."
1249 (car (cdr (cdr date)))) 1264 (nth 2 date))
1250 1265
1251 (defsubst calendar-leap-year-p (year) 1266 (defsubst calendar-leap-year-p (year)
1252 "Return t if YEAR is a Gregorian leap year. 1267 "Return t if YEAR is a Gregorian leap year.
1253 A negative year is interpreted as BC; -1 being 1 BC, and so on." 1268 A negative year is interpreted as BC; -1 being 1 BC, and so on."
1254 ;; 1 BC = 0 AD, 2 BC acts like 1 AD, etc. 1269 ;; 1 BC = 0 AD, 2 BC acts like 1 AD, etc.
1277 1292
1278 (defsubst calendar-day-number (date) 1293 (defsubst calendar-day-number (date)
1279 "Return the day number within the year of the date DATE. 1294 "Return the day number within the year of the date DATE.
1280 For example, (calendar-day-number '(1 1 1987)) returns the value 1, 1295 For example, (calendar-day-number '(1 1 1987)) returns the value 1,
1281 while (calendar-day-number '(12 31 1980)) returns 366." 1296 while (calendar-day-number '(12 31 1980)) returns 366."
1282 (let* ((month (extract-calendar-month date)) 1297 (let* ((month (extract-calendar-month date))
1283 (day (extract-calendar-day date)) 1298 (day (extract-calendar-day date))
1284 (year (extract-calendar-year date)) 1299 (year (extract-calendar-year date))
1285 (day-of-year (+ day (* 31 (1- month))))) 1300 (day-of-year (+ day (* 31 (1- month)))))
1286 (if (> month 2) 1301 (when (> month 2)
1287 (progn 1302 (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10)))
1288 (setq day-of-year (- day-of-year (/ (+ 23 (* 4 month)) 10))) 1303 (if (calendar-leap-year-p year)
1289 (if (calendar-leap-year-p year) 1304 (setq day-of-year (1+ day-of-year))))
1290 (setq day-of-year (1+ day-of-year))))) 1305 day-of-year))
1291 day-of-year))
1292 1306
1293 (defsubst calendar-absolute-from-gregorian (date) 1307 (defsubst calendar-absolute-from-gregorian (date)
1294 "The number of days elapsed between the Gregorian date 12/31/1 BC and DATE. 1308 "The number of days elapsed between the Gregorian date 12/31/1 BC and DATE.
1295 The Gregorian date Sunday, December 31, 1 BC is imaginary. 1309 The Gregorian date Sunday, December 31, 1 BC is imaginary.
1296 DATE is a list of the form (month day year). A negative year is 1310 DATE is a list of the form (month day year). A negative year is
1376 (interactive "P") 1390 (interactive "P")
1377 (set-buffer (get-buffer-create calendar-buffer)) 1391 (set-buffer (get-buffer-create calendar-buffer))
1378 (calendar-mode) 1392 (calendar-mode)
1379 (let* ((pop-up-windows t) 1393 (let* ((pop-up-windows t)
1380 (split-height-threshold 1000) 1394 (split-height-threshold 1000)
1381 (date (if arg 1395 (date (if arg (calendar-read-date t)
1382 (calendar-read-date t)
1383 (calendar-current-date))) 1396 (calendar-current-date)))
1384 (month (extract-calendar-month date)) 1397 (month (extract-calendar-month date))
1385 (year (extract-calendar-year date))) 1398 (year (extract-calendar-year date)))
1386 ;; (calendar-read-date t) returns a date with day = nil, which is 1399 ;; (calendar-read-date t) returns a date with day = nil, which is
1387 ;; not a valid date for the visible test in the diary section. 1400 ;; not a valid date for the visible test in the diary section.
1463 "Produce a calendar for MONTH, YEAR on the Gregorian calendar. 1476 "Produce a calendar for MONTH, YEAR on the Gregorian calendar.
1464 The calendar is inserted at the top of the buffer in which point is currently 1477 The calendar is inserted at the top of the buffer in which point is currently
1465 located, but indented INDENT spaces. The indentation is done from the first 1478 located, but indented INDENT spaces. The indentation is done from the first
1466 character on the line and does not disturb the first INDENT characters on the 1479 character on the line and does not disturb the first INDENT characters on the
1467 line." 1480 line."
1468 (let* ((blank-days ; at start of month 1481 (let ((blank-days ; at start of month
1469 (mod 1482 (mod
1470 (- (calendar-day-of-week (list month 1 year)) 1483 (- (calendar-day-of-week (list month 1 year))
1471 calendar-week-start-day) 1484 calendar-week-start-day)
1472 7)) 1485 7))
1473 (last (calendar-last-day-of-month month year))) 1486 (last (calendar-last-day-of-month month year)))
1474 (goto-char (point-min)) 1487 (goto-char (point-min))
1475 (calendar-insert-indented 1488 (calendar-insert-indented
1476 (calendar-string-spread 1489 (calendar-string-spread
1477 (list (format "%s %d" (calendar-month-name month) year)) ? 20) 1490 (list (format "%s %d" (calendar-month-name month) year)) ? 20)
1489 (calendar-insert-indented "" 0 t) ; force onto following line 1502 (calendar-insert-indented "" 0 t) ; force onto following line
1490 (calendar-insert-indented "" indent) ; go to proper spot 1503 (calendar-insert-indented "" indent) ; go to proper spot
1491 ;; Add blank days before the first of the month. 1504 ;; Add blank days before the first of the month.
1492 (dotimes (idummy blank-days) (insert " ")) 1505 (dotimes (idummy blank-days) (insert " "))
1493 ;; Put in the days of the month. 1506 ;; Put in the days of the month.
1494 (calendar-for-loop i from 1 to last do 1507 (dotimes (i last)
1495 (insert (format "%2d " i)) 1508 (insert (format "%2d " (1+ i)))
1496 (add-text-properties 1509 (add-text-properties
1497 (- (point) 3) (1- (point)) 1510 (- (point) 3) (1- (point))
1498 '(mouse-face highlight 1511 '(mouse-face highlight
1499 help-echo "mouse-2: menu of operations for this date")) 1512 help-echo "mouse-2: menu of operations for this date"))
1500 (and (zerop (mod (+ i blank-days) 7)) 1513 (and (zerop (mod (+ i 1 blank-days) 7))
1501 (/= i last) 1514 (/= i (1- last))
1502 (calendar-insert-indented "" 0 t) ; force onto following line 1515 (calendar-insert-indented "" 0 t) ; force onto following line
1503 (calendar-insert-indented "" indent))))) ; go to proper spot 1516 (calendar-insert-indented "" indent))))) ; go to proper spot
1504 1517
1505 (defun calendar-insert-indented (string indent &optional newline) 1518 (defun calendar-insert-indented (string indent &optional newline)
1506 "Insert STRING at column INDENT. 1519 "Insert STRING at column INDENT.
1507 If the optional parameter NEWLINE is t, leave point at start of next line, 1520 If the optional parameter NEWLINE is non-nil, leave point at start of next
1508 inserting a newline if there was no next line; otherwise, leave point after 1521 line, inserting a newline if there was no next line; otherwise, leave point
1509 the inserted text. Returns t." 1522 after the inserted text. Returns t."
1510 ;; Try to move to that column. 1523 ;; Try to move to that column.
1511 (move-to-column indent) 1524 (move-to-column indent)
1512 ;; If line is too short, indent out to that column. 1525 ;; If line is too short, indent out to that column.
1513 (if (< (current-column) indent) 1526 (if (< (current-column) indent)
1514 (indent-to indent)) 1527 (indent-to indent))
1756 \"\"))" 1769 \"\"))"
1757 :type 'sexp 1770 :type 'sexp
1758 :group 'calendar) 1771 :group 'calendar)
1759 1772
1760 (defun mouse-calendar-other-month (event) 1773 (defun mouse-calendar-other-month (event)
1761 "Display a three-month calendar centered around a specified month and year." 1774 "Display a three-month calendar centered around a specified month and year.
1775 EVENT is the last mouse event."
1762 (interactive "e") 1776 (interactive "e")
1763 (save-selected-window 1777 (save-selected-window
1764 (select-window (posn-window (event-start event))) 1778 (select-window (posn-window (event-start event)))
1765 (call-interactively 'calendar-other-month))) 1779 (call-interactively 'calendar-other-month)))
1766 1780
1862 buffs)) 1876 buffs))
1863 1877
1864 (defun exit-calendar () 1878 (defun exit-calendar ()
1865 "Get out of the calendar window and hide it and related buffers." 1879 "Get out of the calendar window and hide it and related buffers."
1866 (interactive) 1880 (interactive)
1867 (let* ((diary-buffer (get-file-buffer diary-file))) 1881 (let ((diary-buffer (get-file-buffer diary-file)))
1868 (if (or (not diary-buffer) 1882 (if (or (not diary-buffer)
1869 (not (buffer-modified-p diary-buffer)) 1883 (not (buffer-modified-p diary-buffer))
1870 (yes-or-no-p 1884 (yes-or-no-p
1871 "Diary modified; do you really want to exit the calendar? ")) 1885 "Diary modified; do you really want to exit the calendar? "))
1872 ;; Need to do this multiple times because one time can replace some 1886 ;; Need to do this multiple times because one time can replace some
1900 (list (nth 4 now) (nth 3 now) (nth 5 now)))) 1914 (list (nth 4 now) (nth 3 now) (nth 5 now))))
1901 1915
1902 (defun calendar-cursor-to-date (&optional error) 1916 (defun calendar-cursor-to-date (&optional error)
1903 "Return a list (month day year) of current cursor position. 1917 "Return a list (month day year) of current cursor position.
1904 If cursor is not on a specific date, signals an error if optional parameter 1918 If cursor is not on a specific date, signals an error if optional parameter
1905 ERROR is t, otherwise just returns nil." 1919 ERROR is non-nil, otherwise just returns nil."
1906 (let* ((segment (/ (current-column) 25)) 1920 (let* ((segment (/ (current-column) 25))
1907 (month (% (+ displayed-month segment -1) 12)) 1921 (month (% (+ displayed-month segment -1) 12))
1908 (month (if (zerop month) 12 month)) 1922 (month (if (zerop month) 12 month))
1909 (year 1923 (year
1910 (cond 1924 (cond
2000 "Mark the date under the cursor, or jump to marked date. 2014 "Mark the date under the cursor, or jump to marked date.
2001 With no prefix argument, push current date onto marked date ring. 2015 With no prefix argument, push current date onto marked date ring.
2002 With argument ARG, jump to mark, pop it, and put point at end of ring." 2016 With argument ARG, jump to mark, pop it, and put point at end of ring."
2003 (interactive "P") 2017 (interactive "P")
2004 (let ((date (calendar-cursor-to-date t))) 2018 (let ((date (calendar-cursor-to-date t)))
2005 (if (null arg) 2019 (if arg
2006 (progn 2020 (if (null calendar-mark-ring)
2007 (push date calendar-mark-ring) 2021 (error "No mark set in this buffer")
2008 ;; Since the top of the mark ring is the marked date in the 2022 (calendar-goto-date (car calendar-mark-ring))
2009 ;; calendar, the mark ring in the calendar is one longer than 2023 (setq calendar-mark-ring
2010 ;; in other buffers to get the same effect. 2024 (cdr (nconc calendar-mark-ring (list date)))))
2011 (if (> (length calendar-mark-ring) (1+ mark-ring-max)) 2025 (push date calendar-mark-ring)
2012 (setcdr (nthcdr mark-ring-max calendar-mark-ring) nil)) 2026 ;; Since the top of the mark ring is the marked date in the
2013 (message "Mark set")) 2027 ;; calendar, the mark ring in the calendar is one longer than
2014 (if (null calendar-mark-ring) 2028 ;; in other buffers to get the same effect.
2015 (error "No mark set in this buffer") 2029 (if (> (length calendar-mark-ring) (1+ mark-ring-max))
2016 (calendar-goto-date (car calendar-mark-ring)) 2030 (setcdr (nthcdr mark-ring-max calendar-mark-ring) nil))
2017 (setq calendar-mark-ring 2031 (message "Mark set"))))
2018 (cdr (nconc calendar-mark-ring (list date))))))))
2019 2032
2020 (defun calendar-exchange-point-and-mark () 2033 (defun calendar-exchange-point-and-mark ()
2021 "Exchange the current cursor position with the marked date." 2034 "Exchange the current cursor position with the marked date."
2022 (interactive) 2035 (interactive)
2023 (let ((mark (car calendar-mark-ring)) 2036 (let ((mark (car calendar-mark-ring))
2093 file. Do not include a trailing `.' in the strings specified in 2106 file. Do not include a trailing `.' in the strings specified in
2094 this variable, though you may use such in the diary file. If any 2107 this variable, though you may use such in the diary file. If any
2095 element of this array is nil, then the abbreviation will be 2108 element of this array is nil, then the abbreviation will be
2096 constructed as the first `calendar-abbrev-length' characters of the 2109 constructed as the first `calendar-abbrev-length' characters of the
2097 corresponding full name.") 2110 corresponding full name.")
2098
2099
2100 (defun calendar-read-date (&optional noday)
2101 "Prompt for Gregorian date. Return a list (month day year).
2102 If optional NODAY is t, does not ask for day, but just returns
2103 \(month nil year); if NODAY is any other non-nil value the value returned is
2104 \(month year)"
2105 (let* ((year (calendar-read
2106 "Year (>0): "
2107 (lambda (x) (> x 0))
2108 (int-to-string (extract-calendar-year
2109 (calendar-current-date)))))
2110 (month-array calendar-month-name-array)
2111 (completion-ignore-case t)
2112 (month (cdr (assoc-string
2113 (completing-read
2114 "Month name: "
2115 (mapcar 'list (append month-array nil))
2116 nil t)
2117 (calendar-make-alist month-array 1) t)))
2118 (last (calendar-last-day-of-month month year)))
2119 (if noday
2120 (if (eq noday t)
2121 (list month nil year)
2122 (list month year))
2123 (list month
2124 (calendar-read (format "Day (1-%d): " last)
2125 (lambda (x) (and (< 0 x) (<= x last))))
2126 year))))
2127
2128 (defun calendar-interval (mon1 yr1 mon2 yr2)
2129 "The number of months difference between MON1, YR1 and MON2, YR2.
2130 The result is positive if the second date is later than the first.
2131 Negative years are interpreted as years BC; -1 being 1 BC, and so on."
2132 (if (< yr1 0) (setq yr1 (1+ yr1))) ; -1 BC -> 0 AD, etc
2133 (if (< yr2 0) (setq yr2 (1+ yr2)))
2134 (+ (* 12 (- yr2 yr1))
2135 (- mon2 mon1)))
2136
2137 (defun calendar-abbrev-construct (abbrev full &optional period)
2138 "Internal calendar function to return a complete abbreviation array.
2139 ABBREV is an array of abbreviations, FULL the corresponding array
2140 of full names. The return value is the ABBREV array, with any nil
2141 elements replaced by the first three characters taken from the
2142 corresponding element of FULL. If optional argument PERIOD is non-nil,
2143 each element returned has a final `.' character."
2144 (let (elem array name)
2145 (dotimes (i (length full))
2146 (setq name (aref full i)
2147 elem (or (aref abbrev i)
2148 (substring name 0
2149 (min calendar-abbrev-length (length name))))
2150 elem (format "%s%s" elem (if period "." ""))
2151 array (append array (list elem))))
2152 (vconcat array)))
2153
2154 (defvar calendar-font-lock-keywords
2155 `((,(concat (regexp-opt (mapcar 'identity calendar-month-name-array) t)
2156 " -?[0-9]+")
2157 . font-lock-function-name-face) ; month and year
2158 (,(regexp-opt
2159 (list (substring (aref calendar-day-name-array 6) 0 2)
2160 (substring (aref calendar-day-name-array 0) 0 2)))
2161 ;; Saturdays and Sundays are highlighted differently.
2162 . font-lock-comment-face)
2163 ;; First two chars of each day are used in the calendar.
2164 (,(regexp-opt (mapcar (lambda (x) (substring x 0 2))
2165 calendar-day-name-array))
2166 . font-lock-reference-face))
2167 "Default keywords to highlight in Calendar mode.")
2168
2169 (defun calendar-day-name (date &optional abbrev absolute)
2170 "Return a string with the name of the day of the week of DATE.
2171 DATE should be a list in the format (MONTH DAY YEAR), unless the
2172 optional argument ABSOLUTE is non-nil, in which case DATE should
2173 be an integer in the range 0 to 6 corresponding to the day of the
2174 week. Day names are taken from the variable `calendar-day-name-array',
2175 unless the optional argument ABBREV is non-nil, in which case
2176 the variable `calendar-day-abbrev-array' is used."
2177 (aref (if abbrev
2178 (calendar-abbrev-construct calendar-day-abbrev-array
2179 calendar-day-name-array)
2180 calendar-day-name-array)
2181 (if absolute date (calendar-day-of-week date))))
2182 2111
2183 (defun calendar-make-alist (sequence &optional start-index filter abbrevs) 2112 (defun calendar-make-alist (sequence &optional start-index filter abbrevs)
2184 "Make an assoc list corresponding to SEQUENCE. 2113 "Make an assoc list corresponding to SEQUENCE.
2185 Each element of sequence will be associated with an integer, starting 2114 Each element of sequence will be associated with an integer, starting
2186 from 1, or from START-INDEX if that is non-nil. If a sequence ABBREVS 2115 from 1, or from START-INDEX if that is non-nil. If a sequence ABBREVS
2206 index) alist))) 2135 index) alist)))
2207 (if aseqp 2136 (if aseqp
2208 (setq elem (elt aseqp i) 2137 (setq elem (elt aseqp i)
2209 alist (cons (cons (if filter (funcall filter elem) elem) 2138 alist (cons (cons (if filter (funcall filter elem) elem)
2210 index) alist)))))) 2139 index) alist))))))
2140
2141 (defun calendar-read-date (&optional noday)
2142 "Prompt for Gregorian date. Return a list (month day year).
2143 If optional NODAY is t, does not ask for day, but just returns
2144 \(month nil year); if NODAY is any other non-nil value the value returned is
2145 \(month year)"
2146 (let* ((year (calendar-read
2147 "Year (>0): "
2148 (lambda (x) (> x 0))
2149 (int-to-string (extract-calendar-year
2150 (calendar-current-date)))))
2151 (month-array calendar-month-name-array)
2152 (completion-ignore-case t)
2153 (month (cdr (assoc-string
2154 (completing-read
2155 "Month name: "
2156 (mapcar 'list (append month-array nil))
2157 nil t)
2158 (calendar-make-alist month-array 1) t)))
2159 (last (calendar-last-day-of-month month year)))
2160 (if noday
2161 (if (eq noday t)
2162 (list month nil year)
2163 (list month year))
2164 (list month
2165 (calendar-read (format "Day (1-%d): " last)
2166 (lambda (x) (and (< 0 x) (<= x last))))
2167 year))))
2168
2169 (defun calendar-interval (mon1 yr1 mon2 yr2)
2170 "The number of months difference between MON1, YR1 and MON2, YR2.
2171 The result is positive if the second date is later than the first.
2172 Negative years are interpreted as years BC; -1 being 1 BC, and so on."
2173 (if (< yr1 0) (setq yr1 (1+ yr1))) ; -1 BC -> 0 AD, etc
2174 (if (< yr2 0) (setq yr2 (1+ yr2)))
2175 (+ (* 12 (- yr2 yr1))
2176 (- mon2 mon1)))
2177
2178 (defun calendar-abbrev-construct (abbrev full &optional period)
2179 "Internal calendar function to return a complete abbreviation array.
2180 ABBREV is an array of abbreviations, FULL the corresponding array
2181 of full names. The return value is the ABBREV array, with any nil
2182 elements replaced by the first three characters taken from the
2183 corresponding element of FULL. If optional argument PERIOD is non-nil,
2184 each element returned has a final `.' character."
2185 (let (elem array name)
2186 (dotimes (i (length full))
2187 (setq name (aref full i)
2188 elem (or (aref abbrev i)
2189 (substring name 0
2190 (min calendar-abbrev-length (length name))))
2191 elem (format "%s%s" elem (if period "." ""))
2192 array (append array (list elem))))
2193 (vconcat array)))
2194
2195 (defvar calendar-font-lock-keywords
2196 `((,(concat (regexp-opt (mapcar 'identity calendar-month-name-array) t)
2197 " -?[0-9]+")
2198 . font-lock-function-name-face) ; month and year
2199 (,(regexp-opt
2200 (list (substring (aref calendar-day-name-array 6) 0 2)
2201 (substring (aref calendar-day-name-array 0) 0 2)))
2202 ;; Saturdays and Sundays are highlighted differently.
2203 . font-lock-comment-face)
2204 ;; First two chars of each day are used in the calendar.
2205 (,(regexp-opt (mapcar (lambda (x) (substring x 0 2))
2206 calendar-day-name-array))
2207 . font-lock-reference-face))
2208 "Default keywords to highlight in Calendar mode.")
2209
2210 (defun calendar-day-name (date &optional abbrev absolute)
2211 "Return a string with the name of the day of the week of DATE.
2212 DATE should be a list in the format (MONTH DAY YEAR), unless the
2213 optional argument ABSOLUTE is non-nil, in which case DATE should
2214 be an integer in the range 0 to 6 corresponding to the day of the
2215 week. Day names are taken from the variable `calendar-day-name-array',
2216 unless the optional argument ABBREV is non-nil, in which case
2217 the variable `calendar-day-abbrev-array' is used."
2218 (aref (if abbrev
2219 (calendar-abbrev-construct calendar-day-abbrev-array
2220 calendar-day-name-array)
2221 calendar-day-name-array)
2222 (if absolute date (calendar-day-of-week date))))
2211 2223
2212 (defun calendar-month-name (month &optional abbrev) 2224 (defun calendar-month-name (month &optional abbrev)
2213 "Return a string with the name of month number MONTH. 2225 "Return a string with the name of month number MONTH.
2214 Months are numbered from one. Month names are taken from the 2226 Months are numbered from one. Month names are taken from the
2215 variable `calendar-month-name-array', unless the optional 2227 variable `calendar-month-name-array', unless the optional
2352 An optional parameter ABBREVIATE, when non-nil, causes the month 2364 An optional parameter ABBREVIATE, when non-nil, causes the month
2353 and day names to be abbreviated as specified by 2365 and day names to be abbreviated as specified by
2354 `calendar-month-abbrev-array' and `calendar-day-abbrev-array', 2366 `calendar-month-abbrev-array' and `calendar-day-abbrev-array',
2355 respectively. An optional parameter NODAYNAME, when t, omits the 2367 respectively. An optional parameter NODAYNAME, when t, omits the
2356 name of the day of the week." 2368 name of the day of the week."
2357 (let* ((dayname 2369 (let* ((dayname (unless nodayname (calendar-day-name date abbreviate)))
2358 (unless nodayname
2359 (calendar-day-name date abbreviate)))
2360 (month (extract-calendar-month date)) 2370 (month (extract-calendar-month date))
2361 (monthname (calendar-month-name month abbreviate)) 2371 (monthname (calendar-month-name month abbreviate))
2362 (day (int-to-string (extract-calendar-day date))) 2372 (day (int-to-string (extract-calendar-day date)))
2363 (month (int-to-string month)) 2373 (month (int-to-string month))
2364 (year (int-to-string (extract-calendar-year date)))) 2374 (year (int-to-string (extract-calendar-year date))))
2416 day year days-remaining (if (= days-remaining 1) "" "s")))) 2426 day year days-remaining (if (= days-remaining 1) "" "s"))))
2417 2427
2418 (defun calendar-print-other-dates () 2428 (defun calendar-print-other-dates ()
2419 "Show dates on other calendars for date under the cursor." 2429 "Show dates on other calendars for date under the cursor."
2420 (interactive) 2430 (interactive)
2421 (let* ((date (calendar-cursor-to-date t))) 2431 (let ((date (calendar-cursor-to-date t)))
2422 (with-current-buffer (get-buffer-create other-calendars-buffer) 2432 (with-current-buffer (get-buffer-create other-calendars-buffer)
2423 (let ((inhibit-read-only t) 2433 (let ((inhibit-read-only t)
2424 (modified (buffer-modified-p))) 2434 (modified (buffer-modified-p)))
2425 (calendar-set-mode-line 2435 (calendar-set-mode-line
2426 (concat (calendar-date-string date) " (Gregorian)")) 2436 (concat (calendar-date-string date) " (Gregorian)"))
2471 2481
2472 (defun calendar-set-mode-line (str) 2482 (defun calendar-set-mode-line (str)
2473 "Set mode line to STR, centered, surrounded by dashes." 2483 "Set mode line to STR, centered, surrounded by dashes."
2474 (let* ((edges (window-edges)) 2484 (let* ((edges (window-edges))
2475 ;; As per doc of window-width, total visible mode-line length. 2485 ;; As per doc of window-width, total visible mode-line length.
2476 (width (- (nth 2 edges) (nth 0 edges)))) 2486 (width (- (nth 2 edges) (car edges))))
2477 (setq mode-line-format 2487 (setq mode-line-format
2478 (if buffer-file-name 2488 (if buffer-file-name
2479 `("-" mode-line-modified 2489 `("-" mode-line-modified
2480 ,(calendar-string-spread (list str) ?- (- width 6)) 2490 ,(calendar-string-spread (list str) ?- (- width 6))
2481 "---") 2491 "---")