;;; diary-lib.el --- diary functions
;; Copyright (C) 1989, 1990, 1992, 1993, 1994, 1995, 2001, 2002, 2003,
-;; 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+;; 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
;; Maintainer: Glenn Morris <rgm@gnu.org>
;; GNU Emacs is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; This collection of functions implements the diary features as described
;; in calendar.el.
-;; Comments, corrections, and improvements should be sent to
-;; Edward M. Reingold Department of Computer Science
-;; (217) 333-6733 University of Illinois at Urbana-Champaign
-;; reingold@cs.uiuc.edu 1304 West Springfield Avenue
-;; Urbana, Illinois 61801
-
;;; Code:
(require 'calendar)
+(defcustom diary-include-string "#include"
+ "The string indicating inclusion of another file of diary entries.
+See the documentation for the function `include-other-diary-files'."
+ :type 'string
+ :group 'diary)
+
+(defcustom diary-list-include-blanks nil
+ "If nil, do not include days with no diary entry in the list of diary entries.
+Such days will then not be shown in the fancy diary buffer, even if they
+are holidays."
+ :type 'boolean
+ :group 'diary)
+
+(defcustom diary-glob-file-regexp-prefix "^\\#"
+ "Regular expression prepended to attribute-regexps for file-wide specifiers."
+ :type 'regexp
+ :group 'diary)
+
+(defcustom diary-face 'diary
+ "Face name to use for diary entries."
+ :type 'face
+ :group 'diary)
+(make-obsolete-variable 'diary-face "customize the face `diary' instead."
+ "23.1")
+
+(defcustom diary-face-attrs
+ '((" *\\[foreground:\\([-a-z]+\\)\\]$" 1 :foreground string)
+ (" *\\[background:\\([-a-z]+\\)\\]$" 1 :background string)
+ (" *\\[width:\\([-a-z]+\\)\\]$" 1 :width symbol)
+ (" *\\[height:\\([-0-9a-z]+\\)\\]$" 1 :height int)
+ (" *\\[weight:\\([-a-z]+\\)\\]$" 1 :weight symbol)
+ (" *\\[slant:\\([-a-z]+\\)\\]$" 1 :slant symbol)
+ (" *\\[underline:\\([-a-z]+\\)\\]$" 1 :underline stringtnil)
+ (" *\\[overline:\\([-a-z]+\\)\\]$" 1 :overline stringtnil)
+ (" *\\[strike-through:\\([-a-z]+\\)\\]$" 1 :strike-through stringtnil)
+ (" *\\[inverse-video:\\([-a-z]+\\)\\]$" 1 :inverse-video tnil)
+ (" *\\[face:\\([-0-9a-z]+\\)\\]$" 1 :face string)
+ (" *\\[font:\\([-a-z0-9]+\\)\\]$" 1 :font string)
+ ;; Unsupported.
+;;; (" *\\[box:\\([-a-z]+\\)\\]$" 1 :box)
+;;; (" *\\[stipple:\\([-a-z]+\\)\\]$" 1 :stipple)
+ )
+ "A list of (regexp regnum attr attrtype) lists where the
+regexp says how to find the tag, the regnum says which
+parenthetical sub-regexp this regexp looks for, and the attr says
+which attribute of the face (or that this _is_ a face) is being
+modified."
+ :type 'sexp
+ :group 'diary)
+
+(defcustom diary-file-name-prefix nil
+ "Non-nil means prefix each diary entry with the name of the file defining it."
+ :type 'boolean
+ :group 'diary)
+
+(defcustom diary-file-name-prefix-function 'identity
+ "The function that will take a diary file name and return the desired prefix."
+ :type 'function
+ :group 'diary)
+
+(defcustom sexp-diary-entry-symbol "%%"
+ "The string used to indicate a sexp diary entry in `diary-file'.
+See the documentation for the function `list-sexp-diary-entries'."
+ :type 'string
+ :group 'diary)
+
+(defcustom list-diary-entries-hook nil
+ "List of functions called after diary file is culled for relevant entries.
+It is to be used for diary entries that are not found in the diary file.
+
+A function `include-other-diary-files' is provided for use as the value of
+this hook. This function enables you to use shared diary files together
+with your own. The files included are specified in the diary file by lines
+of the form
+
+ #include \"filename\"
+
+This is recursive; that is, #include directives in files thus included are
+obeyed. You can change the \"#include\" to some other string by changing
+the variable `diary-include-string'. When you use `include-other-diary-files'
+as part of the list-diary-entries-hook, you will probably also want to use the
+function `mark-included-diary-files' as part of `mark-diary-entries-hook'.
+
+For example, you could use
+
+ (add-hook 'list-diary-entries-hook 'include-other-diary-files)
+ (add-hook 'list-diary-entries-hook 'sort-diary-entries)
+ (add-hook 'diary-display-hook 'fancy-diary-display)
+
+in your `.emacs' file to cause the fancy diary buffer to be displayed with
+diary entries from various included files, each day's entries sorted into
+lexicographic order."
+ :type 'hook
+ :options '(include-other-diary-files sort-diary-entries)
+ :group 'diary)
+
+(defcustom mark-diary-entries-hook nil
+ "List of functions called after marking diary entries in the calendar.
+
+A function `mark-included-diary-files' is also provided for use as the
+`mark-diary-entries-hook'; it enables you to use shared diary files together
+with your own. The files included are specified in the diary file by lines
+of the form
+ #include \"filename\"
+This is recursive; that is, #include directives in files thus included are
+obeyed. You can change the \"#include\" to some other string by changing the
+variable `diary-include-string'. When you use `mark-included-diary-files' as
+part of the mark-diary-entries-hook, you will probably also want to use the
+function `include-other-diary-files' as part of `list-diary-entries-hook'."
+ :type 'hook
+ :options '(mark-included-diary-files)
+ :group 'diary)
+
+(defcustom nongregorian-diary-listing-hook nil
+ "List of functions called for listing diary file and included files.
+As the files are processed for diary entries, these functions are used
+to cull relevant entries. You can use either or both of
+`list-hebrew-diary-entries', `list-islamic-diary-entries' and
+`diary-bahai-list-entries'. The documentation for these functions
+describes the style of such diary entries."
+ :type 'hook
+ :options '(list-hebrew-diary-entries
+ list-islamic-diary-entries
+ diary-bahai-list-entries)
+ :group 'diary)
+
+(defcustom nongregorian-diary-marking-hook nil
+ "List of functions called for marking diary file and included files.
+As the files are processed for diary entries, these functions are used
+to cull relevant entries. You can use either or both of
+`mark-hebrew-diary-entries', `mark-islamic-diary-entries' and
+`mark-bahai-diary-entries'. The documentation for these functions
+describes the style of such diary entries."
+ :type 'hook
+ :options '(mark-hebrew-diary-entries
+ mark-islamic-diary-entries
+ diary-bahai-mark-entries)
+ :group 'diary)
+
+(defcustom print-diary-entries-hook 'lpr-buffer
+ "List of functions called after a temporary diary buffer is prepared.
+The buffer shows only the diary entries currently visible in the diary
+buffer. The default just does the printing. Other uses might include, for
+example, rearranging the lines into order by day and time, saving the buffer
+instead of deleting it, or changing the function used to do the printing."
+ :type 'hook
+ :group 'diary)
+
+(defcustom diary-unknown-time -9999
+ "Value returned by diary-entry-time when no time is found.
+The default value -9999 causes entries with no recognizable time to be placed
+before those with times; 9999 would place entries with no recognizable time
+after those with times."
+ :type 'integer
+ :group 'diary
+ :version "20.3")
+
+(defcustom diary-mail-addr
+ (if (boundp 'user-mail-address) user-mail-address "")
+ "Email address that `diary-mail-entries' will send email to."
+ :group 'diary
+ :type 'string
+ :version "20.3")
+
+(defcustom diary-mail-days 7
+ "Default number of days for `diary-mail-entries' to check."
+ :group 'diary
+ :type 'integer
+ :version "20.3")
+
+(defcustom diary-remind-message
+ '("Reminder: Only "
+ (if (= 0 (% days 7))
+ (concat (int-to-string (/ days 7)) (if (= 7 days) " week" " weeks"))
+ (concat (int-to-string days) (if (= 1 days) " day" " days")))
+ " until "
+ diary-entry)
+ "Pseudo-pattern giving form of reminder messages in the fancy diary display.
+
+Used by the function `diary-remind', a pseudo-pattern is a list of
+expressions that can involve the keywords `days' (a number), `date' (a list of
+month, day, year), and `diary-entry' (a string)."
+ :type 'sexp
+ :group 'diary)
+
+(defcustom diary-outlook-formats
+ '(
+ ;; When: 11 October 2001 12:00-14:00 (GMT) Greenwich Mean Time : Dublin, ...
+ ;; [Current UK format? The timezone is meaningless. Sometimes the
+ ;; Where is missing.]
+ ("When: \\([0-9]+ [[:alpha:]]+ [0-9]+\\) \
+\\([^ ]+\\) [^\n]+
+\[^\n]+
+\\(?:Where: \\([^\n]+\\)\n+\\)?
+\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*"
+ . "\\1\n \\2 %s, \\3")
+ ;; When: Tuesday, April 30, 2002 03:00 PM-03:30 PM (GMT) Greenwich Mean ...
+ ;; [Old UK format?]
+ ("^When: [[:alpha:]]+, \\([[:alpha:]]+\\) \\([0-9][0-9]*\\), \\([0-9]\\{4\\}\\) \
+\\([^ ]+\\) [^\n]+
+\[^\n]+
+\\(?:Where: \\([^\n]+\\)\\)?\n+"
+ . "\\2 \\1 \\3\n \\4 %s, \\5")
+ (
+ ;; German format, apparently.
+ "^Zeit: [^ ]+, +\\([0-9]+\\)\. +\\([[:upper:]][[:lower:]][[:lower:]]\\)[^ ]* +\\([0-9]+\\) +\\([^ ]+\\).*$"
+ . "\\1 \\2 \\3\n \\4 %s"))
+ "Alist of regexps matching message text and replacement text.
+
+The regexp must match the start of the message text containing an
+appointment, but need not include a leading `^'. If it matches the
+current message, a diary entry is made from the corresponding
+template. If the template is a string, it should be suitable for
+passing to `replace-match', and so will have occurrences of `\\D' to
+substitute the match for the Dth subexpression. It must also contain
+a single `%s' which will be replaced with the text of the message's
+Subject field. Any other `%' characters must be doubled, so that the
+template can be passed to `format'.
+
+If the template is actually a function, it is called with the message
+body text as argument, and may use `match-string' etc. to make a
+template following the rules above."
+ :type '(alist :key-type (regexp :tag "Regexp matching time/place")
+ :value-type (choice
+ (string :tag "Template for entry")
+ (function :tag
+ "Unary function providing template")))
+ :version "22.1"
+ :group 'diary)
+
+;;; More user options below and in calendar.el.
+
+
(defun diary-check-diary-file ()
"Check that the file specified by `diary-file' exists and is readable.
If so, return the expanded file name, otherwise signal an error."
(let ((diary-file d-file))
(diary-view-entries arg)))
-(autoload 'check-calendar-holidays "holidays"
+(autoload 'calendar-check-holidays "holidays"
"Check the list of holidays for any that occur on DATE.
The value returned is a list of strings of relevant holiday descriptions.
The holidays are those in the list `calendar-holidays'.")
(autoload 'diary-bahai-date "cal-bahai"
"Baha'i calendar equivalent of date diary entry.")
-(autoload 'list-bahai-diary-entries "cal-bahai"
+(autoload 'diary-bahai-list-entries "cal-bahai"
"Add any Baha'i date entries from the diary file to `diary-entries-list'.")
-(autoload 'mark-bahai-diary-entries "cal-bahai"
+(autoload 'diary-bahai-mark-entries "cal-bahai"
"Mark days in the calendar window that have Baha'i date diary entries.")
-(autoload 'mark-bahai-calendar-date-pattern "cal-bahai"
+(autoload 'calendar-bahai-mark-date-pattern "cal-bahai"
"Mark dates in calendar window that conform to Baha'i date MONTH/DAY/YEAR.")
(autoload 'diary-hebrew-date "cal-hebrew"
(defvar diary-entries-list)
(defvar displayed-year)
(defvar displayed-month)
-(defvar entry)
(defvar date)
(defvar number)
(defvar date-string)
(setq attr-list (cdr attr-list)))))
(list entry ret-attr))))
+(defun diary-set-maybe-redraw (symbol value)
+ "Set SYMBOL's value to VALUE, and redraw the diary if necessary.
+Redraws the diary if it is being displayed (note this is not the same as
+just visiting the `diary-file'), and SYMBOL's value is to be changed."
+ (let ((oldvalue (eval symbol)))
+ (custom-set-default symbol value)
+ (and (not (equal value oldvalue))
+ (diary-live-p)
+ ;; Note this assumes diary was called without prefix arg.
+ (diary))))
;; This can be removed once the kill/yank treatment of invisible text
;; (see etc/TODO) is fixed. -- gm
(defcustom diary-header-line-flag t
- "If non-nil, `diary-simple-display' will show a header line.
+ "If non-nil, `simple-diary-display' will show a header line.
The format of the header is specified by `diary-header-line-format'."
:group 'diary
:type 'boolean
+ :initialize 'custom-initialize-default
+ ;; FIXME overkill.
+ :set 'diary-set-maybe-redraw
:version "22.1")
(defvar diary-selective-display nil)
before edit/copy"
"Diary"))
?\s (frame-width)))
- "Format of the header line displayed by `diary-simple-display'.
+ "Format of the header line displayed by `simple-diary-display'.
Only used if `diary-header-line-flag' is non-nil."
:group 'diary
:type 'sexp
+ :initialize 'custom-initialize-default
+ ;; FIXME overkill.
+ :set 'diary-set-maybe-redraw
:version "22.1")
(defvar diary-saved-point) ; internal
+;; The first version of this also checked for diary-selective-display
+;; in the non-fancy case. This was an attempt to distinguish between
+;; displaying the diary and just visiting the diary file. However,
+;; when using fancy diary, calling diary when there are no entries to
+;; display does not create the fancy buffer, nor does it switch on
+;; selective-display in the diary buffer. This means some
+;; customizations will not take effect, eg:
+;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-03/msg00466.html
+;; So the check for selective-display was dropped. This means the
+;; diary will be displayed if one customizes a diary variable while
+;; just visiting the diary-file. This is i) unlikely, and ii) no great loss.
+(defun diary-live-p ()
+ "Return non-nil if the diary is being displayed."
+ (or (get-buffer fancy-diary-buffer)
+ (and diary-file
+ (find-buffer-visiting (substitute-in-file-name diary-file)))))
(defcustom number-of-diary-entries 1
"Specifies how many days of diary entries are to be displayed initially.
day's and the next day's entries will be displayed.
The value can also be a vector such as [0 2 2 2 2 4 1]; this value
-says to display no diary entries on Sunday, the display the entries
-for the current date and the day after on Monday through Thursday,
-display Friday through Monday's entries on Friday, and display only
-Saturday's entries on Saturday.
+says to display no diary entries on Sunday, the entries for
+the current date and the day after on Monday through Thursday,
+Friday through Monday's entries on Friday, and only Saturday's
+entries on Saturday.
This variable does not affect the diary display with the `d' command
from the calendar; in that case, the prefix argument controls the
(integer :tag "Thursday")
(integer :tag "Friday")
(integer :tag "Saturday")))
+ :initialize 'custom-initialize-default
+ :set 'diary-set-maybe-redraw
:group 'diary)
(or (verify-visited-file-modtime diary-buffer)
(revert-buffer t t))))
;; Setup things like the header-line-format and invisibility-spec.
- (when (eq major-mode default-major-mode) (diary-mode))
+ (if (eq major-mode default-major-mode)
+ (diary-mode)
+ ;; This kludge is to make customizations to
+ ;; diary-header-line-flag after diary has been displayed
+ ;; take effect. Unconditionally calling (diary-mode)
+ ;; clobbers file local variables.
+ ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-03/msg00363.html
+ ;; http://lists.gnu.org/archive/html/emacs-pretest-bug/2007-04/msg00404.html
+ (if (eq major-mode 'diary-mode)
+ (setq header-line-format (and diary-header-line-flag
+ diary-header-line-format))))
;; d-s-p is passed to the diary display function.
(let ((diary-saved-point (point)))
(save-excursion
(set (make-local-variable 'diary-selective-display) t)
(overlay-put ol 'invisible 'diary)
(overlay-put ol 'evaporate t)))
- (calendar-for-loop
- i from 1 to number do
- (let ((month (extract-calendar-month date))
- (day (extract-calendar-day date))
- (year (extract-calendar-year date))
- (entry-found (list-sexp-diary-entries date)))
- (dolist (date-form diary-date-forms)
- (let*
- ((backup (when (eq (car date-form) 'backup)
- (setq date-form (cdr date-form))
- t))
- (dayname
- (format "%s\\|%s\\.?"
- (calendar-day-name date)
- (calendar-day-name date 'abbrev)))
- (monthname
- (format "\\*\\|%s\\|%s\\.?"
- (calendar-month-name month)
- (calendar-month-name month 'abbrev)))
- (month (concat "\\*\\|0*" (int-to-string month)))
- (day (concat "\\*\\|0*" (int-to-string day)))
- (year
- (concat
- "\\*\\|0*" (int-to-string year)
- (if abbreviated-calendar-year
- (concat "\\|" (format "%02d" (% year 100)))
- "")))
- (regexp
- (concat
- "\\(\\`\\|\^M\\|\n\\)" mark "?\\("
- (mapconcat 'eval date-form "\\)\\(?:")
- "\\)"))
- (case-fold-search t))
- (goto-char (point-min))
- (while (re-search-forward regexp nil t)
- (if backup (re-search-backward "\\<" nil t))
- (if (and (or (char-equal (preceding-char) ?\^M)
- (char-equal (preceding-char) ?\n))
- (not (looking-at " \\|\^I")))
- ;; Diary entry that consists only of date.
- (backward-char 1)
- ;; Found a nonempty diary entry--make it
- ;; visible and add it to the list.
- (setq entry-found t)
- (let ((entry-start (point))
- date-start temp)
- (re-search-backward "\^M\\|\n\\|\\`")
- (setq date-start (point))
- ;; When selective display (rather than
- ;; overlays) was used, diary file used to
- ;; start in a blank line and end in a
- ;; newline. Now that neither of these
- ;; need be true, 'move handles the latter
- ;; and 1/2 kludge the former.
- (re-search-forward
- "\^M\\|\n" nil 'move
- (if (and (bobp) (not (looking-at "\^M\\|\n")))
- 1
- 2))
- (while (looking-at " \\|\^I")
- (re-search-forward "\^M\\|\n" nil 'move))
- (unless (and (eobp) (not (bolp)))
- (backward-char 1))
- (unless list-only
- (remove-overlays date-start (point)
- 'invisible 'diary))
- (setq entry (buffer-substring entry-start (point))
- temp (diary-pull-attrs entry file-glob-attrs)
- entry (nth 0 temp))
- (add-to-diary-list
- date
- entry
- (buffer-substring
- (1+ date-start) (1- entry-start))
- (copy-marker entry-start) (nth 1 temp)))))))
- (or entry-found
- (not diary-list-include-blanks)
- (add-to-diary-list date "" "" "" ""))
- (setq date
- (calendar-gregorian-from-absolute
- (1+ (calendar-absolute-from-gregorian date))))
- (setq entry-found nil)))))
+ (dotimes (idummy number)
+ (let ((month (extract-calendar-month date))
+ (day (extract-calendar-day date))
+ (year (extract-calendar-year date))
+ (entry-found (list-sexp-diary-entries date)))
+ (dolist (date-form diary-date-forms)
+ (let*
+ ((backup (when (eq (car date-form) 'backup)
+ (setq date-form (cdr date-form))
+ t))
+ (dayname
+ (format "%s\\|%s\\.?"
+ (calendar-day-name date)
+ (calendar-day-name date 'abbrev)))
+ (monthname
+ (format "\\*\\|%s\\|%s\\.?"
+ (calendar-month-name month)
+ (calendar-month-name month 'abbrev)))
+ (month (concat "\\*\\|0*" (int-to-string month)))
+ (day (concat "\\*\\|0*" (int-to-string day)))
+ (year
+ (concat
+ "\\*\\|0*" (int-to-string year)
+ (if abbreviated-calendar-year
+ (concat "\\|" (format "%02d" (% year 100)))
+ "")))
+ (regexp
+ (concat
+ "^" mark "?\\("
+ (mapconcat 'eval date-form "\\)\\(?:")
+ "\\)"))
+ (case-fold-search t))
+ (goto-char (point-min))
+ (while (re-search-forward regexp nil t)
+ (if backup (re-search-backward "\\<" nil t))
+ (if (and (bolp) (not (looking-at "[ \t]")))
+ ;; Diary entry that consists only of date.
+ (backward-char 1)
+ ;; Found a nonempty diary entry--make it
+ ;; visible and add it to the list.
+ (setq entry-found t)
+ (if (looking-at "[ \t]*\n[ \t]") (forward-line 1))
+ (let ((entry-start (point))
+ date-start temp)
+ (setq date-start
+ (line-end-position
+ (if (and (bolp) (> number 1)) -1 0)))
+ (forward-line 1)
+ (while (looking-at "[ \t]")
+ (forward-line 1))
+ (unless (and (eobp) (not (bolp)))
+ (backward-char 1))
+ (unless list-only
+ (remove-overlays date-start (point)
+ 'invisible 'diary))
+ (setq entry (buffer-substring entry-start (point))
+ temp (diary-pull-attrs entry file-glob-attrs)
+ entry (nth 0 temp))
+ (add-to-diary-list
+ date
+ entry
+ (buffer-substring
+ (1+ date-start) (1- entry-start))
+ (copy-marker entry-start) (nth 1 temp)))))))
+ (or entry-found
+ (not diary-list-include-blanks)
+ (add-to-diary-list date "" "" "" ""))
+ (setq date
+ (calendar-gregorian-from-absolute
+ (1+ (calendar-absolute-from-gregorian date))))
+ (setq entry-found nil)))))
(goto-char (point-min))
(run-hooks 'nongregorian-diary-listing-hook
'list-diary-entries-hook)
(unless list-only
(if diary-display-hook
- (run-hooks 'diary-display-hook)
- (simple-diary-display)))
+ (run-hooks 'diary-display-hook)
+ (simple-diary-display)))
(run-hooks 'diary-hook)
diary-entries-list))))))
(goto-char (point-min))
(while (re-search-forward
(concat
- "\\(?:\\`\\|\^M\\|\n\\)"
+ "^"
(regexp-quote diary-include-string)
" \"\\([^\"]*\\)\"")
nil t)
(defun simple-diary-display ()
"Display the diary buffer if there are any relevant entries or holidays."
(let* ((holiday-list (if holidays-in-diary-buffer
- (check-calendar-holidays original-date)))
+ (calendar-check-holidays original-date)))
(hol-string (format "%s%s%s"
date-string
(if holiday-list ": " "")
(msg (format "No diary entries for %s" hol-string))
;; If selected window is dedicated (to the calendar),
;; need a new one to display the diary.
- (pop-up-frames (window-dedicated-p (selected-window))))
+ (pop-up-frames (or pop-up-frames
+ (window-dedicated-p (selected-window)))))
(calendar-set-mode-line (format "Diary for %s" hol-string))
(if (or (not diary-entries-list)
(and (not (cdr diary-entries-list))
(and (not (cdr diary-entries-list))
(string-equal (car (cdr (car diary-entries-list))) "")))
(let* ((holiday-list (if holidays-in-diary-buffer
- (check-calendar-holidays original-date)))
+ (calendar-check-holidays original-date)))
(msg (format "No diary entries for %s %s"
(concat date-string (if holiday-list ":" ""))
(mapconcat 'identity holiday-list "; "))))
(diary-unhide-everything)
(display-buffer (current-buffer)))))
-(defcustom diary-mail-addr
- (if (boundp 'user-mail-address) user-mail-address "")
- "Email address that `diary-mail-entries' will send email to."
- :group 'diary
- :type 'string
- :version "20.3")
-
-(defcustom diary-mail-days 7
- "Default number of days for `diary-mail-entries' to check."
- :group 'diary
- :type 'integer
- :version "20.3")
-
;;;###autoload
(defun diary-mail-entries (&optional ndays)
"Send a mail message showing diary entries for next NDAYS days.
(year "[0-9]+\\|\\*")
(l (length date-form))
(d-name-pos (- l (length (memq 'dayname date-form))))
- (d-name-pos (if (/= l d-name-pos) (+ 2 d-name-pos)))
+ (d-name-pos (if (/= l d-name-pos) (+ 1 d-name-pos)))
(m-name-pos (- l (length (memq 'monthname date-form))))
- (m-name-pos (if (/= l m-name-pos) (+ 2 m-name-pos)))
+ (m-name-pos (if (/= l m-name-pos) (+ 1 m-name-pos)))
(d-pos (- l (length (memq 'day date-form))))
- (d-pos (if (/= l d-pos) (+ 2 d-pos)))
+ (d-pos (if (/= l d-pos) (+ 1 d-pos)))
(m-pos (- l (length (memq 'month date-form))))
- (m-pos (if (/= l m-pos) (+ 2 m-pos)))
+ (m-pos (if (/= l m-pos) (+ 1 m-pos)))
(y-pos (- l (length (memq 'year date-form))))
- (y-pos (if (/= l y-pos) (+ 2 y-pos)))
+ (y-pos (if (/= l y-pos) (+ 1 y-pos)))
(regexp
(concat
- "\\(\\`\\|\^M\\|\n\\)\\("
+ "^\\("
(mapconcat 'eval date-form "\\)\\(")
"\\)"))
(case-fold-search t))
Each entry in the diary file (or included files) visible in the calendar window
is marked. See the documentation for the function `list-sexp-diary-entries'."
(let* ((sexp-mark (regexp-quote sexp-diary-entry-symbol))
- (s-entry (concat "\\(\\`\\|\^M\\|\n\\)\\("
+ (s-entry (concat "^\\("
sexp-mark "(\\)\\|\\("
(regexp-quote diary-nonmarking-symbol)
sexp-mark "(diary-remind\\)"))
(setq marking-diary-entry (char-equal (preceding-char) ?\())
(re-search-backward "(")
(let ((sexp-start (point))
- sexp entry entry-start line-start marks)
+ sexp entry entry-start marks)
(forward-sexp)
(setq sexp (buffer-substring-no-properties sexp-start (point)))
- (save-excursion
- (re-search-backward "\^M\\|\n\\|\\`")
- (setq line-start (point)))
(forward-char 1)
- (if (and (or (char-equal (preceding-char) ?\^M)
- (char-equal (preceding-char) ?\n))
- (not (looking-at " \\|\^I")))
+ (if (and (bolp) (not (looking-at "[ \t]")))
(progn;; Diary entry consists only of the sexp
(backward-char 1)
(setq entry ""))
(setq entry-start (point))
;; Find end of entry
- (re-search-forward "\^M\\|\n" nil t)
- (while (looking-at " \\|\^I")
- (or (re-search-forward "\^M\\|\n" nil t)
- (re-search-forward "$" nil t)))
- (if (or (char-equal (preceding-char) ?\^M)
- (char-equal (preceding-char) ?\n))
- (backward-char 1))
- (setq entry (buffer-substring-no-properties entry-start (point)))
- (while (string-match "[\^M]" entry)
- (aset entry (match-beginning 0) ?\n )))
+ (forward-line 1)
+ (while (looking-at "[ \t]")
+ (forward-line 1))
+ (if (bolp) (backward-char 1))
+ (setq entry (buffer-substring-no-properties entry-start (point))))
(calendar-for-loop date from first-date to last-date do
(if (setq mark (diary-sexp-entry sexp entry
(calendar-gregorian-from-absolute date)))
(goto-char (point-min))
(while (re-search-forward
(concat
- "\\(?:\\`\\|\^M\\|\n\\)"
+ "^"
(regexp-quote diary-include-string)
" \"\\([^\"]*\\)\"")
nil t)
(let ((m displayed-month)
(y displayed-year))
(increment-calendar-month m y -1)
- (calendar-for-loop i from 0 to 2 do
- (mark-calendar-month m y month day year color)
- (increment-calendar-month m y 1)))))
+ (dotimes (idummy 3)
+ (mark-calendar-month m y month day year color)
+ (increment-calendar-month m y 1)))))
(defun mark-calendar-month (month year p-month p-day p-year &optional color)
"Mark dates in the MONTH/YEAR that conform to pattern P-MONTH/P_DAY/P-YEAR.
(and (= t1 t2)
(string-lessp ts1 ts2)))))))
-(defcustom diary-unknown-time
- -9999
- "Value returned by diary-entry-time when no time is found.
-The default value -9999 causes entries with no recognizable time to be placed
-before those with times; 9999 would place entries with no recognizable time
-after those with times."
- :type 'integer
- :group 'diary
- :version "20.3")
-
(defun diary-entry-time (s)
"Return time at the beginning of the string S as a military-style integer.
For example, returns 1325 for 1:25pm.
be used instead of a colon (:) to separate the hour and minute parts."
(let ((case-fold-search nil))
(cond ((string-match ; Military time
- "\\`[ \t\n\\^M]*\\([0-9]?[0-9]\\)[:.]?\\([0-9][0-9]\\)\\(\\>\\|[^ap]\\)"
+ "\\`[ \t\n]*\\([0-9]?[0-9]\\)[:.]?\\([0-9][0-9]\\)\\(\\>\\|[^ap]\\)"
s)
(+ (* 100 (string-to-number (match-string 1 s)))
(string-to-number (match-string 2 s))))
((string-match ; Hour only XXam or XXpm
- "\\`[ \t\n\\^M]*\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" s)
+ "\\`[ \t\n]*\\([0-9]?[0-9]\\)\\([ap]\\)m\\>" s)
(+ (* 100 (% (string-to-number (match-string 1 s)) 12))
(if (equal ?a (downcase (aref s (match-beginning 2))))
0 1200)))
((string-match ; Hour and minute XX:XXam or XX:XXpm
- "\\`[ \t\n\\^M]*\\([0-9]?[0-9]\\)[:.]\\([0-9][0-9]\\)\\([ap]\\)m\\>" s)
+ "\\`[ \t\n]*\\([0-9]?[0-9]\\)[:.]\\([0-9][0-9]\\)\\([ap]\\)m\\>" s)
(+ (* 100 (% (string-to-number (match-string 1 s)) 12))
(string-to-number (match-string 2 s))
(if (equal ?a (downcase (aref s (match-beginning 3))))
0 1200)))
(t diary-unknown-time)))) ; Unrecognizable
-;; Unrecognizable
-
(defun list-sexp-diary-entries (date)
"Add sexp entries for DATE from the diary file to `diary-entries-list'.
Also, Make them visible in the diary file. Returns t if any entries were
Marking these entries is *extremely* time consuming, so these entries are
best if they are nonmarking."
- (let ((s-entry (concat "\\(\\`\\|\^M\\|\n\\)"
+ (let ((s-entry (concat "^"
(regexp-quote diary-nonmarking-symbol)
"?"
(regexp-quote sexp-diary-entry-symbol)
sexp entry specifier entry-start line-start)
(forward-sexp)
(setq sexp (buffer-substring-no-properties sexp-start (point)))
- (save-excursion
- (re-search-backward "\^M\\|\n\\|\\`")
- (setq line-start (point)))
+ (setq line-start (line-end-position 0))
(setq specifier
(buffer-substring-no-properties (1+ line-start) (point))
entry-start (1+ line-start))
(forward-char 1)
- (if (and (or (char-equal (preceding-char) ?\^M)
- (char-equal (preceding-char) ?\n))
- (not (looking-at " \\|\^I")))
+ (if (and (bolp) (not (looking-at "[ \t]")))
(progn;; Diary entry consists only of the sexp
(backward-char 1)
(setq entry ""))
(setq entry-start (point))
- (re-search-forward "\^M\\|\n" nil t)
- (while (looking-at " \\|\^I")
- (re-search-forward "\^M\\|\n" nil t))
+ (forward-line 1)
+ (while (looking-at "[ \t]")
+ (forward-line 1))
(backward-char 1)
- (setq entry (buffer-substring-no-properties entry-start (point)))
- (while (string-match "[\^M]" entry)
- (aset entry (match-beginning 0) ?\n )))
+ (setq entry (buffer-substring-no-properties entry-start (point))))
(let ((diary-entry (diary-sexp-entry sexp entry date))
temp literal)
(setq literal entry ; before evaluation
"Day of year and number of days remaining in the year of date diary entry."
(calendar-day-of-year-string date))
-(defcustom diary-remind-message
- '("Reminder: Only "
- (if (= 0 (% days 7))
- (concat (int-to-string (/ days 7)) (if (= 7 days) " week" " weeks"))
- (concat (int-to-string days) (if (= 1 days) " day" " days")))
- " until "
- diary-entry)
- "Pseudo-pattern giving form of reminder messages in the fancy diary
-display.
-
-Used by the function `diary-remind', a pseudo-pattern is a list of
-expressions that can involve the keywords `days' (a number), `date' (a list of
-month, day, year), and `diary-entry' (a string)."
- :type 'sexp
- :group 'diary)
-
(defun diary-remind (sexp days &optional marking)
"Provide a reminder of a diary entry.
SEXP is a diary-sexp. DAYS is either a single number or a list of numbers
'(1 diary-face)))
diary-date-forms)))
-(eval-when-compile (require 'cal-hebrew)
- (require 'cal-islam))
-
-(defvar diary-font-lock-keywords
- (append
- (diary-font-lock-date-forms calendar-month-name-array
- nil calendar-month-abbrev-array)
- (when (or (memq 'mark-hebrew-diary-entries
- nongregorian-diary-marking-hook)
- (memq 'list-hebrew-diary-entries
- nongregorian-diary-listing-hook))
- (require 'cal-hebrew)
- (diary-font-lock-date-forms
- calendar-hebrew-month-name-array-leap-year
- hebrew-diary-entry-symbol))
- (when (or (memq 'mark-islamic-diary-entries
- nongregorian-diary-marking-hook)
- (memq 'list-islamic-diary-entries
- nongregorian-diary-listing-hook))
- (require 'cal-islam)
- (diary-font-lock-date-forms
- calendar-islamic-month-name-array
- islamic-diary-entry-symbol))
- (list
- (cons
- (concat "^" (regexp-quote diary-include-string) ".*$")
- 'font-lock-keyword-face)
- (cons
- (concat "^" (regexp-quote diary-nonmarking-symbol)
- "?\\(" (regexp-quote sexp-diary-entry-symbol) "\\)")
- '(1 font-lock-reference-face))
- (cons
- (concat "^" (regexp-quote diary-nonmarking-symbol))
- 'font-lock-reference-face)
- (cons
- (concat "^" (regexp-quote diary-nonmarking-symbol)
- "?\\(" (regexp-quote hebrew-diary-entry-symbol) "\\)")
- '(1 font-lock-reference-face))
- (cons
- (concat "^" (regexp-quote diary-nonmarking-symbol)
- "?\\(" (regexp-quote islamic-diary-entry-symbol) "\\)")
- '(1 font-lock-reference-face))
- '(diary-font-lock-sexps . font-lock-keyword-face)
- `(,(concat "\\(^\\|\\s-\\)"
- diary-time-regexp "\\(-" diary-time-regexp "\\)?")
- . 'diary-time)))
- "Forms to highlight in `diary-mode'.")
-
+(defvar calendar-hebrew-month-name-array-leap-year)
+(defvar calendar-islamic-month-name-array)
+(defvar calendar-bahai-month-name-array)
+
+(defun diary-font-lock-keywords ()
+ "Return a value for the variable `diary-font-lock-keywords'."
+ (append
+ (diary-font-lock-date-forms calendar-month-name-array
+ nil calendar-month-abbrev-array)
+ (when (or (memq 'mark-hebrew-diary-entries
+ nongregorian-diary-marking-hook)
+ (memq 'list-hebrew-diary-entries
+ nongregorian-diary-listing-hook))
+ (require 'cal-hebrew)
+ (diary-font-lock-date-forms
+ calendar-hebrew-month-name-array-leap-year hebrew-diary-entry-symbol))
+ (when (or (memq 'mark-islamic-diary-entries
+ nongregorian-diary-marking-hook)
+ (memq 'list-islamic-diary-entries
+ nongregorian-diary-listing-hook))
+ (require 'cal-islam)
+ (diary-font-lock-date-forms
+ calendar-islamic-month-name-array islamic-diary-entry-symbol))
+ (when (or (memq 'diary-bahai-mark-entries
+ nongregorian-diary-marking-hook)
+ (memq 'diary-bahai-list-entries
+ nongregorian-diary-marking-hook))
+ (require 'cal-bahai)
+ (diary-font-lock-date-forms
+ calendar-bahai-month-name-array bahai-diary-entry-symbol))
+ (list
+ (cons
+ (format "^%s.*$" (regexp-quote diary-include-string))
+ 'font-lock-keyword-face)
+ (cons
+ (format "^%s?\\(%s\\)" (regexp-quote diary-nonmarking-symbol)
+ (regexp-quote sexp-diary-entry-symbol))
+ '(1 font-lock-reference-face))
+ (cons
+ (format "^%s" (regexp-quote diary-nonmarking-symbol))
+ 'font-lock-reference-face)
+ (cons
+ (format "^%s?%s" (regexp-quote diary-nonmarking-symbol)
+ (regexp-opt (mapcar 'regexp-quote
+ (list hebrew-diary-entry-symbol
+ islamic-diary-entry-symbol
+ bahai-diary-entry-symbol))
+ t))
+ '(1 font-lock-reference-face))
+ '(diary-font-lock-sexps . font-lock-keyword-face)
+ `(,(format "\\(^\\|\\s-\\)%s\\(-%s\\)?" diary-time-regexp
+ diary-time-regexp)
+ . 'diary-time))))
+
+(defvar diary-font-lock-keywords (diary-font-lock-keywords)
+ "Forms to highlight in `diary-mode'.")
;; Following code from Dave Love <fx@gnu.org>.
;; Import Outlook-format appointments from mail messages in Gnus or
;; message formats recognized are customizable through
;; `diary-outlook-formats'.
-(defcustom diary-outlook-formats
- '(
- ;; When: 11 October 2001 12:00-14:00 (GMT) Greenwich Mean Time : Dublin, ...
- ;; [Current UK format? The timezone is meaningless. Sometimes the
- ;; Where is missing.]
- ("When: \\([0-9]+ [[:alpha:]]+ [0-9]+\\) \
-\\([^ ]+\\) [^\n]+
-\[^\n]+
-\\(?:Where: \\([^\n]+\\)\n+\\)?
-\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*~\\*"
- . "\\1\n \\2 %s, \\3")
- ;; When: Tuesday, April 30, 2002 03:00 PM-03:30 PM (GMT) Greenwich Mean ...
- ;; [Old UK format?]
- ("^When: [[:alpha:]]+, \\([[:alpha:]]+\\) \\([0-9][0-9]*\\), \\([0-9]\\{4\\}\\) \
-\\([^ ]+\\) [^\n]+
-\[^\n]+
-\\(?:Where: \\([^\n]+\\)\\)?\n+"
- . "\\2 \\1 \\3\n \\4 %s, \\5")
- (
- ;; German format, apparently.
- "^Zeit: [^ ]+, +\\([0-9]+\\)\. +\\([[:upper:]][[:lower:]][[:lower:]]\\)[^ ]* +\\([0-9]+\\) +\\([^ ]+\\).*$"
- . "\\1 \\2 \\3\n \\4 %s"))
- "Alist of regexps matching message text and replacement text.
-
-The regexp must match the start of the message text containing an
-appointment, but need not include a leading `^'. If it matches the
-current message, a diary entry is made from the corresponding
-template. If the template is a string, it should be suitable for
-passing to `replace-match', and so will have occurrences of `\\D' to
-substitute the match for the Dth subexpression. It must also contain
-a single `%s' which will be replaced with the text of the message's
-Subject field. Any other `%' characters must be doubled, so that the
-template can be passed to `format'.
-
-If the template is actually a function, it is called with the message
-body text as argument, and may use `match-string' etc. to make a
-template following the rules above."
- :type '(alist :key-type (regexp :tag "Regexp matching time/place")
- :value-type (choice
- (string :tag "Template for entry")
- (function :tag "Unary function providing template")))
- :version "22.1"
- :group 'diary)
-
-
;; Dynamically bound.
-(defvar body)
(defvar subject)
(defun diary-from-outlook-internal (&optional test-only)