Minor diary-lib.el fix.
[bpt/emacs.git] / lisp / calendar / diary-lib.el
index a62af91..fc416d8 100644 (file)
@@ -1,7 +1,7 @@
 ;;; diary-lib.el --- diary functions
 
 ;; Copyright (C) 1989, 1990, 1992, 1993, 1994, 1995, 2001, 2002, 2003,
-;;   2004, 2005, 2006, 2007, 2008  Free Software Foundation, Inc.
+;;   2004, 2005, 2006, 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 
 ;; Author: Edward M. Reingold <reingold@cs.uiuc.edu>
 ;; Maintainer: Glenn Morris <rgm@gnu.org>
@@ -9,10 +9,10 @@
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; 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 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,9 +20,7 @@
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -31,7 +29,7 @@
 ;;; Code:
 
 (require 'calendar)
-(require 'diary-loaddefs)
+(eval-and-compile (load "diary-loaddefs" nil t))
 
 (defgroup diary nil
   "Emacs diary."
@@ -73,8 +71,8 @@ are holidays."
   "Face used for buttons in the fancy diary display."
   :version "22.1"
   :group 'calendar-faces)
-;; Backward-compatibility alias. FIXME make obsolete.
-(put 'diary-button-face 'face-alias 'diary-button)
+
+(define-obsolete-face-alias 'diary-button-face 'diary-button "22.1")
 
 ;; Face markup of calendar and diary displays: Any entry line that
 ;; ends with [foo:value] where foo is a face attribute (except :box
@@ -108,7 +106,7 @@ is pre-pended to REGEXP for file-wide specifiers.  ATTRIBUTE
 specifies which face attribute (e.g. `:foreground') to modify, or
 that this is a face (`:face') to apply.  TYPE is the type of
 attribute being applied.  Available TYPES (see `diary-attrtype-convert')
-are: `string', `symbol', `int', `tnil',`stringtnil.'"
+are: `string', `symbol', `int', `tnil', `stringtnil.'"
   :type '(repeat (list (string :tag "Regular expression")
                        (integer :tag "Sub-expression")
                        (symbol :tag "Attribute (e.g. :foreground)")
@@ -150,33 +148,32 @@ Used for example by the appointment package - see `appt-activate'."
   :type 'hook
   :group 'diary)
 
-(defcustom diary-display-hook nil
-  "List of functions that handle the display of the diary.
-If nil (the default), `diary-simple-display' is used.  Use
-`ignore' for no diary display.
-
-Ordinarily, this just displays the diary buffer (with holidays
-indicated in the mode line), if there are any relevant entries.
-At the time these functions are called, the variable
-`diary-entries-list' is a list, in order by date, of all relevant
-diary entries in the form of ((MONTH DAY YEAR) STRING), where
-string is the diary entry for the given date.  This can be used,
-for example, a different buffer for display (perhaps combined
-with holidays), or produce hard copy output.
-
-A function `diary-fancy-display' is provided for use with this
-hook; this function prepares a special noneditable diary buffer
-with the relevant diary entries that has neat day-by-day
-arrangement with headings.  The fancy diary buffer will show the
-holidays unless the variable `diary-show-holidays-flag' is set to
-nil.  Ordinarily, the fancy diary buffer will not show days for
-which there are no diary entries, even if that day is a holiday;
-if you want such days to be shown in the fancy diary buffer, set
-the variable `diary-list-include-blanks' non-nil."
-  :type 'hook
-  :options '(diary-fancy-display)
+(define-obsolete-variable-alias 'diary-display-hook 'diary-display-function
+  "23.1")
+
+(defcustom diary-display-function 'diary-fancy-display
+  "Function used to display the diary.
+The two standard options are `diary-fancy-display' and `diary-simple-display'.
+
+For historical reasons, `nil' is the same as `diary-simple-display'
+\(so you must use `ignore' for no display).  Also for historical
+reasons, this variable can be a list of functions to run.  These
+uses are not recommended and may be removed at some point.
+
+When this function is called, the variable `diary-entries-list'
+is a list, in order by date, of all relevant diary entries in the
+form of ((MONTH DAY YEAR) STRING), where string is the diary
+entry for the given date.  This can be used, for example, to
+produce a different buffer for display (perhaps combined with
+holidays), or hard copy output."
+  :type '(choice (const diary-fancy-display :tag "Fancy display")
+                 (const diary-simple-display :tag "Basic display")
+                 (const ignore :tag "No display")
+                 (const nil :tag "Obsolete way to choose basic display")
+                 (hook :tag "Obsolete form with list of display functions"))
   :initialize 'custom-initialize-default
   :set 'diary-set-maybe-redraw
+  :version "23.2"                       ; simple->fancy
   :group 'diary)
 
 (define-obsolete-variable-alias 'list-diary-entries-hook
@@ -188,9 +185,9 @@ You might wish to add `diary-include-other-diary-files', in which case
 you will probably also want to add `diary-mark-included-diary-files' to
 `diary-mark-entries-hook'.  For example, you could use
 
+     (setq diary-display-function 'diary-fancy-display)
      (add-hook 'diary-list-entries-hook 'diary-include-other-diary-files)
      (add-hook 'diary-list-entries-hook 'diary-sort-entries)
-     (add-hook 'diary-display-hook 'diary-fancy-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
@@ -288,8 +285,8 @@ with no recognizable time after those with times."
   "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)."
+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)
 
@@ -357,9 +354,7 @@ template following the rules above."
 (defun diary-set-header (symbol value)
   "Set SYMBOL's value to VALUE, and redraw the diary header if necessary."
   (let ((oldvalue (symbol-value symbol))
-        (dbuff (and diary-file
-                    (find-buffer-visiting
-                     (substitute-in-file-name diary-file)))))
+        (dbuff (and diary-file (find-buffer-visiting diary-file))))
     (custom-set-default symbol value)
     (and dbuff
          (not (equal value oldvalue))
@@ -388,7 +383,7 @@ The format of the header is specified by `diary-header-line-format'."
                      "Some text is hidden - press \"s\" in calendar \
 before edit/copy"
                    "Diary"))
-           ?\s (frame-width)))
+           ?\s (window-width)))
   "Format of the header line displayed by `diary-simple-display'.
 Only used if `diary-header-line-flag' is non-nil."
   :group 'diary
@@ -412,8 +407,7 @@ Only used if `diary-header-line-flag' is non-nil."
 (defun diary-live-p ()
   "Return non-nil if the diary is being displayed."
   (or (get-buffer diary-fancy-buffer)
-      (and diary-file
-           (find-buffer-visiting (substitute-in-file-name diary-file)))))
+      (and diary-file (find-buffer-visiting diary-file))))
 
 ;;;###cal-autoload
 (defun diary-set-maybe-redraw (symbol value)
@@ -432,21 +426,20 @@ just visiting the `diary-file'), and SYMBOL's value is to be changed."
 
 (defcustom diary-number-of-entries 1
   "Specifies how many days of diary entries are to be displayed initially.
-This variable affects the diary display when the command \\[diary] is used,
-or if the value of the variable `calendar-view-diary-initially-flag' is non-nil.
-For example, if the default value 1 is used, then only the current day's diary
-entries will be displayed.  If the value 2 is used, then both the current
-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 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 affects the diary display when the command \\[diary] is
+used, or if the value of the variable `calendar-view-diary-initially-flag'
+is non-nil.  For example, if the default value 1 is used, then only the
+current day's diary entries will be displayed.  If the value 2 is used,
+then both the current 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 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
-number of days of diary entries displayed."
+from the calendar; in that case, the prefix argument controls the number
+of days of diary entries displayed."
   :type '(choice (integer :tag "Entries")
                  (vector :value [0 0 0 0 0 0 0]
                          (integer :tag "Sunday")
@@ -466,12 +459,11 @@ number of days of diary entries displayed."
 (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 ((d-file (substitute-in-file-name diary-file)))
-    (if (and d-file (file-exists-p d-file))
-        (if (file-readable-p d-file)
-            d-file
-          (error "Diary file `%s' is not readable" diary-file))
-      (error "Diary file `%s' does not exist" diary-file))))
+  (if (and diary-file (file-exists-p diary-file))
+      (if (file-readable-p diary-file)
+          diary-file
+        (error "Diary file `%s' is not readable" diary-file))
+    (error "Diary file `%s' does not exist" diary-file)))
 
 ;;;###autoload
 (defun diary (&optional arg)
@@ -487,8 +479,8 @@ does nothing.  This function is suitable for execution in a `.emacs' file."
 ;;;###cal-autoload
 (defun diary-view-entries (&optional arg)
   "Prepare and display a buffer with diary entries.
-Searches the file named in `diary-file' for entries that
-match ARG days starting with the date indicated by the cursor position
+Searches the file named in `diary-file' for entries that match
+ARG days starting with the date indicated by the cursor position
 in the displayed three-month calendar."
   (interactive "p")
   (diary-check-diary-file)
@@ -589,13 +581,13 @@ The function takes a string argument and must return a string.")
 (defun diary-add-to-list (date string specifier &optional marker
                                globcolor literal)
   "Add an entry to `diary-entries-list'.
-Do nothing if DATE or STRING is nil.  DATE is the (MONTH DAY
+Do nothing if DATE or STRING are nil.  DATE is the (MONTH DAY
 YEAR) for which the entry applies; STRING is the text of the
 entry as it will appear in the diary (i.e. with any format
 strings such as \"%d\" expanded); SPECIFIER is the date part of
 the entry as it appears in the diary-file; LITERAL is the entry
-as it appears in the diary-file (i.e. before expansion).  If
-LITERAL is nil, it is taken to be the same as STRING.
+as it appears in the diary-file (i.e. before expansion).
+If LITERAL is nil, it is taken to be the same as STRING.
 
 The entry is added to the list as (DATE STRING SPECIFIER LOCATOR
 GLOBCOLOR), where LOCATOR has the form (MARKER FILENAME LITERAL),
@@ -618,7 +610,7 @@ FILENAME being the file containing the diary entry."
 (define-obsolete-function-alias 'add-to-diary-list 'diary-add-to-list "23.1")
 
 (defun diary-list-entries-2 (date mark globattr list-only
-                                  &optional months symbol)
+                                  &optional months symbol gdate)
   "Internal subroutine of `diary-list-entries'.
 Find diary entries applying to DATE, by searching from point-min for
 each element of `diary-date-forms'.  MARK indicates an entry is non-marking.
@@ -626,7 +618,9 @@ GLOBATTR is the list of global file attributes.  If LIST-ONLY is
 non-nil, don't change the buffer, only return a list of entries.
 Optional array MONTHS replaces `calendar-month-name-array', and
 means months cannot be abbreviated.  Optional string SYMBOL marks diary
-entries of the desired type.  Returns non-nil if any entries were found."
+entries of the desired type.  If DATE is not Gregorian, then the
+Gregorian equivalent should be provided via GDATE.  Returns non-nil if
+any entries were found."
   (let* ((month (calendar-extract-month date))
          (day (calendar-extract-day date))
          (year (calendar-extract-year date))
@@ -660,7 +654,7 @@ entries of the desired type.  Returns non-nil if any entries were found."
           ;; regexp moves us past the end of date, onto the next line.
           ;; Trailing whitespace after date not allowed (see diary-file).
           (if (and (bolp) (not (looking-at "[ \t]")))
-              ;;  Diary entry that consists only of date.
+              ;; Diary entry that consists only of date.
               (backward-char 1)
             ;; Found a nonempty diary entry--make it
             ;; visible and add it to the list.
@@ -680,7 +674,7 @@ entries of the desired type.  Returns non-nil if any entries were found."
                         (buffer-substring-no-properties
                          entry-start (point)) globattr))
             (diary-add-to-list
-             date (car temp)
+             (or gdate date) (car temp)
              (buffer-substring-no-properties (1+ date-start) (1- entry-start))
              (copy-marker entry-start) (cadr temp))))))
     entry-found))
@@ -699,7 +693,7 @@ of the appropriate type."
     (dotimes (idummy number)
       (diary-list-entries-2
        (funcall absfunc (calendar-absolute-from-gregorian gdate))
-       diary-nonmarking-symbol file-glob-attrs list-only months symbol)
+       diary-nonmarking-symbol file-glob-attrs list-only months symbol gdate)
       (setq gdate
             (calendar-gregorian-from-absolute
              (1+ (calendar-absolute-from-gregorian gdate))))))
@@ -730,18 +724,16 @@ After the list is prepared, the following hooks are run:
       from other files or to sort the diary entries.  Invoked *once*
       only, before the display hook is run.
 
-  `diary-display-hook' does the actual display of information.  If nil,
-      `diary-simple-display' is used.  Use `add-hook' to use
-      `diary-fancy-display', if desired, or `ignore' for no display.
-
-  `diary-hook' is run last.  This is used e.g. by `appt-check'.
+  `diary-hook' is run last, after the diary is displayed.
+      This is used e.g. by `appt-check'.
 
 Functions called by these hooks may use the variables ORIGINAL-DATE
 and NUMBER, which are the arguments with which this function was called.
 Note that hook functions should _not_ use DATE, but ORIGINAL-DATE.
 \(Sexp diary entries may use DATE - see `diary-list-sexp-entries'.)
 
-If LIST-ONLY is non-nil don't modify or display the buffer, only return a list."
+This function displays the list using `diary-display-function', unless
+LIST-ONLY is non-nil, in which case it just returns the list."
   (unless number
     (setq number (if (vectorp diary-number-of-entries)
                      (aref diary-number-of-entries (calendar-day-of-week date))
@@ -749,18 +741,17 @@ If LIST-ONLY is non-nil don't modify or display the buffer, only return a list."
   (when (> number 0)
     (let* ((original-date date)    ; save for possible use in the hooks
            (date-string (calendar-date-string date))
-           (d-file (substitute-in-file-name diary-file))
-           (diary-buffer (find-buffer-visiting d-file))
+           (diary-buffer (find-buffer-visiting diary-file))
            diary-entries-list file-glob-attrs)
       (message "Preparing diary...")
-      (save-excursion
+      (save-current-buffer
         (if (not diary-buffer)
-            (set-buffer (find-file-noselect d-file t))
+            (set-buffer (find-file-noselect diary-file t))
           (set-buffer diary-buffer)
           (or (verify-visited-file-modtime diary-buffer)
               (revert-buffer t t)))
         ;; Setup things like the header-line-format and invisibility-spec.
-        (if (eq major-mode default-major-mode)
+        (if (eq major-mode (default-value 'major-mode))
             (diary-mode)
           ;; This kludge is to make customizations to
           ;; diary-header-line-flag after diary has been displayed
@@ -774,41 +765,48 @@ If LIST-ONLY is non-nil don't modify or display the buffer, only return a list."
         ;; d-s-p is passed to the diary display function.
         (let ((diary-saved-point (point)))
           (save-excursion
-            (setq file-glob-attrs (cadr (diary-pull-attrs nil "")))
-            (with-syntax-table diary-syntax-table
+            (save-restriction
+              (widen)                   ; bug#5093
+              (setq file-glob-attrs (cadr (diary-pull-attrs nil "")))
+              (with-syntax-table diary-syntax-table
+                (goto-char (point-min))
+                (unless list-only
+                  (let ((ol (make-overlay (point-min) (point-max) nil t nil)))
+                    (set (make-local-variable 'diary-selective-display) t)
+                    (overlay-put ol 'invisible 'diary)
+                    (overlay-put ol 'evaporate t)))
+                (dotimes (idummy number)
+                  (let ((sexp-found (diary-list-sexp-entries date))
+                        (entry-found (diary-list-entries-2
+                                      date diary-nonmarking-symbol
+                                      file-glob-attrs list-only)))
+                    (if diary-list-include-blanks
+                        (or sexp-found entry-found
+                            (diary-add-to-list date "" "" "" "")))
+                    (setq date
+                          (calendar-gregorian-from-absolute
+                           (1+ (calendar-absolute-from-gregorian date)))))))
               (goto-char (point-min))
+              (run-hooks 'diary-nongregorian-listing-hook
+                         'diary-list-entries-hook)
               (unless list-only
-                (let ((ol (make-overlay (point-min) (point-max) nil t nil)))
-                  (set (make-local-variable 'diary-selective-display) t)
-                  (overlay-put ol 'invisible 'diary)
-                  (overlay-put ol 'evaporate t)))
-              (dotimes (idummy number)
-                (let ((sexp-found (diary-list-sexp-entries date))
-                      (entry-found (diary-list-entries-2
-                                    date diary-nonmarking-symbol
-                                    file-glob-attrs list-only)))
-                  (if diary-list-include-blanks
-                      (or sexp-found entry-found
-                          (diary-add-to-list date "" "" "" "")))
-                  (setq date
-                        (calendar-gregorian-from-absolute
-                         (1+ (calendar-absolute-from-gregorian date)))))))
-            (goto-char (point-min))
-            (run-hooks 'diary-nongregorian-listing-hook
-                       'diary-list-entries-hook)
-            (unless list-only
-              (if diary-display-hook
-                  (run-hooks 'diary-display-hook)
-                (diary-simple-display)))
-            (run-hooks 'diary-hook)
-            diary-entries-list))))))
+                (if (and diary-display-function
+                         (listp diary-display-function))
+                    ;; Backwards compatibility.
+                    (run-hooks 'diary-display-function)
+                  (funcall (or diary-display-function
+                               'diary-simple-display))))
+              (run-hooks 'diary-hook)
+              diary-entries-list)))))))
 
 (define-obsolete-function-alias 'list-diary-entries 'diary-list-entries "22.1")
 
 (defun diary-unhide-everything ()
   "Show all invisible text in the diary."
   (kill-local-variable 'diary-selective-display)
-  (remove-overlays (point-min) (point-max) 'invisible 'diary)
+  (save-restriction                     ; bug#5477
+    (widen)
+    (remove-overlays (point-min) (point-max) 'invisible 'diary))
   (kill-local-variable 'mode-line-format))
 
 (defvar original-date)                  ; bound in diary-list-entries
@@ -821,18 +819,16 @@ it enables you to use shared diary files together with your own.
 The files included are specified in the `diary-file' by lines of this form:
         #include \"filename\"
 This is recursive; that is, #include directives in diary files thus included
-are obeyed.  You can change the `#include' to some other string by
-changing the variable `diary-include-string'."
+are obeyed.  You can change the `#include' to some other string by changing
+the variable `diary-include-string'."
   (goto-char (point-min))
   (while (re-search-forward
           (format "^%s \"\\([^\"]*\\)\"" (regexp-quote diary-include-string))
           nil t)
-    (let ((diary-file (substitute-in-file-name
-                       (match-string-no-properties 1)))
-          (diary-list-include-blanks nil)
+    (let ((diary-file (match-string-no-properties 1))
           (diary-list-entries-hook 'diary-include-other-diary-files)
-          (diary-display-hook 'ignore)
-          (diary-hook nil))
+          (diary-display-function 'ignore)
+          diary-hook diary-list-include-blanks)
       (if (file-exists-p diary-file)
           (if (file-readable-p diary-file)
               (unwind-protect
@@ -888,12 +884,14 @@ Returns a cons (NOENTRIES . HOLIDAY-STRING)."
 (defvar diary-saved-point)              ; bound in diary-list-entries
 
 (defun diary-simple-display ()
-  "Display the diary buffer if there are any relevant entries or holidays."
+  "Display the diary buffer if there are any relevant entries or holidays.
+Entries that do not apply are made invisible.  Holidays are shown
+in the mode line.  This is an option for `diary-display-function'."
   ;; If selected window is dedicated (to the calendar), need a new one
   ;; to display the diary.
   (let* ((pop-up-frames (or pop-up-frames
                             (window-dedicated-p (selected-window))))
-         (dbuff (find-buffer-visiting (substitute-in-file-name diary-file)))
+         (dbuff (find-buffer-visiting diary-file))
          (empty (diary-display-no-entries)))
     ;; This may be too wide, but when simple diary is used there is
     ;; nowhere else for the holidays to go.  Also, it is documented in
@@ -913,9 +911,9 @@ Returns a cons (NOENTRIES . HOLIDAY-STRING)."
 (define-obsolete-function-alias 'simple-diary-display
   'diary-simple-display "23.1")
 
-(define-button-type 'diary-entry
-  'action #'diary-goto-entry
-  'face 'diary-button)
+(define-button-type 'diary-entry 'action #'diary-goto-entry
+  'face 'diary-button 'help-echo "Find this diary entry"
+  'follow-link t)
 
 (defun diary-goto-entry (button)
   "Jump to the diary entry for the BUTTON at point."
@@ -932,7 +930,7 @@ Returns a cons (NOENTRIES . HOLIDAY-STRING)."
                (file-exists-p file)
                (find-file-other-window file)
                (progn
-                 (when (eq major-mode default-major-mode) (diary-mode))
+                 (when (eq major-mode (default-value 'major-mode)) (diary-mode))
                  (goto-char (point-min))
                  (if (re-search-forward (format "%s.*\\(%s\\)"
                                                 (regexp-quote (nth 2 locator))
@@ -943,10 +941,13 @@ Returns a cons (NOENTRIES . HOLIDAY-STRING)."
 
 (defun diary-fancy-display ()
   "Prepare a diary buffer with relevant entries in a fancy, noneditable form.
-To use this function, add it to `diary-display-hook'."
+Holidays are shown unless `diary-show-holidays-flag' is nil.
+Days with no diary entries are not shown (even if that day is a
+holiday), unless `diary-list-include-blanks' is non-nil.
+
+This is an option for `diary-display-function'."
   ;; Turn off selective-display in the diary file's buffer.
-  (with-current-buffer
-      (find-buffer-visiting (substitute-in-file-name diary-file))
+  (with-current-buffer (find-buffer-visiting diary-file)
     (diary-unhide-everything))
   (unless (car (diary-display-no-entries)) ; no entries
     ;; Prepare the fancy diary buffer.
@@ -1002,7 +1003,7 @@ To use this function, add it to `diary-display-hook'."
                 this-loc marks temp-face)
             (unless (zerop (length this-entry))
               (if (setq this-loc (nth 3 entry))
-                  (insert-button (concat this-entry "\n")
+                  (insert-button this-entry
                                  ;; (MARKER FILENAME SPECIFIER LITERAL)
                                  'locator (list (car this-loc)
                                                 (cadr this-loc)
@@ -1010,8 +1011,11 @@ To use this function, add it to `diary-display-hook'."
                                                 (or (nth 2 this-loc)
                                                     (nth 1 entry)))
                                  :type 'diary-entry)
-                (insert this-entry ?\n))
-              (and font-lock-mode
+                (insert this-entry))
+              (insert ?\n)
+              ;; Doesn't make sense to check font-lock-mode - see
+              ;; comments above diary-entry-marker in calendar.el.
+              (and ; font-lock-mode
                    (setq marks (nth 4 entry))
                    (save-excursion
                      (setq temp-face (calendar-make-temp-face marks))
@@ -1019,7 +1023,11 @@ To use this function, add it to `diary-display-hook'."
                      (overlay-put
                       (make-overlay (match-beginning 0) (match-end 0))
                       'face temp-face)))))))
-      (diary-fancy-display-mode)
+      ;; FIXME can't remember what this check was for.
+      ;; To prevent something looping, or a minor optimization?
+      (if (eq major-mode 'diary-fancy-display-mode)
+          (run-hooks 'diary-fancy-display-mode-hook)
+        (diary-fancy-display-mode))
       (calendar-set-mode-line date-string)
       (message "Preparing diary...done"))))
 
@@ -1044,8 +1052,7 @@ the actual printing."
     (if diary-buffer
         (with-current-buffer diary-buffer
           (run-hooks 'diary-print-entries-hook))
-      (or (setq diary-buffer
-                (find-buffer-visiting (substitute-in-file-name diary-file)))
+      (or (setq diary-buffer (find-buffer-visiting diary-file))
           (error "You don't have a diary buffer!"))
       ;; Name affects printing?
       (setq temp-buffer (get-buffer-create " *Printable Diary Entries*"))
@@ -1081,14 +1088,20 @@ This function gets rid of the selective display of the diary file so that
 all entries, not just some, are visible.  If there is no diary buffer, one
 is created."
   (interactive)
-  (let ((d-file (diary-check-diary-file))
-        (pop-up-frames (or pop-up-frames
-                           (window-dedicated-p (selected-window)))))
+  (let* ((d-file (diary-check-diary-file))
+         (pop-up-frames (or pop-up-frames
+                            (window-dedicated-p (selected-window))))
+         (win (selected-window))
+         (height (window-height)))
     (with-current-buffer (or (find-buffer-visiting d-file)
                              (find-file-noselect d-file t))
-      (when (eq major-mode default-major-mode) (diary-mode))
+      (when (eq major-mode (default-value 'major-mode)) (diary-mode))
       (diary-unhide-everything)
-      (display-buffer (current-buffer)))))
+      (display-buffer (current-buffer))
+      (when (and (/= height (window-height win))
+                 (with-current-buffer (window-buffer win)
+                   (derived-mode-p 'calendar-mode)))
+        (fit-window-to-buffer win)))))
 
 (define-obsolete-function-alias 'show-all-diary-entries
   'diary-show-all-entries "22.1")
@@ -1119,7 +1132,7 @@ should ensure that all relevant variables are set.
   (interactive "P")
   (if (string-equal diary-mail-addr "")
       (error "You must set `diary-mail-addr' to use this command")
-    (let ((diary-display-hook 'diary-fancy-display))
+    (let ((diary-display-function 'diary-fancy-display))
       (diary-list-entries (calendar-current-date) (or ndays diary-mail-days)))
     (compose-mail diary-mail-addr
                   (concat "Diary entries generated "
@@ -1238,7 +1251,9 @@ function that converts absolute dates to dates of the appropriate type.  "
                                (buffer-substring-no-properties
                                 (point) (line-end-position))
                                file-glob-attrs)))
-            (if dd-name
+            ;; Only mark all days of a given name if the pattern
+            ;; contains no more specific elements.
+            (if (and dd-name (not (or d-pos m-pos y-pos)))
                 (calendar-mark-days-named
                  (cdr (assoc-string dd-name
                                     (calendar-make-alist
@@ -1279,7 +1294,7 @@ diary entries."
         file-glob-attrs)
     (with-current-buffer (find-file-noselect (diary-check-diary-file) t)
       (save-excursion
-        (when (eq major-mode default-major-mode) (diary-mode))
+        (when (eq major-mode (default-value 'major-mode)) (diary-mode))
         (setq calendar-mark-diary-entries-flag t)
         (message "Marking diary entries...")
         (setq file-glob-attrs (nth 1 (diary-pull-attrs nil '())))
@@ -1377,14 +1392,13 @@ you to use shared diary files together with your own.  The files included are
 specified in the `diary-file' by lines of this form:
         #include \"filename\"
 This is recursive; that is, #include directives in diary files thus included
-are obeyed.  You can change the `#include' to some other string by
-changing the variable `diary-include-string'."
+are obeyed.  You can change the `#include' to some other string by changing
+the variable `diary-include-string'."
   (goto-char (point-min))
   (while (re-search-forward
           (format "^%s \"\\([^\"]*\\)\"" (regexp-quote diary-include-string))
           nil t)
-    (let* ((diary-file (substitute-in-file-name
-                        (match-string-no-properties 1)))
+    (let* ((diary-file (match-string-no-properties 1))
            (diary-mark-entries-hook 'diary-mark-included-diary-files)
            (dbuff (find-buffer-visiting diary-file)))
       (if (file-exists-p diary-file)
@@ -1494,10 +1508,9 @@ Optional argument COLOR is passed to `calendar-mark-visible-date' as MARK."
 (defun calendar-mark-1 (month day year fromabs toabs &optional color)
   "Mark dates in the calendar conforming to MONTH DAY YEAR of some system.
 The function FROMABS converts absolute dates to the appropriate date system.
-The function TOABDS carries out the inverse operation.  Optional argument
+The function TOABS carries out the inverse operation.  Optional argument
 COLOR is passed to `calendar-mark-visible-date' as MARK."
-  (save-excursion
-    (set-buffer calendar-buffer)
+  (with-current-buffer calendar-buffer
     (if (and (not (zerop month)) (not (zerop day)))
         (if (not (zerop year))
             ;; Fully specified date.
@@ -1529,7 +1542,7 @@ For example, returns 1325 for 1:25pm.
 
 Returns `diary-unknown-time' (default value -9999) if no time is recognized.
 The recognized forms are XXXX, X:XX, or XX:XX (military time), and XXam,
-XXAM, XXpm, XXPM, XX:XXam, XX:XXAM XX:XXpm, or XX:XXPM.  A period (.) can
+XXAM, XXpm, XXPM, XX:XXam, XX:XXAM, XX:XXpm, or XX:XXPM.  A period (.) can
 be used instead of a colon (:) to separate the hour and minute parts."
   (let (case-fold-search)
     (cond ((string-match                ; military time
@@ -1606,12 +1619,13 @@ DAY MONTH YEAR in the European style).
     be a list of integers, `t' (meaning all values), or an integer.
 
   %%(diary-float MONTH DAYNAME N &optional DAY MARK) text
-    Entry will appear on the Nth DAYNAME of MONTH (0 being Sunday,
-    1 Monday, etc; if N is negative it counts backward from the end
-    of the month.  MONTH can be a list of months, a single month, or `t'
-    to specify all months.  Optional DAY means the Nth DAYNAME of MONTH
-    on or after/before DAY.  DAY defaults to 1 if N>0 and the last day of
-    the month if N<0.
+    Entry will appear on the Nth DAYNAME after/before MONTH DAY.
+    DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
+    If N>0, use the Nth DAYNAME after MONTH DAY.
+    If N<0, use the Nth DAYNAME before MONTH DAY.
+    DAY defaults to 1 if N>0, and MONTH's last day otherwise.
+    MONTH can be a list of months, a single month, or `t' to
+    specify all months.
 
   %%(diary-block M1 D1 Y1 M2 D2 Y2 &optional MARK) text
     Entry will appear on dates between M1/D1/Y1 and M2/D2/Y2,
@@ -1669,7 +1683,7 @@ These functions give the date in alternative calendrical systems:
 
 Theses functions only produce output on certain dates:
 
-`diary-phases-of-moon'         - phases of moon (on the appropriate days)
+`diary-lunar-phases'           - phases of moon (on the appropriate days)
 `diary-hebrew-omer'            - Omer count, within 50 days after Passover
 `diary-hebrew-parasha'         - weekly parasha, every Saturday
 `diary-hebrew-rosh-hodesh'     - Rosh Hodesh, or the day or Saturday before
@@ -1684,8 +1698,7 @@ best if they are non-marking."
         sexp-start sexp entry specifier entry-start line-start
         diary-entry temp literal)
     (goto-char (point-min))
-    (save-excursion
-      (setq file-glob-attrs (nth 1 (diary-pull-attrs nil '()))))
+    (setq file-glob-attrs (nth 1 (diary-pull-attrs nil '())))
     (while (re-search-forward s-entry nil t)
       (backward-char 1)
       (setq sexp-start (point))
@@ -1731,7 +1744,7 @@ best if they are non-marking."
   "Convert A B C into the internal calendar date form.
 The expected order of the inputs depends on `calendar-date-style',
 e.g. in the European case, A = day, B = month, C = year.  Returns
-a list\(MONTH DAY YEAR), i.e. the American style, which is the
+a list (MONTH DAY YEAR), i.e. the American style, which is the
 form used internally by the calendar and diary."
   (cond ((eq calendar-date-style 'iso)  ; YMD
          (list b c a))
@@ -1748,13 +1761,13 @@ form used internally by the calendar and diary."
 ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
 (defun diary-date (month day year &optional mark)
   "Specific date(s) diary entry.
-Entry applies if date is MONTH, DAY, YEAR.  Each parameter can be
-a list of integers, `t' (meaning all values), or an integer.  The
-order of the input parameters changes according to `calendar-date-style'
+Entry applies if date is MONTH, DAY, YEAR.  Each parameter can be a
+list of integers, `t' (meaning all values), or an integer.  The order
+of the input parameters changes according to `calendar-date-style'
 \(e.g. to DAY MONTH YEAR in the European style).
 
-An optional parameter MARK specifies a face or single-character string to
-use when highlighting the day in the calendar."
+An optional parameter MARK specifies a face or single-character string
+to use when highlighting the day in the calendar."
   (let* ((ddate (diary-make-date month day year))
          (dd (calendar-extract-day ddate))
          (mm (calendar-extract-month ddate))
@@ -1777,12 +1790,12 @@ use when highlighting the day in the calendar."
 ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
 (defun diary-block (m1 d1 y1 m2 d2 y2 &optional mark)
   "Block diary entry.
-Entry applies if date is between, or on one of, two dates.  The
-order of the input parameters changes according to
-`calendar-date-style' (e.g. to D1, M1, Y1, D2, M2, Y2 in the European style).
+Entry applies if date is between, or on one of, two dates.  The order
+of the input parameters changes according to `calendar-date-style'
+\(e.g. to D1, M1, Y1, D2, M2, Y2 in the European style).
 
-An optional parameter MARK specifies a face or single-character string to
-use when highlighting the day in the calendar."
+An optional parameter MARK specifies a face or single-character string
+to use when highlighting the day in the calendar."
   (let ((date1 (calendar-absolute-from-gregorian
                 (diary-make-date m1 d1 y1)))
         (date2 (calendar-absolute-from-gregorian
@@ -1793,12 +1806,12 @@ use when highlighting the day in the calendar."
 
 ;; To be called from diary-sexp-entry, where DATE, ENTRY are bound.
 (defun diary-float (month dayname n &optional day mark)
-  "Floating diary entry--entry applies if date is the nth dayname of month.
-Parameters are MONTH, DAYNAME, N.  MONTH can be a list of months, an integer,
-or `t' (meaning all months).  If N is negative, count backward from the end
-of the month.
-
-An optional parameter DAY means the Nth DAYNAME on or after/before MONTH DAY.
+  "Diary entry for the Nth DAYNAME after/before MONTH DAY.
+DAYNAME=0 means Sunday, DAYNAME=1 means Monday, and so on.
+If N>0, use the Nth DAYNAME after MONTH DAY.
+If N<0, use the Nth DAYNAME before MONTH DAY.
+DAY defaults to 1 if N>0, and MONTH's last day otherwise.
+MONTH can be a list of months, an integer, or `t' (meaning all months).
 Optional MARK specifies a face or single-character string to use when
 highlighting the day in the calendar."
   ;; This is messy because the diary entry may apply, but the date on which it
@@ -1871,11 +1884,11 @@ Entry applies if date is the anniversary of MONTH, DAY, YEAR.
 The order of the input parameters changes according to
 `calendar-date-style' (e.g. to DAY MONTH YEAR in the European style).
 
-The diary entry can contain `%d' or `%d%s'; the %d will be
-replaced by the number of years since the MONTH, DAY, YEAR, and the
-%s will be replaced by the ordinal ending of that number (that
-is, `st', `nd', `rd' or `th', as appropriate.  The anniversary of
-February 29 is considered to be March 1 in non-leap years.
+The diary entry can contain `%d' or `%d%s'; the %d will be replaced
+by the number of years since the MONTH, DAY, YEAR, and the %s will
+be replaced by the ordinal ending of that number (that is, `st',
+`nd', `rd' or `th', as appropriate).  The anniversary of February 29
+is considered to be March 1 in non-leap years.
 
 An optional parameter MARK specifies a face or single-character
 string to use when highlighting the day in the calendar."
@@ -1896,13 +1909,15 @@ string to use when highlighting the day in the calendar."
   "Cycle diary entry--entry applies every N days starting at MONTH, DAY, YEAR.
 The order of the input parameters changes according to
 `calendar-date-style' (e.g. to N DAY MONTH YEAR in the European
-style).  ENTRY can contain `%d' or `%d%s'; the %d will be
+style).  The entry can contain `%d' or `%d%s'; the %d will be
 replaced by the number of repetitions since the MONTH DAY YEAR,
 and %s by the ordinal ending of that number (that is, `st', `nd',
-`rd' or `th', as appropriate.
+`rd' or `th', as appropriate).
 
 An optional parameter MARK specifies a face or single-character
 string to use when highlighting the day in the calendar."
+  (or (> n 0)
+      (error "Day count must be positive"))
   (let* ((diff (- (calendar-absolute-from-gregorian date)
                   (calendar-absolute-from-gregorian
                    (diary-make-date month day year))))
@@ -1969,8 +1984,8 @@ If omitted, NONMARKING defaults to nil and FILE defaults to
 `diary-file'."
   (let ((pop-up-frames (or pop-up-frames
                            (window-dedicated-p (selected-window)))))
-    (find-file-other-window (substitute-in-file-name (or file diary-file))))
-  (when (eq major-mode default-major-mode) (diary-mode))
+    (find-file-other-window (or file diary-file)))
+  (when (eq major-mode (default-value 'major-mode)) (diary-mode))
   (widen)
   (diary-unhide-everything)
   (goto-char (point-max))
@@ -1990,11 +2005,12 @@ If omitted, NONMARKING defaults to nil and FILE defaults to
 (define-obsolete-function-alias 'make-diary-entry 'diary-make-entry "23.1")
 
 ;;;###cal-autoload
-(defun diary-insert-entry (arg)
+(defun diary-insert-entry (arg &optional event)
   "Insert a diary entry for the date indicated by point.
 Prefix argument ARG makes the entry nonmarking."
-  (interactive "P")
-  (diary-make-entry (calendar-date-string (calendar-cursor-to-date t) t t)
+  (interactive
+   (list current-prefix-arg last-nonmenu-event))
+  (diary-make-entry (calendar-date-string (calendar-cursor-to-date t event) t t)
                     arg))
 
 ;;;###cal-autoload
@@ -2013,7 +2029,7 @@ Prefix argument ARG makes the entry nonmarking."
   'diary-insert-weekly-entry "23.1")
 
 (defun diary-date-display-form (&optional type)
-  "Return value for `calendar-date-display-form' using `calendar-date-style.'
+  "Return value for `calendar-date-display-form' using `calendar-date-style'.
 Optional symbol TYPE is either `monthly' or `yearly'."
   (cond ((eq type 'monthly) (cond ((eq calendar-date-style 'iso)
                                    '((format "*-*-%.2d"
@@ -2039,11 +2055,11 @@ Optional symbol TYPE is either `monthly' or `yearly'."
 
 (defun diary-insert-entry-1 (&optional type nomark months symbol absfunc)
   "Subroutine to insert a diary entry related to the date at point.
-TYPE is the type of entry (`monthly' or `yearly').  NOMARK
-non-nil means make the entry non-marking.  Array MONTHS is used
-in place of `calendar-month-name-array'.  String SYMBOL marks the
-type of diary entry.  Function ABSFUNC converts absolute dates to
-dates of the appropriate type."
+TYPE is the type of entry (`monthly' or `yearly').  NOMARK non-nil
+means make the entry non-marking.  Array MONTHS is used in place
+of `calendar-month-name-array'.  String SYMBOL marks the type of
+diary entry.  Function ABSFUNC converts absolute dates to dates of
+the appropriate type."
   (let ((calendar-date-display-form (if type
                                         (diary-date-display-form type)
                                       calendar-date-display-form))
@@ -2209,8 +2225,8 @@ names."
 (defmacro diary-font-lock-keywords-1 (markfunc listfunc feature months symbol)
   "Subroutine of the function `diary-font-lock-keywords'.
 If MARKFUNC is a member of `diary-nongregorian-marking-hook', or
-LISTFUNC of `diary-nongregorian-listing-hook', then require FEATURE
-and return a font-lock pattern matching array of MONTHS and marking SYMBOL."
+LISTFUNC of `diary-nongregorian-listing-hook', then require FEATURE and
+return a font-lock pattern matching array of MONTHS and marking SYMBOL."
   `(when (or (memq ',markfunc diary-nongregorian-marking-hook)
              (memq ',listfunc diary-nongregorian-listing-hook))
      (require ',feature)
@@ -2344,6 +2360,11 @@ Fontify the region between BEG and END, quietly unless VERBOSE is non-nil."
       (setq end (line-beginning-position 2)))
   (font-lock-default-fontify-region beg end verbose))
 
+(defvar diary-fancy-overriding-map (let ((map (make-sparse-keymap)))
+                                     (define-key map "q" 'quit-window)
+                                     map)
+  "Keymap overriding minor-mode maps in `diary-fancy-display-mode'.")
+
 (define-derived-mode diary-fancy-display-mode fundamental-mode
   "Diary"
   "Major mode used while displaying diary entries using Fancy Display."
@@ -2352,7 +2373,10 @@ Fontify the region between BEG and END, quietly unless VERBOSE is non-nil."
          t nil nil nil
          (font-lock-fontify-region-function
           . diary-fancy-font-lock-fontify-region-function)))
-  (local-set-key "q" 'quit-window))
+  (local-set-key "q" 'quit-window)
+  (set (make-local-variable 'minor-mode-overriding-map-alist)
+       (list (cons t diary-fancy-overriding-map)))
+  (view-mode 1))
 
 (define-obsolete-function-alias 'fancy-diary-display-mode
   'diary-fancy-display-mode "23.1")
@@ -2367,6 +2391,7 @@ Fontify the region between BEG and END, quietly unless VERBOSE is non-nil."
 ;; `diary-outlook-formats'.
 
 (defvar subject)                        ; bound in diary-from-outlook-gnus
+(defvar body)
 
 (defun diary-from-outlook-internal (&optional test-only)
   "Snarf a diary entry from a message assumed to be from MS Outlook.