commit 61c35e415cd4c8046f9b08c29f97a7cf29640c94 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Mon Jan 3 15:44:51 2022 +0800 Fix battery load calculation on Haiku * lisp/battery.el (battery-haiku-acpi-battery): Fix load calculation. diff --git a/lisp/battery.el b/lisp/battery.el index 7661697cb4..f4d59f30bb 100644 --- a/lisp/battery.el +++ b/lisp/battery.el @@ -689,8 +689,8 @@ The following %-sequences are provided: ((eq state 'critical) "!") (t "")))) (cons ?p (format "%.0f" - (/ (plist-get list :capacity) - (plist-get list :last-full-charge))))) + (* 100 (/ (plist-get list :capacity) + (plist-get list :last-full-charge)))))) '((?c . "N/A") (?r . "N/A") (?B . "N/A") commit f563fbf53b47639fe4419425b21aa4feb69c62f8 Author: Po Lu Date: Mon Jan 3 15:39:18 2022 +0800 Add support for the Haiku ACPI battery driver * lisp/battery.el (battery-status-function): Choose `battery-haiku-acpi-battery' if the Haiku ACPI driver is available. (battery--search-haiku-acpi-status): (battery-haiku-acpi-battery): New functions. diff --git a/lisp/battery.el b/lisp/battery.el index c899fb6e43..7661697cb4 100644 --- a/lisp/battery.el +++ b/lisp/battery.el @@ -113,6 +113,10 @@ Value does not include \".\" or \"..\"." (and (eq (call-process "pmset" nil t nil "-g" "ps") 0) (not (bobp)))))) #'battery-pmset) + ((and (eq system-type 'haiku) + ;; TODO: Support the Haiku APM battery driver. + (file-directory-p "/dev/power/acpi_battery")) + #'battery-haiku-acpi-battery) ((fboundp 'w32-battery-status) #'w32-battery-status)) "Function for getting battery status information. @@ -599,6 +603,100 @@ The following %-sequences are provided: ("1" "AC") (_ "N/A")))))) + +;;; `/dev/power/acpi_battery' interface for Haiku. + +(defun battery--search-haiku-acpi-status () + "Search forward for battery status in the current buffer. +Return a property list once all relevant properties are found. +The following properties may be inside the list: + + - `:capacity' (the current capacity of the battery.) + - `:voltage' (the current voltage of the battery.) + - `:rate', (the current rate of charge or discharge.) + - `:state' (the current state of the battery.) + - `:design-capacity' (the design capacity of the battery.) + - `:design-voltage' (the design voltage of the battery.) + - `:last-full-charge' (the capacity at the last full charge of + the battery.) + +`:capacity' and `:design-capacity' are both represented in +terms of milliamp-hours." + (let ((state-regexp "State \\([[:digit:]]+\\), Current Rate \\([[:digit:]]+\\), \ +Capacity \\([[:digit:]]+\\), Voltage \\([[:digit:]]+\\)") + (pu-regexp "Power Unit \\([[:digit:]]\\)+, Design Capacity \\([[:digit:]]+\\), \ +Last Full Charge \\([[:digit:]]+\\)") + (design-regexp "Design Voltage \\([[:digit:]]+\\)") + power-unit last-full-charge state rate capacity + voltage design-capacity design-voltage) + (when (re-search-forward state-regexp) + (setq state (string-to-number (match-string 1))) + (setq rate (string-to-number (match-string 2))) + (setq capacity (string-to-number (match-string 3))) + (setq voltage (/ (string-to-number (match-string 4)) 1000.0))) + (when (re-search-forward pu-regexp) + (setq power-unit (string-to-number (match-string 1))) + (setq design-capacity (string-to-number (match-string 2))) + (setq last-full-charge (string-to-number (match-string 3)))) + (when (re-search-forward design-regexp) + (setq design-voltage (/ (string-to-number (match-string 1)) 1000.0))) + ;; Convert capacity fields to milliamp-hours if they're + ;; specified as miliwatt-hours. + (when (eq power-unit 0) + (setq capacity (/ capacity voltage)) + (setq design-capacity (/ design-capacity design-voltage)) + (setq last-full-charge (/ last-full-charge voltage))) + (list :capacity capacity :voltage voltage + :rate rate :state (cond + ((not (zerop (logand state 2))) 'charging) + ((not (zerop (logand state 1))) 'discharging) + ((not (zerop (logand state 4))) 'critical) + (t 'normal)) + :design-capacity design-capacity + :design-voltage design-voltage + :last-full-charge last-full-charge))) + +(defun battery-haiku-acpi-battery () + "Get battery status from `/dev/power/acpi_battery'. +This function only works on Haiku systems with an ACPI battery. + +The following %-sequences are provided: +%c Current capacity (mAh) +%r Current rate of charge or discharge +%B Battery status (verbose) +%b Battery status: empty means high, `-' means low, + `!' means critical, and `+' means charging +%p Battery load percentage" + (with-temp-buffer + (dolist (file (battery--files "/dev/power/acpi_battery")) + (insert-file-contents (expand-file-name file "/dev/power/acpi_battery"))) + ;; I don't think Haiku actually supports multiple batteries yet, + ;; since the code in PowerStatus doesn't take care of that + ;; situation. + (let ((list (ignore-errors (battery--search-haiku-acpi-status)))) + (if list + (list (cons ?c (format "%.0f" (plist-get list :capacity))) + (cons ?r (format "%.0f" (plist-get list :rate))) + (cons ?B (symbol-name (plist-get list :state))) + (cons ?b (let ((state (plist-get list :state))) + (cond + ((eq state 'charging) "+") + ((and (eq state 'discharging) + (< (/ (plist-get list :capacity) + (plist-get list :last-full-charge)) + 0.15)) + "-") + ((eq state 'critical) "!") + (t "")))) + (cons ?p (format "%.0f" + (/ (plist-get list :capacity) + (plist-get list :last-full-charge))))) + '((?c . "N/A") + (?r . "N/A") + (?B . "N/A") + (?b . "N/A") + (?p . "N/A")))))) + ;;; UPower interface. commit d8959347d918f3f725d38094bdb90d7f923d9edb Author: Stefan Kangas Date: Mon Jan 3 07:52:55 2022 +0100 * lisp/elide-head.el (elide-head-headers-to-hide): Simplify. diff --git a/lisp/elide-head.el b/lisp/elide-head.el index 79af01bd48..619d350c80 100644 --- a/lisp/elide-head.el +++ b/lisp/elide-head.el @@ -55,17 +55,14 @@ "\\(If not, see \\|\ Boston, MA 0211\\(1-1307\\|0-1301\\), USA\\|\ 675 Mass Ave, Cambridge, MA 02139, USA\\)\\.") - ;; FreeBSD license + ;; FreeBSD license / Modified BSD license (3-clause) (,(rx (or "The Regents of the University of California. All rights reserved." "Redistribution and use in source and binary")) - . "THE POSSIBILITY OF SUCH DAMAGE\\.") + . "POSSIBILITY OF SUCH DAMAGE\\.") ;; X11 and Expat ("Permission is hereby granted, free of charge" . - ,(rx (or "authorization from the X Consortium." ; X11 - "THE USE OR OTHER DEALINGS IN THE SOFTWARE."))) ; Expat - ;; Modified BSD license (3-clause) - ("Redistribution and use in source and binary forms" - . "POSSIBILITY OF SUCH DAMAGE\\.")) + ,(rx (or "authorization from the X Consortium." ; X11 + "THE USE OR OTHER DEALINGS IN THE SOFTWARE.")))) ; Expat "Alist of regexps defining start and end of text to elide. The cars of elements of the list are searched for in order. Text is commit 8d6a8f660d13052991f398b220810efea1ae118a Author: Stefan Kangas Date: Mon Jan 3 04:59:03 2022 +0100 Silence byte-compiler in eieio tests This is a temporary workaround for Bug#52971. * test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el (eieio-compat) * test/lisp/emacs-lisp/eieio-tests/eieio-tests.el (eieio-compat): Silence byte-compiler by wrapping require in with-no-warnings. diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el index 3b6d8ca5dd..af19c122b9 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-test-methodinvoke.el @@ -55,7 +55,9 @@ ;;; Code: (require 'eieio) -(require 'eieio-compat) +;; FIXME: See Bug#52971. +(with-no-warnings + (require 'eieio-compat)) (require 'ert) (defvar eieio-test-method-order-list nil diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el index cbcb521556..9b27d4ab93 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el @@ -27,7 +27,9 @@ (require 'ert) (require 'eieio) (require 'eieio-base) -(require 'eieio-compat) +;; FIXME: See Bug#52971. +(with-no-warnings + (require 'eieio-compat)) (require 'eieio-opt) (eval-when-compile (require 'cl-lib)) commit f6501fded744b729b72ed0bbc663e5a7953b04bb Author: Po Lu Date: Mon Jan 3 11:21:16 2022 +0800 Don't try to guess a delta if a scroll valuator's state is unknown * src/xterm.c (x_get_scroll_valuator_delta): Return DBL_MAX if the scroll valuator's value is unknown. diff --git a/src/xterm.c b/src/xterm.c index c9120638a7..31e39280b3 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -502,9 +502,10 @@ x_init_master_valuators (struct x_display_info *dpyinfo) /* Return the delta of the scroll valuator VALUATOR_NUMBER under DEVICE_ID in the display DPYINFO with VALUE. The valuator's valuator will be set to VALUE afterwards. In case no scroll - valuator is found, or if device_id is not known to Emacs, DBL_MAX - is returned. Otherwise, the valuator is returned in - VALUATOR_RETURN. */ + valuator is found, or if the valuator state is invalid (see the + comment under XI_Enter in handle_one_xevent), or if device_id is + not known to Emacs, DBL_MAX is returned. Otherwise, the valuator + is returned in VALUATOR_RETURN. */ static double x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id, int valuator_number, double value, @@ -531,7 +532,7 @@ x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id, *valuator_return = sv; unblock_input (); - return 0.0; + return DBL_MAX; } else { commit 01047cf13f018f10b87788fb86efb61840a07f35 Author: Po Lu Date: Mon Jan 3 11:17:43 2022 +0800 Revert "Stop sending touch-end events if coalescing scroll events" This reverts commit a6952f78f3962ac2d9a5add580a130f0abd31429. diff --git a/src/xterm.c b/src/xterm.c index 3fabdece49..c9120638a7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -10230,12 +10230,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, val->emacs_value += delta; if (mwheel_coalesce_scroll_events - && (fabs (val->emacs_value) < 1)) + && (fabs (val->emacs_value) < 1) + && (fabs (delta) > 0)) continue; bool s = signbit (val->emacs_value); - inev.ie.kind = ((mwheel_coalesce_scroll_events - || fabs (delta) > 0) + inev.ie.kind = (fabs (delta) > 0 ? (val->horizontal ? HORIZ_WHEEL_EVENT : WHEEL_EVENT) commit 7544ede1bc2d9f51f783754d5ca8dd60cd5a1bea Author: Po Lu Date: Mon Jan 3 10:56:45 2022 +0800 Use XKB to find modifiers on x * src/xterm.c (x_find_modifier_meanings): Look for virtual modifiers with Xkb instead. (handle_one_xevent): Add group when translating XI2 keycodes and handle Xkb keymap events. (x_term_init): Populate dpyinfo->xkb_event_type. * src/xterm.h (struct x_display_info): New field `xkb_event_type', and change modifier masks to `unsigned int'. diff --git a/src/xterm.c b/src/xterm.c index c344331755..3fabdece49 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -5321,6 +5321,15 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo) KeySym *syms; int syms_per_code; XModifierKeymap *mods; +#ifdef HAVE_XKB + Atom meta; + Atom super; + Atom hyper; + Atom shiftlock; + Atom alt; + int i; + int found_meta_p = false; +#endif dpyinfo->meta_mod_mask = 0; dpyinfo->shift_lock_mask = 0; @@ -5330,6 +5339,50 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo) XDisplayKeycodes (dpyinfo->display, &min_code, &max_code); +#ifdef HAVE_XKB + if (dpyinfo->xkb_desc) + { + meta = XInternAtom (dpyinfo->display, "Meta", False); + super = XInternAtom (dpyinfo->display, "Super", False); + hyper = XInternAtom (dpyinfo->display, "Hyper", False); + shiftlock = XInternAtom (dpyinfo->display, "ShiftLock", False); + alt = XInternAtom (dpyinfo->display, "Alt", False); + + for (i = 0; i < XkbNumVirtualMods; i++) + { + uint vmodmask = dpyinfo->xkb_desc->server->vmods[i]; + + if (dpyinfo->xkb_desc->names->vmods[i] == meta) + { + dpyinfo->meta_mod_mask |= vmodmask; + found_meta_p = vmodmask; + } + else if (dpyinfo->xkb_desc->names->vmods[i] == alt) + dpyinfo->alt_mod_mask |= vmodmask; + else if (dpyinfo->xkb_desc->names->vmods[i] == super) + dpyinfo->super_mod_mask |= vmodmask; + else if (dpyinfo->xkb_desc->names->vmods[i] == hyper) + dpyinfo->hyper_mod_mask |= vmodmask; + else if (dpyinfo->xkb_desc->names->vmods[i] == shiftlock) + dpyinfo->shift_lock_mask |= vmodmask; + } + + if (!found_meta_p) + { + dpyinfo->meta_mod_mask = dpyinfo->alt_mod_mask; + dpyinfo->alt_mod_mask = 0; + } + + if (dpyinfo->alt_mod_mask & dpyinfo->meta_mod_mask) + dpyinfo->alt_mod_mask &= ~dpyinfo->meta_mod_mask; + + if (dpyinfo->hyper_mod_mask & dpyinfo->super_mod_mask) + dpyinfo->hyper_mod_mask &= ~dpyinfo->super_mod_mask; + + return; + } +#endif + syms = XGetKeyboardMapping (dpyinfo->display, min_code, max_code - min_code + 1, &syms_per_code); @@ -5342,66 +5395,66 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo) bool found_alt_or_meta; for (row = 3; row < 8; row++) - { - found_alt_or_meta = false; - for (col = 0; col < mods->max_keypermod; col++) - { - KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col]; - - /* Zeroes are used for filler. Skip them. */ - if (code == 0) - continue; - - /* Are any of this keycode's keysyms a meta key? */ + { + found_alt_or_meta = false; + for (col = 0; col < mods->max_keypermod; col++) { - int code_col; - - for (code_col = 0; code_col < syms_per_code; code_col++) - { - int sym = syms[((code - min_code) * syms_per_code) + code_col]; + KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col]; - switch (sym) - { - case XK_Meta_L: - case XK_Meta_R: - found_alt_or_meta = true; - dpyinfo->meta_mod_mask |= (1 << row); - break; + /* Zeroes are used for filler. Skip them. */ + if (code == 0) + continue; - case XK_Alt_L: - case XK_Alt_R: - found_alt_or_meta = true; - dpyinfo->alt_mod_mask |= (1 << row); - break; - - case XK_Hyper_L: - case XK_Hyper_R: - if (!found_alt_or_meta) - dpyinfo->hyper_mod_mask |= (1 << row); - code_col = syms_per_code; - col = mods->max_keypermod; - break; + /* Are any of this keycode's keysyms a meta key? */ + { + int code_col; - case XK_Super_L: - case XK_Super_R: - if (!found_alt_or_meta) - dpyinfo->super_mod_mask |= (1 << row); - code_col = syms_per_code; - col = mods->max_keypermod; - break; + for (code_col = 0; code_col < syms_per_code; code_col++) + { + int sym = syms[((code - min_code) * syms_per_code) + code_col]; - case XK_Shift_Lock: - /* Ignore this if it's not on the lock modifier. */ - if (!found_alt_or_meta && ((1 << row) == LockMask)) - dpyinfo->shift_lock_mask = LockMask; - code_col = syms_per_code; - col = mods->max_keypermod; - break; - } - } + switch (sym) + { + case XK_Meta_L: + case XK_Meta_R: + found_alt_or_meta = true; + dpyinfo->meta_mod_mask |= (1 << row); + break; + + case XK_Alt_L: + case XK_Alt_R: + found_alt_or_meta = true; + dpyinfo->alt_mod_mask |= (1 << row); + break; + + case XK_Hyper_L: + case XK_Hyper_R: + if (!found_alt_or_meta) + dpyinfo->hyper_mod_mask |= (1 << row); + code_col = syms_per_code; + col = mods->max_keypermod; + break; + + case XK_Super_L: + case XK_Super_R: + if (!found_alt_or_meta) + dpyinfo->super_mod_mask |= (1 << row); + code_col = syms_per_code; + col = mods->max_keypermod; + break; + + case XK_Shift_Lock: + /* Ignore this if it's not on the lock modifier. */ + if (!found_alt_or_meta && ((1 << row) == LockMask)) + dpyinfo->shift_lock_mask = LockMask; + code_col = syms_per_code; + col = mods->max_keypermod; + break; + } + } + } } - } - } + } } /* If we couldn't find any meta keys, accept any alt keys as meta keys. */ @@ -8360,11 +8413,20 @@ handle_one_xevent (struct x_display_info *dpyinfo, inev.ie.kind = NO_EVENT; inev.ie.arg = Qnil; +#ifdef HAVE_XKB + if (event->type != dpyinfo->xkb_event_type) + { +#endif #ifdef HAVE_XINPUT2 - if (event->type != GenericEvent) + if (event->type != GenericEvent) #endif - any = x_any_window_to_frame (dpyinfo, event->xany.window); + any = x_any_window_to_frame (dpyinfo, event->xany.window); #ifdef HAVE_XINPUT2 + else + any = NULL; +#endif +#ifdef HAVE_XKB + } else any = NULL; #endif @@ -9890,11 +9952,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_find_modifier_meanings (dpyinfo); FALLTHROUGH; case MappingKeyboard: -#ifdef HAVE_XKB - if (dpyinfo->xkb_desc) - XkbGetUpdatedMap (dpyinfo->display, XkbAllComponentsMask, - dpyinfo->xkb_desc); -#endif XRefreshKeyboardMapping ((XMappingEvent *) &event->xmapping); } goto OTHER; @@ -10624,8 +10681,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef HAVE_XKB if (dpyinfo->xkb_desc) { + uint xkb_state = state; + xkb_state &= ~(1 << 13 | 1 << 14); + xkb_state |= xev->group.effective << 13; + if (!XkbTranslateKeyCode (dpyinfo->xkb_desc, keycode, - state, &mods_rtrn, &keysym)) + xkb_state, &mods_rtrn, &keysym)) goto XI_OTHER; } else @@ -11180,6 +11241,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif default: +#ifdef HAVE_XKB + if (event->type == dpyinfo->xkb_event_type) + { + XkbEvent *xkbevent = (XkbEvent *) event; + + if (xkbevent->any.xkb_type == XkbNewKeyboardNotify + || xkbevent->any.xkb_type == XkbMapNotify) + { + if (dpyinfo->xkb_desc) + { + XkbGetUpdatedMap (dpyinfo->display, + (XkbKeySymsMask + | XkbKeyTypesMask + | XkbModifierMapMask + | XkbVirtualModsMask), + dpyinfo->xkb_desc); + XkbGetNames (dpyinfo->display, + XkbGroupNamesMask | XkbVirtualModNamesMask, + dpyinfo->xkb_desc); + + x_find_modifier_meanings (dpyinfo); + } + } + } +#endif OTHER: #ifdef USE_X_TOOLKIT block_input (); @@ -14801,8 +14887,10 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo->x_id = ++x_display_id; +#ifndef HAVE_XKB /* Figure out which modifier bits mean what. */ x_find_modifier_meanings (dpyinfo); +#endif /* Get the scroll bar cursor. */ #ifdef USE_GTK @@ -14918,19 +15006,35 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) #endif #ifdef HAVE_XKB - int xkb_major, xkb_minor, xkb_op, xkb_event, xkb_error_code; + int xkb_major, xkb_minor, xkb_op, xkb_error_code; xkb_major = XkbMajorVersion; xkb_minor = XkbMinorVersion; if (XkbLibraryVersion (&xkb_major, &xkb_minor) - && XkbQueryExtension (dpyinfo->display, &xkb_op, &xkb_event, + && XkbQueryExtension (dpyinfo->display, &xkb_op, &dpyinfo->xkb_event_type, &xkb_error_code, &xkb_major, &xkb_minor)) { dpyinfo->supports_xkb = true; dpyinfo->xkb_desc = XkbGetMap (dpyinfo->display, - XkbAllComponentsMask, + (XkbKeySymsMask + | XkbKeyTypesMask + | XkbModifierMapMask + | XkbVirtualModsMask), XkbUseCoreKbd); + + if (dpyinfo->xkb_desc) + XkbGetNames (dpyinfo->display, + XkbGroupNamesMask | XkbVirtualModNamesMask, + dpyinfo->xkb_desc); + + XkbSelectEvents (dpyinfo->display, + XkbUseCoreKbd, + XkbNewKeyboardNotifyMask | XkbMapNotifyMask, + XkbNewKeyboardNotifyMask | XkbMapNotifyMask); } + + /* Figure out which modifier bits mean what. */ + x_find_modifier_meanings (dpyinfo); #endif #if defined USE_CAIRO || defined HAVE_XFT diff --git a/src/xterm.h b/src/xterm.h index f290cdaa7c..d4600bdf80 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -326,10 +326,10 @@ struct x_display_info use; XK_Caps_Lock should only affect alphabetic keys. With this arrangement, the lock modifier should shift the character if (EVENT.state & shift_lock_mask) != 0. */ - int meta_mod_mask, shift_lock_mask; + unsigned int meta_mod_mask, shift_lock_mask; /* These are like meta_mod_mask, but for different modifiers. */ - int alt_mod_mask, super_mod_mask, hyper_mod_mask; + unsigned alt_mod_mask, super_mod_mask, hyper_mod_mask; /* Communication with window managers. */ Atom Xatom_wm_protocols; @@ -523,6 +523,7 @@ struct x_display_info #ifdef HAVE_XKB bool supports_xkb; + int xkb_event_type; XkbDescPtr xkb_desc; #endif }; commit a4cb14b5365e0cac5c8c181b69ecd504a47a89ec Author: Po Lu Date: Mon Jan 3 00:59:58 2022 +0000 * src/haikumenu.c (haiku_menu_show): Fix input blocking. diff --git a/src/haikumenu.c b/src/haikumenu.c index bff6bd8a48..5cfcc75132 100644 --- a/src/haikumenu.c +++ b/src/haikumenu.c @@ -324,9 +324,8 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags, } digest_menu_items (menu, 0, menu_items_used, 0); BView_convert_to_screen (view, &x, &y); - unblock_input (); - menu_item_selection = BMenu_run (menu, x, y); + unblock_input (); FRAME_DISPLAY_INFO (f)->grabbed = 0; @@ -376,7 +375,9 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags, if (!NILP (subprefix_stack[j])) entry = Fcons (subprefix_stack[j], entry); } + block_input (); BPopUpMenu_delete (menu); + unblock_input (); return entry; } i += MENU_ITEMS_ITEM_LENGTH; @@ -385,10 +386,14 @@ haiku_menu_show (struct frame *f, int x, int y, int menuflags, } else if (!(menuflags & MENU_FOR_CLICK)) { + block_input (); BPopUpMenu_delete (menu); + unblock_input (); quit (); } + block_input (); BPopUpMenu_delete (menu); + unblock_input (); return Qnil; } commit 7ddfe1cab2156db4cb1da1968e6d6dabb533ff33 Author: Stefan Kangas Date: Sun Jan 2 23:27:16 2022 +0100 Move define-keymap and defvar-keymap to keymap.el These functions deal with the "new" keymap binding interface, so they belong in keymap.el rather than in subr.el. * lisp/subr.el (define-keymap--compile, define-keymap) (defvar-keymap): Move from here ... * lisp/keymap.el (define-keymap--compile, define-keymap) (defvar-keymap): ... to here. diff --git a/lisp/keymap.el b/lisp/keymap.el index a60efe18e1..6feb91a60b 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -452,6 +452,139 @@ If MESSAGE (and interactively), message the result." (message "%s is bound to %s globally" keys def)) def)) + +;;; define-keymap and defvar-keymap + +(defun define-keymap--compile (form &rest args) + ;; This compiler macro is only there for compile-time + ;; error-checking; it does not change the call in any way. + (while (and args + (keywordp (car args)) + (not (eq (car args) :menu))) + (unless (memq (car args) '(:full :keymap :parent :suppress :name :prefix)) + (byte-compile-warn "Invalid keyword: %s" (car args))) + (setq args (cdr args)) + (when (null args) + (byte-compile-warn "Uneven number of keywords in %S" form)) + (setq args (cdr args))) + ;; Bindings. + (while args + (let ((key (pop args))) + (when (and (stringp key) (not (key-valid-p key))) + (byte-compile-warn "Invalid `kbd' syntax: %S" key))) + (when (null args) + (byte-compile-warn "Uneven number of key bindings in %S" form)) + (setq args (cdr args))) + form) + +(defun define-keymap (&rest definitions) + "Create a new keymap and define KEY/DEFINITION pairs as key bindings. +The new keymap is returned. + +Options can be given as keywords before the KEY/DEFINITION +pairs. Available keywords are: + +:full If non-nil, create a chartable alist (see `make-keymap'). + If nil (i.e., the default), create a sparse keymap (see + `make-sparse-keymap'). + +:suppress If non-nil, the keymap will be suppressed (see `suppress-keymap'). + If `nodigits', treat digits like other chars. + +:parent If non-nil, this should be a keymap to use as the parent + (see `set-keymap-parent'). + +:keymap If non-nil, instead of creating a new keymap, the given keymap + will be destructively modified instead. + +:name If non-nil, this should be a string to use as the menu for + the keymap in case you use it as a menu with `x-popup-menu'. + +:prefix If non-nil, this should be a symbol to be used as a prefix + command (see `define-prefix-command'). If this is the case, + this symbol is returned instead of the map itself. + +KEY/DEFINITION pairs are as KEY and DEF in `keymap-set'. KEY can +also be the special symbol `:menu', in which case DEFINITION +should be a MENU form as accepted by `easy-menu-define'. + +\(fn &key FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)" + (declare (indent defun) + (compiler-macro define-keymap--compile)) + (let (full suppress parent name prefix keymap) + ;; Handle keywords. + (while (and definitions + (keywordp (car definitions)) + (not (eq (car definitions) :menu))) + (let ((keyword (pop definitions))) + (unless definitions + (error "Missing keyword value for %s" keyword)) + (let ((value (pop definitions))) + (pcase keyword + (:full (setq full value)) + (:keymap (setq keymap value)) + (:parent (setq parent value)) + (:suppress (setq suppress value)) + (:name (setq name value)) + (:prefix (setq prefix value)) + (_ (error "Invalid keyword: %s" keyword)))))) + + (when (and prefix + (or full parent suppress keymap)) + (error "A prefix keymap can't be defined with :full/:parent/:suppress/:keymap keywords")) + + (when (and keymap full) + (error "Invalid combination: :keymap with :full")) + + (let ((keymap (cond + (keymap keymap) + (prefix (define-prefix-command prefix nil name)) + (full (make-keymap name)) + (t (make-sparse-keymap name))))) + (when suppress + (suppress-keymap keymap (eq suppress 'nodigits))) + (when parent + (set-keymap-parent keymap parent)) + + ;; Do the bindings. + (while definitions + (let ((key (pop definitions))) + (unless definitions + (error "Uneven number of key/definition pairs")) + (let ((def (pop definitions))) + (if (eq key :menu) + (easy-menu-define nil keymap "" def) + (keymap-set keymap key def))))) + keymap))) + +(defmacro defvar-keymap (variable-name &rest defs) + "Define VARIABLE-NAME as a variable with a keymap definition. +See `define-keymap' for an explanation of the keywords and KEY/DEFINITION. + +In addition to the keywords accepted by `define-keymap', this +macro also accepts a `:doc' keyword, which (if present) is used +as the variable documentation string. + +\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)" + (declare (indent 1)) + (let ((opts nil) + doc) + (while (and defs + (keywordp (car defs)) + (not (eq (car defs) :menu))) + (let ((keyword (pop defs))) + (unless defs + (error "Uneven number of keywords")) + (if (eq keyword :doc) + (setq doc (pop defs)) + (push keyword opts) + (push (pop defs) opts)))) + (unless (zerop (% (length defs) 2)) + (error "Uneven number of key/definition pairs: %s" defs)) + `(defvar ,variable-name + (define-keymap ,@(nreverse opts) ,@defs) + ,@(and doc (list doc))))) + (provide 'keymap) ;;; keymap.el ends here diff --git a/lisp/subr.el b/lisp/subr.el index 11105c4aa6..7906324f80 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -6526,136 +6526,6 @@ not a list, return a one-element list containing OBJECT." object (list object))) -(defun define-keymap--compile (form &rest args) - ;; This compiler macro is only there for compile-time - ;; error-checking; it does not change the call in any way. - (while (and args - (keywordp (car args)) - (not (eq (car args) :menu))) - (unless (memq (car args) '(:full :keymap :parent :suppress :name :prefix)) - (byte-compile-warn "Invalid keyword: %s" (car args))) - (setq args (cdr args)) - (when (null args) - (byte-compile-warn "Uneven number of keywords in %S" form)) - (setq args (cdr args))) - ;; Bindings. - (while args - (let ((key (pop args))) - (when (and (stringp key) (not (key-valid-p key))) - (byte-compile-warn "Invalid `kbd' syntax: %S" key))) - (when (null args) - (byte-compile-warn "Uneven number of key bindings in %S" form)) - (setq args (cdr args))) - form) - -(defun define-keymap (&rest definitions) - "Create a new keymap and define KEY/DEFINITION pairs as key bindings. -The new keymap is returned. - -Options can be given as keywords before the KEY/DEFINITION -pairs. Available keywords are: - -:full If non-nil, create a chartable alist (see `make-keymap'). - If nil (i.e., the default), create a sparse keymap (see - `make-sparse-keymap'). - -:suppress If non-nil, the keymap will be suppressed (see `suppress-keymap'). - If `nodigits', treat digits like other chars. - -:parent If non-nil, this should be a keymap to use as the parent - (see `set-keymap-parent'). - -:keymap If non-nil, instead of creating a new keymap, the given keymap - will be destructively modified instead. - -:name If non-nil, this should be a string to use as the menu for - the keymap in case you use it as a menu with `x-popup-menu'. - -:prefix If non-nil, this should be a symbol to be used as a prefix - command (see `define-prefix-command'). If this is the case, - this symbol is returned instead of the map itself. - -KEY/DEFINITION pairs are as KEY and DEF in `keymap-set'. KEY can -also be the special symbol `:menu', in which case DEFINITION -should be a MENU form as accepted by `easy-menu-define'. - -\(fn &key FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)" - (declare (indent defun) - (compiler-macro define-keymap--compile)) - (let (full suppress parent name prefix keymap) - ;; Handle keywords. - (while (and definitions - (keywordp (car definitions)) - (not (eq (car definitions) :menu))) - (let ((keyword (pop definitions))) - (unless definitions - (error "Missing keyword value for %s" keyword)) - (let ((value (pop definitions))) - (pcase keyword - (:full (setq full value)) - (:keymap (setq keymap value)) - (:parent (setq parent value)) - (:suppress (setq suppress value)) - (:name (setq name value)) - (:prefix (setq prefix value)) - (_ (error "Invalid keyword: %s" keyword)))))) - - (when (and prefix - (or full parent suppress keymap)) - (error "A prefix keymap can't be defined with :full/:parent/:suppress/:keymap keywords")) - - (when (and keymap full) - (error "Invalid combination: :keymap with :full")) - - (let ((keymap (cond - (keymap keymap) - (prefix (define-prefix-command prefix nil name)) - (full (make-keymap name)) - (t (make-sparse-keymap name))))) - (when suppress - (suppress-keymap keymap (eq suppress 'nodigits))) - (when parent - (set-keymap-parent keymap parent)) - - ;; Do the bindings. - (while definitions - (let ((key (pop definitions))) - (unless definitions - (error "Uneven number of key/definition pairs")) - (let ((def (pop definitions))) - (if (eq key :menu) - (easy-menu-define nil keymap "" def) - (keymap-set keymap key def))))) - keymap))) - -(defmacro defvar-keymap (variable-name &rest defs) - "Define VARIABLE-NAME as a variable with a keymap definition. -See `define-keymap' for an explanation of the keywords and KEY/DEFINITION. - -In addition to the keywords accepted by `define-keymap', this -macro also accepts a `:doc' keyword, which (if present) is used -as the variable documentation string. - -\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)" - (declare (indent 1)) - (let ((opts nil) - doc) - (while (and defs - (keywordp (car defs)) - (not (eq (car defs) :menu))) - (let ((keyword (pop defs))) - (unless defs - (error "Uneven number of keywords")) - (if (eq keyword :doc) - (setq doc (pop defs)) - (push keyword opts) - (push (pop defs) opts)))) - (unless (zerop (% (length defs) 2)) - (error "Uneven number of key/definition pairs: %s" defs)) - `(defvar ,variable-name - (define-keymap ,@(nreverse opts) ,@defs) - ,@(and doc (list doc))))) - (defmacro with-delayed-message (args &rest body) "Like `progn', but display MESSAGE if BODY takes longer than TIMEOUT seconds. The MESSAGE form will be evaluated immediately, but the resulting commit 04c0245d36a7face6a4f4b45a56f65f3a282790f Merge: 9e7191048b 6e53178a37 Author: Stefan Monnier Date: Sun Jan 2 17:07:42 2022 -0500 Merge remote-tracking branch 'origin/emacs-28' into trunk commit 6e53178a37d65218818fac3da1beac33db6ab5eb (refs/remotes/origin/emacs-28) Author: Eli Zaretskii Date: Sun Jan 2 21:36:13 2022 +0200 Avoid inflooping when 'tab-bar-format' includes embedded newlines * src/xdisp.c (tab_bar_height, redisplay_tab_bar): Support 'tab-bar-format' with embedded newlines. (Bug#52947) diff --git a/src/xdisp.c b/src/xdisp.c index 7c3885c975..73edc0d7aa 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -13508,11 +13508,15 @@ tab_bar_height (struct frame *f, int *n_rows, bool pixelwise) 0, 0, 0, STRING_MULTIBYTE (f->desired_tab_bar_string)); it.paragraph_embedding = L2R; + clear_glyph_row (temp_row); while (!ITERATOR_AT_END_P (&it)) { - clear_glyph_row (temp_row); it.glyph_row = temp_row; display_tab_bar_line (&it, -1); + /* If the tab-bar string includes newlines, get past it, because + display_tab_bar_line doesn't. */ + if (ITERATOR_AT_END_OF_LINE_P (&it)) + set_iterator_to_next (&it, true); } clear_glyph_row (temp_row); @@ -13638,6 +13642,10 @@ redisplay_tab_bar (struct frame *f) extra -= h; } display_tab_bar_line (&it, height + h); + /* If the tab-bar string includes newlines, get past it, + because display_tab_bar_line doesn't. */ + if (ITERATOR_AT_END_OF_LINE_P (&it)) + set_iterator_to_next (&it, true); } } else commit 9e7191048b56368a2d8bf3792f67f7b468d18eca Author: Stefan Kangas Date: Sun Jan 2 19:25:02 2022 +0100 elide-head: Add support for modified BSD license * lisp/elide-head.el (elide-head-headers-to-hide): Add support for the modified BSD license (3-clause BSD). diff --git a/lisp/elide-head.el b/lisp/elide-head.el index 30772fa514..79af01bd48 100644 --- a/lisp/elide-head.el +++ b/lisp/elide-head.el @@ -50,16 +50,22 @@ :group 'tools) (defcustom elide-head-headers-to-hide - `(("is free software[:;] you can redistribute it" . ; GNU boilerplate + `(;; GNU GPL + ("is free software[:;] you can redistribute it" . "\\(If not, see \\|\ Boston, MA 0211\\(1-1307\\|0-1301\\), USA\\|\ 675 Mass Ave, Cambridge, MA 02139, USA\\)\\.") + ;; FreeBSD license (,(rx (or "The Regents of the University of California. All rights reserved." "Redistribution and use in source and binary")) - . "THE POSSIBILITY OF SUCH DAMAGE\\.") ; BSD + . "THE POSSIBILITY OF SUCH DAMAGE\\.") + ;; X11 and Expat ("Permission is hereby granted, free of charge" . - ,(rx (or "authorization from the X Consortium." ; X11 - "THE USE OR OTHER DEALINGS IN THE SOFTWARE.")))) ; Expat + ,(rx (or "authorization from the X Consortium." ; X11 + "THE USE OR OTHER DEALINGS IN THE SOFTWARE."))) ; Expat + ;; Modified BSD license (3-clause) + ("Redistribution and use in source and binary forms" + . "POSSIBILITY OF SUCH DAMAGE\\.")) "Alist of regexps defining start and end of text to elide. The cars of elements of the list are searched for in order. Text is commit 83da3a09d0d8fe8f13f405c1ec780e70e94f7b0b Author: Juri Linkov Date: Sun Jan 2 20:00:40 2022 +0200 * lisp/tab-line.el: Revert part of the fix in a6adfe21e4 (bug#52881) (tab-line--get-tab-property, tab-line-auto-hscroll): Use get-pos-property instead of get-text-property that fails after previous-single-property-change. diff --git a/lisp/tab-line.el b/lisp/tab-line.el index 37cfff1723..6aa3a85810 100644 --- a/lisp/tab-line.el +++ b/lisp/tab-line.el @@ -616,10 +616,10 @@ the selected tab visible." (defvar tab-line-auto-hscroll-buffer (generate-new-buffer " *tab-line-hscroll*")) (defun tab-line--get-tab-property (prop string) - (or (get-text-property 1 prop string) ;; for 99% cases of 1-char separator - (get-text-property 0 prop string) ;; for empty separator + (or (get-pos-property 1 prop string) ;; for most cases of 1-char separator + (get-pos-property 0 prop string) ;; for empty separator (let ((pos (next-single-property-change 0 prop string))) ;; long separator - (and pos (get-text-property pos prop string))))) + (and pos (get-pos-property pos prop string))))) (defun tab-line-auto-hscroll (strings hscroll) (with-current-buffer tab-line-auto-hscroll-buffer @@ -656,9 +656,9 @@ the selected tab visible." (if (> (vertical-motion 1) 0) (let* ((point (previous-single-property-change (point) 'tab)) (tab-prop (when point - (or (get-text-property point 'tab) + (or (get-pos-property point 'tab) (and (setq point (previous-single-property-change point 'tab)) - (get-text-property point 'tab))))) + (get-pos-property point 'tab))))) (new-hscroll (when tab-prop (seq-position strings tab-prop (lambda (str tab) @@ -683,9 +683,9 @@ the selected tab visible." (when (> (vertical-motion 1) 0) (let* ((point (previous-single-property-change (point) 'tab)) (tab-prop (when point - (or (get-text-property point 'tab) + (or (get-pos-property point 'tab) (and (setq point (previous-single-property-change point 'tab)) - (get-text-property point 'tab))))) + (get-pos-property point 'tab))))) (new-hscroll (when tab-prop (seq-position strings tab-prop (lambda (str tab) commit 984391a9dc384627533758f6fced219b5381c91f Author: Stefan Kangas Date: Sun Jan 2 16:46:02 2022 +0100 New :type key for defcustom As compared to the old type key-sequence that deals with raw key sequences, this :type conforms to the format used by the new keymap-* functions. * lisp/wid-edit.el (key): New widget type. (Bug#52523) (widget-key-prompt-value-history): New variable. (widget-key-validate): New function. (key-sequence): Doc fix. * doc/lispref/customize.texi (Simple Types): Document above new type. diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi index 9508ca8620..54059d7b6e 100644 --- a/doc/lispref/customize.texi +++ b/doc/lispref/customize.texi @@ -654,10 +654,14 @@ you can specify that the value must be @code{nil} or @code{t}, but also specify the text to describe each value in a way that fits the specific meaning of the alternative. +@item key +The value is a valid key according to @kbd{key-valid-p}, and suitable +for use with, for example @code{keymap-set}. + @item key-sequence The value is a key sequence. The customization buffer shows the key sequence using the same syntax as the @kbd{kbd} function. @xref{Key -Sequences}. +Sequences}. This is a legacy type; use @code{key} instead. @item coding-system The value must be a coding-system name, and you can do completion with diff --git a/etc/NEWS b/etc/NEWS index 29e329edc9..9c892b285d 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -985,6 +985,11 @@ syntax. This is like 'kbd', but only returns vectors instead of a mix of vectors and strings. ++++ +*** New ':type' for 'defcustom' for keys. +The new 'key' type can be used for options that should be a valid key +according to 'key-valid-p'. The type 'key-sequence' is now obsolete. + +++ ** New substitution in docstrings and 'substitute-command-keys'. Use \\`KEYSEQ' to insert a literal key sequence "KEYSEQ" (for example diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el index 831b2ccfca..f00a524c0c 100644 --- a/lisp/wid-edit.el +++ b/lisp/wid-edit.el @@ -3460,7 +3460,7 @@ It reads a directory name from an editable text field." map)) (define-widget 'key-sequence 'restricted-sexp - "A key sequence." + "A key sequence. This is obsolete; use the `key' type instead." :prompt-value 'widget-field-prompt-value :prompt-internal 'widget-symbol-prompt-internal ; :prompt-match 'fboundp ;; What was this good for? KFS @@ -3525,6 +3525,27 @@ It reads a directory name from an editable text field." (read-kbd-macro value)) value)) + +(defvar widget-key-prompt-value-history nil + "History of input to `widget-key-prompt-value'.") + +(define-widget 'key 'editable-field + "A key sequence." + :prompt-value 'widget-field-prompt-value + :match 'key-valid-p + :format "%{%t%}: %v" + :validate 'widget-key-validate + :keymap widget-key-sequence-map + :help-echo "C-q: insert KEY, EVENT, or CODE; RET: enter value" + :tag "Key") + +(defun widget-key-validate (widget) + (unless (and (stringp (widget-value widget)) + (key-valid-p (widget-value widget))) + (widget-put widget :error (format "Invalid key: %S" + (widget-value widget))) + widget)) + (define-widget 'sexp 'editable-field "An arbitrary Lisp expression." commit b2167d98432a78442522b7564e22f47d75a98b6f Author: Mattias EngdegÄrd Date: Sun Jan 2 13:00:13 2022 +0100 Don't fail flymake-tests if `gcc` actually is Clang * test/lisp/progmodes/flymake-tests.el (flymake-tests--gcc-is-clang) (different-diagnostic-types, included-c-header-files): Skip tests that depend on the `gcc` command really being GCC and not Clang. diff --git a/test/lisp/progmodes/flymake-tests.el b/test/lisp/progmodes/flymake-tests.el index 9e5147726f..ced7b5aace 100644 --- a/test/lisp/progmodes/flymake-tests.el +++ b/test/lisp/progmodes/flymake-tests.el @@ -140,9 +140,15 @@ SEVERITY-PREDICATE is used to setup (flymake-goto-next-error) (should (eq 'flymake-error (face-at-point))))))) +(defun flymake-tests--gcc-is-clang () + "Whether the `gcc' command actually runs the Clang compiler." + (string-match "[Cc]lang version " + (shell-command-to-string "gcc --version"))) + (ert-deftest different-diagnostic-types () "Test GCC warning via function predicate." (skip-unless (and (executable-find "gcc") + (not (flymake-tests--gcc-is-clang)) (version<= "5" (string-trim (shell-command-to-string "gcc -dumpversion"))) @@ -166,7 +172,9 @@ SEVERITY-PREDICATE is used to setup (ert-deftest included-c-header-files () "Test inclusion of .h header files." - (skip-unless (and (executable-find "gcc") (executable-find "make"))) + (skip-unless (and (executable-find "gcc") + (not (flymake-tests--gcc-is-clang)) + (executable-find "make"))) (let ((flymake-wrap-around nil)) (flymake-tests--with-flymake ("some-problems.h") commit be6b9e45805f99a70617f7a190f8c76a80543b6c Author: Po Lu Date: Sun Jan 2 20:28:58 2022 +0800 Add column width to tooltip frame width on pgtk * src/pgtkfns.c (Fx_show_tip): Add column width to width to avoid an odd problem in the GTK allocation code. (bug#52705) diff --git a/src/pgtkfns.c b/src/pgtkfns.c index c2e5942dfb..5d596861b8 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -3440,6 +3440,7 @@ Text larger than the specified size is clipped. */) /* Add the frame's internal border to calculated size. */ width = XFIXNUM (Fcar (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); height = XFIXNUM (Fcdr (size)) + 2 * FRAME_INTERNAL_BORDER_WIDTH (tip_f); + width += FRAME_COLUMN_WIDTH (tip_f); /* Calculate position of tooltip frame. */ compute_tip_xy (tip_f, parms, dx, dy, width, height, &root_x, &root_y); commit b477cff35d3f5513e57f71a34272bebd1c205ed3 Author: Eli Zaretskii Date: Sun Jan 2 09:30:15 2022 +0200 Clarify %g and %G time format specs * src/timefns.c (Fformat_time_string): * doc/lispref/os.texi (Time Parsing): Clarify %g/%G. (Bug#52934) diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi index a08af89878..b1c19e384b 100644 --- a/doc/lispref/os.texi +++ b/doc/lispref/os.texi @@ -1793,9 +1793,16 @@ This stands for the ISO 8601 date format, which is like @samp{%+4Y-%m-%d} except that any flags or field width override the @samp{+} and (after subtracting 6) the @samp{4}. @item %g -This stands for the year corresponding to the ISO week within the century. +@cindex ISO week, in time formatting +This stands for the year without century (00--99) corresponding to the +current @dfn{ISO week} number. ISO weeks start on Monday and end on +Sunday. If an ISO week begins in one year and ends in another, the +rules regarding which year @samp{%g} will produce are complex and will +not be described here; however, in general, if most of the week's days +are in the ending year, @samp{%g} will produce that year. @item %G -This stands for the year corresponding to the ISO week. +This stands for the year with century corresponding to the current ISO +week number. @item %h This is a synonym for @samp{%b}. @item %H diff --git a/src/timefns.c b/src/timefns.c index 809ffafea4..3e533ca51d 100644 --- a/src/timefns.c +++ b/src/timefns.c @@ -1422,8 +1422,9 @@ without consideration for daylight saving time. The value is a copy of FORMAT-STRING, but with certain constructs replaced by text that describes the specified date and time in TIME: -%Y is the year, %y within the century, %C the century. -%G is the year corresponding to the ISO week, %g within the century. +%Y is the year, %y year without century, %C the century. +%G is the year corresponding to the ISO week, %g year corresponding + to the ISO week, without century. %m is the numeric month. %b and %h are the locale's abbreviated month name, %B the full name. (%h is not supported on MS-Windows.) @@ -1431,7 +1432,7 @@ by text that describes the specified date and time in TIME: %u is the numeric day of week from 1 (Monday) to 7, %w from 0 (Sunday) to 6. %a is the locale's abbreviated name of the day of week, %A the full name. %U is the week number starting on Sunday, %W starting on Monday, - %V according to ISO 8601. + %V the week number according to ISO 8601. %j is the day of the year. %H is the hour on a 24-hour clock, %I is on a 12-hour clock, %k is like %H commit 9156e109270b837b0b4f5740c305531754e72cf6 Author: Stefan Monnier Date: Sun Jan 2 02:25:55 2022 -0500 (define-char-code-property): Workaround for bug#52945 * lisp/international/mule-cmds.el (define-char-code-property): Ignore requests to re-setup lazy loading after the char-table is already loaded. diff --git a/lisp/international/mule-cmds.el b/lisp/international/mule-cmds.el index 7fd1430c03..28be35d65d 100644 --- a/lisp/international/mule-cmds.el +++ b/lisp/international/mule-cmds.el @@ -2936,8 +2936,14 @@ See also the documentation of `get-char-code-property' and (or (stringp table) (error "Not a char-table nor a file name: %s" table))) (if (stringp table) (setq table (purecopy table))) - (setf (alist-get name char-code-property-alist) table) - (put name 'char-code-property-documentation (purecopy docstring))) + (if (and (stringp table) + (char-table-p (alist-get name char-code-property-alist))) + ;; The table is already setup and we're apparently trying to + ;; undo that, probably because `charprop.el' is being re-loaded. + ;; Just skip it, in order to work around a recursive load (bug#52945). + nil + (setf (alist-get name char-code-property-alist) table) + (put name 'char-code-property-documentation (purecopy docstring)))) (defvar char-code-property-table (make-char-table 'char-code-property-table)