Annotation of GNUtools/emacs/lisp/cal.el, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.