]> code.delx.au - gnu-emacs/commitdiff
Merge from origin/emacs-25
authorJohn Wiegley <johnw@newartisans.com>
Fri, 4 Mar 2016 07:52:26 +0000 (23:52 -0800)
committerJohn Wiegley <johnw@newartisans.com>
Fri, 4 Mar 2016 07:52:26 +0000 (23:52 -0800)
bd58c13 Improve documentation of focus-related hooks
00a4720 Further improve doc string of 'disable-point-adjustment'
c582def Further adaptions in file-notify-tests.el for w32notify
a1585e1 Don't bug out on localised dates in gnus-icalendar

1  2 
doc/lispref/commands.texi
lisp/gnus/gnus-icalendar.el
src/keyboard.c
test/lisp/filenotify-tests.el

index 3ea6ea045eb856fd51469a322a08cfcceffbeaef,a94d46e168490de9c6b291e894f743b8c6fb0278..2048e28d959c621a6a87853eb152500cf7a22f5b
@@@ -1664,7 -1664,8 +1664,8 @@@ gets keyboard input.  This choice of wi
  When the user does something to switch between Emacs frames, that
  generates a @dfn{focus event}.  The normal definition of a focus event,
  in the global keymap, is to select a new frame within Emacs, as the user
- would expect.  @xref{Input Focus}.
+ would expect.  @xref{Input Focus}, which also describes hooks related
+ to focus events.
  
  Focus events are represented in Lisp as lists that look like this:
  
@@@ -2617,31 -2618,6 +2618,31 @@@ causes it to evaluate @code{help-form} 
  then continues to wait for a valid input character, or keyboard-quit.
  @end defun
  
 +@defun read-multiple-choice prompt choices
 +Ask user a multiple choice question.  @var{prompt} should be a string
 +that will be displayed as the prompt.
 +
 +@var{choices} is an alist where the first element in each entry is a
 +character to be entered, the second element is a short name for the
 +entry to be displayed while prompting (if there's room, it might be
 +shortened), and the third, optional entry is a longer explanation that
 +will be displayed in a help buffer if the user requests more help.
 +
 +The return value is the matching value from @var{choices}.
 +
 +@lisp
 +(read-multiple-choice
 + "Continue connecting?"
 + '((?a "always" "Accept this certificate this session and for all future sessions.")
 +   (?s "session only" "Accept this certificate this session only.")
 +   (?n "no" "Refuse to use this certificate, and close the connection.")))
 +@end lisp
 +
 +The @code{read-multiple-choice-face} face is used to highlight the
 +matching characters in the name string on graphical terminals.
 +
 +@end defun
 +
  @node Event Mod
  @subsection Modifying and Translating Input Events
  @cindex modifiers of events
index 96697b22791e26bd6504a548734a9ea7e45302d8,d7a431ae8c6d16948daafd69e5a444a960c60325..dea6523a541f53711bad4c4fd8e66063f53711ef
    nil
    "iCalendar class for REPLY events")
  
 -(defmethod gnus-icalendar-event:recurring-p ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:recurring-p ((event gnus-icalendar-event))
    "Return t if EVENT is recurring."
    (not (null (gnus-icalendar-event:recur event))))
  
 -(defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:recurring-freq ((event gnus-icalendar-event))
    "Return recurring frequency of EVENT."
    (let ((rrule (gnus-icalendar-event:recur event)))
      (string-match "FREQ=\\([[:alpha:]]+\\)" rrule)
      (match-string 1 rrule)))
  
 -(defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:recurring-interval ((event gnus-icalendar-event))
    "Return recurring interval of EVENT."
    (let ((rrule (gnus-icalendar-event:recur event))
          (default-interval 1))
      (or (match-string 1 rrule)
          default-interval)))
  
 -(defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
    (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
  
  (defun gnus-icalendar-event--decode-datefield (event field zone-map)
  (defun gnus-icalendar-event--find-attendee (ical name-or-email)
    (let* ((event (car (icalendar--all-events ical)))
           (event-props (caddr event)))
 -    (gmm-labels ((attendee-name (att) (plist-get (cadr att) 'CN))
 -                 (attendee-email (att)
 -                   (replace-regexp-in-string "^.*MAILTO:" "" (caddr att)))
 -                 (attendee-prop-matches-p (prop)
 -                   (and (eq (car prop) 'ATTENDEE)
 -                        (or (member (attendee-name prop) name-or-email)
 -                            (let ((att-email (attendee-email prop)))
 -                              (gnus-icalendar-find-if (lambda (email)
 -                                                        (string-match email att-email))
 -                                                      name-or-email))))))
 -
 +    (cl-labels ((attendee-name (att) (plist-get (cadr att) 'CN))
 +              (attendee-email
 +               (att)
 +               (replace-regexp-in-string "^.*MAILTO:" "" (caddr att)))
 +              (attendee-prop-matches-p
 +               (prop)
 +               (and (eq (car prop) 'ATTENDEE)
 +                    (or (member (attendee-name prop) name-or-email)
 +                        (let ((att-email (attendee-email prop)))
 +                          (gnus-icalendar-find-if
 +                           (lambda (email)
 +                             (string-match email att-email))
 +                           name-or-email))))))
        (gnus-icalendar-find-if #'attendee-prop-matches-p event-props))))
  
  (defun gnus-icalendar-event--get-attendee-names (ical)
                            (lambda (p) (eq (car p) 'ATTENDEE))
                            (caddr event))))
  
 -    (gmm-labels ((attendee-role (prop) (plist-get (cadr prop) 'ROLE))
 -                 (attendee-name (prop)
 -                                (or (plist-get (cadr prop) 'CN)
 -                                    (replace-regexp-in-string "^.*MAILTO:" "" (caddr prop))))
 -                 (attendees-by-type (type)
 -                   (gnus-remove-if-not
 -                    (lambda (p) (string= (attendee-role p) type))
 -                    attendee-props))
 -                 (attendee-names-by-type (type)
 -                    (mapcar #'attendee-name (attendees-by-type type))))
 -
 +    (cl-labels
 +      ((attendee-role (prop) (plist-get (cadr prop) 'ROLE))
 +       (attendee-name
 +        (prop)
 +        (or (plist-get (cadr prop) 'CN)
 +            (replace-regexp-in-string "^.*MAILTO:" "" (caddr prop))))
 +       (attendees-by-type (type)
 +                          (gnus-remove-if-not
 +                           (lambda (p) (string= (attendee-role p) type))
 +                           attendee-props))
 +       (attendee-names-by-type
 +        (type)
 +        (mapcar #'attendee-name (attendees-by-type type))))
        (list
         (attendee-names-by-type "REQ-PARTICIPANT")
         (attendee-names-by-type "OPT-PARTICIPANT")))))
                         ((string= method "REPLY") 'gnus-icalendar-event-reply)
                         (t 'gnus-icalendar-event))))
  
 -    (gmm-labels ((map-property (prop)
 -                   (let ((value (icalendar--get-event-property event prop)))
 -                     (when value
 -                       ;; ugly, but cannot get
 -                       ;;replace-regexp-in-string work with "\\" as
 -                       ;;REP, plus we should also handle "\\;"
 -                       (replace-regexp-in-string
 -                        "\\\\," ","
 -                        (replace-regexp-in-string
 -                         "\\\\n" "\n" (substring-no-properties value))))))
 -                 (accumulate-args (mapping)
 -                   (destructuring-bind (slot . ical-property) mapping
 -                     (setq args (append (list
 -                                         (intern (concat ":" (symbol-name slot)))
 -                                         (map-property ical-property))
 -                                        args)))))
 -
 +    (cl-labels
 +      ((map-property
 +        (prop)
 +        (let ((value (icalendar--get-event-property event prop)))
 +          (when value
 +            ;; ugly, but cannot get
 +            ;;replace-regexp-in-string work with "\\" as
 +            ;;REP, plus we should also handle "\\;"
 +            (replace-regexp-in-string
 +             "\\\\," ","
 +             (replace-regexp-in-string
 +              "\\\\n" "\n" (substring-no-properties value))))))
 +       (accumulate-args
 +        (mapping)
 +        (destructuring-bind (slot . ical-property) mapping
 +          (setq args (append (list
 +                              (intern (concat ":" (symbol-name slot)))
 +                              (map-property ical-property))
 +                             args)))))
        (mapc #'accumulate-args prop-map)
        (apply 'make-instance event-class args))))
  
@@@ -270,46 -264,41 +270,46 @@@ status will be retrieved from the firs
    (let ((summary-status (capitalize (symbol-name status)))
          (attendee-status (upcase (symbol-name status)))
          reply-event-lines)
 -    (gmm-labels ((update-summary (line)
 -                   (if (string-match "^[^:]+:" line)
 -                       (replace-match (format "\\&%s: " summary-status) t nil line)
 -                     line))
 -                 (update-dtstamp ()
 -                   (format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t))
 -                 (attendee-matches-identity (line)
 -                   (gnus-icalendar-find-if (lambda (name) (string-match-p name line))
 -                                           identities))
 -                 (update-attendee-status (line)
 -                   (when (and (attendee-matches-identity line)
 -                              (string-match "\\(PARTSTAT=\\)[^;]+" line))
 -                     (replace-match (format "\\1%s" attendee-status) t nil line)))
 -                 (process-event-line (line)
 -                   (when (string-match "^\\([^;:]+\\)" line)
 -                     (let* ((key (match-string 0 line))
 -                            ;; NOTE: not all of the below fields are mandatory,
 -                            ;; but they are often present in other clients'
 -                            ;; replies. Can be helpful for debugging, too.
 -                            (new-line
 -                             (cond
 -                              ((string= key "ATTENDEE") (update-attendee-status line))
 -                              ((string= key "SUMMARY") (update-summary line))
 -                              ((string= key "DTSTAMP") (update-dtstamp))
 -                              ((member key '("ORGANIZER" "DTSTART" "DTEND"
 -                                             "LOCATION" "DURATION" "SEQUENCE"
 -                                             "RECURRENCE-ID" "UID")) line)
 -                              (t nil))))
 -                       (when new-line
 -                         (push new-line reply-event-lines))))))
 +    (cl-labels
 +      ((update-summary
 +        (line)
 +        (if (string-match "^[^:]+:" line)
 +            (replace-match (format "\\&%s: " summary-status) t nil line)
 +          line))
 +       (update-dtstamp ()
 +                       (format-time-string "DTSTAMP:%Y%m%dT%H%M%SZ" nil t))
 +       (attendee-matches-identity
 +        (line)
 +        (gnus-icalendar-find-if (lambda (name) (string-match-p name line))
 +                                identities))
 +       (update-attendee-status
 +        (line)
 +        (when (and (attendee-matches-identity line)
 +                   (string-match "\\(PARTSTAT=\\)[^;]+" line))
 +          (replace-match (format "\\1%s" attendee-status) t nil line)))
 +       (process-event-line
 +        (line)
 +        (when (string-match "^\\([^;:]+\\)" line)
 +          (let* ((key (match-string 0 line))
 +                 ;; NOTE: not all of the below fields are mandatory,
 +                 ;; but they are often present in other clients'
 +                 ;; replies. Can be helpful for debugging, too.
 +                 (new-line
 +                  (cond
 +                   ((string= key "ATTENDEE") (update-attendee-status line))
 +                   ((string= key "SUMMARY") (update-summary line))
 +                   ((string= key "DTSTAMP") (update-dtstamp))
 +                   ((member key '("ORGANIZER" "DTSTART" "DTEND"
 +                                  "LOCATION" "DURATION" "SEQUENCE"
 +                                  "RECURRENCE-ID" "UID")) line)
 +                   (t nil))))
 +            (when new-line
 +              (push new-line reply-event-lines))))))
  
        (mapc #'process-event-line (split-string ical-request "\n"))
  
        (unless (gnus-icalendar-find-if (lambda (x) (string-match "^ATTENDEE" x))
 -                          reply-event-lines)
 +                                    reply-event-lines)
          (error "Could not find an event attendee matching given identity"))
  
        (mapconcat #'identity `("BEGIN:VEVENT"
  The reply will have STATUS (`accepted', `tentative' or  `declined').
  The reply will be composed for attendees matching any entry
  on the IDENTITIES list."
 -  (gmm-labels ((extract-block (blockname)
 -               (save-excursion
 -                 (let ((block-start-re (format "^BEGIN:%s" blockname))
 -                       (block-end-re (format "^END:%s" blockname))
 -                       start)
 -                   (when (re-search-forward block-start-re nil t)
 -                     (setq start (line-beginning-position))
 -                     (re-search-forward block-end-re)
 -                     (buffer-substring-no-properties start (line-end-position)))))))
 -
 +  (cl-labels
 +      ((extract-block
 +      (blockname)
 +      (save-excursion
 +        (let ((block-start-re (format "^BEGIN:%s" blockname))
 +              (block-end-re (format "^END:%s" blockname))
 +              start)
 +          (when (re-search-forward block-start-re nil t)
 +            (setq start (line-beginning-position))
 +            (re-search-forward block-end-re)
 +            (buffer-substring-no-properties start (line-end-position)))))))
      (let (zone event)
        (with-current-buffer (icalendar--get-unfolded-buffer (get-buffer buf))
          (goto-char (point-min))
  (defvar gnus-icalendar-org-enabled-p nil)
  
  
 -(defmethod gnus-icalendar-event:org-repeat ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:org-repeat ((event gnus-icalendar-event))
    "Return `org-mode' timestamp repeater string for recurring EVENT.
  Return nil for non-recurring EVENT."
    (when (gnus-icalendar-event:recurring-p event)
        (when org-freq
          (format "+%s%s" (gnus-icalendar-event:recurring-interval event) org-freq)))))
  
 -(defmethod gnus-icalendar-event:org-timestamp ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:org-timestamp ((event gnus-icalendar-event))
    "Build `org-mode' timestamp from EVENT start/end dates and recurrence info."
    (let* ((start (gnus-icalendar-event:start-time event))
           (end (gnus-icalendar-event:end-time event))
 -         (start-date (format-time-string "%Y-%m-%d %a" start))
 +         (start-date (format-time-string "%Y-%m-%d" start))
           (start-time (format-time-string "%H:%M" start))
           (start-at-midnight (string= start-time "00:00"))
 -         (end-date (format-time-string "%Y-%m-%d %a" end))
 +         (end-date (format-time-string "%Y-%m-%d" end))
           (end-time (format-time-string "%H:%M" end))
           (end-at-midnight (string= end-time "00:00"))
-          (start-end-date-diff (/ (float-time (time-subtract
-                                         (date-to-time end-date)
-                                         (date-to-time start-date)))
-                                  86400))
+          (start-end-date-diff
+         (/ (float-time (time-subtract
+                         (org-time-string-to-time end-date)
+                         (org-time-string-to-time start-date)))
+            86400))
           (org-repeat (gnus-icalendar-event:org-repeat event))
           (repeat (if org-repeat (concat " " org-repeat) ""))
           (time-1-day '(0 86400)))
       ;; A 0:0 - A+1 0:0 -> A
       ;; A 0:0 - A+n 0:0 -> A - A+n-1
       ((and start-at-midnight end-at-midnight) (if (> start-end-date-diff 1)
 -                                                  (let ((end-ts (format-time-string "%Y-%m-%d %a" (time-subtract end time-1-day))))
 +                                                  (let ((end-ts (format-time-string "%Y-%m-%d" (time-subtract end time-1-day))))
                                                      (format "<%s>--<%s>" start-date end-ts))
                                                  (format "<%s%s>" start-date repeat)))
       ;; end midnight
       ;; A .:. - A+n 0:0 -> A .:. - A_n-1
       (end-at-midnight (if (= start-end-date-diff 1)
                            (format "<%s %s-23:59%s>" start-date start-time repeat)
 -                        (let ((end-ts (format-time-string "%Y-%m-%d %a" (time-subtract end time-1-day))))
 +                        (let ((end-ts (format-time-string "%Y-%m-%d" (time-subtract end time-1-day))))
                            (format "<%s %s>--<%s>" start-date start-time end-ts))))
       ;; start midnight
       ;; A 0:0 - A .:. -> A 0:0-.:. (default 1)
    (mapconcat #'identity participants ", "))
  
  ;; TODO: make the template customizable
 -(defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status)
 +(cl-defmethod gnus-icalendar-event->org-entry ((event gnus-icalendar-event) reply-status)
    "Return string with new `org-mode' entry describing EVENT."
    (with-temp-buffer
      (org-mode)
@@@ -509,17 -498,16 +510,17 @@@ the optional ORG-FILE argument is speci
  is searched."
    (let ((uid (gnus-icalendar-event:uid event))
          (files (or org-file (org-agenda-files t 'ifmode))))
 -    (gmm-labels
 -        ((find-event-in (file)
 -           (org-check-agenda-file file)
 -           (with-current-buffer (find-file-noselect file)
 -             (let ((event-pos (org-find-entry-with-id uid)))
 -               (when (and event-pos
 -                          (string= (cdr (assoc "ICAL_EVENT" (org-entry-properties event-pos)))
 -                                   "t"))
 -                 (throw 'found file))))))
 -
 +    (cl-labels
 +        ((find-event-in
 +        (file)
 +        (org-check-agenda-file file)
 +        (with-current-buffer (find-file-noselect file)
 +          (let ((event-pos (org-find-entry-with-id uid)))
 +            (when (and event-pos
 +                       (string= (cdr (assoc "ICAL_EVENT"
 +                                            (org-entry-properties event-pos)))
 +                                "t"))
 +              (throw 'found file))))))
        (gnus-icalendar-find-if #'find-event-in files))))
  
  
                      (fill-region (point-min) (point-max))))
  
                  ;; update entry properties
 -                (gmm-labels
 -                    ((update-org-entry (position property value)
 -                                       (if (or (null value)
 -                                               (string= value ""))
 -                                           (org-entry-delete position property)
 -                                         (org-entry-put position property value))))
 +                (cl-labels
 +                    ((update-org-entry
 +                    (position property value)
 +                    (if (or (null value)
 +                            (string= value ""))
 +                        (org-entry-delete position property)
 +                      (org-entry-put position property value))))
  
                    (update-org-entry event-pos "ORGANIZER" organizer)
                    (update-org-entry event-pos "LOCATION" location)
 -                  (update-org-entry event-pos "PARTICIPATION_TYPE" (symbol-name participation-type))
 -                  (update-org-entry event-pos "REQ_PARTICIPANTS" (gnus-icalendar--format-participant-list req-participants))
 -                  (update-org-entry event-pos "OPT_PARTICIPANTS" (gnus-icalendar--format-participant-list opt-participants))
 +                  (update-org-entry event-pos "PARTICIPATION_TYPE"
 +                                  (symbol-name participation-type))
 +                  (update-org-entry event-pos "REQ_PARTICIPANTS"
 +                                  (gnus-icalendar--format-participant-list
 +                                   req-participants))
 +                  (update-org-entry event-pos "OPT_PARTICIPANTS"
 +                                  (gnus-icalendar--format-participant-list
 +                                   opt-participants))
                    (update-org-entry event-pos "RRULE" recur)
 -                  (update-org-entry event-pos "REPLY"
 -                                    (if reply-status (capitalize (symbol-name reply-status))
 -                                      "Not replied yet")))
 +                  (update-org-entry
 +                 event-pos "REPLY"
 +                 (if reply-status (capitalize (symbol-name reply-status))
 +                   "Not replied yet")))
                  (save-buffer)))))))))
  
  
  
      (org-agenda-list nil (gnus-icalendar-event:start event) duration-days)))
  
 -(defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-request) reply-status)
 +(cl-defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-request) reply-status)
    (if (gnus-icalendar-find-org-event-file event)
        (gnus-icalendar--update-org-event event reply-status)
      (gnus-icalendar:org-event-save event reply-status)))
  
 -(defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-cancel) reply-status)
 +(cl-defmethod gnus-icalendar-event:sync-to-org ((event gnus-icalendar-event-cancel) reply-status)
    (when (gnus-icalendar-find-org-event-file event)
      (gnus-icalendar--cancel-org-event event)))
  
@@@ -722,43 -703,40 +723,43 @@@ only makes sense to define names or ema
  
  These will be used to retrieve the RSVP information from ical events."
    (apply #'append
 -         (mapcar (lambda (x) (if (listp x) x (list x)))
 -                 (list user-full-name (regexp-quote user-mail-address)
 -                       ; NOTE: these can be lists
 -                       gnus-ignored-from-addresses ; already regexp-quoted
 -                       message-alternative-emails  ;
 -                       (mapcar #'regexp-quote gnus-icalendar-additional-identities)))))
 +         (mapcar
 +        (lambda (x) (if (listp x) x (list x)))
 +        (list user-full-name (regexp-quote user-mail-address)
 +              ;; NOTE: these can be lists
 +              gnus-ignored-from-addresses ; already regexp-quoted
 +              (unless (functionp message-alternative-emails) ; String or function.
 +                message-alternative-emails)
 +              (mapcar #'regexp-quote gnus-icalendar-additional-identities)))))
  
  ;; TODO: make the template customizable
 -(defmethod gnus-icalendar-event->gnus-calendar ((event gnus-icalendar-event) &optional reply-status)
 +(cl-defmethod gnus-icalendar-event->gnus-calendar ((event gnus-icalendar-event) &optional reply-status)
    "Format an overview of EVENT details."
 -  (gmm-labels ((format-header (x)
 -            (format "%-12s%s"
 -                    (propertize (concat (car x) ":") 'face 'bold)
 -                    (cadr x))))
 +  (cl-labels
 +      ((format-header (x)
 +                    (format "%-12s%s"
 +                            (propertize (concat (car x) ":") 'face 'bold)
 +                            (cadr x))))
  
      (with-slots (organizer summary description location recur uid
                             method rsvp participation-type) event
        (let ((headers `(("Summary" ,summary)
 -                      ("Location" ,(or location ""))
 -                      ("Time" ,(gnus-icalendar-event:org-timestamp event))
 -                      ("Organizer" ,organizer)
 -                      ("Attendance" ,(if (eq participation-type 'non-participant)
 -                                         "You are not listed as an attendee"
 -                                       (capitalize (symbol-name participation-type))))
 -                      ("Method" ,method))))
 -
 -       (when (and (not (gnus-icalendar-event-reply-p event)) rsvp)
 -         (setq headers (append headers
 -                               `(("Status" ,(or reply-status "Not replied yet"))))))
 -
 -       (concat
 -        (mapconcat #'format-header headers "\n")
 -        "\n\n"
 -        description)))))
 +                     ("Location" ,(or location ""))
 +                     ("Time" ,(gnus-icalendar-event:org-timestamp event))
 +                     ("Organizer" ,organizer)
 +                     ("Attendance" ,(if (eq participation-type 'non-participant)
 +                                        "You are not listed as an attendee"
 +                                      (capitalize (symbol-name participation-type))))
 +                     ("Method" ,method))))
 +
 +      (when (and (not (gnus-icalendar-event-reply-p event)) rsvp)
 +        (setq headers (append headers
 +                              `(("Status" ,(or reply-status "Not replied yet"))))))
 +
 +      (concat
 +       (mapconcat #'format-header headers "\n")
 +       "\n\n"
 +       description)))))
  
  (defmacro gnus-icalendar-with-decoded-handle (handle &rest body)
    "Execute BODY in buffer containing the decoded contents of HANDLE."
         (with-temp-buffer
           (mm-insert-part ,handle)
           (when (string= ,charset "utf-8")
 -           (mm-decode-coding-region (point-min) (point-max) 'utf-8))
 -
 +           (decode-coding-region (point-min) (point-max) 'utf-8))
           ,@body))))
  
  
    ;; FIXME: the gnus-mime-button-map keymap does not make sense for this kind
    ;; of button.
    (let ((start (point)))
 -    (gnus-add-text-properties
 +    (add-text-properties
       start
       (progn
         (insert "[ " text " ]")
         face ,gnus-article-button-face
         gnus-data ,data))
      (widget-convert-button 'link start (point)
 -                           :action 'gnus-widget-press-button
 -                           :button-keymap gnus-widget-button-keymap)))
 +                           :action 'gnus-widget-press-button)))
  
  (defun gnus-icalendar-send-buffer-by-mail (buffer-name subject)
    (let ((message-signature nil))
                     (current-buffer) status (gnus-icalendar-identities)))))
  
      (when reply
 -      (gmm-labels ((fold-icalendar-buffer ()
 -               (goto-char (point-min))
 -               (while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
 -                 (replace-match "\\1\n \\2")
 -                 (goto-char (line-beginning-position)))))
 +      (cl-labels
 +        ((fold-icalendar-buffer
 +          ()
 +          (goto-char (point-min))
 +          (while (re-search-forward "^\\(.\\{72\\}\\)\\(.+\\)$" nil t)
 +            (replace-match "\\1\n \\2")
 +            (goto-char (line-beginning-position)))))
          (let ((subject (concat (capitalize (symbol-name status))
                                 ": " (gnus-icalendar-event:summary event))))
  
  (defun gnus-icalendar-sync-event-to-org (event)
    (gnus-icalendar-event:sync-to-org event gnus-icalendar-reply-status))
  
 -(defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event) handle)
 +(cl-defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event) handle)
    (when (gnus-icalendar-event:rsvp event)
      `(("Accept" gnus-icalendar-reply (,handle accepted ,event))
        ("Tentative" gnus-icalendar-reply (,handle tentative ,event))
        ("Decline" gnus-icalendar-reply (,handle declined ,event)))))
  
 -(defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event-reply) handle)
 +(cl-defmethod gnus-icalendar-event:inline-reply-buttons ((event gnus-icalendar-event-reply) handle)
    "No buttons for REPLY events."
    nil)
  
 -(defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event))
    (or (when gnus-icalendar-org-enabled-p
          (gnus-icalendar--get-org-event-reply-status event))
        "Not replied yet"))
  
 -(defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event-reply))
 +(cl-defmethod gnus-icalendar-event:inline-reply-status ((event gnus-icalendar-event-reply))
    "No reply status for REPLY events."
    nil)
  
  
 -(defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event))
 +(cl-defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event))
    (let* ((org-entry-exists-p (gnus-icalendar-find-org-event-file event))
           (export-button-text (if org-entry-exists-p "Update Org Entry" "Export to Org")))
  
                   `("Show Org Entry" gnus-icalendar--show-org-event ,event))))))
  
  
 -(defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event-cancel))
 +(cl-defmethod gnus-icalendar-event:inline-org-buttons ((event gnus-icalendar-event-cancel))
    (let ((org-entry-exists-p (gnus-icalendar-find-org-event-file event)))
  
      (delq nil (list
      (setq gnus-icalendar-reply-status nil)
  
      (when event
 -      (gmm-labels ((insert-button-group (buttons)
 -                (when buttons
 -                  (mapc (lambda (x)
 -                          (apply 'gnus-icalendar-insert-button x)
 -                          (insert "    "))
 -                        buttons)
 -                  (insert "\n\n"))))
 +      (cl-labels
 +        ((insert-button-group
 +          (buttons)
 +          (when buttons
 +            (mapc (lambda (x)
 +                    (apply 'gnus-icalendar-insert-button x)
 +                    (insert "    "))
 +                  buttons)
 +            (insert "\n\n"))))
  
          (insert-button-group
         (gnus-icalendar-event:inline-reply-buttons event handle))
diff --combined src/keyboard.c
index 4d1072776348fa5e6386efc92821841d3b92655a,ef86e69bf91d28e49e5de9df6126720762f43553..6535e04d826bb7830021e7a40c49d78998a2e138
@@@ -5968,6 -5968,7 +5968,6 @@@ make_lispy_event (struct input_event *e
        }
  #endif
  
 -
  #if defined HAVE_INOTIFY || defined HAVE_KQUEUE || defined HAVE_GFILENOTIFY
      case FILE_NOTIFY_EVENT:
        {
@@@ -10299,9 -10300,6 +10299,9 @@@ handle_interrupt (bool in_signal_handle
         is used.  Note that [Enter] is not echoed by dos.  */
        cursor_to (SELECTED_FRAME (), 0, 0);
  #endif
 +
 +      write_stdout ("Emacs is resuming after an emergency escape.\n");
 +
        /* It doesn't work to autosave while GC is in progress;
         the code used for auto-saving doesn't cope with the mark bit.  */
        if (!gc_in_progress)
@@@ -11624,8 -11622,8 +11624,8 @@@ It's called with one argument, the hel
  
  After a command is executed, if point moved into a region that has
  special properties (e.g. composition, display), Emacs adjusts point to
- the boundary of the region.  But when a command binds this variable to
non-nil, this point adjustment is suppressed.
+ the boundary of the region.  But when a command leaves this variable at
a non-nil value (e.g., with a setq), this point adjustment is suppressed.
  
  This variable is set to nil before reading a command, and is checked
  just after executing the command.  */);
               doc: /* If non-nil, always suppress point adjustments.
  
  The default value is nil, in which case point adjustments are
- suppressed only after special commands that set
- `disable-point-adjustment' (which see) to non-nil.  */);
+ suppressed only after special commands that leave
+ `disable-point-adjustment' (which see) at a non-nil value.  */);
    Vglobal_disable_point_adjustment = Qnil;
  
    DEFVAR_LISP ("minibuffer-message-timeout", Vminibuffer_message_timeout,
@@@ -11706,25 -11704,6 +11706,25 @@@ Currently, the only supported values fo
  variable are `sigusr1' and `sigusr2'.  */);
    Vdebug_on_event = intern_c_string ("sigusr2");
  
 +  DEFVAR_BOOL ("attempt-stack-overflow-recovery",
 +               attempt_stack_overflow_recovery,
 +               doc: /* If non-nil, attempt to recover from C stack
 +overflow.  This recovery is unsafe and may lead to deadlocks or data
 +corruption, but it usually works and may preserve modified buffers
 +that would otherwise be lost.  If nil, treat stack overflow like any
 +other kind of crash.  */);
 +  attempt_stack_overflow_recovery = true;
 +
 +  DEFVAR_BOOL ("attempt-orderly-shutdown-on-fatal-signal",
 +               attempt_orderly_shutdown_on_fatal_signal,
 +               doc: /* If non-nil, attempt to perform an orderly
 +shutdown when Emacs receives a fatal signal (e.g., a crash).
 +This cleanup is unsafe and may lead to deadlocks or data corruption,
 +but it usually works and may preserve modified buffers that would
 +otherwise be lost.  If nil, crash immediately in response to fatal
 +signals.  */);
 +  attempt_orderly_shutdown_on_fatal_signal = true;
 +
    /* Create the initial keyboard.  Qt means 'unset'.  */
    initial_kboard = allocate_kboard (Qt);
  }
index a16de7fb0587e7e888d8e1d70d2087e9bdfc7577,9f0c0ed0dc1609f87226d5170f7c93ed03d727f3..9f0c0ed0dc1609f87226d5170f7c93ed03d727f3
@@@ -64,7 -64,7 +64,7 @@@
  (defvar file-notify--test-event nil)
  (defvar file-notify--test-events nil)
  
- (defconst file-notify--test-read-event-timeout 0.02
+ (defconst file-notify--test-read-event-timeout 0.01
    "Timeout for `read-event' calls.
  It is different for local and remote file notification libraries.")
  
@@@ -72,7 -72,7 +72,7 @@@
    "Timeout to wait for arriving events, in seconds."
    (cond
     ((file-remote-p temporary-file-directory) 6)
-    ((string-equal (file-notify--test-library) "w32notify") 10)
+    ((string-equal (file-notify--test-library) "w32notify") 4)
     ((eq system-type 'cygwin) 10)
     (t 3)))
  
@@@ -417,8 -417,8 +417,8 @@@ longer than timeout seconds for the eve
                  '(change) 'file-notify--test-event-handler)))
          (file-notify--test-with-events
              (cond
-              ;; w32notify does raise a `stopped' event when a
-              ;; watched directory is deleted.
+              ;; w32notify does not raise `deleted' and `stopped'
+              ;; events for the watched directory.
               ((string-equal (file-notify--test-library) "w32notify")
                '(created changed deleted))
               ;; cygwin recognizes only `deleted' and `stopped' events.
          (file-notify--test-with-events
              (cond
               ;; w32notify does not distinguish between `changed' and
-              ;; `attribute-changed'.
+              ;; `attribute-changed'.  It does not raise `deleted'
+              ;; and `stopped' events for the watched directory.
               ((string-equal (file-notify--test-library) "w32notify")
-               '(created changed created changed changed changed changed
+               '(created changed created changed
+                 changed changed changed
                  deleted deleted))
               ;; cygwin recognizes only `deleted' and `stopped' events.
               ((eq system-type 'cygwin)
                  '(change) 'file-notify--test-event-handler)))
          (file-notify--test-with-events
              (cond
-              ;; w32notify does not distinguish between `changed' and
-              ;; `attribute-changed'.
+              ;; w32notify does not raise `deleted' and `stopped'
+              ;; events for the watched directory.
               ((string-equal (file-notify--test-library) "w32notify")
                '(created changed renamed deleted))
               ;; cygwin recognizes only `deleted' and `stopped' events.
            (should (string-match "another text" (buffer-string)))
  
              ;; Stop file notification.  Autorevert shall still work via polling.
-           ;; It doesn't work for w32notify.
-           (unless (string-equal (file-notify--test-library) "w32notify")
-             (file-notify-rm-watch auto-revert-notify-watch-descriptor)
+           (file-notify-rm-watch auto-revert-notify-watch-descriptor)
+           (file-notify--wait-for-events
+            timeout (null auto-revert-use-notify))
+           (should-not auto-revert-use-notify)
+           (should-not auto-revert-notify-watch-descriptor)
+           ;; Modify file.  We wait for two seconds, in order to
+           ;; have another timestamp.  One second seems to be too
+           ;; short.
+           (with-current-buffer (get-buffer-create "*Messages*")
+             (narrow-to-region (point-max) (point-max)))
+           (sleep-for 2)
+           (write-region
+            "foo bla" nil file-notify--test-tmpfile nil 'no-message)
+           ;; Check, that the buffer has been reverted.
+           (with-current-buffer (get-buffer-create "*Messages*")
              (file-notify--wait-for-events
-              timeout (null auto-revert-use-notify))
-             (should-not auto-revert-use-notify)
-             (should-not auto-revert-notify-watch-descriptor)
-             ;; Modify file.  We wait for two seconds, in order to
-             ;; have another timestamp.  One second seems to be too
-             ;; short.
-             (with-current-buffer (get-buffer-create "*Messages*")
-               (narrow-to-region (point-max) (point-max)))
-             (sleep-for 2)
-             (write-region
-              "foo bla" nil file-notify--test-tmpfile nil 'no-message)
-             ;; Check, that the buffer has been reverted.
-             (with-current-buffer (get-buffer-create "*Messages*")
-               (file-notify--wait-for-events
-                timeout
-                (string-match
-                 (format-message "Reverting buffer `%s'." (buffer-name buf))
-                 (buffer-string))))
-             (should (string-match "foo bla" (buffer-string))))))
+              timeout
+              (string-match
+               (format-message "Reverting buffer `%s'." (buffer-name buf))
+               (buffer-string))))
+           (should (string-match "foo bla" (buffer-string)))))
  
        ;; Cleanup.
        (with-current-buffer "*Messages*" (widen))
      (file-notify--test-cleanup))
  
    (unwind-protect
-       ;; w32notify does not send a `stopped' event when deleting a
-       ;; directory.  The test does not work, therefore.
-       (unless (string-equal (file-notify--test-library) "w32notify")
-       (let ((temporary-file-directory
-              (make-temp-file "file-notify-test-parent" t)))
-         (should
-          (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
-                file-notify--test-desc
-                (file-notify-add-watch
-                 temporary-file-directory
-                 '(change) #'file-notify--test-event-handler)))
-         (file-notify--test-with-events
-             (cond
-              ;; cygwin recognizes only `deleted' and `stopped' events.
-              ((eq system-type 'cygwin)
-               '(deleted stopped))
-              ;; There are two `deleted' events, for the file and for
-              ;; the directory.  Except for kqueue.
-              ((string-equal (file-notify--test-library) "kqueue")
-               '(created changed deleted stopped))
-              (t '(created changed deleted deleted stopped)))
-           (should (file-notify-valid-p file-notify--test-desc))
-           (read-event nil nil file-notify--test-read-event-timeout)
-           (write-region
-            "any text" nil file-notify--test-tmpfile nil 'no-message)
-           (read-event nil nil file-notify--test-read-event-timeout)
-           (delete-directory temporary-file-directory t))
-         ;; After deleting the parent directory, the descriptor must
-         ;; not be valid anymore.
-         (should-not (file-notify-valid-p file-notify--test-desc))))
+       (let ((temporary-file-directory
+            (make-temp-file "file-notify-test-parent" t)))
+       (should
+        (setq file-notify--test-tmpfile (file-notify--test-make-temp-name)
+              file-notify--test-desc
+              (file-notify-add-watch
+               temporary-file-directory
+               '(change) #'file-notify--test-event-handler)))
+       (file-notify--test-with-events
+        (cond
+         ;; w32notify does not raise `deleted' and `stopped' events
+         ;; for the watched directory.
+         ((string-equal (file-notify--test-library) "w32notify")
+          '(created changed deleted))
+         ;; cygwin recognizes only `deleted' and `stopped' events.
+         ((eq system-type 'cygwin)
+          '(deleted stopped))
+         ;; There are two `deleted' events, for the file and for the
+         ;; directory.  Except for kqueue.
+         ((string-equal (file-notify--test-library) "kqueue")
+          '(created changed deleted stopped))
+         (t '(created changed deleted deleted stopped)))
+        (should (file-notify-valid-p file-notify--test-desc))
+        (read-event nil nil file-notify--test-read-event-timeout)
+        (write-region
+         "any text" nil file-notify--test-tmpfile nil 'no-message)
+        (read-event nil nil file-notify--test-read-event-timeout)
+        (delete-directory temporary-file-directory t))
+       ;; After deleting the parent directory, the descriptor must
+       ;; not be valid anymore.
+       (should-not (file-notify-valid-p file-notify--test-desc)))
  
      ;; Cleanup.
      (file-notify--test-cleanup)))
      (file-notify--test-cleanup))
  
    (unwind-protect
-       ;; The batch-mode operation of w32notify is fragile (there's no
-       ;; input threads to send the message to).
-       (unless (and noninteractive
-                  (string-equal (file-notify--test-library) "w32notify"))
-         (setq file-notify--test-tmpfile
+       (progn
+       (setq file-notify--test-tmpfile
              (file-name-as-directory (file-notify--test-make-temp-name)))
          (make-directory file-notify--test-tmpfile)
        (should
@@@ -1045,7 -1043,11 +1043,11 @@@ the file watch.
                      directory-files-no-dot-files-regexp 'nosort))
                    'deleted)
                   ;; The events of the directory itself.
-                  '(deleted stopped))))
+                  (cond
+                 ;; w32notify does not raise `deleted' and `stopped'
+                 ;; events for the watched directory.
+                   ((string-equal (file-notify--test-library) "w32notify") '())
+                   (t '(deleted stopped))))))
            (delete-directory file-notify--test-tmpfile 'recursive))
          (should-not (file-notify-valid-p file-notify--test-desc1))
          (should-not (file-notify-valid-p file-notify--test-desc2)))
  
  ;; TODO:
  
- ;; * For w32notify, no stopped events arrive when a directory is removed.
+ ;; * kqueue does not send all expected `deleted' events.  Maybe due to
+ ;;   the missing directory monitor.
+ ;; * For w32notify, no `deleted' and `stopped' events arrive when a
+ ;;   directory is removed.
+ ;; * For w32notify, no `attribute-changed' events arrive.  Its sends
+ ;;   `changed' events instead.
  ;; * Check, why cygwin recognizes only `deleted' and `stopped' events.
  
  (provide 'file-notify-tests)